Browse Source

Updated to newest kNet.

Lasse Öörni 13 years ago
parent
commit
317a502b7e
71 changed files with 2337 additions and 1063 deletions
  1. 13 13
      Engine/Network/Network.cpp
  2. 2 2
      Engine/Network/Network.h
  3. 28 26
      ThirdParty/kNet/CMakeLists.txt
  4. 24 24
      ThirdParty/kNet/README.txt
  5. 31 0
      ThirdParty/kNet/WHATSNEW.txt
  6. 1 0
      ThirdParty/kNet/include/kNet.h
  7. 46 0
      ThirdParty/kNet/include/kNet/64BitAllocDebugger.h
  8. 3 5
      ThirdParty/kNet/include/kNet/BasicSerializedDataTypes.h
  9. 23 6
      ThirdParty/kNet/include/kNet/DataDeserializer.h
  10. 133 18
      ThirdParty/kNet/include/kNet/DataSerializer.h
  11. 5 8
      ThirdParty/kNet/include/kNet/DebugMemoryLeakCheck.h
  12. 5 14
      ThirdParty/kNet/include/kNet/EndPoint.h
  13. 2 4
      ThirdParty/kNet/include/kNet/EventArray.h
  14. 8 10
      ThirdParty/kNet/include/kNet/FragmentedTransferManager.h
  15. 9 4
      ThirdParty/kNet/include/kNet/IMessageHandler.h
  16. 1 1
      ThirdParty/kNet/include/kNet/Lockable.h
  17. 22 17
      ThirdParty/kNet/include/kNet/MessageConnection.h
  18. 9 11
      ThirdParty/kNet/include/kNet/MessageListParser.h
  19. 3 7
      ThirdParty/kNet/include/kNet/NetException.h
  20. 12 14
      ThirdParty/kNet/include/kNet/Network.h
  21. 14 14
      ThirdParty/kNet/include/kNet/NetworkMessage.h
  22. 8 10
      ThirdParty/kNet/include/kNet/NetworkServer.h
  23. 103 0
      ThirdParty/kNet/include/kNet/NetworkSimulator.h
  24. 2 4
      ThirdParty/kNet/include/kNet/NetworkWorkerThread.h
  25. 9 11
      ThirdParty/kNet/include/kNet/RingBuffer.h
  26. 2 1
      ThirdParty/kNet/include/kNet/SequentialIntegerSet.h
  27. 3 6
      ThirdParty/kNet/include/kNet/SerializationStructCompiler.h
  28. 1 3
      ThirdParty/kNet/include/kNet/SerializedDataIterator.h
  29. 21 15
      ThirdParty/kNet/include/kNet/Socket.h
  30. 1 3
      ThirdParty/kNet/include/kNet/Sort.h
  31. 21 23
      ThirdParty/kNet/include/kNet/StatsEventHierarchy.h
  32. 3 3
      ThirdParty/kNet/include/kNet/StdCMallocHeap.h
  33. 1 3
      ThirdParty/kNet/include/kNet/TCPMessageConnection.h
  34. 2 4
      ThirdParty/kNet/include/kNet/Thread.h
  35. 15 0
      ThirdParty/kNet/include/kNet/Types.h
  36. 28 11
      ThirdParty/kNet/include/kNet/UDPMessageConnection.h
  37. 1 0
      ThirdParty/kNet/include/kNet/WaitFreeQueue.h
  38. 1 1
      ThirdParty/kNet/include/kNet/qt/GraphDialog.h
  39. 3 1
      ThirdParty/kNet/include/kNet/qt/MessageConnectionDialog.h
  40. 1 1
      ThirdParty/kNet/include/kNet/qt/NetworkDialog.h
  41. 52 0
      ThirdParty/kNet/include/kNet/qt/NetworkSimulationDialog.h
  42. 7 0
      ThirdParty/kNet/include/kNet/win32/WS2Include.h
  43. 1 0
      ThirdParty/kNet/include/kNetFwd.h
  44. 144 0
      ThirdParty/kNet/src/64BitAllocDebugger.cpp
  45. 163 10
      ThirdParty/kNet/src/DataDeserializer.cpp
  46. 249 16
      ThirdParty/kNet/src/DataSerializer.cpp
  47. 36 38
      ThirdParty/kNet/src/FragmentedTransferManager.cpp
  48. 88 88
      ThirdParty/kNet/src/MessageConnection.cpp
  49. 11 13
      ThirdParty/kNet/src/MessageListParser.cpp
  50. 80 81
      ThirdParty/kNet/src/Network.cpp
  51. 12 14
      ThirdParty/kNet/src/NetworkLogging.cpp
  52. 1 3
      ThirdParty/kNet/src/NetworkMessage.cpp
  53. 68 70
      ThirdParty/kNet/src/NetworkServer.cpp
  54. 121 0
      ThirdParty/kNet/src/NetworkSimulator.cpp
  55. 40 42
      ThirdParty/kNet/src/NetworkWorkerThread.cpp
  56. 109 110
      ThirdParty/kNet/src/SerializationStructCompiler.cpp
  57. 20 22
      ThirdParty/kNet/src/SerializedDataIterator.cpp
  58. 68 49
      ThirdParty/kNet/src/Socket.cpp
  59. 39 30
      ThirdParty/kNet/src/TCPMessageConnection.cpp
  60. 8 4
      ThirdParty/kNet/src/Thread.cpp
  61. 257 155
      ThirdParty/kNet/src/UDPMessageConnection.cpp
  62. 1 1
      ThirdParty/kNet/src/boost/BoostThread.cpp
  63. 3 2
      ThirdParty/kNet/src/qt/GraphDialog.cpp
  64. 14 1
      ThirdParty/kNet/src/qt/MessageConnectionDialog.cpp
  65. 4 2
      ThirdParty/kNet/src/qt/NetworkDialog.cpp
  66. 90 0
      ThirdParty/kNet/src/qt/NetworkSimulationDialog.cpp
  67. 1 1
      ThirdParty/kNet/src/unix/UnixClock.cpp
  68. 1 1
      ThirdParty/kNet/src/unix/UnixEvent.cpp
  69. 26 9
      ThirdParty/kNet/src/unix/UnixEventArray.cpp
  70. 2 2
      ThirdParty/kNet/src/unix/UnixThread.cpp
  71. 1 1
      ThirdParty/kNet/src/win32/W32Clock.cpp

+ 13 - 13
Engine/Network/Network.cpp

@@ -67,7 +67,7 @@ Network::~Network()
     network_ = 0;
     network_ = 0;
 }
 }
 
 
-void Network::HandleMessage(kNet::MessageConnection* source, kNet::message_id_t id, const char* data, size_t numBytes)
+void Network::HandleMessage(kNet::MessageConnection *source, kNet::packet_id_t packetId, kNet::message_id_t msgId, const char *data, size_t numBytes)
 {
 {
     // Only process messages from known sources
     // Only process messages from known sources
     Connection* connection = GetConnection(source);
     Connection* connection = GetConnection(source);
@@ -75,31 +75,31 @@ void Network::HandleMessage(kNet::MessageConnection* source, kNet::message_id_t
     {
     {
         MemoryBuffer msg(data, numBytes);
         MemoryBuffer msg(data, numBytes);
         
         
-        switch (id)
+        switch (msgId)
         {
         {
         case MSG_IDENTITY:
         case MSG_IDENTITY:
-            connection->ProcessIdentity(id, msg);
+            connection->ProcessIdentity(msgId, msg);
             return;
             return;
         
         
         case MSG_CONTROLS:
         case MSG_CONTROLS:
-            connection->ProcessControls(id, msg);
+            connection->ProcessControls(msgId, msg);
             return;
             return;
             
             
         case MSG_SCENELOADED:
         case MSG_SCENELOADED:
-            connection->ProcessSceneLoaded(id, msg);
+            connection->ProcessSceneLoaded(msgId, msg);
             return;
             return;
             
             
         case MSG_REQUESTPACKAGE:
         case MSG_REQUESTPACKAGE:
         case MSG_PACKAGEDATA:
         case MSG_PACKAGEDATA:
-            connection->ProcessPackageDownload(id, msg);
+            connection->ProcessPackageDownload(msgId, msg);
             return;
             return;
             
             
         case MSG_LOADSCENE:
         case MSG_LOADSCENE:
-            connection->ProcessLoadScene(id, msg);
+            connection->ProcessLoadScene(msgId, msg);
             return;
             return;
         
         
         case MSG_SCENECHECKSUMERROR:
         case MSG_SCENECHECKSUMERROR:
-            connection->ProcessSceneChecksumError(id, msg);
+            connection->ProcessSceneChecksumError(msgId, msg);
             return;
             return;
             
             
         case MSG_CREATENODE:
         case MSG_CREATENODE:
@@ -110,12 +110,12 @@ void Network::HandleMessage(kNet::MessageConnection* source, kNet::message_id_t
         case MSG_COMPONENTDELTAUPDATE:
         case MSG_COMPONENTDELTAUPDATE:
         case MSG_COMPONENTLATESTDATA:
         case MSG_COMPONENTLATESTDATA:
         case MSG_REMOVECOMPONENT:
         case MSG_REMOVECOMPONENT:
-            connection->ProcessSceneUpdate(id, msg);
+            connection->ProcessSceneUpdate(msgId, msg);
             return;
             return;
             
             
         case MSG_REMOTEEVENT:
         case MSG_REMOTEEVENT:
         case MSG_REMOTENODEEVENT:
         case MSG_REMOTENODEEVENT:
-            connection->ProcessRemoteEvent(id, msg);
+            connection->ProcessRemoteEvent(msgId, msg);
             return;
             return;
         }
         }
         
         
@@ -124,7 +124,7 @@ void Network::HandleMessage(kNet::MessageConnection* source, kNet::message_id_t
         
         
         VariantMap eventData;
         VariantMap eventData;
         eventData[P_CONNECTION] = (void*)connection;
         eventData[P_CONNECTION] = (void*)connection;
-        eventData[P_MESSAGEID] = (int)id;
+        eventData[P_MESSAGEID] = (int)msgId;
         eventData[P_DATA].SetBuffer(msg.GetData(), msg.GetSize());
         eventData[P_DATA].SetBuffer(msg.GetData(), msg.GetSize());
         connection->SendEvent(E_NETWORKMESSAGE, eventData);
         connection->SendEvent(E_NETWORKMESSAGE, eventData);
     }
     }
@@ -132,9 +132,9 @@ void Network::HandleMessage(kNet::MessageConnection* source, kNet::message_id_t
         LOGWARNING("Discarding message from unknown MessageConnection " + ToString((void*)source));
         LOGWARNING("Discarding message from unknown MessageConnection " + ToString((void*)source));
 }
 }
 
 
-u32 Network::ComputeContentID(kNet::message_id_t id, const char* data, size_t numBytes)
+u32 Network::ComputeContentID(kNet::message_id_t msgId, const char* data, size_t numBytes)
 {
 {
-    switch (id)
+    switch (msgId)
     {
     {
     case MSG_CONTROLS:
     case MSG_CONTROLS:
         // Return fixed content ID for controls
         // Return fixed content ID for controls

+ 2 - 2
Engine/Network/Network.h

@@ -51,9 +51,9 @@ public:
     ~Network();
     ~Network();
     
     
     /// Handle a kNet message from either a client or the server.
     /// Handle a kNet message from either a client or the server.
-    virtual void HandleMessage(kNet::MessageConnection* source, kNet::message_id_t id, const char* data, size_t numBytes);
+    virtual void HandleMessage(kNet::MessageConnection *source, kNet::packet_id_t packetId, kNet::message_id_t msgId, const char *data, size_t numBytes);
     /// Compute the content ID for a message.
     /// Compute the content ID for a message.
-    virtual u32 ComputeContentID(kNet::message_id_t id, const char* data, size_t numBytes);
+    virtual u32 ComputeContentID(kNet::message_id_t msgId, const char *data, size_t numBytes);
     /// Handle a new client connection.
     /// Handle a new client connection.
     virtual void NewConnectionEstablished(kNet::MessageConnection* connection);
     virtual void NewConnectionEstablished(kNet::MessageConnection* connection);
     /// Handle a client disconnection.
     /// Handle a client disconnection.

+ 28 - 26
ThirdParty/kNet/CMakeLists.txt

@@ -37,9 +37,14 @@ endmacro()
 #set(USE_BOOST TRUE)
 #set(USE_BOOST TRUE)
 #set(BOOST_ROOT "TODO_SpecifyYourBoostRootHereIfCMakeAutoSearchFails")
 #set(BOOST_ROOT "TODO_SpecifyYourBoostRootHereIfCMakeAutoSearchFails")
 
 
+# TinyXML is embedded to the repository, so you can safely keep this true.
+# However, it is not required for core kNet use, but only for the MessageCompiler tool, in which
+# case you can disable it here by setting USE_TINYXML to FALSE, and excluding MessageCompiler from the build.
 #set(USE_TINYXML TRUE)
 #set(USE_TINYXML TRUE)
-#set(TINYXML_ROOT "TODO_SpecifyYourTinyXMLRootHereIfUsingTinyXML")
+set(TINYXML_ROOT "src/tinyxml")
 
 
+# If you want to enable the use of visual debugging/profiling windows, uncomment the following line (must
+# have Qt installed and set up)
 #set(USE_QT TRUE)
 #set(USE_QT TRUE)
 
 
 # To enable specific flags only in debug mode, use the following syntax.
 # To enable specific flags only in debug mode, use the following syntax.
@@ -49,10 +54,13 @@ endmacro()
 # Affects only Boost threads. When native Win32 threads are used, the id is stored on creation.
 # Affects only Boost threads. When native Win32 threads are used, the id is stored on creation.
 AddCompilationDefine(KNET_ENABLE_WINXP_SUPPORT)
 AddCompilationDefine(KNET_ENABLE_WINXP_SUPPORT)
 
 
-# If set, extra code is inserted in debug mode to assert that certain thread race conditions don't occur.
-AddCompilationDefine(KNET_THREAD_CHECKING_ENABLED)
+if (NOT USE_BOOST) # USE_BOOST and KNET_THREAD_CHECKING_ENABLED are mutually exclusive, because boost::thread_id() does not work across .dll boundaries.
+   # If set, extra code is inserted in debug mode to assert that certain thread race conditions don't occur.
+   # (This can considerably slow down kNet performance)
+   #AddCompilationDefine(KNET_THREAD_CHECKING_ENABLED)
+endif()
 
 
-# Enable internal LOG messaging if this flag is enabled. Comment this out to squeeze the last bit of
+# Enable internal LOG messaging if this flag is enabled. Comment this out to squeeze the last bit of 
 # extra performance by avoiding all logging-related string operations.
 # extra performance by avoiding all logging-related string operations.
 #AddCompilationDefine(KNET_LOGGING_SUPPORT_ENABLED)
 #AddCompilationDefine(KNET_LOGGING_SUPPORT_ENABLED)
 
 
@@ -76,17 +84,17 @@ if (USE_BOOST)
    endif()
    endif()
 endif()
 endif()
 
 
+file(GLOB kNetSourceFiles ./src/*.cpp)
+file(GLOB kNetHeaderFiles ./include/*.h ./include/kNet/*.h ./include/kNet/*.inl)
+
 if (USE_TINYXML)
 if (USE_TINYXML)
    AddCompilationDefine(KNET_USE_TINYXML)
    AddCompilationDefine(KNET_USE_TINYXML)
    
    
+   file(GLOB TinyXmlSourceFiles ${TINYXML_ROOT}/*.cpp)
+   set(kNetSourceFiles ${kNetSourceFiles} ${TinyXmlSourceFiles})
    include_directories(${TINYXML_ROOT})
    include_directories(${TINYXML_ROOT})
-   link_directories(${TINYXML_ROOT})
-   link_directories(${TINYXML_ROOT}/Release)
 endif()
 endif()
 
 
-file(GLOB kNetSourceFiles ./src/*.cpp)
-file(GLOB kNetHeaderFiles ./include/*.h ./include/kNet/*.h ./include/kNet/*.inl)
-
 if (USE_QT)
 if (USE_QT)
    AddCompilationDefine(KNET_USE_QT)
    AddCompilationDefine(KNET_USE_QT)
    
    
@@ -157,33 +165,28 @@ elseif (UNIX)
 
 
    set(kNetSourceFiles ${kNetSourceFiles} ${kNetUnixSourceFiles})
    set(kNetSourceFiles ${kNetSourceFiles} ${kNetUnixSourceFiles})
    set(kNetHeaderFiles ${kNetHeaderFiles} ${kNetUnixHeaderFiles})
    set(kNetHeaderFiles ${kNetHeaderFiles} ${kNetUnixHeaderFiles})
+
+   add_definitions(-DUNIX)
 endif()
 endif()
 
 
 #AddCompilationUnitNameDefines(kNetSourceFiles)
 #AddCompilationUnitNameDefines(kNetSourceFiles)
 #TODO: To clean up, move the lines of code below into a macro, like shown above. Disabled for now since passing a list to a CMake macro was problematic.
 #TODO: To clean up, move the lines of code below into a macro, like shown above. Disabled for now since passing a list to a CMake macro was problematic.
-# Urho3D: use only on Windows
-if (WIN32)
-   foreach(srcFile ${kNetSourceFiles})
-      get_filename_component(baseName ${srcFile} NAME)
-      set_source_files_properties(${srcFile} PROPERTIES COMPILE_FLAGS "-DDEBUG_CPP_NAME=\"\\\"${baseName}\"\\\"")
-   endforeach()
-endif()
+foreach(srcFile ${kNetSourceFiles})
+   get_filename_component(baseName ${srcFile} NAME)
+   set_source_files_properties(${srcFile} PROPERTIES COMPILE_FLAGS "-DDEBUG_CPP_NAME=\"\\\"${baseName}\"\\\"")
+endforeach()
 
 
 add_library(kNet STATIC ${kNetSourceFiles} ${kNetHeaderFiles})
 add_library(kNet STATIC ${kNetSourceFiles} ${kNetHeaderFiles})
 
 
-if (USE_TINYXML)
-   target_link_libraries(kNet debug tinyxmld.lib optimized tinyxml.lib)
-endif()
-
 # Add the main kNet include directory root folder to all projects.
 # Add the main kNet include directory root folder to all projects.
 include_directories(./include)
 include_directories(./include)
 
 
-# Urho3D: add the Container library
-include_directories(../../Engine/Container)
-set(kNetLinkLibraries ${kNetLinkLibraries} Container)
-
 if (USE_BOOST)
 if (USE_BOOST)
-   find_package(Boost 1.38.0 COMPONENTS thread)
+   if (WIN32)
+      find_package(Boost 1.38.0 COMPONENTS thread)
+   else()
+      find_package(Boost)
+   endif()
    if (Boost_FOUND)
    if (Boost_FOUND)
       include_directories(${Boost_INCLUDE_DIRS})
       include_directories(${Boost_INCLUDE_DIRS})
       link_directories(${Boost_LIBRARY_DIRS})
       link_directories(${Boost_LIBRARY_DIRS})
@@ -210,4 +213,3 @@ target_link_libraries(kNet ${kNetLinkLibraries})
 
 
 #add_subdirectory(tests)
 #add_subdirectory(tests)
 
 
-#set_target_properties(kNet Tests ConnectFlood FileTransfer FirewallTest HelloClient HelloServer LatencyTest MessageCompiler SilenceTest SimpleChat SpeedTest TrashTalk PROPERTIES 

+ 24 - 24
ThirdParty/kNet/README.txt

@@ -3,42 +3,42 @@
 kNet is a low-level networking protocol library designed for bit-efficient realtime streaming of custom application-specified messages on top of TCP or UDP. kNet is written in C++.
 kNet is a low-level networking protocol library designed for bit-efficient realtime streaming of custom application-specified messages on top of TCP or UDP. kNet is written in C++.
 
 
 
 
-
    Supported Platforms.
    Supported Platforms.
 
 
 kNet has been tested to build on the following platforms:
 kNet has been tested to build on the following platforms:
  - Windows 7 & Visual Studio 2010 Professional
  - Windows 7 & Visual Studio 2010 Professional
  - Windows 7 & Visual Studio 2008 Standard
  - Windows 7 & Visual Studio 2008 Standard
  - Ubuntu 9.04 & GCC 4.4.1
  - Ubuntu 9.04 & GCC 4.4.1
-
-
-
+ - Windows 7 & MinGW GCC 4.6.1 versioned 20111118 (beware though, MinGW is not actively supported)
+
+ 
+   Documentation.
+ 
+kNet uses doxygen to generate its documentation. See the web page http://clb.demon.fi/knet/ for an online hosted copy.
+ 
+ 
    Building kNet.
    Building kNet.
 
 
 kNet uses cmake (2.6 or newer) as its build system. On Linux it can use pthreads or boost v1.38.0 or newer for threading support. On Windows a CMake flag USE_BOOST can be used to specify whether to depend on boost or not. By default USE_BOOST is on.
 kNet uses cmake (2.6 or newer) as its build system. On Linux it can use pthreads or boost v1.38.0 or newer for threading support. On Windows a CMake flag USE_BOOST can be used to specify whether to depend on boost or not. By default USE_BOOST is on.
 
 
-Windows:
- - Install cmake. 
- - Optional: Install and build Boost. Edit the root CMakeLists.txt to specify the source directory to boost path.
- - If you do not want to use Boost, edit the root CMakeLists.txt and comment out the USE_BOOST directive.
- - Optional: Download and install TinyXML. In TinyXML configuration, adjust the CRT runtimes to use the DLL versions. In the root CMakeLists.txt, uncomment #set(USE_TINYXML) and change TINYXML_ROOT to point to the TinyXML path.
- - If you do not want to use TinyXML, edit the root CMakeLists.txt and make sure the USE_TINYXML directive is commented out. This will disable the functionality of SerializedMessageList/MessageListParser though. 
- - Optional: kNet can use Qt to provider debug statistics and profiling windows. Install and build Qt (4.6.2 or newer recommended) and uncomment #set(USE_QT TRUE) in the root CMakeLists.txt.
- - Execute in project root folder the command 'cmake -G "Visual Studio 10"' (case sensitive!), or click the cmake_vs2010.bat.
- - If CMake fails to find your Qt installation, or if you want to explicitly specify the source location, set the QMAKESPEC and QTDIR environment variables or alter the cmake_vs2008.bat/cmake_vs2010.bat files.
- - Open and build the kNet.sln.
-
-Linux:
- - Install Boost libraries and cmake.
- - If you want to use TinyXML, manually specify the TinyXML source directory to root CMakeLists.txt. Otherwise, comment out the USE_TINYXML directive.
- - If you want to use Qt, make sure USE_QT is defined in the root CMakeLists.txt. Otherwise, comment out that directive.
- - run 'cmake .' in kNet root folder.
- - run 'make'.
+kNet can optionally use Qt to provide a debugging and statistics window for profiling and simulation of different network conditions.
+
+Steps:
+ 1. Install cmake. 
+ 2a. Optional: Install and build Boost. Edit the root CMakeLists.txt to specify the source directory to boost path.
+ 2b. If you do not want to use Boost, edit the root CMakeLists.txt and comment out the USE_BOOST directive. If Boost is not used, kNet will utilize native threading APIs on each platform (WIN32 CreateThread or POSIX threads). There are no functional differences with using either.
+ 3. Optional: If you do not want to use TinyXML, edit the root CMakeLists.txt and make sure the USE_TINYXML directive is commented out. This will disable the functionality of SerializedMessageList/MessageListParser though. 
+ 4. Optional: kNet can use Qt to provider debug statistics and profiling windows. Install and build Qt (4.6.2 or newer recommended) and uncomment #set(USE_QT TRUE) in the root CMakeLists.txt.
+ 5a. Windows VS2008: Execute in project root folder the command 'cmake -G "Visual Studio 9"' (case sensitive!), or click on the cmake_vs2008.bat.
+ 5b. Windows VS2010: Execute in project root folder the command 'cmake -G "Visual Studio 10"' (case sensitive!), or click on the cmake_vs2010.bat.
+ 5c. Linux and Mac: Run 'cmake .' in kNet root folder.
+ 6. If CMake fails to find your Qt installation, or if you want to explicitly specify the source location, set the QMAKESPEC and QTDIR environment variables or alter the cmake_vs2008.bat/cmake_vs2010.bat files.
+ 7a. Windows: Open and build the kNet.sln.
+ 7b. Linux and Mac: Run 'make'.
 
 
 The project output files are placed in the directory kNet/lib.
 The project output files are placed in the directory kNet/lib.
 
 
 
 
-
    Contributors.
    Contributors.
 
 
 The following people have contributed to the project:
 The following people have contributed to the project:
@@ -53,9 +53,9 @@ The following people have contributed to the project:
    Kari Vatjus-Anttila
    Kari Vatjus-Anttila
    Lasse Öörni
    Lasse Öörni
 
 
-
-
+   
    Links.
    Links.
 
 
+The kNet repository is hosted at github: https://github.com/juj/kNet. Please report bugs using the github issue tracker.
 There exists a Wireshark dissector plugin for kNet: http://chiru.cie.fi/chiru-sharedfolder/knet-tundra-v.0.0.8.tar.gz .
 There exists a Wireshark dissector plugin for kNet: http://chiru.cie.fi/chiru-sharedfolder/knet-tundra-v.0.0.8.tar.gz .
 A SCTP -enabled branch of kNet is being developed at https://bitbucket.org/karivatj/knet-sctp/ .
 A SCTP -enabled branch of kNet is being developed at https://bitbucket.org/karivatj/knet-sctp/ .

+ 31 - 0
ThirdParty/kNet/WHATSNEW.txt

@@ -0,0 +1,31 @@
+Version 2.7, 2012-03-23
+-----------
+- Added new InOrderTest sample.
+- Added support for duplicating datagrams in NetworkSimulator.
+- Fixed a bug in duplicated message receive handling.
+- Added support for corrupting datagrams in NetworkSimulator.
+- Added support for 64-bit memory pointer to 32-bit splicing issue detecting for Windows.
+- Removed KNET_THREAD_CHECKING_ENABLED from being enabled if USE_BOOST is enabled. This is to avoid a bug with boost::thread_id() not working across dynamic library boundaries. (KNET_THREAD_CHECKING_ENABLED and USE_BOOST are now mutually exclusive)
+
+Version 2.6, 2012-01-25
+-----------
+- Implement a NetworkSimulator middle layer for adding delays and packet loss to outbound messaging (UDP only).
+- Enhance DataSerializer with new data types:
+   - lossy quantized floats
+   - minifloats
+   - arithmetic encoding
+   - linear algebra types: quaternion, vector, spherical direction vectors with or without magnitude
+- Incorporate TinyXML inside kNet repository, to avoid requiring extra configuration.
+- Pass UDP datagram packet ID to client code for manual client-side latest-data-guarantee checks.
+- Enable build on MinGW GCC 4.6.1 version 20111118.
+- Bug fixes.
+
+Version 2.5, 2012-01-02
+-----------
+- Fix build on Mac.
+- Performance improvements.
+- Added pthreads support for linux and Mac. Thanks to Lasse Öörni for the implementation.
+- Improved networking statistics window display.
+- Bug fixes.
+
+For history on older kNet versions, see the repository history at github.

+ 1 - 0
ThirdParty/kNet/include/kNet.h

@@ -52,6 +52,7 @@
 #include "kNet/Types.h"
 #include "kNet/Types.h"
 #include "kNet/VLEPacker.h"
 #include "kNet/VLEPacker.h"
 #include "kNet/WaitFreeQueue.h"
 #include "kNet/WaitFreeQueue.h"
+#include "kNet/64BitAllocDebugger.h"
 
 
 #ifdef KNET_USE_QT
 #ifdef KNET_USE_QT
 #include "kNet/qt/NetworkDialog.h"
 #include "kNet/qt/NetworkDialog.h"

+ 46 - 0
ThirdParty/kNet/include/kNet/64BitAllocDebugger.h

@@ -0,0 +1,46 @@
+/* Copyright The kNet Project.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. */
+#pragma once
+
+/** @file 64BitAllocDebugger.h
+	@brief Virtually reserves all memory on Windows in the < 4GB memory area so that all
+		pointers used by the application are outside the 32-bit range.
+	
+	Idea and code taken from http://randomascii.wordpress.com/2012/02/14/64-bit-made-easy/ */
+
+#ifdef _WIN64
+
+#include <vector>
+
+class BottomMemoryAllocator
+{
+public:
+	BottomMemoryAllocator();
+
+	~BottomMemoryAllocator();
+
+	std::vector<void *> virtualAllocated;
+	std::vector<void *> heapAllocated;
+	std::vector<void *> mallocAllocated;
+
+	void ReserveBottomMemory();
+	void FreeBottomMemory();
+};
+
+#else
+
+/// On other platforms than 64-bit Windows, this debugging feature is not enabled.
+class BottomMemoryAllocator {};
+
+#endif

+ 3 - 5
ThirdParty/kNet/include/kNet/BasicSerializedDataTypes.h

@@ -16,10 +16,8 @@
 /** @file BasicSerializedDataTypes.h
 /** @file BasicSerializedDataTypes.h
 	@brief Describes the basic POD data types that are used by the DataSerializer and DataDeserializer objects. */
 	@brief Describes the basic POD data types that are used by the DataSerializer and DataDeserializer objects. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
-#include "List.h"
-#include "Str.h"
+#include <list>
+#include <string>
 
 
 #include "Types.h"
 #include "Types.h"
 
 
@@ -87,6 +85,6 @@ template<> struct SerializedDataTypeTraits<float> { static const BasicSerialized
 template<> struct SerializedDataTypeTraits<double> { static const BasicSerializedDataType type = SerialDouble; static const int bitSize = 64; };
 template<> struct SerializedDataTypeTraits<double> { static const BasicSerializedDataType type = SerialDouble; static const int bitSize = 64; };
 template<> struct SerializedDataTypeTraits<char*> { static const BasicSerializedDataType type = SerialString; static const int bitSize = 0; };
 template<> struct SerializedDataTypeTraits<char*> { static const BasicSerializedDataType type = SerialString; static const int bitSize = 0; };
 template<> struct SerializedDataTypeTraits<const char*> { static const BasicSerializedDataType type = SerialString; static const int bitSize = 0; };
 template<> struct SerializedDataTypeTraits<const char*> { static const BasicSerializedDataType type = SerialString; static const int bitSize = 0; };
-template<> struct SerializedDataTypeTraits<String> { static const BasicSerializedDataType type = SerialString; static const int bitSize = 0; };
+template<> struct SerializedDataTypeTraits<std::string> { static const BasicSerializedDataType type = SerialString; static const int bitSize = 0; };
 
 
 } // ~kNet
 } // ~kNet

+ 23 - 6
ThirdParty/kNet/include/kNet/DataDeserializer.h

@@ -16,8 +16,6 @@
 /** @file DataDeserializer.h
 /** @file DataDeserializer.h
 	@brief The class \ref kNet::DataDeserializer DataDeserializer. */
 	@brief The class \ref kNet::DataDeserializer DataDeserializer. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include "kNetBuildConfig.h"
 #include "kNetBuildConfig.h"
 #include "kNet/Types.h"
 #include "kNet/Types.h"
 
 
@@ -82,12 +80,31 @@ public:
 	/// The returned string will only contain ascii values in the range [32, 253], 0x0D, 0x0A, 0x09. Other values will 
 	/// The returned string will only contain ascii values in the range [32, 253], 0x0D, 0x0A, 0x09. Other values will 
 	/// be replaced with a space bar character (0x20). Because of this string validation method, do not use this function
 	/// be replaced with a space bar character (0x20). Because of this string validation method, do not use this function
 	/// to extract binary data of any kind (base64-encoded is fine).
 	/// to extract binary data of any kind (base64-encoded is fine).
-	String ReadString();
+	std::string ReadString();
 
 
 	/// Reads the given amount of bits and packs them into a u32, which is returned.
 	/// Reads the given amount of bits and packs them into a u32, which is returned.
 	/// @param numBits the number of bits to read, [1, 32].
 	/// @param numBits the number of bits to read, [1, 32].
 	u32 ReadBits(int numBits);
 	u32 ReadBits(int numBits);
 
 
+	float ReadUnsignedFixedPoint(int numIntegerBits, int numDecimalBits);
+
+	float ReadSignedFixedPoint(int numIntegerBits, int numDecimalBits);
+
+	float ReadQuantizedFloat(float minRange, float maxRange, int numBits);
+
+	float ReadMiniFloat(bool signBit, int exponentBits, int mantissaBits, int exponentBias);
+
+	void ReadNormalizedVector2D(int numBits, float &x, float &y);
+
+	void ReadVector2D(int magnitudeIntegerBits, int magnitudeDecimalBits, int directionBits, float &x, float &y);
+	void ReadNormalizedVector3D(int numBitsYaw, int numBitsPitch, float &x, float &y, float &z);
+	void ReadVector3D(int numBitsYaw, int numBitsPitch, int magnitudeIntegerBits, int magnitudeDecimalBits, float &x, float &y, float &z);
+
+	void ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2);
+	void ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2, int &val3, int max3);
+	void ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2, int &val3, int max3, int &val4, int max4);
+	void ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2, int &val3, int max3, int &val4, int max4, int &val5, int max5);
+
 	u32 GetDynamicElemCount();
 	u32 GetDynamicElemCount();
 
 
 	/// @return The number of bytes left in the stream to read.
 	/// @return The number of bytes left in the stream to read.
@@ -109,10 +126,10 @@ public:
 	const char *CurrentData() const { return data + BytePos(); }
 	const char *CurrentData() const { return data + BytePos(); }
 
 
 	/// Advances the read pointer with the given amount of bits. Can only be used in nontemplate read mode.
 	/// Advances the read pointer with the given amount of bits. Can only be used in nontemplate read mode.
-	void SkipBits(size_t numBits);
+	void SkipBits(int numBits);
 
 
 	/// Advances the read pointer with the given amount of bytes. Can only be used in nontemplate read mode.
 	/// Advances the read pointer with the given amount of bytes. Can only be used in nontemplate read mode.
-	void SkipBytes(size_t numBytes) { SkipBits(numBytes * 8); }
+	void SkipBytes(int numBytes) { SkipBits(numBytes * 8); }
 
 
 private:
 private:
 	/// The data pointer to read from.
 	/// The data pointer to read from.
@@ -148,7 +165,7 @@ T DataDeserializer::Read()
 	return value;
 	return value;
 }
 }
 
 
-template<> String DataDeserializer::Read<String>();
+template<> std::string DataDeserializer::Read<std::string>();
 
 
 template<> bool DataDeserializer::Read<bit>();
 template<> bool DataDeserializer::Read<bit>();
 
 

+ 133 - 18
ThirdParty/kNet/include/kNet/DataSerializer.h

@@ -16,11 +16,9 @@
 /** @file DataSerializer.h
 /** @file DataSerializer.h
 	@brief The class \ref kNet::DataSerializer DataSerializer. Stores POD data to bit streams. */
 	@brief The class \ref kNet::DataSerializer DataSerializer. Stores POD data to bit streams. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
+#include <vector>
 #include <cassert>
 #include <cassert>
-
-#include "Str.h"
+#include <string>
 
 
 #include "kNetBuildConfig.h"
 #include "kNetBuildConfig.h"
 #include "kNet/SharedPtr.h"
 #include "kNet/SharedPtr.h"
@@ -36,7 +34,7 @@ namespace kNet
 
 
 struct SerializedMessage : public RefCountable
 struct SerializedMessage : public RefCountable
 {
 {
-	PODVector<char> data;
+	std::vector<char> data;
 };
 };
 
 
 /// DataSerializer is a helper class that can be used to serialize data types to a stream of raw bits 
 /// DataSerializer is a helper class that can be used to serialize data types to a stream of raw bits 
@@ -61,15 +59,15 @@ public:
 
 
 	/// Instantiates a new DataSerializer that writes to the given vector. 
 	/// Instantiates a new DataSerializer that writes to the given vector. 
 	/// @param maxBytes The maximum number of bytes that the message can take up space.
 	/// @param maxBytes The maximum number of bytes that the message can take up space.
-	explicit DataSerializer(PODVector<char> &data, size_t maxBytes);
+	explicit DataSerializer(std::vector<char> &data, size_t maxBytes);
 
 
 	/// Instantiates a new DataSerializer that writes to the given vector, using a message template. 
 	/// Instantiates a new DataSerializer that writes to the given vector, using a message template. 
 	/// @param maxBytes The maximum number of bytes that the message can take up space.
 	/// @param maxBytes The maximum number of bytes that the message can take up space.
-	DataSerializer(PODVector<char> &data, size_t maxBytes, const SerializedMessageDesc *msgTemplate);
+	DataSerializer(std::vector<char> &data, size_t maxBytes, const SerializedMessageDesc *msgTemplate);
 
 
 	/// Appends a single element of the passed type. If you are using a serialization template to
 	/// Appends a single element of the passed type. If you are using a serialization template to
 	/// aid in serialization, the type T may be any of the types bit, u8, s8, u16, s16, u32, s32, u64, s64, float, double, 
 	/// aid in serialization, the type T may be any of the types bit, u8, s8, u16, s16, u32, s32, u64, s64, float, double, 
-	/// const char * or String.
+	/// const char * or std::string.
 	/// If you are not using a serialization template, you may pass in any type that is a POD type and can be reinterpret_casted
 	/// If you are not using a serialization template, you may pass in any type that is a POD type and can be reinterpret_casted
 	/// to a u8 buffer and memcpy'd to a byte buffer.
 	/// to a u8 buffer and memcpy'd to a byte buffer.
 	template<typename T>
 	template<typename T>
@@ -80,15 +78,15 @@ public:
 
 
 	/// Appends the given number of bits to the stream.
 	/// Appends the given number of bits to the stream.
 	/// @param value The variable where the bits are taken from. The bits are read from the LSB first, towards the MSB end of the value.
 	/// @param value The variable where the bits are taken from. The bits are read from the LSB first, towards the MSB end of the value.
-	/// @param amount The number of bits to read, in the range [1, 32].
-	void AppendBits(u32 value, int amount);
+	/// @param numBits The number of bits to write, in the range [1, 32].
+	void AppendBits(u32 value, int numBits);
 
 
 	/// Adds a given string as length-prepended (not zero-padded). In the message template, use a
 	/// Adds a given string as length-prepended (not zero-padded). In the message template, use a
 	/// parameter of type 's8' with dynamicCount field set to e.g. 8.
 	/// parameter of type 's8' with dynamicCount field set to e.g. 8.
 	void AddString(const char *str);
 	void AddString(const char *str);
 
 
 	/// See \ref void kNet::DataSerializer::AddString(const char *str); "".
 	/// See \ref void kNet::DataSerializer::AddString(const char *str); "".
-	void AddString(const String &str) { AddString(str.CString()); }
+	void AddString(const std::string &str) { AddString(str.c_str()); }
 
 
 	/// Appends the given amount of elements from the passed array.
 	/// Appends the given amount of elements from the passed array.
 	template<typename T>
 	template<typename T>
@@ -98,6 +96,111 @@ public:
 	/// this function. A serialization template may not be used when calling this function.
 	/// this function. A serialization template may not be used when calling this function.
 	void AddAlignedByteArray(const void *data, u32 numBytes);
 	void AddAlignedByteArray(const void *data, u32 numBytes);
 
 
+	/// Writes the given non-negative float quantized to the given fixed-point precision.
+	/// @param value The floating-point value to send. This float must have a value in the range [0, 2^numIntegerBits[.
+	/// @param numIntegerBits The number of bits to use to represent the integer part.
+	/// @param numDecimalBits The number of bits to use to represent the fractional part.
+	/// @note Before writing the value, it is clamped to range specified above to ensure that the written value does not
+	///	 result in complete garbage due to over/underflow.
+	/// @note The total number of bits written is numIntegerBits + numDecimalBits, which must in total be <= 32.
+	/// @return The bit pattern that was written to the buffer.
+	u32 AddUnsignedFixedPoint(int numIntegerBits, int numDecimalBits, float value);
+
+	/// Writes the given float quantized to the given fixed-point precision.
+	/// @param value The floating-point value to send. This float must have a value in the range [-2^(numIntegerBits-1), 2^(numIntegerBits-1)[.
+	/// @param numIntegerBits The number of bits to use to represent the integer part.
+	/// @param numDecimalBits The number of bits to use to represent the fractional part.
+	/// @note Before writing the value, it is clamped to range specified above to ensure that the written value does not
+	///	 result in complete garbage due to over/underflow.
+	/// @note The total number of bits written is numIntegerBits + numDecimalBits, which must in total be <= 32.
+	/// @return The bit pattern that was written to the buffer.
+	u32 AddSignedFixedPoint(int numIntegerBits, int numDecimalBits, float value);
+
+	/// Writes the given float quantized to the number of bits, that are distributed evenly over the range [minRange, maxRange].
+	/// @param value The floating-point value to send. This float must have a value in the range [minRange, maxRange].
+	/// @param numBits The number of bits to use for representing the value. The total number of different values written is then 2^numBits, 
+	///	 which are evenly distributed across the range [minRange, maxRange]. The value numBits must satisfy 1 <= numBits <= 30.
+	/// @param minRange The lower limit for the value that is being written.
+	/// @param maxRange The upper limit for the value that is being written.
+	/// @return The bit pattern that was written to the buffer.
+	/// @note This function performs quantization, which results in lossy serialization/deserialization.
+	u32 AddQuantizedFloat(float minRange, float maxRange, int numBits, float value);
+
+	/// Writes the given float with a reduced amount of bit precision.
+	/// @param signBit If true, a signed float is written (one bit is reserved for sign-magnitude representation).
+	///                If false, an unsigned float is written. Negative numbers clamp to zero (-inf -> zero as well).
+	/// @param exponentBits The number of bits to use to store the exponent value, in the range [1, 8].
+	/// @param mantissaBits The number of bits to use to store the mantissa value, in the range [1, 23].
+	/// @param exponentBias For IEEE-754 floats, the signed exponent is converted to unsigned number by adding an offset bias.
+	///                This field specifies the bias to use. Usually it is ok to reserve the equal number of exponent values
+	///                for negative and positive exponents, meaning that exponentBias == (1 << (exponentBits - 1)) - 1 is an ok default.
+	/// @param value The floating point number to encode.
+	/// @note This function performs quantization, which results in lossy serialization/deserialization.
+	/// @note An example for 8-bit minifloats: signBit==true, exponentBits==3, mantissaBits==4, exponentBias==3.
+	/// @note IEEE-754 16-bit 'half16': signBit==true, exponentBits==5, mantissaBits==10, exponentBias==15.
+	///       See http://en.wikipedia.org/wiki/Half_precision_floating-point_format
+	/// @note IEEE-754 32-bit floats: signBit==true, exponentBits==8, mantissaBits==23, exponentBias==127.
+	void AddMiniFloat(bool signBit, int exponentBits, int mantissaBits, int exponentBias, float value);
+
+	/// Writes the given normalized 2D vector compressed to a single 1D polar angle value. Then the angle is quantized to the specified 
+	/// precision.
+	/// @param x The x coordinate of the 2D vector.
+	/// @param y The y coordinate of the 2D vector.
+	/// @param numBits The number of bits to quantize the representation down to. This value must satisfy 1 <= numBits <= 30.
+	/// @note The vector (x,y) does not need to be normalized for this function to work properly (don't bother enforcing normality in
+	///	advance prior to calling this). When deserializing, (x,y) is reconstructed as a normalized direction vector.
+	/// @note Do not call this function with (x,y) == (0,0).
+	/// @note This function performs quantization, which results in lossy serialization/deserialization.
+	void AddNormalizedVector2D(float x, float y, int numBits);
+
+	/// Writes the given 2D vector in polar form and quantized to the given precision.
+	/// The length of the 2D vector is stored as fixed-point in magnitudeIntegerBits.magnitudeDecimalBits format.
+	/// The direction of the 2D vector is stores with directionBits.
+	/// @param x The x coordinate of the 2D vector.
+	/// @param y The y coordinate of the 2D vector.
+	/// @param magnitudeIntegerBits The number of bits to use for the integral part of the vector's length. This means
+	///	 that the maximum length of the vector to be written by this function is < 2^magnitudeIntegerBits.
+	/// @param magnitudeDecimalBits The number of bits to use for the fractional part of the vector's length.
+	/// @param directionBits The number of bits of precision to use for storing the direction of the 2D vector.
+	/// @return The number of bits written to the stream.
+	/// @important This function does not write a fixed amount of bits to the stream, but omits the direction if the length is zero. 
+	///	 Therefore only use DataDeserializer::ReadVector2D to extract the vector from the buffer.
+	int AddVector2D(float x, float y, int magnitudeIntegerBits, int magnitudeDecimalBits, int directionBits);
+
+	/// Writes the given normalized 3D vector converted to spherical form (azimuth/yaw, inclination/pitch) and quantized to the specified range.
+	/// The given vector (x,y,z) must be normalized in advance.
+	/// @param numBitsYaw The number of bits to use for storing the azimuth/yaw part of the vector.
+	/// @param numBitsPitch The number of bits to use for storing the inclination/pitch part of the vector.
+	/// @note After converting the euclidean (x,y,z) to spherical (yaw, pitch) format, the yaw value is expressed in the range [-pi, pi] and pitch
+	///	 is expressed in the range [-pi/2, pi/2]. Therefore, to maintain consistent precision, the condition numBitsYaw == numBitsPitch + 1 
+	///	 should hold. E.g. If you specify 8 bits for numBitsPitch, then you should specify 9 bits for numBitsYaw to have yaw & pitch use the same
+	///	 amount of precision.
+	/// @note This function uses the convention that the +Y axis points towards up, i.e. +Y is the "Zenith direction", and the X-Z plane is the horizontal
+	///	 "map" plane.
+	void AddNormalizedVector3D(float x, float y, float z, int numBitsYaw, int numBitsPitch);
+
+	/// Writes the given 3D vector converted to spherical form (azimuth/yaw, inclination/pitch, length) and quantized to the specified range.
+	/// @param numBitsYaw The number of bits to use for storing the azimuth/yaw part of the vector.
+	/// @param numBitsPitch The number of bits to use for storing the inclination/pitch part of the vector.
+	/// @param magnitudeIntegerBits The number of bits to use for the integral part of the vector's length. This means
+	///	 that the maximum length of the vector to be written by this function is < 2^magnitudeIntegerBits.
+	/// @param magnitudeDecimalBits The number of bits to use for the fractional part of the vector's length.
+	/// @return The number of bits written to the stream.
+	/// @important This function does not write a fixed amount of bits to the stream, but omits the direction if the length is zero. 
+	///	 Therefore only use DataDeserializer::ReadVector3D to extract the vector from the buffer.
+	/// @note After converting the euclidean (x,y,z) to spherical (yaw, pitch) format, the yaw value is expressed in the range [-pi, pi] and pitch
+	///	 is expressed in the range [-pi/2, pi/2]. Therefore, to maintain consistent precision, the condition numBitsYaw == numBitsPitch + 1 
+	///	 should hold. E.g. If you specify 8 bits for numBitsPitch, then you should specify 9 bits for numBitsYaw to have yaw & pitch use the same
+	///	 amount of precision.
+	/// @note This function uses the convention that the +Y axis points towards up, i.e. +Y is the "Zenith direction", and the X-Z plane is the horizontal
+	///	 "map" plane.
+	int AddVector3D(float x, float y, float z, int numBitsYaw, int numBitsPitch, int magnitudeIntegerBits, int magnitudeDecimalBits);
+
+	void AddArithmeticEncoded(int numBits, int val1, int max1, int val2, int max2);
+	void AddArithmeticEncoded(int numBits, int val1, int max1, int val2, int max2, int val3, int max3);
+	void AddArithmeticEncoded(int numBits, int val1, int max1, int val2, int max2, int val3, int max3, int val4, int max4);
+	void AddArithmeticEncoded(int numBits, int val1, int max1, int val2, int max2, int val3, int max3, int val4, int max4, int val5, int max5);
+
 	/// Sets the number of instances in a varying element.
 	/// Sets the number of instances in a varying element.
 	void SetVaryingElemSize(u32 count);
 	void SetVaryingElemSize(u32 count);
 
 
@@ -115,7 +218,7 @@ public:
 	/// @return The number of bits filled so far total.
 	/// @return The number of bits filled so far total.
 	size_t BitsFilled() const { return elemOfs * 8 + bitOfs; }
 	size_t BitsFilled() const { return elemOfs * 8 + bitOfs; }
 
 
-	/// @return The total capacity of the buffer we are filling into.
+	/// @return The total capacity of the buffer we are filling into, in bytes.
 	size_t Capacity() const { return maxBytes; }
 	size_t Capacity() const { return maxBytes; }
 
 
 	/// Returns the current byte offset the DataSerializer is writing to.
 	/// Returns the current byte offset the DataSerializer is writing to.
@@ -124,6 +227,18 @@ public:
 	/// Returns the current bit offset in the current byte this DataSerializer is writing to, [0, 7].
 	/// Returns the current bit offset in the current byte this DataSerializer is writing to, [0, 7].
 	size_t BitOffset() const { return bitOfs; }
 	size_t BitOffset() const { return bitOfs; }
 
 
+    /// Returns the total number of bits that can still be serialized into this DataSerializer object before overflowing (which throws an exception).
+    size_t BitsLeft() const { return Capacity()*8 - BitsFilled(); }
+
+    /// Returns the total number of full bytes that can still be serialized into this DataSerializer object before overflowing (which throws an exception).
+    /// @return floor(BitsLeft()/8).
+    size_t BytesLeft() const { return BitsLeft() / 8; }
+
+	/// Returns the bit serialized at the given bit index of this buffer.
+	bool DebugReadBit(int bitIndex) const;
+
+	/// Returns a string of 0's and 1's corresponding to the given bit indices.
+	std::string DebugReadBits(int startIndex, int endIndex) const;
 private:
 private:
 	void AppendByte(u8 byte);
 	void AppendByte(u8 byte);
 	void AppendUnalignedByte(u8 byte);
 	void AppendUnalignedByte(u8 byte);
@@ -168,7 +283,7 @@ void DataSerializer::Add(const T &value)
 
 
 template<> void DataSerializer::Add<char*>(char * const & value);
 template<> void DataSerializer::Add<char*>(char * const & value);
 template<> void DataSerializer::Add<const char*>(const char * const & value);
 template<> void DataSerializer::Add<const char*>(const char * const & value);
-template<> void DataSerializer::Add<String>(const String &value);
+template<> void DataSerializer::Add<std::string>(const std::string &value);
 
 
 template<> void DataSerializer::Add<bit>(const bit &value);
 template<> void DataSerializer::Add<bit>(const bit &value);
 
 
@@ -252,15 +367,15 @@ public:
 };
 };
 
 
 template<>
 template<>
-class TypeSerializer<String>
+class TypeSerializer<std::string>
 {
 {
 public:
 public:
-	static size_t Size(const String &value)
+	static size_t Size(const std::string &value)
 	{
 	{
-		return value.Length()+1;
+		return value.length()+1;
 	}
 	}
 
 
-	static void SerializeTo(DataSerializer &dst, const String &src)
+	static void SerializeTo(DataSerializer &dst, const std::string &src)
 	{
 	{
 #ifdef _DEBUG
 #ifdef _DEBUG
 		size_t bitPos = dst.BitsFilled();
 		size_t bitPos = dst.BitsFilled();
@@ -271,7 +386,7 @@ public:
 #endif
 #endif
 	}
 	}
 
 
-	static void DeserializeFrom(DataDeserializer &src, String &dst)
+	static void DeserializeFrom(DataDeserializer &src, std::string &dst)
 	{
 	{
 		dst = src.ReadString();
 		dst = src.ReadString();
 	}
 	}

+ 5 - 8
ThirdParty/kNet/include/kNet/DebugMemoryLeakCheck.h

@@ -16,19 +16,16 @@
 /** @file DebugMemoryLeakCheck.h
 /** @file DebugMemoryLeakCheck.h
 	@brief Provides overloads of operators new and delete for tracking memory leaks. */
 	@brief Provides overloads of operators new and delete for tracking memory leaks. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #if defined (WIN32) && defined(_DEBUG) && defined(KNET_MEMORY_LEAK_CHECK)
 #if defined (WIN32) && defined(_DEBUG) && defined(KNET_MEMORY_LEAK_CHECK)
 
 
 #include <new>
 #include <new>
 #include <crtdbg.h>
 #include <crtdbg.h>
 
 
-// Include these files beforehand to avoid compilation errors from our operator new redefine.
-#include <ios>
-#include "List.h"
-#include "Map.h"
-#include "Set.h"
-#include "Vector.h"
+// On MSVC2008, include these files beforehand to avoid compilation errors from our operator new redefine.
+#if _MSC_VER == 1500
+#include <ios> 
+#include <map>
+#endif
 
 
 #ifndef _CRTDBG_MAP_ALLOC
 #ifndef _CRTDBG_MAP_ALLOC
 #define _CRTDBG_MAP_ALLOC
 #define _CRTDBG_MAP_ALLOC

+ 5 - 14
ThirdParty/kNet/include/kNet/EndPoint.h

@@ -16,8 +16,6 @@
 /** @file EndPoint.h
 /** @file EndPoint.h
 	@brief The class \ref kNet::EndPoint Endpoint. Represents an endpoint of a network connection. */
 	@brief The class \ref kNet::EndPoint Endpoint. Represents an endpoint of a network connection. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #if defined(UNIX) || defined(ANDROID)
 #if defined(UNIX) || defined(ANDROID)
 #include <sys/types.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/socket.h>
@@ -26,8 +24,7 @@
 
 
 #include <cstring>
 #include <cstring>
 #include <cstdio>
 #include <cstdio>
-
-#include "Str.h"
+#include <string>
 
 
 namespace kNet
 namespace kNet
 {
 {
@@ -67,12 +64,6 @@ struct EndPoint
 
 
 		return false;
 		return false;
 	}
 	}
-	
-	///\todo Not IPv6-capable.
-	bool operator == (const EndPoint &rhs) const
-	{
-		return ip[0] == rhs.ip[0] && ip[1] == rhs.ip[1] && ip[2] == rhs.ip[2] && ip[3] == rhs.ip[3] && port == rhs.port;
-	}
 
 
 	///\todo Not IPv6-capable.
 	///\todo Not IPv6-capable.
 	static EndPoint FromSockAddrIn(const sockaddr_in &addr)
 	static EndPoint FromSockAddrIn(const sockaddr_in &addr)
@@ -116,19 +107,19 @@ struct EndPoint
 	}
 	}
 
 
 	///\todo Not IPv6-capable.
 	///\todo Not IPv6-capable.
-	String IPToString() const
+	std::string IPToString() const
 	{
 	{
 		char str[256];
 		char str[256];
 		sprintf(str, "%d.%d.%d.%d", (unsigned int)ip[0], (unsigned int)ip[1], (unsigned int)ip[2], (unsigned int)ip[3]);
 		sprintf(str, "%d.%d.%d.%d", (unsigned int)ip[0], (unsigned int)ip[1], (unsigned int)ip[2], (unsigned int)ip[3]);
-		return String(str);
+		return std::string(str);
 	}
 	}
 
 
 	///\todo Not IPv6-capable.
 	///\todo Not IPv6-capable.
-	String ToString() const
+	std::string ToString() const
 	{
 	{
 		char str[256];
 		char str[256];
 		sprintf(str, "%d.%d.%d.%d:%d", (unsigned int)ip[0], (unsigned int)ip[1], (unsigned int)ip[2], (unsigned int)ip[3], (unsigned int)port);
 		sprintf(str, "%d.%d.%d.%d:%d", (unsigned int)ip[0], (unsigned int)ip[1], (unsigned int)ip[2], (unsigned int)ip[3], (unsigned int)port);
-		return String(str);
+		return std::string(str);
 	}
 	}
 };
 };
 
 

+ 2 - 4
ThirdParty/kNet/include/kNet/EventArray.h

@@ -16,9 +16,7 @@
 /** @file EventArray.h
 /** @file EventArray.h
 	@brief The class \ref kNet::EventArray EventArray. Allows listening to multiple events at once.*/
 	@brief The class \ref kNet::EventArray EventArray. Allows listening to multiple events at once.*/
 
 
-// Modified by Lasse Öörni for Urho3D
-
-#include "Vector.h"
+#include <vector>
 
 
 #include "Event.h"
 #include "Event.h"
 
 
@@ -68,7 +66,7 @@ private:
 	timeval tv;
 	timeval tv;
 	/// Cache a list of all added events here. This is to remember the order in which the events were added, so that
 	/// Cache a list of all added events here. This is to remember the order in which the events were added, so that
 	/// we can correctly return the occurred event with the smallest index.
 	/// we can correctly return the occurred event with the smallest index.
-	Vector<Event> cachedEvents;
+	std::vector<Event> cachedEvents;
 #endif
 #endif
 };
 };
 
 

+ 8 - 10
ThirdParty/kNet/include/kNet/FragmentedTransferManager.h

@@ -17,10 +17,8 @@
 	@brief The classes \ref kNet::FragmentedSendManager FragmentedSendManager and 
 	@brief The classes \ref kNet::FragmentedSendManager FragmentedSendManager and 
 	\ref kNet::FragmentedSendManager FragmentedReceiveManager. For managing partial transfers. */
 	\ref kNet::FragmentedSendManager FragmentedReceiveManager. For managing partial transfers. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
-#include "Vector.h"
-#include "List.h"
+#include <vector>
+#include <list>
 
 
 namespace kNet
 namespace kNet
 {
 {
@@ -39,7 +37,7 @@ public:
 		/// The total number of fragments in this message.
 		/// The total number of fragments in this message.
 		size_t totalNumFragments;
 		size_t totalNumFragments;
 
 
-		List<NetworkMessage*> fragments;
+		std::list<NetworkMessage*> fragments;
 
 
 		void AddMessage(NetworkMessage *message);
 		void AddMessage(NetworkMessage *message);
 
 
@@ -47,7 +45,7 @@ public:
 		bool RemoveMessage(NetworkMessage *message);
 		bool RemoveMessage(NetworkMessage *message);
 	};
 	};
 
 
-	typedef List<FragmentedTransfer> TransferList;
+	typedef std::list<FragmentedTransfer> TransferList;
 	TransferList transfers;
 	TransferList transfers;
 
 
 	/// Returns a new FragmentedTransfer. A transferID for this transfer will not have been allocated here.
 	/// Returns a new FragmentedTransfer. A transferID for this transfer will not have been allocated here.
@@ -72,7 +70,7 @@ public:
 	{
 	{
 		int fragmentIndex;
 		int fragmentIndex;
 
 
-		PODVector<char> data;
+		std::vector<char> data;
 	};
 	};
 
 
 	struct ReceiveTransfer
 	struct ReceiveTransfer
@@ -81,14 +79,14 @@ public:
 
 
 		int numTotalFragments;
 		int numTotalFragments;
 
 
-		Vector<ReceiveFragment> fragments;
+		std::vector<ReceiveFragment> fragments;
 	};
 	};
 
 
-	Vector<ReceiveTransfer> transfers;
+	std::vector<ReceiveTransfer> transfers;
 
 
 	void NewFragmentStartReceived(int transferID, int numTotalFragments, const char *data, size_t numBytes);
 	void NewFragmentStartReceived(int transferID, int numTotalFragments, const char *data, size_t numBytes);
 	bool NewFragmentReceived(int transferID, int fragmentNumber, const char *data, size_t numBytes);
 	bool NewFragmentReceived(int transferID, int fragmentNumber, const char *data, size_t numBytes);
-	void AssembleMessage(int transferID, PODVector<char> &assembledData);
+	void AssembleMessage(int transferID, std::vector<char> &assembledData);
 	void FreeMessage(int transferID);
 	void FreeMessage(int transferID);
 };
 };
 
 

+ 9 - 4
ThirdParty/kNet/include/kNet/IMessageHandler.h

@@ -23,8 +23,6 @@ namespace kNet
 
 
 class MessageConnection;
 class MessageConnection;
 
 
-typedef unsigned long message_id_t;
-
 /// IMessageHandler is a callback object used by the MessageConnection to invoke the main application
 /// IMessageHandler is a callback object used by the MessageConnection to invoke the main application
 /// whenever a message has been received.
 /// whenever a message has been received.
 class IMessageHandler
 class IMessageHandler
@@ -34,13 +32,20 @@ public:
 
 
 	/// Called whenever the network stack has received a message that the application
 	/// Called whenever the network stack has received a message that the application
 	/// needs to process.
 	/// needs to process.
-	virtual void HandleMessage(MessageConnection *source, message_id_t id, const char *data, size_t numBytes) = 0;
+	/// @param source The kNet connection this message originates from.
+	/// @param packetId A unique incrementing id counter that identifies the number of the UDP packet this message originated from. Use this
+	///     to prune out-of-order messages if necessary. kNet automatically discards duplicate messages, and can do out-of-order discarding
+	///     automatically as well, if you use message content ID's. Otherwise, you can use the packetId to do the pruning manually.
+	/// @param messageId Contains the id (or the "type") of the message. This is the one you specified when sending the message
+	/// @param data Points to the raw data buffer. This buffer may be zero if numBytes == 0.
+	/// @param numBytes The length of the raw data buffer, in bytes.
+	virtual void HandleMessage(MessageConnection *source, packet_id_t packetId, message_id_t messageId, const char *data, size_t numBytes) = 0;
 
 
 	/// Called by the network library to ask the application to produce a content ID
 	/// Called by the network library to ask the application to produce a content ID
 	/// associated with the given message. If the application returns 0, the message doesn't
 	/// associated with the given message. If the application returns 0, the message doesn't
 	/// have a ContentID and it is processed normally.
 	/// have a ContentID and it is processed normally.
 	/// The ContentID of the message is used to determine if a message replaces another.
 	/// The ContentID of the message is used to determine if a message replaces another.
-	virtual u32 ComputeContentID(message_id_t id, const char *data, size_t numBytes)
+	virtual u32 ComputeContentID(message_id_t messageId, const char *data, size_t numBytes)
 	{
 	{
 		// The default behavior is to not have a content ID on any message.
 		// The default behavior is to not have a content ID on any message.
 		return 0;
 		return 0;

+ 1 - 1
ThirdParty/kNet/include/kNet/Lockable.h

@@ -22,10 +22,10 @@
 #elif defined(WIN32)
 #elif defined(WIN32)
 #include <Windows.h>
 #include <Windows.h>
 #else
 #else
-#include <cassert>
 #include <pthread.h>
 #include <pthread.h>
 #endif
 #endif
 
 
+#include <assert.h>
 #include "PolledTimer.h"
 #include "PolledTimer.h"
 #include "NetworkLogging.h"
 #include "NetworkLogging.h"
 
 

+ 22 - 17
ThirdParty/kNet/include/kNet/MessageConnection.h

@@ -16,16 +16,14 @@
 /** @file MessageConnection.h
 /** @file MessageConnection.h
 	@brief The MessageConnection and ConnectionStatistics classes. */
 	@brief The MessageConnection and ConnectionStatistics classes. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
+#include <vector>
+#include <map>
 #include <utility>
 #include <utility>
-
-#include "Vector.h"
-#include "Map.h"
-#include "Set.h"
+#include <set>
 
 
 #include "kNetBuildConfig.h"
 #include "kNetBuildConfig.h"
 #include "WaitFreeQueue.h"
 #include "WaitFreeQueue.h"
+#include "NetworkSimulator.h"
 #include "LockFreePoolAllocator.h"
 #include "LockFreePoolAllocator.h"
 #include "Lockable.h"
 #include "Lockable.h"
 #include "Socket.h"
 #include "Socket.h"
@@ -55,7 +53,7 @@ class Network;
 class NetworkWorkerThread;
 class NetworkWorkerThread;
 class FragmentedSendManager;
 class FragmentedSendManager;
 
 
-#ifdef WIN32
+#ifdef _MSC_VER
 struct FragmentedSendManager::FragmentedTransfer;
 struct FragmentedSendManager::FragmentedTransfer;
 #endif
 #endif
 
 
@@ -71,7 +69,7 @@ struct ConnectionStatistics
 		bool replyReceived;        ///< True of PingReply has already been received for this.
 		bool replyReceived;        ///< True of PingReply has already been received for this.
 	};
 	};
 	/// Contains an entry for each recently performed Ping operation, sorted by age (oldest first).
 	/// Contains an entry for each recently performed Ping operation, sorted by age (oldest first).
-	PODVector<PingTrack> ping;
+	std::vector<PingTrack> ping;
 
 
 	/// Remembers both in- and outbound traffic events on the socket.
 	/// Remembers both in- and outbound traffic events on the socket.
 	struct TrafficTrack
 	struct TrafficTrack
@@ -85,7 +83,7 @@ struct ConnectionStatistics
 		unsigned long bytesOut;    ///< The total number of bytes the sent datagrams contained. 
 		unsigned long bytesOut;    ///< The total number of bytes the sent datagrams contained. 
 	};
 	};
 	/// Contains an entry for each recent traffic event (data in/out) on the connection, sorted by age (oldest first).
 	/// Contains an entry for each recent traffic event (data in/out) on the connection, sorted by age (oldest first).
-	PODVector<TrafficTrack> traffic;
+	std::vector<TrafficTrack> traffic;
 
 
 	/// Remembers the send/receive time of a datagram with a certain ID.
 	/// Remembers the send/receive time of a datagram with a certain ID.
 	struct DatagramIDTrack
 	struct DatagramIDTrack
@@ -94,7 +92,7 @@ struct ConnectionStatistics
 		packet_id_t packetID;
 		packet_id_t packetID;
 	};
 	};
 	/// Contains an entry for each recently received packet, sorted by age (oldest first).
 	/// Contains an entry for each recently received packet, sorted by age (oldest first).
-	PODVector<DatagramIDTrack> recvPacketIDs;
+	std::vector<DatagramIDTrack> recvPacketIDs;
 };
 };
 
 
 /// Comparison object that sorts the two messages by their priority (higher priority/smaller number first).
 /// Comparison object that sorts the two messages by their priority (higher priority/smaller number first).
@@ -125,7 +123,7 @@ enum ConnectionState
 };
 };
 
 
 /// Returns a textual representation of a ConnectionState.
 /// Returns a textual representation of a ConnectionState.
-String ConnectionStateToString(ConnectionState state);
+std::string ConnectionStateToString(ConnectionState state);
 
 
 // Prevent confusion with Win32 functions
 // Prevent confusion with Win32 functions
 #ifdef SendMessage
 #ifdef SendMessage
@@ -307,7 +305,7 @@ public:
 	void FreeMessage(NetworkMessage *msg); // [main and worker thread]
 	void FreeMessage(NetworkMessage *msg); // [main and worker thread]
 	
 	
 	/// Returns a single-line message describing the connection state.
 	/// Returns a single-line message describing the connection state.
-	String ToString() const; // [main and worker thread]
+	std::string ToString() const; // [main and worker thread]
 
 
 	/// Dumps a long multi-line status message of this connection state to stdout.
 	/// Dumps a long multi-line status message of this connection state to stdout.
 	void DumpStatus() const; // [main thread]
 	void DumpStatus() const; // [main thread]
@@ -333,6 +331,9 @@ public:
 	/// Returns the total number of bytes (excluding IP and TCP/UDP headers) that have been sent from this connection.
 	/// Returns the total number of bytes (excluding IP and TCP/UDP headers) that have been sent from this connection.
 	u64 BytesOutTotal() const { return bytesOutTotal; } // [main and worker thread]
 	u64 BytesOutTotal() const { return bytesOutTotal; } // [main and worker thread]
 
 
+	/// Returns the simulator object which can be used to apply network condition simulations to this connection.
+	NetworkSimulator &NetworkSendSimulator() { return networkSendSimulator; }
+
 	/// Stores all the statistics about the current connection. This data is periodically recomputed
 	/// Stores all the statistics about the current connection. This data is periodically recomputed
 	/// by the network worker thread and shared to the client through a lock.
 	/// by the network worker thread and shared to the client through a lock.
 	Lockable<ConnectionStatistics> statistics; // [main and worker thread]
 	Lockable<ConnectionStatistics> statistics; // [main and worker thread]
@@ -514,6 +515,10 @@ protected:
 	u64 bytesInTotal;
 	u64 bytesInTotal;
 	u64 bytesOutTotal;
 	u64 bytesOutTotal;
 
 
+	/// Stores the current settigns related to network conditions testing.
+	/// By default, the simulator is disabled.
+	NetworkSimulator networkSendSimulator;
+
 	/// A running number attached to each outbound message (not present in network stream) to 
 	/// A running number attached to each outbound message (not present in network stream) to 
 	/// break ties when deducing which message should come before which.
 	/// break ties when deducing which message should come before which.
 	unsigned long outboundMessageNumberCounter; // [worker thread]
 	unsigned long outboundMessageNumberCounter; // [worker thread]
@@ -523,15 +528,15 @@ protected:
 	unsigned long outboundReliableMessageNumberCounter; // [worker thread]
 	unsigned long outboundReliableMessageNumberCounter; // [worker thread]
 
 
 	/// A (messageID, contentID) pair.
 	/// A (messageID, contentID) pair.
-	typedef Pair<u32, u32> MsgContentIDPair;
+	typedef std::pair<u32, u32> MsgContentIDPair;
 
 
-	typedef Map<MsgContentIDPair, Pair<packet_id_t, tick_t> > ContentIDReceiveTrack;
+	typedef std::map<MsgContentIDPair, std::pair<packet_id_t, tick_t> > ContentIDReceiveTrack;
 
 
 	/// Each (messageID, contentID) pair has a packetID "stamp" associated to them to track 
 	/// Each (messageID, contentID) pair has a packetID "stamp" associated to them to track 
 	/// and decimate out-of-order received obsoleted messages.
 	/// and decimate out-of-order received obsoleted messages.
 	ContentIDReceiveTrack inboundContentIDStamps; // [worker thread]
 	ContentIDReceiveTrack inboundContentIDStamps; // [worker thread]
 
 
-	typedef Map<MsgContentIDPair, NetworkMessage*> ContentIDSendTrack;
+	typedef std::map<MsgContentIDPair, NetworkMessage*> ContentIDSendTrack;
 
 
 	ContentIDSendTrack outboundContentIDMessages; // [worker thread]
 	ContentIDSendTrack outboundContentIDMessages; // [worker thread]
 
 
@@ -543,7 +548,7 @@ protected:
 	/// by a newer packet and should not be processed.
 	/// by a newer packet and should not be processed.
 	/// @return True if the packet should be processed (there was no superceding record), and
 	/// @return True if the packet should be processed (there was no superceding record), and
 	///         false if the packet is old and should be discarded.
 	///         false if the packet is old and should be discarded.
-	bool CheckAndSaveContentIDStamp(u32 messageID, u32 contentID, packet_id_t packetID); // [worker thread]
+	bool CheckAndSaveContentIDStamp(message_id_t messageID, u32 contentID, packet_id_t packetID); // [worker thread]
 
 
 	void SplitAndQueueMessage(NetworkMessage *message, bool internalQueue, size_t maxFragmentSize); // [main and worker thread]
 	void SplitAndQueueMessage(NetworkMessage *message, bool internalQueue, size_t maxFragmentSize); // [main and worker thread]
 
 
@@ -557,7 +562,7 @@ protected:
 	/// Private ctor - MessageConnections are instantiated by Network and NetworkServer classes.
 	/// Private ctor - MessageConnections are instantiated by Network and NetworkServer classes.
 	explicit MessageConnection(Network *owner, NetworkServer *ownerServer, Socket *socket, ConnectionState startingState);
 	explicit MessageConnection(Network *owner, NetworkServer *ownerServer, Socket *socket, ConnectionState startingState);
 
 
-	virtual bool HandleMessage(packet_id_t /*packetID*/, u32 /*messageID*/, const char * /*data*/, size_t /*numBytes*/) { return false; } // [main thread]
+	virtual bool HandleMessage(packet_id_t /*packetID*/, message_id_t /*messageID*/, const char * /*data*/, size_t /*numBytes*/) { return false; } // [main thread]
 };
 };
 
 
 template<typename SerializableData>
 template<typename SerializableData>

+ 9 - 11
ThirdParty/kNet/include/kNet/MessageListParser.h

@@ -16,9 +16,7 @@
 /** @file MessageListParser.h
 /** @file MessageListParser.h
 	@brief The SerializedMessageList class. */
 	@brief The SerializedMessageList class. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
-#include "Vector.h"
+#include <vector>
 
 
 #include "BasicSerializedDataTypes.h"
 #include "BasicSerializedDataTypes.h"
 
 
@@ -40,7 +38,7 @@ struct SerializedElementDesc
 
 
 	/// A string version of this type is stored here. This field is used if the type of this element is something 
 	/// A string version of this type is stored here. This field is used if the type of this element is something 
 	/// else than a basic type.
 	/// else than a basic type.
-	String typeString;
+	std::string typeString;
 
 
 	/// If true, the number of times this element is instanced is specified in the stream.
 	/// If true, the number of times this element is instanced is specified in the stream.
 	bool varyingCount;
 	bool varyingCount;
@@ -50,10 +48,10 @@ struct SerializedElementDesc
 	int count;
 	int count;
 
 
 	/// The name of this element.
 	/// The name of this element.
-	String name;
+	std::string name;
 
 
 	/// If this element denotes a structure (type == SerialStruct), then this vector contains all the child nodes.
 	/// If this element denotes a structure (type == SerialStruct), then this vector contains all the child nodes.
-	Vector<SerializedElementDesc*> elements;
+	std::vector<SerializedElementDesc*> elements;
 
 
 	/// The parent element, or 0 if this is the root element.
 	/// The parent element, or 0 if this is the root element.
 	SerializedElementDesc *parent;
 	SerializedElementDesc *parent;
@@ -65,7 +63,7 @@ struct SerializedMessageDesc
 	/// This is a weak pointer to the root element of this message description. The memory is owned by the SerializedMessageList
 	/// This is a weak pointer to the root element of this message description. The memory is owned by the SerializedMessageList
 	/// where this SerializedMessageDesc belongs to.
 	/// where this SerializedMessageDesc belongs to.
 	SerializedElementDesc *data;
 	SerializedElementDesc *data;
-	String name;
+	std::string name;
 	u32 id;
 	u32 id;
 	bool reliable;
 	bool reliable;
 	bool inOrder;
 	bool inOrder;
@@ -85,14 +83,14 @@ public:
 	const SerializedMessageDesc *FindMessageByName(const char *name);
 	const SerializedMessageDesc *FindMessageByName(const char *name);
 
 
 	/// Returns the whole list of messages.
 	/// Returns the whole list of messages.
-	const List<SerializedMessageDesc> &GetMessages() const { return messages; }
+	const std::list<SerializedMessageDesc> &GetMessages() const { return messages; }
 
 
 	/// Returns a flat list of all the message elements.
 	/// Returns a flat list of all the message elements.
-	const List<SerializedElementDesc> &GetElements() const { return elements; }
+	const std::list<SerializedElementDesc> &GetElements() const { return elements; }
 
 
 private:
 private:
-	List<SerializedElementDesc> elements;
-	List<SerializedMessageDesc> messages;
+	std::list<SerializedElementDesc> elements;
+	std::list<SerializedMessageDesc> messages;
 
 
 	SerializedElementDesc *ParseNode(TiXmlElement *node, SerializedElementDesc *parentNode);
 	SerializedElementDesc *ParseNode(TiXmlElement *node, SerializedElementDesc *parentNode);
 
 

+ 3 - 7
ThirdParty/kNet/include/kNet/NetException.h

@@ -15,12 +15,8 @@
 
 
 /** @file NetException.h
 /** @file NetException.h
 	@brief The class NetException. Common exception class thrown by kNet on errors. */
 	@brief The class NetException. Common exception class thrown by kNet on errors. */
-
-// Modified by Lasse Öörni for Urho3D
-
 #include <exception>
 #include <exception>
-
-#include "Str.h"
+#include <string>
 
 
 namespace kNet
 namespace kNet
 {
 {
@@ -37,10 +33,10 @@ public:
 	{
 	{
 	}
 	}
 
 
-	const char *what() const throw() { return exception.CString(); }
+	const char *what() const throw() { return exception.c_str(); }
 
 
 private:
 private:
-	String exception;
+	std::string exception;
 };
 };
 
 
 } // ~kNet
 } // ~kNet

+ 12 - 14
ThirdParty/kNet/include/kNet/Network.h

@@ -16,8 +16,6 @@
 /** @file Network.h
 /** @file Network.h
 	@brief The class Network. The root point for creating client and server objects. */
 	@brief The class Network. The root point for creating client and server objects. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #if defined(UNIX) || defined(ANDROID)
 #if defined(UNIX) || defined(ANDROID)
 #include <sys/types.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/socket.h>
@@ -61,7 +59,7 @@ public:
 	/// @param allowAddressReuse If true, kNet passes the SO_REUSEADDR parameter to the server listen socket before binding 
 	/// @param allowAddressReuse If true, kNet passes the SO_REUSEADDR parameter to the server listen socket before binding 
 	///        the socket to a local port (== before starting the server). This allows the same port to be forcibly reused
 	///        the socket to a local port (== before starting the server). This allows the same port to be forcibly reused
 	///        when restarting the server if a crash occurs, without having to wait for the operating system to free up the port.
 	///        when restarting the server if a crash occurs, without having to wait for the operating system to free up the port.
-	NetworkServer *StartServer(const Vector<Pair<unsigned short, SocketTransportLayer> > &listenPorts, INetworkServerListener *serverListener, bool allowAddressReuse);
+	NetworkServer *StartServer(const std::vector<std::pair<unsigned short, SocketTransportLayer> > &listenPorts, INetworkServerListener *serverListener, bool allowAddressReuse);
 
 
 	void StopServer();
 	void StopServer();
 
 
@@ -80,25 +78,25 @@ public:
 	Ptr(MessageConnection) Connect(const char *address, unsigned short port, SocketTransportLayer transport, IMessageHandler *messageHandler, Datagram *connectMessage = 0);
 	Ptr(MessageConnection) Connect(const char *address, unsigned short port, SocketTransportLayer transport, IMessageHandler *messageHandler, Datagram *connectMessage = 0);
 
 
 	/// Returns the local host name of the system (the local machine name or the local IP, whatever is specified by the system).
 	/// Returns the local host name of the system (the local machine name or the local IP, whatever is specified by the system).
-	const char *LocalAddress() const { return localHostName.CString(); }
+	const char *LocalAddress() const { return localHostName.c_str(); }
 
 
 	/// Returns the error string associated with the given networking error id.
 	/// Returns the error string associated with the given networking error id.
-	static String GetErrorString(int error);
+	static std::string GetErrorString(int error);
 
 
 	/// Returns the error string corresponding to the last error that occurred in the networking library.
 	/// Returns the error string corresponding to the last error that occurred in the networking library.
-	static String GetLastErrorString();
+	static std::string GetLastErrorString();
 
 
 	/// Returns the error id corresponding to the last error that occurred in the networking library.
 	/// Returns the error id corresponding to the last error that occurred in the networking library.
 	static int GetLastError();
 	static int GetLastError();
 
 
 	/// Returns the amount of currently executing background network worker threads.
 	/// Returns the amount of currently executing background network worker threads.
-	int NumWorkerThreads() const { return workerThreads.Size(); }
+	int NumWorkerThreads() const { return workerThreads.size(); }
 
 
 	/// Returns the NetworkServer object, or null if no server has been started.
 	/// Returns the NetworkServer object, or null if no server has been started.
 	Ptr(NetworkServer) GetServer() { return server; }
 	Ptr(NetworkServer) GetServer() { return server; }
 
 
 	/// Returns all current connections in the system.
 	/// Returns all current connections in the system.
-	Set<MessageConnection *> Connections() const { return connections; }
+	std::set<MessageConnection *> Connections() const { return connections; }
 
 
 	/// Returns the data structure that collects statistics about the whole Network.
 	/// Returns the data structure that collects statistics about the whole Network.
 	Lock<StatsEventHierarchyNode> Statistics() { return statistics.Acquire(); }
 	Lock<StatsEventHierarchyNode> Statistics() { return statistics.Acquire(); }
@@ -106,17 +104,17 @@ public:
 private:
 private:
 	/// Specifies the local network address of the system. This name is cached here on initialization
 	/// Specifies the local network address of the system. This name is cached here on initialization
 	/// to avoid multiple queries to namespace providers whenever the name is needed.
 	/// to avoid multiple queries to namespace providers whenever the name is needed.
-	String localHostName;
+	std::string localHostName;
 
 
 	/// Maintains the server-related data structures if this computer
 	/// Maintains the server-related data structures if this computer
 	/// is acting as a server. Otherwise this data is not used.
 	/// is acting as a server. Otherwise this data is not used.
 	Ptr(NetworkServer) server;
 	Ptr(NetworkServer) server;
 
 
 	/// Contains all active sockets in the system.
 	/// Contains all active sockets in the system.
-	List<Socket> sockets;
+	std::list<Socket> sockets;
 
 
 	/// Tracks all existing connections in the system.
 	/// Tracks all existing connections in the system.
-	Set<MessageConnection *> connections;
+	std::set<MessageConnection *> connections;
 
 
 	Lockable<StatsEventHierarchyNode> statistics;
 	Lockable<StatsEventHierarchyNode> statistics;
 
 
@@ -141,7 +139,7 @@ private:
 	/// Stores all the currently running network worker threads. Each thread is assigned
 	/// Stores all the currently running network worker threads. Each thread is assigned
 	/// a list of MessageConnections and NetworkServers to oversee. The worker threads
 	/// a list of MessageConnections and NetworkServers to oversee. The worker threads
 	/// then manage the socket reads and writes on these connections.
 	/// then manage the socket reads and writes on these connections.
-	Vector<NetworkWorkerThread*> workerThreads;
+	std::vector<NetworkWorkerThread*> workerThreads;
 
 
 	/// Examines each currently running worker thread and returns one that has sufficiently low load,
 	/// Examines each currently running worker thread and returns one that has sufficiently low load,
 	/// or creates a new thread and returns it if no such thread exists. The thread is added and maintained
 	/// or creates a new thread and returns it if no such thread exists. The thread is added and maintained
@@ -179,8 +177,8 @@ private:
 };
 };
 
 
 /// Outputs the given number of bytes formatted to KB or MB suffix for readability.
 /// Outputs the given number of bytes formatted to KB or MB suffix for readability.
-String FormatBytes(u64 numBytes);
+std::string FormatBytes(u64 numBytes);
 
 
-String FormatBytes(double numBytes);
+std::string FormatBytes(double numBytes);
 
 
 } // ~kNet
 } // ~kNet

+ 14 - 14
ThirdParty/kNet/include/kNet/NetworkMessage.h

@@ -16,27 +16,21 @@
 /** @file NetworkMessage.h
 /** @file NetworkMessage.h
 	@brief The class NetworkMessage. Stores an outbound network message. */
 	@brief The class NetworkMessage. Stores an outbound network message. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include "kNetBuildConfig.h"
 #include "kNetBuildConfig.h"
 #include "LockFreePoolAllocator.h"
 #include "LockFreePoolAllocator.h"
 #include "FragmentedTransferManager.h"
 #include "FragmentedTransferManager.h"
+#include "Types.h"
 
 
 namespace kNet
 namespace kNet
 {
 {
 
 
-/// Contains 22 actual bits of data.
-typedef unsigned long packet_id_t;
-
-/// Performs modular arithmetic comparison to see if newID refers to a PacketID newer than oldID.
-/// @return True if newID is newer than oldID, false otherwise.
+/// Performs modular arithmetic comparison to see if newID refers to a PacketID that is *strictly* newer than oldID.
+/// @return True if newID is *strictly* newer than oldID, false otherwise.
 inline bool PacketIDIsNewerThan(packet_id_t newID, packet_id_t oldID)
 inline bool PacketIDIsNewerThan(packet_id_t newID, packet_id_t oldID)
 {
 {
-	if (newID > oldID)
-		return true;
-	if (oldID - newID >= (1 << 21))
-		return true;
-	return false;
+    packet_id_t diff = (packet_id_t)(newID - oldID);
+    packet_id_t diff2 = (packet_id_t)(newID + 0x3FFFFF - oldID);
+    return diff < 0x1FFFFF || diff2 < 0x1FFFFF;
 }
 }
 
 
 /// Computes the PacketID for the packet (id + increment).
 /// Computes the PacketID for the packet (id + increment).
@@ -92,7 +86,8 @@ public:
 	unsigned long priority;
 	unsigned long priority;
 
 
 	/// The ID of this message. IDs 0 - 5 are reserved for the protocol and may not be used.
 	/// The ID of this message. IDs 0 - 5 are reserved for the protocol and may not be used.
-	packet_id_t id;
+	/// Valid user range is [6, 1073741821 == 0x3FFFFFFD].
+	message_id_t id;
 
 
 	/// When sending out a message, the application can attach a content ID to the message,
 	/// When sending out a message, the application can attach a content ID to the message,
 	/// which will effectively replace all the older messages with the same messageID and
 	/// which will effectively replace all the older messages with the same messageID and
@@ -114,7 +109,7 @@ public:
 	bool obsolete;
 	bool obsolete;
 
 
 #ifdef KNET_NETWORK_PROFILING
 #ifdef KNET_NETWORK_PROFILING
-	String profilerName;
+	std::string profilerName;
 #endif
 #endif
 
 
 	/// Checks if this message is newer than the other message.
 	/// Checks if this message is newer than the other message.
@@ -138,6 +133,11 @@ private:
 	friend class FragmentedSendManager;
 	friend class FragmentedSendManager;
 	friend struct FragmentedSendManager::FragmentedTransfer;
 	friend struct FragmentedSendManager::FragmentedTransfer;
 
 
+	/// A temporary storage area to remember the UDP packet ID this messages was received in.
+	/// For TCP messages, this field is always zero.
+	/// When sending out messages, this field is not used.
+	packet_id_t receivedPacketID;
+
 	/// A running number that is assigned to each message to distinguish the order
 	/// A running number that is assigned to each message to distinguish the order
 	/// the messages were added to the queue. The network layer manages this numbering,
 	/// the messages were added to the queue. The network layer manages this numbering,
 	/// the application can not control it. This is used to break ties on packets
 	/// the application can not control it. This is used to break ties on packets

+ 8 - 10
ThirdParty/kNet/include/kNet/NetworkServer.h

@@ -16,9 +16,7 @@
 /** @file NetworkServer.h
 /** @file NetworkServer.h
 	@brief The NetworkServer class. The main class for hosting a kNet server. */
 	@brief The NetworkServer class. The main class for hosting a kNet server. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
-#include "List.h"
+#include <list>
 
 
 #include "kNetBuildConfig.h"
 #include "kNetBuildConfig.h"
 #include "SharedPtr.h"
 #include "SharedPtr.h"
@@ -101,9 +99,9 @@ public:
 	void ConnectionClosed(MessageConnection *connection);
 	void ConnectionClosed(MessageConnection *connection);
 
 
 	/// Returns all the sockets this server is listening on.
 	/// Returns all the sockets this server is listening on.
-	Vector<Socket *> &ListenSockets();
+	std::vector<Socket *> &ListenSockets();
 
 
-	typedef Map<EndPoint, Ptr(MessageConnection)> ConnectionMap;
+	typedef std::map<EndPoint, Ptr(MessageConnection)> ConnectionMap;
 
 
 	/// Returns all the currently tracked connections.
 	/// Returns all the currently tracked connections.
 	ConnectionMap GetConnections();
 	ConnectionMap GetConnections();
@@ -112,16 +110,16 @@ public:
 	int NumConnections() const;
 	int NumConnections() const;
 
 
 	/// Returns a one-liner textual summary of this server.
 	/// Returns a one-liner textual summary of this server.
-	String ToString() const;
+	std::string ToString() const;
 
 
 private:
 private:
 	/// Private ctor - NetworkServer instances are created by the Network class.
 	/// Private ctor - NetworkServer instances are created by the Network class.
-	NetworkServer(Network *owner, Vector<Socket *> listenSockets);
+	NetworkServer(Network *owner, std::vector<Socket *> listenSockets);
 
 
 	/// We store possibly multiple listening sockets so that the server
 	/// We store possibly multiple listening sockets so that the server
 	/// can listen on several sockets (UDP or TCP) at once, making it
 	/// can listen on several sockets (UDP or TCP) at once, making it
 	/// possible for clients to bypass firewalls and/or mix UDP and TCP use.
 	/// possible for clients to bypass firewalls and/or mix UDP and TCP use.
-	Vector<Socket *> listenSockets;
+	std::vector<Socket *> listenSockets;
 
 
 	/// The list of active client connections.
 	/// The list of active client connections.
 	Lockable<ConnectionMap> clients;
 	Lockable<ConnectionMap> clients;
@@ -195,9 +193,9 @@ void NetworkServer::BroadcastStruct(const SerializableData &data, unsigned long
 
 
 	const size_t dataSize = data.Size();
 	const size_t dataSize = data.Size();
 
 
-	for(ConnectionMap::Iterator iter = clientsLock->Begin(); iter != clientsLock->End(); ++iter)
+	for(ConnectionMap::iterator iter = clientsLock->begin(); iter != clientsLock->end(); ++iter)
 	{
 	{
-		MessageConnection *connection = iter->second_;
+		MessageConnection *connection = iter->second;
 		assert(connection);
 		assert(connection);
 		if (connection == exclude || !connection->IsWriteOpen())
 		if (connection == exclude || !connection->IsWriteOpen())
 			continue;
 			continue;

+ 103 - 0
ThirdParty/kNet/include/kNet/NetworkSimulator.h

@@ -0,0 +1,103 @@
+/* Copyright The kNet Project.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. */
+#pragma once
+
+/** @file NetworkSimulator.h
+	@brief The NetworkSimulator class, which enables different network conditions testing. */
+
+#include "kNetFwd.h"
+#include "PolledTimer.h"
+#include <vector>
+
+#include <cstring>
+
+namespace kNet
+{
+
+/// A NetworkSimulator is attached to MessageConnections to add in an intermediate layer for
+/// network conditions testing.
+class NetworkSimulator
+{
+public:
+	NetworkSimulator();
+	~NetworkSimulator();
+
+	/// If false, the network simulator is not being used.
+	/// By default, this is always false.
+	bool enabled;
+
+	/// Specifies the percentage of messages to drop. This is in the range [0.0, 1.0]. Default: 0 (disabled).
+	float packetLossRate;
+
+	/// Specifies a constant delay to add to each packet (msecs). Default: 0.
+	float constantPacketSendDelay;
+
+	/// Specifies an amount of uniformly random delay to add to each packet (msecs), [0, uniformRandomPacketSendDelay].  Default: 0.
+	float uniformRandomPacketSendDelay;
+
+	/// Specifies the percentage of messages to duplicate. This is in the range [0.0, 1.0]. Default: 0 (disabled). 
+	float packetDuplicationRate;
+
+	/// Corruption options.
+	enum
+	{
+		CorruptDatagram, ///< The whole datagram is subjected to data corruption. This is the default.
+		CorruptPayload, ///< Only kNet message payload (client-side data) will be subjected to corruption.
+		CorruptMessageType ///< Only the message payload of a single given message type will be subjected to corruption.
+	} corruptionType;
+
+	/// If corruptionType == CorruptMessageType, this field specifies a single specific message type ID which
+	/// will be subjected to corruption. Default: 0. No message has the ID 0, i.e. this effectively means "disabled".
+	int corruptMessageId;
+
+	/// Rate in % of the datagrams to corrupt. Default: 0.
+	float corruptToggleBitsRate;
+
+	/// The minimum number of bits to corrupt when a datagram is decided to be tampered. Default: 0.
+	int corruptMinBits;
+
+	/// The maximum number of bits to corrupt when a datagram is decided to be tampered. Default: 0.
+	int corruptMaxBits;
+
+	void SubmitSendBuffer(OverlappedTransferBuffer *buffer, Socket *socket);
+
+	/// Runs a polled update tick on the network simulator. Transfers all expired data.
+	void Process();
+
+	/// Discards and frees all currently queued messages.
+	void Free();
+
+	/// Performs a random roll against the corruptToggleBitsRate counter, and perhaps corrupts some bits
+	/// of the given buffer.
+	/// Alters the raw byte buffer contents by flipping some bits according to the currently specified
+	/// parameters.
+	void MaybeCorruptBufferToggleBits(void *buffer, size_t numBytes) const;
+
+private:
+	struct QueuedBuffer
+	{
+		OverlappedTransferBuffer *buffer;
+
+		/// Stores how long to delay this buffer until transfer.
+		PolledTimer timeUntilTransfer;
+	};
+	std::vector<QueuedBuffer> queuedBuffers;
+
+	MessageConnection *owner;
+
+	friend class MessageConnection;
+};
+
+} // ~kNet
+

+ 2 - 4
ThirdParty/kNet/include/kNet/NetworkWorkerThread.h

@@ -17,8 +17,6 @@
 	@brief The NetworkWorkerThread class. Implements a background thread for responsive
 	@brief The NetworkWorkerThread class. Implements a background thread for responsive
 	processing of server and client connections. */
 	processing of server and client connections. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include "SharedPtr.h"
 #include "SharedPtr.h"
 
 
 #include "Lockable.h"
 #include "Lockable.h"
@@ -49,8 +47,8 @@ public:
 	Thread &ThreadObject() { return workThread; }
 	Thread &ThreadObject() { return workThread; }
 
 
 private:
 private:
-	Lockable<Vector<MessageConnection *> > connections;
-	Lockable<Vector<NetworkServer *> > servers;
+	Lockable<std::vector<MessageConnection *> > connections;
+	Lockable<std::vector<NetworkServer *> > servers;
 
 
 	Thread workThread;
 	Thread workThread;
 
 

+ 9 - 11
ThirdParty/kNet/include/kNet/RingBuffer.h

@@ -16,9 +16,7 @@
 /** @file RingBuffer.h
 /** @file RingBuffer.h
 	@brief The RingBuffer class stores a fast raw byte buffer queue storage. */
 	@brief The RingBuffer class stores a fast raw byte buffer queue storage. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
-#include "Vector.h"
+#include <vector>
 
 
 namespace kNet
 namespace kNet
 {
 {
@@ -29,13 +27,13 @@ class RingBuffer
 public:
 public:
 	explicit RingBuffer(int capacity)
 	explicit RingBuffer(int capacity)
 	{
 	{
-		data.Resize(capacity);
+		data.resize(capacity);
 		start = 0;
 		start = 0;
 		end = 0;
 		end = 0;
 	}
 	}
 
 
 	/// Returns the total number of bytes that this RingBuffer can contain.
 	/// Returns the total number of bytes that this RingBuffer can contain.
-	int Capacity() const { return data.Size(); }
+	int Capacity() const { return data.size(); }
 
 
 	/// Returns the number of bytes filled in the ring buffer.
 	/// Returns the number of bytes filled in the ring buffer.
 	int Size() const { return end - start; }
 	int Size() const { return end - start; }
@@ -61,10 +59,10 @@ public:
 	{
 	{
 		assert(newSize > 0);
 		assert(newSize > 0);
 
 
-		if ((size_t)newSize <= data.Size())
+		if ((size_t)newSize <= data.size())
 			return; // No need to resize.
 			return; // No need to resize.
 		Compact();
 		Compact();
-		data.Resize(newSize);
+		data.resize(newSize);
 	}
 	}
 
 
 	void Clear()
 	void Clear()
@@ -84,7 +82,7 @@ public:
 	void Inserted(int numBytes)
 	void Inserted(int numBytes)
 	{ 
 	{ 
 		end += numBytes; 
 		end += numBytes; 
-		assert(end <= (int)data.Size());
+		assert(end <= (int)data.size());
 	}
 	}
 
 
 	/// Call after having processed the given number of bytes from the buffer.
 	/// Call after having processed the given number of bytes from the buffer.
@@ -97,13 +95,13 @@ public:
 	}
 	}
 
 
 	/// Returns the total number of bytes that can be filled in this structure after compacting.
 	/// Returns the total number of bytes that can be filled in this structure after compacting.
-	int TotalFreeBytesLeft() const { return data.Size() - Size(); }
+	int TotalFreeBytesLeft() const { return data.size() - Size(); }
 
 
 	/// Returns the number of bytes that can be added to this structure contiguously, without having to compact.
 	/// Returns the number of bytes that can be added to this structure contiguously, without having to compact.
-	int ContiguousFreeBytesLeft() const { return data.Size() - end; }
+	int ContiguousFreeBytesLeft() const { return data.size() - end; }
 
 
 private:
 private:
-	PODVector<char> data;
+	std::vector<char> data;
 	int start; ///< Points to the first used byte.
 	int start; ///< Points to the first used byte.
 	int end; ///< Points to the first unused byte.
 	int end; ///< Points to the first unused byte.
 
 

+ 2 - 1
ThirdParty/kNet/include/kNet/SequentialIntegerSet.h

@@ -47,7 +47,8 @@ public:
 
 
 	int Capacity() const { return tableSize; }
 	int Capacity() const { return tableSize; }
 
 
-	int CountSize()
+    /// Recomputes the size of this set, so that Size() returns the exact value.
+	void CountSize()
 	{
 	{
 		size = 0;
 		size = 0;
 		for(int i = 0; i < tableSize; ++i)
 		for(int i = 0; i < tableSize; ++i)

+ 3 - 6
ThirdParty/kNet/include/kNet/SerializationStructCompiler.h

@@ -16,10 +16,7 @@
 /** @file SerializationStructCompiler.h
 /** @file SerializationStructCompiler.h
 	@brief The SerializationStructCompiler class. */
 	@brief The SerializationStructCompiler class. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
-#include "Str.h"
-
+#include <string>
 #include <fstream>
 #include <fstream>
 
 
 #include "MessageListParser.h"
 #include "MessageListParser.h"
@@ -34,7 +31,7 @@ public:
 	void CompileStruct(const SerializedElementDesc &structure, const char *outfile);
 	void CompileStruct(const SerializedElementDesc &structure, const char *outfile);
 	void CompileMessage(const SerializedMessageDesc &message, const char *outfile);
 	void CompileMessage(const SerializedMessageDesc &message, const char *outfile);
 
 
-	static String ParseToValidCSymbolName(const char *str);
+	static std::string ParseToValidCSymbolName(const char *str);
 
 
 private:
 private:
 	void WriteFilePreamble(std::ofstream &out);
 	void WriteFilePreamble(std::ofstream &out);
@@ -48,7 +45,7 @@ private:
 	void WriteSerializeMemberFunction(/*const std::string &className, */const SerializedElementDesc &elem, int level, std::ofstream &out);
 	void WriteSerializeMemberFunction(/*const std::string &className, */const SerializedElementDesc &elem, int level, std::ofstream &out);
 	void WriteDeserializeMemberFunction(/*const std::string &className, */const SerializedElementDesc &elem, int level, std::ofstream &out);
 	void WriteDeserializeMemberFunction(/*const std::string &className, */const SerializedElementDesc &elem, int level, std::ofstream &out);
 
 
-	static String Indent(int level);
+	static std::string Indent(int level);
 };
 };
 
 
 } // ~kNet
 } // ~kNet

+ 1 - 3
ThirdParty/kNet/include/kNet/SerializedDataIterator.h

@@ -16,8 +16,6 @@
 /** @file SerializedDataIterator.h
 /** @file SerializedDataIterator.h
 	@brief The SerializedDataIterator class. */
 	@brief The SerializedDataIterator class. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include "SharedPtr.h"
 #include "SharedPtr.h"
 #include "MessageListParser.h"
 #include "MessageListParser.h"
 
 
@@ -67,7 +65,7 @@ private:
 	void DescendIntoStructure();
 	void DescendIntoStructure();
 
 
 	/// Stores the tree traversal progress.
 	/// Stores the tree traversal progress.
-	PODVector<ElemInfo> currentElementStack;
+	std::vector<ElemInfo> currentElementStack;
 	/// The type of the message we are building.
 	/// The type of the message we are building.
 	const SerializedMessageDesc &desc;
 	const SerializedMessageDesc &desc;
 };
 };

+ 21 - 15
ThirdParty/kNet/include/kNet/Socket.h

@@ -16,8 +16,6 @@
 /** @file Socket.h
 /** @file Socket.h
 	@brief The Socket class. */
 	@brief The Socket class. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #ifdef WIN32
 #ifdef WIN32
 
 
 #include "kNetBuildConfig.h"
 #include "kNetBuildConfig.h"
@@ -55,8 +53,8 @@ typedef unsigned int SOCKET;
 }
 }
 #endif
 #endif
 
 
-#include "Vector.h"
-#include "List.h"
+#include <vector>
+#include <list>
 
 
 #include "SharedPtr.h"
 #include "SharedPtr.h"
 #include "EndPoint.h"
 #include "EndPoint.h"
@@ -74,7 +72,7 @@ enum SocketTransportLayer
 	SocketOverTCP
 	SocketOverTCP
 };
 };
 
 
-String SocketTransportLayerToString(SocketTransportLayer transport);
+std::string SocketTransportLayerToString(SocketTransportLayer transport);
 
 
 /// Converts the given string (case-insensitive parsing) to the corresponding SocketTransportLayer enum.
 /// Converts the given string (case-insensitive parsing) to the corresponding SocketTransportLayer enum.
 /// "tcp" & "socketovertcp" -> SocketOverTCP.
 /// "tcp" & "socketovertcp" -> SocketOverTCP.
@@ -90,7 +88,7 @@ enum SocketType
 	ClientSocket ///< A client-side socket.
 	ClientSocket ///< A client-side socket.
 };
 };
 
 
-String SocketTypeToString(SocketType type);
+std::string SocketTypeToString(SocketType type);
 
 
 typedef int OverlappedTransferTag;
 typedef int OverlappedTransferTag;
 
 
@@ -99,8 +97,9 @@ typedef WSABUF kNetBuffer;
 #else
 #else
 struct kNetBuffer
 struct kNetBuffer
 {
 {
-	/// Specifies the number of bytes allocated to buf. This is the maximum amount of bytes that can
-	/// be written to buf.
+	/// Stores the number of bytes allocated to buf.
+	/// When sending out a message, this field specifies the number of bytes the client
+	/// can write to buf, at maximum.
 	unsigned long len;
 	unsigned long len;
 
 
 	char *buf;
 	char *buf;
@@ -114,9 +113,13 @@ struct OverlappedTransferBuffer
 	WSAOVERLAPPED overlapped;
 	WSAOVERLAPPED overlapped;
 #endif
 #endif
 
 
-	/// Specifies the number of bytes buffer.buf actually contains.
+	/// Stores the number of bytes actually in use in buffer.buf. When sending out a message,
+	/// specify the actual number of bytes filled to buffer.buf here.
 	int bytesContains;
 	int bytesContains;
 
 
+    /// Stores the total number of bytes allocated to the buffer in the overlapped structure.
+    int bytesAllocated;
+
 	sockaddr_in from;
 	sockaddr_in from;
 	socklen_t fromLen;
 	socklen_t fromLen;
 };
 };
@@ -188,9 +191,12 @@ public:
 	/// Starts the sending of new data. After having filled the data to send to the OverlappedTransferBuffer that is
 	/// Starts the sending of new data. After having filled the data to send to the OverlappedTransferBuffer that is
 	/// returned here, commit the send by calling EndSend. If you have called BeginSend, but decide not to send any data,
 	/// returned here, commit the send by calling EndSend. If you have called BeginSend, but decide not to send any data,
 	/// call AbortSend instead (otherwise memory will leak).
 	/// call AbortSend instead (otherwise memory will leak).
+    /// @param maxBytesToSend Specifies the size of the buffer that must be returned. Specify the size (or at least an 
+    ///         upper limit) of the message you are sending here. Specify the actual number of bytes filled in the resulting
+    ///         structure.
 	/// @return A transfer buffer where the data to send is to be filled in. If no new data can be sent at this time,
 	/// @return A transfer buffer where the data to send is to be filled in. If no new data can be sent at this time,
 	///         this function returns 0.
 	///         this function returns 0.
-	OverlappedTransferBuffer *BeginSend();
+	OverlappedTransferBuffer *BeginSend(int maxBytesToSend);
 	/// Finishes and queues up the given transfer that was created with a call to BeginSend.
 	/// Finishes and queues up the given transfer that was created with a call to BeginSend.
 	/// @return True if send succeeded, false otherwise. In either case, the ownership of the passed buffer send
 	/// @return True if send succeeded, false otherwise. In either case, the ownership of the passed buffer send
 	///         is taken by this Socket and may not be accessed anymore. Discard the pointer after calling this function.
 	///         is taken by this Socket and may not be accessed anymore. Discard the pointer after calling this function.
@@ -252,7 +258,7 @@ public:
 	/// Returns the local EndPoint this socket is bound to.
 	/// Returns the local EndPoint this socket is bound to.
 	const EndPoint &LocalEndPoint() const { return localEndPoint; }
 	const EndPoint &LocalEndPoint() const { return localEndPoint; }
 	/// Returns the local address (local hostname) of the local end point this socket is bound to.
 	/// Returns the local address (local hostname) of the local end point this socket is bound to.
-	const char *LocalAddress() const { return localHostName.CString(); }
+	const char *LocalAddress() const { return localHostName.c_str(); }
 	/// Returns the local port that this socket is bound to.
 	/// Returns the local port that this socket is bound to.
 	unsigned short LocalPort() const { return localEndPoint.port; }
 	unsigned short LocalPort() const { return localEndPoint.port; }
 
 
@@ -262,14 +268,14 @@ public:
 	const EndPoint &RemoteEndPoint() const { return remoteEndPoint; }
 	const EndPoint &RemoteEndPoint() const { return remoteEndPoint; }
 	/// Returns the destination address (destination hostname) of the remote end point this socket is connected to.
 	/// Returns the destination address (destination hostname) of the remote end point this socket is connected to.
 	/// If SocketType == ServerListenSocket, returns an empty string.
 	/// If SocketType == ServerListenSocket, returns an empty string.
-	const char *DestinationAddress() const { return remoteHostName.CString(); }
+	const char *DestinationAddress() const { return remoteHostName.c_str(); }
 	/// Returns the destination port of the remote end point this socket is connected to.
 	/// Returns the destination port of the remote end point this socket is connected to.
 	/// If SocketType == ServerListenSocket, returns 0.
 	/// If SocketType == ServerListenSocket, returns 0.
 	unsigned short DestinationPort() const { return remoteEndPoint.port; }
 	unsigned short DestinationPort() const { return remoteEndPoint.port; }
 
 
 	/// Returns a human-readable representation of this socket, specifying the peer address and port this socket is
 	/// Returns a human-readable representation of this socket, specifying the peer address and port this socket is
 	/// connected to.
 	/// connected to.
-	String ToString() const;
+	std::string ToString() const;
 
 
 	/// Sets the socket to blocking or nonblocking state.
 	/// Sets the socket to blocking or nonblocking state.
 	void SetBlocking(bool isBlocking);
 	void SetBlocking(bool isBlocking);
@@ -293,7 +299,7 @@ private:
 	/// Specifies the network host name of the local end point (the local system).
 	/// Specifies the network host name of the local end point (the local system).
 	/// If the local end point does not have a hostname, this field is the string representation of the
 	/// If the local end point does not have a hostname, this field is the string representation of the
 	/// system IP address (one of them, there may be multiple IPs).
 	/// system IP address (one of them, there may be multiple IPs).
-	String localHostName;
+	std::string localHostName;
 	
 	
 	/// Specifies the remote system end point (IP and port) this socket is bound to (== the "peer" address).
 	/// Specifies the remote system end point (IP and port) this socket is bound to (== the "peer" address).
 	/// If SocketType == ServerListenSocket or transport == SocketOverUDP, this socket is not bound
 	/// If SocketType == ServerListenSocket or transport == SocketOverUDP, this socket is not bound
@@ -308,7 +314,7 @@ private:
 	/// Specifies the network host name of the remote end point (== the remote system == the "peer").
 	/// Specifies the network host name of the remote end point (== the remote system == the "peer").
 	/// If the remote end point does not have a known hostname, this field is the string representation of the
 	/// If the remote end point does not have a known hostname, this field is the string representation of the
 	/// remote IP address. If SocketType == ServerListenSocket, this field is empty.
 	/// remote IP address. If SocketType == ServerListenSocket, this field is empty.
-	String remoteHostName;
+	std::string remoteHostName;
 
 
 	/// Specifies the underlying transport protocol that this Socket is using (TCP or UDP).
 	/// Specifies the underlying transport protocol that this Socket is using (TCP or UDP).
 	SocketTransportLayer transport;
 	SocketTransportLayer transport;

+ 1 - 3
ThirdParty/kNet/include/kNet/Sort.h

@@ -16,8 +16,6 @@
 /** @file Sort.h
 /** @file Sort.h
 	@brief A range of comparison sort algorithms. */
 	@brief A range of comparison sort algorithms. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include "Clock.h"
 #include "Clock.h"
 
 
 //#include "LCG.h"
 //#include "LCG.h"
@@ -29,7 +27,7 @@ namespace kNet
 /** @brief A range of comparison sort algorithms.
 /** @brief A range of comparison sort algorithms.
 
 
 	When to use one of these sorts and when to use the std sorts? 
 	When to use one of these sorts and when to use the std sorts? 
-		(std::sort, std::stable_sort, List::sort etc.)
+		(std::sort, std::stable_sort, std::list::sort etc.)
 
 
 	1)	Always consider using the standard versions first. For example, the visual c++ 
 	1)	Always consider using the standard versions first. For example, the visual c++ 
 		std::sort is on average faster than the introsort described here. Additionally, 
 		std::sort is on average faster than the introsort described here. Additionally, 

+ 21 - 23
ThirdParty/kNet/include/kNet/StatsEventHierarchy.h

@@ -16,10 +16,8 @@
 /** @file StatsEventHierarchy.h
 /** @file StatsEventHierarchy.h
 	@brief Stores a hierarchy of network events for profiling purposes. */
 	@brief Stores a hierarchy of network events for profiling purposes. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
-#include "Map.h"
-#include "Str.h"
+#include <map>
+#include <string>
 
 
 #include "kNet/WaitFreeQueue.h"
 #include "kNet/WaitFreeQueue.h"
 #include "kNet/Clock.h"
 #include "kNet/Clock.h"
@@ -42,7 +40,7 @@ struct StatsEvent
 	tick_t time;
 	tick_t time;
 };
 };
 
 
-inline String FirstToken(const char *str, char delimiter, int &nextTokenStart)
+inline std::string FirstToken(const char *str, char delimiter, int &nextTokenStart)
 {
 {
 	int i = 0;
 	int i = 0;
 	while(str[i] != '\0' && str[i] != delimiter)
 	while(str[i] != '\0' && str[i] != delimiter)
@@ -51,20 +49,20 @@ inline String FirstToken(const char *str, char delimiter, int &nextTokenStart)
 		nextTokenStart = -1;
 		nextTokenStart = -1;
 	else
 	else
 		nextTokenStart = i+1;
 		nextTokenStart = i+1;
-	return String(str, i);
+	return std::string(str, str + i);
 }
 }
 
 
 class StatsEventHierarchyNode
 class StatsEventHierarchyNode
 {
 {
 public:
 public:
-	///\todo To improve performance, don't use a String as a key to the map, and replace the map with a more efficient data structure.
-	typedef Map<String, StatsEventHierarchyNode> NodeMap;
+	///\todo To improve performance, don't use a std::string as a key to the map, and replace the map with a more efficient data structure.
+	typedef std::map<std::string, StatsEventHierarchyNode> NodeMap;
 	NodeMap children;
 	NodeMap children;
 
 
 	WaitFreeQueue<StatsEvent> events;
 	WaitFreeQueue<StatsEvent> events;
 
 
 	/// Specifies the unit of the numeric data in this node.
 	/// Specifies the unit of the numeric data in this node.
-	String valueType;
+	std::string valueType;
 
 
 	StatsEventHierarchyNode()
 	StatsEventHierarchyNode()
 	:events(4) // The default size for the queue must be at least four elements (pow2, >2).
 	:events(4) // The default size for the queue must be at least four elements (pow2, >2).
@@ -89,8 +87,8 @@ public:
 	{
 	{
 		PruneOldEventsThisLevel(ageMSecs);
 		PruneOldEventsThisLevel(ageMSecs);
 
 
-		for(NodeMap::Iterator iter = children.Begin(); iter != children.End(); ++iter)
-			iter->second_.PruneOldEventsHierarchy(ageMSecs);
+		for(NodeMap::iterator iter = children.begin(); iter != children.end(); ++iter)
+			iter->second.PruneOldEventsHierarchy(ageMSecs);
 	}
 	}
 
 
 	void AddEventToThisLevel(float value, int oldAgeMSecs)
 	void AddEventToThisLevel(float value, int oldAgeMSecs)
@@ -108,13 +106,13 @@ public:
 	void AddEventToHierarchy(const char *name, float value, const char *valueType, int oldAgeMSecs)
 	void AddEventToHierarchy(const char *name, float value, const char *valueType, int oldAgeMSecs)
 	{
 	{
 		int nextTokenStart = 0;
 		int nextTokenStart = 0;
-		String childName = FirstToken(name, '.', nextTokenStart);
-		if (childName.Empty())
+		std::string childName = FirstToken(name, '.', nextTokenStart);
+		if (childName.empty())
 			AddEventToThisLevel(value, oldAgeMSecs);
 			AddEventToThisLevel(value, oldAgeMSecs);
 		else
 		else
 		{
 		{
-			NodeMap::Iterator iter = children.Find(childName);
-			if (iter == children.End())
+			NodeMap::iterator iter = children.find(childName);
+			if (iter == children.end()) 
 				children[childName].valueType = valueType; // To optimize, only copy this field in the first time the node is created.
 				children[childName].valueType = valueType; // To optimize, only copy this field in the first time the node is created.
 			if (nextTokenStart == -1)
 			if (nextTokenStart == -1)
 				children[childName].AddEventToThisLevel(value, oldAgeMSecs);
 				children[childName].AddEventToThisLevel(value, oldAgeMSecs);
@@ -126,13 +124,13 @@ public:
 	StatsEventHierarchyNode *FindChild(const char *name)
 	StatsEventHierarchyNode *FindChild(const char *name)
 	{
 	{
 		int nextTokenStart = 0;
 		int nextTokenStart = 0;
-		String childName = FirstToken(name, '.', nextTokenStart);
-		if (childName.Empty())
+		std::string childName = FirstToken(name, '.', nextTokenStart);
+		if (childName.empty())
 			return this;
 			return this;
 		else
 		else
 		{
 		{
-			NodeMap::Iterator iter = children.Find(childName);
-			if (iter == children.End())
+			NodeMap::iterator iter = children.find(childName);
+			if (iter == children.end()) 
 				return 0;
 				return 0;
 			if (nextTokenStart == -1)
 			if (nextTokenStart == -1)
 				return &children[childName];
 				return &children[childName];
@@ -150,8 +148,8 @@ public:
 	{
 	{
 		int count = AccumulateTotalCountThisLevel();
 		int count = AccumulateTotalCountThisLevel();
 
 
-		for(NodeMap::ConstIterator iter = children.Begin(); iter != children.End(); ++iter)
-			count += iter->second_.AccumulateTotalCountHierarchy();
+		for(NodeMap::const_iterator iter = children.begin(); iter != children.end(); ++iter)
+			count += iter->second.AccumulateTotalCountHierarchy();
 
 
 		return count;
 		return count;
 	}
 	}
@@ -168,8 +166,8 @@ public:
 	{
 	{
 		float value = AccumulateTotalValueThisLevel();
 		float value = AccumulateTotalValueThisLevel();
 
 
-		for(NodeMap::ConstIterator iter = children.Begin(); iter != children.End(); ++iter)
-			value += iter->second_.AccumulateTotalValueHierarchy();
+		for(NodeMap::const_iterator iter = children.begin(); iter != children.end(); ++iter)
+			value += iter->second.AccumulateTotalValueHierarchy();
 
 
 		return value;
 		return value;
 	}
 	}

+ 3 - 3
ThirdParty/kNet/include/kNet/StdCMallocHeap.h

@@ -37,7 +37,7 @@ public:
 	static inline void *Alloc(StdCAlloc *, size_t size, size_t alignment, const char * /*nameTag*/ = 0, AllocFlags /*flags*/ = AFAllocLow)
 	static inline void *Alloc(StdCAlloc *, size_t size, size_t alignment, const char * /*nameTag*/ = 0, AllocFlags /*flags*/ = AFAllocLow)
 	{
 	{
 		assert(IS_POW2(alignment));
 		assert(IS_POW2(alignment));
-#ifdef WIN32
+#ifdef _MSC_VER
 		void *ptr = _aligned_malloc(size, alignment);
 		void *ptr = _aligned_malloc(size, alignment);
 #else
 #else
 		void *ptr = malloc(size); ///\todo aligned_malloc on unix?
 		void *ptr = malloc(size); ///\todo aligned_malloc on unix?
@@ -46,7 +46,7 @@ public:
 	}
 	}
 	static inline void Free(StdCAlloc *, void *ptr)
 	static inline void Free(StdCAlloc *, void *ptr)
 	{
 	{
-#ifdef WIN32
+#ifdef _MSC_VER
 		_aligned_free(ptr);
 		_aligned_free(ptr);
 #else
 #else
 		free(ptr);
 		free(ptr);
@@ -56,7 +56,7 @@ public:
 	///\todo Perhaps support Resize(void *ptr, size_t newSize); ?
 	///\todo Perhaps support Resize(void *ptr, size_t newSize); ?
 	static inline size_t Size(StdCAlloc *, void *ptr)
 	static inline size_t Size(StdCAlloc *, void *ptr)
 	{
 	{
-#ifdef WIN32
+#ifdef _MSC_VER
 		return ::_msize(ptr);
 		return ::_msize(ptr);
 #else
 #else
 		assert(false && "N/I");
 		assert(false && "N/I");

+ 1 - 3
ThirdParty/kNet/include/kNet/TCPMessageConnection.h

@@ -16,8 +16,6 @@
 /** @file TCPMessageConnection.h
 /** @file TCPMessageConnection.h
 	@brief The TCPMessageConnection class.*/
 	@brief The TCPMessageConnection class.*/
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include "MessageConnection.h"
 #include "MessageConnection.h"
 #include "RingBuffer.h"
 #include "RingBuffer.h"
 
 
@@ -62,7 +60,7 @@ private:
 	void ExtractMessages();
 	void ExtractMessages();
 
 
 	// The following are temporary data structures used by various internal routines for processing.
 	// The following are temporary data structures used by various internal routines for processing.
-	Vector<NetworkMessage*> serializedMessages; // MessageConnection::TCPSendOutPacket()
+	std::vector<NetworkMessage*> serializedMessages; // MessageConnection::TCPSendOutPacket()
 
 
 	void PerformDisconnection();
 	void PerformDisconnection();
 
 

+ 2 - 4
ThirdParty/kNet/include/kNet/Thread.h

@@ -16,9 +16,7 @@
 /** @file Thread.h
 /** @file Thread.h
 	@brief The Thread class. Implements threading either using Boost, native Win32 or pthreads constructs. */
 	@brief The Thread class. Implements threading either using Boost, native Win32 or pthreads constructs. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
-#include "Str.h"
+#include <string>
 
 
 #ifdef KNET_USE_BOOST
 #ifdef KNET_USE_BOOST
 #include <boost/thread.hpp>
 #include <boost/thread.hpp>
@@ -56,7 +54,7 @@ typedef boost::thread::id ThreadId;
 typedef pthread_t ThreadId;
 typedef pthread_t ThreadId;
 #endif
 #endif
 
 
-String ThreadIdToString(const ThreadId &id);
+std::string ThreadIdToString(const ThreadId &id);
 
 
 class Thread : public RefCountable
 class Thread : public RefCountable
 {
 {

+ 15 - 0
ThirdParty/kNet/include/kNet/Types.h

@@ -20,6 +20,10 @@
 
 
 #include "kNetBuildConfig.h"
 #include "kNetBuildConfig.h"
 
 
+#ifdef __MINGW32__
+#include <stdint.h>
+#endif
+
 // As a reminder: http://predef.sourceforge.net/prestd.html
 // As a reminder: http://predef.sourceforge.net/prestd.html
 
 
 // If we have C99, take the types from there.
 // If we have C99, take the types from there.
@@ -77,4 +81,15 @@ typedef signed long long s64; ///< 8 bytes signed. 9,223,372,036,854,775,807 ~ 9
 
 
 #endif
 #endif
 
 
+// kNet special types:
+
+namespace kNet
+{
+	/// Identifies a UDP datagram by auto-incrementing number. Contains 22 actual bits of data.
+	typedef unsigned long packet_id_t;
+	/// Identifies the type of a network message. Contains 30 actual bits of data.
+	/// Valid user range is [6, 1073741821 == 0x3FFFFFFD].
+	typedef unsigned long message_id_t;
+}
+
 #endif // ~KNET_NO_FIXEDWIDTH_TYPES
 #endif // ~KNET_NO_FIXEDWIDTH_TYPES

+ 28 - 11
ThirdParty/kNet/include/kNet/UDPMessageConnection.h

@@ -16,8 +16,6 @@
 /** @file UDPMessageConnection.h
 /** @file UDPMessageConnection.h
 	@brief The UDPMessageConnection class. */
 	@brief The UDPMessageConnection class. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include "MessageConnection.h"
 #include "MessageConnection.h"
 #include "SequentialIntegerSet.h"
 #include "SequentialIntegerSet.h"
 #include "Array.h"
 #include "Array.h"
@@ -68,6 +66,8 @@ public:
 	UDPMessageConnection(Network *owner, NetworkServer *ownerServer, Socket *socket, ConnectionState startingState);
 	UDPMessageConnection(Network *owner, NetworkServer *ownerServer, Socket *socket, ConnectionState startingState);
 	~UDPMessageConnection();
 	~UDPMessageConnection();
 
 
+	void SetDatagramInFlowRatePerSecond(int newDatagramReceiveRate, bool internalCall);
+
 	float RetransmissionTimeout() const { return retransmissionTimeout; }
 	float RetransmissionTimeout() const { return retransmissionTimeout; }
 
 
 	float DatagramSendRate() const { return datagramSendRate; }
 	float DatagramSendRate() const { return datagramSendRate; }
@@ -80,7 +80,7 @@ public:
 
 
 	size_t NumOutboundUnackedDatagrams() const { return outboundPacketAckTrack.Size(); }
 	size_t NumOutboundUnackedDatagrams() const { return outboundPacketAckTrack.Size(); }
 
 
-	size_t NumReceivedUnackedDatagrams() const { return inboundPacketAckTrack.Size(); }
+	size_t NumReceivedUnackedDatagrams() const { return inboundPacketAckTrack.size(); }
 
 
 	float PacketLossCount() const { return packetLossCount; }
 	float PacketLossCount() const { return packetLossCount; }
 
 
@@ -99,6 +99,10 @@ private:
 	/// @param bytesRead [out] Returns the total number of bytes containes in the datagrams that were read.
 	/// @param bytesRead [out] Returns the total number of bytes containes in the datagrams that were read.
 	SocketReadResult UDPReadSocket(size_t &bytesRead); // [worker thread]
 	SocketReadResult UDPReadSocket(size_t &bytesRead); // [worker thread]
 
 
+	// Congestion control and data rate management:
+	void PerformFlowControl(); // [worker thread]
+	void HandleFlowControlRequestMessage(const char *data, size_t numBytes); // [worker thread]
+
 	void UpdateRTOCounterOnPacketAck(float rtt); // [worker thread]
 	void UpdateRTOCounterOnPacketAck(float rtt); // [worker thread]
 	void UpdateRTOCounterOnPacketLoss(); // [worker thread]
 	void UpdateRTOCounterOnPacketLoss(); // [worker thread]
 
 
@@ -113,7 +117,7 @@ private:
 	void SendPacketAckMessage(); // [worker thread]
 	void SendPacketAckMessage(); // [worker thread]
 	void HandlePacketAckMessage(const char *data, size_t numBytes); // [worker thread]
 	void HandlePacketAckMessage(const char *data, size_t numBytes); // [worker thread]
 	
 	
-	bool HandleMessage(packet_id_t packetID, u32 messageID, const char *data, size_t numBytes); // [worker thread]
+	bool HandleMessage(packet_id_t packetID, message_id_t messageID, const char *data, size_t numBytes); // [worker thread]
 
 
 	/// Refreshes Packet Loss related statistics.
 	/// Refreshes Packet Loss related statistics.
 	void ComputePacketLoss(); // [worker thread]
 	void ComputePacketLoss(); // [worker thread]
@@ -149,8 +153,8 @@ private:
 
 
 	/// The flow control algorithm:
 	/// The flow control algorithm:
 	float datagramSendRate; ///< The number of datagrams/second to send.
 	float datagramSendRate; ///< The number of datagrams/second to send.
+
 	float lowestDatagramSendRateOnPacketLoss;
 	float lowestDatagramSendRateOnPacketLoss;
-	int slowModeDelay; ///< Go into slow increase mode for some time on receiving loss
 
 
 	// These variables correspond to RFC2988, http://tools.ietf.org/html/rfc2988 , section 2.
 	// These variables correspond to RFC2988, http://tools.ietf.org/html/rfc2988 , section 2.
 	bool rttCleared; ///< If true, smoothedRTT and rttVariation do not contain meaningful values, but "are clear".
 	bool rttCleared; ///< If true, smoothedRTT and rttVariation do not contain meaningful values, but "are clear".
@@ -219,11 +223,16 @@ private:
 
 
 	/// Connection control update timer.
 	/// Connection control update timer.
 	PolledTimer udpUpdateTimer;
 	PolledTimer udpUpdateTimer;
-	
-	typedef Map<packet_id_t, PacketAckTrack> PacketAckTrackMap;
+
+	PolledTimer statsUpdateTimer;
+
+	typedef std::map<packet_id_t, PacketAckTrack> PacketAckTrackMap;
 	/// Contains the messages we have sent out that we are waiting for the other party to Ack.
 	/// Contains the messages we have sent out that we are waiting for the other party to Ack.
+//	PacketAckTrackMap outboundPacketAckTrack;
 	typedef WaitFreeQueue<PacketAckTrack> PacketAckTrackQueue;
 	typedef WaitFreeQueue<PacketAckTrack> PacketAckTrackQueue;
 	PacketAckTrackQueue outboundPacketAckTrack;
 	PacketAckTrackQueue outboundPacketAckTrack;
+//	typedef OrderedHashTable<PacketAckTrack, PacketAckTrack> PacketAckTrackTable;
+//	PacketAckTrackTable outboundPacketAckTrack;
 
 
 	static int BiasedBinarySearchFindPacketIndex(UDPMessageConnection::PacketAckTrackQueue &queue, int packetID);
 	static int BiasedBinarySearchFindPacketIndex(UDPMessageConnection::PacketAckTrackQueue &queue, int packetID);
 
 
@@ -234,9 +243,17 @@ private:
 	// Contains a list of all messages we've received that we need to Ack at some point.
 	// Contains a list of all messages we've received that we need to Ack at some point.
 	PacketAckTrackMap inboundPacketAckTrack;
 	PacketAckTrackMap inboundPacketAckTrack;
 
 
+	/// The number of UDP packets to send out per second.
+	int datagramOutRatePerSecond;
+
+	/// The number of UDP packets to receive per second. Of course the local end of the
+	/// connection cannot directly control this, but it uses the FlowControlRequest
+	/// packet to send it to the other party.
+	int datagramInRatePerSecond;
+
 	/// Contains the reliable message numbers of all reliable messages we've received.
 	/// Contains the reliable message numbers of all reliable messages we've received.
 	/// Used to detect and discard duplicate messages we've received.
 	/// Used to detect and discard duplicate messages we've received.
-	Set<unsigned long> receivedReliableMessages;
+	std::set<unsigned long> receivedReliableMessages;
 
 
 	SequentialIntegerSet receivedPacketIDs;
 	SequentialIntegerSet receivedPacketIDs;
 	/// Specifies the packet ID of the most recent datagram we sent. Used currently only
 	/// Specifies the packet ID of the most recent datagram we sent. Used currently only
@@ -246,9 +263,9 @@ private:
 	// The following are temporary data structures used by various internal routines for processing.
 	// The following are temporary data structures used by various internal routines for processing.
 	// They are created here as members to avoid having to create objects on the stack at each call to 
 	// They are created here as members to avoid having to create objects on the stack at each call to 
 	// time-sensitive functions.
 	// time-sensitive functions.
-	Vector<NetworkMessage *> datagramSerializedMessages; // MessageConnection::UDPSendOutPacket()
-	Vector<NetworkMessage *> skippedMessages; // MessageConnection::UDPSendOutPacket()
-	PODVector<char> assembledData; // MessageConnection::DatagramExtractMessages
+	std::vector<NetworkMessage *> datagramSerializedMessages; // MessageConnection::UDPSendOutPacket()
+	std::vector<NetworkMessage *> skippedMessages; // MessageConnection::UDPSendOutPacket()
+	std::vector<char> assembledData; // MessageConnection::DatagramExtractMessages
 
 
 	/// Returns the average number of inbound packet loss, packets/sec.
 	/// Returns the average number of inbound packet loss, packets/sec.
 	float GetPacketLossCount() const { return packetLossCount; }
 	float GetPacketLossCount() const { return packetLossCount; }

+ 1 - 0
ThirdParty/kNet/include/kNet/WaitFreeQueue.h

@@ -16,6 +16,7 @@
 /** @file WaitFreeQueue.h
 /** @file WaitFreeQueue.h
 	@brief The WaitFreeQueue<T> template class. */
 	@brief The WaitFreeQueue<T> template class. */
 
 
+#include <stddef.h>
 #include "Alignment.h"
 #include "Alignment.h"
 
 
 namespace kNet
 namespace kNet

+ 1 - 1
ThirdParty/kNet/include/kNet/qt/GraphDialog.h

@@ -1,4 +1,4 @@
-/* Copyright 2010 Jukka Jylänki
+/* Copyright The kNet Project.
 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    you may not use this file except in compliance with the License.

+ 3 - 1
ThirdParty/kNet/include/kNet/qt/MessageConnectionDialog.h

@@ -1,4 +1,4 @@
-/* Copyright 2010 Jukka Jylänki
+/* Copyright The kNet Project.
 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    you may not use this file except in compliance with the License.
@@ -45,6 +45,8 @@ public:
 
 
 public slots:
 public slots:
 	void Update();
 	void Update();
+
+	void OpenSendSimulationWindow();
 };
 };
 
 
 } // ~kNet
 } // ~kNet

+ 1 - 1
ThirdParty/kNet/include/kNet/qt/NetworkDialog.h

@@ -1,4 +1,4 @@
-/* Copyright 2010 Jukka Jylänki
+/* Copyright The kNet Project.
 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    you may not use this file except in compliance with the License.

+ 52 - 0
ThirdParty/kNet/include/kNet/qt/NetworkSimulationDialog.h

@@ -0,0 +1,52 @@
+/* Copyright The kNet Project.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. */
+#pragma once
+
+/** @file NetworkSimulationDialog.h
+	@brief Shows a UI for specifying parameters for network simulations. */
+
+#include "kNetBuildConfig.h"
+
+#ifdef KNET_USE_QT
+
+#include <QObject>
+#include <QWidget>
+#include <QTimer>
+
+#include "kNet/MessageConnection.h"
+#include "kNet/SharedPtr.h"
+
+class Ui_NetworkSimulationDialog;
+
+namespace kNet
+{
+
+class NetworkSimulationDialog : public QWidget
+{
+	Q_OBJECT;
+
+	Ptr(MessageConnection) connection;
+	Ui_NetworkSimulationDialog *dialog;
+
+public:
+	NetworkSimulationDialog(QWidget *parent, Ptr(MessageConnection) connection);
+	~NetworkSimulationDialog();
+
+public slots:
+	void ParameterChanged();
+};
+
+} // ~kNet
+
+#endif

+ 7 - 0
ThirdParty/kNet/include/kNet/win32/WS2Include.h

@@ -38,5 +38,12 @@
 #undef _WINSOCKAPI_
 #undef _WINSOCKAPI_
 #endif
 #endif
 
 
+#ifdef __MINGW32__
+#ifdef _WIN32_WINNT
+#undef _WIN32_WINNT
+#endif
+#define _WIN32_WINNT 0x0501
+#endif
+
 #include <winsock2.h>
 #include <winsock2.h>
 #include <ws2tcpip.h>
 #include <ws2tcpip.h>

+ 1 - 0
ThirdParty/kNet/include/kNetFwd.h

@@ -33,6 +33,7 @@ namespace kNet
 	class Network;
 	class Network;
 	class NetworkMessage;
 	class NetworkMessage;
 	class NetworkServer;
 	class NetworkServer;
+	struct OverlappedTransferBuffer;
 	class PolledTimer;
 	class PolledTimer;
 	class SerializationStructCompiler;
 	class SerializationStructCompiler;
 	class SerializedDataIterator;
 	class SerializedDataIterator;

+ 144 - 0
ThirdParty/kNet/src/64BitAllocDebugger.cpp

@@ -0,0 +1,144 @@
+/* Copyright The kNet Project.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. */
+
+/** @file 64BitAllocDebugger.cpp
+	@brief Virtually reserves all memory on Windows in the < 4GB memory area so that all
+		pointers used by the application are outside the 32-bit range.
+	
+	Idea and code taken from http://randomascii.wordpress.com/2012/02/14/64-bit-made-easy/ */
+
+#ifdef _WIN64
+#include "kNet/64BitAllocDebugger.h"
+#include <stdio.h>
+#include <Windows.h>
+#include <vector>
+
+BottomMemoryAllocator::BottomMemoryAllocator()
+{
+	ReserveBottomMemory();
+}
+
+BottomMemoryAllocator::~BottomMemoryAllocator()
+{
+	FreeBottomMemory();
+}
+
+void BottomMemoryAllocator::ReserveBottomMemory()
+{
+	static bool s_initialized = false;
+	if ( s_initialized )
+		return;
+	s_initialized = true;
+
+	// Start by reserving large blocks of address space, and then
+	// gradually reduce the size in order to capture all of the
+	// fragments. Technically we should continue down to 64 KB but
+	// stopping at 1 MB is sufficient to keep most allocators out.
+	const size_t LOW_MEM_LINE = 0x100000000LL;
+	size_t totalReservation = 0;
+	size_t numVAllocs = 0;
+	size_t numHeapAllocs = 0;
+	size_t oneMB = 1024 * 1024;
+	for (size_t size = 256 * oneMB; size >= oneMB; size /= 2)
+	{
+		for (;;)
+		{
+			void* p = VirtualAlloc(0, size, MEM_RESERVE, PAGE_NOACCESS);
+			if (!p)
+				break;
+ 
+			if ((size_t)p >= LOW_MEM_LINE)
+			{
+				// We don't need this memory, so release it completely.
+				VirtualFree(p, 0, MEM_RELEASE);
+				break;
+			}
+			totalReservation += size;
+			++numVAllocs;
+			virtualAllocated.push_back(p);
+		}
+	}
+
+	// Now repeat the same process but making heap allocations, to use up
+	// the already reserved heap blocks that are below the 4 GB line.
+	HANDLE heap = GetProcessHeap();
+	for (size_t blockSize = 64 * 1024; blockSize >= 16; blockSize /= 2)
+	{
+		for (;;)
+		{
+			void* p = HeapAlloc(heap, 0, blockSize);
+
+			if (!p)
+				break;
+
+			if ((size_t)p >= LOW_MEM_LINE)
+			{
+				// We don't need this memory, so release it completely.
+				HeapFree(heap, 0, p);
+				break;
+			}
+
+			totalReservation += blockSize;
+			++numHeapAllocs;
+			heapAllocated.push_back(p);
+		}
+	}
+
+	// Perversely enough the CRT doesn't use the process heap. Suck up
+	// the memory the CRT heap has already reserved.
+
+	for (size_t blockSize = 64 * 1024; blockSize >= 16; blockSize /= 2)
+	{
+		for (;;)
+		{
+			void* p = malloc(blockSize);
+
+			if (!p)
+				break;
+
+			if ((size_t)p >= LOW_MEM_LINE)
+			{
+				// We don't need this memory, so release it completely.
+				free(p);
+				break;
+			}
+
+			totalReservation += blockSize;
+			++numHeapAllocs;
+			mallocAllocated.push_back(p);
+		}
+	}
+
+	// Print diagnostics showing how many allocations we had to make in
+	// order to reserve all of low memory, typically less than 200.
+	printf("Reserved %1.3f MB (%d vallocs," 
+					"%d heap allocs) of low-memory.\n",
+			totalReservation / (1024 * 1024.0),
+			(int)numVAllocs, (int)numHeapAllocs);
+}
+
+void BottomMemoryAllocator::FreeBottomMemory()
+{
+	for(size_t i = 0; i < virtualAllocated.size(); ++i)
+		VirtualFree(virtualAllocated[i], 0, MEM_RELEASE);
+
+	HANDLE heap = GetProcessHeap();
+	for(size_t i = 0; i < heapAllocated.size(); ++i)
+		HeapFree(heap, 0, heapAllocated[i]);
+
+	for(size_t i = 0; i < mallocAllocated.size(); ++i)
+		free(mallocAllocated[i]);
+}
+
+#endif

+ 163 - 10
ThirdParty/kNet/src/DataDeserializer.cpp

@@ -15,10 +15,9 @@
 /** @file DataDeserializer.cpp
 /** @file DataDeserializer.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include <cassert>
 #include <cassert>
 #include <cstring>
 #include <cstring>
+#include <cmath>
 
 
 #include "kNet/DebugMemoryLeakCheck.h"
 #include "kNet/DebugMemoryLeakCheck.h"
 
 
@@ -102,7 +101,7 @@ u32 DataDeserializer::GetDynamicElemCount()
 }
 }
 
 
 template<>
 template<>
-String DataDeserializer::Read<String>()
+std::string DataDeserializer::Read<std::string>()
 {
 {
 	return ReadString();
 	return ReadString();
 }
 }
@@ -131,7 +130,161 @@ u32 DataDeserializer::ReadBits(int numBits)
 	return val;
 	return val;
 }
 }
 
 
-void DataDeserializer::SkipBits(size_t numBits)
+float DataDeserializer::ReadUnsignedFixedPoint(int numIntegerBits, int numDecimalBits)
+{
+	u32 fp = ReadBits(numIntegerBits + numDecimalBits);
+	return fp / (float)(1 << numDecimalBits);
+}
+
+float DataDeserializer::ReadSignedFixedPoint(int numIntegerBits, int numDecimalBits)
+{
+	// Reading a [0, 2k-1] range -> remap back to [-k, k-1] range.
+	return ReadUnsignedFixedPoint(numIntegerBits, numDecimalBits) - (float)(1 << (numIntegerBits-1));
+}
+
+float DataDeserializer::ReadQuantizedFloat(float minRange, float maxRange, int numBits)
+{
+	u32 val = ReadBits(numBits);
+	return minRange + val * (maxRange-minRange) / (float)((1 << numBits) - 1);
+}
+
+float DataDeserializer::ReadMiniFloat(bool signBit, int exponentBits, int mantissaBits, int exponentBias)
+{
+	assert(sizeof(float) == 4);
+	assert(exponentBits > 0);
+	assert(exponentBits <= 8);
+	assert(mantissaBits > 0);
+	assert(mantissaBits <= 23);
+
+	bool sign = signBit ? Read<bit>() : false;
+	u32 exponent = ReadBits(exponentBits);
+	u32 mantissa = ReadBits(mantissaBits);
+
+	// Shift back the decoded mantissa to proper position.
+	mantissa <<= 23 - mantissaBits;
+
+	// Reconstruct the float exponent.
+	if (exponent == (u32)((1 << exponentBits) - 1)) // If the read exponent was all ones, reconstruct 11111111.
+		exponent = 0xFF;
+	else if (exponent != 0) // If the read exponent was not zero, it was a normal number.
+		exponent = exponent - exponentBias + 127;
+	// else exponent == 0, meaning a zero or a denormal.
+
+	u32 value = (sign ? 0x80000000 : 0) | (exponent << 23) | mantissa;
+
+	return *(float*)&value;
+}
+
+#define PI ((float)3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679)
+
+void DataDeserializer::ReadNormalizedVector2D(int numBits, float &x, float &y)
+{
+	float angle = ReadQuantizedFloat(-PI, PI, numBits);
+	x = cos(angle);
+	y = sin(angle);
+}
+
+void DataDeserializer::ReadVector2D(int magnitudeIntegerBits, int magnitudeDecimalBits, int directionBits, float &x, float &y)
+{
+	// Read the length in unsigned fixed point format.
+	// The following line is effectively the same as calling ReadUnsignedFixedPoint, but manually perform it
+	// to be precisely able to examine whether the length is zero.
+	u32 fp = ReadBits(magnitudeIntegerBits + magnitudeDecimalBits);
+	if (fp != 0) // If length is non-zero, the stream also contains the direction.
+	{
+		float length = fp / (float)(1 << magnitudeDecimalBits);
+
+		// Read the direction in the stream.
+		float angle = ReadQuantizedFloat(-PI, PI, directionBits);
+		x = cos(angle) * length;
+		y = sin(angle) * length;
+	}
+	else // Zero length, no direction present in the buffer.
+	{
+		x = y = 0.f;
+	}
+}
+
+void DataDeserializer::ReadNormalizedVector3D(int numBitsYaw, int numBitsPitch, float &x, float &y, float &z)
+{
+	float azimuth = ReadQuantizedFloat(-PI, PI, numBitsYaw);
+	float inclination = ReadQuantizedFloat(-PI/2, PI/2, numBitsPitch);
+
+	float cx = cos(inclination);
+	x = cx * sin(azimuth);
+	y = -sin(inclination);
+	z = cx * cos(azimuth);
+}
+
+void DataDeserializer::ReadVector3D(int numBitsYaw, int numBitsPitch, int magnitudeIntegerBits, int magnitudeDecimalBits, float &x, float &y, float &z)
+{
+	// Read the length in unsigned fixed point format.
+	// The following line is effectively the same as calling ReadUnsignedFixedPoint, but manually perform it
+	// to be precisely able to examine whether the length is zero.
+	u32 fp = ReadBits(magnitudeIntegerBits + magnitudeDecimalBits);
+	if (fp != 0) // If length is non-zero, the stream also contains the direction.
+	{
+		float length = fp / (float)(1 << magnitudeDecimalBits);
+
+		float azimuth = ReadQuantizedFloat(-PI, PI, numBitsYaw);
+		float inclination = ReadQuantizedFloat(-PI/2, PI/2, numBitsPitch);
+
+		float cx = cos(inclination);
+		x = cx * sin(azimuth) * length;
+		y = -sin(inclination) * length;
+		z = cx * cos(azimuth) * length;
+	}
+	else // length is zero, stream does not contain the direction.
+	{
+		x = y = z = 0.f;
+	}
+}
+
+void DataDeserializer::ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2)
+{
+	assert(max1 * max2 < (1 << numBits));
+	u32 val = ReadBits(numBits);
+	val2 = val % max2;
+	val1 = val / max2;
+}
+
+void DataDeserializer::ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2, int &val3, int max3)
+{
+	assert(max1 * max2 * max3 < (1 << numBits));
+	u32 val = ReadBits(numBits);
+	val3 = val % max3;
+	val /= max3;
+	val2 = val % max2;
+	val1 = val / max2;
+}
+
+void DataDeserializer::ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2, int &val3, int max3, int &val4, int max4)
+{
+	assert(max1 * max2 * max3 * max4 < (1 << numBits));
+	u32 val = ReadBits(numBits);
+	val4 = val % max4;
+	val /= max4;
+	val3 = val % max3;
+	val /= max3;
+	val2 = val % max2;
+	val1 = val / max2;
+}
+
+void DataDeserializer::ReadArithmeticEncoded(int numBits, int &val1, int max1, int &val2, int max2, int &val3, int max3, int &val4, int max4, int &val5, int max5)
+{
+	assert(max1 * max2 * max3 * max4 * max5 < (1 << numBits));
+	u32 val = ReadBits(numBits);
+	val5 = val % max5;
+	val /= max5;
+	val4 = val % max4;
+	val /= max4;
+	val3 = val % max3;
+	val /= max3;
+	val2 = val % max2;
+	val1 = val / max2;
+}
+
+void DataDeserializer::SkipBits(int numBits)
 {
 {
 	assert(!iter);
 	assert(!iter);
 
 
@@ -146,24 +299,24 @@ void DataDeserializer::SkipBits(size_t numBits)
 		throw NetException("Not enough bits left in DataDeserializer::SkipBits(2)!");
 		throw NetException("Not enough bits left in DataDeserializer::SkipBits(2)!");
 }
 }
 
 
-String DataDeserializer::ReadString()
+std::string DataDeserializer::ReadString()
 {
 {
 	u32 length = (iter ? GetDynamicElemCount() : Read<u8>());
 	u32 length = (iter ? GetDynamicElemCount() : Read<u8>());
 	if (BitsLeft() < length*8)
 	if (BitsLeft() < length*8)
 		throw NetException("Not enough bytes left in DataDeserializer::ReadString!");
 		throw NetException("Not enough bytes left in DataDeserializer::ReadString!");
 
 
-	String str;
+	std::string str;
 	if (bitOfs == 0)
 	if (bitOfs == 0)
 	{
 	{
-		str.Append(data + elemOfs, length);
+		str.append(data + elemOfs, length);
 		elemOfs += length;
 		elemOfs += length;
 	}
 	}
 	else
 	else
 	{
 	{
-		PODVector<u8> bytes(length+1);
+		std::vector<u8> bytes(length+1);
 		ReadArray<u8>(&bytes[0], length);
 		ReadArray<u8>(&bytes[0], length);
 
 
-		str.Append((char*)&bytes[0], length);
+		str.append((char*)&bytes[0], length);
 	}
 	}
 
 
 	if (iter)
 	if (iter)
@@ -172,7 +325,7 @@ String DataDeserializer::ReadString()
 
 
 	// Perform string validation: Replace any offending values with the space bar character.
 	// Perform string validation: Replace any offending values with the space bar character.
 	// Valid values: 0x00 (null), 0x09 (tab), 0x0D, 0x0A (newlines), [32, 253] (characters)
 	// Valid values: 0x00 (null), 0x09 (tab), 0x0D, 0x0A (newlines), [32, 253] (characters)
-	for(size_t i = 0; i < str.Length(); ++i)
+	for(size_t i = 0; i < str.length(); ++i)
 		if ((unsigned char)str[i] >= 254 || ((unsigned char)str[i] < 32 && str[i] != 0x0D && str[i] != 0x0A && str[i] != 0x09)) // Retain newlines and tab.
 		if ((unsigned char)str[i] >= 254 || ((unsigned char)str[i] < 32 && str[i] != 0x0D && str[i] != 0x0A && str[i] != 0x09)) // Retain newlines and tab.
 			str[i] = 0x20; // Space bar character
 			str[i] = 0x20; // Space bar character
 
 

+ 249 - 16
ThirdParty/kNet/src/DataSerializer.cpp

@@ -15,9 +15,9 @@
 /** @file DataSerializer.cpp
 /** @file DataSerializer.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include <cstring>
 #include <cstring>
+#include <sstream>
+#include <cmath>
 
 
 #include "kNet/DebugMemoryLeakCheck.h"
 #include "kNet/DebugMemoryLeakCheck.h"
 
 
@@ -33,7 +33,7 @@ DataSerializer::DataSerializer(size_t maxBytes_)
 
 
 	maxBytes = maxBytes_;
 	maxBytes = maxBytes_;
 	messageData = new SerializedMessage();
 	messageData = new SerializedMessage();
-	messageData->data.Resize(maxBytes);
+	messageData->data.resize(maxBytes);
 	data = &messageData->data[0];
 	data = &messageData->data[0];
 
 
 	ResetFill();
 	ResetFill();
@@ -48,7 +48,7 @@ DataSerializer::DataSerializer(size_t maxBytes_, const SerializedMessageDesc *ms
 
 
 	maxBytes = maxBytes_;
 	maxBytes = maxBytes_;
 	messageData = new SerializedMessage();
 	messageData = new SerializedMessage();
-	messageData->data.Resize(maxBytes);
+	messageData->data.resize(maxBytes);
 	data = &messageData->data[0];
 	data = &messageData->data[0];
 
 
 	ResetFill();
 	ResetFill();
@@ -69,24 +69,24 @@ DataSerializer::DataSerializer(char *data_, size_t maxBytes_, const SerializedMe
 	ResetFill();
 	ResetFill();
 }
 }
 
 
-DataSerializer::DataSerializer(PODVector<char> &data_, size_t maxBytes_)
+DataSerializer::DataSerializer(std::vector<char> &data_, size_t maxBytes_)
 {
 {
-	if (data_.Size() < maxBytes_)
-		data_.Resize(maxBytes_);
-	if (data_.Size() == 0 || maxBytes_ == 0)
-		throw NetException("Cannot instantiate a DataSerializer object to a zero-sized Vector-based buffer!");
+	if (data_.size() < maxBytes_)
+		data_.resize(maxBytes_);
+	if (data_.size() == 0 || maxBytes_ == 0)
+		throw NetException("Cannot instantiate a DataSerializer object to a zero-sized std::vector-based buffer!");
 	data = &data_[0];
 	data = &data_[0];
 	maxBytes = maxBytes_;
 	maxBytes = maxBytes_;
 
 
 	ResetFill();
 	ResetFill();
 }
 }
 
 
-DataSerializer::DataSerializer(PODVector<char> &data_, size_t maxBytes_, const SerializedMessageDesc *msgTemplate)
+DataSerializer::DataSerializer(std::vector<char> &data_, size_t maxBytes_, const SerializedMessageDesc *msgTemplate)
 {
 {
-	if (data_.Size() < maxBytes_)
-		data_.Resize(maxBytes_);
-	if (data_.Size() == 0 || maxBytes_ == 0)
-		throw NetException("Cannot instantiate a DataSerializer object to a zero-sized Vector-based buffer!");
+	if (data_.size() < maxBytes_)
+		data_.resize(maxBytes_);
+	if (data_.size() == 0 || maxBytes_ == 0)
+		throw NetException("Cannot instantiate a DataSerializer object to a zero-sized std::vector-based buffer!");
 	data = &data_[0];
 	data = &data_[0];
 	maxBytes = maxBytes_;
 	maxBytes = maxBytes_;
 
 
@@ -159,6 +159,226 @@ void DataSerializer::AddAlignedByteArray(const void *srcData, u32 numBytes)
 	elemOfs += numBytes;
 	elemOfs += numBytes;
 }
 }
 
 
+u32 DataSerializer::AddUnsignedFixedPoint(int numIntegerBits, int numDecimalBits, float value)
+{
+	assert(numIntegerBits >= 0);
+	assert(numDecimalBits > 0);
+	assert(numIntegerBits + numDecimalBits <= 32);
+	const float maxVal = (float)(1 << numIntegerBits);
+	const u32 maxBitPattern = (1 << (numIntegerBits + numDecimalBits)) - 1; // All ones - the largest value we can send.
+	u32 outVal = value <= 0 ? 0 : (value >= maxVal ? maxBitPattern : (u32)(value * (float)(1 << numDecimalBits)));
+	assert(outVal <= maxBitPattern);
+	AppendBits(outVal, numIntegerBits + numDecimalBits);
+	return outVal;
+}
+
+u32 DataSerializer::AddSignedFixedPoint(int numIntegerBits, int numDecimalBits, float value)
+{
+	// Adding a [-k, k-1] range -> remap to unsigned [0, 2k-1] range and send that instead.
+	return AddUnsignedFixedPoint(numIntegerBits, numDecimalBits, value + (float)(1 << (numIntegerBits-1)));
+}
+
+static inline float ClampF(float val, float minVal, float maxVal) { return val <= minVal ? minVal : (val >= maxVal ? maxVal : val); }
+
+u32 DataSerializer::AddQuantizedFloat(float minRange, float maxRange, int numBits, float value)
+{
+	u32 outVal = (u32)((ClampF(value, minRange, maxRange) - minRange) * (float)((1 << numBits)-1) / (maxRange - minRange));
+	AppendBits(outVal, numBits);
+	return outVal;
+}
+
+void DataSerializer::AddMiniFloat(bool signBit, int exponentBits, int mantissaBits, int exponentBias, float value)
+{
+	// Float structure:
+	// 1-bit sign
+	// 8-bit exponent
+	// 23-bit mantissa
+	// s eeeeeeee mmmmmmmmmmmmmmmmmmmmmmm
+	// Different float categories:
+	// 0 00000000 00000000000000000000000  +zero
+	// 1 00000000 00000000000000000000000  -zero
+	// s 00000000 mmmmmmmmmmmmmmmmmmmmmmm  A denormal number, mmmmm != 0, interpreted as (-1)^s * 2^-126 * 0.mmmmm
+	// s eeeeeeee xxxxxxxxxxxxxxxxxxxxxxx  A normal number, eeeee != 0, interpreted as (-1)^s * 2^(e-127) * 1.mmmmm
+	// 0 11111111 00000000000000000000000  +inf
+	// 1 11111111 00000000000000000000000  -inf
+	// y 11111111 1xxxxxxxxxxxxxxxxxxxxxx  Quiet NaN, y and xxxxx are arbitrary (custom) payload for the NaN.
+	// y 11111111 0xxxxxxxxxxxxxxxxxxxxxx  Signalling NaN, y and xxxxx != 0 is arbitrary payload for the NaN.
+
+	// When writing our custom low-precision minifloat, make sure that values in each of the above categories stays in
+	// the same category, if possible:
+	// +zero: Reducing bits does not affect the value.
+	// -zero: Reducing bits does not affect the value. If sending unsigned, -zero becomes +zero.
+	// denormals: Reducing bits from mantissa gracefully loses precision. Reducing exponent does not affect the value.
+	//            If sending unsigned, negative denormals flush to zero.
+	// normals: Reducing bits from exponent can cause the exponent to overflow or underflow.
+	//          If the exponent is too large to be encoded, +inf/-inf is sent instead.
+	//          If the exponent is too small to be encoded, the value is flushed to zero. \todo Could create a denormal!
+	// +inf: Reducing bits does not affect the value.
+	// -inf: Reducing bits from exponent or mantissa does not matter. If sending unsigned, -inf flushes to zero.
+	// QNaN/SNaN: Reducing bits loses data from the custom NaN payload field. If mantissaBits == 0, cannot differentiat
+	//            between QNaN and SNaN.
+
+	assert(sizeof(float) == 4);
+	assert(exponentBits > 0);
+	assert(exponentBits <= 8);
+	assert(mantissaBits > 0);
+	assert(mantissaBits <= 23);
+	u32 v = *(u32*)&value;
+	u32 biasedExponent = (v & 0x7F800000) >> 23;
+	u32 mantissa = v & 0x7FFFFF;
+	bool sign = (v & 0x80000000) != 0; // If true, the float is negative.
+
+	// Write the sign bit, if sending out a signed minifloat. Otherwise, clamp all negative numbers to +zero.
+	if (signBit)
+		Add<bit>(sign);
+	else if (sign && biasedExponent != 0)
+		biasedExponent = mantissa = 0; // If the number was not a NaN, write out +zero.
+
+	// The maximum biased exponent value in the reduced precision representation. This corresponds to NaNs and +/-Infs.
+	const u32 maxBiasedExponent = (1 << exponentBits) - 1;
+
+	int trueExponent = biasedExponent - 127; // The true exponent of the float, if this number is a normal number.
+	int newBiasedExponent;
+
+	// Compute the new biased exponent value to send.
+	if (biasedExponent != 0xFF && biasedExponent != 0) // Is this a normalized float?
+	{
+		newBiasedExponent = trueExponent + exponentBias;
+		
+		// Check if the new biased exponent is too large to be represented, and the float overflows to a +/-Inf.
+		if (newBiasedExponent >= (int)maxBiasedExponent)
+		{
+			newBiasedExponent = maxBiasedExponent;
+			mantissa = 0; // To specify that this is an Inf and not a NaN.
+		}
+		// Check if the new biased exponent underflowed. In that case flush to zero.
+		///\todo This is not absolutely correct with respect to denormalized numbers. Underflowing
+		/// the exponent should produce a denormalized number, but this directly makes it zero.
+		if (newBiasedExponent <= 0)
+			newBiasedExponent = mantissa = 0;
+	}
+	else
+		newBiasedExponent = biasedExponent; // either all zeroes (+/-zero or denormal) or all ones (nan or inf).
+
+	// Scrap the given number of precision from the mantissa.
+	u32 newMantissa = mantissa >> (23 - mantissaBits);
+
+	// If the float was a SNaN, make sure it stays a SNaN after some of the NaN payload was removed.
+	if (biasedExponent == 0xFF && mantissa != 0 && newMantissa == 0)
+		newMantissa = 1; // Set the mantissa to nonzero to denote a NaN (and don't set the MSB of mantissa, to treat it as SNaN)
+
+	AppendBits(newBiasedExponent, exponentBits);
+	AppendBits(newMantissa, mantissaBits);
+}
+
+#define PI ((float)3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679)
+
+void DataSerializer::AddNormalizedVector2D(float x, float y, int numBits)
+{
+	// Call atan2() to get the aimed angle of the 2D vector in the range [-PI, PI], then quantize the 1D result to the desired precision.
+	AddQuantizedFloat(-PI, PI, numBits, atan2(y, x));
+}
+
+int DataSerializer::AddVector2D(float x, float y, int magnitudeIntegerBits, int magnitudeDecimalBits, int directionBits)
+{
+	// Compute the length of the vector. Use a fixed-point representation to store the length.
+	float length = sqrt(x*x+y*y);
+	u32 bitVal = AddUnsignedFixedPoint(magnitudeIntegerBits, magnitudeDecimalBits, length);
+
+	// If length == 0, don't need to send the angle, as it's a zero vector.
+	if (bitVal != 0)
+	{
+		// Call atan2() to get the aimed angle of the 2D vector in the range [-PI, PI], then quantize the 1D result to the desired precision.
+		float angle = atan2(y, x);
+		AddQuantizedFloat(-PI, PI, directionBits, atan2(y, x));
+		return magnitudeIntegerBits + magnitudeDecimalBits + directionBits;
+	}
+	else
+		return magnitudeIntegerBits + magnitudeDecimalBits;
+}
+
+void DataSerializer::AddNormalizedVector3D(float x, float y, float z, int numBitsYaw, int numBitsPitch)
+{
+	// Convert to spherical coordinates. We assume that the vector (x,y,z) has been normalized beforehand.
+	float azimuth = atan2(x, z); // The 'yaw'
+	float inclination = asin(-y); // The 'pitch'
+
+	AddQuantizedFloat(-PI, PI, numBitsYaw, azimuth);
+	AddQuantizedFloat(-PI/2, PI/2, numBitsPitch, inclination);
+}
+
+int DataSerializer::AddVector3D(float x, float y, float z, int numBitsYaw, int numBitsPitch, int magnitudeIntegerBits, int magnitudeDecimalBits)
+{
+	float length = sqrt(x*x + y*y + z*z);
+
+	u32 bitVal = AddUnsignedFixedPoint(magnitudeIntegerBits, magnitudeDecimalBits, length);
+
+	if (bitVal != 0)
+	{
+		// The written length was not zero. Send the spherical angles as well.
+		float azimuth = atan2(x, z);
+		float inclination = asin(-y / length);
+
+		AddQuantizedFloat(-PI, PI, numBitsYaw, azimuth);
+		AddQuantizedFloat(-PI/2, PI/2, numBitsPitch, inclination);
+		return magnitudeIntegerBits + magnitudeDecimalBits + numBitsYaw + numBitsPitch;
+	}
+	else // The vector is (0,0,0). Don't send spherical angles as they're redundant.
+		return magnitudeIntegerBits + magnitudeDecimalBits;
+}
+
+void DataSerializer::AddArithmeticEncoded(int numBits, int val1, int max1, int val2, int max2)
+{
+	assert(max1 * max2 < (1 << numBits));
+	assert(val1 >= 0);
+	assert(val1 < max1);
+	assert(val2 >= 0);
+	assert(val2 < max2);
+	AppendBits(val1 * max2 + val2, numBits);
+}
+
+void DataSerializer::AddArithmeticEncoded(int numBits, int val1, int max1, int val2, int max2, int val3, int max3)
+{
+	assert(max1 * max2 * max3 < (1 << numBits));
+	assert(val1 >= 0);
+	assert(val1 < max1);
+	assert(val2 >= 0);
+	assert(val2 < max2);
+	assert(val3 >= 0);
+	assert(val3 < max3);
+	AppendBits((val1 * max2 + val2) * max3 + val3, numBits);
+}
+
+void DataSerializer::AddArithmeticEncoded(int numBits, int val1, int max1, int val2, int max2, int val3, int max3, int val4, int max4)
+{
+	assert(max1 * max2 * max3 * max4 < (1 << numBits));
+	assert(val1 >= 0);
+	assert(val1 < max1);
+	assert(val2 >= 0);
+	assert(val2 < max2);
+	assert(val3 >= 0);
+	assert(val3 < max3);
+	assert(val4 >= 0);
+	assert(val4 < max4);
+	AppendBits(((val1 * max2 + val2) * max3 + val3) * max4 + val4, numBits);
+}
+
+void DataSerializer::AddArithmeticEncoded(int numBits, int val1, int max1, int val2, int max2, int val3, int max3, int val4, int max4, int val5, int max5)
+{
+	assert(max1 * max2 * max3 * max4 * max5 < (1 << numBits));
+	assert(val1 >= 0);
+	assert(val1 < max1);
+	assert(val2 >= 0);
+	assert(val2 < max2);
+	assert(val3 >= 0);
+	assert(val3 < max3);
+	assert(val4 >= 0);
+	assert(val4 < max4);
+	assert(val5 >= 0);
+	assert(val5 < max5);
+	AppendBits((((val1 * max2 + val2) * max3 + val3) * max4 + val4) * max5 + val5, numBits);
+}
+
 /// Requires a template to be present to use this.
 /// Requires a template to be present to use this.
 void DataSerializer::SetVaryingElemSize(u32 count)
 void DataSerializer::SetVaryingElemSize(u32 count)
 {
 {
@@ -183,7 +403,7 @@ void DataSerializer::Add<const char*>(const char * const & value)
 }
 }
 
 
 template<>
 template<>
-void DataSerializer::Add<String>(const String &value)
+void DataSerializer::Add<std::string>(const std::string &value)
 {
 {
 	AddString(value);
 	AddString(value);
 }
 }
@@ -199,7 +419,7 @@ void DataSerializer::AddString(const char *str)
 {
 {
 	size_t len = strlen(str);
 	size_t len = strlen(str);
 	if (iter)
 	if (iter)
-		SetVaryingElemSize(len);
+		SetVaryingElemSize((u32)len);
 	else
 	else
 		Add<u8>(len);
 		Add<u8>(len);
 
 
@@ -213,4 +433,17 @@ void DataSerializer::SkipNumBytes(size_t numBytes)
 		throw NetException("DataSerializer::SkipNumBytes: Attempted to travel past the end of the array!");
 		throw NetException("DataSerializer::SkipNumBytes: Attempted to travel past the end of the array!");
 }
 }
 
 
+bool DataSerializer::DebugReadBit(int bitIndex) const
+{
+	return (data[bitIndex >> 3] & (1 << (bitIndex & 7))) != 0;
+}
+
+std::string DataSerializer::DebugReadBits(int startIndex, int endIndex) const
+{
+	std::stringstream ss;
+	for(int i = startIndex; i < endIndex; ++i)
+		ss << DebugReadBit(i) ? "1" : "0";
+	return ss.str();
+}
+
 } // ~kNet
 } // ~kNet

+ 36 - 38
ThirdParty/kNet/src/FragmentedTransferManager.cpp

@@ -15,8 +15,6 @@
 /** @file FragmentedTransferManager.cpp
 /** @file FragmentedTransferManager.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include <cstring>
 #include <cstring>
 
 
 #ifdef KNET_USE_BOOST
 #ifdef KNET_USE_BOOST
@@ -37,17 +35,17 @@ namespace kNet
 
 
 void FragmentedSendManager::FragmentedTransfer::AddMessage(NetworkMessage *message)
 void FragmentedSendManager::FragmentedTransfer::AddMessage(NetworkMessage *message)
 {
 {
-	fragments.Push(message);
+	fragments.push_back(message);
 	message->transfer = this;
 	message->transfer = this;
 }
 }
 
 
 bool FragmentedSendManager::FragmentedTransfer::RemoveMessage(NetworkMessage *message)
 bool FragmentedSendManager::FragmentedTransfer::RemoveMessage(NetworkMessage *message)
 {
 {
-	for(List<NetworkMessage*>::Iterator iter = fragments.Begin(); iter != fragments.End(); ++iter)
+	for(std::list<NetworkMessage*>::iterator iter = fragments.begin(); iter != fragments.end(); ++iter)
 		if (*iter == message)
 		if (*iter == message)
 		{
 		{
 			message->transfer = 0;
 			message->transfer = 0;
-			fragments.Erase(iter);
+			fragments.erase(iter);
 			LOG(LogVerbose, "Removing message with seqnum %d (fragnum %d) from transfer ID %d (%p).", (int)message->messageNumber, (int)message->fragmentIndex, id, this);
 			LOG(LogVerbose, "Removing message with seqnum %d (fragnum %d) from transfer ID %d (%p).", (int)message->messageNumber, (int)message->fragmentIndex, id, this);
 			return true;
 			return true;
 		}
 		}
@@ -56,8 +54,8 @@ bool FragmentedSendManager::FragmentedTransfer::RemoveMessage(NetworkMessage *me
 
 
 FragmentedSendManager::FragmentedTransfer *FragmentedSendManager::AllocateNewFragmentedTransfer()
 FragmentedSendManager::FragmentedTransfer *FragmentedSendManager::AllocateNewFragmentedTransfer()
 {
 {
-	transfers.Push(FragmentedTransfer());
-	FragmentedTransfer *transfer = &transfers.Back();
+	transfers.push_back(FragmentedTransfer());
+	FragmentedTransfer *transfer = &transfers.back();
 	transfer->id = -1;
 	transfer->id = -1;
 	transfer->totalNumFragments = 0;
 	transfer->totalNumFragments = 0;
 
 
@@ -69,13 +67,13 @@ FragmentedSendManager::FragmentedTransfer *FragmentedSendManager::AllocateNewFra
 void FragmentedSendManager::FreeFragmentedTransfer(FragmentedTransfer *transfer)
 void FragmentedSendManager::FreeFragmentedTransfer(FragmentedTransfer *transfer)
 {
 {
 	// Remove all references from any NetworkMessages to this structure.
 	// Remove all references from any NetworkMessages to this structure.
-	for(List<NetworkMessage*>::Iterator iter = transfer->fragments.Begin(); iter != transfer->fragments.End(); ++iter)
+	for(std::list<NetworkMessage*>::iterator iter = transfer->fragments.begin(); iter != transfer->fragments.end(); ++iter)
 		(*iter)->transfer = 0;
 		(*iter)->transfer = 0;
 
 
-	for(TransferList::Iterator iter = transfers.Begin(); iter != transfers.End(); ++iter)
+	for(TransferList::iterator iter = transfers.begin(); iter != transfers.end(); ++iter)
 		if (&*iter == transfer)
 		if (&*iter == transfer)
 		{
 		{
-			transfers.Erase(iter);
+			transfers.erase(iter);
 			LOG(LogObjectAlloc, "Freed fragmented transfer ID=%d, numFragments: %d (%p).", transfer->id, (int)transfer->totalNumFragments, transfer);
 			LOG(LogObjectAlloc, "Freed fragmented transfer ID=%d, numFragments: %d (%p).", transfer->id, (int)transfer->totalNumFragments, transfer);
 			return;
 			return;
 		}
 		}
@@ -91,7 +89,7 @@ void FragmentedSendManager::RemoveMessage(FragmentedTransfer *transfer, NetworkM
 		return;
 		return;
 	}
 	}
 
 
-	if (transfer->fragments.Size() == 0)
+	if (transfer->fragments.size() == 0)
 		FreeFragmentedTransfer(transfer);
 		FreeFragmentedTransfer(transfer);
 }
 }
 
 
@@ -108,7 +106,7 @@ bool FragmentedSendManager::AllocateFragmentedTransferID(FragmentedTransfer &tra
 	while(used)
 	while(used)
 	{
 	{
 		used = false;
 		used = false;
-		for(TransferList::Iterator iter = transfers.Begin(); iter != transfers.End(); ++iter)
+		for(TransferList::iterator iter = transfers.begin(); iter != transfers.end(); ++iter)
 		{
 		{
 			if (iter->id == transferID)
 			if (iter->id == transferID)
 			{
 			{
@@ -128,8 +126,8 @@ bool FragmentedSendManager::AllocateFragmentedTransferID(FragmentedTransfer &tra
 
 
 void FragmentedSendManager::FreeAllTransfers()
 void FragmentedSendManager::FreeAllTransfers()
 {
 {
-	while(transfers.Size() > 0)
-		FreeFragmentedTransfer(&transfers.Front());
+	while(transfers.size() > 0)
+		FreeFragmentedTransfer(&transfers.front());
 }
 }
 
 
 void FragmentedReceiveManager::NewFragmentStartReceived(int transferID, int numTotalFragments, const char *data, size_t numBytes)
 void FragmentedReceiveManager::NewFragmentStartReceived(int transferID, int numTotalFragments, const char *data, size_t numBytes)
@@ -143,16 +141,16 @@ void FragmentedReceiveManager::NewFragmentStartReceived(int transferID, int numT
 		return;
 		return;
 	}
 	}
 
 
-	for(size_t i = 0; i < transfers.Size(); ++i)
+	for(size_t i = 0; i < transfers.size(); ++i)
 		if (transfers[i].transferID == transferID)
 		if (transfers[i].transferID == transferID)
 		{
 		{
 			LOG(LogError, "An existing transfer with ID %d existed! Deleting it.", transferID);
 			LOG(LogError, "An existing transfer with ID %d existed! Deleting it.", transferID);
-			transfers.Erase(transfers.Begin() + i);
+			transfers.erase(transfers.begin() + i);
 			--i;
 			--i;
 		}
 		}
 
 
-	transfers.Push(ReceiveTransfer());
-	ReceiveTransfer &transfer = transfers.Back();
+	transfers.push_back(ReceiveTransfer());
+	ReceiveTransfer &transfer = transfers.back();
 	transfer.transferID = transferID;
 	transfer.transferID = transferID;
 	transfer.numTotalFragments = numTotalFragments;
 	transfer.numTotalFragments = numTotalFragments;
 
 
@@ -170,28 +168,28 @@ bool FragmentedReceiveManager::NewFragmentReceived(int transferID, int fragmentN
 		return false;
 		return false;
 	}
 	}
 
 
-	for(size_t i = 0; i < transfers.Size(); ++i)
+	for(size_t i = 0; i < transfers.size(); ++i)
 		if (transfers[i].transferID == transferID)
 		if (transfers[i].transferID == transferID)
 		{
 		{
 			ReceiveTransfer &transfer = transfers[i];
 			ReceiveTransfer &transfer = transfers[i];
 
 
-			for(size_t j = 0; j < transfer.fragments.Size(); ++j)
+			for(size_t j = 0; j < transfer.fragments.size(); ++j)
 				if (transfer.fragments[j].fragmentIndex == fragmentNumber)
 				if (transfer.fragments[j].fragmentIndex == fragmentNumber)
 				{
 				{
 					LOG(LogError, "A fragment with fragmentNumber %d already exists for transferID %d. Discarding the new fragment! Old size: %db, discarded size: %db",
 					LOG(LogError, "A fragment with fragmentNumber %d already exists for transferID %d. Discarding the new fragment! Old size: %db, discarded size: %db",
-						fragmentNumber, transferID, (int)transfer.fragments[j].data.Size(), (int)numBytes);
+						fragmentNumber, transferID, (int)transfer.fragments[j].data.size(), (int)numBytes);
 					return false;
 					return false;
 				}
 				}
 
 
-			transfer.fragments.Push(ReceiveFragment());
-			ReceiveFragment &fragment = transfer.fragments.Back();
+			transfer.fragments.push_back(ReceiveFragment());
+			ReceiveFragment &fragment = transfer.fragments.back();
 			fragment.fragmentIndex = fragmentNumber;
 			fragment.fragmentIndex = fragmentNumber;
-			fragment.data.Insert(fragment.data.End(), data, data + numBytes);
+			fragment.data.insert(fragment.data.end(), data, data + numBytes);
 
 
-			if (transfer.fragments.Size() >= (size_t)transfer.numTotalFragments)
+			if (transfer.fragments.size() >= (size_t)transfer.numTotalFragments)
 			{
 			{
 				LOG(LogData, "Finished receiving a fragmented transfer that consisted of %d fragments (transferID=%d).",
 				LOG(LogData, "Finished receiving a fragmented transfer that consisted of %d fragments (transferID=%d).",
-					(int)transfer.fragments.Size(), transfer.transferID);
+					(int)transfer.fragments.size(), transfer.transferID);
 				return true;
 				return true;
 			}
 			}
 			else
 			else
@@ -202,38 +200,38 @@ bool FragmentedReceiveManager::NewFragmentReceived(int transferID, int fragmentN
 	return false;
 	return false;
 }
 }
 
 
-void FragmentedReceiveManager::AssembleMessage(int transferID, PODVector<char> &assembledData)
+void FragmentedReceiveManager::AssembleMessage(int transferID, std::vector<char> &assembledData)
 {
 {
-	for(size_t i = 0; i < transfers.Size(); ++i)
+	for(size_t i = 0; i < transfers.size(); ++i)
 		if (transfers[i].transferID == transferID)
 		if (transfers[i].transferID == transferID)
 		{
 		{
 			ReceiveTransfer &transfer = transfers[i];
 			ReceiveTransfer &transfer = transfers[i];
 			size_t totalSize = 0;
 			size_t totalSize = 0;
 
 
-			for(size_t j = 0; j < transfer.fragments.Size(); ++j)
-				totalSize += transfer.fragments[j].data.Size();
+			for(size_t j = 0; j < transfer.fragments.size(); ++j)
+				totalSize += transfer.fragments[j].data.size();
 
 
-			assembledData.Resize(totalSize);
+			assembledData.resize(totalSize);
 
 
 			///\todo Sort by fragmentIndex.
 			///\todo Sort by fragmentIndex.
 			
 			
 			size_t offset = 0;
 			size_t offset = 0;
-			for(size_t j = 0; j < transfer.fragments.Size(); ++j)
+			for(size_t j = 0; j < transfer.fragments.size(); ++j)
 			{
 			{
-				assert(transfer.fragments[j].data.Size() > 0);
-				memcpy(&assembledData[offset], &transfer.fragments[j].data[0], transfer.fragments[j].data.Size());
-				offset += transfer.fragments[j].data.Size();
-				assert(offset <= assembledData.Size());
+				assert(transfer.fragments[j].data.size() > 0);
+				memcpy(&assembledData[offset], &transfer.fragments[j].data[0], transfer.fragments[j].data.size());
+				offset += transfer.fragments[j].data.size();
+				assert(offset <= assembledData.size());
 			}
 			}
 		}
 		}
 }
 }
 
 
 void FragmentedReceiveManager::FreeMessage(int transferID)
 void FragmentedReceiveManager::FreeMessage(int transferID)
 {
 {
-	for(size_t i = 0; i < transfers.Size(); ++i)
+	for(size_t i = 0; i < transfers.size(); ++i)
 		if (transfers[i].transferID == transferID)
 		if (transfers[i].transferID == transferID)
 		{
 		{
-			transfers.Erase(transfers.Begin() + i);
+			transfers.erase(transfers.begin() + i);
 			return;
 			return;
 		}
 		}
 }
 }

+ 88 - 88
ThirdParty/kNet/src/MessageConnection.cpp

@@ -15,8 +15,6 @@
 /** @file MessageConnection.cpp
 /** @file MessageConnection.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include <algorithm>
 #include <algorithm>
 #include <iostream>
 #include <iostream>
 #include <cassert>
 #include <cassert>
@@ -49,7 +47,7 @@ namespace
 
 
 	/// The interval at which we send ping messages.
 	/// The interval at which we send ping messages.
 	///\todo Make this user-defineable.
 	///\todo Make this user-defineable.
-	const float pingIntervalMSecs = 1000.f;
+	const float pingIntervalMSecs = 3.5 * 1000.f;
 	/// The interval at which we update the internal statistics fields.
 	/// The interval at which we update the internal statistics fields.
 	const float statsRefreshIntervalMSecs = 1000.f;
 	const float statsRefreshIntervalMSecs = 1000.f;
 	/// The time interval after which, if we don't get a response to a PingRequest message, the connection is declared lost.
 	/// The time interval after which, if we don't get a response to a PingRequest message, the connection is declared lost.
@@ -64,17 +62,17 @@ namespace
 namespace kNet
 namespace kNet
 {
 {
 
 
-void AppendU8ToVector(PODVector<char> &data, unsigned long value)
+void AppendU8ToVector(std::vector<char> &data, unsigned long value)
 {
 {
-	data.Insert(data.End(), (const char *)&value, (const char *)&value + 1);
+	data.insert(data.end(), (const char *)&value, (const char *)&value + 1);
 }
 }
 
 
-void AppendU32ToVector(PODVector<char> &data, unsigned long value)
+void AppendU32ToVector(std::vector<char> &data, unsigned long value)
 {
 {
-	data.Insert(data.End(), (const char *)&value, (const char *)&value + 4);
+	data.insert(data.end(), (const char *)&value, (const char *)&value + 4);
 }
 }
 
 
-String ConnectionStateToString(ConnectionState state)
+std::string ConnectionStateToString(ConnectionState state)
 {
 {
 	switch(state)
 	switch(state)
 	{
 	{
@@ -104,6 +102,7 @@ bytesInTotal(0), bytesOutTotal(0)
 #endif
 #endif
 {
 {
 	connectionState = startingState;
 	connectionState = startingState;
+	networkSendSimulator.owner = this;
 
 
 	eventMsgsOutAvailable = CreateNewEvent(EventWaitSignal);
 	eventMsgsOutAvailable = CreateNewEvent(EventWaitSignal);
 	assert(eventMsgsOutAvailable.IsValid());
 	assert(eventMsgsOutAvailable.IsValid());
@@ -195,7 +194,7 @@ bool MessageConnection::WaitToEstablishConnection(int maxMSecsToWait)
 		Clock::Sleep(1); ///\todo Instead of waiting multiple 1msec slices, should wait for proper event.
 		Clock::Sleep(1); ///\todo Instead of waiting multiple 1msec slices, should wait for proper event.
 
 
 	LOG(LogWaits, "MessageConnection::WaitToEstablishConnection: Waited %f msecs for connection. Result: %s.",
 	LOG(LogWaits, "MessageConnection::WaitToEstablishConnection: Waited %f msecs for connection. Result: %s.",
-		timer.MSecsElapsed(), ConnectionStateToString(GetConnectionState()).CString());
+		timer.MSecsElapsed(), ConnectionStateToString(GetConnectionState()).c_str());
 
 
 	return GetConnectionState() == ConnectionOK;
 	return GetConnectionState() == ConnectionOK;
 }
 }
@@ -211,7 +210,7 @@ void MessageConnection::Disconnect(int maxMSecsToWait)
 		return;
 		return;
 
 
 	LOG(LogInfo, "MessageConnection::Disconnect(%d msecs): Write-closing connection. connectionState = %s, socket readOpen:%s, socket writeOpen:%s.", 
 	LOG(LogInfo, "MessageConnection::Disconnect(%d msecs): Write-closing connection. connectionState = %s, socket readOpen:%s, socket writeOpen:%s.", 
-		maxMSecsToWait, ConnectionStateToString(connectionState).CString(), socket->IsReadOpen() ? "true":"false",
+		maxMSecsToWait, ConnectionStateToString(connectionState).c_str(), socket->IsReadOpen() ? "true":"false",
 		socket->IsWriteOpen() ? "true":"false");
 		socket->IsWriteOpen() ? "true":"false");
 	assert(maxMSecsToWait >= 0);
 	assert(maxMSecsToWait >= 0);
 
 
@@ -226,7 +225,7 @@ void MessageConnection::Disconnect(int maxMSecsToWait)
 		}
 		}
 
 
 		LOG(LogWaits, "MessageConnection::Disconnect: Waited %f msecs for disconnection. Result: %s.",
 		LOG(LogWaits, "MessageConnection::Disconnect: Waited %f msecs for disconnection. Result: %s.",
-			timer.MSecsElapsed(), ConnectionStateToString(GetConnectionState()).CString());
+			timer.MSecsElapsed(), ConnectionStateToString(GetConnectionState()).c_str());
 	}
 	}
 
 
 	if (GetConnectionState() == ConnectionClosed)
 	if (GetConnectionState() == ConnectionClosed)
@@ -241,13 +240,13 @@ void MessageConnection::Close(int maxMSecsToWait) // [main thread]
 	{
 	{
 		Disconnect(maxMSecsToWait);
 		Disconnect(maxMSecsToWait);
 		LOG(LogInfo, "MessageConnection::Close(%d msecs): Disconnecting. connectionState = %s, readOpen:%s, writeOpen:%s.", 
 		LOG(LogInfo, "MessageConnection::Close(%d msecs): Disconnecting. connectionState = %s, readOpen:%s, writeOpen:%s.", 
-			maxMSecsToWait, ConnectionStateToString(connectionState).CString(), (socket && socket->IsReadOpen()) ? "true":"false",
+			maxMSecsToWait, ConnectionStateToString(connectionState).c_str(), (socket && socket->IsReadOpen()) ? "true":"false",
 			(socket && socket->IsWriteOpen()) ? "true":"false");
 			(socket && socket->IsWriteOpen()) ? "true":"false");
 	}
 	}
 
 
 	if (owner)
 	if (owner)
 	{
 	{
-		LOG(LogInfo, "MessageConnection::Close: Closed connection to %s.", ToString().CString());
+		LOG(LogInfo, "MessageConnection::Close: Closed connection to %s.", ToString().c_str());
 		owner->CloseConnection(this); // This will cause this connection to be disconnected of its worker thread, so that we can safely proceed to tear down the socket.
 		owner->CloseConnection(this); // This will cause this connection to be disconnected of its worker thread, so that we can safely proceed to tear down the socket.
 		assert(!IsWorkerThreadRunning());
 		assert(!IsWorkerThreadRunning());
 		owner = 0;
 		owner = 0;
@@ -272,11 +271,11 @@ void MessageConnection::Close(int maxMSecsToWait) // [main thread]
 	if (inboundMessageQueue.Size() > 0)
 	if (inboundMessageQueue.Size() > 0)
 		LOG(LogVerbose, "MessageConnection::Close(): Had %d messages in inboundMessageQueue!", (int)inboundMessageQueue.Size());
 		LOG(LogVerbose, "MessageConnection::Close(): Had %d messages in inboundMessageQueue!", (int)inboundMessageQueue.Size());
 
 
-	if (fragmentedSends.UnsafeGetValue().transfers.Size() > 0)
-		LOG(LogVerbose, "MessageConnection::Close(): Had %d messages in fragmentedSends.transfers list!", (int)fragmentedSends.UnsafeGetValue().transfers.Size());
+	if (fragmentedSends.UnsafeGetValue().transfers.size() > 0)
+		LOG(LogVerbose, "MessageConnection::Close(): Had %d messages in fragmentedSends.transfers list!", (int)fragmentedSends.UnsafeGetValue().transfers.size());
 
 
-	if (fragmentedReceives.transfers.Size() > 0)
-		LOG(LogVerbose, "MessageConnection::Close(): Had %d messages in fragmentedReceives.transfers list!", (int)fragmentedReceives.transfers.Size());
+	if (fragmentedReceives.transfers.size() > 0)
+		LOG(LogVerbose, "MessageConnection::Close(): Had %d messages in fragmentedReceives.transfers list!", (int)fragmentedReceives.transfers.size());
 
 
 	FreeMessageData();
 	FreeMessageData();
 }
 }
@@ -331,7 +330,7 @@ void MessageConnection::FreeMessageData() // [main thread]
 	Lockable<FragmentedSendManager>::LockType sends = fragmentedSends.Acquire();
 	Lockable<FragmentedSendManager>::LockType sends = fragmentedSends.Acquire();
 	sends->FreeAllTransfers();
 	sends->FreeAllTransfers();
 
 
-	fragmentedReceives.transfers.Clear();
+	fragmentedReceives.transfers.clear();
 
 
 	while(outboundAcceptQueue.Size() > 0)
 	while(outboundAcceptQueue.Size() > 0)
 	{
 	{
@@ -355,14 +354,16 @@ void MessageConnection::FreeMessageData() // [main thread]
 
 
 	outboundQueue.Clear();
 	outboundQueue.Clear();
 
 
-	inboundContentIDStamps.Clear();
+	inboundContentIDStamps.clear();
 
 
-	outboundContentIDMessages.Clear();
+	outboundContentIDMessages.clear();
 
 
 	Lockable<ConnectionStatistics>::LockType stats_ = statistics.Acquire();
 	Lockable<ConnectionStatistics>::LockType stats_ = statistics.Acquire();
-	stats_->ping.Clear();
-	stats_->recvPacketIDs.Clear();
-	stats_->traffic.Clear();
+	stats_->ping.clear();
+	stats_->recvPacketIDs.clear();
+	stats_->traffic.clear();
+
+	networkSendSimulator.Free();
 }
 }
 
 
 void MessageConnection::DetectConnectionTimeOut()
 void MessageConnection::DetectConnectionTimeOut()
@@ -432,6 +433,8 @@ void MessageConnection::UpdateConnection() // [Called from the worker thread]
 
 
 	AcceptOutboundMessages();
 	AcceptOutboundMessages();
 
 
+	networkSendSimulator.Process();
+
 	// MessageConnection needs to automatically manage the sending of ping messages in an unreliable channel.
 	// MessageConnection needs to automatically manage the sending of ping messages in an unreliable channel.
 	if (connectionState == ConnectionOK && pingTimer.TriggeredOrNotRunning())
 	if (connectionState == ConnectionOK && pingTimer.TriggeredOrNotRunning())
 	{
 	{
@@ -650,7 +653,7 @@ void MessageConnection::EndAndQueueMessage(NetworkMessage *msg, size_t numBytes,
 		LOG(LogVerbose, "MessageConnection::EndAndQueueMessage: Discarded message with ID 0x%X and size %d bytes. "
 		LOG(LogVerbose, "MessageConnection::EndAndQueueMessage: Discarded message with ID 0x%X and size %d bytes. "
 			"msg->obsolete: %d. socket ptr: %p. ConnectionState: %s. socket->IsWriteOpen(): %s. msgconn->IsWriteOpen: %s. "
 			"msg->obsolete: %d. socket ptr: %p. ConnectionState: %s. socket->IsWriteOpen(): %s. msgconn->IsWriteOpen: %s. "
 			"internalQueue: %s.",
 			"internalQueue: %s.",
-			(int)msg->id, (int)numBytes, (int)msg->obsolete, socket, ConnectionStateToString(GetConnectionState()).CString(), (socket && socket->IsWriteOpen()) ? "true" : "false",
+			(int)msg->id, (int)numBytes, (int)msg->obsolete, socket, ConnectionStateToString(GetConnectionState()).c_str(), (socket && socket->IsWriteOpen()) ? "true" : "false",
 			IsWriteOpen() ? "true" : "false", internalQueue ? "true" : "false");
 			IsWriteOpen() ? "true" : "false", internalQueue ? "true" : "false");
 		FreeMessage(msg);
 		FreeMessage(msg);
 		return;
 		return;
@@ -672,7 +675,7 @@ void MessageConnection::EndAndQueueMessage(NetworkMessage *msg, size_t numBytes,
 	///\todo We can optimize here by doing the splitting at datagram creation time to create optimally sized datagrams, but
 	///\todo We can optimize here by doing the splitting at datagram creation time to create optimally sized datagrams, but
 	/// it is quite more complicated, so left for later. 
 	/// it is quite more complicated, so left for later. 
 	const size_t sendHeaderUpperBound = 32; // Reserve some bytes for the packet and message headers. (an approximate upper bound)
 	const size_t sendHeaderUpperBound = 32; // Reserve some bytes for the packet and message headers. (an approximate upper bound)
-	if (msg->dataSize + sendHeaderUpperBound > socket->MaxSendSize())
+	if (msg->dataSize + sendHeaderUpperBound > socket->MaxSendSize() && socket->TransportLayer() == SocketOverUDP)
 	{
 	{
 		const size_t maxFragmentSize = socket->MaxSendSize() / 4 - sendHeaderUpperBound; ///\todo Check this is ok.
 		const size_t maxFragmentSize = socket->MaxSendSize() / 4 - sendHeaderUpperBound; ///\todo Check this is ok.
 		assert(maxFragmentSize > 0 && maxFragmentSize < socket->MaxSendSize());
 		assert(maxFragmentSize > 0 && maxFragmentSize < socket->MaxSendSize());
@@ -697,20 +700,16 @@ void MessageConnection::EndAndQueueMessage(NetworkMessage *msg, size_t numBytes,
 	}
 	}
 	else
 	else
 	{
 	{
-		if (msg->reliable)
-		{
-			// If message is reliable, block and retry until succeed to queue
-			while (!outboundAcceptQueue.Insert(msg))
-				kNet::Clock::Sleep(5);
-		}
-		else
+		if (!outboundAcceptQueue.Insert(msg))
 		{
 		{
-			// If unreliable, just discard if failed to insert
-			if (!outboundAcceptQueue.Insert(msg))
+			if (msg->reliable) // For nonreliable messages it is not critical if we can't enqueue the message. Just discard it.
 			{
 			{
-				FreeMessage(msg);
-				return;
+				///\todo Is it possible to check beforehand if this criteria is avoided, or if we are doomed?
+				LOG(LogVerbose, "Critical: Failed to add new reliable message to outboundAcceptQueue! Queue was full. Discarding the message!");
+				assert(false);
 			}
 			}
+			FreeMessage(msg);
+			return;
 		}
 		}
 		LOG(LogData, "MessageConnection::EndAndQueueMessage: Queued message of size %d bytes and ID 0x%X.", (int)msg->Size(), (int)msg->id);
 		LOG(LogData, "MessageConnection::EndAndQueueMessage: Queued message of size %d bytes and ID 0x%X.", (int)msg->Size(), (int)msg->id);
 	}
 	}
@@ -766,7 +765,7 @@ void MessageConnection::Process(int maxMessagesToProcess)
 		if (!inboundMessageHandler)
 		if (!inboundMessageHandler)
 		{
 		{
 			LOG(LogVerbose, "Warning! Cannot process messages since no message handler registered to connection %s!",
 			LOG(LogVerbose, "Warning! Cannot process messages since no message handler registered to connection %s!",
-				ToString().CString());
+				ToString().c_str());
 			return;
 			return;
 		}
 		}
 
 
@@ -776,7 +775,7 @@ void MessageConnection::Process(int maxMessagesToProcess)
 		inboundMessageQueue.PopFront();
 		inboundMessageQueue.PopFront();
 		assert(msg);
 		assert(msg);
 
 
-		inboundMessageHandler->HandleMessage(this, msg->id, (msg->dataSize > 0) ? msg->data : 0, msg->dataSize);
+		inboundMessageHandler->HandleMessage(this, msg->receivedPacketID, msg->id, (msg->dataSize > 0) ? msg->data : 0, msg->dataSize);
 
 
 		FreeMessage(msg);
 		FreeMessage(msg);
 	}
 	}
@@ -816,7 +815,7 @@ void MessageConnection::WaitForMessage(int maxMSecsToWait) // [main thread]
 		if (timer.MSecsElapsed() >= 1000.f)
 		if (timer.MSecsElapsed() >= 1000.f)
 		{
 		{
 				LOG(LogWaits, "MessageConnection::WaitForMessage: Waited %f msecs for a new message. ConnectionState: %s. %d messages in queue.",
 				LOG(LogWaits, "MessageConnection::WaitForMessage: Waited %f msecs for a new message. ConnectionState: %s. %d messages in queue.",
-				timer.MSecsElapsed(), ConnectionStateToString(GetConnectionState()).CString(), (int)inboundMessageQueue.Size());
+				timer.MSecsElapsed(), ConnectionStateToString(GetConnectionState()).c_str(), (int)inboundMessageQueue.Size());
 		}
 		}
 	}
 	}
 }
 }
@@ -882,8 +881,8 @@ void MessageConnection::AddOutboundStats(unsigned long numBytes, unsigned long n
 		return;
 		return;
 
 
 	ConnectionStatistics &cs = statistics.LockGet();
 	ConnectionStatistics &cs = statistics.LockGet();
-	cs.traffic.Push(ConnectionStatistics::TrafficTrack());
-	ConnectionStatistics::TrafficTrack &t = cs.traffic.Back();
+	cs.traffic.push_back(ConnectionStatistics::TrafficTrack());
+	ConnectionStatistics::TrafficTrack &t = cs.traffic.back();
 	t.bytesIn = t.messagesIn = t.packetsIn = 0;
 	t.bytesIn = t.messagesIn = t.packetsIn = 0;
 	t.bytesOut = numBytes;
 	t.bytesOut = numBytes;
 	t.packetsOut = numPackets;
 	t.packetsOut = numPackets;
@@ -901,8 +900,8 @@ void MessageConnection::AddInboundStats(unsigned long numBytes, unsigned long nu
 		return;
 		return;
 
 
 	ConnectionStatistics &cs = statistics.LockGet();
 	ConnectionStatistics &cs = statistics.LockGet();
-	cs.traffic.Push(ConnectionStatistics::TrafficTrack());
-	ConnectionStatistics::TrafficTrack &t = cs.traffic.Back();
+	cs.traffic.push_back(ConnectionStatistics::TrafficTrack());
+	ConnectionStatistics::TrafficTrack &t = cs.traffic.back();
 	t.bytesOut = t.messagesOut = t.packetsOut = 0;
 	t.bytesOut = t.messagesOut = t.packetsOut = 0;
 	t.bytesIn = numBytes;
 	t.bytesIn = numBytes;
 	t.packetsIn = numPackets;
 	t.packetsIn = numPackets;
@@ -922,14 +921,14 @@ void MessageConnection::ComputeStats()
 	const tick_t timeNow = Clock::Tick();
 	const tick_t timeNow = Clock::Tick();
 	const tick_t maxTickAge = timeNow - maxEntryAge;
 	const tick_t maxTickAge = timeNow - maxEntryAge;
 
 
-	for(size_t i = 0; i < cs.traffic.Size(); ++i)
+	for(size_t i = 0; i < cs.traffic.size(); ++i)
 		if (Clock::IsNewer(cs.traffic[i].tick, maxTickAge))
 		if (Clock::IsNewer(cs.traffic[i].tick, maxTickAge))
 		{
 		{
-			cs.traffic.Erase(cs.traffic.Begin(), cs.traffic.Begin() + i);
+			cs.traffic.erase(cs.traffic.begin(), cs.traffic.begin() + i);
 			break;
 			break;
 		}
 		}
 
 
-	if (cs.traffic.Size() <= 1)
+	if (cs.traffic.size() <= 1)
 	{
 	{
 		bytesInPerSec = bytesOutPerSec = msgsInPerSec = msgsOutPerSec = packetsInPerSec = packetsOutPerSec = 0.f;
 		bytesInPerSec = bytesOutPerSec = msgsInPerSec = msgsOutPerSec = packetsInPerSec = packetsOutPerSec = 0.f;
 		statistics.Unlock();
 		statistics.Unlock();
@@ -943,7 +942,7 @@ void MessageConnection::ComputeStats()
 	unsigned long totalPacketsIn = 0;
 	unsigned long totalPacketsIn = 0;
 	unsigned long totalPacketsOut = 0;
 	unsigned long totalPacketsOut = 0;
 
 
-	for(size_t i = 0; i < cs.traffic.Size(); ++i)
+	for(size_t i = 0; i < cs.traffic.size(); ++i)
 	{
 	{
 		totalBytesIn += cs.traffic[i].bytesIn;
 		totalBytesIn += cs.traffic[i].bytesIn;
 		totalBytesOut += cs.traffic[i].bytesOut;
 		totalBytesOut += cs.traffic[i].bytesOut;
@@ -952,7 +951,7 @@ void MessageConnection::ComputeStats()
 		totalMsgsIn += cs.traffic[i].messagesIn;
 		totalMsgsIn += cs.traffic[i].messagesIn;
 		totalMsgsOut += cs.traffic[i].messagesOut;
 		totalMsgsOut += cs.traffic[i].messagesOut;
 	}
 	}
-	tick_t ticks = cs.traffic.Back().tick - cs.traffic.Front().tick;
+	tick_t ticks = cs.traffic.back().tick - cs.traffic.front().tick;
 	float secs = max(1.f, (float)Clock::TicksToMillisecondsD(ticks) / 1000.f);
 	float secs = max(1.f, (float)Clock::TicksToMillisecondsD(ticks) / 1000.f);
 	bytesInPerSec = (float)totalBytesIn / secs;
 	bytesInPerSec = (float)totalBytesIn / secs;
 	bytesOutPerSec = (float)totalBytesOut / secs;
 	bytesOutPerSec = (float)totalBytesOut / secs;
@@ -972,26 +971,26 @@ void MessageConnection::CheckAndSaveOutboundMessageWithContentID(NetworkMessage
 	if (msg->contentID == 0)
 	if (msg->contentID == 0)
 		return;
 		return;
 
 
-	MsgContentIDPair key(msg->id, msg->contentID);
-	ContentIDSendTrack::Iterator iter = outboundContentIDMessages.Find(key);
-	if (iter != outboundContentIDMessages.End()) // We have a previous message in the queue which is now obsoleted by this message.
+	MsgContentIDPair key = std::make_pair(msg->id, msg->contentID);
+	ContentIDSendTrack::iterator iter = outboundContentIDMessages.find(key);
+	if (iter != outboundContentIDMessages.end()) // We have a previous message in the queue which is now obsoleted by this message.
 	{
 	{
 		// Sanity check: The message numbers must be in the proper order. msg must have been admitted later to send queue than the existing message.
 		// Sanity check: The message numbers must be in the proper order. msg must have been admitted later to send queue than the existing message.
-		if (msg->IsNewerThan(*iter->second_))
+		if (msg->IsNewerThan(*iter->second))
 		{
 		{
-			iter->second_->obsolete = true;
-
-			assert(iter->second_ != msg);
-			assert(iter->first_.first_ == iter->second_->id);
-			assert(iter->first_.second_ == iter->second_->contentID);
-			assert(iter->first_.first_ == msg->id);
-			assert(iter->first_.second_ == msg->contentID);
-			iter->second_ = msg;
+			iter->second->obsolete = true;
+
+			assert(iter->second != msg);
+			assert(iter->first.first == iter->second->id);
+			assert(iter->first.second == iter->second->contentID);
+			assert(iter->first.first == msg->id);
+			assert(iter->first.second == msg->contentID);
+			iter->second = msg;
 		}
 		}
 		else // This shouldn't happen, but gracefully handle that situation if it does!
 		else // This shouldn't happen, but gracefully handle that situation if it does!
 		{
 		{
 			LOG(LogError, "Warning! Adding new message ID %d, number %d, content ID %d, priority %d, but it was obsoleted by an already existing message number %d.", 
 			LOG(LogError, "Warning! Adding new message ID %d, number %d, content ID %d, priority %d, but it was obsoleted by an already existing message number %d.", 
-				(int)msg->id, (int)msg->messageNumber, (int)msg->contentID, (int)iter->second_->priority, (int)iter->second_->messageNumber);
+				(int)msg->id, (int)msg->messageNumber, (int)msg->contentID, (int)iter->second->priority, (int)iter->second->messageNumber);
 			msg->obsolete = true;
 			msg->obsolete = true;
 		}
 		}
 	}
 	}
@@ -1011,14 +1010,14 @@ void MessageConnection::ClearOutboundMessageWithContentID(NetworkMessage *msg)
 	assert(msg);
 	assert(msg);
 	if (msg->contentID == 0)
 	if (msg->contentID == 0)
 		return;
 		return;
-	MsgContentIDPair key(msg->id, msg->contentID);
-	ContentIDSendTrack::Iterator iter = outboundContentIDMessages.Find(key);
-	if (iter != outboundContentIDMessages.End())
-		if (msg == iter->second_)
-			outboundContentIDMessages.Erase(iter);
+	MsgContentIDPair key = std::make_pair(msg->id, msg->contentID);
+	ContentIDSendTrack::iterator iter = outboundContentIDMessages.find(key);
+	if (iter != outboundContentIDMessages.end())
+		if (msg == iter->second)
+			outboundContentIDMessages.erase(iter);
 }
 }
 
 
-bool MessageConnection::CheckAndSaveContentIDStamp(u32 messageID, u32 contentID, packet_id_t packetID)
+bool MessageConnection::CheckAndSaveContentIDStamp(message_id_t messageID, u32 contentID, packet_id_t packetID)
 {
 {
 	AssertInWorkerThreadContext();
 	AssertInWorkerThreadContext();
 
 
@@ -1026,18 +1025,18 @@ bool MessageConnection::CheckAndSaveContentIDStamp(u32 messageID, u32 contentID,
 
 
 	tick_t now = Clock::Tick();
 	tick_t now = Clock::Tick();
 
 
-	MsgContentIDPair key(messageID, contentID);
-	ContentIDReceiveTrack::Iterator iter = inboundContentIDStamps.Find(key);
-	if (iter == inboundContentIDStamps.End())
+	MsgContentIDPair key = std::make_pair(messageID, contentID);
+	ContentIDReceiveTrack::iterator iter = inboundContentIDStamps.find(key);
+	if (iter == inboundContentIDStamps.end())
 	{
 	{
-		inboundContentIDStamps[key] = Pair<packet_id_t, tick_t>(packetID, now);
+		inboundContentIDStamps[key] = std::make_pair(packetID, now);
 		return true;
 		return true;
 	}
 	}
 	else
 	else
 	{
 	{
-		if (PacketIDIsNewerThan(packetID, iter->second_.first_) || (float)Clock::TimespanToMillisecondsD(iter->second_.second_, now) > 5.f * 1000.f)
+		if (PacketIDIsNewerThan(packetID, iter->second.first) || (float)Clock::TimespanToMillisecondsD(iter->second.second, now) > 5.f * 1000.f)
 		{
 		{
-			iter->second_ = Pair<packet_id_t, tick_t>(packetID, now);
+			iter->second = std::make_pair(packetID, now);
 			return true;
 			return true;
 		}
 		}
 		else
 		else
@@ -1056,16 +1055,16 @@ void MessageConnection::HandleInboundMessage(packet_id_t packetID, const char *d
 
 
 	// Read the message ID.
 	// Read the message ID.
 	DataDeserializer reader(data, numBytes);
 	DataDeserializer reader(data, numBytes);
-	u32 messageID = reader.ReadVLE<VLE8_16_32>(); ///\todo Check that there actually is enough space to read.
+	message_id_t messageID = reader.ReadVLE<VLE8_16_32>(); ///\todo Check that there actually is enough space to read.
 	if (messageID == DataDeserializer::VLEReadError)
 	if (messageID == DataDeserializer::VLEReadError)
 	{
 	{
-		LOG(LogError, "Error parsing messageID of a message in socket %s. Data size: %d bytes.", socket->ToString().CString(), (int)numBytes);
+		LOG(LogError, "Error parsing messageID of a message in socket %s. Data size: %d bytes.", socket->ToString().c_str(), (int)numBytes);
 		throw NetException("MessageConnection::HandleInboundMessage: Network error occurred when deserializing message ID VLE field!");
 		throw NetException("MessageConnection::HandleInboundMessage: Network error occurred when deserializing message ID VLE field!");
 	}
 	}
-	LOG(LogData, "Received message with ID %d and size %d from peer %s.", (int)packetID, (int)numBytes, socket->ToString().CString());
+	LOG(LogData, "Received message with ID %d and size %d from peer %s.", (int)packetID, (int)numBytes, socket->ToString().c_str());
 
 
 	char str[256];
 	char str[256];
-	sprintf(str, "messageIn.%u", messageID);
+	sprintf(str, "messageIn.%u", (unsigned int)messageID);
 	ADDEVENT(str, (float)reader.BytesLeft(), "bytes");
 	ADDEVENT(str, (float)reader.BytesLeft(), "bytes");
 
 
 	// Pass the message to TCP/UDP -specific message handler.
 	// Pass the message to TCP/UDP -specific message handler.
@@ -1090,6 +1089,7 @@ void MessageConnection::HandleInboundMessage(packet_id_t packetID, const char *d
 			msg->dataSize = reader.BytesLeft();
 			msg->dataSize = reader.BytesLeft();
 			msg->id = messageID;
 			msg->id = messageID;
 			msg->contentID = 0;
 			msg->contentID = 0;
+			msg->receivedPacketID = packetID;
 			bool success = inboundMessageQueue.Insert(msg);
 			bool success = inboundMessageQueue.Insert(msg);
 			if (!success)
 			if (!success)
 			{
 			{
@@ -1124,9 +1124,9 @@ void MessageConnection::SendPingRequestMessage(bool internalQueue)
 
 
 	ConnectionStatistics &cs = statistics.LockGet();
 	ConnectionStatistics &cs = statistics.LockGet();
 	
 	
-	u8 pingID = (u8)((cs.ping.Size() == 0) ? 1 : (cs.ping.Back().pingID + 1));
-	cs.ping.Push(ConnectionStatistics::PingTrack());
-	ConnectionStatistics::PingTrack &pingTrack = cs.ping.Back();
+	u8 pingID = (u8)((cs.ping.size() == 0) ? 1 : (cs.ping.back().pingID + 1));
+	cs.ping.push_back(ConnectionStatistics::PingTrack());
+	ConnectionStatistics::PingTrack &pingTrack = cs.ping.back();
 	pingTrack.replyReceived = false;
 	pingTrack.replyReceived = false;
 	pingTrack.pingSentTick = Clock::Tick();
 	pingTrack.pingSentTick = Clock::Tick();
 	pingTrack.pingID = pingID;
 	pingTrack.pingID = pingID;
@@ -1180,24 +1180,24 @@ void MessageConnection::HandlePingReplyMessage(const char *data, size_t numBytes
 	const float rttPredictBias = 0.5f;
 	const float rttPredictBias = 0.5f;
 
 
 	u8 pingID = *(u8*)data;
 	u8 pingID = *(u8*)data;
-	for(size_t i = 0; i < cs.ping.Size(); ++i)
+	for(size_t i = 0; i < cs.ping.size(); ++i)
 		if (cs.ping[i].pingID == pingID && cs.ping[i].replyReceived == false)
 		if (cs.ping[i].pingID == pingID && cs.ping[i].replyReceived == false)
 		{
 		{
 			cs.ping[i].pingReplyTick = Clock::Tick();
 			cs.ping[i].pingReplyTick = Clock::Tick();
 			float newRtt = (float)Clock::TicksToMillisecondsD(Clock::TicksInBetween(cs.ping[i].pingReplyTick, cs.ping[i].pingSentTick));
 			float newRtt = (float)Clock::TicksToMillisecondsD(Clock::TicksInBetween(cs.ping[i].pingReplyTick, cs.ping[i].pingSentTick));
 			cs.ping[i].replyReceived = true;
 			cs.ping[i].replyReceived = true;
 			statistics.Unlock();
 			statistics.Unlock();
-			rtt = rttPredictBias * newRtt + (1.f - rttPredictBias) * rtt;
+			rtt = rttPredictBias * newRtt + (1.f * rttPredictBias) * rtt;
 
 
 			LOG(LogVerbose, "HandlePingReplyMessage: %d.", (int)pingID);
 			LOG(LogVerbose, "HandlePingReplyMessage: %d.", (int)pingID);
 			return;
 			return;
 		}
 		}
 
 
 	statistics.Unlock();
 	statistics.Unlock();
-	LOG(LogError, "Received PingReply with ID %d in socket %s, but no matching PingRequest was ever sent!", (int)pingID, socket->ToString().CString());
+	LOG(LogError, "Received PingReply with ID %d in socket %s, but no matching PingRequest was ever sent!", (int)pingID, socket->ToString().c_str());
 }
 }
 
 
-String MessageConnection::ToString() const
+std::string MessageConnection::ToString() const
 {
 {
 	if (socket)
 	if (socket)
 		return socket->ToString();
 		return socket->ToString();
@@ -1229,7 +1229,7 @@ void MessageConnection::DumpStatus() const
 		"\tOverlapped out: %d (event: %s)\n"
 		"\tOverlapped out: %d (event: %s)\n"
 		"\tTime until next send: %d\n"
 		"\tTime until next send: %d\n"
 		"\toutboundQueue.Size(): %d\n",
 		"\toutboundQueue.Size(): %d\n",
-		ConnectionStateToString(GetConnectionState()).CString(),
+		ConnectionStateToString(GetConnectionState()).c_str(),
 		(int)NumInboundMessagesPending(),
 		(int)NumInboundMessagesPending(),
 		(int)NumOutboundMessagesPending(),
 		(int)NumOutboundMessagesPending(),
 		Connected() ? "connected" : "",
 		Connected() ? "connected" : "",
@@ -1241,7 +1241,7 @@ void MessageConnection::DumpStatus() const
 		(socket && socket->IsWriteOpen()) ? "writeOpen" : "",
 		(socket && socket->IsWriteOpen()) ? "writeOpen" : "",
 		RoundTripTime(), LastHeardTime(), PacketsInPerSec(), PacketsOutPerSec(),
 		RoundTripTime(), LastHeardTime(), PacketsInPerSec(), PacketsOutPerSec(),
 		MsgsInPerSec(), MsgsOutPerSec(), 
 		MsgsInPerSec(), MsgsOutPerSec(), 
-		FormatBytes(BytesInPerSec()).CString(), FormatBytes(BytesOutPerSec()).CString(),
+		FormatBytes(BytesInPerSec()).c_str(), FormatBytes(BytesOutPerSec()).c_str(),
 		(int)eventMsgsOutAvailable.Test(), 
 		(int)eventMsgsOutAvailable.Test(), 
 #ifdef WIN32
 #ifdef WIN32
 		socket ? socket->NumOverlappedReceivesInProgress() : -1,
 		socket ? socket->NumOverlappedReceivesInProgress() : -1,
@@ -1288,7 +1288,7 @@ void MessageConnection::AssertInWorkerThreadContext() const
 	if (haveWorkerThread && currentThreadId != workerThreadId)
 	if (haveWorkerThread && currentThreadId != workerThreadId)
 	{
 	{
 		LOG(LogError, "Assert failure in MessageConnection::AssertInWorkerThreadContext()!: haveWorkerThread: %s, currentThreadId: %s, workerThreadId: %s,",
 		LOG(LogError, "Assert failure in MessageConnection::AssertInWorkerThreadContext()!: haveWorkerThread: %s, currentThreadId: %s, workerThreadId: %s,",
-			haveWorkerThread ? "true" : "false", ThreadIdToString(currentThreadId).CString(), ThreadIdToString(workerThreadId).CString());
+			haveWorkerThread ? "true" : "false", ThreadIdToString(currentThreadId).c_str(), ThreadIdToString(workerThreadId).c_str());
 		assert(false && "MessageConnection::AssertInWorkerThreadContext assert failure!");
 		assert(false && "MessageConnection::AssertInWorkerThreadContext assert failure!");
 	}
 	}
 #endif
 #endif
@@ -1303,7 +1303,7 @@ void MessageConnection::AssertInMainThreadContext() const
 	if (haveWorkerThread && currentThreadId == workerThreadId)
 	if (haveWorkerThread && currentThreadId == workerThreadId)
 	{
 	{
 		LOG(LogError, "Assert failure in MessageConnection::AssertInMainThreadContext()!: haveWorkerThread: %s, currentThreadId: %s, workerThreadId: %s,",
 		LOG(LogError, "Assert failure in MessageConnection::AssertInMainThreadContext()!: haveWorkerThread: %s, currentThreadId: %s, workerThreadId: %s,",
-			haveWorkerThread ? "true" : "false", ThreadIdToString(currentThreadId).CString(), ThreadIdToString(workerThreadId).CString());
+			haveWorkerThread ? "true" : "false", ThreadIdToString(currentThreadId).c_str(), ThreadIdToString(workerThreadId).c_str());
 		assert(false && "MessageConnection::AssertInMainThreadContext assert failure!");
 		assert(false && "MessageConnection::AssertInMainThreadContext assert failure!");
 	}
 	}
 #endif
 #endif

+ 11 - 13
ThirdParty/kNet/src/MessageListParser.cpp

@@ -15,8 +15,6 @@
 /** @file MessageListParser.cpp
 /** @file MessageListParser.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #ifdef KNET_USE_TINYXML
 #ifdef KNET_USE_TINYXML
 #include <tinyxml.h>
 #include <tinyxml.h>
 #endif
 #endif
@@ -45,7 +43,7 @@ namespace kNet
 
 
 BasicSerializedDataType StringToSerialType(const char *type)
 BasicSerializedDataType StringToSerialType(const char *type)
 {
 {
-	if (type == "string" || type == "String")
+	if (type == "string" || type == "std::string")
 		return SerialString;
 		return SerialString;
 	assert(NumSerialTypes-2 == NUMELEMS(data));
 	assert(NumSerialTypes-2 == NUMELEMS(data));
 	for(int i = 0; i < NUMELEMS(data); ++i)
 	for(int i = 0; i < NUMELEMS(data); ++i)
@@ -66,7 +64,7 @@ const char *SerialTypeToReadableString(BasicSerializedDataType type)
 const char *SerialTypeToCTypeString(BasicSerializedDataType type)
 const char *SerialTypeToCTypeString(BasicSerializedDataType type)
 {
 {
 	if (type == SerialString)
 	if (type == SerialString)
-		return "String";
+		return "std::string";
 	assert(NumSerialTypes-2 == NUMELEMS(data));
 	assert(NumSerialTypes-2 == NUMELEMS(data));
 	assert(type >= SerialInvalid);
 	assert(type >= SerialInvalid);
 	assert(type < NumSerialTypes); 
 	assert(type < NumSerialTypes); 
@@ -84,7 +82,7 @@ size_t SerialTypeSize(BasicSerializedDataType type)
 SerializedElementDesc *SerializedMessageList::ParseNode(TiXmlElement *node, SerializedElementDesc *parentNode)
 SerializedElementDesc *SerializedMessageList::ParseNode(TiXmlElement *node, SerializedElementDesc *parentNode)
 {
 {
 #ifdef KNET_USE_TINYXML
 #ifdef KNET_USE_TINYXML
-	elements.Push(SerializedElementDesc());
+	elements.push_back(SerializedElementDesc());
 	SerializedElementDesc *elem = &elements.back();
 	SerializedElementDesc *elem = &elements.back();
 	elem->parent = parentNode;
 	elem->parent = parentNode;
 	elem->name = node->Attribute("name") ? node->Attribute("name") : "";
 	elem->name = node->Attribute("name") ? node->Attribute("name") : "";
@@ -119,9 +117,9 @@ SerializedElementDesc *SerializedMessageList::ParseNode(TiXmlElement *node, Seri
 
 
 		elem->typeString = node->Value();
 		elem->typeString = node->Value();
 		if (elem->typeString == "string")
 		if (elem->typeString == "string")
-			elem->typeString = "String";
+			elem->typeString = "std::string";
 		elem->type = StringToSerialType(node->Value());
 		elem->type = StringToSerialType(node->Value());
-		if (elem->type == SerialInvalid && !elem->typeString.Empty())
+		if (elem->type == SerialInvalid && !elem->typeString.empty())
 			elem->type = SerialOther;
 			elem->type = SerialOther;
 		if (elem->type == SerialStruct)
 		if (elem->type == SerialStruct)
 			elem->typeString = "S_" + elem->name; ///\todo Add a ClassName parameter for better control over naming here?
 			elem->typeString = "S_" + elem->name; ///\todo Add a ClassName parameter for better control over naming here?
@@ -134,7 +132,7 @@ SerializedElementDesc *SerializedMessageList::ParseNode(TiXmlElement *node, Seri
 		while(child)
 		while(child)
 		{
 		{
 			SerializedElementDesc *childElem = ParseNode(child, elem);
 			SerializedElementDesc *childElem = ParseNode(child, elem);
-			elem->elements.Push(childElem);
+			elem->elements.push_back(childElem);
 
 
 			child = child->NextSiblingElement();
 			child = child->NextSiblingElement();
 		}
 		}
@@ -182,7 +180,7 @@ void SerializedMessageList::ParseMessages(TiXmlElement *root)
 
 
 		// Work a slight convenience - if there is a single struct inside a single struct inside a single struct - jump straight through to the data.
 		// Work a slight convenience - if there is a single struct inside a single struct inside a single struct - jump straight through to the data.
 
 
-		messages.Push(desc);
+		messages.push_back(desc);
 
 
 		node = node->NextSiblingElement("message");
 		node = node->NextSiblingElement("message");
 	}
 	}
@@ -229,8 +227,8 @@ void SerializedMessageList::LoadMessagesFromFile(const char *filename)
 
 
 const SerializedMessageDesc *SerializedMessageList::FindMessageByID(u32 id)
 const SerializedMessageDesc *SerializedMessageList::FindMessageByID(u32 id)
 {
 {
-	for(List<SerializedMessageDesc>::Iterator iter = messages.Begin();
-		iter != messages.End(); ++iter)
+	for(std::list<SerializedMessageDesc>::iterator iter = messages.begin();
+		iter != messages.end(); ++iter)
 		if (iter->id == id)
 		if (iter->id == id)
 			return &*iter;
 			return &*iter;
 
 
@@ -239,8 +237,8 @@ const SerializedMessageDesc *SerializedMessageList::FindMessageByID(u32 id)
 
 
 const SerializedMessageDesc *SerializedMessageList::FindMessageByName(const char *name)
 const SerializedMessageDesc *SerializedMessageList::FindMessageByName(const char *name)
 {
 {
-	for(List<SerializedMessageDesc>::Iterator iter = messages.Begin();
-		iter != messages.End(); ++iter)
+	for(std::list<SerializedMessageDesc>::iterator iter = messages.begin();
+		iter != messages.end(); ++iter)
 		if (iter->name == name)
 		if (iter->name == name)
 			return &*iter;
 			return &*iter;
 
 

+ 80 - 81
ThirdParty/kNet/src/Network.cpp

@@ -15,9 +15,8 @@
 /** @file Network.cpp
 /** @file Network.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
-#include "Str.h"
+#include <string>
+#include <sstream>
 
 
 #include <cassert>
 #include <cassert>
 
 
@@ -44,10 +43,10 @@
 namespace kNet
 namespace kNet
 {
 {
 
 
-const int cMaxTCPSendSize = 256 * 1024;
+const int cMaxTCPSendSize = 25 * 1024 * 1024; // For TCP sockets, there is no specific limit to send(), specify something.
 const int cMaxUDPSendSize = 1400;
 const int cMaxUDPSendSize = 1400;
 
 
-String Network::GetErrorString(int error)
+std::string Network::GetErrorString(int error)
 {
 {
 #ifdef WIN32
 #ifdef WIN32
 	void *lpMsgBuf = 0;
 	void *lpMsgBuf = 0;
@@ -57,14 +56,14 @@ String Network::GetErrorString(int error)
 		0, hresult, 0 /*Default language*/, (LPTSTR) &lpMsgBuf, 0, 0);
 		0, hresult, 0 /*Default language*/, (LPTSTR) &lpMsgBuf, 0, 0);
 
 
 	// Copy message to C++ -style string, since the data need to be freed before return.
 	// Copy message to C++ -style string, since the data need to be freed before return.
-	String str;
-	str += String((LPCSTR)lpMsgBuf) + "(" + String(error) + ")"; ///\todo Bug: The cast to LPCSTR converts wstr -> str if UNICODE is defined, which will cut out text.
+	std::stringstream ss;
+	ss << (LPCSTR)lpMsgBuf << "(" << error << ")"; ///\todo Bug: The cast to LPCSTR converts wstr -> str if UNICODE is defined, which will cut out text.
 	LocalFree(lpMsgBuf);
 	LocalFree(lpMsgBuf);
-	return str;
+	return ss.str();
 #else
 #else
-	String str;
-	str += String(strerror(error)) + "(" + error + ")";
-	return str;
+	std::stringstream ss;
+	ss << strerror(error) << "(" << error << ")";
+	return ss.str();
 #endif
 #endif
 }
 }
 
 
@@ -77,17 +76,17 @@ int Network::GetLastError()
 #endif
 #endif
 }
 }
 
 
-String Network::GetLastErrorString()
+std::string Network::GetLastErrorString()
 {
 {
 	return GetErrorString(GetLastError());
 	return GetErrorString(GetLastError());
 }
 }
 
 
-String FormatBytes(u64 numBytes)
+std::string FormatBytes(u64 numBytes)
 {
 {
 	return FormatBytes((double)numBytes);
 	return FormatBytes((double)numBytes);
 }
 }
 
 
-String FormatBytes(double numBytes)
+std::string FormatBytes(double numBytes)
 {
 {
 	char str[256];
 	char str[256];
 	if (numBytes >= 1000.0 * 1000.0 * 1000.0)
 	if (numBytes >= 1000.0 * 1000.0 * 1000.0)
@@ -98,7 +97,7 @@ String FormatBytes(double numBytes)
 		sprintf(str, "%.3f KB", (float)(numBytes / 1024.0));
 		sprintf(str, "%.3f KB", (float)(numBytes / 1024.0));
 	else
 	else
 		sprintf(str, "%.2f B", (float)numBytes);
 		sprintf(str, "%.2f B", (float)numBytes);
-	return String(str);
+	return std::string(str);
 }
 }
 
 
 Network::Network()
 Network::Network()
@@ -270,7 +269,7 @@ void Network::Init()
 	int result = WSAStartup(MAKEWORD(2,2), &wsaData);
 	int result = WSAStartup(MAKEWORD(2,2), &wsaData);
 	if (result != 0)
 	if (result != 0)
 	{
 	{
-		LOG(LogError, "Network::Init: WSAStartup failed: %s!", GetErrorString(result).CString());
+		LOG(LogError, "Network::Init: WSAStartup failed: %s!", GetErrorString(result).c_str());
 		return;
 		return;
 	}
 	}
 #endif
 #endif
@@ -286,7 +285,7 @@ void Network::Init()
 	}
 	}
 	else
 	else
 	{
 	{
-		LOG(LogError, "Network::Init: gethostname failed! Error: %s. Using 'localhost' as the local host name", GetLastErrorString().CString());
+		LOG(LogError, "Network::Init: gethostname failed! Error: %s. Using 'localhost' as the local host name", GetLastErrorString().c_str());
 		localHostName = "localhost";
 		localHostName = "localhost";
 	}
 	}
 }
 }
@@ -296,15 +295,15 @@ NetworkWorkerThread *Network::GetOrCreateWorkerThread()
 	static const int maxConnectionsPerThread = 8;
 	static const int maxConnectionsPerThread = 8;
 
 
 	// Find an existing thread with sufficiently low load.
 	// Find an existing thread with sufficiently low load.
-	for(size_t i = 0; i < workerThreads.Size(); ++i)
+	for(size_t i = 0; i < workerThreads.size(); ++i)
 		if (workerThreads[i]->NumConnections() + workerThreads[i]->NumServers() < maxConnectionsPerThread)
 		if (workerThreads[i]->NumConnections() + workerThreads[i]->NumServers() < maxConnectionsPerThread)
 			return workerThreads[i];
 			return workerThreads[i];
 
 
 	// No appropriate thread found. Create a new one.
 	// No appropriate thread found. Create a new one.
 	NetworkWorkerThread *workerThread = new NetworkWorkerThread();
 	NetworkWorkerThread *workerThread = new NetworkWorkerThread();
 	workerThread->StartThread();
 	workerThread->StartThread();
-	workerThreads.Push(workerThread);
-	LOG(LogInfo, "Created a new NetworkWorkerThread. There are now %d worker threads.", (int)workerThreads.Size());
+	workerThreads.push_back(workerThread);
+	LOG(LogInfo, "Created a new NetworkWorkerThread. There are now %d worker threads.", (int)workerThreads.size());
 	return workerThread;
 	return workerThread;
 }
 }
 
 
@@ -363,15 +362,15 @@ void Network::CloseWorkerThread(NetworkWorkerThread *workerThread)
 	if (workerThread->NumConnections() + workerThread->NumServers() > 0)
 	if (workerThread->NumConnections() + workerThread->NumServers() > 0)
 		LOG(LogError, "Warning: Closing a worker thread %p when it still has %d connections and %d servers to handle.", workerThread, workerThread->NumConnections(), workerThread->NumServers());
 		LOG(LogError, "Warning: Closing a worker thread %p when it still has %d connections and %d servers to handle.", workerThread, workerThread->NumConnections(), workerThread->NumServers());
 
 
-	for(size_t i = 0; i < workerThreads.Size(); ++i)
+	for(size_t i = 0; i < workerThreads.size(); ++i)
 		if (workerThreads[i] == workerThread)
 		if (workerThreads[i] == workerThread)
 		{
 		{
 			// Remove the thread pointer from internal list.
 			// Remove the thread pointer from internal list.
-			Swap(workerThreads[i], workerThreads[workerThreads.Size()-1]);
-			workerThreads.Pop();
+			std::swap(workerThreads[i], workerThreads[workerThreads.size()-1]);
+			workerThreads.pop_back();
 
 
 			workerThread->StopThread();
 			workerThread->StopThread();
-			LOG(LogInfo, "Deleted a NetworkWorkerThread. There are now %d worker threads left.", (int)workerThreads.Size());
+			LOG(LogInfo, "Deleted a NetworkWorkerThread. There are now %d worker threads left.", (int)workerThreads.size());
 			delete workerThread;
 			delete workerThread;
 			return;
 			return;
 		}
 		}
@@ -389,38 +388,38 @@ NetworkServer *Network::StartServer(unsigned short port, SocketTransportLayer tr
 		return 0;
 		return 0;
 	}
 	}
 
 
-	Vector<Socket *> listenSockets;
-	listenSockets.Push(listenSock);
+	std::vector<Socket *> listenSockets;
+	listenSockets.push_back(listenSock);
 
 
 	server = new NetworkServer(this, listenSockets);
 	server = new NetworkServer(this, listenSockets);
 	server->RegisterServerListener(serverListener);
 	server->RegisterServerListener(serverListener);
 
 
 	AssignServerToWorkerThread(server);
 	AssignServerToWorkerThread(server);
 
 
-	LOG(LogInfo, "Server up (%s). Waiting for client to connect.", listenSock->ToString().CString());
+	LOG(LogInfo, "Server up (%s). Waiting for client to connect.", listenSock->ToString().c_str());
 
 
 	return server;
 	return server;
 }
 }
 
 
-NetworkServer *Network::StartServer(const Vector<Pair<unsigned short, SocketTransportLayer> > &listenPorts, 
+NetworkServer *Network::StartServer(const std::vector<std::pair<unsigned short, SocketTransportLayer> > &listenPorts, 
 	INetworkServerListener *serverListener, bool allowAddressReuse)
 	INetworkServerListener *serverListener, bool allowAddressReuse)
 {
 {
-	if (listenPorts.Size() == 0)
+	if (listenPorts.size() == 0)
 	{
 	{
 		LOG(LogError, "Failed to start server, since you did not provide a list of ports to listen to in Network::StartServer()!");
 		LOG(LogError, "Failed to start server, since you did not provide a list of ports to listen to in Network::StartServer()!");
 		return 0;
 		return 0;
 	}
 	}
 
 
-	Vector<Socket *> listenSockets;
+	std::vector<Socket *> listenSockets;
 
 
-	for(size_t i = 0; i < listenPorts.Size(); ++i)
+	for(size_t i = 0; i < listenPorts.size(); ++i)
 	{
 	{
-		Socket *listenSock = OpenListenSocket(listenPorts[i].first_, listenPorts[i].second_, allowAddressReuse);
+		Socket *listenSock = OpenListenSocket(listenPorts[i].first, listenPorts[i].second, allowAddressReuse);
 		if (listenSock)
 		if (listenSock)
-			listenSockets.Push(listenSock);
+			listenSockets.push_back(listenSock);
 	}
 	}
 
 
-	if (listenSockets.Size() == 0)
+	if (listenSockets.size() == 0)
 	{
 	{
 		LOG(LogError, "Failed to start server. No ports to listen to!");
 		LOG(LogError, "Failed to start server. No ports to listen to!");
 		return 0;
 		return 0;
@@ -433,20 +432,20 @@ NetworkServer *Network::StartServer(const Vector<Pair<unsigned short, SocketTran
 
 
 	LOG(LogInfo, "Server up and listening on the following ports: ");
 	LOG(LogInfo, "Server up and listening on the following ports: ");
 	{
 	{
-		String str;
-		str += "UDP ";
-		for(size_t i = 0; i < listenSockets.Size(); ++i)
+		std::stringstream ss;
+		ss << "UDP ";
+		for(size_t i = 0; i < listenSockets.size(); ++i)
 			if (listenSockets[i]->TransportLayer() == SocketOverUDP)
 			if (listenSockets[i]->TransportLayer() == SocketOverUDP)
-				str += String(listenSockets[i]->LocalPort()) + " ";
-		LOG(LogInfo, str.CString());
+				ss << listenSockets[i]->LocalPort() << " ";
+		LOG(LogInfo, ss.str().c_str());
 	}
 	}
 	{
 	{
-		String str;
-		str += "TCP ";
-		for(size_t i = 0; i < listenSockets.Size(); ++i)
+		std::stringstream ss;
+		ss << "TCP ";
+		for(size_t i = 0; i < listenSockets.size(); ++i)
 			if (listenSockets[i]->TransportLayer() == SocketOverTCP)
 			if (listenSockets[i]->TransportLayer() == SocketOverTCP)
-				str += String(listenSockets[i]->LocalPort()) + " ";
-		LOG(LogInfo, str.CString());
+				ss << listenSockets[i]->LocalPort() << " ";
+		LOG(LogInfo, ss.str().c_str());
 	}
 	}
 
 
 	return server;
 	return server;
@@ -472,13 +471,13 @@ void Network::DeleteSocket(Socket *socket)
 		return;
 		return;
 	}
 	}
 
 
-	for(List<Socket>::Iterator iter = sockets.Begin(); iter != sockets.End(); ++iter)
+	for(std::list<Socket>::iterator iter = sockets.begin(); iter != sockets.end(); ++iter)
 		if (&*iter == socket)
 		if (&*iter == socket)
 		{
 		{
 			socket->Close();
 			socket->Close();
 			// The Socket pointers MessageConnection objects have are pointers to this list,
 			// The Socket pointers MessageConnection objects have are pointers to this list,
 			// so after calling this function with a Socket pointer, the Socket is deleted for good.
 			// so after calling this function with a Socket pointer, the Socket is deleted for good.
-			sockets.Erase(iter);
+			sockets.erase(iter);
 			LOG(LogInfo, "Network::DeleteSocket: Closed socket %p.", socket);
 			LOG(LogInfo, "Network::DeleteSocket: Closed socket %p.", socket);
 			return;
 			return;
 		}
 		}
@@ -496,7 +495,7 @@ void Network::CloseConnection(MessageConnection *connection)
 	connection->socket = 0;
 	connection->socket = 0;
 	connection->owner = 0;
 	connection->owner = 0;
 	connection->ownerServer = 0;
 	connection->ownerServer = 0;
-	connections.Erase(connection);
+	connections.erase(connection);
 }
 }
 
 
 void Network::DeInit()
 void Network::DeInit()
@@ -505,9 +504,9 @@ void Network::DeInit()
 	PolledTimer timer;
 	PolledTimer timer;
 
 
 	// Kill all connections.
 	// Kill all connections.
-	while(connections.Size() > 0)
+	while(connections.size() > 0)
 	{
 	{
-		MessageConnection *connection = *connections.Begin();
+		MessageConnection *connection = *connections.begin();
 		CloseConnection(connection); // CloseConnection erases connection from the connections list, so this loop terminates.
 		CloseConnection(connection); // CloseConnection erases connection from the connections list, so this loop terminates.
 	}
 	}
 
 
@@ -515,14 +514,14 @@ void Network::DeInit()
 	StopServer();
 	StopServer();
 
 
 	// Kill all worker threads.
 	// Kill all worker threads.
-	while(workerThreads.Size() > 0)
-		CloseWorkerThread(workerThreads.Front()); // Erases the item from workerThreads, so this loop terminates.
+	while(workerThreads.size() > 0)
+		CloseWorkerThread(workerThreads.front()); // Erases the item from workerThreads, so this loop terminates.
 
 
 	// Clean up any sockets that might be remaining.
 	// Clean up any sockets that might be remaining.
-	while(sockets.Size() > 0)
+	while(sockets.size() > 0)
 	{
 	{
-		sockets.Front().Close();
-		sockets.PopFront();
+		sockets.front().Close();
+		sockets.pop_front();
 	}
 	}
 
 
 	// Deinitialize network subsystem.
 	// Deinitialize network subsystem.
@@ -535,7 +534,7 @@ void Network::DeInit()
 
 
 void Network::NewMessageConnectionCreated(MessageConnection *connection)
 void Network::NewMessageConnectionCreated(MessageConnection *connection)
 {
 {
-	connections.Insert(connection);
+	connections.insert(connection);
 }
 }
 
 
 Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer transport, bool allowAddressReuse)
 Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer transport, bool allowAddressReuse)
@@ -555,7 +554,7 @@ Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer tran
 	int ret = getaddrinfo(NULL, strPort, &hints, &result);
 	int ret = getaddrinfo(NULL, strPort, &hints, &result);
 	if (ret != 0)
 	if (ret != 0)
 	{
 	{
-		LOG(LogError, "getaddrinfo failed: %s", GetErrorString(ret).CString());
+		LOG(LogError, "getaddrinfo failed: %s", GetErrorString(ret).c_str());
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -564,7 +563,7 @@ Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer tran
 
 
 	if (listenSocket == INVALID_SOCKET)
 	if (listenSocket == INVALID_SOCKET)
 	{
 	{
-		LOG(LogError, "Error at socket(): %s", GetLastErrorString().CString());
+		LOG(LogError, "Error at socket(): %s", GetLastErrorString().c_str());
 		freeaddrinfo(result);
 		freeaddrinfo(result);
 		return 0;
 		return 0;
 	}
 	}
@@ -582,7 +581,7 @@ Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer tran
 		ret = setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
 		ret = setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
 #endif
 #endif
 		if (ret != 0)
 		if (ret != 0)
-			LOG(LogError, "setsockopt to SO_REUSEADDR failed: %s", GetLastErrorString().CString());
+			LOG(LogError, "setsockopt to SO_REUSEADDR failed: %s", GetLastErrorString().c_str());
 	}
 	}
 
 
 	// It is safe to cast to a sockaddr_in, since we've specifically queried for AF_INET addresses.
 	// It is safe to cast to a sockaddr_in, since we've specifically queried for AF_INET addresses.
@@ -595,7 +594,7 @@ Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer tran
 	if (ret == KNET_SOCKET_ERROR)
 	if (ret == KNET_SOCKET_ERROR)
 	{
 	{
 		LOG(LogError, "bind failed: %s when trying to bind to port %d with transport %s", 
 		LOG(LogError, "bind failed: %s when trying to bind to port %d with transport %s", 
-			GetLastErrorString().CString(), (int)port, transport == SocketOverTCP ? "TCP" : "UDP");
+			GetLastErrorString().c_str(), (int)port, transport == SocketOverTCP ? "TCP" : "UDP");
 		closesocket(listenSocket);
 		closesocket(listenSocket);
 		freeaddrinfo(result);
 		freeaddrinfo(result);
 		return 0;
 		return 0;
@@ -610,7 +609,7 @@ Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer tran
 		ret = listen(listenSocket, SOMAXCONN);
 		ret = listen(listenSocket, SOMAXCONN);
 		if (ret == KNET_SOCKET_ERROR)
 		if (ret == KNET_SOCKET_ERROR)
 		{
 		{
-			LOG(LogError, "Error at listen(): %s", GetLastErrorString().CString());
+			LOG(LogError, "Error at listen(): %s", GetLastErrorString().c_str());
 			closesocket(listenSocket);
 			closesocket(listenSocket);
 			return 0;
 			return 0;
 		}
 		}
@@ -623,8 +622,8 @@ Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer tran
 	remoteEndPoint.Reset();
 	remoteEndPoint.Reset();
 
 
 	const size_t maxSendSize = (transport == SocketOverTCP ? cMaxTCPSendSize : cMaxUDPSendSize);
 	const size_t maxSendSize = (transport == SocketOverTCP ? cMaxTCPSendSize : cMaxUDPSendSize);
-	sockets.Push(Socket(listenSocket, localEndPoint, localHostName.CString(), remoteEndPoint, "", transport, ServerListenSocket, maxSendSize));
-	Socket *listenSock = &sockets.Back();
+	sockets.push_back(Socket(listenSocket, localEndPoint, localHostName.c_str(), remoteEndPoint, "", transport, ServerListenSocket, maxSendSize));
+	Socket *listenSock = &sockets.back();
 	listenSock->SetBlocking(false);
 	listenSock->SetBlocking(false);
 
 
 	return listenSock;
 	return listenSock;
@@ -645,7 +644,7 @@ Socket *Network::ConnectSocket(const char *address, unsigned short port, SocketT
 	int ret = getaddrinfo(address, strPort, &hints, &result);
 	int ret = getaddrinfo(address, strPort, &hints, &result);
 	if (ret != 0)
 	if (ret != 0)
 	{
 	{
-		LOG(LogError, "Network::Connect: getaddrinfo failed: %s", GetErrorString(ret).CString());
+		LOG(LogError, "Network::Connect: getaddrinfo failed: %s", GetErrorString(ret).c_str());
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -658,7 +657,7 @@ Socket *Network::ConnectSocket(const char *address, unsigned short port, SocketT
 #endif
 #endif
 	if (connectSocket == INVALID_SOCKET)
 	if (connectSocket == INVALID_SOCKET)
 	{
 	{
-		LOG(LogError, "Network::Connect: Error at socket(): %s", GetLastErrorString().CString());
+		LOG(LogError, "Network::Connect: Error at socket(): %s", GetLastErrorString().c_str());
 		freeaddrinfo(result);
 		freeaddrinfo(result);
 		return 0;
 		return 0;
 	}
 	}
@@ -691,7 +690,7 @@ Socket *Network::ConnectSocket(const char *address, unsigned short port, SocketT
 	if (ret == 0)
 	if (ret == 0)
 		 localEndPoint = EndPoint::FromSockAddrIn(sockname);
 		 localEndPoint = EndPoint::FromSockAddrIn(sockname);
 	else
 	else
-		LOG(LogError, "Network::ConnectSocket: getsockname failed: %s!", Network::GetLastErrorString().CString());
+		LOG(LogError, "Network::ConnectSocket: getsockname failed: %s!", Network::GetLastErrorString().c_str());
 
 
 	EndPoint remoteEndPoint;
 	EndPoint remoteEndPoint;
 	sockaddr_in peername;
 	sockaddr_in peername;
@@ -700,17 +699,17 @@ Socket *Network::ConnectSocket(const char *address, unsigned short port, SocketT
 	if (ret == 0)
 	if (ret == 0)
 		remoteEndPoint = EndPoint::FromSockAddrIn(peername);
 		remoteEndPoint = EndPoint::FromSockAddrIn(peername);
 	else
 	else
-		LOG(LogError, "Network::ConnectSocket: getpeername failed: %s!", Network::GetLastErrorString().CString());
+		LOG(LogError, "Network::ConnectSocket: getpeername failed: %s!", Network::GetLastErrorString().c_str());
 
 
-	String remoteHostName = remoteEndPoint.IPToString();
+	std::string remoteHostName = remoteEndPoint.IPToString();
 
 
 	const size_t maxSendSize = (transport == SocketOverTCP) ? cMaxTCPSendSize : cMaxUDPSendSize;
 	const size_t maxSendSize = (transport == SocketOverTCP) ? cMaxTCPSendSize : cMaxUDPSendSize;
-	Socket socket(connectSocket, localEndPoint, localHostName.CString(), remoteEndPoint, remoteHostName.CString(), transport, ClientSocket, maxSendSize);
+	Socket socket(connectSocket, localEndPoint, localHostName.c_str(), remoteEndPoint, remoteHostName.c_str(), transport, ClientSocket, maxSendSize);
 
 
 	socket.SetBlocking(false);
 	socket.SetBlocking(false);
-	sockets.Push(socket);
+	sockets.push_back(socket);
 
 
-	Socket *sock = &sockets.Back();
+	Socket *sock = &sockets.back();
 
 
 	return sock;
 	return sock;
 }
 }
@@ -725,10 +724,10 @@ Ptr(MessageConnection) Network::Connect(const char *address, unsigned short port
 	if (transport == SocketOverUDP)
 	if (transport == SocketOverUDP)
 	{
 	{
 		SendUDPConnectDatagram(*socket, connectMessage);
 		SendUDPConnectDatagram(*socket, connectMessage);
-		LOG(LogInfo, "Network::Connect: Sent a UDP Connection Start datagram to to %s.", socket->ToString().CString());
+		LOG(LogInfo, "Network::Connect: Sent a UDP Connection Start datagram to to %s.", socket->ToString().c_str());
 	}
 	}
 	else
 	else
-		LOG(LogInfo, "Network::Connect: Connected a TCP socket to %s.", socket->ToString().CString());
+		LOG(LogInfo, "Network::Connect: Connected a TCP socket to %s.", socket->ToString().c_str());
 
 
 	Ptr(MessageConnection) connection;
 	Ptr(MessageConnection) connection;
 	if (transport == SocketOverTCP)
 	if (transport == SocketOverTCP)
@@ -739,7 +738,7 @@ Ptr(MessageConnection) Network::Connect(const char *address, unsigned short port
 	connection->RegisterInboundMessageHandler(messageHandler);
 	connection->RegisterInboundMessageHandler(messageHandler);
 	AssignConnectionToWorkerThread(connection);
 	AssignConnectionToWorkerThread(connection);
 
 
-	connections.Insert(connection);
+	connections.insert(connection);
 	return connection;
 	return connection;
 }
 }
 
 
@@ -758,40 +757,40 @@ Socket *Network::CreateUDPSlaveSocket(Socket *serverListenSocket, const EndPoint
 		return 0;
 		return 0;
 	}
 	}
 
 
-	sockets.Push(Socket(udpSocket, serverListenSocket->LocalEndPoint(),
+	sockets.push_back(Socket(udpSocket, serverListenSocket->LocalEndPoint(),
 		serverListenSocket->LocalAddress(), remoteEndPoint, remoteHostName, SocketOverUDP, ServerClientSocket, cMaxUDPSendSize));
 		serverListenSocket->LocalAddress(), remoteEndPoint, remoteHostName, SocketOverUDP, ServerClientSocket, cMaxUDPSendSize));
-	Socket *socket = &sockets.Back();
+	Socket *socket = &sockets.back();
 	socket->SetBlocking(false);
 	socket->SetBlocking(false);
 
 
-	LOG(LogInfo, "Network::CreateUDPSlaveSocket: Connected an UDP socket to %s.", socket->ToString().CString());
+	LOG(LogInfo, "Network::CreateUDPSlaveSocket: Connected an UDP socket to %s.", socket->ToString().c_str());
 	return socket;
 	return socket;
 }
 }
 
 
 Socket *Network::StoreSocket(const Socket &cp)
 Socket *Network::StoreSocket(const Socket &cp)
 {
 {
-	sockets.Push(cp);
-	return &sockets.Back();
+	sockets.push_back(cp);
+	return &sockets.back();
 }
 }
 
 
 void Network::SendUDPConnectDatagram(Socket &socket, Datagram *connectMessage)
 void Network::SendUDPConnectDatagram(Socket &socket, Datagram *connectMessage)
 {
 {
-	OverlappedTransferBuffer *sendData = socket.BeginSend();
+    const int connectMessageSize = connectMessage ? connectMessage->size : 8;
+	OverlappedTransferBuffer *sendData = socket.BeginSend(connectMessageSize);
 	if (!sendData)
 	if (!sendData)
 	{
 	{
 		LOG(LogError, "Network::SendUDPConnectDatagram: socket.BeginSend failed! Cannot send UDP connection datagram!");
 		LOG(LogError, "Network::SendUDPConnectDatagram: socket.BeginSend failed! Cannot send UDP connection datagram!");
 		return;
 		return;
 	}
 	}
+	sendData->bytesContains = connectMessageSize;
 	if (connectMessage)
 	if (connectMessage)
 	{
 	{
 		///\todo Craft the proper connection attempt datagram.
 		///\todo Craft the proper connection attempt datagram.
-		sendData->buffer.len = std::min<int>(connectMessage->size, sendData->buffer.len);
 		memcpy(sendData->buffer.buf, connectMessage->data, sendData->buffer.len);
 		memcpy(sendData->buffer.buf, connectMessage->data, sendData->buffer.len);
 		LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending UDP connect message of size %d.", (int)sendData->buffer.len);
 		LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending UDP connect message of size %d.", (int)sendData->buffer.len);
 	}
 	}
 	else
 	else
 	{
 	{
 		///\todo Craft the proper connection attempt datagram.
 		///\todo Craft the proper connection attempt datagram.
-		sendData->buffer.len = std::min<int>(8, sendData->buffer.len);
 		memset(sendData->buffer.buf, 0, sendData->buffer.len);
 		memset(sendData->buffer.buf, 0, sendData->buffer.len);
 		LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending null UDP connect message of size %d.", (int)sendData->buffer.len);
 		LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending null UDP connect message of size %d.", (int)sendData->buffer.len);
 	}
 	}

+ 12 - 14
ThirdParty/kNet/src/NetworkLogging.cpp

@@ -15,16 +15,14 @@
 /** @file NetworkLogging.cpp
 /** @file NetworkLogging.cpp
 	@brief Implements logging functionalities to stdout/file for different log channels. */
 	@brief Implements logging functionalities to stdout/file for different log channels. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
+#include <sstream>
 #include <iostream>
 #include <iostream>
 #include <fstream>
 #include <fstream>
 #include <cstdarg>
 #include <cstdarg>
 #include <cstdio>
 #include <cstdio>
+#include <string>
 #include <cstring>
 #include <cstring>
 
 
-#include "Str.h"
-
 #ifdef KNET_USE_BOOST
 #ifdef KNET_USE_BOOST
 #include <boost/thread/thread.hpp>
 #include <boost/thread/thread.hpp>
 #endif
 #endif
@@ -53,7 +51,7 @@ ofstream kNetLogFile;
 
 
 Lockable<int> logWriteMutex;
 Lockable<int> logWriteMutex;
 
 
-String Time()
+string Time()
 {
 {
 	static tick_t firstTick;
 	static tick_t firstTick;
 	static bool firstCall = true;
 	static bool firstCall = true;
@@ -64,12 +62,12 @@ String Time()
 		return "0.000";
 		return "0.000";
 	}
 	}
 	double t = Clock::SecondsSinceD(firstTick);
 	double t = Clock::SecondsSinceD(firstTick);
-	String str;
-	str += String(t);
+	std::stringstream ss;
+	ss << t;
 #ifdef KNET_USE_BOOST
 #ifdef KNET_USE_BOOST
-	str += ", " + String(boost::this_thread::get_id());
+	ss << ", " << boost::this_thread::get_id();
 #endif
 #endif
-	return str;
+	return ss.str();
 }
 }
 
 
 } // ~unnamed namespace
 } // ~unnamed namespace
@@ -87,9 +85,9 @@ void TimeOutputDebugStringVariadic(LogChannel logChannel, const char * /*filenam
 	vsnprintf(errorStr, 1023, msg, args);
 	vsnprintf(errorStr, 1023, msg, args);
 
 
 	if (kNetLogFile.is_open())
 	if (kNetLogFile.is_open())
-		kNetLogFile << Time().CString() << ": " << errorStr << std::endl;
+		kNetLogFile << Time() << ": " << errorStr << std::endl;
 	else
 	else
-		std::cout << Time().CString() << ": " << errorStr << std::endl;
+		std::cout << Time() << ": " << errorStr << std::endl;
 
 
 	va_end(args);
 	va_end(args);
 }
 }
@@ -105,9 +103,9 @@ void TimeOutputDebugString(LogChannel logChannel, const char * /*filename*/, int
 	_snprintf(errorStr, 1023, "%s", msg);
 	_snprintf(errorStr, 1023, "%s", msg);
 
 
 	if (kNetLogFile.is_open())
 	if (kNetLogFile.is_open())
-		kNetLogFile << Time().CString() << ": " << errorStr << std::endl;
+		kNetLogFile << Time() << ": " << errorStr << std::endl;
 	else
 	else
-		std::cout << Time().CString() << ": " << errorStr << std::endl;
+		std::cout << Time() << ": " << errorStr << std::endl;
 }
 }
 
 
 void SetLogChannels(LogChannel logChannels)
 void SetLogChannels(LogChannel logChannels)
@@ -136,7 +134,7 @@ void SetLogFile(const char *filename)
 
 
 void EnableMemoryLeakLoggingAtExit()
 void EnableMemoryLeakLoggingAtExit()
 {
 {
-#ifdef WIN32
+#ifdef _MSC_VER
 	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
 	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
 
 
 	_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
 	_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);

+ 1 - 3
ThirdParty/kNet/src/NetworkMessage.cpp

@@ -15,9 +15,7 @@
 /** @file NetworkMessage.cpp
 /** @file NetworkMessage.cpp
 	@brief Represents a serializable network message. */
 	@brief Represents a serializable network message. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
-#include "Str.h"
+#include <string.h>
 
 
 #include "kNet/DebugMemoryLeakCheck.h"
 #include "kNet/DebugMemoryLeakCheck.h"
 #include "kNet/NetworkMessage.h"
 #include "kNet/NetworkMessage.h"

+ 68 - 70
ThirdParty/kNet/src/NetworkServer.cpp

@@ -15,8 +15,6 @@
 /** @file NetworkServer.cpp
 /** @file NetworkServer.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #ifdef KNET_USE_BOOST
 #ifdef KNET_USE_BOOST
 #include <boost/thread/thread.hpp>
 #include <boost/thread/thread.hpp>
 #endif
 #endif
@@ -38,7 +36,7 @@
 namespace kNet
 namespace kNet
 {
 {
 
 
-NetworkServer::NetworkServer(Network *owner_, Vector<Socket *> listenSockets_)
+NetworkServer::NetworkServer(Network *owner_, std::vector<Socket *> listenSockets_)
 :owner(owner_), listenSockets(listenSockets_), acceptNewConnections(true), networkServerListener(0),
 :owner(owner_), listenSockets(listenSockets_), acceptNewConnections(true), networkServerListener(0),
 udpConnectionAttempts(64), workerThread(0)
 udpConnectionAttempts(64), workerThread(0)
 #ifdef KNET_THREAD_CHECKING_ENABLED
 #ifdef KNET_THREAD_CHECKING_ENABLED
@@ -46,7 +44,7 @@ udpConnectionAttempts(64), workerThread(0)
 #endif
 #endif
 {
 {
 	assert(owner);
 	assert(owner);
-	assert(listenSockets.Size() > 0);
+	assert(listenSockets.size() > 0);
 }
 }
 
 
 NetworkServer::~NetworkServer()
 NetworkServer::~NetworkServer()
@@ -76,7 +74,7 @@ void NetworkServer::CloseListenSockets()
 {
 {
 	assert(owner);
 	assert(owner);
 
 
-	for(size_t i = 0; i < listenSockets.Size(); ++i)
+	for(size_t i = 0; i < listenSockets.size(); ++i)
 	{
 	{
 		if (listenSockets[i]->TransportLayer() == SocketOverUDP)
 		if (listenSockets[i]->TransportLayer() == SocketOverUDP)
 			acceptNewConnections = false; ///\todo At this point, if in UDP mode, we should have destroyed all connections that use this socket!
 			acceptNewConnections = false; ///\todo At this point, if in UDP mode, we should have destroyed all connections that use this socket!
@@ -85,7 +83,7 @@ void NetworkServer::CloseListenSockets()
 	}
 	}
 
 
 	// Now forget all sockets - not getting them back in any way.
 	// Now forget all sockets - not getting them back in any way.
-	listenSockets.Clear();
+	listenSockets.clear();
 }
 }
 
 
 Socket *NetworkServer::AcceptConnections(Socket *listenSocket)
 Socket *NetworkServer::AcceptConnections(Socket *listenSocket)
@@ -103,7 +101,7 @@ Socket *NetworkServer::AcceptConnections(Socket *listenSocket)
 		int error = Network::GetLastError();
 		int error = Network::GetLastError();
 		if (error != KNET_EWOULDBLOCK)
 		if (error != KNET_EWOULDBLOCK)
 		{
 		{
-			LOG(LogError, "NetworkServer::AcceptConnections: accept failed: %s", Network::GetErrorString(error).CString());
+			LOG(LogError, "NetworkServer::AcceptConnections: accept failed: %s", Network::GetErrorString(error).c_str());
 			closesocket(listenSock);
 			closesocket(listenSock);
 			listenSock = INVALID_SOCKET;
 			listenSock = INVALID_SOCKET;
 		}
 		}
@@ -111,19 +109,19 @@ Socket *NetworkServer::AcceptConnections(Socket *listenSocket)
 	}
 	}
 
 
 	EndPoint remoteEndPoint = EndPoint::FromSockAddrIn(remoteAddress);
 	EndPoint remoteEndPoint = EndPoint::FromSockAddrIn(remoteAddress);
-	String remoteHostName = remoteEndPoint.IPToString();
+	std::string remoteHostName = remoteEndPoint.IPToString();
 
 
-	LOG(LogInfo, "Accepted incoming TCP connection from %s:%d.", remoteHostName.CString(), (int)remoteEndPoint.port);
+	LOG(LogInfo, "Accepted incoming TCP connection from %s:%d.", remoteHostName.c_str(), (int)remoteEndPoint.port);
 
 
 	EndPoint localEndPoint;
 	EndPoint localEndPoint;
 	sockaddr_in localSockAddr;
 	sockaddr_in localSockAddr;
 	socklen_t namelen = sizeof(localSockAddr);
 	socklen_t namelen = sizeof(localSockAddr);
 	int sockRet = getsockname(acceptSocket, (sockaddr*)&localSockAddr, &namelen); // Note: This works only if family==INETv4
 	int sockRet = getsockname(acceptSocket, (sockaddr*)&localSockAddr, &namelen); // Note: This works only if family==INETv4
 	localEndPoint = EndPoint::FromSockAddrIn(localSockAddr);
 	localEndPoint = EndPoint::FromSockAddrIn(localSockAddr);
-	String localHostName = owner->LocalAddress();
+	std::string localHostName = owner->LocalAddress();
 
 
 	const size_t maxTcpSendSize = 65536;
 	const size_t maxTcpSendSize = 65536;
-	Socket *socket = owner->StoreSocket(Socket(acceptSocket, localEndPoint, localHostName.CString(), remoteEndPoint, remoteHostName.CString(), SocketOverTCP, ServerClientSocket, maxTcpSendSize));
+	Socket *socket = owner->StoreSocket(Socket(acceptSocket, localEndPoint, localHostName.c_str(), remoteEndPoint, remoteHostName.c_str(), SocketOverTCP, ServerClientSocket, maxTcpSendSize));
 	socket->SetBlocking(false);
 	socket->SetBlocking(false);
 
 
 	return socket;
 	return socket;
@@ -135,22 +133,22 @@ void NetworkServer::CleanupDeadConnections()
 	ConnectionMap clientsMap = *clients.Acquire();
 	ConnectionMap clientsMap = *clients.Acquire();
 
 
 	// Clean up all disconnected/timed out connections.
 	// Clean up all disconnected/timed out connections.
-	ConnectionMap::Iterator iter = clientsMap.Begin();
-	while(iter != clientsMap.End())
+	ConnectionMap::iterator iter = clientsMap.begin();
+	while(iter != clientsMap.end())
 	{
 	{
-		ConnectionMap::Iterator next = iter;
+		ConnectionMap::iterator next = iter;
 		++next;
 		++next;
-		if (!iter->second_->Connected())
+		if (!iter->second->Connected())
 		{
 		{
-			LOG(LogInfo, "Client %s disconnected.", iter->second_->ToString().CString());
+			LOG(LogInfo, "Client %s disconnected.", iter->second->ToString().c_str());
 			if (networkServerListener)
 			if (networkServerListener)
-				networkServerListener->ClientDisconnected(iter->second_);
-			if (iter->second_->GetSocket() && iter->second_->GetSocket()->TransportLayer() == SocketOverTCP)
-				owner->CloseConnection(iter->second_);
+				networkServerListener->ClientDisconnected(iter->second);
+			if (iter->second->GetSocket() && iter->second->GetSocket()->TransportLayer() == SocketOverTCP)
+				owner->CloseConnection(iter->second);
 
 
 			{
 			{
 				Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
 				Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
-				clientsLock->Erase(iter->first_);
+				clientsLock->erase(iter->first);
 			}
 			}
 		}
 		}
 		iter = next;
 		iter = next;
@@ -161,7 +159,7 @@ void NetworkServer::Process()
 {
 {
 	CleanupDeadConnections();
 	CleanupDeadConnections();
 
 
-	for(size_t i = 0; i < listenSockets.Size(); ++i)
+	for(size_t i = 0; i < listenSockets.size(); ++i)
 	{
 	{
 		Socket *listen = listenSockets[i];
 		Socket *listen = listenSockets[i];
 
 
@@ -174,7 +172,7 @@ void NetworkServer::Process()
 				if (!client->Connected())
 				if (!client->Connected())
 					LOG(LogError, "Warning: Accepted an already closed connection!");
 					LOG(LogError, "Warning: Accepted an already closed connection!");
 
 
-				LOG(LogInfo, "Client connected from %s.", client->ToString().CString());
+				LOG(LogInfo, "Client connected from %s.", client->ToString().c_str());
 
 
 				// Build a MessageConnection on top of the raw socket.
 				// Build a MessageConnection on top of the raw socket.
 				assert(listen->TransportLayer() == SocketOverTCP);
 				assert(listen->TransportLayer() == SocketOverTCP);
@@ -211,8 +209,8 @@ void NetworkServer::Process()
 
 
 	// Process all new inbound data for each connection handled by this server.
 	// Process all new inbound data for each connection handled by this server.
 	ConnectionMap clientMap = *clients.Acquire();
 	ConnectionMap clientMap = *clients.Acquire();
-	for(ConnectionMap::Iterator iter = clientMap.Begin(); iter != clientMap.End(); ++iter)
-		iter->second_->Process();
+	for(ConnectionMap::iterator iter = clientMap.begin(); iter != clientMap.end(); ++iter)
+		iter->second->Process();
 }
 }
 
 
 void NetworkServer::ReadUDPSocketData(Socket *listenSocket) // [worker thread]
 void NetworkServer::ReadUDPSocketData(Socket *listenSocket) // [worker thread]
@@ -231,8 +229,8 @@ void NetworkServer::ReadUDPSocketData(Socket *listenSocket) // [worker thread]
 		return;
 		return;
 	}
 	}
 	EndPoint endPoint = EndPoint::FromSockAddrIn(recvData->from); // This conversion is quite silly, perhaps it could be removed to gain performance?
 	EndPoint endPoint = EndPoint::FromSockAddrIn(recvData->from); // This conversion is quite silly, perhaps it could be removed to gain performance?
-	LOG(LogData, "Received a datagram of size %d to socket %s from endPoint %s.", recvData->bytesContains, listenSocket->ToString().CString(),
-		endPoint.ToString().CString());
+	LOG(LogData, "Received a datagram of size %d to socket %s from endPoint %s.", recvData->bytesContains, listenSocket->ToString().c_str(),
+		endPoint.ToString().c_str());
 
 
 	PolledTimer timer;
 	PolledTimer timer;
 	MessageConnection *receiverConnection = 0;
 	MessageConnection *receiverConnection = 0;
@@ -245,9 +243,9 @@ void NetworkServer::ReadUDPSocketData(Socket *listenSocket) // [worker thread]
 			timer.MSecsElapsed());
 			timer.MSecsElapsed());
 		}
 		}
 
 
-		ConnectionMap::Iterator iter = clientsLock->Find(endPoint); ///\todo HashTable for performance.
-		if (iter != clientsLock->End())
-			receiverConnection = iter->second_;
+		ConnectionMap::iterator iter = clientsLock->find(endPoint); ///\todo HashTable for performance.
+		if (iter != clientsLock->end())
+			receiverConnection = iter->second;
 	}
 	}
 
 
 	if (receiverConnection)
 	if (receiverConnection)
@@ -282,12 +280,12 @@ void NetworkServer::EnqueueNewUDPConnectionAttempt(Socket *listenSocket, const E
 	if (!success)
 	if (!success)
 		LOG(LogError, "Too many connection attempts!");
 		LOG(LogError, "Too many connection attempts!");
 	else
 	else
-		LOG(LogInfo, "Queued new connection attempt from %s.", endPoint.ToString().CString());
+		LOG(LogInfo, "Queued new connection attempt from %s.", endPoint.ToString().c_str());
 }
 }
 
 
 bool NetworkServer::ProcessNewUDPConnectionAttempt(Socket *listenSocket, const EndPoint &endPoint, const char *data, size_t numBytes)
 bool NetworkServer::ProcessNewUDPConnectionAttempt(Socket *listenSocket, const EndPoint &endPoint, const char *data, size_t numBytes)
 {
 {
-	LOG(LogInfo, "New inbound connection attempt from %s with datagram of size %d.", endPoint.ToString().CString(), (int)numBytes);
+	LOG(LogInfo, "New inbound connection attempt from %s with datagram of size %d.", endPoint.ToString().c_str(), (int)numBytes);
 	if (!acceptNewConnections)
 	if (!acceptNewConnections)
 	{
 	{
 		LOG(LogError, "Ignored a new connection attempt since server is set not to accept new connections.");
 		LOG(LogError, "Ignored a new connection attempt since server is set not to accept new connections.");
@@ -308,10 +306,10 @@ bool NetworkServer::ProcessNewUDPConnectionAttempt(Socket *listenSocket, const E
 	///\todo Check IP banlist.
 	///\todo Check IP banlist.
 	///\todo Check that the maximum number of active concurrent connections is not exceeded.
 	///\todo Check that the maximum number of active concurrent connections is not exceeded.
 
 
-	String remoteHostName = endPoint.IPToString();
+	std::string remoteHostName = endPoint.IPToString();
 
 
 	// Accept the connection and create a new UDP socket that communicates to that endpoint.
 	// Accept the connection and create a new UDP socket that communicates to that endpoint.
-	Socket *socket = owner->CreateUDPSlaveSocket(listenSocket, endPoint, remoteHostName.CString());
+	Socket *socket = owner->CreateUDPSlaveSocket(listenSocket, endPoint, remoteHostName.c_str());
 	if (!socket)
 	if (!socket)
 	{
 	{
 		LOG(LogError, "Network::ConnectUDP failed! Cannot accept new UDP connection.");
 		LOG(LogError, "Network::ConnectUDP failed! Cannot accept new UDP connection.");
@@ -353,9 +351,9 @@ void NetworkServer::BroadcastMessage(const NetworkMessage &msg, MessageConnectio
 			timer.MSecsElapsed());
 			timer.MSecsElapsed());
 	}
 	}
 
 
-	for(ConnectionMap::Iterator iter = clientsLock->Begin(); iter != clientsLock->End(); ++iter)
+	for(ConnectionMap::iterator iter = clientsLock->begin(); iter != clientsLock->end(); ++iter)
 	{
 	{
-		MessageConnection *connection = iter->second_;
+		MessageConnection *connection = iter->second;
 		if (connection == exclude)
 		if (connection == exclude)
 			continue;
 			continue;
 
 
@@ -375,9 +373,9 @@ void NetworkServer::BroadcastMessage(unsigned long id, bool reliable, bool inOrd
 			timer.MSecsElapsed());
 			timer.MSecsElapsed());
 	}
 	}
 
 
-	for(ConnectionMap::Iterator iter = clientsLock->Begin(); iter != clientsLock->End(); ++iter)
+	for(ConnectionMap::iterator iter = clientsLock->begin(); iter != clientsLock->end(); ++iter)
 	{
 	{
-		MessageConnection *connection = iter->second_;
+		MessageConnection *connection = iter->second;
 		assert(connection);
 		assert(connection);
 		if (connection == exclude || !connection->IsWriteOpen())
 		if (connection == exclude || !connection->IsWriteOpen())
 			continue;
 			continue;
@@ -413,8 +411,8 @@ void NetworkServer::DisconnectAllClients()
 	LOG(LogWaits, "NetworkServer::DisconnectAllClients: Accessing the connection list took %f msecs.",
 	LOG(LogWaits, "NetworkServer::DisconnectAllClients: Accessing the connection list took %f msecs.",
 		timer.MSecsElapsed());
 		timer.MSecsElapsed());
 
 
-	for(ConnectionMap::Iterator iter = clientsLock->Begin(); iter != clientsLock->End(); ++iter)
-		iter->second_->Disconnect(0); // Do not wait for any client.
+	for(ConnectionMap::iterator iter = clientsLock->begin(); iter != clientsLock->end(); ++iter)
+		iter->second->Disconnect(0); // Do not wait for any client.
 }
 }
 
 
 void NetworkServer::Close(int disconnectWaitMilliseconds)
 void NetworkServer::Close(int disconnectWaitMilliseconds)
@@ -423,7 +421,7 @@ void NetworkServer::Close(int disconnectWaitMilliseconds)
 
 
 	///\todo Re-implement this function to remove the monolithic Sleep here. Instead of this,
 	///\todo Re-implement this function to remove the monolithic Sleep here. Instead of this,
 	/// wait for the individual connections to finish.
 	/// wait for the individual connections to finish.
-	if (GetConnections().Size() > 0)
+	if (GetConnections().size() > 0)
 	{
 	{
 		Clock::Sleep(disconnectWaitMilliseconds);
 		Clock::Sleep(disconnectWaitMilliseconds);
 		LOG(LogVerbose, "NetworkServer::Close: Waited a fixed period of %d msecs for all connections to disconnect.",
 		LOG(LogVerbose, "NetworkServer::Close: Waited a fixed period of %d msecs for all connections to disconnect.",
@@ -434,8 +432,8 @@ void NetworkServer::Close(int disconnectWaitMilliseconds)
 	Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
 	Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
 	LOG(LogWaits, "NetworkServer::Close: Accessing the connection list took %f msecs.",
 	LOG(LogWaits, "NetworkServer::Close: Accessing the connection list took %f msecs.",
 		timer.MSecsElapsed());
 		timer.MSecsElapsed());
-	for(ConnectionMap::Iterator iter = clientsLock->Begin(); iter != clientsLock->End(); ++iter)
-		iter->second_->Close(0); // Do not wait for any client.
+	for(ConnectionMap::iterator iter = clientsLock->begin(); iter != clientsLock->end(); ++iter)
+		iter->second->Close(0); // Do not wait for any client.
 }
 }
 
 
 void NetworkServer::RunModalServer()
 void NetworkServer::RunModalServer()
@@ -458,8 +456,8 @@ void NetworkServer::ConnectionClosed(MessageConnection *connection)
 	Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
 	Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
 	LOG(LogWaits, "NetworkServer::ConnectionClosed: Accessing the connection list took %f msecs.",
 	LOG(LogWaits, "NetworkServer::ConnectionClosed: Accessing the connection list took %f msecs.",
 		timer.MSecsElapsed());
 		timer.MSecsElapsed());
-	for(ConnectionMap::Iterator iter = clientsLock->Begin(); iter != clientsLock->End(); ++iter)
-		if (iter->second_ == connection)
+	for(ConnectionMap::iterator iter = clientsLock->begin(); iter != clientsLock->end(); ++iter)
+		if (iter->second == connection)
 		{
 		{
 			if (networkServerListener)
 			if (networkServerListener)
 				networkServerListener->ClientDisconnected(connection);
 				networkServerListener->ClientDisconnected(connection);
@@ -470,7 +468,7 @@ void NetworkServer::ConnectionClosed(MessageConnection *connection)
 				connection->socket = 0;
 				connection->socket = 0;
 			}
 			}
 
 
-			clientsLock->Erase(iter);
+			clientsLock->erase(iter);
 
 
 			return;
 			return;
 		}
 		}
@@ -478,7 +476,7 @@ void NetworkServer::ConnectionClosed(MessageConnection *connection)
 	LOG(LogError, "Unknown MessageConnection passed to NetworkServer::Disconnect!");
 	LOG(LogError, "Unknown MessageConnection passed to NetworkServer::Disconnect!");
 }
 }
 
 
-Vector<Socket *> &NetworkServer::ListenSockets()
+std::vector<Socket *> &NetworkServer::ListenSockets()
 {
 {
 	return listenSockets;
 	return listenSockets;
 }
 }
@@ -499,67 +497,67 @@ int NetworkServer::NumConnections() const
 {
 {
 	int numConnections = 0;
 	int numConnections = 0;
 	Lockable<ConnectionMap>::ConstLockType lock = clients.Acquire();
 	Lockable<ConnectionMap>::ConstLockType lock = clients.Acquire();
-	for(ConnectionMap::ConstIterator iter = lock->Begin(); iter != lock->End(); ++iter)
+	for(ConnectionMap::const_iterator iter = lock->begin(); iter != lock->end(); ++iter)
 	{
 	{
-		const MessageConnection *connection = iter->second_.ptr();
+		const MessageConnection *connection = iter->second.ptr();
 		if (connection && (connection->IsPending() || connection->IsReadOpen() || connection->IsWriteOpen()))
 		if (connection && (connection->IsPending() || connection->IsReadOpen() || connection->IsWriteOpen()))
 			++numConnections;
 			++numConnections;
 	}
 	}
 	return numConnections;
 	return numConnections;
 }
 }
 
 
-String NetworkServer::ToString() const
+std::string NetworkServer::ToString() const
 {
 {
 	bool isUdp = false;
 	bool isUdp = false;
 	bool isTcp = false;
 	bool isTcp = false;
-	for(size_t i = 0; i < listenSockets.Size(); ++i)
+	for(size_t i = 0; i < listenSockets.size(); ++i)
 		if (listenSockets[i]->TransportLayer() == SocketOverUDP)
 		if (listenSockets[i]->TransportLayer() == SocketOverUDP)
 			isUdp = true;
 			isUdp = true;
 		else
 		else
 			isTcp = true;
 			isTcp = true;
 
 
-	String str;
+	std::stringstream ss;
 	if (isUdp && isTcp)
 	if (isUdp && isTcp)
-		str += "TCP+UDP server";
+		ss << "TCP+UDP server";
 	else if (isUdp)
 	else if (isUdp)
-		str += "UDP server";
+		ss << "UDP server";
 	else if (isTcp)
 	else if (isTcp)
-		str += "TCP server";
-	else str += "Server (no listen sockets open)";
+		ss << "TCP server";
+	else ss << "Server (no listen sockets open)";
 
 
-	if (listenSockets.Size() == 1)
+	if (listenSockets.size() == 1)
 	{
 	{
 		int port = (int)listenSockets[0]->LocalPort();
 		int port = (int)listenSockets[0]->LocalPort();
-		str += " at local port " + String(port);
+		ss << " at local port " << port;
 	}
 	}
-	else if (listenSockets.Size() > 1)
+	else if (listenSockets.size() > 1)
 	{
 	{
-		str += " (" + String((int)listenSockets.Size()) + " listen sockets at local ports ";
-		for(size_t i = 0; i < listenSockets.Size() && i < 3; ++i)
+		ss << " (" << (int)listenSockets.size() << " listen sockets at local ports ";
+		for(size_t i = 0; i < listenSockets.size() && i < 3; ++i)
 		{
 		{
 			if (i > 0)
 			if (i > 0)
-				str += ", ";
-			str += String(listenSockets[i]->LocalPort());
+				ss << ", ";
+			ss << listenSockets[i]->LocalPort();
 		}
 		}
-		if (listenSockets.Size() > 3)
-			str += ", ...";
-		str += ")";
+		if (listenSockets.size() > 3)
+			ss << ", ...";
+		ss << ")";
 	}
 	}
-	str += ": ";
+	ss << ": ";
 
 
 	int numConnections = 0;
 	int numConnections = 0;
 	{
 	{
 		Lockable<ConnectionMap>::ConstLockType lock = clients.Acquire();
 		Lockable<ConnectionMap>::ConstLockType lock = clients.Acquire();
-		numConnections = lock->Size();
+		numConnections = lock->size();
 	}
 	}
-	str += String(numConnections) + " connections.";
+	ss << numConnections << " connections.";
 
 
 	if (!acceptNewConnections)
 	if (!acceptNewConnections)
-		str += " (not accepting new connections)";
+		ss << " (not accepting new connections)";
 
 
 	///\todo Add note about stealth mode.
 	///\todo Add note about stealth mode.
 
 
-	return str;
+	return ss.str();
 }
 }
 
 
 } // ~kNet
 } // ~kNet

+ 121 - 0
ThirdParty/kNet/src/NetworkSimulator.cpp

@@ -0,0 +1,121 @@
+/* Copyright The kNet Project.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. */
+
+#include "kNet/NetworkSimulator.h"
+#include "kNet/MessageConnection.h"
+
+namespace kNet
+{
+
+NetworkSimulator::NetworkSimulator()
+:enabled(false),
+packetLossRate(0),
+constantPacketSendDelay(0),
+uniformRandomPacketSendDelay(0),
+owner(0),
+corruptMessageId(0),
+corruptToggleBitsRate(0),
+corruptionType(CorruptDatagram),
+corruptMinBits(0),
+corruptMaxBits(0)
+{
+}
+
+NetworkSimulator::~NetworkSimulator()
+{
+	if (queuedBuffers.size() > 0)
+		LOG(LogError, "NetworkSimulator: Leaked %d buffers with improper NetworkSimulator teardown!", (int)queuedBuffers.size());
+}
+
+static float rand01() { return (float)rand() / (RAND_MAX+1); }
+
+void NetworkSimulator::Free()
+{
+	if (!owner || !owner->GetSocket())
+		return;
+
+	for(size_t i = 0; i < queuedBuffers.size(); ++i)
+		owner->GetSocket()->AbortSend(queuedBuffers[i].buffer);
+	queuedBuffers.clear();
+}
+
+void NetworkSimulator::SubmitSendBuffer(kNet::OverlappedTransferBuffer *buffer, Socket *socket)
+{
+	if (rand01() < packetLossRate)
+	{
+		if (owner && owner->GetSocket())
+			owner->GetSocket()->AbortSend(buffer);
+		return; // Dropped this packet!
+	}
+
+	// Should we duplicate this packet?
+	if (rand01() < packetDuplicationRate)
+	{
+		QueuedBuffer b;
+		assert(socket);
+        b.buffer = socket->BeginSend(buffer->bytesContains);
+		if (b.buffer)
+		{
+			assert(b.buffer->buffer.len >= buffer->bytesContains);
+			memcpy(b.buffer->buffer.buf, buffer->buffer.buf, buffer->bytesContains);
+			b.buffer->bytesContains = buffer->bytesContains;
+
+			// Should we corrupt the newly created copy?
+			if (corruptionType == CorruptDatagram)
+				MaybeCorruptBufferToggleBits(b.buffer->buffer.buf, b.buffer->bytesContains);
+
+			b.timeUntilTransfer.StartMSecs(constantPacketSendDelay + (float)rand() * uniformRandomPacketSendDelay / RAND_MAX);
+			queuedBuffers.push_back(b);
+		}
+	}
+
+	// Should we corrupt this packet?
+	if (corruptionType == CorruptDatagram)
+		MaybeCorruptBufferToggleBits(buffer->buffer.buf, buffer->bytesContains);
+
+	QueuedBuffer b;
+	b.buffer = buffer;
+	b.timeUntilTransfer.StartMSecs(constantPacketSendDelay + (float)rand() * uniformRandomPacketSendDelay / RAND_MAX);
+	queuedBuffers.push_back(b);
+}
+
+void NetworkSimulator::Process()
+{
+	for(size_t i = 0; i < queuedBuffers.size(); ++i)
+		if (queuedBuffers[i].timeUntilTransfer.Test())
+		{
+			if (owner && owner->GetSocket())
+				owner->GetSocket()->EndSend(queuedBuffers[i].buffer);
+			queuedBuffers.erase(queuedBuffers.begin() + i);
+			--i;
+		}
+}
+
+void NetworkSimulator::MaybeCorruptBufferToggleBits(void *buffer, size_t numBytes) const
+{
+	// Should corrupt this data?
+	if (rand01() < corruptToggleBitsRate)
+	{
+		int numBitsToCorrupt = corruptMinBits + rand() * (corruptMaxBits - corruptMinBits + 1) / (RAND_MAX+1);
+		for(int i = 0; i < numBitsToCorrupt; ++i)
+		{
+			int byteIndex = rand() * numBytes / (RAND_MAX+1);
+			int bitIndex = rand() % 8;
+			int bitMask = (1 << bitIndex);
+			((char*)buffer)[byteIndex] ^= bitMask;
+		}
+	}
+}
+
+} // ~kNet

+ 40 - 42
ThirdParty/kNet/src/NetworkWorkerThread.cpp

@@ -15,8 +15,6 @@
 /** @file NetworkWorkerThread.cpp
 /** @file NetworkWorkerThread.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include <utility>
 #include <utility>
 
 
 #ifdef KNET_USE_BOOST
 #ifdef KNET_USE_BOOST
@@ -46,8 +44,8 @@ NetworkWorkerThread::NetworkWorkerThread()
 void NetworkWorkerThread::AddConnection(MessageConnection *connection)
 void NetworkWorkerThread::AddConnection(MessageConnection *connection)
 {
 {
 	workThread.Hold();
 	workThread.Hold();
-	Lockable<Vector<MessageConnection *> >::LockType lock = connections.Acquire();
-	lock->Push(connection);
+	Lockable<std::vector<MessageConnection *> >::LockType lock = connections.Acquire();
+	lock->push_back(connection);
 	LOG(LogVerbose, "Added connection %p to NetworkWorkerThread.", connection);
 	LOG(LogVerbose, "Added connection %p to NetworkWorkerThread.", connection);
 	workThread.Resume();
 	workThread.Resume();
 }
 }
@@ -56,12 +54,12 @@ void NetworkWorkerThread::RemoveConnection(MessageConnection *connection)
 {
 {
 	workThread.Hold();
 	workThread.Hold();
 
 
-	Lockable<Vector<MessageConnection *> >::LockType lock = connections.Acquire();
+	Lockable<std::vector<MessageConnection *> >::LockType lock = connections.Acquire();
 
 
-	for(size_t i = 0; i < lock->Size(); ++i)
+	for(size_t i = 0; i < lock->size(); ++i)
 		if ((*lock)[i] == connection)
 		if ((*lock)[i] == connection)
 		{
 		{
-			lock->Erase(lock->Begin() + i);
+			lock->erase(lock->begin() + i);
 			LOG(LogVerbose, "NetworkWorkerThread::RemoveConnection: Connection %p removed.", connection);
 			LOG(LogVerbose, "NetworkWorkerThread::RemoveConnection: Connection %p removed.", connection);
 			workThread.Resume();
 			workThread.Resume();
 			return;
 			return;
@@ -73,8 +71,8 @@ void NetworkWorkerThread::RemoveConnection(MessageConnection *connection)
 void NetworkWorkerThread::AddServer(NetworkServer *server)
 void NetworkWorkerThread::AddServer(NetworkServer *server)
 {
 {
 	workThread.Hold();
 	workThread.Hold();
-	Lockable<Vector<NetworkServer *> >::LockType lock = servers.Acquire();
-	lock->Push(server);
+	Lockable<std::vector<NetworkServer *> >::LockType lock = servers.Acquire();
+	lock->push_back(server);
 	LOG(LogVerbose, "Added server %p to NetworkWorkerThread.", server);
 	LOG(LogVerbose, "Added server %p to NetworkWorkerThread.", server);
 	workThread.Resume();
 	workThread.Resume();
 }
 }
@@ -84,15 +82,15 @@ void NetworkWorkerThread::RemoveServer(NetworkServer *server)
 	workThread.Hold();
 	workThread.Hold();
 
 
 	PolledTimer timer;
 	PolledTimer timer;
-	Lockable<Vector<NetworkServer *> >::LockType lock = servers.Acquire();
+	Lockable<std::vector<NetworkServer *> >::LockType lock = servers.Acquire();
 	float lockWait = timer.MSecsElapsed();
 	float lockWait = timer.MSecsElapsed();
 	LOG(LogWaits, "NetworkWorkerThread::RemoveServer: Waited %f msecs to lock servers list.",
 	LOG(LogWaits, "NetworkWorkerThread::RemoveServer: Waited %f msecs to lock servers list.",
 		lockWait);
 		lockWait);
 
 
-	for(size_t i = 0; i < lock->Size(); ++i)
+	for(size_t i = 0; i < lock->size(); ++i)
 		if ((*lock)[i] == server)
 		if ((*lock)[i] == server)
 		{
 		{
-			lock->Erase(lock->Begin() + i);
+			lock->erase(lock->begin() + i);
 			LOG(LogVerbose, "NetworkWorkerThread::RemoveServer: Server %p removed.", server);
 			LOG(LogVerbose, "NetworkWorkerThread::RemoveServer: Server %p removed.", server);
 			workThread.Resume();
 			workThread.Resume();
 			return;
 			return;
@@ -111,16 +109,16 @@ void NetworkWorkerThread::StopThread()
 	workThread.Stop();
 	workThread.Stop();
 
 
 	{
 	{
-		Lockable<Vector<NetworkServer *> >::LockType lock = servers.Acquire();
-		for(size_t i = 0; i < lock->Size(); ++i)
+		Lockable<std::vector<NetworkServer *> >::LockType lock = servers.Acquire();
+		for(size_t i = 0; i < lock->size(); ++i)
 		{
 		{
 			LOG(LogError, "NetworkWorkerThread::StopThread: Warning: NetworkServer %p was not detached from workerThread %p prior to stopping the thread!.", (*lock)[i], this);
 			LOG(LogError, "NetworkWorkerThread::StopThread: Warning: NetworkServer %p was not detached from workerThread %p prior to stopping the thread!.", (*lock)[i], this);
 			(*lock)[i]->SetWorkerThread(0);
 			(*lock)[i]->SetWorkerThread(0);
 		}
 		}
 	}
 	}
 	{
 	{
-		Lockable<Vector<MessageConnection *> >::LockType lock = connections.Acquire();
-		for(size_t i = 0; i < lock->Size(); ++i)
+		Lockable<std::vector<MessageConnection *> >::LockType lock = connections.Acquire();
+		for(size_t i = 0; i < lock->size(); ++i)
 		{
 		{
 			LOG(LogError, "NetworkWorkerThread::StopThread: Warning: MessageConnection %p was not detached from workerThread %p prior to stopping the thread!.", (*lock)[i], this);
 			LOG(LogError, "NetworkWorkerThread::StopThread: Warning: MessageConnection %p was not detached from workerThread %p prior to stopping the thread!.", (*lock)[i], this);
 			(*lock)[i]->SetWorkerThread(0);
 			(*lock)[i]->SetWorkerThread(0);
@@ -130,17 +128,17 @@ void NetworkWorkerThread::StopThread()
 
 
 int NetworkWorkerThread::NumConnections() const
 int NetworkWorkerThread::NumConnections() const
 {
 {
-	return connections.Acquire()->Size();
+	return connections.Acquire()->size();
 }
 }
 
 
 int NetworkWorkerThread::NumServers() const
 int NetworkWorkerThread::NumServers() const
 {
 {
-	return servers.Acquire()->Size();
+	return servers.Acquire()->size();
 }
 }
 
 
 void NetworkWorkerThread::MainLoop()
 void NetworkWorkerThread::MainLoop()
 {
 {
-	Vector<MessageConnection*> writeWaitConnections;
+	std::vector<MessageConnection*> writeWaitConnections;
 
 
 	EventArray waitEvents;
 	EventArray waitEvents;
 
 
@@ -151,8 +149,8 @@ void NetworkWorkerThread::MainLoop()
 
 
 	LOG(LogInfo, "NetworkWorkerThread starting main loop.");
 	LOG(LogInfo, "NetworkWorkerThread starting main loop.");
 
 
-	Vector<MessageConnection*> connectionList;
-	Vector<NetworkServer*> serverList;
+	std::vector<MessageConnection*> connectionList;
+	std::vector<NetworkServer*> serverList;
 
 
 	while(!workThread.ShouldQuit())
 	while(!workThread.ShouldQuit())
 	{
 	{
@@ -161,11 +159,11 @@ void NetworkWorkerThread::MainLoop()
 			break;
 			break;
 	
 	
 		{
 		{
-			Lockable<Vector<MessageConnection *> >::LockType lock = connections.Acquire();
+			Lockable<std::vector<MessageConnection *> >::LockType lock = connections.Acquire();
 			connectionList = *lock;
 			connectionList = *lock;
 		}
 		}
 		{
 		{
-			Lockable<Vector<NetworkServer *> >::LockType serverLock = servers.Acquire();
+			Lockable<std::vector<NetworkServer *> >::LockType serverLock = servers.Acquire();
 			serverList = *serverLock;
 			serverList = *serverLock;
 		}
 		}
 
 
@@ -177,12 +175,12 @@ void NetworkWorkerThread::MainLoop()
 		int waitTime = maxWaitTime;
 		int waitTime = maxWaitTime;
 
 
 		waitEvents.Clear();
 		waitEvents.Clear();
-		writeWaitConnections.Clear();
+		writeWaitConnections.clear();
 
 
 		// Next, build the event array that is used for waiting on the sockets.
 		// Next, build the event array that is used for waiting on the sockets.
 		// At odd indices we will have socket read events, and at even indices the socket write events.
 		// At odd indices we will have socket read events, and at even indices the socket write events.
 		// After the events for each connection, we will have the UDP listen sockets for each UDP server connection.
 		// After the events for each connection, we will have the UDP listen sockets for each UDP server connection.
-		for(size_t i = 0; i < connectionList.Size(); ++i)
+		for(size_t i = 0; i < connectionList.size(); ++i)
 		{
 		{
 			MessageConnection &connection = *connectionList[i];
 			MessageConnection &connection = *connectionList[i];
 
 
@@ -191,14 +189,14 @@ void NetworkWorkerThread::MainLoop()
 				connection.UpdateConnection();
 				connection.UpdateConnection();
 			} catch(const NetException &e)
 			} catch(const NetException &e)
 			{
 			{
-				LOG(LogError, (String("kNet::NetException thrown when processing UpdateConnection() for client connection: ") + e.what()).CString());
+				LOG(LogError, (std::string("kNet::NetException thrown when processing UpdateConnection() for client connection: ") + e.what()).c_str());
 				if (connection.GetSocket())
 				if (connection.GetSocket())
 					connection.GetSocket()->Close();
 					connection.GetSocket()->Close();
 			}
 			}
 
 
 			if (connection.GetConnectionState() == ConnectionClosed || !connection.GetSocket() || !connection.GetSocket()->Connected()) // This does not need to be checked each iteration.
 			if (connection.GetConnectionState() == ConnectionClosed || !connection.GetSocket() || !connection.GetSocket()->Connected()) // This does not need to be checked each iteration.
 			{
 			{
-				connectionList.Erase(connectionList.Begin()+i);
+				connectionList.erase(connectionList.begin()+i);
 				--i;
 				--i;
 				continue;
 				continue;
 			}
 			}
@@ -225,7 +223,7 @@ void NetworkWorkerThread::MainLoop()
 				{
 				{
 					int msecsLeftUntilWrite = (int)connection.TimeUntilCanSendPacket();
 					int msecsLeftUntilWrite = (int)connection.TimeUntilCanSendPacket();
 					waitTime = min(waitTime, msecsLeftUntilWrite);
 					waitTime = min(waitTime, msecsLeftUntilWrite);
-					writeWaitConnections.Push(&connection);
+					writeWaitConnections.push_back(&connection);
 					waitEvents.AddEvent(falseEvent);
 					waitEvents.AddEvent(falseEvent);
 					assert(falseEvent.Test() == false && !falseEvent.IsNull());
 					assert(falseEvent.Test() == false && !falseEvent.IsNull());
 				}
 				}
@@ -251,13 +249,13 @@ void NetworkWorkerThread::MainLoop()
 		// In this case, the NetworkServer object handlesg all data reads, but data sends
 		// In this case, the NetworkServer object handlesg all data reads, but data sends
 		// are still managed by the individual MessageConnection objects.
 		// are still managed by the individual MessageConnection objects.
 		// For TCP servers, this step is not needed, since each connection has its own independent socket.
 		// For TCP servers, this step is not needed, since each connection has its own independent socket.
-		for(size_t i = 0; i < serverList.Size(); ++i)
+		for(size_t i = 0; i < serverList.size(); ++i)
 		{
 		{
 			NetworkServer &server = *serverList[i];
 			NetworkServer &server = *serverList[i];
 
 
-			Vector<Socket *> &listenSockets = server.ListenSockets();
+			std::vector<Socket *> &listenSockets = server.ListenSockets();
 
 
-			for(size_t j = 0; j < listenSockets.Size(); ++j)
+			for(size_t j = 0; j < listenSockets.size(); ++j)
 				if (listenSockets[j]->TransportLayer() == SocketOverUDP)
 				if (listenSockets[j]->TransportLayer() == SocketOverUDP)
 				{
 				{
 					Event listenEvent = listenSockets[j]->GetOverlappedReceiveEvent();
 					Event listenEvent = listenSockets[j]->GetOverlappedReceiveEvent();
@@ -283,7 +281,7 @@ void NetworkWorkerThread::MainLoop()
 
 
 		if (index >= 0 && index < waitEvents.Size()) // An event was triggered?
 		if (index >= 0 && index < waitEvents.Size()) // An event was triggered?
 		{
 		{
-			if ((index >> 1) < (int)connectionList.Size())
+			if ((index >> 1) < (int)connectionList.size())
 			{
 			{
 				MessageConnection *connection = connectionList[index>>1];
 				MessageConnection *connection = connectionList[index>>1];
 				assert(connection);
 				assert(connection);
@@ -300,39 +298,39 @@ void NetworkWorkerThread::MainLoop()
 						connection->SendOutPackets();
 						connection->SendOutPackets();
 				} catch(const NetException &e)
 				} catch(const NetException &e)
 				{
 				{
-					LOG(LogError, (String("kNet::NetException thrown when processing client connection: ") + e.what()).CString());
+					LOG(LogError, (std::string("kNet::NetException thrown when processing client connection: ") + e.what()).c_str());
 					if (connection->GetSocket())
 					if (connection->GetSocket())
 						connection->GetSocket()->Close();
 						connection->GetSocket()->Close();
 				}
 				}
 			}
 			}
 			else // A UDP server received a message.
 			else // A UDP server received a message.
 			{
 			{
-				int socketIndex = index - connectionList.Size() * 2;
-				if (serverList.Size() > 0)
+				int socketIndex = index - connectionList.size() * 2;
+				if (serverList.size() > 0)
 				{
 				{
 					NetworkServer &server = *serverList[0]; ///\bug In case of multiple servers, this is not correct!
 					NetworkServer &server = *serverList[0]; ///\bug In case of multiple servers, this is not correct!
-					Vector<Socket *> &listenSockets = server.ListenSockets();
-					if (socketIndex < (int)listenSockets.Size())
+					std::vector<Socket *> &listenSockets = server.ListenSockets();
+					if (socketIndex < (int)listenSockets.size())
 					{
 					{
 						try
 						try
 						{
 						{
 							server.ReadUDPSocketData(listenSockets[socketIndex]);
 							server.ReadUDPSocketData(listenSockets[socketIndex]);
 						} catch(const NetException &e)
 						} catch(const NetException &e)
 						{
 						{
-							LOG(LogError, (String("kNet::NetException thrown when reading server socket: ") + e.what()).CString());
+							LOG(LogError, (std::string("kNet::NetException thrown when reading server socket: ") + e.what()).c_str());
 							///\todo Could Close(0) the connection here.
 							///\todo Could Close(0) the connection here.
 						}
 						}
 					}
 					}
 					else
 					else
 					{
 					{
 						LOG(LogError, "NetworkWorkerThread::MainLoop: Warning: Cannot find server socket to read from: EventArray::Wait returned index %d (socketIndex %d), but "
 						LOG(LogError, "NetworkWorkerThread::MainLoop: Warning: Cannot find server socket to read from: EventArray::Wait returned index %d (socketIndex %d), but "
-							"serverList.Size()=%d, connectionList.Size()=%d!", index, socketIndex, (int)serverList.Size(), (int)connectionList.Size());
+							"serverList.size()=%d, connectionList.size()=%d!", index, socketIndex, (int)serverList.size(), (int)connectionList.size());
 					}
 					}
 				}
 				}
 				else
 				else
 				{
 				{
 					LOG(LogError, "NetworkWorkerThread::MainLoop: Warning: EventArray::Wait returned index %d (socketIndex %d), but "
 					LOG(LogError, "NetworkWorkerThread::MainLoop: Warning: EventArray::Wait returned index %d (socketIndex %d), but "
-						"serverList.Size()=%d, connectionList.Size()=%d!", index, socketIndex, (int)serverList.Size(), (int)connectionList.Size());
+						"serverList.size()=%d, connectionList.size()=%d!", index, socketIndex, (int)serverList.size(), (int)connectionList.size());
 				}
 				}
 			}
 			}
 		}
 		}
@@ -340,14 +338,14 @@ void NetworkWorkerThread::MainLoop()
 		// The UDP send throttle timers are not read through events. The writeWaitConnections list
 		// The UDP send throttle timers are not read through events. The writeWaitConnections list
 		// contains a list of UDP connections which are now, or will very soon (in less than 1msec) be ready for writing. 
 		// contains a list of UDP connections which are now, or will very soon (in less than 1msec) be ready for writing. 
 		// Poll each and try to send a message.
 		// Poll each and try to send a message.
-		for(size_t i = 0; i < writeWaitConnections.Size(); ++i)
+		for(size_t i = 0; i < writeWaitConnections.size(); ++i)
 		{
 		{
 			try
 			try
 			{
 			{
 				writeWaitConnections[i]->SendOutPackets();
 				writeWaitConnections[i]->SendOutPackets();
 			} catch(const NetException &e)
 			} catch(const NetException &e)
 			{
 			{
-				LOG(LogError, (String("kNet::NetException thrown when sending out a network message: ") + e.what()).CString());
+				LOG(LogError, (std::string("kNet::NetException thrown when sending out a network message: ") + e.what()).c_str());
 			}
 			}
 		}
 		}
 	}
 	}

+ 109 - 110
ThirdParty/kNet/src/SerializationStructCompiler.cpp

@@ -15,9 +15,8 @@
 /** @file SerializationStructCompiler.cpp
 /** @file SerializationStructCompiler.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include <fstream>
 #include <fstream>
+#include <sstream>
 #include <cassert>
 #include <cassert>
 #include <cstring>
 #include <cstring>
 
 
@@ -31,15 +30,15 @@ using namespace std;
 namespace kNet
 namespace kNet
 {
 {
 
 
-String SerializationStructCompiler::ParseToValidCSymbolName(const char *str)
+std::string SerializationStructCompiler::ParseToValidCSymbolName(const char *str)
 {
 {
-	String outStr;
+	stringstream ss;
 	size_t len = strlen(str);
 	size_t len = strlen(str);
 	for(size_t i = 0; i < len; ++i)
 	for(size_t i = 0; i < len; ++i)
-		if ((isalpha(str[i]) || (outStr.Length() > 0 && isdigit(str[i]))) && str[i] != ' ')
-			outStr += str[i];
+		if ((isalpha(str[i]) || (ss.str().length() > 0 && isdigit(str[i]))) && str[i] != ' ')
+			ss << str[i];
 
 
-	return outStr;
+	return ss.str();
 }
 }
 
 
 void SerializationStructCompiler::WriteFilePreamble(std::ofstream &out)
 void SerializationStructCompiler::WriteFilePreamble(std::ofstream &out)
@@ -54,12 +53,12 @@ void SerializationStructCompiler::WriteFilePreamble(std::ofstream &out)
 
 
 void SerializationStructCompiler::WriteMemberDefinition(const SerializedElementDesc &elem, int level, std::ofstream &out)
 void SerializationStructCompiler::WriteMemberDefinition(const SerializedElementDesc &elem, int level, std::ofstream &out)
 {
 {
-	String type;
+	string type;
 
 
 	if (elem.type == SerialInvalid)
 	if (elem.type == SerialInvalid)
 		throw kNet::NetException("Invalid element type for SerializationStructCompiler::WriteMemberDefinition!");
 		throw kNet::NetException("Invalid element type for SerializationStructCompiler::WriteMemberDefinition!");
 
 
-	String name = ParseToValidCSymbolName(elem.name.CString());
+	string name = ParseToValidCSymbolName(elem.name.c_str());
 
 
 	if (elem.type == SerialStruct || elem.type == SerialOther)
 	if (elem.type == SerialStruct || elem.type == SerialOther)
 		type = elem.typeString;
 		type = elem.typeString;
@@ -67,14 +66,14 @@ void SerializationStructCompiler::WriteMemberDefinition(const SerializedElementD
 		type = SerialTypeToCTypeString(elem.type);
 		type = SerialTypeToCTypeString(elem.type);
 
 
 	if (type == "string")
 	if (type == "string")
-		type = "String";
+		type = "std::string"; // Make a hardcoded fix for std::string so that the user doesn't have to specify 'std::string' into the XML, which would be clumsy.
 
 
 	if (elem.varyingCount == true)
 	if (elem.varyingCount == true)
-		out << Indent(level).CString() << "Vector<" << type.CString() << "> " << name.CString() << ";" << endl;
+		out << Indent(level) << "std::vector<" << type << "> " << name << ";" << endl;
 	else if (elem.count > 1)
 	else if (elem.count > 1)
-		out << Indent(level).CString() << type.CString() << " " << name.CString() << "[" << elem.count << "];" << endl;
+		out << Indent(level) << type << " " << name << "[" << elem.count << "];" << endl;
 	else
 	else
-		out << Indent(level).CString() << type.CString() << " " << name.CString() << ";" << endl;
+		out << Indent(level) << type << " " << name << ";" << endl;
 }
 }
 
 
 void SerializationStructCompiler::WriteStructMembers(const SerializedElementDesc &elem, int level, std::ofstream &out)
 void SerializationStructCompiler::WriteStructMembers(const SerializedElementDesc &elem, int level, std::ofstream &out)
@@ -83,7 +82,7 @@ void SerializationStructCompiler::WriteStructMembers(const SerializedElementDesc
 
 
 	int childStructIndex = 1;
 	int childStructIndex = 1;
 
 
-	for(size_t i = 0; i < elem.elements.Size(); ++i)
+	for(size_t i = 0; i < elem.elements.size(); ++i)
 	{
 	{
 		SerializedElementDesc &e = *elem.elements[i];
 		SerializedElementDesc &e = *elem.elements[i];
 		assert(&e);
 		assert(&e);
@@ -97,7 +96,7 @@ void SerializationStructCompiler::WriteNestedStructs(const SerializedElementDesc
 {
 {
 	assert(&elem && elem.type == SerialStruct);
 	assert(&elem && elem.type == SerialStruct);
 
 
-	for(size_t i = 0; i < elem.elements.Size(); ++i)
+	for(size_t i = 0; i < elem.elements.size(); ++i)
 	{
 	{
 		SerializedElementDesc &e = *elem.elements[i];
 		SerializedElementDesc &e = *elem.elements[i];
 		assert(&e);
 		assert(&e);
@@ -112,11 +111,11 @@ void SerializationStructCompiler::WriteStructSizeMemberFunction(const Serialized
 {
 {
 	assert(&elem && elem.type == SerialStruct);
 	assert(&elem && elem.type == SerialStruct);
 
 
-	out << Indent(level).CString() << "inline size_t Size() const" << endl
-		<< Indent(level).CString() << "{" << endl
-		<< Indent(level+1).CString() << "return ";
+	out << Indent(level) << "inline size_t Size() const" << endl
+		<< Indent(level) << "{" << endl
+		<< Indent(level+1) << "return ";
 
 
-	for(size_t i = 0; i < elem.elements.Size(); ++i)
+	for(size_t i = 0; i < elem.elements.size(); ++i)
 	{
 	{
 		SerializedElementDesc &e = *elem.elements[i];
 		SerializedElementDesc &e = *elem.elements[i];
 		assert(&e);
 		assert(&e);
@@ -124,7 +123,7 @@ void SerializationStructCompiler::WriteStructSizeMemberFunction(const Serialized
 		if (i > 0)
 		if (i > 0)
 			out << " + ";
 			out << " + ";
 
 
-		String memberName = ParseToValidCSymbolName(e.name.CString());
+		string memberName = ParseToValidCSymbolName(e.name.c_str());
 
 
 		if (e.varyingCount)
 		if (e.varyingCount)
 		{
 		{
@@ -138,26 +137,26 @@ void SerializationStructCompiler::WriteStructSizeMemberFunction(const Serialized
 		if (e.type == SerialStruct)
 		if (e.type == SerialStruct)
 		{
 		{
 			if (e.varyingCount)
 			if (e.varyingCount)
-				out << "kNet::SumArray(" << memberName.CString() << ", " << memberName.CString() << ".size())";
+				out << "kNet::SumArray(" << memberName << ", " << memberName << ".size())";
 			else if (e.count > 1)
 			else if (e.count > 1)
-				out << "kNet::SumArray(" << memberName.CString() << ", " << e.count << ")";
+				out << "kNet::SumArray(" << memberName << ", " << e.count << ")";
 			else
 			else
-				out << memberName.CString() << ".Size()";
+				out << memberName << ".Size()";
 		}
 		}
 		else*/ if (e.type == SerialStruct || e.type == SerialOther || e.type == SerialString)
 		else*/ if (e.type == SerialStruct || e.type == SerialOther || e.type == SerialString)
 		{
 		{
-			String typeSerializer = "kNet::TypeSerializer<" + e.typeString + ">";
+			std::string typeSerializer = "kNet::TypeSerializer<" + e.typeString + ">";
 			if (e.varyingCount)
 			if (e.varyingCount)
-				out << "kNet::ArraySize<" << typeSerializer.CString() << " >(" << memberName.CString() << ", " << memberName.CString() << ".Size())";
+				out << "kNet::ArraySize<" << typeSerializer << " >(" << memberName << ", " << memberName << ".size())";
 			else if (e.count > 1)
 			else if (e.count > 1)
-				out << "kNet::ArraySize(" << typeSerializer.CString() << " >(" << memberName.CString() << ", " << e.count << ")";
+				out << "kNet::ArraySize(" << typeSerializer << " >(" << memberName << ", " << e.count << ")";
 			else
 			else
-				out << typeSerializer.CString() << "::Size(" << memberName.CString() << ")";
+				out << typeSerializer << "::Size(" << memberName << ")";
 		}
 		}
 		else
 		else
 		{
 		{
 			if (e.varyingCount)
 			if (e.varyingCount)
-				out << memberName.CString() << ".Size()" << "*" << SerialTypeSize(e.type);
+				out << memberName << ".size()" << "*" << SerialTypeSize(e.type);
 			else if (e.count > 1)
 			else if (e.count > 1)
 				out << e.count << "*" << SerialTypeSize(e.type);
 				out << e.count << "*" << SerialTypeSize(e.type);
 			else
 			else
@@ -165,36 +164,36 @@ void SerializationStructCompiler::WriteStructSizeMemberFunction(const Serialized
 		}
 		}
 	}
 	}
 
 
-	if (elem.elements.Size() == 0)
+	if (elem.elements.size() == 0)
 		out << "0";
 		out << "0";
 
 
 	out << ";" << endl
 	out << ";" << endl
-		<< Indent(level).CString() << "}" << endl << endl;
+		<< Indent(level) << "}" << endl << endl;
 }
 }
 
 
-void SerializationStructCompiler::WriteSerializeMemberFunction(/*const String &className, */const SerializedElementDesc &elem, int level, std::ofstream &out)
+void SerializationStructCompiler::WriteSerializeMemberFunction(/*const std::string &className, */const SerializedElementDesc &elem, int level, std::ofstream &out)
 {
 {
 	assert(&elem && elem.type == SerialStruct);
 	assert(&elem && elem.type == SerialStruct);
 
 
-	out << Indent(level).CString() << "inline void SerializeTo(kNet::DataSerializer &dst) const" << endl
-		<< Indent(level).CString() << "{" << endl;
+	out << Indent(level) << "inline void SerializeTo(kNet::DataSerializer &dst) const" << endl
+		<< Indent(level) << "{" << endl;
 
 
 	++level;
 	++level;
 
 
-	for(size_t i = 0; i < elem.elements.Size(); ++i)
+	for(size_t i = 0; i < elem.elements.size(); ++i)
 	{
 	{
 		SerializedElementDesc &e = *elem.elements[i];
 		SerializedElementDesc &e = *elem.elements[i];
 		assert(&e);
 		assert(&e);
 
 
-		String memberName = ParseToValidCSymbolName(e.name.CString());
+		string memberName = ParseToValidCSymbolName(e.name.c_str());
 
 
 		if (e.varyingCount == true)
 		if (e.varyingCount == true)
 		{
 		{
 			// What type of variable will hold the varyingCount field?
 			// What type of variable will hold the varyingCount field?
 			if (e.count != 8 && e.count != 16 && e.count != 32) ///\todo Support arbitrary bit-length varyingCounts.
 			if (e.count != 8 && e.count != 16 && e.count != 32) ///\todo Support arbitrary bit-length varyingCounts.
-				out << Indent(level).CString() << "// TODO: Unsupported varyingCount field length of " << e.count << " bits used!" << endl;
+				out << Indent(level) << "// TODO: Unsupported varyingCount field length of " << e.count << " bits used!" << endl;
 
 
-			out << Indent(level).CString() << "dst.Add<u" << e.count << ">(" << memberName.CString() << ".Size());" << endl;
+			out << Indent(level) << "dst.Add<u" << e.count << ">(" << memberName << ".size());" << endl;
 		}
 		}
 /*
 /*
 		if (e.type == SerialStruct)
 		if (e.type == SerialStruct)
@@ -214,118 +213,118 @@ void SerializationStructCompiler::WriteSerializeMemberFunction(/*const String &c
 		}
 		}
 		else*/ if (e.type == SerialStruct || e.type == SerialOther)
 		else*/ if (e.type == SerialStruct || e.type == SerialOther)
 		{
 		{
-			String typeSerializer = "kNet::TypeSerializer<" + e.typeString + ">";
+			std::string typeSerializer = "kNet::TypeSerializer<" + e.typeString + ">";
 
 
 			if (e.varyingCount == true)
 			if (e.varyingCount == true)
 			{
 			{
-				out << Indent(level).CString() << "for(size_t i = 0; i < " << memberName.CString() << ".Size(); ++i)" << endl;
-				out << Indent(level+1).CString() << typeSerializer.CString() << "::SerializeTo(dst, " << memberName.CString() << "[i]);" << endl;
+				out << Indent(level) << "for(size_t i = 0; i < " << memberName << ".size(); ++i)" << endl;
+				out << Indent(level+1) << typeSerializer << "::SerializeTo(dst, " << memberName << "[i]);" << endl;
 			}
 			}
 			else if (e.count > 1)
 			else if (e.count > 1)
 			{
 			{
-				out << Indent(level).CString() << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
-				out << Indent(level+1).CString() << typeSerializer.CString() << "::SerializeTo(dst, " << memberName.CString() << "[i]);" << endl;
+				out << Indent(level) << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
+				out << Indent(level+1) << typeSerializer << "::SerializeTo(dst, " << memberName << "[i]);" << endl;
 			}
 			}
 			else
 			else
-				out << Indent(level).CString() << typeSerializer.CString() << "::SerializeTo(dst, " << memberName.CString() << ");" << endl;
+				out << Indent(level) << typeSerializer << "::SerializeTo(dst, " << memberName << ");" << endl;
 		}
 		}
 		else
 		else
 		{
 		{
 			if (e.varyingCount == true)
 			if (e.varyingCount == true)
 			{
 			{
-				out << Indent(level).CString() << "if (" << memberName.CString() << ".size() > 0)" << endl;
-				out << Indent(level+1).CString() << "dst.AddArray<" << SerialTypeToCTypeString(e.type) << ">(&" << memberName.CString()
-					<< "[0], " << memberName.CString() << ".size());" << endl;
+				out << Indent(level) << "if (" << memberName << ".size() > 0)" << endl;
+				out << Indent(level+1) << "dst.AddArray<" << SerialTypeToCTypeString(e.type) << ">(&" << memberName
+					<< "[0], " << memberName << ".size());" << endl;
 			}
 			}
 			else if (e.count > 1)
 			else if (e.count > 1)
-				out << Indent(level).CString() << "dst.AddArray<" << SerialTypeToCTypeString(e.type) << ">(" << memberName.CString()
+				out << Indent(level) << "dst.AddArray<" << SerialTypeToCTypeString(e.type) << ">(" << memberName
 					<< ", " << e.count << ");" << endl;
 					<< ", " << e.count << ");" << endl;
 			else 
 			else 
-				out << Indent(level).CString() << "dst.Add<" << SerialTypeToCTypeString(e.type) << ">(" << memberName.CString()
+				out << Indent(level) << "dst.Add<" << SerialTypeToCTypeString(e.type) << ">(" << memberName
 					<< ");" << endl;
 					<< ");" << endl;
 		}
 		}
 	}
 	}
 	--level;
 	--level;
-	out << Indent(level).CString() << "}" << endl;
-//	out << Indent(level).CString() << "inline static void SerializeTo(knet::DataSerializer &dst, const " << className.CString() << " &src) { src.SerializeTo(dst); }"<< endl;
+	out << Indent(level) << "}" << endl;
+//	out << Indent(level) << "inline static void SerializeTo(knet::DataSerializer &dst, const " << className << " &src) { src.SerializeTo(dst); }"<< endl;
 	out << endl;
 	out << endl;
 }
 }
 
 
-void SerializationStructCompiler::WriteDeserializeMemberFunction(/*const String &className, */const SerializedElementDesc &elem, int level, std::ofstream &out)
+void SerializationStructCompiler::WriteDeserializeMemberFunction(/*const std::string &className, */const SerializedElementDesc &elem, int level, std::ofstream &out)
 {
 {
 	assert(&elem && elem.type == SerialStruct);
 	assert(&elem && elem.type == SerialStruct);
 
 
-	out << Indent(level).CString() << "inline void DeserializeFrom(kNet::DataDeserializer &src)" << endl
-		<< Indent(level).CString() << "{" << endl;
+	out << Indent(level) << "inline void DeserializeFrom(kNet::DataDeserializer &src)" << endl
+		<< Indent(level) << "{" << endl;
 
 
 	++level;
 	++level;
 
 
-	for(size_t i = 0; i < elem.elements.Size(); ++i)
+	for(size_t i = 0; i < elem.elements.size(); ++i)
 	{
 	{
 		SerializedElementDesc &e = *elem.elements[i];
 		SerializedElementDesc &e = *elem.elements[i];
 		assert(&e);
 		assert(&e);
 
 
-		String memberName = ParseToValidCSymbolName(e.name.CString());
+		string memberName = ParseToValidCSymbolName(e.name.c_str());
 
 
 		if (e.varyingCount == true)
 		if (e.varyingCount == true)
 		{
 		{
 			// What type of variable will hold the varyingCount field?
 			// What type of variable will hold the varyingCount field?
 			if (e.count != 8 && e.count != 16 && e.count != 32) ///\todo Support arbitrary bit-length varyingCounts.
 			if (e.count != 8 && e.count != 16 && e.count != 32) ///\todo Support arbitrary bit-length varyingCounts.
-				out << Indent(level).CString() << "// TODO: Unsupported varyingCount field length of " << e.count << " bits used!" << endl;
+				out << Indent(level) << "// TODO: Unsupported varyingCount field length of " << e.count << " bits used!" << endl;
 
 
-			out << Indent(level).CString() << memberName.CString() << ".Resize(src.Read<u" << e.count << ">());" << endl;
+			out << Indent(level) << memberName << ".resize(src.Read<u" << e.count << ">());" << endl;
 		}
 		}
 
 
 /*		if (e.type == SerialStruct)
 /*		if (e.type == SerialStruct)
 		{
 		{
 			if (e.varyingCount == true)
 			if (e.varyingCount == true)
 			{
 			{
-				out << Indent(level).CString() << "for(size_t i = 0; i < " << memberName << ".Size(); ++i)" << endl;
-				out << Indent(level+1).CString() << memberName.CString() << "[i].DeserializeFrom(src);" << endl;
+				out << Indent(level) << "for(size_t i = 0; i < " << memberName << ".size(); ++i)" << endl;
+				out << Indent(level+1) << memberName << "[i].DeserializeFrom(src);" << endl;
 			}
 			}
 			else if (e.count > 1)
 			else if (e.count > 1)
 			{
 			{
-				out << Indent(level).CString() << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
-				out << Indent(level+1).CString() << memberName.CString() << "[i].DeserializeFrom(src);" << endl;
+				out << Indent(level) << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
+				out << Indent(level+1) << memberName << "[i].DeserializeFrom(src);" << endl;
 			}
 			}
 			else
 			else
-				out << Indent(level).CString() << memberName.CString() << ".DeserializeFrom(src);" << endl;
+				out << Indent(level) << memberName << ".DeserializeFrom(src);" << endl;
 		} */
 		} */
 		if (e.type == SerialStruct || e.type == SerialOther)
 		if (e.type == SerialStruct || e.type == SerialOther)
 		{
 		{
-			String typeSerializer = "kNet::TypeSerializer<" + e.typeString + ">";
+			std::string typeSerializer = "kNet::TypeSerializer<" + e.typeString + ">";
 
 
 			if (e.varyingCount == true)
 			if (e.varyingCount == true)
 			{
 			{
-				out << Indent(level).CString() << "for(size_t i = 0; i < " << memberName.CString() << ".Size(); ++i)" << endl;
-				out << Indent(level+1).CString() << typeSerializer.CString() << "::DeserializeFrom(src, " << memberName.CString() << "[i]);" << endl;
+				out << Indent(level) << "for(size_t i = 0; i < " << memberName << ".size(); ++i)" << endl;
+				out << Indent(level+1) << typeSerializer << "::DeserializeFrom(src, " << memberName << "[i]);" << endl;
 			}
 			}
 			else if (e.count > 1)
 			else if (e.count > 1)
 			{
 			{
-				out << Indent(level).CString() << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
-				out << Indent(level+1).CString() << typeSerializer.CString() << "::DeserializeFrom(src, " << memberName.CString() << "[i]);" << endl;
+				out << Indent(level) << "for(size_t i = 0; i < " << e.count << "; ++i)" << endl;
+				out << Indent(level+1) << typeSerializer << "::DeserializeFrom(src, " << memberName << "[i]);" << endl;
 			}
 			}
 			else
 			else
-				out << Indent(level).CString() << typeSerializer.CString() << "::DeserializeFrom(src, " << memberName.CString() << ");" << endl;
+				out << Indent(level) << typeSerializer << "::DeserializeFrom(src, " << memberName << ");" << endl;
 		}
 		}
 		else 
 		else 
 		{
 		{
 			if (e.varyingCount == true)
 			if (e.varyingCount == true)
 			{
 			{
-				out << Indent(level).CString() << "if (" << memberName.CString() << ".Size() > 0)" << endl;
-				out << Indent(level+1).CString() << "src.ReadArray<" << SerialTypeToCTypeString(e.type) << ">(&" << memberName.CString()
-					<< "[0], " << memberName.CString() << ".size());" << endl;
+				out << Indent(level) << "if (" << memberName << ".size() > 0)" << endl;
+				out << Indent(level+1) << "src.ReadArray<" << SerialTypeToCTypeString(e.type) << ">(&" << memberName
+					<< "[0], " << memberName << ".size());" << endl;
 			}
 			}
 			else if (e.count > 1)
 			else if (e.count > 1)
-				out << Indent(level).CString() << "src.ReadArray<" << SerialTypeToCTypeString(e.type) << ">(" << memberName.CString()
+				out << Indent(level) << "src.ReadArray<" << SerialTypeToCTypeString(e.type) << ">(" << memberName
 					<< ", " << e.count << ");" << endl;
 					<< ", " << e.count << ");" << endl;
 			else 
 			else 
-				out << Indent(level).CString() << memberName.CString() << " = src.Read<" << SerialTypeToCTypeString(e.type) << ">();" << endl;
+				out << Indent(level) << memberName << " = src.Read<" << SerialTypeToCTypeString(e.type) << ">();" << endl;
 		}
 		}
 	}
 	}
 	--level;
 	--level;
-	out << Indent(level).CString() << "}" << endl;
-//	out << Indent(level).CString() << "inline static void DeserializeFrom(knet::DataDeserializer &src, " << className.CString() << " &dst) { dst.DeserializeFrom(src); }"<< endl;
+	out << Indent(level) << "}" << endl;
+//	out << Indent(level) << "inline static void DeserializeFrom(knet::DataDeserializer &src, " << className << " &dst) { dst.DeserializeFrom(src); }"<< endl;
 	out << endl;
 	out << endl;
 }
 }
 
 
@@ -333,19 +332,19 @@ void SerializationStructCompiler::WriteStruct(const SerializedElementDesc &elem,
 {
 {
 	assert(&elem && elem.type == SerialStruct);
 	assert(&elem && elem.type == SerialStruct);
 
 
-	String className = String("struct S_") + ParseToValidCSymbolName(elem.name.CString());
+	string className = string("struct S_") + ParseToValidCSymbolName(elem.name.c_str());
 	if (level == 0)
 	if (level == 0)
-		className = String("struct ") + ParseToValidCSymbolName(elem.name.CString());
+		className = string("struct ") + ParseToValidCSymbolName(elem.name.c_str());
 
 
-	out << Indent(level).CString() << className.CString() << endl
-	    << Indent(level).CString() << "{" << endl;
+	out << Indent(level) << className << endl
+	    << Indent(level) << "{" << endl;
 
 
 	WriteNestedStructs(elem, level+1, out);
 	WriteNestedStructs(elem, level+1, out);
 	WriteStructMembers(elem, level+1, out);
 	WriteStructMembers(elem, level+1, out);
 	WriteStructSizeMemberFunction(elem, level+1, out);
 	WriteStructSizeMemberFunction(elem, level+1, out);
 	WriteSerializeMemberFunction(/*className, */elem, level+1, out);
 	WriteSerializeMemberFunction(/*className, */elem, level+1, out);
 	WriteDeserializeMemberFunction(/*className, */elem, level+1, out);
 	WriteDeserializeMemberFunction(/*className, */elem, level+1, out);
-	out << Indent(level).CString() << "};" << endl << endl;
+	out << Indent(level) << "};" << endl << endl;
 }
 }
 
 
 void SerializationStructCompiler::CompileStruct(const SerializedElementDesc &structure, const char *outfile)
 void SerializationStructCompiler::CompileStruct(const SerializedElementDesc &structure, const char *outfile)
@@ -358,39 +357,39 @@ void SerializationStructCompiler::CompileStruct(const SerializedElementDesc &str
 
 
 void SerializationStructCompiler::WriteMessage(const SerializedMessageDesc &message, std::ofstream &out)
 void SerializationStructCompiler::WriteMessage(const SerializedMessageDesc &message, std::ofstream &out)
 {
 {
-	String structName = "Msg" + message.name;
-	out << "struct " << structName.CString() << endl
+	string structName = string("Msg") + message.name;
+	out << "struct " << structName << endl
 		<< "{" << endl;
 		<< "{" << endl;
 
 
-	out << Indent(1).CString() << structName.CString() << "()" << endl 
-		<< Indent(1).CString() << "{" << endl
-		<< Indent(2).CString() << "InitToDefault();" << endl
-		<< Indent(1).CString() << "}" << endl << endl;
+	out << Indent(1) << structName << "()" << endl 
+		<< Indent(1) << "{" << endl
+		<< Indent(2) << "InitToDefault();" << endl
+		<< Indent(1) << "}" << endl << endl;
 
 
-	out << Indent(1).CString() << structName.CString() << "(const char *data, size_t numBytes)" << endl 
-		<< Indent(1).CString() << "{" << endl
-		<< Indent(2).CString() << "InitToDefault();" << endl
-		<< Indent(2).CString() << "kNet::DataDeserializer dd(data, numBytes);" << endl
-		<< Indent(2).CString() << "DeserializeFrom(dd);" << endl
-		<< Indent(1).CString() << "}" << endl << endl;
+	out << Indent(1) << structName << "(const char *data, size_t numBytes)" << endl 
+		<< Indent(1) << "{" << endl
+		<< Indent(2) << "InitToDefault();" << endl
+		<< Indent(2) << "kNet::DataDeserializer dd(data, numBytes);" << endl
+		<< Indent(2) << "DeserializeFrom(dd);" << endl
+		<< Indent(1) << "}" << endl << endl;
 
 
-	out << Indent(1).CString() << "void InitToDefault()" << endl
-		<< Indent(1).CString() << "{" << endl
-		<< Indent(2).CString() << "reliable = defaultReliable;" << endl
-		<< Indent(2).CString() << "inOrder = defaultInOrder;" << endl
-		<< Indent(2).CString() << "priority = defaultPriority;" << endl
-		<< Indent(1).CString() << "}" << endl << endl;
+	out << Indent(1) << "void InitToDefault()" << endl
+		<< Indent(1) << "{" << endl
+		<< Indent(2) << "reliable = defaultReliable;" << endl
+		<< Indent(2) << "inOrder = defaultInOrder;" << endl
+		<< Indent(2) << "priority = defaultPriority;" << endl
+		<< Indent(1) << "}" << endl << endl;
 
 
-	out << Indent(1).CString() << "enum { messageID = "<< message.id << " };" << endl;
-	out << Indent(1).CString() << "static inline const char * const Name() { return \"" << message.name.CString() << "\"; }" << endl << endl;
+	out << Indent(1) << "enum { messageID = "<< message.id << " };" << endl;
+	out << Indent(1) << "static inline const char * const Name() { return \"" << message.name << "\"; }" << endl << endl;
 
 
-	out << Indent(1).CString() << "static const bool defaultReliable = " << (message.reliable ? "true" : "false") << ";" << endl;
-	out << Indent(1).CString() << "static const bool defaultInOrder = " << (message.inOrder ? "true" : "false") << ";" << endl;
-	out << Indent(1).CString() << "static const u32 defaultPriority = " << message.priority << ";" << endl << endl;
+	out << Indent(1) << "static const bool defaultReliable = " << (message.reliable ? "true" : "false") << ";" << endl;
+	out << Indent(1) << "static const bool defaultInOrder = " << (message.inOrder ? "true" : "false") << ";" << endl;
+	out << Indent(1) << "static const u32 defaultPriority = " << message.priority << ";" << endl << endl;
 
 
-	out << Indent(1).CString() << "bool reliable;" << endl;
-	out << Indent(1).CString() << "bool inOrder;" << endl;
-	out << Indent(1).CString() << "u32 priority;" << endl << endl;
+	out << Indent(1) << "bool reliable;" << endl;
+	out << Indent(1) << "bool inOrder;" << endl;
+	out << Indent(1) << "u32 priority;" << endl << endl;
 
 
 	WriteNestedStructs(*message.data, 1, out);
 	WriteNestedStructs(*message.data, 1, out);
 	WriteStructMembers(*message.data, 1, out);
 	WriteStructMembers(*message.data, 1, out);
@@ -410,12 +409,12 @@ void SerializationStructCompiler::CompileMessage(const SerializedMessageDesc &me
 	WriteMessage(message, out);
 	WriteMessage(message, out);
 }
 }
 
 
-String SerializationStructCompiler::Indent(int level)
+std::string SerializationStructCompiler::Indent(int level)
 {
 {
-	String str;
+	stringstream ss;
 	for(int i = 0; i < level; ++i)
 	for(int i = 0; i < level; ++i)
-		str += "\t";
-	return str;
+		ss << "\t";
+	return ss.str();
 }
 }
 
 
 } // ~kNet
 } // ~kNet

+ 20 - 22
ThirdParty/kNet/src/SerializedDataIterator.cpp

@@ -15,8 +15,6 @@
 /** @file SerializedDataIterator.cpp
 /** @file SerializedDataIterator.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include <cassert>
 #include <cassert>
 
 
 #include "kNet/DebugMemoryLeakCheck.h"
 #include "kNet/DebugMemoryLeakCheck.h"
@@ -28,41 +26,41 @@ namespace kNet
 
 
 BasicSerializedDataType SerializedDataIterator::NextElementType() const
 BasicSerializedDataType SerializedDataIterator::NextElementType() const
 {
 {
-	if (currentElementStack.Size() == 0)
+	if (currentElementStack.size() == 0)
 		return SerialInvalid;
 		return SerialInvalid;
 
 
-	assert(currentElementStack.Back().elem);
+	assert(currentElementStack.back().elem);
 
 
 	// If we don't know how many instances there are of the next element, it's the next field 
 	// If we don't know how many instances there are of the next element, it's the next field 
 	// to be filled - our iterator is pointing to the dynamicCount property of that field.
 	// to be filled - our iterator is pointing to the dynamicCount property of that field.
-	if (currentElementStack.Back().elem->varyingCount && currentElementStack.Back().dynamicCountSpecified == false)
+	if (currentElementStack.back().elem->varyingCount && currentElementStack.back().dynamicCountSpecified == false)
 		return SerialDynamicCount;
 		return SerialDynamicCount;
 
 
-	return currentElementStack.Back().elem->type;
+	return currentElementStack.back().elem->type;
 }
 }
 
 
 const SerializedElementDesc *SerializedDataIterator::NextElementDesc() const
 const SerializedElementDesc *SerializedDataIterator::NextElementDesc() const
 {
 {
-	return currentElementStack.Size() > 0 ? currentElementStack.Back().elem : 0;
+	return currentElementStack.size() > 0 ? currentElementStack.back().elem : 0;
 }
 }
 
 
 void SerializedDataIterator::ProceedToNextVariable()
 void SerializedDataIterator::ProceedToNextVariable()
 {
 {
-	if (currentElementStack.Size() == 0)
+	if (currentElementStack.size() == 0)
 		return;
 		return;
 
 
-	ElemInfo &nextVar = currentElementStack.Back();
+	ElemInfo &nextVar = currentElementStack.back();
 
 
 	if (nextVar.elem->type == SerialStruct)
 	if (nextVar.elem->type == SerialStruct)
 	{
 	{
 		++nextVar.nextElem;
 		++nextVar.nextElem;
-		if (nextVar.nextElem >= (int)nextVar.elem->elements.Size())
+		if (nextVar.nextElem >= (int)nextVar.elem->elements.size())
 		{
 		{
 			nextVar.nextElem = 0;
 			nextVar.nextElem = 0;
 			++nextVar.nextIndex;
 			++nextVar.nextIndex;
 			if (nextVar.nextIndex >= nextVar.count)
 			if (nextVar.nextIndex >= nextVar.count)
 			{
 			{
-				currentElementStack.Pop();
+				currentElementStack.pop_back();
 				ProceedToNextVariable();
 				ProceedToNextVariable();
 				return;
 				return;
 			}
 			}
@@ -75,7 +73,7 @@ void SerializedDataIterator::ProceedToNextVariable()
 		++nextVar.nextIndex;
 		++nextVar.nextIndex;
 		if (nextVar.nextIndex >= nextVar.count)
 		if (nextVar.nextIndex >= nextVar.count)
 		{
 		{
-			currentElementStack.Pop();
+			currentElementStack.pop_back();
 			ProceedToNextVariable();
 			ProceedToNextVariable();
 		}
 		}
 	}
 	}
@@ -90,22 +88,22 @@ void SerializedDataIterator::ProceedNVariables(int count)
 
 
 void SerializedDataIterator::ProceedToNextElement()
 void SerializedDataIterator::ProceedToNextElement()
 {
 {
-	ElemInfo &nextVar = currentElementStack.Back();
+	ElemInfo &nextVar = currentElementStack.back();
 
 
 	++nextVar.nextElem;
 	++nextVar.nextElem;
-	if (nextVar.nextElem >= (int)nextVar.elem->elements.Size())
+	if (nextVar.nextElem >= (int)nextVar.elem->elements.size())
 	{
 	{
 		nextVar.nextElem = 0;
 		nextVar.nextElem = 0;
 		++nextVar.nextIndex;
 		++nextVar.nextIndex;
 		if (nextVar.nextIndex >= nextVar.count)
 		if (nextVar.nextIndex >= nextVar.count)
 		{
 		{
-			currentElementStack.Pop();
+			currentElementStack.pop_back();
 			ProceedToNextElement();
 			ProceedToNextElement();
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
-/*		currentElementStack.Push(ElemInfo());
+/*		currentElementStack.push_back(ElemInfo());
 		ElemInfo &newVar = currentElementStack.back();
 		ElemInfo &newVar = currentElementStack.back();
 		newVar.elem = nextVar.elem->elements[nextVar.nextElem];
 		newVar.elem = nextVar.elem->elements[nextVar.nextElem];
 		newVar.nextIndex = 0;
 		newVar.nextIndex = 0;
@@ -118,7 +116,7 @@ void SerializedDataIterator::ProceedToNextElement()
 
 
 void SerializedDataIterator::SetVaryingElemSize(u32 count)
 void SerializedDataIterator::SetVaryingElemSize(u32 count)
 {
 {
-	ElemInfo &nextVar = currentElementStack.Back();
+	ElemInfo &nextVar = currentElementStack.back();
 	assert(nextVar.dynamicCountSpecified == false);
 	assert(nextVar.dynamicCountSpecified == false);
 	assert(nextVar.elem->varyingCount == true);
 	assert(nextVar.elem->varyingCount == true);
 	assert(nextVar.nextIndex == 0);
 	assert(nextVar.nextIndex == 0);
@@ -131,11 +129,11 @@ void SerializedDataIterator::SetVaryingElemSize(u32 count)
 
 
 void SerializedDataIterator::DescendIntoStructure()
 void SerializedDataIterator::DescendIntoStructure()
 {
 {
-	ElemInfo &nextVar = currentElementStack.Back();
+	ElemInfo &nextVar = currentElementStack.back();
 
 
 	if (nextVar.dynamicCountSpecified == false && nextVar.elem->varyingCount == true)
 	if (nextVar.dynamicCountSpecified == false && nextVar.elem->varyingCount == true)
 		return;
 		return;
-	if (nextVar.nextElem >= (int)nextVar.elem->elements.Size())
+	if (nextVar.nextElem >= (int)nextVar.elem->elements.size())
 		return;
 		return;
 
 
 	ElemInfo newVar;
 	ElemInfo newVar;
@@ -144,7 +142,7 @@ void SerializedDataIterator::DescendIntoStructure()
 	newVar.nextElem = 0;
 	newVar.nextElem = 0;
  	newVar.count = (newVar.elem->varyingCount ? 0 : newVar.elem->count); // A varying block? Then the user has to supply multiplicity.
  	newVar.count = (newVar.elem->varyingCount ? 0 : newVar.elem->count); // A varying block? Then the user has to supply multiplicity.
 	newVar.dynamicCountSpecified = false;
 	newVar.dynamicCountSpecified = false;
-	currentElementStack.Push(newVar);
+	currentElementStack.push_back(newVar);
 
 
 	// Descend again in case we have a struct-in-struct-in-struct...
 	// Descend again in case we have a struct-in-struct-in-struct...
 	DescendIntoStructure();
 	DescendIntoStructure();
@@ -152,7 +150,7 @@ void SerializedDataIterator::DescendIntoStructure()
 
 
 void SerializedDataIterator::ResetTraversal()
 void SerializedDataIterator::ResetTraversal()
 {
 {
-	currentElementStack.Clear();
+	currentElementStack.clear();
 
 
 	ElemInfo newVar;
 	ElemInfo newVar;
 	newVar.elem = desc.data;
 	newVar.elem = desc.data;
@@ -160,7 +158,7 @@ void SerializedDataIterator::ResetTraversal()
 	newVar.nextElem = 0;
 	newVar.nextElem = 0;
  	newVar.count = (newVar.elem->varyingCount ? 0 : newVar.elem->count); // A varying block? Then the user has to supply multiplicity.
  	newVar.count = (newVar.elem->varyingCount ? 0 : newVar.elem->count); // A varying block? Then the user has to supply multiplicity.
 	newVar.dynamicCountSpecified = false;
 	newVar.dynamicCountSpecified = false;
-	currentElementStack.Push(newVar);
+	currentElementStack.push_back(newVar);
 
 
 	// Descend again in case we have a struct-in-struct-in-struct...
 	// Descend again in case we have a struct-in-struct-in-struct...
 	DescendIntoStructure();
 	DescendIntoStructure();

+ 68 - 49
ThirdParty/kNet/src/Socket.cpp

@@ -15,12 +15,10 @@
 /** @file Socket.cpp
 /** @file Socket.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
+#include <string>
 #include <cassert>
 #include <cassert>
 #include <utility>
 #include <utility>
-
-#include "Str.h"
+#include <sstream>
 
 
 #ifdef KNET_USE_BOOST
 #ifdef KNET_USE_BOOST
 #include <boost/thread/thread.hpp>
 #include <boost/thread/thread.hpp>
@@ -51,7 +49,7 @@ const int numConcurrentSendBuffers = 4;
 namespace kNet
 namespace kNet
 {
 {
 
 
-String SocketTransportLayerToString(SocketTransportLayer transport)
+std::string SocketTransportLayerToString(SocketTransportLayer transport)
 {
 {
 	switch(transport)
 	switch(transport)
 	{
 	{
@@ -59,9 +57,9 @@ String SocketTransportLayerToString(SocketTransportLayer transport)
 	case SocketOverTCP: return "TCP";
 	case SocketOverTCP: return "TCP";
 	default:
 	default:
 		{
 		{
-			String str;
-			str += "Invalid SocketTransportLayer (" + String((int)transport) + ")!";
-			return str;
+			std::stringstream ss;
+			ss << "Invalid SocketTransportLayer (" << (int)transport << ")!";
+			return ss.str();
 		}
 		}
 	}
 	}
 }
 }
@@ -78,7 +76,7 @@ SocketTransportLayer StringToSocketTransportLayer(const char *str)
 }
 }
 
 
 
 
-String SocketTypeToString(SocketType type)
+std::string SocketTypeToString(SocketType type)
 {
 {
 	switch(type)
 	switch(type)
 	{
 	{
@@ -87,9 +85,9 @@ String SocketTypeToString(SocketType type)
 	case ClientSocket: return "Client socket";
 	case ClientSocket: return "Client socket";
 	default:
 	default:
 		{
 		{
-			String str;
-			str += "Invalid SocketType (" + String((int)type) + ")!";
-			return str;
+			std::stringstream ss;
+			ss << "Invalid SocketType (" << (int)type << ")!";
+			return ss.str();
 		}
 		}
 	}
 	}
 }
 }
@@ -182,6 +180,8 @@ OverlappedTransferBuffer *AllocateOverlappedTransferBuffer(int bytes)
 	memset(buffer, 0, sizeof(OverlappedTransferBuffer));
 	memset(buffer, 0, sizeof(OverlappedTransferBuffer));
 	buffer->buffer.buf = new char[bytes];
 	buffer->buffer.buf = new char[bytes];
 	buffer->buffer.len = bytes;
 	buffer->buffer.len = bytes;
+	buffer->bytesContains = 0;
+    buffer->bytesAllocated = bytes;
 #ifdef WIN32
 #ifdef WIN32
 	buffer->overlapped.hEvent = WSACreateEvent();
 	buffer->overlapped.hEvent = WSACreateEvent();
 	if (buffer->overlapped.hEvent == WSA_INVALID_EVENT)
 	if (buffer->overlapped.hEvent == WSA_INVALID_EVENT)
@@ -214,14 +214,14 @@ void Socket::SetSendBufferSize(int bytes)
 {
 {
 	socklen_t len = sizeof(bytes);
 	socklen_t len = sizeof(bytes);
 	if (setsockopt(connectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bytes, len))
 	if (setsockopt(connectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bytes, len))
-		LOG(LogError, "Socket::SetSendBufferSize: setsockopt failed with error %s!", Network::GetLastErrorString().CString());
+		LOG(LogError, "Socket::SetSendBufferSize: setsockopt failed with error %s!", Network::GetLastErrorString().c_str());
 }
 }
 
 
 void Socket::SetReceiveBufferSize(int bytes)
 void Socket::SetReceiveBufferSize(int bytes)
 {
 {
 	socklen_t len = sizeof(bytes);
 	socklen_t len = sizeof(bytes);
 	if (setsockopt(connectSocket, SOL_SOCKET, SO_RCVBUF, (char*)&bytes, len))
 	if (setsockopt(connectSocket, SOL_SOCKET, SO_RCVBUF, (char*)&bytes, len))
-		LOG(LogError, "Socket::SetReceiveBufferSize: setsockopt failed with error %s!", Network::GetLastErrorString().CString());
+		LOG(LogError, "Socket::SetReceiveBufferSize: setsockopt failed with error %s!", Network::GetLastErrorString().c_str());
 }
 }
 
 
 int Socket::SendBufferSize() const
 int Socket::SendBufferSize() const
@@ -230,7 +230,7 @@ int Socket::SendBufferSize() const
 	socklen_t len = sizeof(bytes);
 	socklen_t len = sizeof(bytes);
 	if (getsockopt(connectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bytes, &len))
 	if (getsockopt(connectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bytes, &len))
 	{
 	{
-		LOG(LogError, "Socket::SendBufferSize: getsockopt failed with error %s!", Network::GetLastErrorString().CString());
+		LOG(LogError, "Socket::SendBufferSize: getsockopt failed with error %s!", Network::GetLastErrorString().c_str());
 		return 0;
 		return 0;
 	}
 	}
 	return bytes;
 	return bytes;
@@ -242,7 +242,7 @@ int Socket::ReceiveBufferSize() const
 	socklen_t len = sizeof(bytes);
 	socklen_t len = sizeof(bytes);
 	if (getsockopt(connectSocket, SOL_SOCKET, SO_RCVBUF, (char*)&bytes, &len))
 	if (getsockopt(connectSocket, SOL_SOCKET, SO_RCVBUF, (char*)&bytes, &len))
 	{
 	{
-		LOG(LogError, "Socket::ReceiveBufferSize: getsockopt failed with error %s!", Network::GetLastErrorString().CString());
+		LOG(LogError, "Socket::ReceiveBufferSize: getsockopt failed with error %s!", Network::GetLastErrorString().c_str());
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -293,7 +293,7 @@ void Socket::EnqueueNewReceiveBuffer(OverlappedTransferBuffer *buffer)
 			if (IsUDPServerSocket())
 			if (IsUDPServerSocket())
 				LOG(LogError, "Unexpected: Received a message of 0 bytes on a UDP server socket!");
 				LOG(LogError, "Unexpected: Received a message of 0 bytes on a UDP server socket!");
 
 
-			LOG(LogInfo, "Socket::EnqueueNewReceiveBuffer: Received 0 bytes from the network. Read connection closed in socket %s.", ToString().CString());
+			LOG(LogInfo, "Socket::EnqueueNewReceiveBuffer: Received 0 bytes from the network. Read connection closed in socket %s.", ToString().c_str());
 			readOpen = false;
 			readOpen = false;
 			DeleteOverlappedTransferBuffer(buffer);
 			DeleteOverlappedTransferBuffer(buffer);
 			return;
 			return;
@@ -312,7 +312,7 @@ void Socket::EnqueueNewReceiveBuffer(OverlappedTransferBuffer *buffer)
 		if (IsUDPServerSocket())
 		if (IsUDPServerSocket())
 			LOG(LogError, "Unexpected: Received WSAEDISCON on a UDP server socket!");
 			LOG(LogError, "Unexpected: Received WSAEDISCON on a UDP server socket!");
 
 
-		LOG(LogError, "Socket::EnqueueNewReceivebuffer: WSAEDISCON. Connection closed in socket %s.", ToString().CString());
+		LOG(LogError, "Socket::EnqueueNewReceivebuffer: WSAEDISCON. Connection closed in socket %s.", ToString().c_str());
 		readOpen = false;
 		readOpen = false;
 		///\todo Should do writeOpen = false; here as well?
 		///\todo Should do writeOpen = false; here as well?
 		DeleteOverlappedTransferBuffer(buffer);
 		DeleteOverlappedTransferBuffer(buffer);
@@ -322,7 +322,7 @@ void Socket::EnqueueNewReceiveBuffer(OverlappedTransferBuffer *buffer)
 	{
 	{
 		if (error != WSAEWOULDBLOCK && error != 0)
 		if (error != WSAEWOULDBLOCK && error != 0)
 		{
 		{
-			LOG(LogError, "Socket::EnqueueNewReceiveBuffer: %s for overlapped socket %s failed! Error: %s.", IsUDPServerSocket() ? "WSARecvFrom" : "WSARecv", ToString().CString(), Network::GetErrorString(error).CString());
+			LOG(LogError, "Socket::EnqueueNewReceiveBuffer: %s for overlapped socket %s failed! Error: %s.", IsUDPServerSocket() ? "WSARecvFrom" : "WSARecv", ToString().c_str(), Network::GetErrorString(error).c_str());
 
 
 			// We never close the server socket as a reaction on any error, since an error on one client could shut down
 			// We never close the server socket as a reaction on any error, since an error on one client could shut down
 			// the whole server for all clients. This check is mainly here to ignore the 10054 error (WSAECONNRESET) which
 			// the whole server for all clients. This check is mainly here to ignore the 10054 error (WSAECONNRESET) which
@@ -330,7 +330,7 @@ void Socket::EnqueueNewReceiveBuffer(OverlappedTransferBuffer *buffer)
 			// client-specific errors, we don't explicitly check for the 10054 case only.
 			// client-specific errors, we don't explicitly check for the 10054 case only.
 			if (!IsUDPServerSocket())
 			if (!IsUDPServerSocket())
 			{
 			{
-				LOG(LogError, "Socket::EnqueueNewReceiveBuffer: Closing down socket.",  Network::GetErrorString(error).CString());
+				LOG(LogError, "Socket::EnqueueNewReceiveBuffer: Closing down socket.",  Network::GetErrorString(error).c_str());
 				readOpen = false;
 				readOpen = false;
 				writeOpen = false;
 				writeOpen = false;
 				Close();
 				Close();
@@ -376,12 +376,12 @@ size_t Socket::Receive(char *dst, size_t maxBytes, EndPoint *endPoint)
 		{
 		{
 			int error = Network::GetLastError();
 			int error = Network::GetLastError();
 			if (error != KNET_EWOULDBLOCK && error != 0)
 			if (error != KNET_EWOULDBLOCK && error != 0)
-				LOG(LogError, "Socket::Receive: recvfrom failed: %s in socket %s", Network::GetErrorString(error).CString(), ToString().CString());
+				LOG(LogError, "Socket::Receive: recvfrom failed: %s in socket %s", Network::GetErrorString(error).c_str(), ToString().c_str());
 
 
 			return 0;
 			return 0;
 		}
 		}
 		if (numBytesRead > 0)
 		if (numBytesRead > 0)
-			LOG(LogData, "recvfrom (%d) in socket %s", numBytesRead, ToString().CString());
+			LOG(LogData, "recvfrom (%d) in socket %s", numBytesRead, ToString().c_str());
 
 
 		if (endPoint)
 		if (endPoint)
 			*endPoint = EndPoint::FromSockAddrIn(from);
 			*endPoint = EndPoint::FromSockAddrIn(from);
@@ -400,7 +400,7 @@ size_t Socket::Receive(char *dst, size_t maxBytes, EndPoint *endPoint)
 	}
 	}
 	else if (ret == 0)
 	else if (ret == 0)
 	{
 	{
-		LOG(LogInfo, "Socket::Receive: Received 0 bytes from network. Read-connection closed to socket %s.", ToString().CString());
+		LOG(LogInfo, "Socket::Receive: Received 0 bytes from network. Read-connection closed to socket %s.", ToString().c_str());
 		readOpen = false;
 		readOpen = false;
 		return 0;
 		return 0;
 	}
 	}
@@ -409,7 +409,7 @@ size_t Socket::Receive(char *dst, size_t maxBytes, EndPoint *endPoint)
 		int error = Network::GetLastError();
 		int error = Network::GetLastError();
 		if (error != KNET_EWOULDBLOCK && error != 0)
 		if (error != KNET_EWOULDBLOCK && error != 0)
 		{
 		{
-			LOG(LogError, "Socket::Receive: recv failed in socket %s. Error %s", ToString().CString(), Network::GetErrorString(error).CString());
+			LOG(LogError, "Socket::Receive: recv failed in socket %s. Error %s", ToString().c_str(), Network::GetErrorString(error).c_str());
 
 
 			// We never close the server socket as a reaction on any error, since an error on one client could shut down
 			// We never close the server socket as a reaction on any error, since an error on one client could shut down
 			// the whole server for all clients. This check is mainly here to ignore the 10054 error (WSAECONNRESET) which
 			// the whole server for all clients. This check is mainly here to ignore the 10054 error (WSAECONNRESET) which
@@ -527,7 +527,7 @@ OverlappedTransferBuffer *Socket::BeginReceive()
 		{
 		{
 			DeleteOverlappedTransferBuffer(receivedData);
 			DeleteOverlappedTransferBuffer(receivedData);
 			if (readOpen)
 			if (readOpen)
-				LOG(LogInfo, "Socket::BeginReceive: Received 0 bytes from the network. Read connection closed in socket %s.", ToString().CString());
+				LOG(LogInfo, "Socket::BeginReceive: Received 0 bytes from the network. Read connection closed in socket %s.", ToString().c_str());
 			readOpen = false;
 			readOpen = false;
 			if (IsUDPServerSocket())
 			if (IsUDPServerSocket())
 				LOG(LogError, "Socket::BeginReceive: UDP server socket transitioned to readOpen==false!");
 				LOG(LogError, "Socket::BeginReceive: UDP server socket transitioned to readOpen==false!");
@@ -541,7 +541,7 @@ OverlappedTransferBuffer *Socket::BeginReceive()
 		queuedReceiveBuffers.PopFront();
 		queuedReceiveBuffers.PopFront();
 		DeleteOverlappedTransferBuffer(receivedData);
 		DeleteOverlappedTransferBuffer(receivedData);
 		if (readOpen || writeOpen)
 		if (readOpen || writeOpen)
-			LOG(LogError, "Socket::BeginReceive: WSAEDISCON. Bidirectionally closing connection in socket %s.", ToString().CString());
+			LOG(LogError, "Socket::BeginReceive: WSAEDISCON. Bidirectionally closing connection in socket %s.", ToString().c_str());
 		if (IsUDPServerSocket())
 		if (IsUDPServerSocket())
 			LOG(LogError, "Socket::BeginReceive: Unexpected: Received WSAEDISCON on UDP server socket!");
 			LOG(LogError, "Socket::BeginReceive: Unexpected: Received WSAEDISCON on UDP server socket!");
 		Close();
 		Close();
@@ -552,7 +552,7 @@ OverlappedTransferBuffer *Socket::BeginReceive()
 		queuedReceiveBuffers.PopFront();
 		queuedReceiveBuffers.PopFront();
 		if (readOpen || writeOpen)
 		if (readOpen || writeOpen)
 			if (!(IsUDPServerSocket() && error == 10054)) // If we are running both UDP server and client on localhost, we can receive 10054 (Peer closed connection) on the server side, in which case, we ignore this error print.
 			if (!(IsUDPServerSocket() && error == 10054)) // If we are running both UDP server and client on localhost, we can receive 10054 (Peer closed connection) on the server side, in which case, we ignore this error print.
-				LOG(LogError, "Socket::BeginReceive: WSAGetOverlappedResult failed with code %d when reading from an overlapped socket! Reason: %s.", error, Network::GetErrorString(error).CString());
+				LOG(LogError, "Socket::BeginReceive: WSAGetOverlappedResult failed with code %d when reading from an overlapped socket! Reason: %s.", error, Network::GetErrorString(error).c_str());
 		DeleteOverlappedTransferBuffer(receivedData);
 		DeleteOverlappedTransferBuffer(receivedData);
 		// Mark this socket closed, unless the read error was on a UDP server socket, in which case we must ignore
 		// Mark this socket closed, unless the read error was on a UDP server socket, in which case we must ignore
 		// the read error on this buffer (an error on a single client connection cannot shut down the whole server!)
 		// the read error on this buffer (an error on a single client connection cannot shut down the whole server!)
@@ -610,9 +610,9 @@ void Socket::Disconnect()
 	{
 	{
 		int result = shutdown(connectSocket, SD_SEND);
 		int result = shutdown(connectSocket, SD_SEND);
 		if (result == KNET_SOCKET_ERROR)
 		if (result == KNET_SOCKET_ERROR)
-			LOG(LogError, "Socket::Disconnect(): TCP socket shutdown(SD_SEND) failed: %s in socket %s.", Network::GetLastErrorString().CString(), ToString().CString());
+			LOG(LogError, "Socket::Disconnect(): TCP socket shutdown(SD_SEND) failed: %s in socket %s.", Network::GetLastErrorString().c_str(), ToString().c_str());
 		else
 		else
-			LOG(LogInfo, "Socket::Disconnect(): TCP socket shutdown(SD_SEND) succeeded on socket %s.", ToString().CString());
+			LOG(LogInfo, "Socket::Disconnect(): TCP socket shutdown(SD_SEND) succeeded on socket %s.", ToString().c_str());
 	}
 	}
 
 
 	writeOpen = false;
 	writeOpen = false;
@@ -626,7 +626,7 @@ void Socket::Close()
 		return;
 		return;
 	}
 	}
 
 
-	LOG(LogInfo, "Socket::Close(): Closing socket %s.", ToString().CString());
+	LOG(LogInfo, "Socket::Close(): Closing socket %s.", ToString().c_str());
 
 
 	if (!IsUDPSlaveSocket())
 	if (!IsUDPSlaveSocket())
 	{
 	{
@@ -636,13 +636,13 @@ void Socket::Close()
 
 
 		int result = shutdown(connectSocket, SD_BOTH);
 		int result = shutdown(connectSocket, SD_BOTH);
 		if (result == KNET_SOCKET_ERROR)
 		if (result == KNET_SOCKET_ERROR)
-			LOG(LogError, "Socket::Close(): Socket shutdown(SD_BOTH) failed: %s in socket %s.", Network::GetLastErrorString().CString(), ToString().CString());
+			LOG(LogError, "Socket::Close(): Socket shutdown(SD_BOTH) failed: %s in socket %s.", Network::GetLastErrorString().c_str(), ToString().c_str());
 		else
 		else
-			LOG(LogInfo, "Socket::Close(): Socket shutdown(SD_BOTH) succeeded on socket %s.", ToString().CString());
+			LOG(LogInfo, "Socket::Close(): Socket shutdown(SD_BOTH) succeeded on socket %s.", ToString().c_str());
 
 
 		result = closesocket(connectSocket);
 		result = closesocket(connectSocket);
 		if (result == KNET_SOCKET_ERROR)
 		if (result == KNET_SOCKET_ERROR)
-			LOG(LogError, "Socket::Close(): closesocket() failed: %s in socket %s.", Network::GetLastErrorString().CString(), ToString().CString());
+			LOG(LogError, "Socket::Close(): closesocket() failed: %s in socket %s.", Network::GetLastErrorString().c_str(), ToString().c_str());
 	}
 	}
 
 
 	connectSocket = INVALID_SOCKET;
 	connectSocket = INVALID_SOCKET;
@@ -681,7 +681,7 @@ void Socket::SetBlocking(bool isBlocking)
 	u_long nonBlocking = (isBlocking == false) ? 1 : 0;
 	u_long nonBlocking = (isBlocking == false) ? 1 : 0;
 #ifdef WIN32
 #ifdef WIN32
 	if (ioctlsocket(connectSocket, FIONBIO, &nonBlocking))
 	if (ioctlsocket(connectSocket, FIONBIO, &nonBlocking))
-		LOG(LogError, "Socket::SetBlocking: ioctlsocket failed with error %s!", Network::GetLastErrorString().CString());
+		LOG(LogError, "Socket::SetBlocking: ioctlsocket failed with error %s!", Network::GetLastErrorString().c_str());
 #else
 #else
 	int flags = fcntl(connectSocket, F_GETFL, 0);
 	int flags = fcntl(connectSocket, F_GETFL, 0);
 	fcntl(connectSocket, F_SETFL, flags | O_NONBLOCK);
 	fcntl(connectSocket, F_SETFL, flags | O_NONBLOCK);
@@ -719,7 +719,7 @@ bool Socket::Send(const char *data, size_t numBytes)
 
 
 	if (bytesSent == numBytes)
 	if (bytesSent == numBytes)
 	{
 	{
-		LOG(LogData, "Socket::EndSend: Sent out %d bytes to socket %s.", bytesSent, ToString().CString());
+		LOG(LogData, "Socket::EndSend: Sent out %d bytes to socket %s.", bytesSent, ToString().c_str());
 		return true;
 		return true;
 	}
 	}
 	else if (bytesSent > 0) // Managed to send some data, but not all bytes.
 	else if (bytesSent > 0) // Managed to send some data, but not all bytes.
@@ -733,7 +733,7 @@ bool Socket::Send(const char *data, size_t numBytes)
 		bool waitSuccess = WaitForSendReady(socketWriteTimeout);
 		bool waitSuccess = WaitForSendReady(socketWriteTimeout);
 		if (!waitSuccess)
 		if (!waitSuccess)
 		{
 		{
-			LOG(LogError, "Socket::EndSend: Warning! Managed to only partially send out %d bytes out of %d bytes in the buffer, and socket did not transition to write-ready in the timeout period. Closing connection.", 
+			LOG(LogError, "Socket::Send: Warning! Managed to only partially send out %d bytes out of %d bytes in the buffer, and socket did not transition to write-ready in the timeout period. Closing connection.", 
 				bytesSent, (int)numBytes);
 				bytesSent, (int)numBytes);
 			Close();
 			Close();
 			return false;
 			return false;
@@ -749,7 +749,7 @@ bool Socket::Send(const char *data, size_t numBytes)
 
 
 		if (error != KNET_EWOULDBLOCK)
 		if (error != KNET_EWOULDBLOCK)
 		{
 		{
-			LOG(LogError, "Socket::EndSend() failed! Error: %s.", Network::GetErrorString(error).CString());
+			LOG(LogError, "Socket::Send() failed! Error: %s.", Network::GetErrorString(error).c_str());
 			if (type == ServerClientSocket && transport == SocketOverUDP)
 			if (type == ServerClientSocket && transport == SocketOverUDP)
 			{
 			{
 				// UDP client sockets are shared between each client (and by the server socket),
 				// UDP client sockets are shared between each client (and by the server socket),
@@ -802,11 +802,13 @@ bool Socket::IsOverlappedSendReady()
 #endif
 #endif
 }
 }
 
 
-OverlappedTransferBuffer *Socket::BeginSend()
+OverlappedTransferBuffer *Socket::BeginSend(int maxBytesToSend)
 {
 {
 	if (!writeOpen)
 	if (!writeOpen)
 		return 0;
 		return 0;
 
 
+	// See if the oldest one of the previously submitted transfers has now finished,
+	// and reuse that buffer without allocating a new one, if so.
 #ifdef WIN32
 #ifdef WIN32
 	if (queuedSendBuffers.Size() > 0)
 	if (queuedSendBuffers.Size() > 0)
 	{
 	{
@@ -818,13 +820,26 @@ OverlappedTransferBuffer *Socket::BeginSend()
 		if (ret == TRUE)
 		if (ret == TRUE)
 		{
 		{
 			queuedSendBuffers.PopFront();
 			queuedSendBuffers.PopFront();
-			sentData->buffer.len = maxSendSize; // This is the number of bytes that the client is allowed to fill.
-			return sentData;
+
+            // If the buffer we pulled off was too small, free it and allocate a new one which is of the desired size.
+            if (sentData->bytesAllocated < maxBytesToSend)
+            {
+                DeleteOverlappedTransferBuffer(sentData);
+	            return AllocateOverlappedTransferBuffer(maxBytesToSend); ///\todo In debug mode - track this pointer.
+            }
+            else
+            {
+                // The existing transfer buffer is large enough. Prepare it for reuse and pass back to caller.
+			    sentData->buffer.len = sentData->bytesAllocated; // This is the number of bytes that the client is allowed to fill.
+			    sentData->bytesContains = 0; // No bytes currently in use.
+
+			    return sentData;
+            }
 		}
 		}
 		if (ret == FALSE && error != WSA_IO_INCOMPLETE)
 		if (ret == FALSE && error != WSA_IO_INCOMPLETE)
 		{
 		{
 			LOG(LogError, "Socket::BeginSend: WSAGetOverlappedResult failed with an error %s, code %d != WSA_IO_INCOMPLETE!", 
 			LOG(LogError, "Socket::BeginSend: WSAGetOverlappedResult failed with an error %s, code %d != WSA_IO_INCOMPLETE!", 
-				Network::GetErrorString(error).CString(), error);
+				Network::GetErrorString(error).c_str(), error);
 			writeOpen = false;
 			writeOpen = false;
 			return 0;
 			return 0;
 		}
 		}
@@ -834,8 +849,8 @@ OverlappedTransferBuffer *Socket::BeginSend()
 		return 0;
 		return 0;
 #endif
 #endif
 
 
-	OverlappedTransferBuffer *transfer = AllocateOverlappedTransferBuffer(maxSendSize);
-	return transfer; ///\todo In debug mode - track this pointer.
+	// No previous send buffer has finished from use (or not using overlapped transfers) - allocate a new buffer.
+	return AllocateOverlappedTransferBuffer(maxBytesToSend);
 }
 }
 
 
 bool Socket::EndSend(OverlappedTransferBuffer *sendBuffer)
 bool Socket::EndSend(OverlappedTransferBuffer *sendBuffer)
@@ -844,6 +859,10 @@ bool Socket::EndSend(OverlappedTransferBuffer *sendBuffer)
 	if (!sendBuffer)
 	if (!sendBuffer)
 		return false;
 		return false;
 
 
+	// For the purposes of this send, mark the allocated length of the send buffer equal to the 
+	// number of bytes the user had filled into the buffer.
+	sendBuffer->buffer.len = sendBuffer->bytesContains;
+
 #ifdef WIN32
 #ifdef WIN32
 	// Clear the event flag so that the completion of WSASend can trigger this and signal us.
 	// Clear the event flag so that the completion of WSASend can trigger this and signal us.
 	WSAResetEvent(sendBuffer->overlapped.hEvent);
 	WSAResetEvent(sendBuffer->overlapped.hEvent);
@@ -862,7 +881,7 @@ bool Socket::EndSend(OverlappedTransferBuffer *sendBuffer)
 	{
 	{
 		if (error != KNET_EWOULDBLOCK)
 		if (error != KNET_EWOULDBLOCK)
 		{
 		{
-			LOG(LogError, "Socket::EndSend() failed! Error: %s.", Network::GetErrorString(error).CString());
+			LOG(LogError, "Socket::EndSend() failed! Error: %s.", Network::GetErrorString(error).c_str());
 			if (!IsUDPServerSocket())
 			if (!IsUDPServerSocket())
 				writeOpen = false;
 				writeOpen = false;
 		}
 		}
@@ -915,7 +934,7 @@ void Socket::AbortSend(OverlappedTransferBuffer *send)
 #endif
 #endif
 }
 }
 
 
-String Socket::ToString() const
+std::string Socket::ToString() const
 {
 {
 	sockaddr_in addr;
 	sockaddr_in addr;
 	socklen_t namelen = sizeof(addr);
 	socklen_t namelen = sizeof(addr);
@@ -930,11 +949,11 @@ String Socket::ToString() const
 		DestinationAddress(), (int)DestinationPort(), 
 		DestinationAddress(), (int)DestinationPort(), 
 		(transport == SocketOverTCP) ? "TCP" : (IsUDPServerSocket() ? "UDP server" : (IsUDPSlaveSocket() ? "UDP Slave" : "UDP")), 
 		(transport == SocketOverTCP) ? "TCP" : (IsUDPServerSocket() ? "UDP server" : (IsUDPSlaveSocket() ? "UDP Slave" : "UDP")), 
 		Connected() ? "true" : "false", readOpen ? "true" : "false", writeOpen ? "true" : "false",
 		Connected() ? "true" : "false", readOpen ? "true" : "false", writeOpen ? "true" : "false",
-		(int)maxSendSize, sockRet == 0 ? sockName.ToString().CString() : "(-)", 
-		peerRet == 0 ? peerName.ToString().CString() : "(-)", (int)connectSocket,
+		(int)maxSendSize, sockRet == 0 ? sockName.ToString().c_str() : "(-)", 
+		peerRet == 0 ? peerName.ToString().c_str() : "(-)", (int)connectSocket,
 		this);
 		this);
 
 
-	return String(str);
+	return std::string(str);
 }
 }
 
 
 void Socket::SetNaglesAlgorithmEnabled(bool enabled)
 void Socket::SetNaglesAlgorithmEnabled(bool enabled)
@@ -959,7 +978,7 @@ void Socket::SetNaglesAlgorithmEnabled(bool enabled)
 #endif
 #endif
 	if (ret != 0)
 	if (ret != 0)
 		LOG(LogError, "Setting TCP_NODELAY=%s for socket %d failed. Reason: %s.",
 		LOG(LogError, "Setting TCP_NODELAY=%s for socket %d failed. Reason: %s.",
-			enabled ? "true" : "false", (int)connectSocket, Network::GetLastErrorString().CString());
+			enabled ? "true" : "false", (int)connectSocket, Network::GetLastErrorString().c_str());
 }
 }
 
 
 } // ~kNet
 } // ~kNet

+ 39 - 30
ThirdParty/kNet/src/TCPMessageConnection.cpp

@@ -15,8 +15,6 @@
 /** @file TCPMessageConnection.cpp
 /** @file TCPMessageConnection.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include <sstream>
 #include <sstream>
 
 
 #ifdef KNET_USE_BOOST
 #ifdef KNET_USE_BOOST
@@ -38,7 +36,7 @@ namespace kNet
 
 
 /// The maximum size for a TCP message we will allow to be received. If we receive a message larger than this, we consider
 /// The maximum size for a TCP message we will allow to be received. If we receive a message larger than this, we consider
 /// it as a protocol violation and kill the connection.
 /// it as a protocol violation and kill the connection.
-static const u32 cMaxReceivableTCPMessageSize = 1024 * 1024;
+static const u32 cMaxReceivableTCPMessageSize = 10 * 1024 * 1024; ///\todo Make this configurable for the connection.
 
 
 TCPMessageConnection::TCPMessageConnection(Network *owner, NetworkServer *ownerServer, Socket *socket, ConnectionState startingState)
 TCPMessageConnection::TCPMessageConnection(Network *owner, NetworkServer *ownerServer, Socket *socket, ConnectionState startingState)
 :MessageConnection(owner, ownerServer, socket, startingState),
 :MessageConnection(owner, ownerServer, socket, startingState),
@@ -112,7 +110,7 @@ MessageConnection::SocketReadResult TCPMessageConnection::ReadSocket(size_t &tot
 		}
 		}
 
 
 		LOG(LogData, "TCPMessageConnection::ReadSocket: Received %d bytes from the network from peer %s.", 
 		LOG(LogData, "TCPMessageConnection::ReadSocket: Received %d bytes from the network from peer %s.", 
-			buffer->bytesContains, socket->ToString().CString());
+			buffer->bytesContains, socket->ToString().c_str());
 
 
 		assert((size_t)buffer->bytesContains <= (size_t)tcpInboundSocketData.ContiguousFreeBytesLeft());
 		assert((size_t)buffer->bytesContains <= (size_t)tcpInboundSocketData.ContiguousFreeBytesLeft());
 		///\todo For performance, this memcpy can be optimized away. We can parse the message directly
 		///\todo For performance, this memcpy can be optimized away. We can parse the message directly
@@ -148,7 +146,7 @@ MessageConnection::SocketReadResult TCPMessageConnection::ReadSocket(size_t &tot
 /// Warning: This is a non-threadsafe check for the container, only to be used for debugging.
 /// Warning: This is a non-threadsafe check for the container, only to be used for debugging.
 /// Warning #2: This function is very slow, as it performs a N^2 search through the container.
 /// Warning #2: This function is very slow, as it performs a N^2 search through the container.
 template<typename T>
 template<typename T>
-bool ContainerUniqueAndNoNullElements(const Vector<T> &cont)
+bool ContainerUniqueAndNoNullElements(const std::vector<T> &cont)
 {
 {
 	for(size_t i = 0; i < cont.size(); ++i)
 	for(size_t i = 0; i < cont.size(); ++i)
 		for(size_t j = i+1; j < cont.size(); ++j)
 		for(size_t j = i+1; j < cont.size(); ++j)
@@ -176,25 +174,22 @@ MessageConnection::PacketSendResult TCPMessageConnection::SendOutPacket()
 		return PacketSendSocketClosed;
 		return PacketSendSocketClosed;
 	}
 	}
 
 
+    // 'serializedMessages' is a temporary data structure used only by this member function.
+    // It caches a list of all the messages we are pushing out during this call.
+	serializedMessages.clear();
+
 	// In the following, we start coalescing multiple messages into a single socket send() calls.
 	// In the following, we start coalescing multiple messages into a single socket send() calls.
 	// Get the maximum number of bytes we can coalesce for the send() call. This is only a soft limit
 	// Get the maximum number of bytes we can coalesce for the send() call. This is only a soft limit
 	// in the sense that if we encounter a single message that is larger than this limit, then we try
 	// in the sense that if we encounter a single message that is larger than this limit, then we try
 	// to send that through in one send() call.
 	// to send that through in one send() call.
-	const size_t maxSendSize = socket->MaxSendSize();
+//	const size_t maxSendSize = socket->MaxSendSize();
 
 
 	// Push out all the pending data to the socket.
 	// Push out all the pending data to the socket.
-//	assert(ContainerUniqueAndNoNullElements(serializedMessages));
-//	assert(ContainerUniqueAndNoNullElements(outboundQueue));
-	serializedMessages.Clear(); // 'serializedMessages' is a temporary data structure used only by this member function.
-	OverlappedTransferBuffer *overlappedTransfer = socket->BeginSend();
-	if (!overlappedTransfer)
-	{
-		LOG(LogError, "TCPMessageConnection::SendOutPacket: Starting an overlapped send failed!");
-		return PacketSendSocketClosed;
-	}
+	OverlappedTransferBuffer *overlappedTransfer = 0;
 
 
 	int numMessagesPacked = 0;
 	int numMessagesPacked = 0;
-	DataSerializer writer(overlappedTransfer->buffer.buf, overlappedTransfer->buffer.len);
+	DataSerializer writer;
+//	assert(ContainerUniqueAndNoNullElements(outboundQueue)); // This precondition should always hold (but very heavy to test, uncomment to debug)
 	while(outboundQueue.Size() > 0)
 	while(outboundQueue.Size() > 0)
 	{
 	{
 #ifdef KNET_NO_MAXHEAP
 #ifdef KNET_NO_MAXHEAP
@@ -210,12 +205,26 @@ MessageConnection::PacketSendResult TCPMessageConnection::SendOutPacket()
 			outboundQueue.PopFront();
 			outboundQueue.PopFront();
 			continue;
 			continue;
 		}
 		}
+
 		const int encodedMsgIdLength = VLE8_16_32::GetEncodedBitLength(msg->id) / 8;
 		const int encodedMsgIdLength = VLE8_16_32::GetEncodedBitLength(msg->id) / 8;
 		const size_t messageContentSize = msg->dataSize + encodedMsgIdLength; // 1 byte: Message ID. X bytes: Content.
 		const size_t messageContentSize = msg->dataSize + encodedMsgIdLength; // 1 byte: Message ID. X bytes: Content.
 		const int encodedMsgSizeLength = VLE8_16_32::GetEncodedBitLength(messageContentSize) / 8;
 		const int encodedMsgSizeLength = VLE8_16_32::GetEncodedBitLength(messageContentSize) / 8;
 		const size_t totalMessageSize = messageContentSize + encodedMsgSizeLength; // 2 bytes: Content length. X bytes: Content.
 		const size_t totalMessageSize = messageContentSize + encodedMsgSizeLength; // 2 bytes: Content length. X bytes: Content.
-		// If this message won't fit into the buffer, send out all previously gathered messages (except if there were none, then try to get the big message through).
-		if (writer.BytesFilled() + totalMessageSize >= maxSendSize && numMessagesPacked > 0)
+
+        if (!overlappedTransfer)
+        {
+            overlappedTransfer = socket->BeginSend(std::max<size_t>(socket->MaxSendSize(), totalMessageSize));
+	        if (!overlappedTransfer)
+	        {
+		        LOG(LogError, "TCPMessageConnection::SendOutPacket: Starting an overlapped send failed!");
+                assert(serializedMessages.size() == 0);
+		        return PacketSendSocketClosed;
+	        }
+            writer = DataSerializer(overlappedTransfer->buffer.buf, overlappedTransfer->buffer.len);
+        }
+
+		// If this message won't fit into the buffer, send out all previously gathered messages.
+        if (writer.BytesLeft() < totalMessageSize)
 			break;
 			break;
 
 
 		writer.AddVLE<VLE8_16_32>(messageContentSize);
 		writer.AddVLE<VLE8_16_32>(messageContentSize);
@@ -224,7 +233,7 @@ MessageConnection::PacketSendResult TCPMessageConnection::SendOutPacket()
 			writer.AddAlignedByteArray(msg->data, msg->dataSize);
 			writer.AddAlignedByteArray(msg->data, msg->dataSize);
 		++numMessagesPacked;
 		++numMessagesPacked;
 
 
-		serializedMessages.Push(msg);
+		serializedMessages.push_back(msg);
 #ifdef KNET_NO_MAXHEAP
 #ifdef KNET_NO_MAXHEAP
 		assert(*outboundQueue.Front() == msg);
 		assert(*outboundQueue.Front() == msg);
 #else
 #else
@@ -232,17 +241,17 @@ MessageConnection::PacketSendResult TCPMessageConnection::SendOutPacket()
 #endif
 #endif
 		outboundQueue.PopFront();
 		outboundQueue.PopFront();
 	}
 	}
-//	assert(ContainerUniqueAndNoNullElements(serializedMessages));
+//	assert(ContainerUniqueAndNoNullElements(serializedMessages)); // This precondition should always hold (but very heavy to test, uncomment to debug)
 
 
 	if (writer.BytesFilled() == 0 && outboundQueue.Size() > 0)
 	if (writer.BytesFilled() == 0 && outboundQueue.Size() > 0)
-		LOG(LogError, "Failed to send any messages to socket %s! (Probably next message was too big to fit in the buffer).", socket->ToString().CString());
+		LOG(LogError, "Failed to send any messages to socket %s! (Probably next message was too big to fit in the buffer).", socket->ToString().c_str());
 
 
-	overlappedTransfer->buffer.len = writer.BytesFilled();
+	overlappedTransfer->bytesContains = writer.BytesFilled();
 	bool success = socket->EndSend(overlappedTransfer);
 	bool success = socket->EndSend(overlappedTransfer);
 
 
 	if (!success) // If we failed to send, put all the messages back into the outbound queue to wait for the next send round.
 	if (!success) // If we failed to send, put all the messages back into the outbound queue to wait for the next send round.
 	{
 	{
-		for(size_t i = 0; i < serializedMessages.Size(); ++i)
+		for(size_t i = 0; i < serializedMessages.size(); ++i)
 #ifdef KNET_NO_MAXHEAP
 #ifdef KNET_NO_MAXHEAP
 			outboundQueue.InsertWithResize(serializedMessages[i]);
 			outboundQueue.InsertWithResize(serializedMessages[i]);
 #else
 #else
@@ -255,21 +264,21 @@ MessageConnection::PacketSendResult TCPMessageConnection::SendOutPacket()
 		return PacketSendSocketFull;
 		return PacketSendSocketFull;
 	}
 	}
 
 
-	LOG(LogData, "TCPMessageConnection::SendOutPacket: Sent %d bytes (%d messages) to peer %s.", (int)writer.BytesFilled(), (int)serializedMessages.Size(), socket->ToString().CString());
+	LOG(LogData, "TCPMessageConnection::SendOutPacket: Sent %d bytes (%d messages) to peer %s.", (int)writer.BytesFilled(), (int)serializedMessages.size(), socket->ToString().c_str());
 	AddOutboundStats(writer.BytesFilled(), 1, numMessagesPacked);
 	AddOutboundStats(writer.BytesFilled(), 1, numMessagesPacked);
 	ADDEVENT("tcpDataOut", (float)writer.BytesFilled(), "bytes");
 	ADDEVENT("tcpDataOut", (float)writer.BytesFilled(), "bytes");
 
 
 	// The messages in serializedMessages array are now in the TCP driver to handle. It will guarantee
 	// The messages in serializedMessages array are now in the TCP driver to handle. It will guarantee
 	// delivery if possible, so we can free the messages already.
 	// delivery if possible, so we can free the messages already.
-	for(size_t i = 0; i < serializedMessages.Size(); ++i)
+	for(size_t i = 0; i < serializedMessages.size(); ++i)
 	{
 	{
 #ifdef KNET_NETWORK_PROFILING
 #ifdef KNET_NETWORK_PROFILING
-		String str;
-		if (!serializedMessages[i]->profilerName.Empty())
-			str += "messageOut." + serializedMessages[i]->profilerName;
+		std::stringstream ss;
+		if (!serializedMessages[i]->profilerName.empty())
+			ss << "messageOut." << serializedMessages[i]->profilerName;
 		else
 		else
-			str += "messageOut." + String((unsigned)serializedMessages[i]->id);
-		ADDEVENT(str.CString(), (float)serializedMessages[i]->Size(), "bytes");
+			ss << "messageOut." << serializedMessages[i]->id;
+		ADDEVENT(ss.str().c_str(), (float)serializedMessages[i]->Size(), "bytes");
 #endif
 #endif
 		ClearOutboundMessageWithContentID(serializedMessages[i]);
 		ClearOutboundMessageWithContentID(serializedMessages[i]);
 		FreeMessage(serializedMessages[i]);
 		FreeMessage(serializedMessages[i]);

+ 8 - 4
ThirdParty/kNet/src/Thread.cpp

@@ -15,8 +15,6 @@
 /** @file Thread.cpp
 /** @file Thread.cpp
 	@brief Implements platform-generic Thread functions. */
 	@brief Implements platform-generic Thread functions. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #ifdef KNET_USE_BOOST
 #ifdef KNET_USE_BOOST
 #include <boost/thread/thread.hpp>
 #include <boost/thread/thread.hpp>
 #endif
 #endif
@@ -32,9 +30,11 @@
 namespace kNet
 namespace kNet
 {
 {
 
 
-String ThreadIdToString(const ThreadId &id)
+std::string ThreadIdToString(const ThreadId &id)
 {
 {
-	return String((unsigned)id);
+	std::stringstream ss;
+	ss << id;
+	return ss.str();
 }
 }
 
 
 /// Suspends the thread until 'Resume()' is called. Call this function from the main thread.
 /// Suspends the thread until 'Resume()' is called. Call this function from the main thread.
@@ -102,6 +102,7 @@ typedef struct tagTHREADNAME_INFO
 
 
 void SetThreadName(DWORD dwThreadID, const char *threadName)
 void SetThreadName(DWORD dwThreadID, const char *threadName)
 {
 {
+#ifdef _MSC_VER
 	THREADNAME_INFO info;
 	THREADNAME_INFO info;
 	info.dwType = 0x1000;
 	info.dwType = 0x1000;
 	info.szName = threadName;
 	info.szName = threadName;
@@ -116,6 +117,9 @@ void SetThreadName(DWORD dwThreadID, const char *threadName)
 	__except(EXCEPTION_CONTINUE_EXECUTION)
 	__except(EXCEPTION_CONTINUE_EXECUTION)
 	{
 	{
 	}
 	}
+#else
+#warning SetThreadName undefined for current platform!
+#endif
 }
 }
 #endif
 #endif
 
 

+ 257 - 155
ThirdParty/kNet/src/UDPMessageConnection.cpp

@@ -16,8 +16,6 @@
 	@brief Implements the UDP-specific code of MessageConnection.
 	@brief Implements the UDP-specific code of MessageConnection.
 	\todo Flow control currently disabled since testing out the performance of UDT. */
 	\todo Flow control currently disabled since testing out the performance of UDT. */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include <cmath>
 #include <cmath>
 #include <cstdio>
 #include <cstdio>
 #include <sstream>
 #include <sstream>
@@ -44,25 +42,26 @@ using namespace std;
 namespace kNet
 namespace kNet
 {
 {
 
 
+static const int initialDatagramRatePerSecond = 30;
 /// The maximum time to wait before acking a packet. If there are enough packets to ack for a full ack message,
 /// The maximum time to wait before acking a packet. If there are enough packets to ack for a full ack message,
 /// acking will be performed earlier. (milliseconds)
 /// acking will be performed earlier. (milliseconds)
 static const float maxAckDelay = 33.f; // (1/30th of a second)
 static const float maxAckDelay = 33.f; // (1/30th of a second)
+/// The time counter after which an unacked reliable message will be resent. (UDP only)
+static const float timeOutMilliseconds = 2000.f;//750.f;
 /// The maximum number of datagrams to read in from the socket at one go - after this reads will be throttled
 /// The maximum number of datagrams to read in from the socket at one go - after this reads will be throttled
 /// to give time for data sending as well.
 /// to give time for data sending as well.
 static const int cMaxDatagramsToReadInOneFrame = 2048;
 static const int cMaxDatagramsToReadInOneFrame = 2048;
 
 
-/// Minimum retransmission timeout value (milliseconds)
-static const float minRTOTimeoutValue = 500.f;
-/// Maximum retransmission timeout value (milliseconds)
-static const float maxRTOTimeoutValue = 5000.f;
+static const u32 cMaxUDPMessageFragmentSize = 470;
 
 
 UDPMessageConnection::UDPMessageConnection(Network *owner, NetworkServer *ownerServer, Socket *socket, ConnectionState startingState)
 UDPMessageConnection::UDPMessageConnection(Network *owner, NetworkServer *ownerServer, Socket *socket, ConnectionState startingState)
 :MessageConnection(owner, ownerServer, socket, startingState),
 :MessageConnection(owner, ownerServer, socket, startingState),
-retransmissionTimeout(1000.f), numAcksLastFrame(0), numLossesLastFrame(0), smoothedRTT(1000.f), rttVariation(0.f), rttCleared(true), // Set RTT initial values as per RFC 2988.
+retransmissionTimeout(3.f), numAcksLastFrame(0), numLossesLastFrame(0), smoothedRTT(3.f), rttVariation(0.f), rttCleared(true), // Set RTT initial values as per RFC 2988.
 lastReceivedInOrderPacketID(0), 
 lastReceivedInOrderPacketID(0), 
 lastSentInOrderPacketID(0), datagramPacketIDCounter(1),
 lastSentInOrderPacketID(0), datagramPacketIDCounter(1),
-packetLossRate(0.f), packetLossCount(0.f), 
-datagramSendRate(50.f), lowestDatagramSendRateOnPacketLoss(50.f), slowModeDelay(0),
+packetLossRate(0.f), packetLossCount(0.f), datagramOutRatePerSecond(initialDatagramRatePerSecond), 
+datagramInRatePerSecond(initialDatagramRatePerSecond),
+datagramSendRate(70),
 receivedPacketIDs(64 * 1024), outboundPacketAckTrack(1024),
 receivedPacketIDs(64 * 1024), outboundPacketAckTrack(1024),
 previousReceivedPacketID(0), queuedInboundDatagrams(128)
 previousReceivedPacketID(0), queuedInboundDatagrams(128)
 {
 {
@@ -140,7 +139,7 @@ UDPMessageConnection::SocketReadResult UDPMessageConnection::ReadSocket(size_t &
 	{
 	{
 		connectionState = ConnectionOK;
 		connectionState = ConnectionOK;
 		LOG(LogUser, "UDPMessageConnection::ReadSocket: Received data from socket %s. Transitioned from ConnectionPending to ConnectionOK state.", 
 		LOG(LogUser, "UDPMessageConnection::ReadSocket: Received data from socket %s. Transitioned from ConnectionPending to ConnectionOK state.", 
-			(socket ? socket->ToString().CString() : "(null)"));
+			(socket ? socket->ToString().c_str() : "(null)"));
 	}
 	}
 	if (readResult == SocketReadError)
 	if (readResult == SocketReadError)
 		return SocketReadError;
 		return SocketReadError;
@@ -156,10 +155,10 @@ void UDPMessageConnection::PerformPacketAckSends()
 	AssertInWorkerThreadContext();
 	AssertInWorkerThreadContext();
 
 
 	tick_t now = Clock::Tick();
 	tick_t now = Clock::Tick();
-	while(inboundPacketAckTrack.Size() > 0)
+	while(inboundPacketAckTrack.size() > 0)
 	{
 	{
-		if (Clock::TimespanToMillisecondsF(inboundPacketAckTrack.Begin()->second_.sentTick, now) < maxAckDelay &&
-			inboundPacketAckTrack.Size() < 33)
+		if (Clock::TimespanToMillisecondsF(inboundPacketAckTrack.begin()->second.sentTick, now) < maxAckDelay &&
+			inboundPacketAckTrack.size() < 33)
 			break;
 			break;
 
 
 		SendPacketAckMessage();
 		SendPacketAckMessage();
@@ -256,67 +255,42 @@ void UDPMessageConnection::HandleFlowControl()
 	AssertInWorkerThreadContext();
 	AssertInWorkerThreadContext();
 
 
 	// In packets/second.
 	// In packets/second.
-	const float minBandwidthOnLoss = 10.f;
-	const float minBandwidth = 50.f;
-	const float maxBandwidth = 10000.f;
-	const int framesPerSec = 10;
-	const int maxSlowModeDelay = 10 * framesPerSec;
-
-	const tick_t frameLength = Clock::TicksPerSec() / framesPerSec; // in ticks
-	const tick_t now = Clock::Tick();
+	const float totalEstimatedBandwidth = 50; ///\todo Make this estimation dynamic as in UDT or similar.
+	const float additiveIncreaseAggressiveness = 5e-2f;
 
 
-	unsigned long numFrames = (unsigned long)(Clock::TicksInBetween(now, lastFrameTime) / frameLength);
-	if (numFrames > 0)
+	const tick_t frameLength = Clock::TicksPerSec() / 100; // in ticks
+	// Additively increase the outbound send rate.
+	unsigned long numFrames = (unsigned long)(Clock::TicksInBetween(Clock::Tick(), lastFrameTime) / frameLength);
+	if (/*numAcksLastFrame > 0 &&*/ numFrames > 0)
 	{
 	{
-		if (numFrames >= framesPerSec)
-			numFrames = framesPerSec;
-
-		int numUnacked = NumOutboundUnackedDatagrams();
+		if (numFrames >= 100)
+			numFrames = 100;
 
 
-		// Reduce sendrate on significant loss
-		if (numLossesLastFrame > 2)
+		if (numLossesLastFrame > 5) // Do not respond to a random single packet losses.
 		{
 		{
 			float oldRate = datagramSendRate;
 			float oldRate = datagramSendRate;
-			datagramSendRate = min(datagramSendRate, max(minBandwidthOnLoss, lowestDatagramSendRateOnPacketLoss * 0.9f)); // Multiplicative decreases.
+			datagramSendRate = min(datagramSendRate, max(1.f, lowestDatagramSendRateOnPacketLoss * 0.9f)); // Multiplicative decreases.
+//			datagramSendRate = max(1.f, datagramSendRate * 0.9f); // Multiplicative decreases.
 			LOG(LogVerbose, "Received %d losses. datagramSendRate backed to %.2f from %.2f", (int)numLossesLastFrame, datagramSendRate, oldRate);
 			LOG(LogVerbose, "Received %d losses. datagramSendRate backed to %.2f from %.2f", (int)numLossesLastFrame, datagramSendRate, oldRate);
 		}
 		}
-		else
+		else // Additive increases.
 		{
 		{
-			// Check if more or less bandwidth is needed
-			///\todo Very simple logic for now, can be improved
-			bool needMore = outboundQueue.Size() > 10;
-			bool needLess = outboundQueue.Size() == 0;
-			float maxRTT = max(rtt, smoothedRTT);
-
-			// Need more: increase sendrate. Factor in RTT and acks
-			if (needMore && numLossesLastFrame == 0)
-			{
-				float delta = (50.f + 2.f * numAcksLastFrame) / maxRTT;
-				if (slowModeDelay > 0)
-					delta *= 0.2f;
-				datagramSendRate = min(datagramSendRate + delta, maxBandwidth);
-				lowestDatagramSendRateOnPacketLoss = datagramSendRate;
-			}
-			// Need less: decrease sendrate if not already at minimum
-			else if (needLess && datagramSendRate > minBandwidth)
-				datagramSendRate = max(datagramSendRate * 0.98f, minBandwidth);
-
-			// Whenever slow mode or slight loss is occurring and RTT is more than the minimum RTO value, back off slowly
-			// This is to ensure we do not stay "balanced" in a state where slight loss occurs constantly due to sending too much
-			if ((numLossesLastFrame > 0 || slowModeDelay > 0) && maxRTT > minRTOTimeoutValue && datagramSendRate > minBandwidth)
-				datagramSendRate = max(datagramSendRate * 0.999f, minBandwidth);
+			float increment = min((float)numFrames * additiveIncreaseAggressiveness * (totalEstimatedBandwidth - datagramSendRate), 1.f);
+			datagramSendRate += increment;
+			datagramSendRate = min(datagramSendRate, totalEstimatedBandwidth);
+			lowestDatagramSendRateOnPacketLoss = datagramSendRate;
+//			LOG(LogVerbose, "Incremented sendRate by %.2f to %.2f", increment, datagramSendRate);
 		}
 		}
-
-		// Update the slow mode timer
-		if (numLossesLastFrame > 1)
-			slowModeDelay = min(slowModeDelay + numLossesLastFrame * framesPerSec, maxSlowModeDelay);
-		else if (slowModeDelay > 0)
-			--slowModeDelay;
-
 		numAcksLastFrame = 0;
 		numAcksLastFrame = 0;
 		numLossesLastFrame = 0;
 		numLossesLastFrame = 0;
-		lastFrameTime = now;
+		if (numFrames < 100)
+			lastFrameTime += numFrames * frameLength;
+		else
+			lastFrameTime = Clock::Tick();
 	}
 	}
+
+	// Do a fixed flow control for testing.
+	datagramSendRate = 1000; ///\todo Remove.
 }
 }
 
 
 void UDPMessageConnection::SendOutPackets()
 void UDPMessageConnection::SendOutPackets()
@@ -361,7 +335,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 	if (!CanSendOutNewDatagram())
 	if (!CanSendOutNewDatagram())
 		return PacketSendThrottled;
 		return PacketSendThrottled;
 
 
-	OverlappedTransferBuffer *data = socket->BeginSend();
+    OverlappedTransferBuffer *data = socket->BeginSend(socket->MaxSendSize());
 	if (!data)
 	if (!data)
 		return PacketSendThrottled;
 		return PacketSendThrottled;
 
 
@@ -369,7 +343,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 	const size_t maxSendSize = socket->MaxSendSize();
 	const size_t maxSendSize = socket->MaxSendSize();
 
 
 	// Push out all the pending data to the socket.
 	// Push out all the pending data to the socket.
-	datagramSerializedMessages.Clear();
+	datagramSerializedMessages.clear();
 
 
 	// If true, the receiver needs to Ack the packet we are now crafting.
 	// If true, the receiver needs to Ack the packet we are now crafting.
 	bool reliable = false;
 	bool reliable = false;
@@ -381,7 +355,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 
 
 	unsigned long smallestReliableMessageNumber = 0xFFFFFFFF;
 	unsigned long smallestReliableMessageNumber = 0xFFFFFFFF;
 
 
-	skippedMessages.Clear();
+	skippedMessages.clear();
 
 
 	// Fill up the rest of the packet from messages from the outbound queue.
 	// Fill up the rest of the packet from messages from the outbound queue.
 	while(outboundQueue.Size() > 0)
 	while(outboundQueue.Size() > 0)
@@ -413,7 +387,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 				{
 				{
 					LOG(LogError, "Throttling fragmented transfer send! No free TransferID to start a new fragmented transfer with!");
 					LOG(LogError, "Throttling fragmented transfer send! No free TransferID to start a new fragmented transfer with!");
 					outboundQueue.PopFront();
 					outboundQueue.PopFront();
-					skippedMessages.Push(msg);
+					skippedMessages.push_back(msg);
 					continue;
 					continue;
 				}
 				}
 			}
 			}
@@ -425,13 +399,13 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 		int totalMessageSize = msg->GetTotalDatagramPackedSize();// + ((msg->inOrder && !inOrder) ? cBytesForInOrderDeltaCounter : 0);
 		int totalMessageSize = msg->GetTotalDatagramPackedSize();// + ((msg->inOrder && !inOrder) ? cBytesForInOrderDeltaCounter : 0);
 
 
 		// If this message won't fit into the buffer, send out all the previously gathered messages (there must at least be one previously submitted message).		
 		// If this message won't fit into the buffer, send out all the previously gathered messages (there must at least be one previously submitted message).		
-		if (datagramSerializedMessages.Size() > 0 && (size_t)packetSizeInBytes + totalMessageSize >= maxSendSize)
+		if (datagramSerializedMessages.size() > 0 && (size_t)packetSizeInBytes + totalMessageSize >= maxSendSize)
 			break;
 			break;
 
 
 		if (totalMessageSize > (int)maxSendSize)
 		if (totalMessageSize > (int)maxSendSize)
 			LOG(LogError, "Warning: Sending out a message of ID %d and size %d bytes, but UDP socket max send size is only %d bytes!", (int)msg->id, totalMessageSize, (int)maxSendSize);
 			LOG(LogError, "Warning: Sending out a message of ID %d and size %d bytes, but UDP socket max send size is only %d bytes!", (int)msg->id, totalMessageSize, (int)maxSendSize);
 
 
-		datagramSerializedMessages.Push(msg);
+		datagramSerializedMessages.push_back(msg);
 		outboundQueue.PopFront();
 		outboundQueue.PopFront();
 
 
 		packetSizeInBytes += totalMessageSize;
 		packetSizeInBytes += totalMessageSize;
@@ -447,7 +421,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 	}
 	}
 
 
 	// Ensure that the range of the message numbers is within the capacity that the protocol can represent in the byte stream.
 	// Ensure that the range of the message numbers is within the capacity that the protocol can represent in the byte stream.
-	for(size_t i = 0; i < datagramSerializedMessages.Size(); ++i)
+	for(size_t i = 0; i < datagramSerializedMessages.size(); ++i)
 		if (datagramSerializedMessages[i]->reliable)
 		if (datagramSerializedMessages[i]->reliable)
 		{
 		{
 			u32 reliableDelta = (u32)(datagramSerializedMessages[i]->reliableMessageNumber - smallestReliableMessageNumber);
 			u32 reliableDelta = (u32)(datagramSerializedMessages[i]->reliableMessageNumber - smallestReliableMessageNumber);
@@ -455,15 +429,15 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 			{                                      // they will have to be serialized in separate datagrams.
 			{                                      // they will have to be serialized in separate datagrams.
 				LOG(LogError, "UDPMessageConnection::SendOutPacket: Too large msgnum delta present - skipping serialization of message with ID %d (lowest: %d, delta: %d)",
 				LOG(LogError, "UDPMessageConnection::SendOutPacket: Too large msgnum delta present - skipping serialization of message with ID %d (lowest: %d, delta: %d)",
 					(int)datagramSerializedMessages[i]->reliableMessageNumber, (int)smallestReliableMessageNumber, (int)reliableDelta);
 					(int)datagramSerializedMessages[i]->reliableMessageNumber, (int)smallestReliableMessageNumber, (int)reliableDelta);
-				skippedMessages.Push(datagramSerializedMessages[i]);
-				datagramSerializedMessages.Erase(datagramSerializedMessages.Begin() + i);
+				skippedMessages.push_back(datagramSerializedMessages[i]);
+				datagramSerializedMessages.erase(datagramSerializedMessages.begin() + i);
 				--i;
 				--i;
 			}
 			}
 		}
 		}
 
 
 	// If we had skipped any messages from the outbound queue while looking for good messages to send, put all the messages
 	// If we had skipped any messages from the outbound queue while looking for good messages to send, put all the messages
 	// we skipped back to the outbound queue to wait to be processed during subsequent frames.
 	// we skipped back to the outbound queue to wait to be processed during subsequent frames.
-	for(size_t i = 0; i < skippedMessages.Size(); ++i)
+	for(size_t i = 0; i < skippedMessages.size(); ++i)
 #ifdef KNET_NO_MAXHEAP
 #ifdef KNET_NO_MAXHEAP
 		outboundQueue.InsertWithResize(skippedMessages[i]);
 		outboundQueue.InsertWithResize(skippedMessages[i]);
 #else
 #else
@@ -486,7 +460,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 	bool sentDisconnectAckMessage = false;
 	bool sentDisconnectAckMessage = false;
 
 
 	// Write all the messages in this UDP packet.
 	// Write all the messages in this UDP packet.
-	for(size_t i = 0; i < datagramSerializedMessages.Size(); ++i)
+	for(size_t i = 0; i < datagramSerializedMessages.size(); ++i)
 	{
 	{
 		NetworkMessage *msg = datagramSerializedMessages[i];
 		NetworkMessage *msg = datagramSerializedMessages[i];
 		assert(!msg->transfer || msg->transfer->id != -1);
 		assert(!msg->transfer || msg->transfer->id != -1);
@@ -522,36 +496,52 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 		if (msg->transfer == 0 || msg->fragmentIndex == 0)
 		if (msg->transfer == 0 || msg->fragmentIndex == 0)
 			writer.AddVLE<VLE8_16_32>(msg->id); // Add the message ID number.
 			writer.AddVLE<VLE8_16_32>(msg->id); // Add the message ID number.
 		if (msg->dataSize > 0) // Add the actual message payload data.
 		if (msg->dataSize > 0) // Add the actual message payload data.
+		{
+			if (networkSendSimulator.enabled && 
+				(networkSendSimulator.corruptionType == NetworkSimulator::CorruptPayload ||
+				(networkSendSimulator.corruptionType == NetworkSimulator::CorruptMessageType &&
+				 msg->id == networkSendSimulator.corruptMessageId)))
+				 networkSendSimulator.MaybeCorruptBufferToggleBits(msg->data, msg->dataSize);
 			writer.AddAlignedByteArray(msg->data, msg->dataSize);
 			writer.AddAlignedByteArray(msg->data, msg->dataSize);
+		}
 	}
 	}
 
 
 	// Send the crafted packet out to the socket.
 	// Send the crafted packet out to the socket.
-	data->buffer.len = writer.BytesFilled();
-	bool success = socket->EndSend(data);
+	data->bytesContains = writer.BytesFilled();
+	bool success;
+
+	if (!networkSendSimulator.enabled)
+		success = socket->EndSend(data); // Send the data out.
+	else
+	{
+		// We're running a network simulator. Pass the buffer to networkSendSimulator for delayed sending.
+		networkSendSimulator.SubmitSendBuffer(data, socket);
+		success = true; // Act here as if we succeeded.
+	}
 
 
 	if (!success)
 	if (!success)
 	{
 	{
 		// We failed, so put all messages back to the outbound queue, except for those that are from old in-order packet,
 		// We failed, so put all messages back to the outbound queue, except for those that are from old in-order packet,
 		// since they need to be resent with the old packet ID and not as fresh messages.
 		// since they need to be resent with the old packet ID and not as fresh messages.
-		for(size_t i = 0; i < datagramSerializedMessages.Size(); ++i)
+		for(size_t i = 0; i < datagramSerializedMessages.size(); ++i)
 			outboundQueue.Insert(datagramSerializedMessages[i]);
 			outboundQueue.Insert(datagramSerializedMessages[i]);
 
 
-		LOG(LogError, "UDPMessageConnection::SendOutPacket: Socket::EndSend failed to socket %s!", socket->ToString().CString());
+		LOG(LogError, "UDPMessageConnection::SendOutPacket: Socket::EndSend failed to socket %s!", socket->ToString().c_str());
 		return PacketSendSocketFull;
 		return PacketSendSocketFull;
 	}
 	}
 
 
 	// Sending the datagram succeeded - increment the send count of each message by one, to remember the retry timeout count.
 	// Sending the datagram succeeded - increment the send count of each message by one, to remember the retry timeout count.
-	for(size_t i = 0; i < datagramSerializedMessages.Size(); ++i)
+	for(size_t i = 0; i < datagramSerializedMessages.size(); ++i)
 	{
 	{
 		++datagramSerializedMessages[i]->sendCount;
 		++datagramSerializedMessages[i]->sendCount;
 
 
 #ifdef KNET_NETWORK_PROFILING
 #ifdef KNET_NETWORK_PROFILING
-		String str;
-		if (!datagramSerializedMessages[i]->profilerName.Empty())
-			str += "messageOut." + datagramSerializedMessages[i]->profilerName;
+		std::stringstream ss;
+		if (!datagramSerializedMessages[i]->profilerName.empty())
+			ss << "messageOut." << datagramSerializedMessages[i]->profilerName;
 		else
 		else
-			str += "messageOut." + String((unsigned)datagramSerializedMessages[i]->id);
-		ADDEVENT(str.CString(), (float)datagramSerializedMessages[i]->Size(), "bytes");
+			ss << "messageOut." << datagramSerializedMessages[i]->id;
+		ADDEVENT(ss.str().c_str(), (float)datagramSerializedMessages[i]->Size(), "bytes");
 		if (datagramSerializedMessages[i]->transfer)
 		if (datagramSerializedMessages[i]->transfer)
 		{
 		{
 			if (datagramSerializedMessages[i]->fragmentIndex > 0)
 			if (datagramSerializedMessages[i]->fragmentIndex > 0)
@@ -570,7 +560,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 	lastSentInOrderPacketID = datagramPacketIDCounter;
 	lastSentInOrderPacketID = datagramPacketIDCounter;
 	datagramPacketIDCounter = AddPacketID(datagramPacketIDCounter, 1);
 	datagramPacketIDCounter = AddPacketID(datagramPacketIDCounter, 1);
 
 
-	AddOutboundStats(writer.BytesFilled(), 1, datagramSerializedMessages.Size());
+	AddOutboundStats(writer.BytesFilled(), 1, datagramSerializedMessages.size());
 	ADDEVENT("datagramOut", (float)writer.BytesFilled(), "bytes");
 	ADDEVENT("datagramOut", (float)writer.BytesFilled(), "bytes");
 
 
 	if (reliable)
 	if (reliable)
@@ -582,10 +572,11 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 		const tick_t now = Clock::Tick();
 		const tick_t now = Clock::Tick();
 		ack.sendCount = 1;
 		ack.sendCount = 1;
 		ack.sentTick = now;
 		ack.sentTick = now;
+		retransmissionTimeout = 5000.f; ///\todo Remove this.
 		ack.timeoutTick = now + (tick_t)((double)retransmissionTimeout * Clock::TicksPerMillisecond());
 		ack.timeoutTick = now + (tick_t)((double)retransmissionTimeout * Clock::TicksPerMillisecond());
 		ack.datagramSendRate = datagramSendRate;
 		ack.datagramSendRate = datagramSendRate;
 
 
-		for(size_t i = 0; i < datagramSerializedMessages.Size(); ++i)
+		for(size_t i = 0; i < datagramSerializedMessages.size(); ++i)
 		{
 		{
 			if (datagramSerializedMessages[i]->reliable)
 			if (datagramSerializedMessages[i]->reliable)
 				ack.messages.push_back(datagramSerializedMessages[i]); // The ownership of these messages is transferred into this struct.
 				ack.messages.push_back(datagramSerializedMessages[i]); // The ownership of these messages is transferred into this struct.
@@ -600,7 +591,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 	else // We sent an unreliable datagram.
 	else // We sent an unreliable datagram.
 	{
 	{
 		// This is send-and-forget, we can free all the message data we just sent.
 		// This is send-and-forget, we can free all the message data we just sent.
-		for(size_t i = 0; i < datagramSerializedMessages.Size(); ++i)
+		for(size_t i = 0; i < datagramSerializedMessages.size(); ++i)
 		{
 		{
 			ClearOutboundMessageWithContentID(datagramSerializedMessages[i]);
 			ClearOutboundMessageWithContentID(datagramSerializedMessages[i]);
 			FreeMessage(datagramSerializedMessages[i]);
 			FreeMessage(datagramSerializedMessages[i]);
@@ -617,7 +608,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 			connectionState = ConnectionClosed;
 			connectionState = ConnectionClosed;
 		if (socket)
 		if (socket)
 			socket->MarkWriteClosed();
 			socket->MarkWriteClosed();
-		LOG(LogInfo, "UDPMessageConnection::SendOutPacket: Send Disconnect from connection %s.", ToString().CString());
+		LOG(LogInfo, "UDPMessageConnection::SendOutPacket: Send Disconnect from connection %s.", ToString().c_str());
 	}
 	}
 	// If we sent out the DisconnectAck message, we can tear down the connection right now - we're finished.
 	// If we sent out the DisconnectAck message, we can tear down the connection right now - we're finished.
 	if (sentDisconnectAckMessage)
 	if (sentDisconnectAckMessage)
@@ -628,7 +619,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 			socket->MarkWriteClosed();
 			socket->MarkWriteClosed();
 		}
 		}
 		connectionState = ConnectionClosed;
 		connectionState = ConnectionClosed;
-		LOG(LogInfo, "UDPMessageConnection::SendOutPacket: Send DisconnectAck from connection %s.", ToString().CString());
+		LOG(LogInfo, "UDPMessageConnection::SendOutPacket: Send DisconnectAck from connection %s.", ToString().c_str());
 	}
 	}
 
 
 	LOG(LogVerbose, "UDPMessageConnection::SendOutPacket: Socket::EndSend succeeded with %d bytes.", (int)writer.BytesFilled());
 	LOG(LogVerbose, "UDPMessageConnection::SendOutPacket: Socket::EndSend succeeded with %d bytes.", (int)writer.BytesFilled());
@@ -662,17 +653,28 @@ void UDPMessageConnection::DoUpdateConnection()
 
 
 		udpUpdateTimer.StartMSecs(10.f);
 		udpUpdateTimer.StartMSecs(10.f);
 	}
 	}
+
+/*
+	if (statsUpdateTimer.TriggeredOrNotRunning())
+	{
+		///\todo Put this behind a timer - update only once every 1 sec or so.
+		ComputePacketLoss();
+		statsUpdateTimer.StartMSecs(1000.f);
+	}
+*/
 }
 }
 
 
 unsigned long UDPMessageConnection::TimeUntilCanSendPacket() const
 unsigned long UDPMessageConnection::TimeUntilCanSendPacket() const
 {
 {
-	tick_t now = Clock::Tick();
+	const tick_t now = Clock::Tick();
 
 
+	// The interval at which we send out datagrams.
 	const tick_t datagramSendTickDelay = (tick_t)(Clock::TicksPerSec() / datagramSendRate);
 	const tick_t datagramSendTickDelay = (tick_t)(Clock::TicksPerSec() / datagramSendRate);
-	tick_t nextDatagramSendTime = lastDatagramSendTime + datagramSendTickDelay;
-	
+
+	const tick_t nextDatagramSendTime = lastDatagramSendTime + datagramSendTickDelay;
+
 	if (Clock::IsNewer(now, nextDatagramSendTime))
 	if (Clock::IsNewer(now, nextDatagramSendTime))
-		return 0;
+		return 0; // We are already due to send out the next datagram?
 
 
 	return (unsigned long)Clock::TimespanToMillisecondsF(now, nextDatagramSendTime);
 	return (unsigned long)Clock::TimespanToMillisecondsF(now, nextDatagramSendTime);
 }
 }
@@ -693,7 +695,7 @@ void UDPMessageConnection::AddReceivedPacketIDStats(packet_id_t packetID)
 //	if (packetID == 0)
 //	if (packetID == 0)
 //		cs.recvPacketIDs.clear();
 //		cs.recvPacketIDs.clear();
 
 
-	cs.recvPacketIDs.Push(ConnectionStatistics::DatagramIDTrack());
+	cs.recvPacketIDs.push_back(ConnectionStatistics::DatagramIDTrack());
 	ConnectionStatistics::DatagramIDTrack &t = cs.recvPacketIDs.back();
 	ConnectionStatistics::DatagramIDTrack &t = cs.recvPacketIDs.back();
 	t.tick = Clock::Tick();
 	t.tick = Clock::Tick();
 	t.packetID = packetID;
 	t.packetID = packetID;
@@ -754,10 +756,11 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 	}
 	}
 
 
 	// Note that this check must be after the ack check (above), since we still need to ack the new packet as well (our
 	// Note that this check must be after the ack check (above), since we still need to ack the new packet as well (our
-	// previous ack might not have reached the sender or was delayed, which is why he's resending it).
+	// previous ack might not have reached the sender or was delayed, which is why the peer is resending it).
 	if (HaveReceivedPacketID(packetID))
 	if (HaveReceivedPacketID(packetID))
 	{
 	{
 		ADDEVENT("duplicateReceived", (float)numBytes, "bytes");
 		ADDEVENT("duplicateReceived", (float)numBytes, "bytes");
+		LOG(LogVerbose, "Duplicate datagram with packet ID %d received!", (int)packetID);
 		return;
 		return;
 	}
 	}
 	if (packetID != previousReceivedPacketID + 1)
 	if (packetID != previousReceivedPacketID + 1)
@@ -806,10 +809,10 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 
 
 			reliableMessageNumber = reliableMessageIndexBase + reader.ReadVLE<VLE8_16>();
 			reliableMessageNumber = reliableMessageIndexBase + reader.ReadVLE<VLE8_16>();
 
 
-			if (receivedReliableMessages.Find(reliableMessageNumber) != receivedReliableMessages.End())
+			if (receivedReliableMessages.find(reliableMessageNumber) != receivedReliableMessages.end())
 				duplicateMessage = true;
 				duplicateMessage = true;
 			else 
 			else 
-				receivedReliableMessages.Insert(reliableMessageNumber);
+				receivedReliableMessages.insert(reliableMessageNumber);
 		}
 		}
 
 
 		if (contentLength == 0)
 		if (contentLength == 0)
@@ -829,53 +832,58 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 			throw NetException("Malformed UDP packet received! Message payload missing.");
 			throw NetException("Malformed UDP packet received! Message payload missing.");
 		}
 		}
 
 
-		// If we received the start of a new fragment, start tracking a new fragmented transfer.
-		if (fragmentStart)
+		if (!duplicateMessage)
 		{
 		{
-			if (numTotalFragments == DataDeserializer::VLEReadError || numTotalFragments <= 1)
+			// If we received the start of a new fragment, start tracking a new fragmented transfer.
+			if (fragmentStart)
 			{
 			{
-				LOG(LogError, "Malformed UDP packet! This packet had fragmentStart bit on, but parsing numTotalFragments VLE failed!");
-				throw NetException("Malformed UDP packet received! This packet had fragmentStart bit on, but parsing numTotalFragments VLE failed!");
-			}
+				if (numTotalFragments == DataDeserializer::VLEReadError || numTotalFragments <= 1)
+				{
+					LOG(LogError, "Malformed UDP packet! This packet had fragmentStart bit on, but parsing numTotalFragments VLE failed!");
+					throw NetException("Malformed UDP packet received! This packet had fragmentStart bit on, but parsing numTotalFragments VLE failed!");
+				}
 
 
-			if (!duplicateMessage)
-			{
 				fragmentedReceives.NewFragmentStartReceived(fragmentTransferID, numTotalFragments, &data[reader.BytePos()], contentLength);
 				fragmentedReceives.NewFragmentStartReceived(fragmentTransferID, numTotalFragments, &data[reader.BytePos()], contentLength);
 				ADDEVENT("FragmentStartReceived", 1, "");
 				ADDEVENT("FragmentStartReceived", 1, "");
-			}
 
 
-		}
-		// If we received a fragment that is a part of an old fragmented transfer, pass it to the fragmented transfer manager
-		// so that it can reconstruct the final stream when the transfer finishes.
-		else if (fragment)
-		{
-			if (fragmentNumber == DataDeserializer::VLEReadError)
-			{
-				LOG(LogError, "Malformed UDP packet! This packet has fragment flag on, but parsing the fragment number failed!");
-				throw NetException("Malformed UDP packet received! This packet has fragment flag on, but parsing the fragment number failed!");
 			}
 			}
+			// If we received a fragment that is a part of an old fragmented transfer, pass it to the fragmented transfer manager
+			// so that it can reconstruct the final stream when the transfer finishes.
+			else if (fragment)
+			{
+				if (fragmentNumber == DataDeserializer::VLEReadError)
+				{
+					LOG(LogError, "Malformed UDP packet! This packet has fragment flag on, but parsing the fragment number failed!");
+					throw NetException("Malformed UDP packet received! This packet has fragment flag on, but parsing the fragment number failed!");
+				}
 
 
-			ADDEVENT("FragmentReceived", 1, "");
+				ADDEVENT("FragmentReceived", 1, "");
 
 
-			bool messageReady = fragmentedReceives.NewFragmentReceived(fragmentTransferID, fragmentNumber, &data[reader.BytePos()], contentLength);
-			if (messageReady)
+				bool messageReady = fragmentedReceives.NewFragmentReceived(fragmentTransferID, fragmentNumber, &data[reader.BytePos()], contentLength);
+				if (messageReady)
+				{
+					// This was the last fragment of the whole message - reconstruct the message from the fragments and pass it on to
+					// the client to handle.
+					assembledData.clear();
+					fragmentedReceives.AssembleMessage(fragmentTransferID, assembledData);
+					assert(assembledData.size() > 0);
+					///\todo InOrder.
+					HandleInboundMessage(packetID, &assembledData[0], assembledData.size());
+					++numMessagesReceived;
+					fragmentedReceives.FreeMessage(fragmentTransferID);
+				}
+			}
+			else
 			{
 			{
-				// This was the last fragment of the whole message - reconstruct the message from the fragments and pass it on to
-				// the client to handle.
-				assembledData.Clear();
-				fragmentedReceives.AssembleMessage(fragmentTransferID, assembledData);
-				assert(assembledData.Size() > 0);
-				///\todo InOrder.
-				HandleInboundMessage(packetID, &assembledData[0], assembledData.Size());
+				// Not a fragment, so directly call the handling code.
+				HandleInboundMessage(packetID, &data[reader.BytePos()], contentLength);
 				++numMessagesReceived;
 				++numMessagesReceived;
-				fragmentedReceives.FreeMessage(fragmentTransferID);
 			}
 			}
 		}
 		}
-		else if (!duplicateMessage)
+		else // this is a duplicate reliable message, ignore it.
 		{
 		{
-			// Not a fragment, so directly call the handling code.
-			HandleInboundMessage(packetID, &data[reader.BytePos()], contentLength);
-			++numMessagesReceived;
+			///\todo Can we remove this duplicate reliable message checking?
+			LOG(LogVerbose, "Received a duplicate reliable message with message number %d!", (int)reliableMessageNumber);
 		}
 		}
 
 
 		reader.SkipBytes(contentLength);
 		reader.SkipBytes(contentLength);
@@ -944,6 +952,31 @@ void UDPMessageConnection::SendDisconnectAckMessage()
 	LOG(LogInfo, "UDPMessageConnection::SendDisconnectAckMessage: Sent DisconnectAck.");
 	LOG(LogInfo, "UDPMessageConnection::SendDisconnectAckMessage: Sent DisconnectAck.");
 }
 }
 
 
+void UDPMessageConnection::HandleFlowControlRequestMessage(const char *data, size_t numBytes)
+{
+	AssertInWorkerThreadContext();
+	/*
+	if (numBytes != 2)
+	{
+		LOG(LogError, "Malformed FlowControlRequest message received! Size was %d bytes, expected 2 bytes!", (int)numBytes);
+		return;
+	}
+
+	const u16 minOutboundRate = 5;
+	const u16 maxOutboundRate = 10 * 1024;
+	u16 newOutboundRate = *reinterpret_cast<const u16*>(data);
+	if (newOutboundRate < minOutboundRate || newOutboundRate > maxOutboundRate)
+	{
+		LOG(LogError, "Invalid FlowControlRequest rate %d packets/sec received! Ignored. Valid range (%d, %d)", (int)newOutboundRate,
+			(int)minOutboundRate, (int)maxOutboundRate);
+		return;
+	}
+
+//	LOG(LogVerbose, "Received FlowControl message. Adjusting OutRate from %d to %d msgs/sec.", (int)datagramOutRatePerSecond, (int)newOutboundRate);
+
+	datagramOutRatePerSecond = newOutboundRate;*/
+}
+
 int UDPMessageConnection::BiasedBinarySearchFindPacketIndex(PacketAckTrackQueue &queue, int packetID)
 int UDPMessageConnection::BiasedBinarySearchFindPacketIndex(PacketAckTrackQueue &queue, int packetID)
 {
 {
 	///\bug Make this all packetID wrap-around -aware.
 	///\bug Make this all packetID wrap-around -aware.
@@ -1009,13 +1042,16 @@ void UDPMessageConnection::FreeOutboundPacketAckTrack(packet_id_t packetID)
 
 
 	if (track.sendCount <= 1)
 	if (track.sendCount <= 1)
 	{
 	{
-		UpdateRTOCounterOnPacketAck((float)Clock::TimespanToMillisecondsD(track.sentTick, Clock::Tick()));
+		UpdateRTOCounterOnPacketAck((float)Clock::TimespanToSecondsD(track.sentTick, Clock::Tick()));
 		++numAcksLastFrame;
 		++numAcksLastFrame;
 	}
 	}
 
 
 	outboundPacketAckTrack.EraseItemAt(itemIndex);
 	outboundPacketAckTrack.EraseItemAt(itemIndex);
 }
 }
 
 
+static const float minRTOTimeoutValue = 1000.f;
+static const float maxRTOTimeoutValue = 5000.f;
+
 /// Adjusts the retransmission timer values as per RFC 2988.
 /// Adjusts the retransmission timer values as per RFC 2988.
 /// @param rtt The round trip time that was measured on the packet that was just acked.
 /// @param rtt The round trip time that was measured on the packet that was just acked.
 void UDPMessageConnection::UpdateRTOCounterOnPacketAck(float rtt)
 void UDPMessageConnection::UpdateRTOCounterOnPacketAck(float rtt)
@@ -1040,9 +1076,20 @@ void UDPMessageConnection::UpdateRTOCounterOnPacketAck(float rtt)
 	}
 	}
 	// We add this much constant delay to all RTO timers to avoid too optimistic RTO values
 	// We add this much constant delay to all RTO timers to avoid too optimistic RTO values
 	// in excellent conditions (localhost, LAN).
 	// in excellent conditions (localhost, LAN).
+	const float safetyThresholdAdd = 1.f;
 	const float safetyThresholdMul = 2.f;
 	const float safetyThresholdMul = 2.f;
 
 
-	retransmissionTimeout = min(maxRTOTimeoutValue, max(minRTOTimeoutValue, safetyThresholdMul * (smoothedRTT + rttVariation)));
+//	retransmissionTimeout = min(maxRTOTimeoutValue, max(minRTOTimeoutValue, safetyThresholdAdd + safetyThresholdMul * (smoothedRTT + rttVariation)));
+	retransmissionTimeout = min(maxRTOTimeoutValue, max(minRTOTimeoutValue, safetyThresholdAdd + safetyThresholdMul * (smoothedRTT + rttVariation)));
+
+///	const float maxDatagramSendRate = 3000.f;
+	// Update data send rate.
+//	++datagramOutRatePerSecond; // Additive increases.
+//	datagramSendRate = datagramSendRate + 1.f; // Increase by one datagram/successfully sent packet.
+//	datagramSendRate = min(datagramSendRate + 1.f, maxDatagramSendRate); // Increase by one datagram/successfully sent packet.
+
+//	LOG(LogVerbose, "Packet ack event: RTO: %.3f sec., srtt: %.3f sec., rttvar: %.3f sec. datagramSendRate: %.2f", 
+//		retransmissionTimeout, smoothedRTT, rttVariation, datagramSendRate);
 }
 }
 
 
 void UDPMessageConnection::UpdateRTOCounterOnPacketLoss()
 void UDPMessageConnection::UpdateRTOCounterOnPacketLoss()
@@ -1051,10 +1098,14 @@ void UDPMessageConnection::UpdateRTOCounterOnPacketLoss()
 
 
 	using namespace std;
 	using namespace std;
 
 
-	// retransmissionTimeout = smoothedRTT = min(maxRTOTimeoutValue, max(minRTOTimeoutValue, smoothedRTT * 2.f));
+	retransmissionTimeout = smoothedRTT = min(maxRTOTimeoutValue, max(minRTOTimeoutValue, smoothedRTT * 2.f));
 	// The variation just gives bogus values, so clear it altogether.
 	// The variation just gives bogus values, so clear it altogether.
 	rttVariation = 0.f;
 	rttVariation = 0.f;
 
 
+	// Multiplicative decreases.
+//	datagramOutRatePerSecond = max(1, datagramOutRatePerSecond / 2);
+//	datagramSendRate = max(1.f, datagramSendRate * 0.9f); // At least send one packet/second.
+
 	++numLossesLastFrame;
 	++numLossesLastFrame;
 
 
 //	LOG(LogVerbose, "Packet loss event: RTO: %.3f sec. datagramSendRate: %.2f", retransmissionTimeout, datagramSendRate);
 //	LOG(LogVerbose, "Packet loss event: RTO: %.3f sec. datagramSendRate: %.2f", retransmissionTimeout, datagramSendRate);
@@ -1064,21 +1115,21 @@ void UDPMessageConnection::SendPacketAckMessage()
 {
 {
 	AssertInWorkerThreadContext();
 	AssertInWorkerThreadContext();
 
 
-	while(inboundPacketAckTrack.Size() > 0)
+	while(inboundPacketAckTrack.size() > 0)
 	{
 	{
-		packet_id_t packetID = inboundPacketAckTrack.Begin()->first_;
+		packet_id_t packetID = inboundPacketAckTrack.begin()->first;
 		u32 sequence = 0;
 		u32 sequence = 0;
 
 
-		inboundPacketAckTrack.Erase(packetID);
+		inboundPacketAckTrack.erase(packetID);
 		for(int i = 0; i < 32; ++i)
 		for(int i = 0; i < 32; ++i)
 		{
 		{
 			packet_id_t id = AddPacketID(packetID, i + 1);
 			packet_id_t id = AddPacketID(packetID, i + 1);
 			
 			
-			PacketAckTrackMap::Iterator iter = inboundPacketAckTrack.Find(id);
-			if (iter != inboundPacketAckTrack.End())
+			PacketAckTrackMap::iterator iter = inboundPacketAckTrack.find(id);
+			if (iter != inboundPacketAckTrack.end())
 			{
 			{
 				sequence |= 1 << i;
 				sequence |= 1 << i;
-				inboundPacketAckTrack.Erase(id);
+				inboundPacketAckTrack.erase(id);
 			}
 			}
 		}
 		}
 
 
@@ -1150,18 +1201,44 @@ void UDPMessageConnection::HandleDisconnectAckMessage()
 		LOG(LogInfo, "Received DisconnectAck message on a MessageConnection not in ConnectionDisconnecting state! (state was %d)",
 		LOG(LogInfo, "Received DisconnectAck message on a MessageConnection not in ConnectionDisconnecting state! (state was %d)",
 		(int)connectionState);
 		(int)connectionState);
 	else
 	else
-		LOG(LogInfo, "UDPMessageConnection::HandleDisconnectAckMessage: Connection closed to %s.", ToString().CString());
+		LOG(LogInfo, "UDPMessageConnection::HandleDisconnectAckMessage: Connection closed to %s.", ToString().c_str());
 
 
 	connectionState = ConnectionClosed;
 	connectionState = ConnectionClosed;
 }
 }
 
 
+void UDPMessageConnection::PerformFlowControl()
+{
+	AssertInWorkerThreadContext();
+
+	/*
+	// The manual flow control only applies to UDP connections.
+	if (socket->TransportLayer() == SocketOverTCP)
+		return;
+
+	const float maxAllowedPacketLossRate = 0.f;
+	if (GetPacketLossRate() > maxAllowedPacketLossRate)
+	{
+		float newInboundRate = PacketsInPerSec() * (1.f - GetPacketLossRate());
+//		LOG(LogVerbose, "Packet loss rate: %.2f. Adjusting InRate from %d to %d!", GetPacketLossRate(), datagramInRatePerSecond, (int)newInboundRate);
+		SetDatagramInFlowRatePerSecond((int)newInboundRate, true);
+	}
+	else if (PacketsInPerSec() >= (float)datagramInRatePerSecond / 2)
+	{
+		const int flowRateIncr = 50;
+//		LOG(LogVerbose, "Have received %.2f packets in/sec with loss rate of %.2f. Increasing InRate from %d to %d.",
+//			PacketsInPerSec(), GetPacketLossRate(), datagramInRatePerSecond, datagramInRatePerSecond + flowRateIncr);
+		SetDatagramInFlowRatePerSecond(datagramInRatePerSecond + flowRateIncr, true);
+	}
+	*/
+}
+
 void UDPMessageConnection::ComputePacketLoss()
 void UDPMessageConnection::ComputePacketLoss()
 {
 {
 	AssertInWorkerThreadContext();
 	AssertInWorkerThreadContext();
 
 
 	Lockable<ConnectionStatistics>::LockType cs = statistics.Acquire();
 	Lockable<ConnectionStatistics>::LockType cs = statistics.Acquire();
 
 
-	if (cs->recvPacketIDs.Size() <= 1)
+	if (cs->recvPacketIDs.size() <= 1)
 	{
 	{
 		packetLossRate = packetLossCount = 0.f;
 		packetLossRate = packetLossCount = 0.f;
 		return;
 		return;
@@ -1172,14 +1249,14 @@ void UDPMessageConnection::ComputePacketLoss()
 	const tick_t maxTickAge = timeNow - maxEntryAge;
 	const tick_t maxTickAge = timeNow - maxEntryAge;
 
 
 	// Remove old entries.
 	// Remove old entries.
-	for(size_t i = 0; i < cs->recvPacketIDs.Size(); ++i)
+	for(size_t i = 0; i < cs->recvPacketIDs.size(); ++i)
 		if (Clock::IsNewer(cs->recvPacketIDs[i].tick, maxTickAge))
 		if (Clock::IsNewer(cs->recvPacketIDs[i].tick, maxTickAge))
 		{
 		{
-			cs->recvPacketIDs.Erase(cs->recvPacketIDs.Begin(), cs->recvPacketIDs.Begin() + i);
+			cs->recvPacketIDs.erase(cs->recvPacketIDs.begin(), cs->recvPacketIDs.begin() + i);
 			break;
 			break;
 		}
 		}
 
 
-	if (cs->recvPacketIDs.Size() <= 1)
+	if (cs->recvPacketIDs.size() <= 1)
 	{
 	{
 		packetLossRate = packetLossCount = 0.f;
 		packetLossRate = packetLossCount = 0.f;
 		return;
 		return;
@@ -1187,34 +1264,56 @@ void UDPMessageConnection::ComputePacketLoss()
 
 
 	// Find the oldest packet (in terms of messageID)
 	// Find the oldest packet (in terms of messageID)
 	int oldestIndex = 0;
 	int oldestIndex = 0;
-	for(size_t i = 1; i < cs->recvPacketIDs.Size(); ++i)
+	for(size_t i = 1; i < cs->recvPacketIDs.size(); ++i)
 		if (PacketIDIsNewerThan(cs->recvPacketIDs[oldestIndex].packetID, cs->recvPacketIDs[i].packetID))
 		if (PacketIDIsNewerThan(cs->recvPacketIDs[oldestIndex].packetID, cs->recvPacketIDs[i].packetID))
 			oldestIndex = i;
 			oldestIndex = i;
 
 
-	Vector<packet_id_t> relIDs;
-	relIDs.Reserve(cs->recvPacketIDs.Size());
-	for(size_t i = 0; i < cs->recvPacketIDs.Size(); ++i)
-		relIDs.Push(SubPacketID(cs->recvPacketIDs[i].packetID, cs->recvPacketIDs[oldestIndex].packetID));
+	std::vector<packet_id_t> relIDs;
+	relIDs.reserve(cs->recvPacketIDs.size());
+	for(size_t i = 0; i < cs->recvPacketIDs.size(); ++i)
+		relIDs.push_back(SubPacketID(cs->recvPacketIDs[i].packetID, cs->recvPacketIDs[oldestIndex].packetID));
 
 
-	sort::CocktailSort(&relIDs[0], relIDs.Size());
+	sort::CocktailSort(&relIDs[0], relIDs.size());
 
 
 	int numMissedPackets = 0;
 	int numMissedPackets = 0;
-	for(size_t i = 0; i+1 < cs->recvPacketIDs.Size(); ++i)
+	for(size_t i = 0; i+1 < cs->recvPacketIDs.size(); ++i)
 	{
 	{
 		assert(relIDs[i+1] > relIDs[i]);
 		assert(relIDs[i+1] > relIDs[i]);
 		numMissedPackets += relIDs[i+1] - relIDs[i] - 1;
 		numMissedPackets += relIDs[i+1] - relIDs[i] - 1;
 	}
 	}
 
 
-	packetLossRate = (float)numMissedPackets / (cs->recvPacketIDs.Size() + numMissedPackets);
+	packetLossRate = (float)numMissedPackets / (cs->recvPacketIDs.size() + numMissedPackets);
 	packetLossCount = (float)numMissedPackets * 1000.f / (float)Clock::TimespanToMillisecondsD(maxTickAge, timeNow);
 	packetLossCount = (float)numMissedPackets * 1000.f / (float)Clock::TimespanToMillisecondsD(maxTickAge, timeNow);
 }
 }
 
 
-void AppendU16ToVector(Vector<char> &data, unsigned long value)
+void AppendU16ToVector(std::vector<char> &data, unsigned long value)
 {
 {
-	data.Insert(data.End(), (const char *)&value, (const char *)&value + 2);
+	data.insert(data.end(), (const char *)&value, (const char *)&value + 2);
+}
+
+void UDPMessageConnection::SetDatagramInFlowRatePerSecond(int newDatagramReceiveRate, bool internalCall)
+{/*
+	if (newDatagramReceiveRate == datagramInRatePerSecond) // No need to set it multiple times.
+		return;
+
+	if (newDatagramReceiveRate < 5 || newDatagramReceiveRate > 10 * 1024)
+	{
+		LOG(LogError, "Tried to set invalid UDP receive rate %d packets/sec! Ignored.", newDatagramReceiveRate);
+		return;
+	}
+	
+	datagramInRatePerSecond = newDatagramReceiveRate;
+
+	NetworkMessage *msg = StartNewMessage(MsgIdFlowControlRequest);
+	AppendU16ToVector(msg->data, newDatagramReceiveRate);
+	msg->priority = NetworkMessage::cMaxPriority - 1;
+#ifdef KNET_NETWORK_PROFILING
+	msg->profilerName = "FlowControlRequest (3)";
+#endif
+	EndAndQueueMessage(msg, 2, internalCall);*/
 }
 }
 
 
-bool UDPMessageConnection::HandleMessage(packet_id_t packetID, u32 messageID, const char *data, size_t numBytes)
+bool UDPMessageConnection::HandleMessage(packet_id_t packetID, message_id_t messageID, const char *data, size_t numBytes)
 {
 {
 	AssertInWorkerThreadContext();
 	AssertInWorkerThreadContext();
 
 
@@ -1224,6 +1323,9 @@ bool UDPMessageConnection::HandleMessage(packet_id_t packetID, u32 messageID, co
 	case MsgIdPingReply:
 	case MsgIdPingReply:
 		return false; // We don't do anything with these messages, the MessageConnection base class handles these.
 		return false; // We don't do anything with these messages, the MessageConnection base class handles these.
 
 
+	case MsgIdFlowControlRequest:
+		HandleFlowControlRequestMessage(data, numBytes);
+		return true;
 	case MsgIdPacketAck:
 	case MsgIdPacketAck:
 		HandlePacketAckMessage(data, numBytes);
 		HandlePacketAckMessage(data, numBytes);
 		return true;
 		return true;
@@ -1270,7 +1372,7 @@ void UDPMessageConnection::DumpConnectionStatus() const
 	smoothedRTT,
 	smoothedRTT,
 	rttVariation,
 	rttVariation,
 	(int)outboundPacketAckTrack.Size(), ///\todo Accessing this variable is not thread-safe.
 	(int)outboundPacketAckTrack.Size(), ///\todo Accessing this variable is not thread-safe.
-	(int)inboundPacketAckTrack.Size(), ///\todo Accessing this variable is not thread-safe.
+	(int)inboundPacketAckTrack.size(), ///\todo Accessing this variable is not thread-safe.
 	packetLossCount,
 	packetLossCount,
 	packetLossRate,
 	packetLossRate,
 	PacketsInPerSec(), 
 	PacketsInPerSec(), 

+ 1 - 1
ThirdParty/kNet/src/boost/BoostThread.cpp

@@ -1,4 +1,4 @@
-/* Copyright 2010 Jukka Jylänki
+/* Copyright The kNet Project.
 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    you may not use this file except in compliance with the License.

+ 3 - 2
ThirdParty/kNet/src/qt/GraphDialog.cpp

@@ -1,4 +1,4 @@
-/* Copyright 2010 Jukka Jylänki
+/* Copyright The kNet Project.
 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
 #include <QTreeWidget>
 #include <QTreeWidget>
 #include <QPainter>
 #include <QPainter>
 #include <sstream>
 #include <sstream>
+#include <algorithm>
 
 
 #ifdef KNET_USE_BOOST
 #ifdef KNET_USE_BOOST
 #include <boost/thread/thread.hpp>
 #include <boost/thread/thread.hpp>
@@ -77,7 +78,7 @@ void GraphDialog::Update(StatsEventHierarchyNode &node, int timeMSecs)
 		{
 		{
 			StatsEvent *e = node.events.ItemAt(i);
 			StatsEvent *e = node.events.ItemAt(i);
 			if (Clock::IsNewer(e->time, leftX) && Clock::IsNewer(rightX, e->time))
 			if (Clock::IsNewer(e->time, leftX) && Clock::IsNewer(rightX, e->time))
-				maxY = max(maxY, e->value);
+				maxY = std::max(maxY, e->value);
 		}
 		}
 
 
 		painter.setPen(QPen(QColor(0,0,0)));
 		painter.setPen(QPen(QColor(0,0,0)));

+ 14 - 1
ThirdParty/kNet/src/qt/MessageConnectionDialog.cpp

@@ -1,4 +1,4 @@
-/* Copyright 2010 Jukka Jylänki
+/* Copyright The kNet Project.
 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
 #include "kNet/UDPMessageConnection.h"
 #include "kNet/UDPMessageConnection.h"
 
 
 #include "kNet/qt/MessageConnectionDialog.h"
 #include "kNet/qt/MessageConnectionDialog.h"
+#include "kNet/qt/NetworkSimulationDialog.h"
 #include "kNet/qt/ui/ui_MessageConnectionDialog.h"
 #include "kNet/qt/ui/ui_MessageConnectionDialog.h"
 
 
 namespace kNet
 namespace kNet
@@ -51,6 +52,7 @@ MessageConnectionDialog::MessageConnectionDialog(QWidget *parent, Ptr(MessageCon
 		dialog->labelDatagramsOut->setText("# send() calls:");
 		dialog->labelDatagramsOut->setText("# send() calls:");
 	}
 	}
 
 
+	connect(dialog->pushButtonSendSimulation, SIGNAL(pressed()), this, SLOT(OpenSendSimulationWindow()));
 	Update();
 	Update();
 }
 }
 
 
@@ -125,4 +127,15 @@ void MessageConnectionDialog::Update()
 	QTimer::singleShot(dialogUpdateInterval, this, SLOT(Update()));
 	QTimer::singleShot(dialogUpdateInterval, this, SLOT(Update()));
 }
 }
 
 
+void MessageConnectionDialog::OpenSendSimulationWindow()
+{
+	if (connection)
+	{
+		NetworkSimulationDialog *dialog = new NetworkSimulationDialog(0, connection);
+		dialog->setWindowTitle(QString("Outbound connection to ") + connection->RemoteEndPoint().ToString().c_str());
+		dialog->show();
+		dialog->setAttribute(Qt::WA_DeleteOnClose);
+	}
+}
+
 } // ~kNet
 } // ~kNet

+ 4 - 2
ThirdParty/kNet/src/qt/NetworkDialog.cpp

@@ -1,4 +1,4 @@
-/* Copyright 2010 Jukka Jylänki
+/* Copyright The kNet Project.
 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    you may not use this file except in compliance with the License.
@@ -303,7 +303,9 @@ void NetworkDialog::PopulateStatsTree()
 		}
 		}
 		else
 		else
 		{
 		{
-			iter = graphs.erase(iter);
+         GraphMap::iterator next = iter;
+			graphs.erase(iter);
+         iter = next;
 		}
 		}
 	}
 	}
 }
 }

+ 90 - 0
ThirdParty/kNet/src/qt/NetworkSimulationDialog.cpp

@@ -0,0 +1,90 @@
+/* Copyright The kNet Project.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License. */
+
+/** @file MessageConnectionDialog.cpp
+	@brief */
+
+#include "kNet/qt/NetworkSimulationDialog.h"
+#include "kNet/qt/ui/ui_NetworkSimulationDialog.h"
+
+namespace kNet
+{
+
+NetworkSimulationDialog::NetworkSimulationDialog(QWidget *parent, Ptr(MessageConnection) connection_)
+:connection(connection_), QWidget(parent)
+{
+	dialog = new Ui_NetworkSimulationDialog;
+	dialog->setupUi(this);
+
+	NetworkSimulator &s = connection->NetworkSendSimulator();
+
+	dialog->labelConnectionName->setText(connection->ToString().c_str());
+	dialog->checkBoxPacketDelayEnabled->setChecked(s.enabled && (s.constantPacketSendDelay > 0 || s.uniformRandomPacketSendDelay > 0));
+	dialog->checkBoxPacketLossEnabled->setChecked(s.enabled && s.packetLossRate > 0);
+	dialog->spinBoxConstantDelay->setValue(s.constantPacketSendDelay);
+	dialog->spinBoxRandomDelay->setValue(s.uniformRandomPacketSendDelay);
+	dialog->spinBoxUniformLoss->setValue(s.packetLossRate * 100.f);
+
+	connect(dialog->checkBoxPacketDelayEnabled, SIGNAL(toggled(bool)), this, SLOT(ParameterChanged()));
+	connect(dialog->checkBoxPacketLossEnabled, SIGNAL(toggled(bool)), this, SLOT(ParameterChanged()));
+	connect(dialog->checkBoxPacketDuplicationEnabled, SIGNAL(toggled(bool)), this, SLOT(ParameterChanged()));
+	connect(dialog->checkBoxPacketCorruptionEnabled, SIGNAL(toggled(bool)), this, SLOT(ParameterChanged()));
+	connect(dialog->checkBoxCorruptPayload, SIGNAL(toggled(bool)), this, SLOT(ParameterChanged()));
+	connect(dialog->checkBoxBurstsEnabled, SIGNAL(toggled(bool)), this, SLOT(ParameterChanged()));
+	connect(dialog->spinBoxConstantDelay, SIGNAL(valueChanged(int)), this, SLOT(ParameterChanged()));
+	connect(dialog->spinBoxRandomDelay, SIGNAL(valueChanged(int)), this, SLOT(ParameterChanged()));
+	connect(dialog->spinBoxNormalMean, SIGNAL(valueChanged(int)), this, SLOT(ParameterChanged()));
+	connect(dialog->doubleSpinBoxNormalVar, SIGNAL(valueChanged(double)), this, SLOT(ParameterChanged()));
+	connect(dialog->spinBoxUniformLoss, SIGNAL(valueChanged(int)), this, SLOT(ParameterChanged()));
+	connect(dialog->spinBoxUniformDuplication, SIGNAL(valueChanged(int)), this, SLOT(ParameterChanged()));
+	connect(dialog->spinBoxToggleBitsPr, SIGNAL(valueChanged(int)), this, SLOT(ParameterChanged()));
+	connect(dialog->spinBoxBitsMin, SIGNAL(valueChanged(int)), this, SLOT(ParameterChanged()));
+	connect(dialog->spinBoxBitsMax, SIGNAL(valueChanged(int)), this, SLOT(ParameterChanged()));
+	connect(dialog->spinBoxBurstInterval, SIGNAL(valueChanged(int)), this, SLOT(ParameterChanged()));
+	connect(dialog->spinBoxBurstLength, SIGNAL(valueChanged(int)), this, SLOT(ParameterChanged()));
+}
+
+NetworkSimulationDialog::~NetworkSimulationDialog()
+{
+	delete dialog;
+}
+
+void NetworkSimulationDialog::ParameterChanged()
+{
+	if (!connection)
+		return;
+	
+	NetworkSimulator &s = connection->NetworkSendSimulator();
+	s.enabled = dialog->checkBoxPacketDelayEnabled->isChecked() || dialog->checkBoxPacketLossEnabled->isChecked()
+		|| dialog->checkBoxPacketCorruptionEnabled->isChecked() || dialog->checkBoxPacketDuplicationEnabled->isChecked();
+
+	if (dialog->checkBoxPacketDelayEnabled->isChecked())
+	{
+		s.constantPacketSendDelay = dialog->spinBoxConstantDelay->value();
+		s.uniformRandomPacketSendDelay = dialog->spinBoxRandomDelay->value();
+	}
+	else
+	{
+		s.constantPacketSendDelay = 0;
+		s.uniformRandomPacketSendDelay = 0;
+	}
+
+	if (dialog->checkBoxPacketLossEnabled->isChecked())
+		s.packetLossRate = dialog->spinBoxUniformLoss->value() / 100.f;
+	else
+		s.packetLossRate = 0;
+}
+
+
+} // ~kNet

+ 1 - 1
ThirdParty/kNet/src/unix/UnixClock.cpp

@@ -1,4 +1,4 @@
-/* Copyright 2010 Jukka Jylänki
+/* Copyright The kNet Project.
 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    you may not use this file except in compliance with the License.

+ 1 - 1
ThirdParty/kNet/src/unix/UnixEvent.cpp

@@ -1,4 +1,4 @@
-/* Copyright 2010 Jukka Jylänki
+/* Copyright The kNet Project.
 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    you may not use this file except in compliance with the License.

+ 26 - 9
ThirdParty/kNet/src/unix/UnixEventArray.cpp

@@ -1,4 +1,4 @@
-/* Copyright 2010 Jukka Jylänki
+/* Copyright The kNet Project.
 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    you may not use this file except in compliance with the License.
@@ -15,11 +15,8 @@
 /** @file UnixEventArray.cpp
 /** @file UnixEventArray.cpp
 	@brief */
 	@brief */
 
 
-// Modified by Lasse Öörni for Urho3D
-
 #include <cassert>
 #include <cassert>
 #include <utility>
 #include <utility>
-#include <algorithm>
 
 
 #include <sys/time.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <sys/types.h>
@@ -28,6 +25,7 @@
 #include <string.h>
 #include <string.h>
 
 
 #include "kNet/EventArray.h"
 #include "kNet/EventArray.h"
+#include "kNet/Thread.h"
 #include "kNet/NetworkLogging.h"
 #include "kNet/NetworkLogging.h"
 
 
 using namespace std;
 using namespace std;
@@ -42,7 +40,7 @@ EventArray::EventArray()
 
 
 int EventArray::Size() const
 int EventArray::Size() const
 {
 {
-	return cachedEvents.Size();
+	return cachedEvents.size();
 }
 }
 
 
 void EventArray::Clear()
 void EventArray::Clear()
@@ -51,7 +49,7 @@ void EventArray::Clear()
 	FD_ZERO(&writefds);
 	FD_ZERO(&writefds);
 	nfds = -1;
 	nfds = -1;
 	numAdded = 0;
 	numAdded = 0;
-	cachedEvents.Clear();
+	cachedEvents.clear();
 }
 }
 
 
 void EventArray::AddEvent(const Event &e)
 void EventArray::AddEvent(const Event &e)
@@ -65,21 +63,26 @@ void EventArray::AddEvent(const Event &e)
 
 
 	switch(e.Type())
 	switch(e.Type())
 	{
 	{
+	case EventWaitInvalid:
+		LOG(LogError, "Error: Tried to add an invalid event to a wait event array!");
+		return;
 	case EventWaitRead:
 	case EventWaitRead:
 	case EventWaitSignal:
 	case EventWaitSignal:
 		FD_SET(e.fd[0], &readfds);
 		FD_SET(e.fd[0], &readfds);
 		nfds = max(nfds, e.fd[0]+1);
 		nfds = max(nfds, e.fd[0]+1);
+		assert(nfds > 0);
 		break;
 		break;
 	case EventWaitWrite: // The Event represents write-availability of the socket, in which case, e.fd[0] is the socket (e.fd[1] is left unused)
 	case EventWaitWrite: // The Event represents write-availability of the socket, in which case, e.fd[0] is the socket (e.fd[1] is left unused)
 		FD_SET(e.fd[0], &writefds);
 		FD_SET(e.fd[0], &writefds);
 		nfds = max(nfds, e.fd[0]+1);
 		nfds = max(nfds, e.fd[0]+1);
+		assert(nfds > 0);
 	default:
 	default:
 		break;
 		break;
 	}
 	}
 
 
 	// No need to add dummy events to select(), but need to add them to the cached events list to keep
 	// No need to add dummy events to select(), but need to add them to the cached events list to keep
 	// the indices matching.
 	// the indices matching.
-	cachedEvents.Push(e);
+	cachedEvents.push_back(e);
 	++numAdded;
 	++numAdded;
 }
 }
 
 
@@ -91,13 +94,27 @@ int EventArray::Wait(int msecs)
 		return WaitFailed;
 		return WaitFailed;
 	}
 	}
 
 
+	// If we have added some number of events to the event array, but nfds == -1, it means we are waiting on a set
+	// of dummy events, which are always false. In that case, sleep for a small arbitrary duration and return a timeout.
+	// Note that it's a bad idea to wait for the full msecs delay, since it can be very large, and would effectively 
+	// stall this thread.
+	if (nfds == -1)
+	{
+		if (msecs > 0)
+			Thread::Sleep(min(msecs, 10)); // Arbitrary max sleep 10 msecs.
+		return WaitTimedOut;
+	}
+
 	tv.tv_sec = msecs / 1000;
 	tv.tv_sec = msecs / 1000;
 	tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
 	tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000;
 
 
 	int ret = select(nfds, &readfds, &writefds, NULL, &tv); // http://linux.die.net/man/2/select
 	int ret = select(nfds, &readfds, &writefds, NULL, &tv); // http://linux.die.net/man/2/select
 	if (ret == -1)
 	if (ret == -1)
 	{
 	{
-		LOG(LogError, "EventArray::Wait: select() failed: %s(%d)", strerror(errno), (int)errno);
+		LOG(LogError, "EventArray::Wait(%d, %p, %p, NULL, {%d, %d}: select() failed on an array of %d events: %s(%d)", 
+			(int)nfds, &readfds, &writefds, (int)tv.tv_sec, (int)tv.tv_usec,
+			numAdded,
+			strerror(errno), (int)errno);
 		return WaitFailed;
 		return WaitFailed;
 	}
 	}
 
 
@@ -111,7 +128,7 @@ int EventArray::Wait(int msecs)
 		return WaitFailed;
 		return WaitFailed;
 	}
 	}
 
 
-	for(int i = 0; i < cachedEvents.Size(); ++i)
+	for(int i = 0; i < cachedEvents.size(); ++i)
 		switch(cachedEvents[i].Type())
 		switch(cachedEvents[i].Type())
 		{
 		{
 		case EventWaitRead:
 		case EventWaitRead:

+ 2 - 2
ThirdParty/kNet/src/unix/UnixThread.cpp

@@ -1,4 +1,4 @@
-/* Copyright 2010 Jukka Jylänki
+/* Copyright The kNet Project.
 
 
    Licensed under the Apache License, Version 2.0 (the "License");
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    you may not use this file except in compliance with the License.
@@ -84,7 +84,7 @@ void Thread::Stop()
 
 
 void* ThreadEntryPoint(void* data)
 void* ThreadEntryPoint(void* data)
 {
 {
-	LOG(LogInfo, "ThreadEntryPoint: Thread started with param 0x%08X.", (unsigned)data);
+	LOG(LogInfo, "ThreadEntryPoint: Thread started with param 0x%p.", data);
 
 
 	Thread *thread = reinterpret_cast<Thread*>(data);
 	Thread *thread = reinterpret_cast<Thread*>(data);
 	if (!thread)
 	if (!thread)

+ 1 - 1
ThirdParty/kNet/src/win32/W32Clock.cpp

@@ -23,7 +23,7 @@
 #include "kNet/NetworkLogging.h"
 #include "kNet/NetworkLogging.h"
 
 
 #define NOMINMAX
 #define NOMINMAX
-#include <Windows.h>
+#include <windows.h>
 
 
 namespace kNet
 namespace kNet
 {
 {