Josh Engebretson 11 years ago
parent
commit
12efdcac5b
91 changed files with 1769 additions and 1695 deletions
  1. 1 1
      Bin/CoreData/Shaders/GLSL/Lighting.glsl
  2. 1 1
      Bin/CoreData/Shaders/HLSL/Lighting.hlsl
  3. 1 1
      CMake/Modules/AtomicAndroid.cmake
  4. 1 1
      CMake/Modules/AtomicApple.cmake
  5. 2 3
      Source/Atomic/Atomic2D/AnimatedSprite2D.cpp
  6. 1 1
      Source/Atomic/Atomic2D/AnimatedSprite2D.h
  7. 3 6
      Source/Atomic/Atomic2D/Drawable2D.cpp
  8. 1 7
      Source/Atomic/Atomic2D/Drawable2D.h
  9. 14 14
      Source/Atomic/Atomic2D/ParticleEffect2D.cpp
  10. 2 2
      Source/Atomic/Atomic2D/PhysicsEvents2D.h
  11. 2 2
      Source/Atomic/Atomic2D/PhysicsWorld2D.cpp
  12. 66 55
      Source/Atomic/Atomic2D/Renderer2D.cpp
  13. 13 8
      Source/Atomic/Atomic2D/Renderer2D.h
  14. 11 1
      Source/Atomic/Atomic2D/StaticSprite2D.cpp
  15. 5 1
      Source/Atomic/Atomic2D/StaticSprite2D.h
  16. 47 11
      Source/Atomic/Container/ForEach.h
  17. 4 1
      Source/Atomic/Container/HashMap.h
  18. 3 1
      Source/Atomic/Container/Vector.h
  19. 5 10
      Source/Atomic/Graphics/Batch.cpp
  20. 97 108
      Source/Atomic/Graphics/Direct3D9/D3D9Graphics.cpp
  21. 9 7
      Source/Atomic/Graphics/Direct3D9/D3D9Graphics.h
  22. 7 15
      Source/Atomic/Graphics/Direct3D9/D3D9ShaderVariation.cpp
  23. 5 1
      Source/Atomic/Graphics/GraphicsEvents.h
  24. 33 4
      Source/Atomic/Graphics/Material.cpp
  25. 10 2
      Source/Atomic/Graphics/Material.h
  26. 9 7
      Source/Atomic/Graphics/OpenGL/OGLGraphics.cpp
  27. 2 2
      Source/Atomic/Graphics/OpenGL/OGLGraphics.h
  28. 3 13
      Source/Atomic/Graphics/Renderer.cpp
  29. 18 2
      Source/Atomic/Graphics/View.cpp
  30. 3 1
      Source/Atomic/Graphics/View.h
  31. 38 4
      Source/Atomic/Physics/CollisionShape.cpp
  32. 4 4
      Source/Atomic/Physics/CollisionShape.h
  33. 15 11
      Source/Atomic/UI/UI.cpp
  34. 2 2
      Source/Atomic/UI/UI.h
  35. 6 4
      Source/ThirdParty/Bullet/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp
  36. 4 0
      Source/ThirdParty/SDL/src/video/uikit/SDL_uikitwindow.m
  37. 64 66
      Source/ThirdParty/kNet/CMakeLists.txt
  38. 46 46
      Source/ThirdParty/kNet/LICENSE.txt
  39. 1 1
      Source/ThirdParty/kNet/include/kNet/Alignment.h
  40. 2 2
      Source/ThirdParty/kNet/include/kNet/Allocator.h
  41. 3 0
      Source/ThirdParty/kNet/include/kNet/Atomics.h
  42. 3 0
      Source/ThirdParty/kNet/include/kNet/BasicSerializedDataTypes.h
  43. 2 2
      Source/ThirdParty/kNet/include/kNet/DataDeserializer.h
  44. 7 4
      Source/ThirdParty/kNet/include/kNet/DataSerializer.h
  45. 1 1
      Source/ThirdParty/kNet/include/kNet/EndPoint.h
  46. 1 1
      Source/ThirdParty/kNet/include/kNet/Event.h
  47. 4 5
      Source/ThirdParty/kNet/include/kNet/EventArray.h
  48. 3 0
      Source/ThirdParty/kNet/include/kNet/FragmentedTransferManager.h
  49. 9 5
      Source/ThirdParty/kNet/include/kNet/MaxHeap.h
  50. 5 4
      Source/ThirdParty/kNet/include/kNet/MessageConnection.h
  51. 2 2
      Source/ThirdParty/kNet/include/kNet/MessageListParser.h
  52. 30 5
      Source/ThirdParty/kNet/include/kNet/NetworkLogging.h
  53. 4 5
      Source/ThirdParty/kNet/include/kNet/NetworkMessage.h
  54. 104 103
      Source/ThirdParty/kNet/include/kNet/NetworkSimulator.h
  55. 2 0
      Source/ThirdParty/kNet/include/kNet/NetworkWorkerThread.h
  56. 3 3
      Source/ThirdParty/kNet/include/kNet/PolledTimer.h
  57. 3 0
      Source/ThirdParty/kNet/include/kNet/SequentialIntegerSet.h
  58. 5 5
      Source/ThirdParty/kNet/include/kNet/SharedPtr.h
  59. 11 3
      Source/ThirdParty/kNet/include/kNet/Sort.h
  60. 3 1
      Source/ThirdParty/kNet/include/kNet/SortCmp.h
  61. 6 1
      Source/ThirdParty/kNet/include/kNet/Types.h
  62. 1 1
      Source/ThirdParty/kNet/include/kNet/UDPMessageConnection.h
  63. 10 10
      Source/ThirdParty/kNet/include/kNet/VLEPacker.h
  64. 10 5
      Source/ThirdParty/kNet/include/kNet/WaitFreeQueue.h
  65. 147 144
      Source/ThirdParty/kNet/include/kNet/win32/WS2Include.h
  66. 253 254
      Source/ThirdParty/kNet/src/Clock.cpp
  67. 2 1
      Source/ThirdParty/kNet/src/DataDeserializer.cpp
  68. 4 4
      Source/ThirdParty/kNet/src/DataSerializer.cpp
  69. 15 15
      Source/ThirdParty/kNet/src/FragmentedTransferManager.cpp
  70. 61 57
      Source/ThirdParty/kNet/src/MessageConnection.cpp
  71. 5 5
      Source/ThirdParty/kNet/src/MessageListParser.cpp
  72. 83 82
      Source/ThirdParty/kNet/src/Network.cpp
  73. 1 1
      Source/ThirdParty/kNet/src/NetworkLogging.cpp
  74. 9 5
      Source/ThirdParty/kNet/src/NetworkMessage.cpp
  75. 46 43
      Source/ThirdParty/kNet/src/NetworkServer.cpp
  76. 134 133
      Source/ThirdParty/kNet/src/NetworkSimulator.cpp
  77. 20 24
      Source/ThirdParty/kNet/src/NetworkWorkerThread.cpp
  78. 1 3
      Source/ThirdParty/kNet/src/SerializationStructCompiler.cpp
  79. 3 3
      Source/ThirdParty/kNet/src/SerializedDataIterator.cpp
  80. 69 67
      Source/ThirdParty/kNet/src/Socket.cpp
  81. 12 12
      Source/ThirdParty/kNet/src/TCPMessageConnection.cpp
  82. 3 3
      Source/ThirdParty/kNet/src/Thread.cpp
  83. 50 52
      Source/ThirdParty/kNet/src/UDPMessageConnection.cpp
  84. 3 2
      Source/ThirdParty/kNet/src/boost/BoostThread.cpp
  85. 0 142
      Source/ThirdParty/kNet/src/unix/UnixClock.cpp
  86. 13 13
      Source/ThirdParty/kNet/src/unix/UnixEvent.cpp
  87. 6 6
      Source/ThirdParty/kNet/src/unix/UnixEventArray.cpp
  88. 12 8
      Source/ThirdParty/kNet/src/unix/UnixThread.cpp
  89. 6 3
      Source/ThirdParty/kNet/src/win32/W32Event.cpp
  90. 4 4
      Source/ThirdParty/kNet/src/win32/W32EventArray.cpp
  91. 14 14
      Source/ThirdParty/kNet/src/win32/W32Thread.cpp

+ 1 - 1
Bin/CoreData/Shaders/GLSL/Lighting.glsl

@@ -113,7 +113,7 @@ float GetSpecular(vec3 normal, vec3 eyeVec, vec3 lightDir, float specularPower)
 
 float GetIntensity(vec3 color)
 {
-    return dot(color, vec3(0.333));
+    return dot(color, vec3(0.299, 0.587, 0.114));
 }
 
 #ifdef SHADOW

+ 1 - 1
Bin/CoreData/Shaders/HLSL/Lighting.hlsl

@@ -126,7 +126,7 @@ float GetSpecular(float3 normal, float3 eyeVec, float3 lightDir, float specularP
 
 float GetIntensity(float3 color)
 {
-    return dot(color, float3(0.333, 0.333, 0.333));
+    return dot(color, float3(0.299, 0.587, 0.114));
 }
 
 #ifdef SHADOW

+ 1 - 1
CMake/Modules/AtomicAndroid.cmake

@@ -1,7 +1,7 @@
 
 
 add_definitions(-DATOMIC_PLATFORM_ANDROID)
-add_definitions(-DATOMIC_OPENGL)
+add_definitions(-DATOMIC_OPENGL -DKNET_UNIX)
 
 set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector")
 set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof -std=gnu++0x -fstack-protector")

+ 1 - 1
CMake/Modules/AtomicApple.cmake

@@ -2,7 +2,7 @@
 include (BundleUtilities)
 include(AtomicDesktop)
 
-add_definitions(-DATOMIC_PLATFORM_OSX -DATOMIC_OPENGL)
+add_definitions(-DATOMIC_PLATFORM_OSX -DATOMIC_OPENGL -DKNET_UNIX)
 
 list (APPEND ATOMIC_LINK_LIBRARIES GLEW)
 

+ 2 - 3
Source/Atomic/Atomic2D/AnimatedSprite2D.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -459,14 +459,13 @@ void AnimatedSprite2D::UpdateAnimation(float timeStep)
                 {
                     staticSprite->SetOrderInLayer(orderInLayer_ + nodeInfo.value.zIndex_);
                     staticSprite->SetSprite(nodeInfo.value.sprite_);
+                    staticSprite->SetAlpha(nodeInfo.value.alpha_);
                     staticSprite->SetUseHotSpot(nodeInfo.value.useHotSpot_);
                     staticSprite->SetHotSpot(nodeInfo.value.hotSpot_);
                 }
             }
         }
     }
-
-    MarkForUpdate();
 }
 
 void AnimatedSprite2D::CalculateTimelineWorldTransform(unsigned index)

+ 1 - 1
Source/Atomic/Atomic2D/AnimatedSprite2D.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal

+ 3 - 6
Source/Atomic/Atomic2D/Drawable2D.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -42,8 +42,7 @@ Drawable2D::Drawable2D(Context* context) :
     layer_(0),
     orderInLayer_(0),
     blendMode_(BLEND_ALPHA),
-    verticesDirty_(true),
-    visibility_(true)
+    verticesDirty_(true)
 {
 }
 
@@ -182,9 +181,7 @@ void Drawable2D::OnNodeSet(Node* node)
         Scene* scene = GetScene();
         if (scene)
         {
-            if (renderer_.Null())
-                renderer_ = scene->GetOrCreateComponent<Renderer2D>();
-
+            renderer_ = scene->GetOrCreateComponent<Renderer2D>();
             if (IsEnabledEffective())
                 renderer_->AddDrawable(this);
         }

+ 1 - 7
Source/Atomic/Atomic2D/Drawable2D.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -90,10 +90,6 @@ public:
     void SetMaterial(Material* material);
     /// Return custom material or material (called by Renderer2D).
     Material* GetMaterial() const;
-    /// Set visibility (called by Renderer2D).
-    void SetVisibility(bool visibility) { visibility_ = visibility; }
-    /// Return visibility (called by Renderer2D).
-    bool GetVisibility() const { return visibility_; }
     /// Return all vertices (called by Renderer2D).
     const Vector<Vertex2D>& GetVertices();
 
@@ -129,8 +125,6 @@ protected:
     SharedPtr<Material> material_;
     /// Renderer2D.
     WeakPtr<Renderer2D> renderer_;
-    /// Test visible.
-    bool visibility_;
 };
 
 }

+ 14 - 14
Source/Atomic/Atomic2D/ParticleEffect2D.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -285,7 +285,7 @@ bool ParticleEffect2D::Save(Serializer& dest) const
     WriteFloat(rootElem, "rotationEnd", rotationEnd_);
     WriteFloat(rootElem, "rotationEndVariance", rotationEndVariance_);
 
-	return xmlFile.Save(dest);
+    return xmlFile.Save(dest);
 }
 
 void ParticleEffect2D::SetSprite(Sprite2D* sprite)
@@ -487,30 +487,30 @@ Vector2 ParticleEffect2D::ReadVector2(const XMLElement& element, const String& n
 
 void ParticleEffect2D::WriteInt(XMLElement& element, const String& name, int value) const
 {
-	XMLElement child = element.CreateChild(name);
-	child.SetInt("value", value);
+    XMLElement child = element.CreateChild(name);
+    child.SetInt("value", value);
 }
 
 void ParticleEffect2D::WriteFloat(XMLElement& element, const String& name, float value) const
 {
-	XMLElement child = element.CreateChild(name);
-	child.SetFloat("value", value);
+    XMLElement child = element.CreateChild(name);
+    child.SetFloat("value", value);
 }
 
 void ParticleEffect2D::WriteColor(XMLElement& element, const String& name, const Color& color) const
 {
-	XMLElement child = element.CreateChild(name);
-	child.SetFloat("red", color.r_);
-	child.SetFloat("green", color.g_);
-	child.SetFloat("blue", color.b_);
-	child.SetFloat("alpha", color.a_);
+    XMLElement child = element.CreateChild(name);
+    child.SetFloat("red", color.r_);
+    child.SetFloat("green", color.g_);
+    child.SetFloat("blue", color.b_);
+    child.SetFloat("alpha", color.a_);
 }
 
 void ParticleEffect2D::WriteVector2(XMLElement& element,const String& name,const Vector2& value) const
 {
-	XMLElement child = element.CreateChild(name);
-	child.SetFloat("x", value.x_);
-	child.SetFloat("y", value.y_);
+    XMLElement child = element.CreateChild(name);
+    child.SetFloat("x", value.x_);
+    child.SetFloat("y", value.y_);
 }
 
 }

+ 2 - 2
Source/Atomic/Atomic2D/PhysicsEvents2D.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -28,7 +28,7 @@ namespace Atomic
 {
 
 /// Physics world is about to be stepped.
-EVENT(E_PHYSICSPRESTEP2D, Physics2DPreStep2D)
+EVENT(E_PHYSICSPRESTEP2D, PhysicsPreStep2D)
 {
     PARAM(P_WORLD, World);                  // PhysicsWorld2D pointer
     PARAM(P_TIMESTEP, TimeStep);            // float

+ 2 - 2
Source/Atomic/Atomic2D/PhysicsWorld2D.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -224,7 +224,7 @@ void PhysicsWorld2D::DrawTransform(const b2Transform& xf)
 
 void PhysicsWorld2D::Update(float timeStep)
 {
-    using namespace Physics2DPreStep2D;
+    using namespace PhysicsPreStep2D;
 
     VariantMap& eventData = GetEventDataMap();
     eventData[P_WORLD] = this;

+ 66 - 55
Source/Atomic/Atomic2D/Renderer2D.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -37,6 +37,7 @@
 #include "../Graphics/Technique.h"
 #include "../Graphics/Texture2D.h"
 #include "../Graphics/VertexBuffer.h"
+#include "../Graphics/View.h"
 #include "../Core/WorkQueue.h"
 
 #include "../DebugNew.h"
@@ -52,10 +53,10 @@ Renderer2D::Renderer2D(Context* context) :
     vertexBuffer_(new VertexBuffer(context_)),
     orderDirty_(true),
     frustum_(0),
-    indexCount_(0),
-    vertexCount_(0),
-    useTris_(false)
+    useTris_(false),
+    geometryCount_(0)
 {
+    frame_.frameNumber_ = 0;
     SubscribeToEvent(E_BEGINVIEWUPDATE, HANDLER(Renderer2D, HandleBeginViewUpdate));
 }
 
@@ -115,15 +116,18 @@ void Renderer2D::UpdateBatches(const FrameInfo& frame)
 
 void Renderer2D::UpdateGeometry(const FrameInfo& frame)
 {
+    unsigned& vertexCount = vertexCount_[frame.camera_];
+    unsigned& indexCount = indexCount_[frame.camera_];
+
     // Fill index buffer
-    if (indexBuffer_->GetIndexCount() < indexCount_ || indexBuffer_->IsDataLost())
+    if (indexBuffer_->GetIndexCount() < indexCount || indexBuffer_->IsDataLost())
     {
-        bool largeIndices = vertexCount_ > 0xffff;
-        indexBuffer_->SetSize(indexCount_, largeIndices);
-        void* buffer = indexBuffer_->Lock(0, indexCount_, true);
+        bool largeIndices = vertexCount > 0xffff;
+        indexBuffer_->SetSize(indexCount, largeIndices);
+        void* buffer = indexBuffer_->Lock(0, indexCount, true);
         if (buffer)
         {
-            unsigned quadCount =  useTris_ ? indexCount_/3 : indexCount_ / 6;
+            unsigned quadCount =  useTris_ ? indexCount/3 : indexCount / 6;
             if (largeIndices)
             {
                 unsigned* dest = reinterpret_cast<unsigned*>(buffer);
@@ -174,17 +178,17 @@ void Renderer2D::UpdateGeometry(const FrameInfo& frame)
         }
     }
 
-    if (vertexBuffer_->GetVertexCount() < vertexCount_)
-        vertexBuffer_->SetSize(vertexCount_, MASK_VERTEX2D);
+    if (vertexBuffer_->GetVertexCount() < vertexCount)
+        vertexBuffer_->SetSize(vertexCount, MASK_VERTEX2D);
 
-    if (vertexCount_)
+    if (vertexCount)
     {
-        Vertex2D* dest = reinterpret_cast<Vertex2D*>(vertexBuffer_->Lock(0, vertexCount_, true));
+        Vertex2D* dest = reinterpret_cast<Vertex2D*>(vertexBuffer_->Lock(0, vertexCount, true));
         if (dest)
         {
             for (unsigned d = 0; d < drawables_.Size(); ++d)
             {
-                if (!drawables_[d]->GetVisibility() || drawables_[d]->GetVertices().Empty())
+                if (!drawables_[d]->IsInView(frame) || drawables_[d]->GetVertices().Empty())
                     continue;
 
                 const Vector<Vertex2D>& vertices = drawables_[d]->GetVertices();
@@ -222,12 +226,23 @@ void Renderer2D::RemoveDrawable(Drawable2D* drawable)
         return;
 
     drawables_.Remove(drawable);
-    materialDirtyDrawables_.Remove(drawable);
+
+    // Drawable may be on the dirty list multiple times; remove all instances
+    for (;;)
+    {
+        PODVector<Drawable2D*>::Iterator i = materialDirtyDrawables_.Find(drawable);
+        if (i != materialDirtyDrawables_.End())
+            materialDirtyDrawables_.Erase(i);
+        else
+            break;
+    }
+
     orderDirty_ = true;
 }
 
 void Renderer2D::MarkMaterialDirty(Drawable2D* drawable)
 {
+    // Note: this may cause the drawable to appear on the dirty list multiple times
     materialDirtyDrawables_.Push(drawable);
 }
 
@@ -247,7 +262,7 @@ void Renderer2D::OnWorldBoundingBoxUpdate()
     worldBoundingBox_ = boundingBox_;
 }
 
-static void CheckDrawableVisibility(const WorkItem* item, unsigned threadIndex)
+void CheckDrawableVisibility(const WorkItem* item, unsigned threadIndex)
 {
     Renderer2D* renderer = reinterpret_cast<Renderer2D*>(item->aux_);
     Drawable2D** start = reinterpret_cast<Drawable2D**>(item->start_);
@@ -257,9 +272,7 @@ static void CheckDrawableVisibility(const WorkItem* item, unsigned threadIndex)
     {
         Drawable2D* drawable = *start++;
         if (renderer->CheckVisibility(drawable) && drawable->GetVertices().Size())
-            drawable->SetVisibility(true);
-        else
-            drawable->SetVisibility(false);
+            drawable->MarkInView(renderer->frame_);
     }
 }
 
@@ -271,6 +284,11 @@ void Renderer2D::HandleBeginViewUpdate(StringHash eventType, VariantMap& eventDa
     // Check that we are updating the correct scene
     if (scene != eventData[P_SCENE].GetPtr())
         return;
+    unsigned lastFrameNumber = frame_.frameNumber_;
+    frame_ = static_cast<View*>(eventData[P_VIEW].GetPtr())->GetFrameInfo();
+    // Reset geometry use when new frame started
+    if (frame_.frameNumber_ != lastFrameNumber)
+        geometryCount_ = 0;
 
     PROFILE(UpdateRenderer2D);
 
@@ -330,36 +348,30 @@ void Renderer2D::HandleBeginViewUpdate(StringHash eventType, VariantMap& eventDa
         queue->Complete(M_MAX_UNSIGNED);
     }
 
-    vertexCount_ = 0;
-    for (unsigned i = 0; i < drawables_.Size(); ++i)
-    {
-        if (drawables_[i]->GetVisibility())
-            vertexCount_ += drawables_[i]->GetVertices().Size();
-    }
-
-    if (useTris_)
-        indexCount_ = vertexCount_;
-    else
-        indexCount_ = vertexCount_ / 4 * 6;
-
-
-    // Go through the drawables to form geometries & batches, but upload the actual vertex data later
-    materials_.Clear();
-
+    // Go through the drawables to form geometries & batches and calculate the total vertex / index count,
+    // but upload the actual vertex data later. The idea is that the View class copies our batch vector to
+    // its internal data structures, so we can reuse the batches for each view, provided that unique Geometry
+    // objects are used for each view to specify the draw ranges
+    batches_.Clear();
     Material* material = 0;
     unsigned iStart = 0;
     unsigned iCount = 0;
     unsigned vStart = 0;
     unsigned vCount = 0;
+    unsigned& vTotal = vertexCount_[frame_.camera_];
+    unsigned& iTotal = indexCount_[frame_.camera_];
+    vTotal = 0;
+    iTotal = 0;
 
     for (unsigned d = 0; d < drawables_.Size(); ++d)
     {
-        if (!drawables_[d]->GetVisibility())
+        if (!drawables_[d]->IsInView(frame_))
             continue;
 
         Material* usedMaterial = drawables_[d]->GetMaterial();
         const Vector<Vertex2D>& vertices = drawables_[d]->GetVertices();
 
+        // When new material encountered, finish the current batch and start new
         if (material != usedMaterial)
         {
             if (material)
@@ -374,27 +386,21 @@ void Renderer2D::HandleBeginViewUpdate(StringHash eventType, VariantMap& eventDa
             material = usedMaterial;
         }
 
+        unsigned indices;
         if (useTris_)
-            iCount += vertices.Size();
+            indices = vertices.Size();
         else
-            iCount += vertices.Size() / 4 * 6;
+            indices = vertices.Size() / 4 * 6;
 
+        iCount += indices;
+        iTotal += indices;
         vCount += vertices.Size();
+        vTotal += vertices.Size();
     }
 
-    if (material)
+    // Add the final batch if necessary
+    if (material && vCount)
         AddBatch(material, iStart, iCount, vStart, vCount);
-
-    // Now the amount of batches is known. Build the part of source batches that are sensitive to threading issues
-    // (material & geometry pointers)
-    unsigned count = materials_.Size();
-    batches_.Resize(count);
-
-    for (unsigned i = 0; i < count; ++i)
-    {
-        batches_[i].material_ = materials_[i];
-        batches_[i].geometry_ = geometries_[i];
-    }
 }
 
 void Renderer2D::GetDrawables(PODVector<Drawable2D*>& dest, Node* node)
@@ -466,10 +472,8 @@ void Renderer2D::AddBatch(Material* material, unsigned indexStart, unsigned inde
     if (!material || indexCount == 0 || vertexCount == 0)
         return;
 
-    materials_.Push(SharedPtr<Material>(material));
-
-    unsigned batchSize = materials_.Size();
-    if (geometries_.Size() < batchSize)
+    // Allocate new geometry if necessary
+    if (geometries_.Size() <= geometryCount_)
     {
         SharedPtr<Geometry> geometry(new Geometry(context_));
         geometry->SetIndexBuffer(indexBuffer_);
@@ -477,7 +481,14 @@ void Renderer2D::AddBatch(Material* material, unsigned indexStart, unsigned inde
         geometries_.Push(geometry);
     }
 
-    geometries_[batchSize - 1]->SetDrawRange(TRIANGLE_LIST, indexStart, indexCount, vertexStart, vertexCount, false);
+    geometries_[geometryCount_]->SetDrawRange(TRIANGLE_LIST, indexStart, indexCount, vertexStart, vertexCount, false);
+
+    batches_.Resize(batches_.Size() + 1);
+    SourceBatch& batch = batches_.Back();
+    batch.geometry_ = geometries_[geometryCount_];
+    batch.material_ = material;
+
+    ++geometryCount_;
 }
 
 void Renderer2D::SetUseTris(bool tris)

+ 13 - 8
Source/Atomic/Atomic2D/Renderer2D.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -31,12 +31,15 @@ class Drawable2D;
 class IndexBuffer;
 class Material;
 class VertexBuffer;
+struct FrameInfo;
 
 /// 2D renderer components.
 class ATOMIC_API Renderer2D : public Drawable
 {
     OBJECT(Renderer2D);
 
+    friend void CheckDrawableVisibility(const WorkItem* item, unsigned threadIndex);
+
 public:
     /// Construct.
     Renderer2D(Context* context);
@@ -91,18 +94,20 @@ private:
     PODVector<Drawable2D*> materialDirtyDrawables_;
     /// Order dirty.
     bool orderDirty_;
-    /// Materials.
-    Vector<SharedPtr<Material> > materials_;
-    /// Geometries.
+    /// View frameinfo for current frame.
+    FrameInfo frame_;
+    /// Used geometry count. Shared by all views and reset when a new frame begins.
+    unsigned geometryCount_;
+    /// Vertex count by view.
+    HashMap<Camera*, unsigned> vertexCount_;
+    /// Index count by view.
+    HashMap<Camera*, unsigned> indexCount_;
+    /// Geometries used in all views.
     Vector<SharedPtr<Geometry> > geometries_;
     /// Frustum for current frame.
     const Frustum* frustum_;
     /// Frustum bounding box for current frame.
     BoundingBox frustumBoundingBox_;
-    /// Total index count for the current frame.
-    unsigned indexCount_;
-    /// Total vertex count for the current frame.
-    unsigned vertexCount_;
     /// Cached materials.
     HashMap<Texture2D*, HashMap<int, SharedPtr<Material> > > cachedMaterials_;
 

+ 11 - 1
Source/Atomic/Atomic2D/StaticSprite2D.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -108,6 +108,16 @@ void StaticSprite2D::SetColor(const Color& color)
     MarkNetworkUpdate();
 }
 
+void StaticSprite2D::SetAlpha(float alpha)
+{
+    if (alpha == color_.a_)
+        return;
+
+    color_.a_ = alpha;
+    verticesDirty_ = true;
+    MarkNetworkUpdate();
+}
+
 void StaticSprite2D::SetUseHotSpot(bool useHotSpot)
 {
     if (useHotSpot == useHotSpot_)

+ 5 - 1
Source/Atomic/Atomic2D/StaticSprite2D.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -52,6 +52,8 @@ public:
     void SetFlipY(bool flipY);
     /// Set color.
     void SetColor(const Color& color);
+    /// Set alpha.
+    void SetAlpha(float alpha);
     /// Set use hot spot.
     void SetUseHotSpot(bool useHotSpot);
     /// Set hot spot.
@@ -65,6 +67,8 @@ public:
     bool GetFlipY() const { return flipY_; }
     /// Return color.
     const Color& GetColor() const { return color_; }
+    /// Return alpha.
+    float GetAlpha() const { return color_.a_; }
     /// Return use hot spot.
     bool GetUseHotSpot() const { return useHotSpot_; }
     /// Return hot spot.

+ 47 - 11
Source/Atomic/Container/ForEach.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -23,10 +23,52 @@
 #pragma once
 
 #include "../Container/Vector.h"
+#include "../Container/List.h"
+#include "../Container/HashSet.h"
+#include "../Container/HashMap.h"
 
-// Note: ForEach is not supported on all compilers, such as VS2008.
+#include <algorithm>
 
-namespace Atomic {
+namespace std
+{
+
+template <class T> typename Atomic::Vector<T>::ConstIterator begin(const Atomic::Vector<T>& v) { return v.Begin(); }
+template <class T> typename Atomic::Vector<T>::ConstIterator end(const Atomic::Vector<T>& v) { return v.End(); }
+template <class T> typename Atomic::Vector<T>::Iterator begin(Atomic::Vector<T>& v) { return v.Begin(); }
+template <class T> typename Atomic::Vector<T>::Iterator end(Atomic::Vector<T>& v) { return v.End(); }
+
+template <class T> typename Atomic::PODVector<T>::ConstIterator begin(const Atomic::PODVector<T>& v) { return v.Begin(); }
+template <class T> typename Atomic::PODVector<T>::ConstIterator end(const Atomic::PODVector<T>& v) { return v.End(); }
+template <class T> typename Atomic::PODVector<T>::Iterator begin(Atomic::PODVector<T>& v) { return v.Begin(); }
+template <class T> typename Atomic::PODVector<T>::Iterator end(Atomic::PODVector<T>& v) { return v.End(); }
+
+template <class T> typename Atomic::List<T>::ConstIterator begin(const Atomic::List<T>& v) { return v.Begin(); }
+template <class T> typename Atomic::List<T>::ConstIterator end(const Atomic::List<T>& v) { return v.End(); }
+template <class T> typename Atomic::List<T>::Iterator begin(Atomic::List<T>& v) { return v.Begin(); }
+template <class T> typename Atomic::List<T>::Iterator end(Atomic::List<T>& v) { return v.End(); }
+
+template <class T, class U> typename Atomic::HashMap<T, U>::ConstIterator begin(const Atomic::HashMap<T, U>& v) { return v.Begin(); }
+template <class T, class U> typename Atomic::HashMap<T, U>::ConstIterator end(const Atomic::HashMap<T, U>& v) { return v.End(); }
+template <class T, class U> typename Atomic::HashMap<T, U>::Iterator begin(Atomic::HashMap<T, U>& v) { return v.Begin(); }
+template <class T, class U> typename Atomic::HashMap<T, U>::Iterator end(Atomic::HashMap<T, U>& v) { return v.End(); }
+
+template <class T> typename Atomic::HashSet<T>::ConstIterator begin(const Atomic::HashSet<T>& v) { return v.Begin(); }
+template <class T> typename Atomic::HashSet<T>::ConstIterator end(const Atomic::HashSet<T>& v) { return v.End(); }
+template <class T> typename Atomic::HashSet<T>::Iterator begin(Atomic::HashSet<T>& v) { return v.Begin(); }
+template <class T> typename Atomic::HashSet<T>::Iterator end(Atomic::HashSet<T>& v) { return v.End(); }
+
+}
+
+// VS2010+ and other compilers: use std::begin(), std::end() & range based for
+// C++11 features need to be enabled
+#if !defined(_MSC_VER) || _MSC_VER > 1600
+#define foreach(VAL, VALS) for (VAL : VALS)
+// Fallback solution for VS2010. Will have problem with break statement.
+// See https://github.com/urho3d/Atomic/issues/561
+#else
+
+namespace Atomic
+{
 
 template<typename T>
 struct false_wrapper {
@@ -116,7 +158,7 @@ Atomic::RandomAccessConstIterator<T> End(const Atomic::PODVector<T> *v) {
     return v->End();
 }
 
-} // namespace Atomic
+}
 
 #define foreach(VAL, VALS) \
     if (const auto& _foreach_begin = Atomic::make_false_wrapper(Atomic::Begin(VALS))) { } else \
@@ -125,10 +167,4 @@ Atomic::RandomAccessConstIterator<T> End(const Atomic::PODVector<T> *v) {
     if (bool _foreach_flag = false) { } else \
     for (VAL = *it; !_foreach_flag; _foreach_flag = true)
 
-#define foreachv(ITER, VAL, VALS) \
-    if (const auto& _foreach_begin = Atomic::make_false_wrapper(Atomic::Begin(VALS))) { } else \
-    if (const auto& _foreach_end = Atomic::make_false_wrapper(Atomic::End(VALS))) { } else \
-    if (int ITER = 0) { } else \
-    for (auto it = _foreach_begin.value; it != _foreach_end.value; ++it) \
-    if (bool _foreach_flag = false) { } else \
-    for (VAL = *it; !_foreach_flag; ITER++, _foreach_flag = true)
+#endif

+ 4 - 1
Source/Atomic/Container/HashMap.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -36,6 +36,9 @@ namespace Atomic
 template <class T, class U> class HashMap : public HashBase
 {
 public:
+    typedef T KeyType;
+    typedef U ValueType;
+    
     /// Hash map key-value pair with const key.
     class KeyValue
     {

+ 3 - 1
Source/Atomic/Container/Vector.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -35,6 +35,7 @@ namespace Atomic
 template <class T> class Vector : public VectorBase
 {
 public:
+    typedef T ValueType;
     typedef RandomAccessIterator<T> Iterator;
     typedef RandomAccessConstIterator<T> ConstIterator;
     
@@ -458,6 +459,7 @@ private:
 template <class T> class PODVector : public VectorBase
 {
 public:
+    typedef T ValueType;
     typedef RandomAccessIterator<T> Iterator;
     typedef RandomAccessConstIterator<T> ConstIterator;
     

+ 5 - 10
Source/Atomic/Graphics/Batch.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -250,11 +250,6 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
                 graphics->SetShaderParameter(VSP_BILLBOARDROT, cameraNode->GetWorldRotation().RotationMatrix());
         }
     }
-
-    if (lightmapTilingOffset_)
-    {
-        graphics->SetShaderParameter(VSP_LMOFFSET, *lightmapTilingOffset_);
-    }
     
     // Set zone-related shader parameters
     BlendMode blend = graphics->GetBlendMode();
@@ -301,7 +296,7 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
     // Set light-related shader parameters
     if (lightQueue_)
     {
-        if (graphics->NeedParameterUpdate(SP_VERTEXLIGHTS, lightQueue_) && graphics->HasShaderParameter(VS, VSP_VERTEXLIGHTS))
+        if (graphics->NeedParameterUpdate(SP_VERTEXLIGHTS, lightQueue_) && graphics->HasShaderParameter(VSP_VERTEXLIGHTS))
         {
             Vector4 vertexLights[MAX_VERTEX_LIGHTS * 3];
             const PODVector<Light*>& lights = lightQueue_->vertexLights_;
@@ -369,7 +364,7 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
         float atten = 1.0f / Max(light->GetRange(), M_EPSILON);
         graphics->SetShaderParameter(VSP_LIGHTPOS, Vector4(lightNode->GetWorldPosition(), atten));
         
-        if (graphics->HasShaderParameter(VS, VSP_LIGHTMATRICES))
+        if (graphics->HasShaderParameter(VSP_LIGHTMATRICES))
         {
             switch (light->GetLightType())
             {
@@ -427,7 +422,7 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
         graphics->SetShaderParameter(PSP_LIGHTPOS, Vector4((isLightVolume ? (lightNode->GetWorldPosition() -
             cameraEffectivePos) : lightNode->GetWorldPosition()), atten));
         
-        if (graphics->HasShaderParameter(PS, PSP_LIGHTMATRICES))
+        if (graphics->HasShaderParameter(PSP_LIGHTMATRICES))
         {
             switch (light->GetLightType())
             {
@@ -554,7 +549,7 @@ void Batch::Prepare(View* view, bool setModelTransform, bool allowDepthWrite) co
     // Set material-specific shader parameters and textures
     if (material_)
     {
-        if (graphics->NeedParameterUpdate(SP_MATERIAL, material_))
+        if (graphics->NeedParameterUpdate(SP_MATERIAL, (const void*)material_->GetShaderParameterHash()))
         {
             const HashMap<StringHash, MaterialShaderParameter>& parameters = material_->GetShaderParameters();
             for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)

+ 97 - 108
Source/Atomic/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -20,7 +20,6 @@
 // THE SOFTWARE.
 //
 
-#include "Precompiled.h"
 #include "../../Graphics/AnimatedModel.h"
 #include "../../Graphics/Animation.h"
 #include "../../Graphics/AnimationController.h"
@@ -274,6 +273,7 @@ Graphics::Graphics(Context* context) :
     numBatches_(0),
     maxScratchBufferRequest_(0),
     defaultTextureFilterMode_(FILTER_TRILINEAR),
+    currentShaderParameters_(0),
     shaderPath_("Shaders/HLSL/"),
     shaderExtension_(".hlsl"),
     orientations_("LandscapeLeft LandscapeRight")
@@ -1113,13 +1113,6 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
     
     if (vs != vertexShader_)
     {
-        // Clear all previous vertex shader register mappings
-        for (HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Begin(); i != shaderParameters_.End(); ++i)
-        {
-            if (i->second_.type_ == VS)
-                i->second_.register_ = M_MAX_UNSIGNED;
-        }
-        
         // Create the shader now if not yet created. If already attempted, do not retry
         if (vs && !vs->GetGPUObject())
         {
@@ -1139,14 +1132,7 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
         }
         
         if (vs && vs->GetShaderType() == VS)
-        {
             impl_->device_->SetVertexShader((IDirect3DVertexShader9*)vs->GetGPUObject());
-            
-            // Update the parameter-to-register mappings
-            const HashMap<StringHash, ShaderParameter>& parameters = vs->GetParameters();
-            for (HashMap<StringHash, ShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
-                shaderParameters_[i->first_].register_ = i->second_.register_;
-        }
         else
         {
             impl_->device_->SetVertexShader(0);
@@ -1158,12 +1144,6 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
     
     if (ps != pixelShader_)
     {
-        for (HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Begin(); i != shaderParameters_.End(); ++i)
-        {
-            if (i->second_.type_ == PS)
-                i->second_.register_ = M_MAX_UNSIGNED;
-        }
-        
         if (ps && !ps->GetGPUObject())
         {
             if (ps->GetCompilerOutput().Empty())
@@ -1182,13 +1162,7 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
         }
         
         if (ps && ps->GetShaderType() == PS)
-        {
             impl_->device_->SetPixelShader((IDirect3DPixelShader9*)ps->GetGPUObject());
-            
-            const HashMap<StringHash, ShaderParameter>& parameters = ps->GetParameters();
-            for (HashMap<StringHash, ShaderParameter>::ConstIterator i = parameters.Begin(); i != parameters.End(); ++i)
-                shaderParameters_[i->first_].register_ = i->second_.register_;
-        }
         else
         {
             impl_->device_->SetPixelShader(0);
@@ -1198,6 +1172,34 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
         pixelShader_ = ps;
     }
     
+    // Update current available shader parameters
+    if (vertexShader_ && pixelShader_)
+    {
+        Pair<ShaderVariation*, ShaderVariation*> key = MakePair(vertexShader_, pixelShader_);
+        HashMap<Pair<ShaderVariation*, ShaderVariation*>, HashMap<StringHash, Pair<ShaderType, unsigned> > >::Iterator i =
+            shaderParameters_.Find(key);
+        if (i != shaderParameters_.End())
+            currentShaderParameters_ = &i->second_;
+        else
+        {
+            HashMap<StringHash, Pair<ShaderType, unsigned> >& parameters = shaderParameters_[key];
+
+            const HashMap<StringHash, ShaderParameter>& vsParams = vertexShader_->GetParameters();
+            for (HashMap<StringHash, ShaderParameter>::ConstIterator i = vsParams.Begin(); i != vsParams.End(); ++i)
+                parameters[i->first_] = MakePair(i->second_.type_, i->second_.register_);
+
+            const HashMap<StringHash, ShaderParameter>& psParams = pixelShader_->GetParameters();
+            for (HashMap<StringHash, ShaderParameter>::ConstIterator i = psParams.Begin(); i != psParams.End(); ++i)
+                parameters[i->first_] = MakePair(i->second_.type_, i->second_.register_);
+
+            // Optimize shader parameter lookup by rehashing to next power of two
+            parameters.Rehash(NextPowerOfTwo(parameters.Size()));
+            currentShaderParameters_ = &parameters;
+        }
+    }
+    else
+        currentShaderParameters_ = 0;
+
     // Store shader combination if shader dumping in progress
     if (shaderPrecache_)
         shaderPrecache_->StoreShaders(vertexShader_, pixelShader_);
@@ -1205,20 +1207,20 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
 
 void Graphics::SetShaderParameter(StringHash param, const float* data, unsigned count)
 {
-    HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
+    HashMap<StringHash, Pair<ShaderType, unsigned> >::Iterator i;
+    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
         return;
     
-    if (i->second_.type_ == VS)
-        impl_->device_->SetVertexShaderConstantF(i->second_.register_, data, count / 4);
+    if (i->second_.first_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.second_, data, count / 4);
     else
-        impl_->device_->SetPixelShaderConstantF(i->second_.register_, data, count / 4);
+        impl_->device_->SetPixelShaderConstantF(i->second_.second_, data, count / 4);
 }
 
 void Graphics::SetShaderParameter(StringHash param, float value)
 {
-    HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
+    HashMap<StringHash, Pair<ShaderType, unsigned> >::Iterator i;
+    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
         return;
     
     float data[4];
@@ -1228,43 +1230,43 @@ void Graphics::SetShaderParameter(StringHash param, float value)
     data[2] = 0.0f;
     data[3] = 0.0f;
     
-    if (i->second_.type_ == VS)
-        impl_->device_->SetVertexShaderConstantF(i->second_.register_, &data[0], 1);
+    if (i->second_.first_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.second_, &data[0], 1);
     else
-        impl_->device_->SetPixelShaderConstantF(i->second_.register_, &data[0], 1);
+        impl_->device_->SetPixelShaderConstantF(i->second_.second_, &data[0], 1);
 }
 
 void Graphics::SetShaderParameter(StringHash param, bool value)
 {
     /// \todo Bool constants possibly have no effect on Direct3D9
-    HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
+    HashMap<StringHash, Pair<ShaderType, unsigned> >::Iterator i;
+    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
         return;
 
     BOOL data = value;
 
-    if (i->second_.type_ == VS)
-        impl_->device_->SetVertexShaderConstantB(i->second_.register_, &data, 1);
+    if (i->second_.first_ == VS)
+        impl_->device_->SetVertexShaderConstantB(i->second_.second_, &data, 1);
     else
-        impl_->device_->SetPixelShaderConstantB(i->second_.register_, &data, 1);
+        impl_->device_->SetPixelShaderConstantB(i->second_.second_, &data, 1);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Color& color)
 {
-    HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
+    HashMap<StringHash, Pair<ShaderType, unsigned> >::Iterator i;
+    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
         return;
     
-    if (i->second_.type_ == VS)
-        impl_->device_->SetVertexShaderConstantF(i->second_.register_, color.Data(), 1);
+    if (i->second_.first_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.second_, color.Data(), 1);
     else
-        impl_->device_->SetPixelShaderConstantF(i->second_.register_, color.Data(), 1);
+        impl_->device_->SetPixelShaderConstantF(i->second_.second_, color.Data(), 1);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Vector2& vector)
 {
-    HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
+    HashMap<StringHash, Pair<ShaderType, unsigned> >::Iterator i;
+    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
         return;
     
     float data[4];
@@ -1274,16 +1276,16 @@ void Graphics::SetShaderParameter(StringHash param, const Vector2& vector)
     data[2] = 0.0f;
     data[3] = 0.0f;
     
-    if (i->second_.type_ == VS)
-        impl_->device_->SetVertexShaderConstantF(i->second_.register_, &data[0], 1);
+    if (i->second_.first_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.second_, &data[0], 1);
     else
-        impl_->device_->SetPixelShaderConstantF(i->second_.register_, &data[0], 1);
+        impl_->device_->SetPixelShaderConstantF(i->second_.second_, &data[0], 1);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Matrix3& matrix)
 {
-    HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
+    HashMap<StringHash, Pair<ShaderType, unsigned> >::Iterator i;
+    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
         return;
     
     float data[12];
@@ -1301,16 +1303,16 @@ void Graphics::SetShaderParameter(StringHash param, const Matrix3& matrix)
     data[10] = matrix.m22_;
     data[11] = 0.0f;
     
-    if (i->second_.type_ == VS)
-        impl_->device_->SetVertexShaderConstantF(i->second_.register_, &data[0], 3);
+    if (i->second_.first_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.second_, &data[0], 3);
     else
-        impl_->device_->SetPixelShaderConstantF(i->second_.register_, &data[0], 3);
+        impl_->device_->SetPixelShaderConstantF(i->second_.second_, &data[0], 3);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Vector3& vector)
 {
-    HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
+    HashMap<StringHash, Pair<ShaderType, unsigned> >::Iterator i;
+    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
         return;
     
     float data[4];
@@ -1320,46 +1322,46 @@ void Graphics::SetShaderParameter(StringHash param, const Vector3& vector)
     data[2] = vector.z_;
     data[3] = 0.0f;
     
-    if (i->second_.type_ == VS)
-        impl_->device_->SetVertexShaderConstantF(i->second_.register_, &data[0], 1);
+    if (i->second_.first_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.second_, &data[0], 1);
     else
-        impl_->device_->SetPixelShaderConstantF(i->second_.register_, &data[0], 1);
+        impl_->device_->SetPixelShaderConstantF(i->second_.second_, &data[0], 1);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Matrix4& matrix)
 {
-    HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
+    HashMap<StringHash, Pair<ShaderType, unsigned> >::Iterator i;
+    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
         return;
     
-    if (i->second_.type_ == VS)
-        impl_->device_->SetVertexShaderConstantF(i->second_.register_, matrix.Data(), 4);
+    if (i->second_.first_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.second_, matrix.Data(), 4);
     else
-        impl_->device_->SetPixelShaderConstantF(i->second_.register_, matrix.Data(), 4);
+        impl_->device_->SetPixelShaderConstantF(i->second_.second_, matrix.Data(), 4);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Vector4& vector)
 {
-    HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
+    HashMap<StringHash, Pair<ShaderType, unsigned> >::Iterator i;
+    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
         return;
     
-    if (i->second_.type_ == VS)
-        impl_->device_->SetVertexShaderConstantF(i->second_.register_, vector.Data(), 1);
+    if (i->second_.first_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.second_, vector.Data(), 1);
     else
-        impl_->device_->SetPixelShaderConstantF(i->second_.register_, vector.Data(), 1);
+        impl_->device_->SetPixelShaderConstantF(i->second_.second_, vector.Data(), 1);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Matrix3x4& matrix)
 {
-    HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    if (i == shaderParameters_.End() || i->second_.register_ >= MAX_CONSTANT_REGISTERS)
+    HashMap<StringHash, Pair<ShaderType, unsigned> >::Iterator i;
+    if (!currentShaderParameters_ || (i = currentShaderParameters_->Find(param)) == currentShaderParameters_->End())
         return;
     
-    if (i->second_.type_ == VS)
-        impl_->device_->SetVertexShaderConstantF(i->second_.register_, matrix.Data(), 3);
+    if (i->second_.first_ == VS)
+        impl_->device_->SetVertexShaderConstantF(i->second_.second_, matrix.Data(), 3);
     else
-        impl_->device_->SetPixelShaderConstantF(i->second_.register_, matrix.Data(), 3);
+        impl_->device_->SetPixelShaderConstantF(i->second_.second_, matrix.Data(), 3);
 }
 
 void Graphics::SetShaderParameter(StringHash param, const Variant& value)
@@ -1408,31 +1410,6 @@ void Graphics::SetShaderParameter(StringHash param, const Variant& value)
     }
 }
 
-void Graphics::RegisterShaderParameter(StringHash param, const ShaderParameter& definition)
-{
-    HashMap<StringHash, ShaderParameter>::Iterator i = shaderParameters_.Find(param);
-    
-    if (i == shaderParameters_.End())
-    {
-        // Define new parameter
-        i = shaderParameters_.Insert(MakePair(param, definition));
-        i->second_.register_ = M_MAX_UNSIGNED;
-        
-        // Rehash the parameters to ensure minimum load factor and fast queries
-        shaderParameters_.Rehash(NextPowerOfTwo(shaderParameters_.Size()));
-    }
-    else
-    {
-        // Existing parameter: check that there is no conflict
-        if (i->second_.type_ != definition.type_)
-            LOGWARNING("Shader type mismatch on shader parameter " + String(param));
-        
-        // The same parameter is possibly defined with different sizes in different shaders. Use the highest size
-        if (i->second_.regCount_ < definition.regCount_)
-            i->second_.regCount_ = definition.regCount_;
-    }
-}
-
 bool Graphics::NeedParameterUpdate(ShaderParameterGroup group, const void* source)
 {
     if ((unsigned)(size_t)shaderParameterSources_[group] == M_MAX_UNSIGNED || shaderParameterSources_[group] != source)
@@ -1444,12 +1421,9 @@ bool Graphics::NeedParameterUpdate(ShaderParameterGroup group, const void* sourc
         return false;
 }
 
-bool Graphics::HasShaderParameter(ShaderType type, StringHash param)
+bool Graphics::HasShaderParameter(StringHash param)
 {
-    if (type == VS)
-        return vertexShader_ && vertexShader_->HasParameter(param);
-    else
-        return pixelShader_ && pixelShader_->HasParameter(param);
+    return currentShaderParameters_ && currentShaderParameters_->Find(param) != currentShaderParameters_->End();
 }
 
 bool Graphics::HasTextureUnit(TextureUnit unit)
@@ -2363,6 +2337,21 @@ void Graphics::CleanupScratchBuffers()
     maxScratchBufferRequest_ = 0;
 }
 
+void Graphics::CleanupShaderParameters(ShaderVariation* variation)
+{
+    for (HashMap<Pair<ShaderVariation*, ShaderVariation*>, HashMap<StringHash, Pair<ShaderType, unsigned> > >::Iterator i =
+        shaderParameters_.Begin(); i != shaderParameters_.End();)
+    {
+        if (i->first_.first_ == variation || i->first_.second_ == variation)
+            i = shaderParameters_.Erase(i);
+        else
+            ++i;
+    }
+
+    if (vertexShader_ == variation || pixelShader_ == variation)
+        currentShaderParameters_ = 0;
+}
+
 unsigned Graphics::GetAlphaFormat()
 {
     return D3DFMT_A8;

+ 9 - 7
Source/Atomic/Graphics/Direct3D9/D3D9Graphics.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -155,12 +155,10 @@ public:
     void SetShaderParameter(StringHash param, const Matrix3x4& matrix);
     /// Set shader constant from a variant. Supported variant types: bool, float, vector2, vector3, vector4, color.
     void SetShaderParameter(StringHash param, const Variant& value);
-    /// Register a shader parameter globally. Called by Shader.
-    void RegisterShaderParameter(StringHash param, const ShaderParameter& definition);
     /// Check whether a shader parameter group needs update. Does not actually check whether parameters exist in the shaders.
     bool NeedParameterUpdate(ShaderParameterGroup group, const void* source);
     /// Check whether a shader parameter exists on the currently set shaders.
-    bool HasShaderParameter(ShaderType type, StringHash param);
+    bool HasShaderParameter(StringHash param);
     /// Check whether the current pixel shader uses a texture unit.
     bool HasTextureUnit(TextureUnit unit);
     /// Clear remembered shader parameter source group.
@@ -393,7 +391,9 @@ public:
     void FreeScratchBuffer(void* buffer);
     /// Clean up too large scratch buffers.
     void CleanupScratchBuffers();
-    
+    /// Clean up shader parameters when a shader variation is released or destroyed.
+    void CleanupShaderParameters(ShaderVariation* variation);
+
     /// Return the API-specific alpha texture format.
     static unsigned GetAlphaFormat();
     /// Return the API-specific luminance texture format.
@@ -537,8 +537,6 @@ private:
     ShaderVariation* vertexShader_;
     /// Pixel shader in use.
     ShaderVariation* pixelShader_;
-    /// All known shader parameters.
-    HashMap<StringHash, ShaderParameter> shaderParameters_;
     /// Textures in use.
     Texture* textures_[MAX_TEXTURE_UNITS];
     /// Texture unit mappings.
@@ -593,6 +591,10 @@ private:
     bool drawAntialiased_;
     /// Default texture filtering mode.
     TextureFilterMode defaultTextureFilterMode_;
+    /// Shader parameters for all vertex/pixel shader combinations.
+    HashMap<Pair<ShaderVariation*, ShaderVariation*>, HashMap<StringHash, Pair<ShaderType, unsigned> > > shaderParameters_;
+    /// Current active shader parameters.
+    HashMap<StringHash, Pair<ShaderType, unsigned> >* currentShaderParameters_;
     /// Remembered shader parameter sources.
     const void* shaderParameterSources_[MAX_SHADER_PARAMETER_GROUPS];
     /// Base directory for shaders.

+ 7 - 15
Source/Atomic/Graphics/Direct3D9/D3D9ShaderVariation.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -20,7 +20,6 @@
 // THE SOFTWARE.
 //
 
-#include "Precompiled.h"
 #include "../../IO/File.h"
 #include "../../IO/FileSystem.h"
 #include "../../Graphics/Graphics.h"
@@ -115,6 +114,8 @@ void ShaderVariation::Release()
         if (!graphics_)
             return;
         
+        graphics_->CleanupShaderParameters(this);
+
         if (type_ == VS)
         {
             if (graphics_->GetVertexShader() == this)
@@ -129,7 +130,7 @@ void ShaderVariation::Release()
             
             ((IDirect3DPixelShader9*)object_)->Release();
         }
-        
+
         object_ = 0;
     }
     
@@ -186,12 +187,9 @@ bool ShaderVariation::LoadByteCode(PODVector<unsigned>& byteCode, const String&
         String name = file->ReadString();
         unsigned reg = file->ReadUByte();
         unsigned regCount = file->ReadUByte();
-        
+
         ShaderParameter parameter(type_, name, reg, regCount);
-        HashMap<StringHash, ShaderParameter>::Iterator j = parameters_.Insert(MakePair(StringHash(name), parameter));
-        
-        // Register the parameter globally
-        graphics_->RegisterShaderParameter(j->first_, j->second_);
+        parameters_[StringHash(name)] = parameter;
     }
     
     unsigned numTextureUnits = file->ReadUInt();
@@ -352,17 +350,11 @@ void ShaderVariation::ParseParameters(unsigned char* bufData, unsigned bufSize)
         else
         {
             ShaderParameter newParam(type_, name, reg, regCount);
-            HashMap<StringHash, ShaderParameter>::Iterator i = parameters_.Insert(MakePair(StringHash(name), newParam));
-            
-            // Register the parameter globally
-            graphics_->RegisterShaderParameter(i->first_, i->second_);
+            parameters_[StringHash(name)] = newParam;
         }
     }
     
     MOJOSHADER_freeParseData(parseData);
-    
-    // Optimize shader parameter lookup by rehashing to next power of two
-    parameters_.Rehash(NextPowerOfTwo(parameters_.Size()));
 }
 
 void ShaderVariation::CopyStrippedCode(PODVector<unsigned>& byteCode, unsigned char* bufData, unsigned bufSize)

+ 5 - 1
Source/Atomic/Graphics/GraphicsEvents.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -67,6 +67,7 @@ EVENT(E_ENDRENDERING, EndRendering)
 /// Update of a view started.
 EVENT(E_BEGINVIEWUPDATE, BeginViewUpdate)
 {
+    PARAM(P_VIEW, View);                    // View pointer
     PARAM(P_TEXTURE, Texture);              // Texture pointer
     PARAM(P_SURFACE, Surface);              // RenderSurface pointer
     PARAM(P_SCENE, Scene);                  // Scene pointer
@@ -76,6 +77,7 @@ EVENT(E_BEGINVIEWUPDATE, BeginViewUpdate)
 /// Update of a view ended.
 EVENT(E_ENDVIEWUPDATE, EndViewUpdate)
 {
+    PARAM(P_VIEW, View);                    // View pointer
     PARAM(P_TEXTURE, Texture);              // Texture pointer
     PARAM(P_SURFACE, Surface);              // RenderSurface pointer
     PARAM(P_SCENE, Scene);                  // Scene pointer
@@ -85,6 +87,7 @@ EVENT(E_ENDVIEWUPDATE, EndViewUpdate)
 /// Render of a view started.
 EVENT(E_BEGINVIEWRENDER, BeginViewRender)
 {
+    PARAM(P_VIEW, View);                    // View pointer
     PARAM(P_TEXTURE, Texture);              // Texture pointer
     PARAM(P_SURFACE, Surface);              // RenderSurface pointer
     PARAM(P_SCENE, Scene);                  // Scene pointer
@@ -94,6 +97,7 @@ EVENT(E_BEGINVIEWRENDER, BeginViewRender)
 /// Render of a view ended.
 EVENT(E_ENDVIEWRENDER, EndViewRender)
 {
+    PARAM(P_VIEW, View);                    // View pointer
     PARAM(P_TEXTURE, Texture);              // Texture pointer
     PARAM(P_SURFACE, Surface);              // RenderSurface pointer
     PARAM(P_SCENE, Scene);                  // Scene pointer

+ 33 - 4
Source/Atomic/Graphics/Material.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -26,6 +26,7 @@
 #include "../IO/FileSystem.h"
 #include "../Graphics/Graphics.h"
 #include "../IO/Log.h"
+#include "../IO/VectorBuffer.h"
 #include "../Graphics/Material.h"
 #include "../Math/Matrix3x4.h"
 #include "../Core/Profiler.h"
@@ -154,9 +155,11 @@ Material::Material(Context* context) :
     Resource(context),
     auxViewFrameNumber_(0),
     numUsedTextureUnits_(0),
+    shaderParameterHash_(0),
     occlusion_(true),
     specular_(false),
-    subscribed_(false)
+    subscribed_(false),
+    batchedParameterUpdate_(false)
 {
     ResetToDefaults();
 }
@@ -299,6 +302,7 @@ bool Material::Load(const XMLElement& source)
         textureElem = textureElem.GetNext("texture");
     }
 
+    batchedParameterUpdate_ = true;
     XMLElement parameterElem = source.GetChild("parameter");
     while (parameterElem)
     {
@@ -306,6 +310,7 @@ bool Material::Load(const XMLElement& source)
         SetShaderParameter(name, ParseShaderParameterValue(parameterElem.GetAttribute("value")));
         parameterElem = parameterElem.GetNext("parameter");
     }
+    batchedParameterUpdate_ = false;
 
     XMLElement parameterAnimationElem = source.GetChild("parameteranimation");
     while (parameterAnimationElem)
@@ -347,6 +352,7 @@ bool Material::Load(const XMLElement& source)
     if (depthBiasElem)
         SetDepthBias(BiasParameters(depthBiasElem.GetFloat("constant"), depthBiasElem.GetFloat("slopescaled")));
 
+    RefreshShaderParameterHash();
     RefreshMemoryUse();
     CheckOcclusion();
     return true;
@@ -462,7 +468,11 @@ void Material::SetShaderParameter(const String& name, const Variant& value)
         }
     }
 
-    RefreshMemoryUse();
+    if (!batchedParameterUpdate_)
+    {
+        RefreshShaderParameterHash();
+        RefreshMemoryUse();
+    }
 }
 
 void Material::SetShaderParameterAnimation(const String& name, ValueAnimation* animation, WrapMode wrapMode, float speed)
@@ -596,6 +606,7 @@ void Material::RemoveShaderParameter(const String& name)
     if (nameHash == PSP_MATSPECCOLOR)
         specular_ = false;
 
+    RefreshShaderParameterHash();
     RefreshMemoryUse();
 }
 
@@ -730,22 +741,40 @@ void Material::ResetToDefaults()
     for (unsigned i = 0; i < MAX_TEXTURE_UNITS; ++i)
         textures_[i] = 0;
 
+    batchedParameterUpdate_ = true;
     shaderParameters_.Clear();
-
     SetShaderParameter("UOffset", Vector4(1.0f, 0.0f, 0.0f, 0.0f));
     SetShaderParameter("VOffset", Vector4(0.0f, 1.0f, 0.0f, 0.0f));
     SetShaderParameter("MatDiffColor", Vector4::ONE);
     SetShaderParameter("MatEmissiveColor", Vector3::ZERO);
     SetShaderParameter("MatEnvMapColor", Vector3::ONE);
     SetShaderParameter("MatSpecColor", Vector4(0.0f, 0.0f, 0.0f, 1.0f));
+    batchedParameterUpdate_ = false;
 
     cullMode_ = CULL_CCW;
     shadowCullMode_ = CULL_CCW;
     depthBias_ = BiasParameters(0.0f, 0.0f);
 
+    RefreshShaderParameterHash();
     RefreshMemoryUse();
 }
 
+void Material::RefreshShaderParameterHash()
+{
+    VectorBuffer temp;
+    for (HashMap<StringHash, MaterialShaderParameter>::ConstIterator i = shaderParameters_.Begin(); i != shaderParameters_.End(); ++i)
+    {
+        temp.WriteStringHash(i->first_);
+        temp.WriteVariant(i->second_.value_);
+    }
+
+    shaderParameterHash_ = 0;
+    const unsigned char* data = temp.GetData();
+    unsigned dataSize = temp.GetSize();
+    for (unsigned i = 0; i < dataSize; ++i)
+        shaderParameterHash_ = SDBMHash(shaderParameterHash_, data[i]);
+}
+
 void Material::RefreshMemoryUse()
 {
     unsigned memoryUse = sizeof(Material);

+ 10 - 2
Source/Atomic/Graphics/Material.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -191,6 +191,8 @@ public:
     Scene* GetScene() const;
     /// Return the last non-null texture unit + 1. Used as an optimization when applying the material to render state.
     unsigned GetNumUsedTextureUnits() const { return numUsedTextureUnits_; }
+    /// Return shader parameter hash value. Used as an optimization to avoid setting shader parameters unnecessarily.
+    unsigned GetShaderParameterHash() const { return shaderParameterHash_; }
 
     /// Return name for texture unit.
     static String GetTextureUnitName(TextureUnit unit);
@@ -202,6 +204,8 @@ private:
     void CheckOcclusion();
     /// Reset to defaults.
     void ResetToDefaults();
+    /// Recalculate shader parameter hash.
+    void RefreshShaderParameterHash();
     /// Recalculate the memory used by the material.
     void RefreshMemoryUse();
     /// Return shader parameter animation info.
@@ -210,7 +214,7 @@ private:
     void UpdateEventSubscription();
     /// Update shader parameter animations.
     void HandleAttributeAnimationUpdate(StringHash eventType, VariantMap& eventData);
-
+    
     /// Techniques.
     Vector<TechniqueEntry> techniques_;
     /// Textures.
@@ -229,12 +233,16 @@ private:
     unsigned auxViewFrameNumber_;
     /// Number of maximum non-null texture unit + 1.
     unsigned numUsedTextureUnits_;
+    /// Shader parameter hash value.
+    unsigned shaderParameterHash_;
     /// Render occlusion flag.
     bool occlusion_;
     /// Specular lighting flag.
     bool specular_;
     /// Flag for whether is subscribed to animation updates.
     bool subscribed_;
+    /// Flag to suppress parameter hash and memory use recalculation when setting multiple shader parameters (loading or resetting the material.)
+    bool batchedParameterUpdate_;
     /// XML file used while loading.
     SharedPtr<XMLFile> loadXMLFile_;
     /// Associated scene for shader parameter animation updates.

+ 9 - 7
Source/Atomic/Graphics/OpenGL/OGLGraphics.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -1079,9 +1079,7 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
             
             bool success = vs->Create();
             if (success)
-            {
-                //LOGDEBUG("Compiled vertex shader " + vs->GetFullName());
-            }
+                LOGDEBUG("Compiled vertex shader " + vs->GetFullName());
             else
             {
                 LOGERROR("Failed to compile vertex shader " + vs->GetFullName() + ":\n" + vs->GetCompilerOutput());
@@ -1148,7 +1146,7 @@ void Graphics::SetShaders(ShaderVariation* vs, ShaderVariation* ps)
             SharedPtr<ShaderProgram> newProgram(new ShaderProgram(this, vs, ps));
             if (newProgram->Link())
             {
-                //LOGDEBUG("Linked vertex shader " + vs->GetFullName() + " and pixel shader " + ps->GetFullName());
+                LOGDEBUG("Linked vertex shader " + vs->GetFullName() + " and pixel shader " + ps->GetFullName());
                 // Note: Link() calls glUseProgram() to set the texture sampler uniforms,
                 // so it is not necessary to call it again
                 shaderProgram_ = newProgram;
@@ -1412,7 +1410,7 @@ bool Graphics::NeedParameterUpdate(ShaderParameterGroup group, const void* sourc
         return false;
 }
 
-bool Graphics::HasShaderParameter(ShaderType type, StringHash param)
+bool Graphics::HasShaderParameter(StringHash param)
 {
     return shaderProgram_ && shaderProgram_->HasParameter(param);
 }
@@ -1485,8 +1483,12 @@ void Graphics::SetTexture(unsigned index, Texture* texture)
             if (glType != textureTypes_[index])
             {
                 if (textureTypes_[index])
+                {
+                    if (textures_[index])
+                        glBindTexture(textureTypes_[index], 0);
                     glDisable(textureTypes_[index]);
-                
+                }
+
                 glEnable(glType);
                 textureTypes_[index] = glType;
             }

+ 2 - 2
Source/Atomic/Graphics/OpenGL/OGLGraphics.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -158,7 +158,7 @@ public:
     /// Check whether a shader parameter group needs update. Does not actually check whether parameters exist in the shaders.
     bool NeedParameterUpdate(ShaderParameterGroup group, const void* source);
     /// Check whether a shader parameter exists on the currently set shaders.
-    bool HasShaderParameter(ShaderType type, StringHash param);
+    bool HasShaderParameter(StringHash param);
     /// Check whether the current pixel shader uses a texture unit.
     bool HasTextureUnit(TextureUnit unit);
     /// Clear remembered shader parameter source group.

+ 3 - 13
Source/Atomic/Graphics/Renderer.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -632,20 +632,9 @@ void Renderer::Update(float timeStep)
                 debug->SetView(viewport->GetCamera());
         }
         
-        // Update view. This may queue further views
-        using namespace BeginViewUpdate;
-        
-        VariantMap& eventData = GetEventDataMap();
-        eventData[P_SURFACE] = renderTarget.Get();
-        eventData[P_TEXTURE] = (renderTarget ? renderTarget->GetParentTexture() : 0);
-        eventData[P_SCENE] = scene;
-        eventData[P_CAMERA] = viewport->GetCamera();
-        SendEvent(E_BEGINVIEWUPDATE, eventData);
-        
+        // Update view. This may queue further views. View will send update begin/end events once its state is set
         ResetShadowMapAllocations(); // Each view can reuse the same shadow maps
         view->Update(frame_);
-        
-        SendEvent(E_ENDVIEWUPDATE, eventData);
     }
     
     // Reset update flag from queued render surfaces. At this point no new views can be added on this frame
@@ -704,6 +693,7 @@ void Renderer::Render()
             RenderSurface* renderTarget = views_[i]->GetRenderTarget();
             
             VariantMap& eventData = GetEventDataMap();
+            eventData[P_VIEW] = views_[i];
             eventData[P_SURFACE] = renderTarget;
             eventData[P_TEXTURE] = (renderTarget ? renderTarget->GetParentTexture() : 0);
             eventData[P_SCENE] = views_[i]->GetScene();

+ 18 - 2
Source/Atomic/Graphics/View.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -26,6 +26,7 @@
 #include "../IO/FileSystem.h"
 #include "../Graphics/Geometry.h"
 #include "../Graphics/Graphics.h"
+#include "../Graphics/GraphicsEvents.h"
 #include "../Graphics/GraphicsImpl.h"
 #include "../IO/Log.h"
 #include "../Graphics/Material.h"
@@ -509,6 +510,16 @@ void View::Update(const FrameInfo& frame)
     frame_.frameNumber_ = frame.frameNumber_;
     frame_.viewSize_ = viewSize_;
     
+    using namespace BeginViewUpdate;
+
+    VariantMap& eventData = GetEventDataMap();
+    eventData[P_VIEW] = this;
+    eventData[P_SURFACE] = renderTarget_;
+    eventData[P_TEXTURE] = (renderTarget_ ? renderTarget_->GetParentTexture() : 0);
+    eventData[P_SCENE] = scene_;
+    eventData[P_CAMERA] = camera_;
+    renderer_->SendEvent(E_BEGINVIEWUPDATE, eventData);
+
     int maxSortedInstances = renderer_->GetMaxSortedInstances();
     
     // Clear buffers, geometry, light, occluder & batch list
@@ -522,14 +533,19 @@ void View::Update(const FrameInfo& frame)
         i->second_.Clear(maxSortedInstances);
     
     if (hasScenePasses_ && (!camera_ || !octree_))
+    {
+        renderer_->SendEvent(E_ENDVIEWUPDATE, eventData);
         return;
-    
+    }
+
     // Set automatic aspect ratio if required
     if (camera_ && camera_->GetAutoAspectRatio())
         camera_->SetAspectRatioInternal((float)frame_.viewSize_.x_ / (float)frame_.viewSize_.y_);
     
     GetDrawables();
     GetBatches();
+
+    renderer_->SendEvent(E_ENDVIEWUPDATE, eventData);
 }
 
 void View::Render()

+ 3 - 1
Source/Atomic/Graphics/View.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -37,8 +37,10 @@ class Camera;
 class DebugRenderer;
 class Light;
 class Drawable;
+class Graphics;
 class OcclusionBuffer;
 class Octree;
+class Renderer;
 class RenderPath;
 class RenderSurface;
 class Technique;

+ 38 - 4
Source/Atomic/Physics/CollisionShape.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -305,7 +305,7 @@ ConvexData::~ConvexData()
 {
 }
 
-HeightfieldData::HeightfieldData(Terrain* terrain) :
+HeightfieldData::HeightfieldData(Terrain* terrain, unsigned lodLevel) :
     heightData_(terrain->GetHeightData()),
     spacing_(terrain->GetSpacing()),
     size_(terrain->GetNumVertices()),
@@ -314,6 +314,39 @@ HeightfieldData::HeightfieldData(Terrain* terrain) :
 {
     if (heightData_)
     {
+        if (lodLevel > 0)
+        {
+            IntVector2 lodSize = size_;
+            Vector3 lodSpacing = spacing_;
+            unsigned skip = 1;
+
+            for (unsigned i = 0; i < lodLevel; ++i)
+            {
+                skip *= 2;
+                lodSpacing.x_ *= 2.0f;
+                lodSpacing.z_ *= 2.0f;
+                int rX = lodSize.x_ & 1;
+                int rY = lodSize.y_ & 1;
+                lodSize.x_ >>= 1;
+                lodSize.y_ >>= 1;
+                lodSize.x_ += rX;
+                lodSize.y_ += rY;
+                if (lodSize.x_ <= 2 || lodSize.y_ <= 2)
+                    break;
+            }
+            
+            SharedArrayPtr<float> lodHeightData(new float[lodSize.x_ * lodSize.y_]);
+            for (int y = 0, dY = 0; y < size_.y_ && dY < lodSize.y_; y += skip, ++dY)
+            {
+                for (int x = 0, dX = 0; x < size_.x_ && dX < lodSize.x_; x += skip, ++dX)
+                    lodHeightData[dY * lodSize.x_ + dX] = heightData_[y * size_.x_ + x];
+            }
+
+            size_ = lodSize;
+            spacing_ = lodSpacing;
+            heightData_ = lodHeightData;
+        }
+
         unsigned points = size_.x_ * size_.y_;
         float* data = heightData_.Get();
 
@@ -662,7 +695,7 @@ void CollisionShape::SetCustomConvexHull(CustomGeometry* custom, const Vector3&
     MarkNetworkUpdate();
 }
 
-void CollisionShape::SetTerrain()
+void CollisionShape::SetTerrain(unsigned lodLevel)
 {
     Terrain* terrain = GetComponent<Terrain>();
     if (!terrain)
@@ -675,6 +708,7 @@ void CollisionShape::SetTerrain()
         UnsubscribeFromEvent(model_, E_RELOADFINISHED);
 
     shapeType_ = SHAPE_TERRAIN;
+    lodLevel_ = lodLevel;
 
     UpdateShape();
     NotifyRigidBody();
@@ -1066,7 +1100,7 @@ void CollisionShape::UpdateShape()
                 Terrain* terrain = GetComponent<Terrain>();
                 if (terrain && terrain->GetHeightData())
                 {
-                    geometry_ = new HeightfieldData(terrain);
+                    geometry_ = new HeightfieldData(terrain, lodLevel_);
                     HeightfieldData* heightfield = static_cast<HeightfieldData*>(geometry_.Get());
 
                     shape_ = new btHeightfieldTerrainShape(heightfield->size_.x_, heightfield->size_.y_,

+ 4 - 4
Source/Atomic/Physics/CollisionShape.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -109,11 +109,11 @@ struct ConvexData : public CollisionGeometryData
 struct HeightfieldData : public CollisionGeometryData
 {
     /// Construct from a terrain.
-    HeightfieldData(Terrain* terrain);
+    HeightfieldData(Terrain* terrain, unsigned lodLevel);
     /// Destruct. Free geometry data.
     ~HeightfieldData();
 
-    /// Height data.
+    /// Height data. On LOD level 0 the original height data will be used.
     SharedArrayPtr<float> heightData_;
     /// Vertex spacing.
     Vector3 spacing_;
@@ -168,7 +168,7 @@ public:
     /// Set as a convex hull from CustomGeometry.
     void SetCustomConvexHull(CustomGeometry* custom, const Vector3& scale = Vector3::ONE, const Vector3& position = Vector3::ZERO, const Quaternion& rotation = Quaternion::IDENTITY);
     /// Set as a terrain. Only works if the same scene node contains a Terrain component.
-    void SetTerrain();
+    void SetTerrain(unsigned lodLevel = 0);
     /// Set shape type.
     void SetShapeType(ShapeType type);
     /// Set shape size.

+ 15 - 11
Source/Atomic/UI/UI.cpp

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -320,7 +320,7 @@ void UI::Update(float timeStep)
 
             if (!dragElement)
             {
-                i = dragElementErase(i);
+                i = DragElementErase(i);
                 continue;
             }
 
@@ -643,7 +643,7 @@ const Vector<UIElement*> UI::GetDragElements()
 
         if (!dragElement)
         {
-            i = dragElementErase(i);
+            i = DragElementErase(i);
             continue;
         }
 
@@ -1005,7 +1005,7 @@ void UI::ProcessHover(const IntVector2& cursorPos, int buttons, int qualifiers,
 
         if (!dragElement)
         {
-            i = dragElementErase(i);
+            i = DragElementErase(i);
             continue;
         }
 
@@ -1173,7 +1173,7 @@ void UI::ProcessClickEnd(const IntVector2& cursorPos, int button, int buttons, i
 
             if (!dragElement)
             {
-                i = dragElementErase(i);
+                i = DragElementErase(i);
                 continue;
             }
 
@@ -1215,7 +1215,7 @@ void UI::ProcessClickEnd(const IntVector2& cursorPos, int button, int buttons, i
                     }
                 }
 
-                i = dragElementErase(i);
+                i = DragElementErase(i);
             }
             else
                 ++i;
@@ -1236,7 +1236,7 @@ void UI::ProcessMove(const IntVector2& cursorPos, const IntVector2& cursorDeltaP
 
             if (!dragElement)
             {
-                i = dragElementErase(i);
+                i = DragElementErase(i);
                 continue;
             }
 
@@ -1684,17 +1684,21 @@ void UI::HandleDropFile(StringHash eventType, VariantMap& eventData)
     }
 }
 
-HashMap<WeakPtr<UIElement>, UI::DragData*>::Iterator UI::dragElementErase(HashMap<WeakPtr<UIElement>, UI::DragData*>::Iterator i)
+HashMap<WeakPtr<UIElement>, UI::DragData*>::Iterator UI::DragElementErase(HashMap<WeakPtr<UIElement>, UI::DragData*>::Iterator i)
 {
+    // If running the engine frame in response to an event (re-entering UI frame logic) the dragElements_ may already be empty
+    if (dragElements_.Empty())
+        return dragElements_.End();
+
     dragElementsConfirmed_.Clear();
 
     WeakPtr<UIElement> dragElement = i->first_;
     DragData* dragData = i->second_;
 
     if (!dragData->dragBeginPending)
-        dragConfirmedCount_ --;
+        --dragConfirmedCount_;
     i = dragElements_.Erase(i);
-    dragElementsCount_ --;
+    --dragElementsCount_;
 
     delete dragData;
     return i;
@@ -1719,7 +1723,7 @@ void UI::ProcessDragCancel()
         {
             dragElement->OnDragCancel(dragElement->ScreenToElement(cursorPos), cursorPos, dragData->dragButtons, mouseButtons_, cursor_);
             SendDragOrHoverEvent(E_DRAGCANCEL, dragElement, cursorPos, IntVector2::ZERO, dragData);
-            i = dragElementErase(i);
+            i = DragElementErase(i);
         }
         else
             ++i;

+ 2 - 2
Source/Atomic/UI/UI.h

@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2008-2014 the Urho3D project.
+// Copyright (c) 2008-2015 the Urho3D project.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal
@@ -224,7 +224,7 @@ private:
     /// Handle a file being drag-dropped into the application window.
     void HandleDropFile(StringHash eventType, VariantMap& eventData);
     /// Remove drag data and return next iterator.
-    HashMap<WeakPtr<UIElement>, DragData*>::Iterator dragElementErase(HashMap<WeakPtr<UIElement>, DragData*>::Iterator dragElement);
+    HashMap<WeakPtr<UIElement>, DragData*>::Iterator DragElementErase(HashMap<WeakPtr<UIElement>, DragData*>::Iterator dragElement);
     /// Handle clean up on a drag cancel.
     void ProcessDragCancel();
     /// Sum touch positions and return the begin position ready to send.

+ 6 - 4
Source/ThirdParty/Bullet/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp

@@ -429,8 +429,9 @@ void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstr
 
 //		btScalar positionalError = 0.f;
 
-		btSimdScalar velocityError =  desiredVelocity - rel_vel;
-		btSimdScalar	velocityImpulse = velocityError * btSimdScalar(solverConstraint.m_jacDiagABInv);
+        // Urho3D: possible friction fix from https://github.com/bulletphysics/bullet3/commit/907ac49892ede3f4a3295f7cbd96759107e5fc0e
+		btScalar velocityError =  desiredVelocity - rel_vel;
+		btScalar	velocityImpulse = velocityError * btScalar(solverConstraint.m_jacDiagABInv);
 		solverConstraint.m_rhs = velocityImpulse;
 		solverConstraint.m_cfm = cfmSlip;
 		solverConstraint.m_lowerLimit = -solverConstraint.m_friction;
@@ -509,8 +510,9 @@ void btSequentialImpulseConstraintSolver::setupRollingFrictionConstraint(	btSolv
 
 //		btScalar positionalError = 0.f;
 
-		btSimdScalar velocityError =  desiredVelocity - rel_vel;
-		btSimdScalar	velocityImpulse = velocityError * btSimdScalar(solverConstraint.m_jacDiagABInv);
+        // Urho3D: possible friction fix from https://github.com/bulletphysics/bullet3/commit/907ac49892ede3f4a3295f7cbd96759107e5fc0e
+		btScalar velocityError =  desiredVelocity - rel_vel;
+		btScalar	velocityImpulse = velocityError * btScalar(solverConstraint.m_jacDiagABInv);
 		solverConstraint.m_rhs = velocityImpulse;
 		solverConstraint.m_cfm = cfmSlip;
 		solverConstraint.m_lowerLimit = -solverConstraint.m_friction;

+ 4 - 0
Source/ThirdParty/SDL/src/video/uikit/SDL_uikitwindow.m

@@ -53,9 +53,13 @@
     [super layoutSubviews];
 
     // Forcibly set window frame based on screen bounds, which follow the orientation on iOS 8
+    // Note: we compile this hack only when the version define exists (iOS SDK 8.1); Urho3D compiled
+    // on earlier iOS SDK's did not need this behavior, even when running on an iOS 8 device
+#ifdef NSFoundationVersionNumber_iOS_7_1
     if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_7_1) {
         self.frame = self.screen.bounds;
     }
+#endif
 }
 @end
 

+ 64 - 66
Source/ThirdParty/kNet/CMakeLists.txt

@@ -1,66 +1,64 @@
-# Copyright 2010 Jukka Jylänki
-
-#  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.
-
-# Modified by Lasse Oorni and Yao Wei Tjong for Urho3D
-
-#set (TARGET_NAME kNet)
-
-include_directories(include)
-
-file (GLOB kNetSourceFiles src/*.cpp)
-file (GLOB kNetHeaderFiles include/*.h include/kNet/*.h include/kNet/*.inl)
-
-if (WIN32)
-   file (GLOB kNetWin32SourceFiles src/win32/*.cpp)
-   file (GLOB kNetWin32HeaderFiles include/kNet/win32/*.h)
-
-   if (USE_BOOST)
-      list (REMOVE_ITEM kNetWin32SourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/src/win32/W32Thread.cpp)
-   endif ()
-
-   list (APPEND kNetSourceFiles ${kNetWin32SourceFiles})
-   list (APPEND kNetHeaderFiles ${kNetWin32HeaderFiles})
-
-   add_definitions (-D_WINSOCKAPI_)
-   add_definitions (-D_CRT_SECURE_NO_WARNINGS)
-   add_definitions (-DKNET_MEMORY_LEAK_CHECK)
-elseif (UNIX)
-   list (REMOVE_ITEM kNetSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/src/Clock.cpp)
-   file (GLOB kNetUnixSourceFiles src/unix/*.cpp)
-   file (GLOB kNetUnixHeaderFiles include/*.h include/kNet/*.h include/kNet/unix/*.h)
-
-   if (USE_BOOST)
-      list (REMOVE_ITEM kNetUnixSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/src/unix/UnixThread.cpp)
-   endif ()
-
-   list (APPEND kNetSourceFiles ${kNetUnixSourceFiles})
-   list (APPEND kNetHeaderFiles ${kNetUnixHeaderFiles})
-
-   add_definitions (-DUNIX)
-endif ()
-
-# Urho3D: set DEBUG_CPP_NAME only on Windows, Xcode project file can not be opened if this is included
-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 ()
-
-# Define source files
-set (SOURCE_FILES ${kNetSourceFiles} ${kNetHeaderFiles})
-
-add_library(kNet ${SOURCE_FILES})
-
-
+# Copyright 2010 Jukka Jylänki
+
+#  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.
+
+# Modified by Lasse Oorni and Yao Wei Tjong for Urho3D
+
+#set (TARGET_NAME kNet)
+
+include_directories(include)
+
+file (GLOB kNetSourceFiles src/*.cpp)
+file (GLOB kNetHeaderFiles include/*.h include/kNet/*.h include/kNet/*.inl)
+
+if (WIN32)
+   file (GLOB kNetWin32SourceFiles src/win32/*.cpp)
+   file (GLOB kNetWin32HeaderFiles include/kNet/win32/*.h)
+
+   if (USE_BOOST)
+      list (REMOVE_ITEM kNetWin32SourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/src/win32/W32Thread.cpp)
+   endif ()
+
+   list (APPEND kNetSourceFiles ${kNetWin32SourceFiles})
+   list (APPEND kNetHeaderFiles ${kNetWin32HeaderFiles})
+
+   add_definitions (-D_WINSOCKAPI_)
+   add_definitions (-D_CRT_SECURE_NO_WARNINGS)
+   add_definitions (-DKNET_MEMORY_LEAK_CHECK)
+elseif (UNIX)
+   file (GLOB kNetUnixSourceFiles src/unix/*.cpp)
+   file (GLOB kNetUnixHeaderFiles include/*.h include/kNet/*.h include/kNet/unix/*.h)
+
+   if (USE_BOOST)
+      list (REMOVE_ITEM kNetUnixSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/src/unix/UnixThread.cpp)
+   endif ()
+
+   list (APPEND kNetSourceFiles ${kNetUnixSourceFiles})
+   list (APPEND kNetHeaderFiles ${kNetUnixHeaderFiles})
+
+   add_definitions (-DKNET_UNIX)
+endif ()
+
+# Urho3D: set DEBUG_CPP_NAME only on Windows, Xcode project file can not be opened if this is included
+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 ()
+
+# Define source files
+set (SOURCE_FILES ${kNetSourceFiles} ${kNetHeaderFiles})
+
+add_library(kNet ${SOURCE_FILES})
+

+ 46 - 46
Source/ThirdParty/kNet/LICENSE.txt

@@ -1,46 +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
+/* 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

+ 1 - 1
Source/ThirdParty/kNet/include/kNet/Alignment.h

@@ -20,7 +20,7 @@
 
 #include "Types.h"
 
-#if defined(UNIX) || defined(ANDROID)
+#if defined(KNET_UNIX) || defined(ANDROID)
 #include <stdint.h>
 #endif
 

+ 2 - 2
Source/ThirdParty/kNet/include/kNet/Allocator.h

@@ -104,11 +104,11 @@ public:
 	typedef ArrayIterator<T, AllocT> iterator;
 
 	Array(AllocT *allocator_ = 0)
-	:data(0), cap(0), used(0), allocator(allocator_)
+	:data(0), allocator(allocator_), cap(0), used(0)
 	{ }
 
 	Array(const Array &rhs)
-	:allocator(rhs.allocator), data(0), cap(0), used(0)
+	:data(0), allocator(rhs.allocator), cap(0), used(0)
 	{
 		reserve(rhs.cap);
 		for(size_t i = 0; i < rhs.size(); ++i)

+ 3 - 0
Source/ThirdParty/kNet/include/kNet/Atomics.h

@@ -13,7 +13,10 @@
    limitations under the License. */
 #pragma once
 
+// Modified by Lasse Oorni for Urho3D
+
 #ifdef WIN32
+// Urho3D: windows.h in lowercase to fix MinGW cross-compiling on a case-sensitive system
 #include <windows.h>
 #endif
 

+ 3 - 0
Source/ThirdParty/kNet/include/kNet/BasicSerializedDataTypes.h

@@ -16,7 +16,10 @@
 /** @file Clock.h
 	@brief The Clock class. Supplies timing facilities. */
 
+// Modifed by Lasse Oorni for Urho3D
+
 #ifdef WIN32
+// Urho3D: windows.h in lowercase to fix MinGW cross-compiling on a case-sensitive system
 #include <windows.h>
 #endif
 

+ 2 - 2
Source/ThirdParty/kNet/include/kNet/DataDeserializer.h

@@ -182,7 +182,7 @@ u32 DataDeserializer::ReadVLE()
 		return sml;
 	sml &= (1 << VLEType::numBits1) - 1;
 
-	const int numBitsMed = VLEType::numBits2 + (VLEType::numBits3 == 0 ? 0 : 1);
+	const u32 numBitsMed = VLEType::numBits2 + (VLEType::numBits3 == 0 ? 0 : 1);
 	if (BitsLeft() < numBitsMed)
 		return cStreamEndError;
 
@@ -190,7 +190,7 @@ u32 DataDeserializer::ReadVLE()
 	if ((med & (1 << VLEType::numBits2)) == 0)
 		return sml | (med << VLEType::numBits1);
 
-	if (BitsLeft() < VLEType::numBits3)
+	if (BitsLeft() < (u32)VLEType::numBits3)
 		return cStreamEndError;
 
 	med &= (1 << VLEType::numBits2) - 1;

+ 7 - 4
Source/ThirdParty/kNet/include/kNet/DataSerializer.h

@@ -16,6 +16,9 @@
 /** @file DebugMemoryLeakCheck.h
 	@brief Provides overloads of operators new and delete for tracking memory leaks. */
 
+// Modified by Lasse Oorni for Urho3D
+
+// Urho3D: only include on MSVC
 #if defined(_MSC_VER) && defined(_DEBUG) && defined(KNET_MEMORY_LEAK_CHECK)
 
 #include <new>
@@ -51,7 +54,7 @@ __forceinline static void operator delete[](void *ptr, const char *, int)
 	_free_dbg(ptr, _NORMAL_BLOCK);
 }
 
-__forceinline static void *operator new(size_t size)
+__forceinline void *operator new(size_t size)
 {
 #ifdef DEBUG_CPP_NAME
 	return _malloc_dbg(size, _NORMAL_BLOCK, DEBUG_CPP_NAME, 1);
@@ -60,7 +63,7 @@ __forceinline static void *operator new(size_t size)
 #endif
 }
 
-__forceinline static void *operator new[](size_t size)
+__forceinline void *operator new[](size_t size)
 {
 #ifdef DEBUG_CPP_NAME
 	return _malloc_dbg(size, _NORMAL_BLOCK, DEBUG_CPP_NAME " new[]", 1);
@@ -69,12 +72,12 @@ __forceinline static void *operator new[](size_t size)
 #endif
 }
 
-__forceinline static void operator delete(void *ptr)
+__forceinline void operator delete(void *ptr)
 {
 	_free_dbg(ptr, _NORMAL_BLOCK);
 }
 
-__forceinline static void operator delete[](void *ptr)
+__forceinline void operator delete[](void *ptr)
 {
 	_free_dbg(ptr, _NORMAL_BLOCK);
 }

+ 1 - 1
Source/ThirdParty/kNet/include/kNet/EndPoint.h

@@ -16,7 +16,7 @@
 /** @file EndPoint.h
 	@brief The class \ref kNet::EndPoint Endpoint. Represents an endpoint of a network connection. */
 
-#if defined(UNIX) || defined(ANDROID)
+#if defined(KNET_UNIX) || defined(ANDROID)
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>

+ 1 - 1
Source/ThirdParty/kNet/include/kNet/Event.h

@@ -98,7 +98,7 @@ public:
 
 	/// Wraps the given WSAEVENT into this event.
 	explicit Event(WSAEVENT wsaEvent, EventWaitType eventType);
-#elif defined(UNIX) || defined(ANDROID)
+#elif defined(KNET_UNIX) || defined(ANDROID)
 public:
 	int fd[2]; // fd[0] is used for reading, fd[1] for writing.
 

+ 4 - 5
Source/ThirdParty/kNet/include/kNet/EventArray.h

@@ -16,13 +16,12 @@
 /** @file EventArray.h
 	@brief The class \ref kNet::EventArray EventArray. Allows listening to multiple events at once.*/
 
-// Urho3D: added include file
-#ifdef UNIX
+#include <vector>
+
+#if defined(KNET_UNIX) || defined(ANDROID)
 #include <sys/select.h>
 #endif
 
-#include <vector>
-
 #include "Event.h"
 
 namespace kNet
@@ -64,7 +63,7 @@ private:
 #ifdef WIN32
 	WSAEVENT events[maxEvents]; 
 
-#elif defined(UNIX) || defined(ANDROID)
+#elif defined(KNET_UNIX) || defined(ANDROID)
 	fd_set readfds;
 	fd_set writefds;
 	int nfds;

+ 3 - 0
Source/ThirdParty/kNet/include/kNet/FragmentedTransferManager.h

@@ -16,10 +16,13 @@
 /** @file Lockable.h
 	@brief The Lock<T> and Lockable<T> template classes. */
 
+// Modified by Lasse Oorni for Urho3D
+
 #ifdef KNET_USE_BOOST
 #include <boost/thread/recursive_mutex.hpp>
 #include <boost/thread/thread.hpp>
 #elif defined(WIN32)
+// Urho3D: windows.h in lowercase to fix MinGW cross-compiling on a case-sensitive system
 #include <windows.h>
 #else
 #include <pthread.h>

+ 9 - 5
Source/ThirdParty/kNet/include/kNet/MaxHeap.h

@@ -32,7 +32,11 @@ public:
 	/// Called whenever an element in the MaxHeap is moved around.
 	/// @param element The element that was moved around.
 	/// @param newIndex The new index of the element.
-	void IndexUpdated(const T &element, int newIndex) {}
+	void IndexUpdated(const T &element, int newIndex)
+	{
+		MARK_UNUSED(element);
+		MARK_UNUSED(newIndex);
+	}
 };
 
 /** Implements a max heap data structure, see http://en.wikipedia.org/wiki/Binary_heap.
@@ -101,7 +105,7 @@ public:
 	int LowestPriorityIndex() const;
 
 	/// How many elements are in the queue total.
-	int Size() const { return data.size(); }
+	int Size() const { return (int)data.size(); }
 
 	/// As the underlying data structure is an array, you can use this to preallocate space.
 	void Reserve(int size) { data.reserve(size); }
@@ -159,9 +163,9 @@ void MaxHeap<T, PriorityCmp, EqualCmp, LookupNotify, AllocT>::Insert(const T &va
 {
 	// New element is added to the end of the array.
 	data.push_back(value);
-	notify.IndexUpdated(data.back(), data.size()-1);
+	notify.IndexUpdated(data.back(), (int)data.size()-1);
 	// We need to fix the heap by MaxHeapifying all the way to the top.
-	KeyIncreased(data.size()-1);
+	KeyIncreased((int)data.size()-1);
 }
 
 template<typename T, typename PriorityCmp, typename EqualCmp, typename LookupNotify, typename AllocT>
@@ -179,7 +183,7 @@ void MaxHeap<T, PriorityCmp, EqualCmp, LookupNotify, AllocT>::KeyIncreased(int i
 template<typename T, typename PriorityCmp, typename EqualCmp, typename LookupNotify, typename AllocT>
 void MaxHeap<T, PriorityCmp, EqualCmp, LookupNotify, AllocT>::PopFront()
 {
-	std::swap(data[0], data[data.size()-1]);
+	std::swap(data[0], data[(int)data.size()-1]);
 	data.pop_back();
 	MaxHeapify(0);
 }

+ 5 - 4
Source/ThirdParty/kNet/include/kNet/MessageConnection.h

@@ -22,11 +22,11 @@
 #include <set>
 
 #include "kNetBuildConfig.h"
-#include "Socket.h"
 #include "WaitFreeQueue.h"
 #include "NetworkSimulator.h"
 #include "LockFreePoolAllocator.h"
 #include "Lockable.h"
+#include "Socket.h"
 #include "IMessageHandler.h"
 #include "BasicSerializedDataTypes.h"
 #include "Datagram.h"
@@ -501,9 +501,6 @@ protected:
 	/// Posted when the application has pushed us some messages to handle.
 	Event eventMsgsOutAvailable; // [main and worker thread]
 
-	void operator=(const MessageConnection &); ///< Noncopyable, N/I.
-	MessageConnection(const MessageConnection &); ///< Noncopyable, N/I.
-
 	float rtt; ///< The currently estimated round-trip time, in milliseconds. [main and worker thread]
 	tick_t lastHeardTime; ///< The tick since last successful receive from the socket. [main and worker thread]
 	float packetsInPerSec; ///< The average number of datagrams we are receiving/second. [main and worker thread]
@@ -563,6 +560,10 @@ protected:
 	explicit MessageConnection(Network *owner, NetworkServer *ownerServer, Socket *socket, ConnectionState startingState);
 
 	virtual bool HandleMessage(packet_id_t /*packetID*/, message_id_t /*messageID*/, const char * /*data*/, size_t /*numBytes*/) { return false; } // [main thread]
+
+private:
+	void operator=(const MessageConnection &); ///< Noncopyable, N/I.
+	MessageConnection(const MessageConnection &); ///< Noncopyable, N/I.
 };
 
 template<typename SerializableData>

+ 2 - 2
Source/ThirdParty/kNet/include/kNet/MessageListParser.h

@@ -18,7 +18,7 @@
 
 // Modified by Lasse Oorni for Urho3D
 
-#if defined(UNIX) || defined(ANDROID)
+#if defined(KNET_UNIX) || defined(ANDROID)
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -94,7 +94,7 @@ public:
 	static int GetLastError();
 
 	/// Returns the amount of currently executing background network worker threads.
-	int NumWorkerThreads() const { return workerThreads.size(); }
+	int NumWorkerThreads() const { return (int)workerThreads.size(); }
 
 	/// Returns the NetworkServer object, or null if no server has been started.
 	Ptr(NetworkServer) GetServer() { return server; }

+ 30 - 5
Source/ThirdParty/kNet/include/kNet/NetworkLogging.h

@@ -16,6 +16,23 @@
 /** @file NetworkLogging.h
 	@brief The LOG and LOGUSER macros. Provides an unified mechanism for logging. */
 
+// From http://cnicholson.net/2009/03/stupid-c-tricks-dowhile0-and-c4127/
+#ifdef _MSC_VER
+#define MULTI_LINE_MACRO_BEGIN do { \
+	__pragma(warning(push)) \
+	__pragma(warning(disable:4127))
+
+#define MULTI_LINE_MACRO_END \
+	} while(0) \
+	__pragma(warning(pop))
+
+#else
+
+#define MULTI_LINE_MACRO_BEGIN do {
+#define MULTI_LINE_MACRO_END } while(0)
+
+#endif
+
 namespace kNet
 {
 
@@ -66,17 +83,25 @@ void EnableMemoryLeakLoggingAtExit();
 } // ~kNet
 
 /// Prints out a variadic message to the log channel User.
-#define LOGUSER(msg, ...) ( kNet::IsLogChannelActive(LogUser) && (kNet::TimeOutputDebugStringVariadic(LogUser, __FILE__, __LINE__, msg, ##__VA_ARGS__), true) )
+#define KNET_LOGUSER(msg, ...) \
+	MULTI_LINE_MACRO_BEGIN \
+		if (kNet::IsLogChannelActive(LogUser)) \
+			kNet::TimeOutputDebugStringVariadic(LogUser, __FILE__, __LINE__, msg, ##__VA_ARGS__); \
+	MULTI_LINE_MACRO_END
 
 #ifdef KNET_LOGGING_SUPPORT_ENABLED
 
 /// Prints out a variadic message to the given log channel.
-#define LOG(channel, msg, ...)  ( kNet::IsLogChannelActive(channel) && (kNet::TimeOutputDebugStringVariadic(channel, __FILE__, __LINE__, msg, ##__VA_ARGS__), true) )
+#define KNET_LOG(channel, msg, ...) \
+	MULTI_LINE_MACRO_BEGIN \
+		if (kNet::IsLogChannelActive(channel)) \
+			kNet::TimeOutputDebugStringVariadic(channel, __FILE__, __LINE__, msg, ##__VA_ARGS__); \
+	MULTI_LINE_MACRO_END
 
 #else
 
-/// If kNet logging is disabled, LOG() macro is a no-op. This avoids having to evaluate the arguments of the
-/// LOG() call, which improves performance.
-#define LOG(...) ((void)0)
+/// If kNet logging is disabled, KNET_LOG() macro is a no-op. This avoids having to evaluate the arguments of the
+/// KNET_LOG() call, which improves performance.
+#define KNET_LOG(...) ((void)0)
 
 #endif

+ 4 - 5
Source/ThirdParty/kNet/include/kNet/NetworkMessage.h

@@ -152,10 +152,9 @@ private:
 
 	void RegisterServerListener(INetworkServerListener *listener);
 
-	/// Stops listening for new connections, but all already established connections are maintained.
-	/// \todo As a limitation of this library, you cannot reopen the sockets after closing them.
-	/// You must create a new NetworkServer instance to do that, but this means you'll lose the old active connections.
-	void CloseListenSockets();
+	/// Shuts down all listen sockets used by this server.
+	/// This function is to be called only at destruction time when no network communication is being performed anymore.
+	void CloseSockets();
 
 	void CleanupDeadConnections();
 
@@ -187,7 +186,7 @@ void NetworkServer::BroadcastStruct(const SerializableData &data, unsigned long
 	Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
 	if (timer.MSecsElapsed() >= 50.f)
 	{
-		LOG(LogWaits, "NetworkServer::BroadcastMessage: Accessing the connection list took %f msecs.",
+		KNET_LOG(LogWaits, "NetworkServer::BroadcastMessage: Accessing the connection list took %f msecs.",
 			timer.MSecsElapsed());
 	}
 

+ 104 - 103
Source/ThirdParty/kNet/include/kNet/NetworkSimulator.h

@@ -1,103 +1,104 @@
-/* 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
-
+/* 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 "Types.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".
+	message_id_t 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 - 0
Source/ThirdParty/kNet/include/kNet/NetworkWorkerThread.h

@@ -147,6 +147,8 @@ private:
 	size_t numElemsMask;
 	size_t size;
 
+	void operator =(const OrderedHashTable &); ///< \todo Implement.
+	OrderedHashTable(const OrderedHashTable &); ///< \todo Implement.
 };
 
 } // ~kNet

+ 3 - 3
Source/ThirdParty/kNet/include/kNet/PolledTimer.h

@@ -33,7 +33,7 @@ public:
 	}
 
 	/// Returns the total number of bytes that this RingBuffer can contain.
-	int Capacity() const { return data.size(); }
+	int Capacity() const { return (int)data.size(); }
 
 	/// Returns the number of bytes filled in the ring buffer.
 	int Size() const { return end - start; }
@@ -95,10 +95,10 @@ public:
 	}
 
 	/// 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 (int)data.size() - Size(); }
 
 	/// 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 (int)data.size() - end; }
 
 private:
 	std::vector<char> data;

+ 3 - 0
Source/ThirdParty/kNet/include/kNet/SequentialIntegerSet.h

@@ -68,6 +68,9 @@ private:
 	std::vector<ElemInfo> currentElementStack;
 	/// The type of the message we are building.
 	const SerializedMessageDesc &desc;
+
+	void operator =(const SerializedDataIterator&);
+	SerializedDataIterator(const SerializedDataIterator&);
 };
 
 } // ~kNet

+ 5 - 5
Source/ThirdParty/kNet/include/kNet/SharedPtr.h

@@ -29,7 +29,7 @@ namespace kNet
 typedef int socklen_t;
 }
 
-#elif defined(UNIX) || defined(ANDROID)
+#elif defined(KNET_UNIX) || defined(ANDROID)
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -37,9 +37,9 @@ typedef int socklen_t;
 #include <netdb.h>
 #include <errno.h>
 
-#define INVALID_SOCKET (0)
-#define KNET_SOCKET_ERROR (-1)
-#define KNET_ACCEPT_FAILURE (-1)
+#define INVALID_SOCKET ((SOCKET)0)
+#define KNET_SOCKET_ERROR ((SOCKET)-1)
+#define KNET_ACCEPT_FAILURE ((SOCKET)-1)
 #define KNET_EWOULDBLOCK EWOULDBLOCK
 #define closesocket close
 #define TIMEVAL timeval
@@ -49,7 +49,7 @@ typedef int socklen_t;
 
 namespace kNet
 {
-typedef unsigned int SOCKET;
+typedef int SOCKET;
 }
 #endif
 

+ 11 - 3
Source/ThirdParty/kNet/include/kNet/Sort.h

@@ -16,6 +16,14 @@
 /** @file Sort.inl
 	@brief Implementations of template functions for sorting algorithms. */
 
+#ifdef __GNUC__
+/// If a variable or a function definition is labelled with this directive, the compiler should not emit a warning even if it is unused
+/// in the code.
+#define DONT_WARN_UNUSED __attribute__((unused))
+#else
+#define DONT_WARN_UNUSED
+#endif
+
 #include <utility>
 
 namespace kNet
@@ -325,11 +333,11 @@ void CocktailSort(T *list, int numItems, CmpFunc &cmp)
 namespace
 {
 /// Gives the index of the parent of the element at index i, or 0 if i==0 (i is the root)
-inline int HeapParent(int i) { return (i+1)/2-1; }
+inline int DONT_WARN_UNUSED HeapParent(int i) { return (i+1)/2-1; }
 /// Gives the left child of the element at index i. Note that this will address out-of-bounds if there is no child.
-inline int HeapLeftChild(int i) { return i*2+1; }
+inline int DONT_WARN_UNUSED HeapLeftChild(int i) { return i*2+1; }
 /// Gives the right child of the element at index i. Note that this will address out-of-bounds if there is no child.
-inline int HeapRightChild(int i) { return i*2+2; }
+inline int DONT_WARN_UNUSED HeapRightChild(int i) { return i*2+2; }
 
 /** MaxHeapifies one node of the heap at index i and recursively calls itself to MaxHeapify the child nodes,
 	so that all child nodes also satisfy the MaxHeap property.

+ 3 - 1
Source/ThirdParty/kNet/include/kNet/SortCmp.h

@@ -16,6 +16,8 @@
 /** @file Thread.h
 	@brief The Thread class. Implements threading either using Boost, native Win32 or pthreads constructs. */
 
+// Modified by Lasse Oorni for Urho3D
+
 #include <string>
 
 #ifdef KNET_USE_BOOST
@@ -23,6 +25,7 @@
 #else
 
 #ifdef WIN32
+// Urho3D: windows.h in lowercase to fix MinGW cross-compiling on a case-sensitive system
 #include <windows.h>
 #else
 #include <pthread.h>
@@ -39,7 +42,6 @@ typedef void (*ThreadEntryFunc)(void *threadStartData);
 
 #define CALL_MEMBER_FN(object,ptrToMember)  ((object).*(ptrToMember))
 
-#include "kNetBuildConfig.h"
 #include "SharedPtr.h"
 
 namespace kNet

+ 6 - 1
Source/ThirdParty/kNet/include/kNet/Types.h

@@ -23,9 +23,14 @@
 #define UNUSED(x)
 #endif
 
+#ifndef MARK_UNUSED
+/// If a variable is labelled with this directive, the compiler should not emit a warning even if it is unused in the code.
+#define MARK_UNUSED(x) ((void)x)
+#endif
+
 #ifndef KNET_NO_FIXEDWIDTH_TYPES
 
-#include "../kNetBuildConfig.h"
+#include "kNetBuildConfig.h"
 
 #ifdef __MINGW32__
 #include <stdint.h>

+ 1 - 1
Source/ThirdParty/kNet/include/kNet/UDPMessageConnection.h

@@ -231,7 +231,7 @@ private:
 //	typedef OrderedHashTable<PacketAckTrack, PacketAckTrack> PacketAckTrackTable;
 //	PacketAckTrackTable outboundPacketAckTrack;
 
-	static int BiasedBinarySearchFindPacketIndex(UDPMessageConnection::PacketAckTrackQueue &queue, int packetID);
+	static int BiasedBinarySearchFindPacketIndex(UDPMessageConnection::PacketAckTrackQueue &queue, packet_id_t packetID);
 
 	WaitFreeQueue<Datagram> queuedInboundDatagrams;
 

+ 10 - 10
Source/ThirdParty/kNet/include/kNet/VLEPacker.h

@@ -34,8 +34,8 @@ public:
 	// For compatibility when inter-using with VLEType3
 	static const int numBits3 = 0;
 
-	static const u32 maxValue1 = LSBT<numBits1>::val;
-	static const u32 maxValue2 = LSBT<numBits1+numBits2>::val;
+	static const u32 maxValue1 = static_cast<u32>(LSBT<numBits1>::val);
+	static const u32 maxValue2 = static_cast<u32>(LSBT<numBits1+numBits2>::val);
 
 	static const u32 maxValue = maxValue2;
 
@@ -44,8 +44,8 @@ public:
 
 	static const u32 maxBits = bitsValue2;
 
-	static const u32 bitMask1 = BitMaskT<0, numBits1>::val;
-	static const u32 bitMask2 = BitMaskT<bitsValue1, numBits2>::val;// == ((1 << numBits2) - 1) << bitsValue1;
+	static const u32 bitMask1 = static_cast<u32>(BitMaskT<0, numBits1>::val);
+	static const u32 bitMask2 = static_cast<u32>(BitMaskT<bitsValue1, numBits2>::val);// == ((1 << numBits2) - 1) << bitsValue1;
 
 	static int GetEncodedBitLength(u32 value)
 	{
@@ -96,9 +96,9 @@ public:
 	static const int numBits2 = bits2;
 	static const int numBits3 = bits3;
 
-	static const u32 maxValue1 = LSBT<numBits1>::val;
-	static const u32 maxValue2 = LSBT<numBits1+numBits2>::val;
-	static const u32 maxValue3 = LSBT<numBits1+numBits2+numBits3>::val;
+	static const u32 maxValue1 = static_cast<u32>(LSBT<numBits1>::val);
+	static const u32 maxValue2 = static_cast<u32>(LSBT<numBits1+numBits2>::val);
+	static const u32 maxValue3 = static_cast<u32>(LSBT<numBits1+numBits2+numBits3>::val);
 
 	static const u32 maxValue = maxValue3;
 
@@ -108,9 +108,9 @@ public:
 
 	static const u32 maxBits = bitsValue3;
 
-	static const u32 bitMask1 = BitMaskT<0, numBits1>::val;
-	static const u32 bitMask2 = BitMaskT<bitsValue1, numBits2>::val; // == ((1 << numBits2) - 1) << bitsValue1;
-	static const u32 bitMask3 = BitMaskT<bitsValue2, numBits3>::val; // == ((1 << numBits3) - 1) << bitsValue2;
+	static const u32 bitMask1 = static_cast<u32>(BitMaskT<0, numBits1>::val);
+	static const u32 bitMask2 = static_cast<u32>(BitMaskT<bitsValue1, numBits2>::val); // == ((1 << numBits2) - 1) << bitsValue1;
+	static const u32 bitMask3 = static_cast<u32>(BitMaskT<bitsValue2, numBits3>::val); // == ((1 << numBits3) - 1) << bitsValue2;
 
 	static int GetEncodedBitLength(u32 value)
 	{

+ 10 - 5
Source/ThirdParty/kNet/include/kNet/WaitFreeQueue.h

@@ -44,12 +44,12 @@ public:
 		maxElements = (size_t)RoundUpToNextPow2((u32)maxElements); // but avoid any silliness in release anyways.
 
 		data = new T[maxElements];
-		maxElementsMask = maxElements - 1;
+		maxElementsMask = (unsigned long)maxElements - 1;
 	}
 
 	/// Warning: This is not thread-safe.
 	WaitFreeQueue(const WaitFreeQueue &rhs)
-	:head(rhs.head), tail(rhs.tail), maxElementsMask(rhs.maxElementsMask)
+	:maxElementsMask(rhs.maxElementsMask), head(rhs.head), tail(rhs.tail)
 	{
 		size_t maxElements = rhs.maxElementsMask+1;
 		data = new T[maxElements];
@@ -144,9 +144,14 @@ public:
 		if (!success)
 		{
 			DoubleCapacity();
-			success = Insert(value);
+#ifdef _DEBUG
+			success = 
+#endif
+				Insert(value);
 		}
+#ifdef _DEBUG
 		assert(success);
+#endif
 	}
 
 	/// Re-allocates the queue to the new maximum size. All old elements are copied over.
@@ -165,7 +170,7 @@ public:
 		data = newData;
 		head = 0;
 		tail = newTail;
-		maxElementsMask = newSize - 1;
+		maxElementsMask = (unsigned long)newSize - 1;
 	}
 
 	/// Resizes this queue to hold twice the amount of maximum elements.
@@ -282,7 +287,7 @@ public:
 		if (head == tail)
 			return;
 		size_t head_ = (head + 1) & maxElementsMask;
-		head = head_;
+		head = (unsigned long)head_;
 	}
 
 private:

+ 147 - 144
Source/ThirdParty/kNet/include/kNet/win32/WS2Include.h

@@ -1,144 +1,147 @@
-/* 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
+/* 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/ */
+
+// Modified by Lasse Oorni for Urho3D
+
+#ifdef _WIN64
+#include "kNet/64BitAllocDebugger.h"
+#include <stdio.h>
+// Urho3D: windows.h in lowercase to fix MinGW cross-compiling on a case-sensitive system
+#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

+ 253 - 254
Source/ThirdParty/kNet/src/Clock.cpp

@@ -1,254 +1,253 @@
-/* Copyright 2010 Jukka Jylänki
-
-   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 Clock.cpp
-	@brief */
-
-#if defined(__unix__) || defined(__native_client__) || defined(EMSCRIPTEN) || defined(ANDROID) || defined(__APPLE__) || defined (__CYGWIN__)
-#include <time.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/time.h>
-#endif
-
-#ifdef WIN32
-#define NOMINMAX
-#include <windows.h>
-#endif
-
-#ifdef EMSCRIPTEN
-#include <emscripten.h>
-#endif
-
-#include "kNetBuildConfig.h"
-#include "kNet/Clock.h"
-#include "kNet/NetworkLogging.h"
-
-namespace kNet
-{
-
-#ifdef WIN32
-LARGE_INTEGER Clock::ddwTimerFrequency;
-#endif
-
-tick_t Clock::appStartTime = 0;
-
-Clock impl;
-
-void Clock::InitClockData()
-{
-	if (appStartTime == 0)
-		appStartTime = Tick();
-
-#ifdef WIN32
-	if (!QueryPerformanceFrequency(&ddwTimerFrequency))
-	{
-		LOG(LogError, "The system doesn't support high-resolution timers!");
-		ddwTimerFrequency.HighPart = (unsigned long)-1;
-		ddwTimerFrequency.LowPart = (unsigned long)-1;
-	}
-
-	if (ddwTimerFrequency.HighPart > 0)
-		LOG(LogError, "Warning: Clock::TicksPerSec will yield invalid timing data!");
-
-	if (appStartTime == 0)
-	{
-#if WINVER >= 0x0600 && !defined(KNET_ENABLE_WINXP_SUPPORT)
-		appStartTime = (tick_t)GetTickCount64();
-#else
-		appStartTime = (tick_t)GetTickCount();
-#endif		
-	}
-
-	///\todo Test here that the return values of QueryPerformanceCounter is nondecreasing.
-#endif
-}
-
-Clock::Clock()
-{
-	InitClockData();
-}
-
-void Clock::Sleep(int milliseconds)
-{
-#ifdef WIN8RT
-#pragma WARNING(Clock::Sleep has not been implemented!)
-#elif defined(WIN32)
-	::Sleep(milliseconds);
-#elif !defined(__native_client__) && !defined(EMSCRIPTEN) && !defined(__APPLE__)
-	// http://linux.die.net/man/2/nanosleep
-	timespec ts;
-	ts.tv_sec = milliseconds / 1000;
-	ts.tv_nsec = (milliseconds - ts.tv_sec * 1000) * 1000 * 1000;
-	int ret = nanosleep(&ts, NULL);
-	if (ret == -1)
-		LOG(LogError, "nanosleep returned -1! Reason: %s(%d).", strerror(errno), (int)errno);
-#else
-#warning Clock::Sleep has not been implemented!
-#endif
-}
-
-int Clock::Year()
-{
-#ifdef WIN32
-	SYSTEMTIME s;
-	GetSystemTime(&s);
-	return s.wYear;
-#else
-	///\todo.
-	return 0;
-#endif
-}
-
-int Clock::Month()
-{
-#ifdef WIN32
-	SYSTEMTIME s;
-	GetSystemTime(&s);
-	return s.wMonth;
-#else
-	///\todo.
-	return 0;
-#endif
-}
-
-int Clock::Day()
-{
-#ifdef WIN32
-	SYSTEMTIME s;
-	GetSystemTime(&s);
-	return s.wDay;
-#else
-	///\todo.
-	return 0;
-#endif
-}
-
-int Clock::Hour()
-{
-#ifdef WIN32
-	SYSTEMTIME s;
-	GetSystemTime(&s);
-	return s.wHour;
-#else
-	///\todo.
-	return 0;
-#endif
-}
-
-int Clock::Min()
-{
-#ifdef WIN32
-	SYSTEMTIME s;
-	GetSystemTime(&s);
-	return s.wMinute;
-#else
-	///\todo.
-	return 0;
-#endif
-}
-
-int Clock::Sec()
-{
-#ifdef WIN32
-	SYSTEMTIME s;
-	GetSystemTime(&s);
-	return s.wSecond;
-#else
-	///\todo.
-	return 0;
-#endif
-}
-
-unsigned long Clock::SystemTime()
-{
-#ifdef WIN32
-#if WINVER >= 0x0600 && !defined(KNET_ENABLE_WINXP_SUPPORT)
-	return (unsigned long)GetTickCount64();
-#else
-	return (unsigned long)GetTickCount();
-#endif		
-#else
-	return TickU32();
-#endif
-}
-/*
-tick_t Clock::ApplicationStartupTick()
-{
-	return appStartTime;
-}
-*/
-unsigned long Clock::Time()
-{
-	return (unsigned long)(Tick() - appStartTime);
-}
-
-tick_t Clock::Tick()
-{
-#if defined(ANDROID)
-	struct timespec res;
-	clock_gettime(CLOCK_REALTIME, &res);
-	return 1000000000ULL*res.tv_sec + (tick_t)res.tv_nsec;
-#elif defined(EMSCRIPTEN)
-	// emscripten_get_now() returns a wallclock time as a float in milliseconds (1e-3).
-	// scale it to microseconds (1e-6) and return as a tick.
-	return (tick_t)(((double)emscripten_get_now()) * 1e3);
-//	return (tick_t)clock();
-#elif defined(WIN32)
-	LARGE_INTEGER ddwTimer;
-	QueryPerformanceCounter(&ddwTimer);
-	return ddwTimer.QuadPart;
-#elif defined(_POSIX_MONOTONIC_CLOCK)
-	timespec t;
-	clock_gettime(CLOCK_MONOTONIC, &t);
-	return (tick_t)t.tv_sec * 1000 * 1000 * 1000 + (tick_t)t.tv_nsec;
-#elif defined(_POSIX_C_SOURCE) || defined(__APPLE__)
-	timeval t;
-	gettimeofday(&t, NULL);
-	return (tick_t)t.tv_sec * 1000 * 1000 + (tick_t)t.tv_usec;
-#else
-	return (tick_t)clock();
-#endif
-}
-
-unsigned long Clock::TickU32()
-{
-#ifdef WIN32
-	LARGE_INTEGER ddwTimer;
-	QueryPerformanceCounter(&ddwTimer);
-	return ddwTimer.LowPart;
-#else
-	return (unsigned long)Tick();
-#endif
-}
-
-tick_t Clock::TicksPerSec()
-{
-#if defined(ANDROID)
-	return 1000000000ULL; // 1e9 == nanoseconds.
-#elif defined(EMSCRIPTEN)
-	return 1000000ULL; // 1e6 == microseconds.
-//	return CLOCKS_PER_SEC;
-#elif defined(WIN32)
-	return ddwTimerFrequency.QuadPart;
-#elif defined(_POSIX_MONOTONIC_CLOCK)
-	return 1000 * 1000 * 1000;
-#elif defined(_POSIX_C_SOURCE) || defined(__APPLE__)
-	return 1000 * 1000;
-#else
-	return CLOCKS_PER_SEC;
-#endif
-}
-
-} // ~kNet
+/* Copyright 2010 Jukka Jylänki
+
+   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 Clock.cpp
+	@brief */
+
+#if defined(__unix__) || defined(__native_client__) || defined(EMSCRIPTEN) || defined(ANDROID) || defined(__APPLE__) || defined (__CYGWIN__)
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+#endif
+
+#ifdef WIN32
+#define NOMINMAX
+#include <windows.h>
+#endif
+
+#ifdef EMSCRIPTEN
+#include <emscripten.h>
+#endif
+
+#include "kNet/Clock.h"
+#include "kNet/NetworkLogging.h"
+
+namespace kNet
+{
+
+#ifdef WIN32
+LARGE_INTEGER Clock::ddwTimerFrequency;
+#endif
+
+tick_t Clock::appStartTime = 0;
+
+Clock impl;
+
+void Clock::InitClockData()
+{
+	if (appStartTime == 0)
+		appStartTime = Tick();
+
+#ifdef WIN32
+	if (!QueryPerformanceFrequency(&ddwTimerFrequency))
+	{
+		KNET_LOG(LogError, "The system doesn't support high-resolution timers!");
+		ddwTimerFrequency.HighPart = (unsigned long)-1;
+		ddwTimerFrequency.LowPart = (unsigned long)-1;
+	}
+
+	if (ddwTimerFrequency.HighPart > 0)
+		KNET_LOG(LogError, "Warning: Clock::TicksPerSec will yield invalid timing data!");
+
+	if (appStartTime == 0)
+	{
+#if WINVER >= 0x0600 && !defined(KNET_ENABLE_WINXP_SUPPORT)
+		appStartTime = (tick_t)GetTickCount64();
+#else
+		appStartTime = (tick_t)GetTickCount();
+#endif		
+	}
+
+	///\todo Test here that the return values of QueryPerformanceCounter is nondecreasing.
+#endif
+}
+
+Clock::Clock()
+{
+	InitClockData();
+}
+
+void Clock::Sleep(int milliseconds)
+{
+#ifdef WIN8RT
+#pragma WARNING(Clock::Sleep has not been implemented!)
+#elif defined(WIN32)
+	::Sleep(milliseconds);
+#elif !defined(__native_client__) && !defined(EMSCRIPTEN) && !defined(__APPLE__)
+	// http://linux.die.net/man/2/nanosleep
+	timespec ts;
+	ts.tv_sec = milliseconds / 1000;
+	ts.tv_nsec = (milliseconds - ts.tv_sec * 1000) * 1000 * 1000;
+	int ret = nanosleep(&ts, NULL);
+	if (ret == -1)
+		KNET_LOG(LogError, "nanosleep returned -1! Reason: %s(%d).", strerror(errno), (int)errno);
+#else
+#warning Clock::Sleep has not been implemented!
+#endif
+}
+
+int Clock::Year()
+{
+#ifdef WIN32
+	SYSTEMTIME s;
+	GetSystemTime(&s);
+	return s.wYear;
+#else
+	///\todo.
+	return 0;
+#endif
+}
+
+int Clock::Month()
+{
+#ifdef WIN32
+	SYSTEMTIME s;
+	GetSystemTime(&s);
+	return s.wMonth;
+#else
+	///\todo.
+	return 0;
+#endif
+}
+
+int Clock::Day()
+{
+#ifdef WIN32
+	SYSTEMTIME s;
+	GetSystemTime(&s);
+	return s.wDay;
+#else
+	///\todo.
+	return 0;
+#endif
+}
+
+int Clock::Hour()
+{
+#ifdef WIN32
+	SYSTEMTIME s;
+	GetSystemTime(&s);
+	return s.wHour;
+#else
+	///\todo.
+	return 0;
+#endif
+}
+
+int Clock::Min()
+{
+#ifdef WIN32
+	SYSTEMTIME s;
+	GetSystemTime(&s);
+	return s.wMinute;
+#else
+	///\todo.
+	return 0;
+#endif
+}
+
+int Clock::Sec()
+{
+#ifdef WIN32
+	SYSTEMTIME s;
+	GetSystemTime(&s);
+	return s.wSecond;
+#else
+	///\todo.
+	return 0;
+#endif
+}
+
+unsigned long Clock::SystemTime()
+{
+#ifdef WIN32
+#if WINVER >= 0x0600 && !defined(KNET_ENABLE_WINXP_SUPPORT)
+	return (unsigned long)GetTickCount64();
+#else
+	return (unsigned long)GetTickCount();
+#endif		
+#else
+	return TickU32();
+#endif
+}
+/*
+tick_t Clock::ApplicationStartupTick()
+{
+	return appStartTime;
+}
+*/
+unsigned long Clock::Time()
+{
+	return (unsigned long)(Tick() - appStartTime);
+}
+
+tick_t Clock::Tick()
+{
+#if defined(ANDROID)
+	struct timespec res;
+	clock_gettime(CLOCK_REALTIME, &res);
+	return 1000000000ULL*res.tv_sec + (tick_t)res.tv_nsec;
+#elif defined(EMSCRIPTEN)
+	// emscripten_get_now() returns a wallclock time as a float in milliseconds (1e-3).
+	// scale it to microseconds (1e-6) and return as a tick.
+	return (tick_t)(((double)emscripten_get_now()) * 1e3);
+//	return (tick_t)clock();
+#elif defined(WIN32)
+	LARGE_INTEGER ddwTimer;
+	QueryPerformanceCounter(&ddwTimer);
+	return ddwTimer.QuadPart;
+#elif defined(_POSIX_MONOTONIC_CLOCK)
+	timespec t;
+	clock_gettime(CLOCK_MONOTONIC, &t);
+	return (tick_t)t.tv_sec * 1000 * 1000 * 1000 + (tick_t)t.tv_nsec;
+#elif defined(_POSIX_C_SOURCE) || defined(__APPLE__)
+	timeval t;
+	gettimeofday(&t, NULL);
+	return (tick_t)t.tv_sec * 1000 * 1000 + (tick_t)t.tv_usec;
+#else
+	return (tick_t)clock();
+#endif
+}
+
+unsigned long Clock::TickU32()
+{
+#ifdef WIN32
+	LARGE_INTEGER ddwTimer;
+	QueryPerformanceCounter(&ddwTimer);
+	return ddwTimer.LowPart;
+#else
+	return (unsigned long)Tick();
+#endif
+}
+
+tick_t Clock::TicksPerSec()
+{
+#if defined(ANDROID)
+	return 1000000000ULL; // 1e9 == nanoseconds.
+#elif defined(EMSCRIPTEN)
+	return 1000000ULL; // 1e6 == microseconds.
+//	return CLOCKS_PER_SEC;
+#elif defined(WIN32)
+	return ddwTimerFrequency.QuadPart;
+#elif defined(_POSIX_MONOTONIC_CLOCK)
+	return 1000 * 1000 * 1000;
+#elif defined(_POSIX_C_SOURCE) || defined(__APPLE__)
+	return 1000 * 1000;
+#else
+	return CLOCKS_PER_SEC;
+#endif
+}
+
+} // ~kNet

+ 2 - 1
Source/ThirdParty/kNet/src/DataDeserializer.cpp

@@ -21,6 +21,7 @@
 
 #include "kNet/DebugMemoryLeakCheck.h"
 
+#include "kNet/VLEPacker.h"
 #include "kNet/DataDeserializer.h"
 #include "kNet/NetException.h"
 
@@ -301,7 +302,7 @@ void DataDeserializer::SkipBits(int numBits)
 
 std::string DataDeserializer::ReadString()
 {
-	u32 length = (iter ? GetDynamicElemCount() : Read<u8>());
+	u32 length = (iter ? GetDynamicElemCount() : ReadVLE<VLE8_16_32>());
 	if (BitsLeft() < length*8)
 		throw NetException("Not enough bytes left in DataDeserializer::ReadString!");
 

+ 4 - 4
Source/ThirdParty/kNet/src/DataSerializer.cpp

@@ -73,7 +73,7 @@ DataSerializer::DataSerializer(std::vector<char> &data_, size_t maxBytes_)
 {
 	if (data_.size() < maxBytes_)
 		data_.resize(maxBytes_);
-	if (data_.size() == 0 || maxBytes_ == 0)
+	if (data_.empty() || maxBytes_ == 0)
 		throw NetException("Cannot instantiate a DataSerializer object to a zero-sized std::vector-based buffer!");
 	data = &data_[0];
 	maxBytes = maxBytes_;
@@ -85,7 +85,7 @@ DataSerializer::DataSerializer(std::vector<char> &data_, size_t maxBytes_, const
 {
 	if (data_.size() < maxBytes_)
 		data_.resize(maxBytes_);
-	if (data_.size() == 0 || maxBytes_ == 0)
+	if (data_.empty() || maxBytes_ == 0)
 		throw NetException("Cannot instantiate a DataSerializer object to a zero-sized std::vector-based buffer!");
 	data = &data_[0];
 	maxBytes = maxBytes_;
@@ -290,7 +290,7 @@ int DataSerializer::AddVector2D(float x, float y, int magnitudeIntegerBits, int
 	{
 		// 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));
+		AddQuantizedFloat(-PI, PI, directionBits, angle);
 		return magnitudeIntegerBits + magnitudeDecimalBits + directionBits;
 	}
 	else
@@ -421,7 +421,7 @@ void DataSerializer::AddString(const char *str)
 	if (iter)
 		SetVaryingElemSize((u32)len);
 	else
-		Add<u8>(len);
+		AddVLE<VLE8_16_32>(len);
 
 	AddArray<s8>((const s8*)str, len);
 }

+ 15 - 15
Source/ThirdParty/kNet/src/FragmentedTransferManager.cpp

@@ -46,7 +46,7 @@ bool FragmentedSendManager::FragmentedTransfer::RemoveMessage(NetworkMessage *me
 		{
 			message->transfer = 0;
 			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);
+			KNET_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 false;
@@ -59,7 +59,7 @@ FragmentedSendManager::FragmentedTransfer *FragmentedSendManager::AllocateNewFra
 	transfer->id = -1;
 	transfer->totalNumFragments = 0;
 
-	LOG(LogObjectAlloc, "Allocated new fragmented transfer %p.", transfer);
+	KNET_LOG(LogObjectAlloc, "Allocated new fragmented transfer %p.", transfer);
 
 	return transfer;
 }
@@ -74,10 +74,10 @@ void FragmentedSendManager::FreeFragmentedTransfer(FragmentedTransfer *transfer)
 		if (&*iter == transfer)
 		{
 			transfers.erase(iter);
-			LOG(LogObjectAlloc, "Freed fragmented transfer ID=%d, numFragments: %d (%p).", transfer->id, (int)transfer->totalNumFragments, transfer);
+			KNET_LOG(LogObjectAlloc, "Freed fragmented transfer ID=%d, numFragments: %d (%p).", transfer->id, (int)transfer->totalNumFragments, transfer);
 			return;
 		}
-	LOG(LogError, "Tried to free a fragmented send struct that didn't exist!");
+	KNET_LOG(LogError, "Tried to free a fragmented send struct that didn't exist!");
 }
 
 void FragmentedSendManager::RemoveMessage(FragmentedTransfer *transfer, NetworkMessage *message)
@@ -85,7 +85,7 @@ void FragmentedSendManager::RemoveMessage(FragmentedTransfer *transfer, NetworkM
 	bool success = transfer->RemoveMessage(message);
 	if (!success)
 	{
-		LOG(LogError, "Tried to remove a nonexisting message from a fragmented send struct!");
+		KNET_LOG(LogError, "Tried to remove a nonexisting message from a fragmented send struct!");
 		return;
 	}
 
@@ -119,32 +119,32 @@ bool FragmentedSendManager::AllocateFragmentedTransferID(FragmentedTransfer &tra
 		return false;
 	transfer.id = transferID;
 
-	LOG(LogObjectAlloc, "Allocated a transferID %d to a transfer of %d fragments.", transfer.id, (int)transfer.totalNumFragments);
+	KNET_LOG(LogObjectAlloc, "Allocated a transferID %d to a transfer of %d fragments.", transfer.id, (int)transfer.totalNumFragments);
 
 	return true;
 }
 
 void FragmentedSendManager::FreeAllTransfers()
 {
-	while(transfers.size() > 0)
+	while(!transfers.empty())
 		FreeFragmentedTransfer(&transfers.front());
 }
 
 void FragmentedReceiveManager::NewFragmentStartReceived(int transferID, int numTotalFragments, const char *data, size_t numBytes)
 {
 	assert(data);
-	LOG(LogVerbose, "Received a fragmentStart of size %db (#total fragments %d) for a transfer with ID %d.", (int)numBytes, numTotalFragments, transferID);
+	KNET_LOG(LogVerbose, "Received a fragmentStart of size %db (#total fragments %d) for a transfer with ID %d.", (int)numBytes, numTotalFragments, transferID);
 
 	if (numBytes == 0 || numTotalFragments <= 1)
 	{
-		LOG(LogError, "Discarding degenerate fragmentStart of size %db and numTotalFragments=%db!", (int)numBytes, numTotalFragments);
+		KNET_LOG(LogError, "Discarding degenerate fragmentStart of size %db and numTotalFragments=%db!", (int)numBytes, numTotalFragments);
 		return;
 	}
 
 	for(size_t i = 0; i < transfers.size(); ++i)
 		if (transfers[i].transferID == transferID)
 		{
-			LOG(LogError, "An existing transfer with ID %d existed! Deleting it.", transferID);
+			KNET_LOG(LogError, "An existing transfer with ID %d existed! Deleting it.", transferID);
 			transfers.erase(transfers.begin() + i);
 			--i;
 		}
@@ -160,11 +160,11 @@ void FragmentedReceiveManager::NewFragmentStartReceived(int transferID, int numT
 
 bool FragmentedReceiveManager::NewFragmentReceived(int transferID, int fragmentNumber, const char *data, size_t numBytes)
 {
-	LOG(LogVerbose, "Received a fragment of size %db (index %d) for a transfer with ID %d.", (int)numBytes, fragmentNumber, transferID);
+	KNET_LOG(LogVerbose, "Received a fragment of size %db (index %d) for a transfer with ID %d.", (int)numBytes, fragmentNumber, transferID);
 
 	if (numBytes == 0)
 	{
-		LOG(LogError, "Discarding fragment of size 0!");
+		KNET_LOG(LogError, "Discarding fragment of size 0!");
 		return false;
 	}
 
@@ -176,7 +176,7 @@ bool FragmentedReceiveManager::NewFragmentReceived(int transferID, int fragmentN
 			for(size_t j = 0; j < transfer.fragments.size(); ++j)
 				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",
+					KNET_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);
 					return false;
 				}
@@ -188,14 +188,14 @@ bool FragmentedReceiveManager::NewFragmentReceived(int transferID, int fragmentN
 
 			if (transfer.fragments.size() >= (size_t)transfer.numTotalFragments)
 			{
-				LOG(LogData, "Finished receiving a fragmented transfer that consisted of %d fragments (transferID=%d).",
+				KNET_LOG(LogData, "Finished receiving a fragmented transfer that consisted of %d fragments (transferID=%d).",
 					(int)transfer.fragments.size(), transfer.transferID);
 				return true;
 			}
 			else
 				return false;
 		}
-	LOG(LogError, "Received a fragment of size %db (index %d) for a transfer with ID %d, but that transfer had not been initiated!",
+	KNET_LOG(LogError, "Received a fragment of size %db (index %d) for a transfer with ID %d, but that transfer had not been initiated!",
 		(int)numBytes, fragmentNumber, transferID);
 	return false;
 }

+ 61 - 57
Source/ThirdParty/kNet/src/MessageConnection.cpp

@@ -86,20 +86,24 @@ std::string ConnectionStateToString(ConnectionState state)
 }
 
 MessageConnection::MessageConnection(Network *owner_, NetworkServer *ownerServer_, Socket *socket_, ConnectionState startingState)
-:owner(owner_), ownerServer(ownerServer_), inboundMessageHandler(0), socket(socket_), 
-bOutboundSendsPaused(false),
+:owner(owner_), ownerServer(ownerServer_), workerThread(0), 
+#ifdef KNET_THREAD_CHECKING_ENABLED
+workerThreadId(Thread::NullThreadId()),
+#endif
 outboundAcceptQueue(16*1024), inboundMessageQueue(16*1024), 
-rtt(0.f), packetsInPerSec(0), packetsOutPerSec(0), 
-msgsInPerSec(0), msgsOutPerSec(0), bytesInPerSec(0), bytesOutPerSec(0),
-lastHeardTime(Clock::Tick()), outboundMessageNumberCounter(0), outboundReliableMessageNumberCounter(0),
 #ifdef KNET_NO_MAXHEAP
 outboundQueue(16 * 1024), 
 #endif
-workerThread(0),
-bytesInTotal(0), bytesOutTotal(0)
-#ifdef KNET_THREAD_CHECKING_ENABLED
-,workerThreadId(Thread::NullThreadId())
-#endif
+inboundMessageHandler(0), socket(socket_), 
+bOutboundSendsPaused(false), 
+rtt(0.f), 
+lastHeardTime(Clock::Tick()), 
+packetsInPerSec(0), packetsOutPerSec(0), 
+msgsInPerSec(0), msgsOutPerSec(0),
+bytesInPerSec(0), bytesOutPerSec(0), 
+bytesInTotal(0), bytesOutTotal(0),
+outboundMessageNumberCounter(0),
+outboundReliableMessageNumberCounter(0)
 {
 	connectionState = startingState;
 	networkSendSimulator.owner = this;
@@ -110,7 +114,7 @@ bytesInTotal(0), bytesOutTotal(0)
 
 MessageConnection::~MessageConnection()
 {
-	LOG(LogObjectAlloc, "Deleting MessageConnection %p.", this);
+	KNET_LOG(LogObjectAlloc, "Deleting MessageConnection %p.", this);
 
 	// This MessageConnection must have been detached from its owners before deleting it. 
 	// (owner->CloseConnection must have been called)
@@ -193,7 +197,7 @@ bool MessageConnection::WaitToEstablishConnection(int maxMSecsToWait)
 	while(GetConnectionState() == ConnectionPending && !timer.Test())
 		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.",
+	KNET_LOG(LogWaits, "MessageConnection::WaitToEstablishConnection: Waited %f msecs for connection. Result: %s.",
 		timer.MSecsElapsed(), ConnectionStateToString(GetConnectionState()).c_str());
 
 	return GetConnectionState() == ConnectionOK;
@@ -209,7 +213,7 @@ void MessageConnection::Disconnect(int maxMSecsToWait)
 	if (connectionState == ConnectionClosed || connectionState == ConnectionDisconnecting)
 		return;
 
-	LOG(LogInfo, "MessageConnection::Disconnect(%d msecs): Write-closing connection. connectionState = %s, socket readOpen:%s, socket writeOpen:%s.", 
+	KNET_LOG(LogInfo, "MessageConnection::Disconnect(%d msecs): Write-closing connection. connectionState = %s, socket readOpen:%s, socket writeOpen:%s.", 
 		maxMSecsToWait, ConnectionStateToString(connectionState).c_str(), socket->IsReadOpen() ? "true":"false",
 		socket->IsWriteOpen() ? "true":"false");
 	assert(maxMSecsToWait >= 0);
@@ -224,7 +228,7 @@ void MessageConnection::Disconnect(int maxMSecsToWait)
 			Clock::Sleep(1); ///\todo Instead of waiting multiple 1msec slices, should wait for proper event.
 		}
 
-		LOG(LogWaits, "MessageConnection::Disconnect: Waited %f msecs for disconnection. Result: %s.",
+		KNET_LOG(LogWaits, "MessageConnection::Disconnect: Waited %f msecs for disconnection. Result: %s.",
 			timer.MSecsElapsed(), ConnectionStateToString(GetConnectionState()).c_str());
 	}
 
@@ -239,14 +243,14 @@ void MessageConnection::Close(int maxMSecsToWait) // [main thread]
 	if (maxMSecsToWait > 0 && socket && socket->IsWriteOpen())
 	{
 		Disconnect(maxMSecsToWait);
-		LOG(LogInfo, "MessageConnection::Close(%d msecs): Disconnecting. connectionState = %s, readOpen:%s, writeOpen:%s.", 
+		KNET_LOG(LogInfo, "MessageConnection::Close(%d msecs): Disconnecting. connectionState = %s, readOpen:%s, writeOpen:%s.", 
 			maxMSecsToWait, ConnectionStateToString(connectionState).c_str(), (socket && socket->IsReadOpen()) ? "true":"false",
 			(socket && socket->IsWriteOpen()) ? "true":"false");
 	}
 
 	if (owner)
 	{
-		LOG(LogInfo, "MessageConnection::Close: Closed connection to %s.", ToString().c_str());
+		KNET_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.
 		assert(!IsWorkerThreadRunning());
 		owner = 0;
@@ -263,19 +267,19 @@ void MessageConnection::Close(int maxMSecsToWait) // [main thread]
 	connectionState = ConnectionClosed;
 
 	if (outboundAcceptQueue.Size() > 0)
-		LOG(LogVerbose, "MessageConnection::Close(): Had %d messages in outboundAcceptQueue!", (int)outboundAcceptQueue.Size());
+		KNET_LOG(LogVerbose, "MessageConnection::Close(): Had %d messages in outboundAcceptQueue!", (int)outboundAcceptQueue.Size());
 
 	if (outboundQueue.Size() > 0)
-		LOG(LogVerbose, "MessageConnection::Close(): Had %d messages in outboundQueue!", (int)outboundQueue.Size());
+		KNET_LOG(LogVerbose, "MessageConnection::Close(): Had %d messages in outboundQueue!", (int)outboundQueue.Size());
 
 	if (inboundMessageQueue.Size() > 0)
-		LOG(LogVerbose, "MessageConnection::Close(): Had %d messages in inboundMessageQueue!", (int)inboundMessageQueue.Size());
+		KNET_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());
+		KNET_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.empty())
+		KNET_LOG(LogVerbose, "MessageConnection::Close(): Had %d messages in fragmentedReceives.transfers list!", (int)fragmentedReceives.transfers.size());
 
 	FreeMessageData();
 }
@@ -304,7 +308,7 @@ void MessageConnection::SetPeerClosed()
 	switch(connectionState)
 	{
 	case ConnectionPending:
-		LOG(LogVerbose, "Peer closed connection when in ConnectionPending state!"); 
+		KNET_LOG(LogVerbose, "Peer closed connection when in ConnectionPending state!"); 
 		connectionState = ConnectionClosed; // Just tear it down, the peer rejected the connection.
 		break;
 	case ConnectionOK:
@@ -317,7 +321,7 @@ void MessageConnection::SetPeerClosed()
 	case ConnectionClosed:
 		break; // We've already in the state where peer has closed the connection, no need to do anything.
 	default:
-		LOG(LogError, "SetPeerClosed() called at an unexpected time. The internal connectionState has an invalid value %d!", (int)connectionState);
+		KNET_LOG(LogError, "SetPeerClosed() called at an unexpected time. The internal connectionState has an invalid value %d!", (int)connectionState);
 		assert(false);
 		break;
 	}
@@ -376,7 +380,7 @@ void MessageConnection::DetectConnectionTimeOut()
 	float lastHeardSince = LastHeardTime();
 	if (lastHeardSince > connectionLostTimeout)
 	{
-		LOG(LogInfo, "It's been %.2fms since last heard from other end. connectionLostTimeout=%.2fms, so closing connection.",
+		KNET_LOG(LogInfo, "It's been %.2fms since last heard from other end. connectionLostTimeout=%.2fms, so closing connection.",
 			lastHeardSince, connectionLostTimeout);
 		connectionState = ConnectionClosed;
 	}
@@ -393,7 +397,7 @@ void MessageConnection::AcceptOutboundMessages() // [worker thread]
 		{
 			NetworkMessage *msg = *outboundAcceptQueue.Front();
 			outboundAcceptQueue.PopFront();
-			LOG(LogVerbose, "Warning: Discarding outbound network message with ID %d, since the connection is write-closed.", 
+			KNET_LOG(LogVerbose, "Warning: Discarding outbound network message with ID %d, since the connection is write-closed.", 
 				msg->id);
 			// assert(!HaveOutboundMessageWithContentID(msg));
 			FreeMessage(msg);
@@ -453,7 +457,7 @@ void MessageConnection::UpdateConnection() // [Called from the worker thread]
 		if (connectionState == ConnectionOK || connectionState == ConnectionDisconnecting)
 			if (!socket || !socket->IsReadOpen())
 			{
-				LOG(LogInfo, "Peer closed connection.");
+				KNET_LOG(LogInfo, "Peer closed connection.");
 				SetPeerClosed();
 			}
 
@@ -478,7 +482,7 @@ void MessageConnection::UpdateConnection() // [Called from the worker thread]
 NetworkMessage *MessageConnection::AllocateNewMessage()
 {
 	NetworkMessage *msg = messagePool.New();
-	LOG(LogObjectAlloc, "MessageConnection::AllocateMessage %p!", msg);
+	KNET_LOG(LogObjectAlloc, "MessageConnection::AllocateMessage %p!", msg);
 	return msg;
 }
 
@@ -493,7 +497,7 @@ void MessageConnection::FreeMessage(NetworkMessage *msg) // [main and worker thr
 		msg->transfer = 0;
 	}
 
-	LOG(LogObjectAlloc, "MessageConnection::FreeMessage %p!", msg);
+	KNET_LOG(LogObjectAlloc, "MessageConnection::FreeMessage %p!", msg);
 	messagePool.Free(msg);
 }
 
@@ -502,7 +506,7 @@ NetworkMessage *MessageConnection::StartNewMessage(unsigned long id, size_t numB
 	NetworkMessage *msg = AllocateNewMessage();
 	if (!msg)
 	{
-		LOG(LogError, "MessageConnection::SendMessage: StartNewMessage failed! Discarding message send.");
+		KNET_LOG(LogError, "MessageConnection::SendMessage: StartNewMessage failed! Discarding message send.");
 		return 0; // Failed to allocate a new message. This is caused only by memory allocation issues.
 	}
 
@@ -545,7 +549,7 @@ void MessageConnection::SplitAndQueueMessage(NetworkMessage *message, bool inter
 	const size_t totalNumFragments = (message->dataSize + maxFragmentSize - 1) / maxFragmentSize;
 	assert(totalNumFragments > 1); // Shouldn't be calling this function if the message can well fit into one fragment.
 
-	LOG(LogVerbose, "Splitting a message of %db into %d fragments of %db size at most.",
+	KNET_LOG(LogVerbose, "Splitting a message of %db into %d fragments of %db size at most.",
 		(int)message->dataSize, (int)totalNumFragments, (int)maxFragmentSize);
 
 /** \todo Would like to do this:
@@ -567,12 +571,12 @@ void MessageConnection::SplitAndQueueMessage(NetworkMessage *message, bool inter
 
 	if (!message->reliable)
 	{
-		LOG(LogVerbose, "Upgraded a nonreliable message with ID %d and size %d to a reliable message since it had to be fragmented!", (int)message->id, (int)message->dataSize);
+		KNET_LOG(LogVerbose, "Upgraded a nonreliable message with ID %d and size %d to a reliable message since it had to be fragmented!", (int)message->id, (int)message->dataSize);
 	}
 
 	if (message->contentID != 0)
 	{
-		LOG(LogVerbose, "Warning: Content IDs are not supported with fragmented transfers. Removing the content ID %d of message %d of size %d.",
+		KNET_LOG(LogVerbose, "Warning: Content IDs are not supported with fragmented transfers. Removing the content ID %d of message %d of size %d.",
 			(int)message->contentID, (int)message->id, (int)message->Size());
 		message->contentID = 0;
 	}
@@ -618,7 +622,7 @@ void MessageConnection::SplitAndQueueMessage(NetworkMessage *message, bool inter
 			if (!outboundAcceptQueue.Insert(fragment))
 			{
 				///\todo Is it possible to check beforehand if this criteria is avoided, or if we are doomed?
-				LOG(LogError, "Critical: Failed to add message fragment to outboundAcceptQueue! Queue was full. Do not know how to recover here!");
+				KNET_LOG(LogError, "Critical: Failed to add message fragment to outboundAcceptQueue! Queue was full. Do not know how to recover here!");
 				assert(false);
 			}
 		}
@@ -650,7 +654,7 @@ void MessageConnection::EndAndQueueMessage(NetworkMessage *msg, size_t numBytes,
 	if (msg->obsolete || !socket || GetConnectionState() == ConnectionClosed || !socket->IsWriteOpen() || 
 		(internalQueue == false && !IsWriteOpen()))
 	{
-		LOG(LogVerbose, "MessageConnection::EndAndQueueMessage: Discarded message with ID 0x%X and size %d bytes. "
+		KNET_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. "
 			"internalQueue: %s.",
 			(int)msg->id, (int)numBytes, (int)msg->obsolete, socket, ConnectionStateToString(GetConnectionState()).c_str(), (socket && socket->IsWriteOpen()) ? "true" : "false",
@@ -666,7 +670,7 @@ void MessageConnection::EndAndQueueMessage(NetworkMessage *msg, size_t numBytes,
 	assert(msg->dataSize <= msg->Capacity());
 	if (msg->dataSize > msg->Capacity())
 	{
-		LOG(LogError, "Critical! User specified a larger NetworkMessage than there is Capacity() for. Call NetworkMessage::Reserve() "
+		KNET_LOG(LogError, "Critical! User specified a larger NetworkMessage than there is Capacity() for. Call NetworkMessage::Reserve() "
 			"to ensure there is a proper amount of space for the buffer! Specified: %d bytes, Capacity(): %d bytes.",
 			(int)msg->dataSize, (int)msg->Capacity());
 	}
@@ -689,7 +693,7 @@ void MessageConnection::EndAndQueueMessage(NetworkMessage *msg, size_t numBytes,
 
 	if (internalQueue) // if true, we are accessing from the worker thread, and can directly access the outboundQueue member.
 	{
-		LOG(LogVerbose, "MessageConnection::EndAndQueueMessage: Internal-queued message of size %d bytes and ID 0x%X.", (int)msg->Size(), (int)msg->id);
+		KNET_LOG(LogVerbose, "MessageConnection::EndAndQueueMessage: Internal-queued message of size %d bytes and ID 0x%X.", (int)msg->Size(), (int)msg->id);
 //		assert(ContainerUniqueAndNoNullElements(outboundQueue));
 #ifdef KNET_NO_MAXHEAP
 		outboundQueue.InsertWithResize(msg);
@@ -705,13 +709,13 @@ void MessageConnection::EndAndQueueMessage(NetworkMessage *msg, size_t numBytes,
 			if (msg->reliable) // For nonreliable messages it is not critical if we can't enqueue the message. Just discard it.
 			{
 				///\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!");
+				KNET_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);
+		KNET_LOG(LogData, "MessageConnection::EndAndQueueMessage: Queued message of size %d bytes and ID 0x%X.", (int)msg->Size(), (int)msg->id);
 	}
 
 	// Signal the worker thread that there are new outbound events available.
@@ -727,7 +731,7 @@ void MessageConnection::SendMessage(unsigned long id, bool reliable, bool inOrde
 	NetworkMessage *msg = StartNewMessage(id, numBytes);
 	if (!msg)
 	{
-		LOG(LogError, "MessageConnection::SendMessage: StartNewMessage failed! Discarding message send.");
+		KNET_LOG(LogError, "MessageConnection::SendMessage: StartNewMessage failed! Discarding message send.");
 		return;
 	}
 	msg->reliable = reliable;
@@ -764,7 +768,7 @@ void MessageConnection::Process(int maxMessagesToProcess)
 	{
 		if (!inboundMessageHandler)
 		{
-			LOG(LogVerbose, "Warning! Cannot process messages since no message handler registered to connection %s!",
+			KNET_LOG(LogVerbose, "Warning! Cannot process messages since no message handler registered to connection %s!",
 				ToString().c_str());
 			return;
 		}
@@ -814,7 +818,7 @@ void MessageConnection::WaitForMessage(int maxMSecsToWait) // [main thread]
 
 		if (timer.MSecsElapsed() >= 1000.f)
 		{
-				LOG(LogWaits, "MessageConnection::WaitForMessage: Waited %f msecs for a new message. ConnectionState: %s. %d messages in queue.",
+				KNET_LOG(LogWaits, "MessageConnection::WaitForMessage: Waited %f msecs for a new message. ConnectionState: %s. %d messages in queue.",
 				timer.MSecsElapsed(), ConnectionStateToString(GetConnectionState()).c_str(), (int)inboundMessageQueue.Size());
 		}
 	}
@@ -989,7 +993,7 @@ void MessageConnection::CheckAndSaveOutboundMessageWithContentID(NetworkMessage
 		}
 		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.", 
+			KNET_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);
 			msg->obsolete = true;
 		}
@@ -1058,10 +1062,10 @@ void MessageConnection::HandleInboundMessage(packet_id_t packetID, const char *d
 	message_id_t messageID = reader.ReadVLE<VLE8_16_32>(); ///\todo Check that there actually is enough space to read.
 	if (messageID == DataDeserializer::VLEReadError)
 	{
-		LOG(LogError, "Error parsing messageID of a message in socket %s. Data size: %d bytes.", socket->ToString().c_str(), (int)numBytes);
+		KNET_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!");
 	}
-	LOG(LogData, "Received message with ID %d and size %d from peer %s.", (int)packetID, (int)numBytes, socket->ToString().c_str());
+	KNET_LOG(LogData, "Received message with ID %d and size %d from peer %s.", (int)packetID, (int)numBytes, socket->ToString().c_str());
 
 	char str[256];
 	sprintf(str, "messageIn.%u", (unsigned int)messageID);
@@ -1093,7 +1097,7 @@ void MessageConnection::HandleInboundMessage(packet_id_t packetID, const char *d
 			bool success = inboundMessageQueue.Insert(msg);
 			if (!success)
 			{
-				LOG(LogError, "Failed to add a new message of ID %d and size %dB to inbound queue! Queue was full.",
+				KNET_LOG(LogError, "Failed to add a new message of ID %d and size %dB to inbound queue! Queue was full.",
 					(int)messageID, (int)msg->dataSize);
 				FreeMessage(msg);
 			}
@@ -1102,7 +1106,7 @@ void MessageConnection::HandleInboundMessage(packet_id_t packetID, const char *d
 	}
 }
 
-void MessageConnection::SetMaximumDataSendRate(int numBytesPerSec, int numDatagramsPerSec)
+void MessageConnection::SetMaximumDataSendRate(int /*numBytesPerSec*/, int /*numDatagramsPerSec*/)
 {
 }
 
@@ -1124,7 +1128,7 @@ void MessageConnection::SendPingRequestMessage(bool internalQueue)
 
 	ConnectionStatistics &cs = statistics.LockGet();
 	
-	u8 pingID = (u8)((cs.ping.size() == 0) ? 1 : (cs.ping.back().pingID + 1));
+	u8 pingID = (u8)((cs.ping.empty()) ? 1 : (cs.ping.back().pingID + 1));
 	cs.ping.push_back(ConnectionStatistics::PingTrack());
 	ConnectionStatistics::PingTrack &pingTrack = cs.ping.back();
 	pingTrack.replyReceived = false;
@@ -1140,7 +1144,7 @@ void MessageConnection::SendPingRequestMessage(bool internalQueue)
 	msg->profilerName = "PingRequest (1)";
 #endif
 	EndAndQueueMessage(msg, 1, internalQueue);
-	LOG(LogVerbose, "Enqueued ping message %d.", (int)pingID);
+	KNET_LOG(LogVerbose, "Enqueued ping message %d.", (int)pingID);
 }
 
 void MessageConnection::HandlePingRequestMessage(const char *data, size_t numBytes)
@@ -1149,7 +1153,7 @@ void MessageConnection::HandlePingRequestMessage(const char *data, size_t numByt
 
 	if (numBytes != 1)
 	{
-		LOG(LogError, "Malformed PingRequest message received! Size was %d bytes, expected 1 byte!", (int)numBytes);
+		KNET_LOG(LogError, "Malformed PingRequest message received! Size was %d bytes, expected 1 byte!", (int)numBytes);
 		return;
 	}
 
@@ -1161,7 +1165,7 @@ void MessageConnection::HandlePingRequestMessage(const char *data, size_t numByt
 	msg->profilerName = "PingReply (2)";
 #endif
 	EndAndQueueMessage(msg, 1, true);
-	LOG(LogVerbose, "HandlePingRequestMessage: %d.", (int)pingID);
+	KNET_LOG(LogVerbose, "HandlePingRequestMessage: %d.", (int)pingID);
 }
 
 void MessageConnection::HandlePingReplyMessage(const char *data, size_t numBytes)
@@ -1170,7 +1174,7 @@ void MessageConnection::HandlePingReplyMessage(const char *data, size_t numBytes
 
 	if (numBytes != 1)
 	{
-		LOG(LogError, "Malformed PingReply message received! Size was %d bytes, expected 1 byte!", (int)numBytes);
+		KNET_LOG(LogError, "Malformed PingReply message received! Size was %d bytes, expected 1 byte!", (int)numBytes);
 		return;
 	}
 
@@ -1189,12 +1193,12 @@ void MessageConnection::HandlePingReplyMessage(const char *data, size_t numBytes
 			statistics.Unlock();
 			rtt = rttPredictBias * newRtt + (1.f * rttPredictBias) * rtt;
 
-			LOG(LogVerbose, "HandlePingReplyMessage: %d.", (int)pingID);
+			KNET_LOG(LogVerbose, "HandlePingReplyMessage: %d.", (int)pingID);
 			return;
 		}
 
 	statistics.Unlock();
-	LOG(LogError, "Received PingReply with ID %d in socket %s, but no matching PingRequest was ever sent!", (int)pingID, socket->ToString().c_str());
+	KNET_LOG(LogError, "Received PingReply with ID %d in socket %s, but no matching PingRequest was ever sent!", (int)pingID, socket->ToString().c_str());
 }
 
 std::string MessageConnection::ToString() const
@@ -1258,7 +1262,7 @@ void MessageConnection::DumpStatus() const
 		(int)TimeUntilCanSendPacket(),
 		(int)outboundQueue.Size());
 
-	LOGUSER(str);
+	KNET_LOGUSER(str);
 
 	DumpConnectionStatus();
 }
@@ -1287,7 +1291,7 @@ void MessageConnection::AssertInWorkerThreadContext() const
 	kNet::ThreadId currentThreadId = Thread::CurrentThreadId();
 	if (haveWorkerThread && currentThreadId != workerThreadId)
 	{
-		LOG(LogError, "Assert failure in MessageConnection::AssertInWorkerThreadContext()!: haveWorkerThread: %s, currentThreadId: %s, workerThreadId: %s,",
+		KNET_LOG(LogError, "Assert failure in MessageConnection::AssertInWorkerThreadContext()!: haveWorkerThread: %s, currentThreadId: %s, workerThreadId: %s,",
 			haveWorkerThread ? "true" : "false", ThreadIdToString(currentThreadId).c_str(), ThreadIdToString(workerThreadId).c_str());
 		assert(false && "MessageConnection::AssertInWorkerThreadContext assert failure!");
 	}
@@ -1302,7 +1306,7 @@ void MessageConnection::AssertInMainThreadContext() const
 	kNet::ThreadId currentThreadId = Thread::CurrentThreadId();
 	if (haveWorkerThread && currentThreadId == workerThreadId)
 	{
-		LOG(LogError, "Assert failure in MessageConnection::AssertInMainThreadContext()!: haveWorkerThread: %s, currentThreadId: %s, workerThreadId: %s,",
+		KNET_LOG(LogError, "Assert failure in MessageConnection::AssertInMainThreadContext()!: haveWorkerThread: %s, currentThreadId: %s, workerThreadId: %s,",
 			haveWorkerThread ? "true" : "false", ThreadIdToString(currentThreadId).c_str(), ThreadIdToString(workerThreadId).c_str());
 		assert(false && "MessageConnection::AssertInMainThreadContext assert failure!");
 	}

+ 5 - 5
Source/ThirdParty/kNet/src/MessageListParser.cpp

@@ -35,7 +35,7 @@ namespace
 {
 	///\note See BasicSerializedDataTypes.h:31: The order of these elements matches that of the BasicSerializedDataType enum.
 	const char *data[] = { "", "bit", "u8", "s8", "u16", "s16", "u32", "s32", "u64", "s64", "float", "double", "string", "struct" };
-    const size_t typeSizes[] = { (size_t)-1, (size_t)-1, 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, (size_t)-1, (size_t)-1 }; ///< -1 here denotes 'does not apply'.
+	const size_t typeSizes[] = { 0xFFFFFFFF, 0xFFFFFFFF, 1, 1, 2, 2, 4, 4, 8, 8, 4, 8, 0xFFFFFFFF, 0xFFFFFFFF }; // 0xFFFFFFFF here denotes 'does not apply'.
 }
 
 namespace kNet
@@ -46,7 +46,7 @@ BasicSerializedDataType StringToSerialType(const char *type)
 	if (!strcmp(type, "string") || !strcmp(type, "std::string"))
 		return SerialString;
 	assert(NumSerialTypes-2 == NUMELEMS(data));
-	for(int i = 0; i < NUMELEMS(data); ++i)
+	for(size_t i = 0; i < NUMELEMS(data); ++i)
 		if (!strcmp(type, data[i]))
 			return (BasicSerializedDataType)i;
 
@@ -97,7 +97,7 @@ SerializedElementDesc *SerializedMessageList::ParseNode(TiXmlElement *node, Seri
 	{
 		// Cannot have both static count and dynamic count!
 		if (node->Attribute("count") && node->Attribute("varyingCount"))
-			LOG(LogError, "Warning: An XML node contains both 'count' and 'varyingCount' attributes! 'varyingCount' takes precedence.");
+			KNET_LOG(LogError, "Warning: An XML node contains both 'count' and 'varyingCount' attributes! 'varyingCount' takes precedence.");
 
 		if (node->Attribute("dynamicCount"))
 		{
@@ -165,7 +165,7 @@ void SerializedMessageList::ParseMessages(TiXmlElement *root)
 		int success = node->QueryIntAttribute("id", (int*)&desc.id);
 		if (success == TIXML_NO_ATTRIBUTE)
 		{
-			LOG(LogError, "Error parsing message attribute 'id' as int!");
+			KNET_LOG(LogError, "Error parsing message attribute 'id' as int!");
 			node = node->NextSiblingElement("message");
 			continue; 
 		}
@@ -211,7 +211,7 @@ void SerializedMessageList::LoadMessagesFromFile(const char *filename)
 	bool success = doc.LoadFile();
 	if (!success)
 	{
-		LOG(LogError, "TiXmlDocument open failed on filename %s!", filename);
+		KNET_LOG(LogError, "TiXmlDocument open failed on filename %s!", filename);
 		return;
 	}
 

+ 83 - 82
Source/ThirdParty/kNet/src/Network.cpp

@@ -20,11 +20,12 @@
 
 #include <cassert>
 
-#if defined(UNIX) || defined(ANDROID)
+#if defined(KNET_UNIX) || defined(ANDROID)
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <errno.h>
+#include <unistd.h>
 #endif
 
 #ifdef KNET_USE_BOOST
@@ -89,7 +90,9 @@ std::string FormatBytes(u64 numBytes)
 std::string FormatBytes(double numBytes)
 {
 	char str[256];
-	if (numBytes >= 1000.0 * 1000.0 * 1000.0)
+	if (numBytes >= 1000.0 * 1000.0 * 1000.0 * 1000.0)
+		sprintf(str, "%.3f TB", (float)(numBytes / (1024.0 * 1024.0 * 1024.0 * 1024.0)));
+	else if (numBytes >= 1000.0 * 1000.0 * 1000.0)
 		sprintf(str, "%.3f GB", (float)(numBytes / (1024.0 * 1024.0 * 1024.0)));
 	else if (numBytes >= 1000.0 * 1000.0)
 		sprintf(str, "%.3f MB", (float)(numBytes / (1024.0 * 1024.0)));
@@ -119,15 +122,15 @@ void PrintLocalIP()
 	char ac[80];
 	if (gethostname(ac, sizeof(ac)) == KNET_SOCKET_ERROR)
 	{
-		LOG(LogError, "Error getting local host name!");
+		KNET_LOG(LogError, "Error getting local host name!");
 		return;
 	}
-	LOG(LogInfo, "Host name is %s", ac);
+	KNET_LOG(LogInfo, "Host name is %s", ac);
 
 	struct hostent *phe = gethostbyname(ac);
 	if (phe == 0)
 	{
-		LOG(LogError, "Bad host lookup.");
+		KNET_LOG(LogError, "Bad host lookup.");
 		return;
 	}
 
@@ -135,7 +138,7 @@ void PrintLocalIP()
 	{
 		struct in_addr addr;
 		memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
-		LOG(LogInfo, "Address %d: %s", i, inet_ntoa(addr)); ///\todo inet_ntoa is deprecated! doesn't handle IPv6!
+		KNET_LOG(LogInfo, "Address %d: %s", i, inet_ntoa(addr)); ///\todo inet_ntoa is deprecated! doesn't handle IPv6!
 	}
 }
 
@@ -143,82 +146,82 @@ void Network::PrintAddrInfo(const addrinfo *ptr)
 {
 	if (!ptr)
 	{
-		LOG(LogError, "Null pointer passed to Network::PrintAddrInfo!");
+		KNET_LOG(LogError, "Null pointer passed to Network::PrintAddrInfo!");
 		return;
 	}
 
-	LOG(LogInfo, "\tFlags: 0x%x\n", ptr->ai_flags);
-	LOG(LogInfo, "\tFamily: ");
+	KNET_LOG(LogInfo, "\tFlags: 0x%x\n", ptr->ai_flags);
+	KNET_LOG(LogInfo, "\tFamily: ");
 	switch(ptr->ai_family)
 	{
 	case AF_UNSPEC:
-		LOG(LogInfo, "Unspecified\n");
+		KNET_LOG(LogInfo, "Unspecified\n");
 		break;
 	case AF_INET:
-		LOG(LogInfo, "AF_INET (IPv4)\n");
+		KNET_LOG(LogInfo, "AF_INET (IPv4)\n");
 		break;
 	case AF_INET6:
-		LOG(LogInfo, "AF_INET6 (IPv6)\n");
+		KNET_LOG(LogInfo, "AF_INET6 (IPv6)\n");
 		break;
 #ifdef WIN32
 	case AF_NETBIOS:
-		LOG(LogInfo, "AF_NETBIOS (NetBIOS)\n");
+		KNET_LOG(LogInfo, "AF_NETBIOS (NetBIOS)\n");
 		break;
 #endif
 	default:
-		LOG(LogInfo, "Other %u\n", ptr->ai_family);
+		KNET_LOG(LogInfo, "Other %u\n", ptr->ai_family);
 		break;
 	}
-	LOG(LogInfo, "\tSocket type: ");
+	KNET_LOG(LogInfo, "\tSocket type: ");
 	switch(ptr->ai_socktype)
 	{
 	case 0:
-		LOG(LogInfo, "Unspecified\n");
+		KNET_LOG(LogInfo, "Unspecified\n");
 		break;
 	case SOCK_STREAM:
-		LOG(LogInfo, "SOCK_STREAM (stream)\n");
+		KNET_LOG(LogInfo, "SOCK_STREAM (stream)\n");
 		break;
 	case SOCK_DGRAM:
-		LOG(LogInfo, "SOCK_DGRAM (datagram) \n");
+		KNET_LOG(LogInfo, "SOCK_DGRAM (datagram) \n");
 		break;
 	case SOCK_RAW:
-		LOG(LogInfo, "SOCK_RAW (raw) \n");
+		KNET_LOG(LogInfo, "SOCK_RAW (raw) \n");
 		break;
 	case SOCK_RDM:
-		LOG(LogInfo, "SOCK_RDM (reliable message datagram)\n");
+		KNET_LOG(LogInfo, "SOCK_RDM (reliable message datagram)\n");
 		break;
 	case SOCK_SEQPACKET:
-		LOG(LogInfo, "SOCK_SEQPACKET (pseudo-stream packet)\n");
+		KNET_LOG(LogInfo, "SOCK_SEQPACKET (pseudo-stream packet)\n");
 		break;
 	default:
-		LOG(LogInfo, "Other %u\n", ptr->ai_socktype);
+		KNET_LOG(LogInfo, "Other %u\n", ptr->ai_socktype);
 		break;
 	}
-	LOG(LogInfo, "\tProtocol: ");
+	KNET_LOG(LogInfo, "\tProtocol: ");
 	switch(ptr->ai_protocol)
 	{
 	case 0:
-		LOG(LogInfo, "Unspecified\n");
+		KNET_LOG(LogInfo, "Unspecified\n");
 		break;
 	case IPPROTO_TCP:
-		LOG(LogInfo, "IPPROTO_TCP (TCP)\n");
+		KNET_LOG(LogInfo, "IPPROTO_TCP (TCP)\n");
 		break;
 	case IPPROTO_UDP:
-		LOG(LogInfo, "IPPROTO_UDP (UDP) \n");
+		KNET_LOG(LogInfo, "IPPROTO_UDP (UDP) \n");
 		break;
 	default:
-		LOG(LogInfo, "Other %u\n", ptr->ai_protocol);
+		KNET_LOG(LogInfo, "Other %u\n", ptr->ai_protocol);
 		break;
 	}
-	LOG(LogInfo, "\tLength of this sockaddr: %d\n", (int)ptr->ai_addrlen);
-	LOG(LogInfo, "\tCanonical name: %s\n", ptr->ai_canonname);
+	KNET_LOG(LogInfo, "\tLength of this sockaddr: %d\n", (int)ptr->ai_addrlen);
+	KNET_LOG(LogInfo, "\tCanonical name: %s\n", ptr->ai_canonname);
 
 	char address[256];
 	sprintf(address, "%d.%d.%d.%d",
 		(unsigned int)(unsigned char)ptr->ai_addr->sa_data[2], (unsigned int)(unsigned char)ptr->ai_addr->sa_data[3],
 		(unsigned int)(unsigned char)ptr->ai_addr->sa_data[4], (unsigned int)(unsigned char)ptr->ai_addr->sa_data[5]);
 
-	LOG(LogInfo, "Address of this sockaddr: %s.\n", address);
+	KNET_LOG(LogInfo, "Address of this sockaddr: %s.\n", address);
 }
 
 void Network::PrintHostNameInfo(const char *hostname, const char *port)
@@ -242,18 +245,18 @@ void Network::PrintHostNameInfo(const char *hostname, const char *port)
 	unsigned long dwRetval = (unsigned long)getaddrinfo(hostname, port, &hints, &result);
 	if (dwRetval != 0)
 	{
-		LOG(LogError, "getaddrinfo failed with error: %d\n", (int)dwRetval);
+		KNET_LOG(LogError, "getaddrinfo failed with error: %d", (int)dwRetval);
 		return;
 	}
 
-	LOG(LogInfo, "getaddrinfo returned success\n");
+	KNET_LOG(LogInfo, "getaddrinfo returned success");
 
 	int i = 1;
 
 	// Retrieve each address and print out the hex bytes
-	for (addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next)
+	for(addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next)
 	{
-		LOG(LogInfo, "getaddrinfo response %d\n", i++);
+		KNET_LOG(LogInfo, "getaddrinfo response %d", i++);
 		PrintAddrInfo(ptr);
 	}
 
@@ -269,7 +272,7 @@ void Network::Init()
 	int result = WSAStartup(MAKEWORD(2,2), &wsaData);
 	if (result != 0)
 	{
-		LOG(LogError, "Network::Init: WSAStartup failed: %s!", GetErrorString(result).c_str());
+		KNET_LOG(LogError, "Network::Init: WSAStartup failed: %s!", GetErrorString(result).c_str());
 		return;
 	}
 #endif
@@ -281,11 +284,11 @@ void Network::Init()
 	if (ret == 0)
 	{
 		localHostName = str;
-		LOG(LogInfo, "Network::Init successful. gethostname returned %s", str);
+		KNET_LOG(LogInfo, "Network::Init successful. gethostname returned %s", str);
 	}
 	else
 	{
-		LOG(LogError, "Network::Init: gethostname failed! Error: %s. Using 'localhost' as the local host name", GetLastErrorString().c_str());
+		KNET_LOG(LogError, "Network::Init: gethostname failed! Error: %s. Using 'localhost' as the local host name", GetLastErrorString().c_str());
 		localHostName = "localhost";
 	}
 }
@@ -303,7 +306,7 @@ NetworkWorkerThread *Network::GetOrCreateWorkerThread()
 	NetworkWorkerThread *workerThread = new NetworkWorkerThread();
 	workerThread->StartThread();
 	workerThreads.push_back(workerThread);
-	LOG(LogInfo, "Created a new NetworkWorkerThread. There are now %d worker threads.", (int)workerThreads.size());
+	KNET_LOG(LogInfo, "Created a new NetworkWorkerThread. There are now %d worker threads.", (int)workerThreads.size());
 	return workerThread;
 }
 
@@ -360,7 +363,7 @@ void Network::CloseWorkerThread(NetworkWorkerThread *workerThread)
 
 	// We (should) never close a worker thread until we have first removed all the connections and servers it handles.
 	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());
+		KNET_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)
 		if (workerThreads[i] == workerThread)
@@ -370,12 +373,12 @@ void Network::CloseWorkerThread(NetworkWorkerThread *workerThread)
 			workerThreads.pop_back();
 
 			workerThread->StopThread();
-			LOG(LogInfo, "Deleted a NetworkWorkerThread. There are now %d worker threads left.", (int)workerThreads.size());
+			KNET_LOG(LogInfo, "Deleted a NetworkWorkerThread. There are now %d worker threads left.", (int)workerThreads.size());
 			delete workerThread;
 			return;
 		}
 
-	LOG(LogError, "Network::CloseWorkerThread: Asked to close worker thread %p, but no such thread is tracked by this Network object! Ignoring the request.", workerThread);
+	KNET_LOG(LogError, "Network::CloseWorkerThread: Asked to close worker thread %p, but no such thread is tracked by this Network object! Ignoring the request.", workerThread);
 }
 
 NetworkServer *Network::StartServer(unsigned short port, SocketTransportLayer transport, INetworkServerListener *serverListener, bool allowAddressReuse)
@@ -383,7 +386,7 @@ NetworkServer *Network::StartServer(unsigned short port, SocketTransportLayer tr
 	Socket *listenSock = OpenListenSocket(port, transport, allowAddressReuse);
 	if (listenSock == 0)
 	{
-		LOG(LogError, "Failed to start server. Could not open listen port to %d using %s.", (int)port, 
+		KNET_LOG(LogError, "Failed to start server. Could not open listen port to %d using %s.", (int)port, 
 			transport == SocketOverTCP ? "TCP" : "UDP");
 		return 0;
 	}
@@ -396,7 +399,7 @@ NetworkServer *Network::StartServer(unsigned short port, SocketTransportLayer tr
 
 	AssignServerToWorkerThread(server);
 
-	LOG(LogInfo, "Server up (%s). Waiting for client to connect.", listenSock->ToString().c_str());
+	KNET_LOG(LogInfo, "Server up (%s). Waiting for client to connect.", listenSock->ToString().c_str());
 
 	return server;
 }
@@ -404,9 +407,9 @@ NetworkServer *Network::StartServer(unsigned short port, SocketTransportLayer tr
 NetworkServer *Network::StartServer(const std::vector<std::pair<unsigned short, SocketTransportLayer> > &listenPorts, 
 	INetworkServerListener *serverListener, bool allowAddressReuse)
 {
-	if (listenPorts.size() == 0)
+	if (listenPorts.empty())
 	{
-		LOG(LogError, "Failed to start server, since you did not provide a list of ports to listen to in Network::StartServer()!");
+		KNET_LOG(LogError, "Failed to start server, since you did not provide a list of ports to listen to in Network::StartServer()!");
 		return 0;
 	}
 
@@ -419,9 +422,9 @@ NetworkServer *Network::StartServer(const std::vector<std::pair<unsigned short,
 			listenSockets.push_back(listenSock);
 	}
 
-	if (listenSockets.size() == 0)
+	if (listenSockets.empty())
 	{
-		LOG(LogError, "Failed to start server. No ports to listen to!");
+		KNET_LOG(LogError, "Failed to start server. No ports to listen to!");
 		return 0;
 	}
 
@@ -430,14 +433,14 @@ NetworkServer *Network::StartServer(const std::vector<std::pair<unsigned short,
 
 	AssignServerToWorkerThread(server);
 
-	LOG(LogInfo, "Server up and listening on the following ports: ");
+	KNET_LOG(LogInfo, "Server up and listening on the following ports: ");
 	{
 		std::stringstream ss;
 		ss << "UDP ";
 		for(size_t i = 0; i < listenSockets.size(); ++i)
 			if (listenSockets[i]->TransportLayer() == SocketOverUDP)
 				ss << listenSockets[i]->LocalPort() << " ";
-		LOG(LogInfo, ss.str().c_str());
+		KNET_LOG(LogInfo, ss.str().c_str());
 	}
 	{
 		std::stringstream ss;
@@ -445,7 +448,7 @@ NetworkServer *Network::StartServer(const std::vector<std::pair<unsigned short,
 		for(size_t i = 0; i < listenSockets.size(); ++i)
 			if (listenSockets[i]->TransportLayer() == SocketOverTCP)
 				ss << listenSockets[i]->LocalPort() << " ";
-		LOG(LogInfo, ss.str().c_str());
+		KNET_LOG(LogInfo, ss.str().c_str());
 	}
 
 	return server;
@@ -460,14 +463,14 @@ void Network::StopServer()
 
 	///\todo This is a forceful stop. Perhaps have a benign teardown as well?
 	server = 0;
-	LOG(LogVerbose, "Network::StopServer: Deinitialized NetworkServer.");
+	KNET_LOG(LogVerbose, "Network::StopServer: Deinitialized NetworkServer.");
 }
 
 void Network::DeleteSocket(Socket *socket)
 {
 	if (!socket)
 	{
-		LOG(LogError, "Network::DeleteSocket() called with a null socket pointer!");
+		KNET_LOG(LogError, "Network::DeleteSocket() called with a null socket pointer!");
 		return;
 	}
 
@@ -478,15 +481,15 @@ void Network::DeleteSocket(Socket *socket)
 			// 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.
 			sockets.erase(iter);
-			LOG(LogInfo, "Network::DeleteSocket: Closed socket %p.", socket);
+			KNET_LOG(LogInfo, "Network::DeleteSocket: Closed socket %p.", socket);
 			return;
 		}
-	LOG(LogError, "Network::DeleteSocket: Tried to free a nonexisting socket %p!", socket);
+	KNET_LOG(LogError, "Network::DeleteSocket: Tried to free a nonexisting socket %p!", socket);
 }
 
 void Network::CloseConnection(MessageConnection *connection)
 {
-	LOG(LogVerbose, "Network::CloseConnection: Closing down connection %p.", connection);
+	KNET_LOG(LogVerbose, "Network::CloseConnection: Closing down connection %p.", connection);
 	if (!connection)
 		return;
 
@@ -500,11 +503,11 @@ void Network::CloseConnection(MessageConnection *connection)
 
 void Network::DeInit()
 {
-	LOG(LogVerbose, "Network::DeInit: Closing down.");
+	KNET_LOG(LogVerbose, "Network::DeInit: Closing down.");
 	PolledTimer timer;
 
 	// Kill all connections.
-	while(connections.size() > 0)
+	while(!connections.empty())
 	{
 		MessageConnection *connection = *connections.begin();
 		CloseConnection(connection); // CloseConnection erases connection from the connections list, so this loop terminates.
@@ -514,11 +517,11 @@ void Network::DeInit()
 	StopServer();
 
 	// Kill all worker threads.
-	while(workerThreads.size() > 0)
+	while(!workerThreads.empty())
 		CloseWorkerThread(workerThreads.front()); // Erases the item from workerThreads, so this loop terminates.
 
 	// Clean up any sockets that might be remaining.
-	while(sockets.size() > 0)
+	while(!sockets.empty())
 	{
 		sockets.front().Close();
 		sockets.pop_front();
@@ -529,7 +532,7 @@ void Network::DeInit()
 	WSACleanup();
 #endif
 
-	LOG(LogWaits, "Network::DeInit: Deinitialized kNet Network object, took %f msecs.", timer.MSecsElapsed());
+	KNET_LOG(LogWaits, "Network::DeInit: Deinitialized kNet Network object, took %f msecs.", timer.MSecsElapsed());
 }
 
 void Network::NewMessageConnectionCreated(MessageConnection *connection)
@@ -540,7 +543,6 @@ void Network::NewMessageConnectionCreated(MessageConnection *connection)
 Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer transport, bool allowAddressReuse)
 {
 	addrinfo *result = NULL;
-	addrinfo *ptr = NULL;
 	addrinfo hints;
 	memset(&hints, 0, sizeof(hints));
 	hints.ai_family = AF_INET;
@@ -554,16 +556,16 @@ Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer tran
 	int ret = getaddrinfo(NULL, strPort, &hints, &result);
 	if (ret != 0)
 	{
-		LOG(LogError, "getaddrinfo failed: %s", GetErrorString(ret).c_str());
+		KNET_LOG(LogError, "getaddrinfo failed: %s", GetErrorString(ret).c_str());
 		return 0;
 	}
 
 	SOCKET listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
-	LOG(LogInfo, "Network::OpenListenSocket: Created listenSocket 0x%8X.", (unsigned int)listenSocket);
+	KNET_LOG(LogInfo, "Network::OpenListenSocket: Created listenSocket 0x%8X.", (unsigned int)listenSocket);
 
 	if (listenSocket == INVALID_SOCKET)
 	{
-		LOG(LogError, "Error at socket(): %s", GetLastErrorString().c_str());
+		KNET_LOG(LogError, "Error at socket(): %s", GetLastErrorString().c_str());
 		freeaddrinfo(result);
 		return 0;
 	}
@@ -581,7 +583,7 @@ Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer tran
 		ret = setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
 #endif
 		if (ret != 0)
-			LOG(LogError, "setsockopt to SO_REUSEADDR failed: %s", GetLastErrorString().c_str());
+			KNET_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.
@@ -593,7 +595,7 @@ Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer tran
 	ret = bind(listenSocket, result->ai_addr, (int)result->ai_addrlen);
 	if (ret == KNET_SOCKET_ERROR)
 	{
-		LOG(LogError, "bind failed: %s when trying to bind to port %d with transport %s", 
+		KNET_LOG(LogError, "bind failed: %s when trying to bind to port %d with transport %s", 
 			GetLastErrorString().c_str(), (int)port, transport == SocketOverTCP ? "TCP" : "UDP");
 		closesocket(listenSocket);
 		freeaddrinfo(result);
@@ -609,7 +611,7 @@ Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer tran
 		ret = listen(listenSocket, SOMAXCONN);
 		if (ret == KNET_SOCKET_ERROR)
 		{
-			LOG(LogError, "Error at listen(): %s", GetLastErrorString().c_str());
+			KNET_LOG(LogError, "Error at listen(): %s", GetLastErrorString().c_str());
 			closesocket(listenSocket);
 			return 0;
 		}
@@ -632,7 +634,6 @@ Socket *Network::OpenListenSocket(unsigned short port, SocketTransportLayer tran
 Socket *Network::ConnectSocket(const char *address, unsigned short port, SocketTransportLayer transport)
 {
 	addrinfo *result = NULL;
-	addrinfo *ptr = NULL;
 	addrinfo hints;
 	memset(&hints, 0, sizeof(hints));
 	hints.ai_family = AF_INET;
@@ -644,7 +645,7 @@ Socket *Network::ConnectSocket(const char *address, unsigned short port, SocketT
 	int ret = getaddrinfo(address, strPort, &hints, &result);
 	if (ret != 0)
 	{
-		LOG(LogError, "Network::Connect: getaddrinfo failed: %s", GetErrorString(ret).c_str());
+		KNET_LOG(LogError, "Network::Connect: getaddrinfo failed: %s", GetErrorString(ret).c_str());
 		return 0;
 	}
 
@@ -653,11 +654,11 @@ Socket *Network::ConnectSocket(const char *address, unsigned short port, SocketT
 		NULL, 0, WSA_FLAG_OVERLAPPED);
 #else
 	SOCKET connectSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
-	LOG(LogInfo, "A call to socket() returned a new socket 0x%8X.", (unsigned int)connectSocket);
+	KNET_LOG(LogInfo, "A call to socket() returned a new socket 0x%8X.", (unsigned int)connectSocket);
 #endif
 	if (connectSocket == INVALID_SOCKET)
 	{
-		LOG(LogError, "Network::Connect: Error at socket(): %s", GetLastErrorString().c_str());
+		KNET_LOG(LogError, "Network::Connect: Error at socket(): %s", GetLastErrorString().c_str());
 		freeaddrinfo(result);
 		return 0;
 	}
@@ -679,7 +680,7 @@ Socket *Network::ConnectSocket(const char *address, unsigned short port, SocketT
 
 	if (connectSocket == INVALID_SOCKET)
 	{
-		LOG(LogError, "Unable to connect to server!");
+		KNET_LOG(LogError, "Unable to connect to server!");
 		return 0;
 	}
 
@@ -690,7 +691,7 @@ Socket *Network::ConnectSocket(const char *address, unsigned short port, SocketT
 	if (ret == 0)
 		 localEndPoint = EndPoint::FromSockAddrIn(sockname);
 	else
-		LOG(LogError, "Network::ConnectSocket: getsockname failed: %s!", Network::GetLastErrorString().c_str());
+		KNET_LOG(LogError, "Network::ConnectSocket: getsockname failed: %s!", Network::GetLastErrorString().c_str());
 
 	EndPoint remoteEndPoint;
 	sockaddr_in peername;
@@ -699,7 +700,7 @@ Socket *Network::ConnectSocket(const char *address, unsigned short port, SocketT
 	if (ret == 0)
 		remoteEndPoint = EndPoint::FromSockAddrIn(peername);
 	else
-		LOG(LogError, "Network::ConnectSocket: getpeername failed: %s!", Network::GetLastErrorString().c_str());
+		KNET_LOG(LogError, "Network::ConnectSocket: getpeername failed: %s!", Network::GetLastErrorString().c_str());
 
 	std::string remoteHostName = remoteEndPoint.IPToString();
 
@@ -724,10 +725,10 @@ Ptr(MessageConnection) Network::Connect(const char *address, unsigned short port
 	if (transport == SocketOverUDP)
 	{
 		SendUDPConnectDatagram(*socket, connectMessage);
-		LOG(LogInfo, "Network::Connect: Sent a UDP Connection Start datagram to to %s.", socket->ToString().c_str());
+		KNET_LOG(LogInfo, "Network::Connect: Sent a UDP Connection Start datagram to to %s.", socket->ToString().c_str());
 	}
 	else
-		LOG(LogInfo, "Network::Connect: Connected a TCP socket to %s.", socket->ToString().c_str());
+		KNET_LOG(LogInfo, "Network::Connect: Connected a TCP socket to %s.", socket->ToString().c_str());
 
 	Ptr(MessageConnection) connection;
 	if (transport == SocketOverTCP)
@@ -746,14 +747,14 @@ Socket *Network::CreateUDPSlaveSocket(Socket *serverListenSocket, const EndPoint
 {
 	if (!serverListenSocket)
 	{
-		LOG(LogError, "Network::CreateUDPSlaveSocket called with null serverListenSocket handle!");
+		KNET_LOG(LogError, "Network::CreateUDPSlaveSocket called with null serverListenSocket handle!");
 		return 0;
 	}
 
 	SOCKET udpSocket = serverListenSocket->GetSocketHandle();
 	if (udpSocket == INVALID_SOCKET)
 	{
-		LOG(LogError, "Network::CreateUDPSlaveSocket called with a UDP server socket with invalid internal socket handle!");
+		KNET_LOG(LogError, "Network::CreateUDPSlaveSocket called with a UDP server socket with invalid internal socket handle!");
 		return 0;
 	}
 
@@ -762,7 +763,7 @@ Socket *Network::CreateUDPSlaveSocket(Socket *serverListenSocket, const EndPoint
 	Socket *socket = &sockets.back();
 	socket->SetBlocking(false);
 
-	LOG(LogInfo, "Network::CreateUDPSlaveSocket: Connected an UDP socket to %s.", socket->ToString().c_str());
+	KNET_LOG(LogInfo, "Network::CreateUDPSlaveSocket: Connected an UDP socket to %s.", socket->ToString().c_str());
 	return socket;
 }
 
@@ -778,7 +779,7 @@ void Network::SendUDPConnectDatagram(Socket &socket, Datagram *connectMessage)
 	OverlappedTransferBuffer *sendData = socket.BeginSend(connectMessageSize);
 	if (!sendData)
 	{
-		LOG(LogError, "Network::SendUDPConnectDatagram: socket.BeginSend failed! Cannot send UDP connection datagram!");
+		KNET_LOG(LogError, "Network::SendUDPConnectDatagram: socket.BeginSend failed! Cannot send UDP connection datagram!");
 		return;
 	}
 	sendData->bytesContains = connectMessageSize;
@@ -786,13 +787,13 @@ void Network::SendUDPConnectDatagram(Socket &socket, Datagram *connectMessage)
 	{
 		///\todo Craft the proper connection attempt datagram.
 		memcpy(sendData->buffer.buf, connectMessage->data, sendData->buffer.len);
-		LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending UDP connect message of size %d.", (int)sendData->buffer.len);
+		KNET_LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending UDP connect message of size %d.", (int)sendData->buffer.len);
 	}
 	else
 	{
 		///\todo Craft the proper connection attempt datagram.
 		memset(sendData->buffer.buf, 0, sendData->buffer.len);
-		LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending null UDP connect message of size %d.", (int)sendData->buffer.len);
+		KNET_LOG(LogVerbose, "Network::SendUDPConnectDatagram: Sending null UDP connect message of size %d.", (int)sendData->buffer.len);
 	}
 	socket.EndSend(sendData);
 }

+ 1 - 1
Source/ThirdParty/kNet/src/NetworkLogging.cpp

@@ -33,7 +33,7 @@
 #include "kNet/Lockable.h"
 #include "kNet/Clock.h"
 
-#if defined(UNIX) || defined(ANDROID)
+#if defined(KNET_UNIX) || defined(ANDROID)
 #define _snprintf snprintf
 #endif
 

+ 9 - 5
Source/ThirdParty/kNet/src/NetworkMessage.cpp

@@ -24,16 +24,20 @@ namespace kNet
 {
 
 NetworkMessage::NetworkMessage()
-:messageNumber(0),
+:data(0),
+priority(0),
+id(0),
+contentID(0),
+reliable(true),
+inOrder(true),
+obsolete(false),
+receivedPacketID(0),
+messageNumber(0),
 reliableMessageNumber(0),
 sendCount(0),
 fragmentIndex(0),
 dataCapacity(0),
 dataSize(0),
-data(0),
-contentID(0),
-obsolete(false),
-priority(0),
 transfer(0)
 {
 }

+ 46 - 43
Source/ThirdParty/kNet/src/NetworkServer.cpp

@@ -15,12 +15,12 @@
 /** @file NetworkServer.cpp
 	@brief */
 
-// Modified by Lasse Oorni for Urho3D
-
 #ifdef KNET_USE_BOOST
 #include <boost/thread/thread.hpp>
 #endif
-
+#ifdef KNET_UNIX
+#include <unistd.h>
+#endif
 #include "kNet/DebugMemoryLeakCheck.h"
 
 #include "kNet/Network.h"
@@ -39,21 +39,24 @@ namespace kNet
 {
 
 NetworkServer::NetworkServer(Network *owner_, std::vector<Socket *> listenSockets_)
-:owner(owner_), listenSockets(listenSockets_), acceptNewConnections(true), networkServerListener(0),
-udpConnectionAttempts(64), workerThread(0)
+:listenSockets(listenSockets_), 
+owner(owner_), 
+workerThread(0), 
 #ifdef KNET_THREAD_CHECKING_ENABLED
-,workerThreadId(Thread::NullThreadId())
+workerThreadId(Thread::NullThreadId()),
 #endif
+acceptNewConnections(true), 
+networkServerListener(0),
+udpConnectionAttempts(64)
 {
 	assert(owner);
-	assert(listenSockets.size() > 0);
+	assert(!listenSockets.empty());
 }
 
 NetworkServer::~NetworkServer()
 {
-    // Urho3D: close listen sockets when shutting down
-    CloseListenSockets();
-	LOG(LogObjectAlloc, "Deleting NetworkServer %p.", this);
+	KNET_LOG(LogObjectAlloc, "Deleting NetworkServer %p.", this);
+	CloseSockets();
 }
 
 void NetworkServer::RegisterServerListener(INetworkServerListener *listener)
@@ -74,17 +77,15 @@ void NetworkServer::SetWorkerThread(NetworkWorkerThread *thread) // [main thread
 #endif
 }
 
-void NetworkServer::CloseListenSockets()
+void NetworkServer::CloseSockets()
 {
+	KNET_LOG(LogInfo, "NetworkServer::CloseSockets(): Network server is terminated. (%p)", this);
 	assert(owner);
 
+	acceptNewConnections = false;
+
 	for(size_t i = 0; i < listenSockets.size(); ++i)
-	{
-		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!
-        // Urho3D: free also UDP listen sockets
 		owner->DeleteSocket(listenSockets[i]); 
-	}
 
 	// Now forget all sockets - not getting them back in any way.
 	listenSockets.clear();
@@ -105,7 +106,7 @@ Socket *NetworkServer::AcceptConnections(Socket *listenSocket)
 		int error = Network::GetLastError();
 		if (error != KNET_EWOULDBLOCK)
 		{
-			LOG(LogError, "NetworkServer::AcceptConnections: accept failed: %s", Network::GetErrorString(error).c_str());
+			KNET_LOG(LogError, "NetworkServer::AcceptConnections: accept failed: %s", Network::GetErrorString(error).c_str());
 			closesocket(listenSock);
 			listenSock = INVALID_SOCKET;
 		}
@@ -115,12 +116,14 @@ Socket *NetworkServer::AcceptConnections(Socket *listenSocket)
 	EndPoint remoteEndPoint = EndPoint::FromSockAddrIn(remoteAddress);
 	std::string remoteHostName = remoteEndPoint.IPToString();
 
-	LOG(LogInfo, "Accepted incoming TCP connection from %s:%d.", remoteHostName.c_str(), (int)remoteEndPoint.port);
+	KNET_LOG(LogInfo, "Accepted incoming TCP connection from %s:%d.", remoteHostName.c_str(), (int)remoteEndPoint.port);
 
 	EndPoint localEndPoint;
 	sockaddr_in localSockAddr;
 	socklen_t namelen = sizeof(localSockAddr);
 	int sockRet = getsockname(acceptSocket, (sockaddr*)&localSockAddr, &namelen); // Note: This works only if family==INETv4
+	if (sockRet != 0)
+		KNET_LOG(LogError, "getsockname failed!");
 	localEndPoint = EndPoint::FromSockAddrIn(localSockAddr);
 	std::string localHostName = owner->LocalAddress();
 
@@ -144,7 +147,7 @@ void NetworkServer::CleanupDeadConnections()
 		++next;
 		if (!iter->second->Connected())
 		{
-			LOG(LogInfo, "Client %s disconnected.", iter->second->ToString().c_str());
+			KNET_LOG(LogInfo, "Client %s disconnected.", iter->second->ToString().c_str());
 			if (networkServerListener)
 				networkServerListener->ClientDisconnected(iter->second);
 			if (iter->second->GetSocket() && iter->second->GetSocket()->TransportLayer() == SocketOverTCP)
@@ -174,9 +177,9 @@ void NetworkServer::Process()
 			if (client)
 			{
 				if (!client->Connected())
-					LOG(LogError, "Warning: Accepted an already closed connection!");
+					KNET_LOG(LogError, "Warning: Accepted an already closed connection!");
 
-				LOG(LogInfo, "Client connected from %s.", client->ToString().c_str());
+				KNET_LOG(LogInfo, "Client connected from %s.", client->ToString().c_str());
 
 				// Build a MessageConnection on top of the raw socket.
 				assert(listen->TransportLayer() == SocketOverTCP);
@@ -191,7 +194,7 @@ void NetworkServer::Process()
 					PolledTimer timer;
 					Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
 					(*clientsLock)[clientConnection->RemoteEndPoint()] = clientConnection;
-					LOG(LogWaits, "NetworkServer::Process: Adding new accepted TCP connection to connection list took %f msecs.",
+					KNET_LOG(LogWaits, "NetworkServer::Process: Adding new accepted TCP connection to connection list took %f msecs.",
 						timer.MSecsElapsed());
 				}
 
@@ -229,11 +232,11 @@ void NetworkServer::ReadUDPSocketData(Socket *listenSocket) // [worker thread]
 	if (recvData->bytesContains == 0)
 	{
 		listenSocket->EndReceive(recvData);
-		LOG(LogError, "Received 0 bytes of data in NetworkServer::ReadUDPSocketData!");
+		KNET_LOG(LogError, "Received 0 bytes of data in NetworkServer::ReadUDPSocketData!");
 		return;
 	}
 	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().c_str(),
+	KNET_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;
@@ -243,7 +246,7 @@ void NetworkServer::ReadUDPSocketData(Socket *listenSocket) // [worker thread]
 		Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
 		if (timer.MSecsElapsed() > 50.f)
 		{
-			LOG(LogWaits, "NetworkServer::ReadUDPSocketData: Accessing the connection list in UDP server receive code took %f msecs.",
+			KNET_LOG(LogWaits, "NetworkServer::ReadUDPSocketData: Accessing the connection list in UDP server receive code took %f msecs.",
 			timer.MSecsElapsed());
 		}
 
@@ -259,7 +262,7 @@ void NetworkServer::ReadUDPSocketData(Socket *listenSocket) // [worker thread]
 		if (udpConnection)
 			udpConnection->QueueInboundDatagram(recvData->buffer.buf, recvData->bytesContains);
 		else
-			LOG(LogError, "Critical! UDP socket data received into a TCP socket!");
+			KNET_LOG(LogError, "Critical! UDP socket data received into a TCP socket!");
 	}
 	else
 	{
@@ -282,17 +285,17 @@ void NetworkServer::EnqueueNewUDPConnectionAttempt(Socket *listenSocket, const E
 
 	bool success = udpConnectionAttempts.Insert(desc);
 	if (!success)
-		LOG(LogError, "Too many connection attempts!");
+		KNET_LOG(LogError, "Too many connection attempts!");
 	else
-		LOG(LogInfo, "Queued new connection attempt from %s.", endPoint.ToString().c_str());
+		KNET_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)
 {
-	LOG(LogInfo, "New inbound connection attempt from %s with datagram of size %d.", endPoint.ToString().c_str(), (int)numBytes);
+	KNET_LOG(LogInfo, "New inbound connection attempt from %s with datagram of size %d.", endPoint.ToString().c_str(), (int)numBytes);
 	if (!acceptNewConnections)
 	{
-		LOG(LogError, "Ignored a new connection attempt since server is set not to accept new connections.");
+		KNET_LOG(LogError, "Ignored a new connection attempt since server is set not to accept new connections.");
 		return false;
 	}
 
@@ -302,7 +305,7 @@ bool NetworkServer::ProcessNewUDPConnectionAttempt(Socket *listenSocket, const E
 		bool connectionAccepted = networkServerListener->NewConnectionAttempt(endPoint, data, numBytes);
 		if (!connectionAccepted)
 		{
-			LOG(LogError, "Server listener did not accept the new connection.");
+			KNET_LOG(LogError, "Server listener did not accept the new connection.");
 			return false;
 		}
 	}
@@ -316,7 +319,7 @@ bool NetworkServer::ProcessNewUDPConnectionAttempt(Socket *listenSocket, const E
 	Socket *socket = owner->CreateUDPSlaveSocket(listenSocket, endPoint, remoteHostName.c_str());
 	if (!socket)
 	{
-		LOG(LogError, "Network::ConnectUDP failed! Cannot accept new UDP connection.");
+		KNET_LOG(LogError, "Network::ConnectUDP failed! Cannot accept new UDP connection.");
 		return false;
 	}
 
@@ -328,11 +331,11 @@ bool NetworkServer::ProcessNewUDPConnectionAttempt(Socket *listenSocket, const E
 		if (clientsLock->find(endPoint) == clientsLock->end())
 			(*clientsLock)[endPoint] = connection;
 		else
-			LOG(LogError, "NetworkServer::ProcessNewUDPConnectionAttempt: Trying to overwrite an old connection with a new one! Discarding connection attempt datagram!",
+			KNET_LOG(LogError, "NetworkServer::ProcessNewUDPConnectionAttempt: Trying to overwrite an old connection with a new one! Discarding connection attempt datagram!",
 				timer.MSecsElapsed());
 
 
-		LOG(LogWaits, "NetworkServer::ProcessNewUDPConnectionAttempt: Accessing the connection list took %f msecs.",
+		KNET_LOG(LogWaits, "NetworkServer::ProcessNewUDPConnectionAttempt: Accessing the connection list took %f msecs.",
 			timer.MSecsElapsed());
 	}
 
@@ -346,7 +349,7 @@ bool NetworkServer::ProcessNewUDPConnectionAttempt(Socket *listenSocket, const E
 
 	owner->NewMessageConnectionCreated(connection);
 
-	LOG(LogInfo, "Accepted new UDP connection.");
+	KNET_LOG(LogInfo, "Accepted new UDP connection.");
 	return true;
 }
 
@@ -356,7 +359,7 @@ void NetworkServer::BroadcastMessage(const NetworkMessage &msg, MessageConnectio
 	Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
 	if (timer.MSecsElapsed() >= 50.f)
 	{
-		LOG(LogWaits, "NetworkServer::BroadcastMessage: Accessing the connection list took %f msecs.",
+		KNET_LOG(LogWaits, "NetworkServer::BroadcastMessage: Accessing the connection list took %f msecs.",
 			timer.MSecsElapsed());
 	}
 
@@ -378,7 +381,7 @@ void NetworkServer::BroadcastMessage(unsigned long id, bool reliable, bool inOrd
 	Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
 	if (timer.MSecsElapsed() >= 50.f)
 	{
-		LOG(LogWaits, "NetworkServer::BroadcastMessage: Accessing the connection list took %f msecs.",
+		KNET_LOG(LogWaits, "NetworkServer::BroadcastMessage: Accessing the connection list took %f msecs.",
 			timer.MSecsElapsed());
 	}
 
@@ -417,7 +420,7 @@ void NetworkServer::DisconnectAllClients()
 
 	PolledTimer timer;
 	Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
-	LOG(LogWaits, "NetworkServer::DisconnectAllClients: Accessing the connection list took %f msecs.",
+	KNET_LOG(LogWaits, "NetworkServer::DisconnectAllClients: Accessing the connection list took %f msecs.",
 		timer.MSecsElapsed());
 
 	for(ConnectionMap::iterator iter = clientsLock->begin(); iter != clientsLock->end(); ++iter)
@@ -433,13 +436,13 @@ void NetworkServer::Close(int disconnectWaitMilliseconds)
 	if (GetConnections().size() > 0)
 	{
 		Clock::Sleep(disconnectWaitMilliseconds);
-		LOG(LogVerbose, "NetworkServer::Close: Waited a fixed period of %d msecs for all connections to disconnect.",
+		KNET_LOG(LogVerbose, "NetworkServer::Close: Waited a fixed period of %d msecs for all connections to disconnect.",
 			disconnectWaitMilliseconds);
 	}
 
 	PolledTimer timer;
 	Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
-	LOG(LogWaits, "NetworkServer::Close: Accessing the connection list took %f msecs.",
+	KNET_LOG(LogWaits, "NetworkServer::Close: Accessing the connection list took %f msecs.",
 		timer.MSecsElapsed());
 	for(ConnectionMap::iterator iter = clientsLock->begin(); iter != clientsLock->end(); ++iter)
 		iter->second->Close(0); // Do not wait for any client.
@@ -463,7 +466,7 @@ void NetworkServer::ConnectionClosed(MessageConnection *connection)
 {
 	PolledTimer timer;
 	Lockable<ConnectionMap>::LockType clientsLock = clients.Acquire();
-	LOG(LogWaits, "NetworkServer::ConnectionClosed: Accessing the connection list took %f msecs.",
+	KNET_LOG(LogWaits, "NetworkServer::ConnectionClosed: Accessing the connection list took %f msecs.",
 		timer.MSecsElapsed());
 	for(ConnectionMap::iterator iter = clientsLock->begin(); iter != clientsLock->end(); ++iter)
 		if (iter->second == connection)
@@ -482,7 +485,7 @@ void NetworkServer::ConnectionClosed(MessageConnection *connection)
 			return;
 		}
 
-	LOG(LogError, "Unknown MessageConnection passed to NetworkServer::Disconnect!");
+	KNET_LOG(LogError, "Unknown MessageConnection passed to NetworkServer::Disconnect!");
 }
 
 std::vector<Socket *> &NetworkServer::ListenSockets()
@@ -496,7 +499,7 @@ NetworkServer::ConnectionMap NetworkServer::GetConnections()
 	Lockable<ConnectionMap>::LockType lock = clients.Acquire();
 	if (timer.MSecsElapsed() > 50.f)
 	{
-		LOG(LogWaits, "NetworkServer::GetConnections: Accessing the connection list took %f msecs.",
+		KNET_LOG(LogWaits, "NetworkServer::GetConnections: Accessing the connection list took %f msecs.",
 			timer.MSecsElapsed());
 	}
 	return *lock;

+ 134 - 133
Source/ThirdParty/kNet/src/NetworkSimulator.cpp

@@ -1,133 +1,134 @@
-/* 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/MessageConnection.h"
-#include "kNet/NetworkSimulator.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());
-}
-
-/// Generates a float in half-open interval [0, 1[.
-static float rand01()
-{ 
-	assert(RAND_MAX >= 0x7FFF); ///\todo static assert.
-	return (float)(rand()&0x7FFF) / 0x8000;
-}
-
-/// Generates a float in closed interval [0, 1].
-static float rand01incl()
-{ 
-	assert(RAND_MAX >= 0x7FFF); ///\todo static assert.
-	return (float)(rand()&0x7FFF) / 0x7FFF;
-}
-
-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 >= (u32)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 + rand01incl() * uniformRandomPacketSendDelay);
-			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 + rand01incl() * uniformRandomPacketSendDelay);
-	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 + (int)(rand01() * (corruptMaxBits - corruptMinBits + 1));
-		for(int i = 0; i < numBitsToCorrupt; ++i)
-		{
-			int byteIndex = (int)(rand01() * numBytes);
-			int bitIndex = rand() % 8;
-			int bitMask = (1 << bitIndex);
-			((char*)buffer)[byteIndex] ^= bitMask;
-		}
-	}
-}
-
-} // ~kNet
+/* 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),
+packetDuplicationRate(0.f),
+corruptionType(CorruptDatagram),
+corruptMessageId(0),
+corruptToggleBitsRate(0),
+corruptMinBits(0),
+corruptMaxBits(0),
+owner(0)
+{
+}
+
+NetworkSimulator::~NetworkSimulator()
+{
+	if (queuedBuffers.size() > 0)
+		KNET_LOG(LogError, "NetworkSimulator: Leaked %d buffers with improper NetworkSimulator teardown!", (int)queuedBuffers.size());
+}
+
+/// Generates a float in half-open interval [0, 1[.
+static float rand01()
+{ 
+	assert(RAND_MAX >= 0x7FFF); ///\todo static assert.
+	return (float)(rand()&0x7FFF) / 0x8000;
+}
+
+/// Generates a float in closed interval [0, 1].
+static float rand01incl()
+{ 
+	assert(RAND_MAX >= 0x7FFF); ///\todo static assert.
+	return (float)(rand()&0x7FFF) / 0x7FFF;
+}
+
+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 >= (u32)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 + rand01incl() * uniformRandomPacketSendDelay);
+			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 + rand01incl() * uniformRandomPacketSendDelay);
+	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 + (int)(rand01() * (corruptMaxBits - corruptMinBits + 1));
+		for(int i = 0; i < numBitsToCorrupt; ++i)
+		{
+			int byteIndex = (int)(rand01() * numBytes);
+			int bitIndex = rand() % 8;
+			int bitMask = (1 << bitIndex);
+			((char*)buffer)[byteIndex] ^= bitMask;
+		}
+	}
+}
+
+} // ~kNet

+ 20 - 24
Source/ThirdParty/kNet/src/NetworkWorkerThread.cpp

@@ -15,8 +15,6 @@
 /** @file NetworkWorkerThread.cpp
 	@brief */
 
-// Modified by Lasse Oorni for Urho3D
-
 #include <utility>
 
 #ifdef KNET_USE_BOOST
@@ -48,7 +46,7 @@ void NetworkWorkerThread::AddConnection(MessageConnection *connection)
 	workThread.Hold();
 	Lockable<std::vector<MessageConnection *> >::LockType lock = connections.Acquire();
 	lock->push_back(connection);
-	LOG(LogVerbose, "Added connection %p to NetworkWorkerThread.", connection);
+	KNET_LOG(LogVerbose, "Added connection %p to NetworkWorkerThread.", connection);
 	workThread.Resume();
 }
 
@@ -62,11 +60,11 @@ void NetworkWorkerThread::RemoveConnection(MessageConnection *connection)
 		if ((*lock)[i] == connection)
 		{
 			lock->erase(lock->begin() + i);
-			LOG(LogVerbose, "NetworkWorkerThread::RemoveConnection: Connection %p removed.", connection);
+			KNET_LOG(LogVerbose, "NetworkWorkerThread::RemoveConnection: Connection %p removed.", connection);
 			workThread.Resume();
 			return;
 		}
-	LOG(LogError, "NetworkWorkerThread::RemoveConnection called for a nonexisting connection %p!", connection);
+	KNET_LOG(LogError, "NetworkWorkerThread::RemoveConnection called for a nonexisting connection %p!", connection);
 	workThread.Resume();
 }
 
@@ -75,7 +73,7 @@ void NetworkWorkerThread::AddServer(NetworkServer *server)
 	workThread.Hold();
 	Lockable<std::vector<NetworkServer *> >::LockType lock = servers.Acquire();
 	lock->push_back(server);
-	LOG(LogVerbose, "Added server %p to NetworkWorkerThread.", server);
+	KNET_LOG(LogVerbose, "Added server %p to NetworkWorkerThread.", server);
 	workThread.Resume();
 }
 
@@ -85,19 +83,18 @@ void NetworkWorkerThread::RemoveServer(NetworkServer *server)
 
 	PolledTimer timer;
 	Lockable<std::vector<NetworkServer *> >::LockType lock = servers.Acquire();
-	float lockWait = timer.MSecsElapsed();
-	LOG(LogWaits, "NetworkWorkerThread::RemoveServer: Waited %f msecs to lock servers list.",
-		lockWait);
+	KNET_LOG(LogWaits, "NetworkWorkerThread::RemoveServer: Waited %f msecs to lock servers list.",
+		timer.MSecsElapsed());
 
 	for(size_t i = 0; i < lock->size(); ++i)
 		if ((*lock)[i] == server)
 		{
 			lock->erase(lock->begin() + i);
-			LOG(LogVerbose, "NetworkWorkerThread::RemoveServer: Server %p removed.", server);
+			KNET_LOG(LogVerbose, "NetworkWorkerThread::RemoveServer: Server %p removed.", server);
 			workThread.Resume();
 			return;
 		}
-	LOG(LogError, "NetworkWorkerThread::RemoveServer called for a nonexisting server %p!", server);
+	KNET_LOG(LogError, "NetworkWorkerThread::RemoveServer called for a nonexisting server %p!", server);
 	workThread.Resume();
 }
 
@@ -114,7 +111,7 @@ void NetworkWorkerThread::StopThread()
 		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);
+			KNET_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);
 		}
 	}
@@ -122,7 +119,7 @@ void NetworkWorkerThread::StopThread()
 		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);
+			KNET_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);
 		}
 	}
@@ -149,7 +146,7 @@ void NetworkWorkerThread::MainLoop()
 	assert(!falseEvent.IsNull());
 	assert(falseEvent.Test() == false);
 
-	LOG(LogInfo, "NetworkWorkerThread starting main loop.");
+	KNET_LOG(LogInfo, "NetworkWorkerThread starting main loop.");
 
 	std::vector<MessageConnection*> connectionList;
 	std::vector<NetworkServer*> serverList;
@@ -173,8 +170,7 @@ void NetworkWorkerThread::MainLoop()
 		// which does not support aborting from the wait if the thread is signalled to interrupt and quit/join. To fix
 		// this, should add a custom "interrupt Event" into the WaitArray to wake the thread up when it is supposed to be killed.
 		// For now, just sleep only small periods of time at once to make this issue not a problem at application exit time.
-        // Urho3D: changed smaller for potentially less network latency
-		const int maxWaitTime = 10; // msecs. ///\todo Make this a lot larger, like, 2000msecs, once the thread interrupts are handled in Sleep and EventArray::Wait.
+		const int maxWaitTime = 50; // msecs. ///\todo Make this a lot larger, like, 2000msecs, once the thread interrupts are handled in Sleep and EventArray::Wait.
 		int waitTime = maxWaitTime;
 
 		waitEvents.Clear();
@@ -192,7 +188,7 @@ void NetworkWorkerThread::MainLoop()
 				connection.UpdateConnection();
 			} catch(const NetException &e)
 			{
-				LOG(LogError, (std::string("kNet::NetException thrown when processing UpdateConnection() for client connection: ") + e.what()).c_str());
+				KNET_LOG(LogError, (std::string("kNet::NetException thrown when processing UpdateConnection() for client connection: ") + e.what()).c_str());
 				if (connection.GetSocket())
 					connection.GetSocket()->Close();
 			}
@@ -301,7 +297,7 @@ void NetworkWorkerThread::MainLoop()
 						connection->SendOutPackets();
 				} catch(const NetException &e)
 				{
-					LOG(LogError, (std::string("kNet::NetException thrown when processing client connection: ") + e.what()).c_str());
+					KNET_LOG(LogError, (std::string("kNet::NetException thrown when processing client connection: ") + e.what()).c_str());
 					if (connection->GetSocket())
 						connection->GetSocket()->Close();
 				}
@@ -309,7 +305,7 @@ void NetworkWorkerThread::MainLoop()
 			else // A UDP server received a message.
 			{
 				int socketIndex = index - connectionList.size() * 2;
-				if (serverList.size() > 0)
+				if (!serverList.empty())
 				{
 					NetworkServer &server = *serverList[0]; ///\bug In case of multiple servers, this is not correct!
 					std::vector<Socket *> &listenSockets = server.ListenSockets();
@@ -320,19 +316,19 @@ void NetworkWorkerThread::MainLoop()
 							server.ReadUDPSocketData(listenSockets[socketIndex]);
 						} catch(const NetException &e)
 						{
-							LOG(LogError, (std::string("kNet::NetException thrown when reading server socket: ") + e.what()).c_str());
+							KNET_LOG(LogError, (std::string("kNet::NetException thrown when reading server socket: ") + e.what()).c_str());
 							///\todo Could Close(0) the connection here.
 						}
 					}
 					else
 					{
-						LOG(LogError, "NetworkWorkerThread::MainLoop: Warning: Cannot find server socket to read from: EventArray::Wait returned index %d (socketIndex %d), but "
+						KNET_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());
 					}
 				}
 				else
 				{
-					LOG(LogError, "NetworkWorkerThread::MainLoop: Warning: EventArray::Wait returned index %d (socketIndex %d), but "
+					KNET_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());
 				}
 			}
@@ -348,12 +344,12 @@ void NetworkWorkerThread::MainLoop()
 				writeWaitConnections[i]->SendOutPackets();
 			} catch(const NetException &e)
 			{
-				LOG(LogError, (std::string("kNet::NetException thrown when sending out a network message: ") + e.what()).c_str());
+				KNET_LOG(LogError, (std::string("kNet::NetException thrown when sending out a network message: ") + e.what()).c_str());
 			}
 		}
 	}
 	falseEvent.Close();
-	LOG(LogInfo, "NetworkWorkerThread quit.");
+	KNET_LOG(LogInfo, "NetworkWorkerThread quit.");
 }
 
 } // ~kNet

+ 1 - 3
Source/ThirdParty/kNet/src/SerializationStructCompiler.cpp

@@ -80,8 +80,6 @@ void SerializationStructCompiler::WriteStructMembers(const SerializedElementDesc
 {
 	assert(&elem && elem.type == SerialStruct);
 
-	int childStructIndex = 1;
-
 	for(size_t i = 0; i < elem.elements.size(); ++i)
 	{
 		SerializedElementDesc &e = *elem.elements[i];
@@ -164,7 +162,7 @@ void SerializationStructCompiler::WriteStructSizeMemberFunction(const Serialized
 		}
 	}
 
-	if (elem.elements.size() == 0)
+	if (elem.elements.empty())
 		out << "0";
 
 	out << ";" << endl

+ 3 - 3
Source/ThirdParty/kNet/src/SerializedDataIterator.cpp

@@ -26,7 +26,7 @@ namespace kNet
 
 BasicSerializedDataType SerializedDataIterator::NextElementType() const
 {
-	if (currentElementStack.size() == 0)
+	if (currentElementStack.empty())
 		return SerialInvalid;
 
 	assert(currentElementStack.back().elem);
@@ -41,12 +41,12 @@ BasicSerializedDataType SerializedDataIterator::NextElementType() const
 
 const SerializedElementDesc *SerializedDataIterator::NextElementDesc() const
 {
-	return currentElementStack.size() > 0 ? currentElementStack.back().elem : 0;
+	return currentElementStack.empty() ? 0 : currentElementStack.back().elem;
 }
 
 void SerializedDataIterator::ProceedToNextVariable()
 {
-	if (currentElementStack.size() == 0)
+	if (currentElementStack.empty())
 		return;
 
 	ElemInfo &nextVar = currentElementStack.back();

+ 69 - 67
Source/ThirdParty/kNet/src/Socket.cpp

@@ -15,8 +15,6 @@
 /** @file Socket.cpp
 	@brief */
 
-// Modified by Lasse Oorni for Urho3D
-
 #include <string>
 #include <cassert>
 #include <utility>
@@ -36,11 +34,12 @@
 
 using namespace std;
 
-#if defined(UNIX) || defined(ANDROID)
+#if defined(KNET_UNIX) || defined(ANDROID)
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/tcp.h>
+#include <unistd.h>
 #endif
 
 #ifdef WIN32
@@ -96,10 +95,11 @@ std::string SocketTypeToString(SocketType type)
 
 Socket::Socket()
 :connectSocket(INVALID_SOCKET),
-writeOpen(false),
-readOpen(false),
 transport(InvalidTransportLayer),
-type(InvalidSocketType)
+type(InvalidSocketType),
+maxSendSize(0),
+writeOpen(false),
+readOpen(false)
 #ifdef WIN32
 ,queuedReceiveBuffers(numConcurrentReceiveBuffers)
 ,queuedSendBuffers(numConcurrentSendBuffers)
@@ -188,7 +188,7 @@ OverlappedTransferBuffer *AllocateOverlappedTransferBuffer(int bytes)
 	buffer->overlapped.hEvent = WSACreateEvent();
 	if (buffer->overlapped.hEvent == WSA_INVALID_EVENT)
 	{
-		LOG(LogError, "Socket.cpp:AllocateOverlappedTransferBuffer: WSACreateEvent failed!");
+		KNET_LOG(LogError, "Socket.cpp:AllocateOverlappedTransferBuffer: WSACreateEvent failed!");
 		delete[] buffer->buffer.buf;
 		delete buffer;
 		return 0;
@@ -206,7 +206,7 @@ void DeleteOverlappedTransferBuffer(OverlappedTransferBuffer *buffer)
 #ifdef WIN32
 	BOOL success = WSACloseEvent(buffer->overlapped.hEvent);
 	if (success == FALSE)
-		LOG(LogError, "Socket.cpp:DeleteOverlappedTransferBuffer: WSACloseEvent failed!");
+		KNET_LOG(LogError, "Socket.cpp:DeleteOverlappedTransferBuffer: WSACloseEvent failed!");
 	buffer->overlapped.hEvent = WSA_INVALID_EVENT;
 #endif
 	delete buffer;
@@ -216,14 +216,14 @@ void Socket::SetSendBufferSize(int bytes)
 {
 	socklen_t len = sizeof(bytes);
 	if (setsockopt(connectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bytes, len))
-		LOG(LogError, "Socket::SetSendBufferSize: setsockopt failed with error %s!", Network::GetLastErrorString().c_str());
+		KNET_LOG(LogError, "Socket::SetSendBufferSize: setsockopt failed with error %s!", Network::GetLastErrorString().c_str());
 }
 
 void Socket::SetReceiveBufferSize(int bytes)
 {
 	socklen_t len = sizeof(bytes);
 	if (setsockopt(connectSocket, SOL_SOCKET, SO_RCVBUF, (char*)&bytes, len))
-		LOG(LogError, "Socket::SetReceiveBufferSize: setsockopt failed with error %s!", Network::GetLastErrorString().c_str());
+		KNET_LOG(LogError, "Socket::SetReceiveBufferSize: setsockopt failed with error %s!", Network::GetLastErrorString().c_str());
 }
 
 int Socket::SendBufferSize() const
@@ -232,7 +232,7 @@ int Socket::SendBufferSize() const
 	socklen_t len = sizeof(bytes);
 	if (getsockopt(connectSocket, SOL_SOCKET, SO_SNDBUF, (char*)&bytes, &len))
 	{
-		LOG(LogError, "Socket::SendBufferSize: getsockopt failed with error %s!", Network::GetLastErrorString().c_str());
+		KNET_LOG(LogError, "Socket::SendBufferSize: getsockopt failed with error %s!", Network::GetLastErrorString().c_str());
 		return 0;
 	}
 	return bytes;
@@ -244,7 +244,7 @@ int Socket::ReceiveBufferSize() const
 	socklen_t len = sizeof(bytes);
 	if (getsockopt(connectSocket, SOL_SOCKET, SO_RCVBUF, (char*)&bytes, &len))
 	{
-		LOG(LogError, "Socket::ReceiveBufferSize: getsockopt failed with error %s!", Network::GetLastErrorString().c_str());
+		KNET_LOG(LogError, "Socket::ReceiveBufferSize: getsockopt failed with error %s!", Network::GetLastErrorString().c_str());
 		return 0;
 	}
 
@@ -266,13 +266,13 @@ void Socket::EnqueueNewReceiveBuffer(OverlappedTransferBuffer *buffer)
 		buffer = AllocateOverlappedTransferBuffer(receiveBufferSize);
 		if (!buffer)
 		{
-			LOG(LogError, "Socket::EnqueueNewReceiveBuffer: Call to AllocateOverlappedTransferBuffer failed!");
+			KNET_LOG(LogError, "Socket::EnqueueNewReceiveBuffer: Call to AllocateOverlappedTransferBuffer failed!");
 			return;
 		}
 	}
 
 	if (WSAResetEvent(buffer->overlapped.hEvent) != TRUE)
-		LOG(LogError, "Socket::EnqueueNewReceiveBuffer: WSAResetEvent failed!");
+		KNET_LOG(LogError, "Socket::EnqueueNewReceiveBuffer: WSAResetEvent failed!");
 
 	unsigned long flags = 0;
 	int ret;
@@ -292,12 +292,11 @@ void Socket::EnqueueNewReceiveBuffer(OverlappedTransferBuffer *buffer)
 	{
 		if (ret == 0 && buffer->bytesContains == 0)
 		{
-            // Urho3D: only close TCP sockets upon receiving 0 bytes
-            if (transport == SocketOverTCP && readOpen)
-            {
-			LOG(LogInfo, "Socket::EnqueueNewReceiveBuffer: Received 0 bytes from the network. Read connection closed in socket %s.", ToString().c_str());
+			if (IsUDPServerSocket())
+				KNET_LOG(LogError, "Unexpected: Received a message of 0 bytes on a UDP server socket!");
+
+			KNET_LOG(LogInfo, "Socket::EnqueueNewReceiveBuffer: Received 0 bytes from the network. Read connection closed in socket %s.", ToString().c_str());
 			readOpen = false;
-            }
 			DeleteOverlappedTransferBuffer(buffer);
 			return;
 		}
@@ -306,16 +305,16 @@ void Socket::EnqueueNewReceiveBuffer(OverlappedTransferBuffer *buffer)
 		bool success = queuedReceiveBuffers.Insert(buffer);
 		if (!success)
 		{
-			LOG(LogError, "Socket::EnqueueNewReceiveBuffer: queuedReceiveBuffers.Insert(buffer); failed!");
+			KNET_LOG(LogError, "Socket::EnqueueNewReceiveBuffer: queuedReceiveBuffers.Insert(buffer); failed!");
 			DeleteOverlappedTransferBuffer(buffer);
 		}
 	}
 	else if (error == WSAEDISCON)
 	{
 		if (IsUDPServerSocket())
-			LOG(LogError, "Unexpected: Received WSAEDISCON on a UDP server socket!");
+			KNET_LOG(LogError, "Unexpected: Received WSAEDISCON on a UDP server socket!");
 
-		LOG(LogError, "Socket::EnqueueNewReceivebuffer: WSAEDISCON. Connection closed in socket %s.", ToString().c_str());
+		KNET_LOG(LogError, "Socket::EnqueueNewReceivebuffer: WSAEDISCON. Connection closed in socket %s.", ToString().c_str());
 		readOpen = false;
 		///\todo Should do writeOpen = false; here as well?
 		DeleteOverlappedTransferBuffer(buffer);
@@ -325,7 +324,7 @@ void Socket::EnqueueNewReceiveBuffer(OverlappedTransferBuffer *buffer)
 	{
 		if (error != WSAEWOULDBLOCK && error != 0)
 		{
-			LOG(LogError, "Socket::EnqueueNewReceiveBuffer: %s for overlapped socket %s failed! Error: %s.", IsUDPServerSocket() ? "WSARecvFrom" : "WSARecv", ToString().c_str(), Network::GetErrorString(error).c_str());
+			KNET_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
 			// the whole server for all clients. This check is mainly here to ignore the 10054 error (WSAECONNRESET) which
@@ -333,7 +332,7 @@ void Socket::EnqueueNewReceiveBuffer(OverlappedTransferBuffer *buffer)
 			// client-specific errors, we don't explicitly check for the 10054 case only.
 			if (!IsUDPServerSocket())
 			{
-				LOG(LogError, "Socket::EnqueueNewReceiveBuffer: Closing down socket.",  Network::GetErrorString(error).c_str());
+				KNET_LOG(LogError, "Socket::EnqueueNewReceiveBuffer: Closing down socket.",  Network::GetErrorString(error).c_str());
 				readOpen = false;
 				writeOpen = false;
 				Close();
@@ -379,12 +378,12 @@ size_t Socket::Receive(char *dst, size_t maxBytes, EndPoint *endPoint)
 		{
 			int error = Network::GetLastError();
 			if (error != KNET_EWOULDBLOCK && error != 0)
-				LOG(LogError, "Socket::Receive: recvfrom failed: %s in socket %s", Network::GetErrorString(error).c_str(), ToString().c_str());
+				KNET_LOG(LogError, "Socket::Receive: recvfrom failed: %s in socket %s", Network::GetErrorString(error).c_str(), ToString().c_str());
 
 			return 0;
 		}
 		if (numBytesRead > 0)
-			LOG(LogData, "recvfrom (%d) in socket %s", numBytesRead, ToString().c_str());
+			KNET_LOG(LogData, "recvfrom (%d) in socket %s", numBytesRead, ToString().c_str());
 
 		if (endPoint)
 			*endPoint = EndPoint::FromSockAddrIn(from);
@@ -398,17 +397,13 @@ size_t Socket::Receive(char *dst, size_t maxBytes, EndPoint *endPoint)
 
 	if (ret > 0)
 	{
-		LOG(LogData, "Received %d bytes of data from socket 0x%X.", ret, (unsigned int)connectSocket);
+		KNET_LOG(LogData, "Received %d bytes of data from socket 0x%X.", ret, (unsigned int)connectSocket);
 		return (size_t)ret;
 	}
 	else if (ret == 0)
 	{
-        // Urho3D: only close TCP sockets upon receiving 0 bytes
-        if (transport == SocketOverTCP && readOpen)
-        {
-		LOG(LogInfo, "Socket::Receive: Received 0 bytes from network. Read-connection closed to socket %s.", ToString().c_str());
+		KNET_LOG(LogInfo, "Socket::Receive: Received 0 bytes from network. Read-connection closed to socket %s.", ToString().c_str());
 		readOpen = false;
-        }
 		return 0;
 	}
 	else
@@ -416,7 +411,7 @@ size_t Socket::Receive(char *dst, size_t maxBytes, EndPoint *endPoint)
 		int error = Network::GetLastError();
 		if (error != KNET_EWOULDBLOCK && error != 0)
 		{
-			LOG(LogError, "Socket::Receive: recv failed in socket %s. Error %s", ToString().c_str(), Network::GetErrorString(error).c_str());
+			KNET_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
 			// the whole server for all clients. This check is mainly here to ignore the 10054 error (WSAECONNRESET) which
@@ -533,12 +528,16 @@ OverlappedTransferBuffer *Socket::BeginReceive()
 		if (receivedData->bytesContains == 0)
 		{
 			DeleteOverlappedTransferBuffer(receivedData);
-            // Urho3D: only close TCP sockets upon receiving 0 bytes
-            if (transport == SocketOverTCP && readOpen)
+			if (!IsUDPServerSocket())
+			{
+				if (readOpen)
 				{
-					LOG(LogInfo, "Socket::BeginReceive: Received 0 bytes from the network. Read connection closed in socket %s.", ToString().c_str());
+					KNET_LOG(LogInfo, "Socket::BeginReceive: Received 0 bytes from the network. Read connection closed in socket %s.", ToString().c_str());
 					readOpen = false;
 				}
+			}
+			else
+				KNET_LOG(LogVerbose, "Socket::BeginReceive: Server received a UDP datagram of 0 bytes from a client! This is a malformed kNet UDP datagram!");
 			return 0;
 		}
 
@@ -549,9 +548,9 @@ OverlappedTransferBuffer *Socket::BeginReceive()
 		queuedReceiveBuffers.PopFront();
 		DeleteOverlappedTransferBuffer(receivedData);
 		if (readOpen || writeOpen)
-			LOG(LogError, "Socket::BeginReceive: WSAEDISCON. Bidirectionally closing connection in socket %s.", ToString().c_str());
+			KNET_LOG(LogError, "Socket::BeginReceive: WSAEDISCON. Bidirectionally closing connection in socket %s.", ToString().c_str());
 		if (IsUDPServerSocket())
-			LOG(LogError, "Socket::BeginReceive: Unexpected: Received WSAEDISCON on UDP server socket!");
+			KNET_LOG(LogError, "Socket::BeginReceive: Unexpected: Received WSAEDISCON on UDP server socket!");
 		Close();
 		return 0;
 	}
@@ -560,13 +559,13 @@ OverlappedTransferBuffer *Socket::BeginReceive()
 		queuedReceiveBuffers.PopFront();
 		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.
-				LOG(LogError, "Socket::BeginReceive: WSAGetOverlappedResult failed with code %d when reading from an overlapped socket! Reason: %s.", error, Network::GetErrorString(error).c_str());
+				KNET_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);
 		// 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!)
 		if (!IsUDPServerSocket() && (readOpen || writeOpen))
 		{
-			LOG(LogError, "Socket::BeginReceive: Closing socket due to read error!");
+			KNET_LOG(LogError, "Socket::BeginReceive: Closing socket due to read error!");
 			Close();
 		}
 	}
@@ -612,15 +611,15 @@ void Socket::Disconnect()
 	if (connectSocket == INVALID_SOCKET)
 		return;
 
-	LOG(LogVerbose, "Socket::Disconnect(), this: %p.", this);
+	KNET_LOG(LogVerbose, "Socket::Disconnect(), this: %p.", this);
 
 	if (transport == SocketOverTCP)
 	{
 		int result = shutdown(connectSocket, SD_SEND);
 		if (result == KNET_SOCKET_ERROR)
-			LOG(LogError, "Socket::Disconnect(): TCP socket shutdown(SD_SEND) failed: %s in socket %s.", Network::GetLastErrorString().c_str(), ToString().c_str());
+			KNET_LOG(LogError, "Socket::Disconnect(): TCP socket shutdown(SD_SEND) failed: %s in socket %s.", Network::GetLastErrorString().c_str(), ToString().c_str());
 		else
-			LOG(LogInfo, "Socket::Disconnect(): TCP socket shutdown(SD_SEND) succeeded on socket %s.", ToString().c_str());
+			KNET_LOG(LogInfo, "Socket::Disconnect(): TCP socket shutdown(SD_SEND) succeeded on socket %s.", ToString().c_str());
 	}
 
 	writeOpen = false;
@@ -634,7 +633,7 @@ void Socket::Close()
 		return;
 	}
 
-	LOG(LogInfo, "Socket::Close(): Closing socket %s.", ToString().c_str());
+	KNET_LOG(LogInfo, "Socket::Close(): Closing socket %s.", ToString().c_str());
 
 	if (!IsUDPSlaveSocket())
 	{
@@ -644,13 +643,13 @@ void Socket::Close()
 
 		int result = shutdown(connectSocket, SD_BOTH);
 		if (result == KNET_SOCKET_ERROR)
-			LOG(LogError, "Socket::Close(): Socket shutdown(SD_BOTH) failed: %s in socket %s.", Network::GetLastErrorString().c_str(), ToString().c_str());
+			KNET_LOG(LogError, "Socket::Close(): Socket shutdown(SD_BOTH) failed: %s in socket %s.", Network::GetLastErrorString().c_str(), ToString().c_str());
 		else
-			LOG(LogInfo, "Socket::Close(): Socket shutdown(SD_BOTH) succeeded on socket %s.", ToString().c_str());
+			KNET_LOG(LogInfo, "Socket::Close(): Socket shutdown(SD_BOTH) succeeded on socket %s.", ToString().c_str());
 
 		result = closesocket(connectSocket);
 		if (result == KNET_SOCKET_ERROR)
-			LOG(LogError, "Socket::Close(): closesocket() failed: %s in socket %s.", Network::GetLastErrorString().c_str(), ToString().c_str());
+			KNET_LOG(LogError, "Socket::Close(): closesocket() failed: %s in socket %s.", Network::GetLastErrorString().c_str(), ToString().c_str());
 	}
 
 	connectSocket = INVALID_SOCKET;
@@ -671,7 +670,7 @@ void Socket::Close()
 #ifdef WIN32
 void Socket::FreeOverlappedTransferBuffers()
 {
-	LOG(LogVerbose, "Socket::FreeOverlappedTransferBuffers(), this: %p.", this);
+	KNET_LOG(LogVerbose, "Socket::FreeOverlappedTransferBuffers(), this: %p.", this);
 /// \todo Use CancelIo to tear-down commited OverlappedTransferBuffers before freeing data. http://msdn.microsoft.com/en-us/library/aa363792(VS.85).aspx
 	while(queuedReceiveBuffers.Size() > 0)
 		DeleteOverlappedTransferBuffer(queuedReceiveBuffers.TakeFront());
@@ -686,13 +685,16 @@ void Socket::SetBlocking(bool isBlocking)
 	if (connectSocket == INVALID_SOCKET)
 		return;
 
-	u_long nonBlocking = (isBlocking == false) ? 1 : 0;
 #ifdef WIN32
+	u_long nonBlocking = (isBlocking == false) ? 1 : 0;
 	if (ioctlsocket(connectSocket, FIONBIO, &nonBlocking))
-		LOG(LogError, "Socket::SetBlocking: ioctlsocket failed with error %s!", Network::GetLastErrorString().c_str());
+		KNET_LOG(LogError, "Socket::SetBlocking: ioctlsocket failed with error %s!", Network::GetLastErrorString().c_str());
 #else
 	int flags = fcntl(connectSocket, F_GETFL, 0);
-	fcntl(connectSocket, F_SETFL, flags | O_NONBLOCK);
+	if (!isBlocking)
+		fcntl(connectSocket, F_SETFL, flags | O_NONBLOCK);
+	else
+		fcntl(connectSocket, F_SETFL, flags & ~O_NONBLOCK);
 #endif
 }
 
@@ -701,20 +703,20 @@ bool Socket::Send(const char *data, size_t numBytes)
 {
 	if (connectSocket == INVALID_SOCKET)
 	{
-		LOG(LogError, "Trying to send a datagram to INVALID_SOCKET!");
+		KNET_LOG(LogError, "Trying to send a datagram to INVALID_SOCKET!");
 		return false;
 	}
 
 	// Server listen sockets are *not* for sending data. They only accept incoming connections.
 	if (type == ServerListenSocket)
 	{
-		LOG(LogError, "Trying to send data through a server listen socket!");
+		KNET_LOG(LogError, "Trying to send data through a server listen socket!");
 		return false;
 	}
 
 	if (!writeOpen)
 	{
-		LOG(LogError, "Trying to send data to a socket that is not open for writing!");
+		KNET_LOG(LogError, "Trying to send data to a socket that is not open for writing!");
 		return false;
 	}
 
@@ -725,9 +727,9 @@ bool Socket::Send(const char *data, size_t numBytes)
 	else
 		bytesSent = send(connectSocket, data, numBytes, 0);
 
-	if (bytesSent == numBytes)
+	if (bytesSent == (int)numBytes)
 	{
-		LOG(LogData, "Socket::EndSend: Sent out %d bytes to socket %s.", bytesSent, ToString().c_str());
+		KNET_LOG(LogData, "Socket::EndSend: Sent out %d bytes to socket %s.", bytesSent, ToString().c_str());
 		return true;
 	}
 	else if (bytesSent > 0) // Managed to send some data, but not all bytes.
@@ -741,7 +743,7 @@ bool Socket::Send(const char *data, size_t numBytes)
 		bool waitSuccess = WaitForSendReady(socketWriteTimeout);
 		if (!waitSuccess)
 		{
-			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.", 
+			KNET_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);
 			Close();
 			return false;
@@ -757,7 +759,7 @@ bool Socket::Send(const char *data, size_t numBytes)
 
 		if (error != KNET_EWOULDBLOCK)
 		{
-			LOG(LogError, "Socket::Send() failed! Error: %s.", Network::GetErrorString(error).c_str());
+			KNET_LOG(LogError, "Socket::Send() failed! Error: %s.", Network::GetErrorString(error).c_str());
 			if (type == ServerClientSocket && transport == SocketOverUDP)
 			{
 				// UDP client sockets are shared between each client (and by the server socket),
@@ -846,7 +848,7 @@ OverlappedTransferBuffer *Socket::BeginSend(int maxBytesToSend)
 		}
 		if (ret == FALSE && error != WSA_IO_INCOMPLETE)
 		{
-			LOG(LogError, "Socket::BeginSend: WSAGetOverlappedResult failed with an error %s, code %d != WSA_IO_INCOMPLETE!", 
+			KNET_LOG(LogError, "Socket::BeginSend: WSAGetOverlappedResult failed with an error %s, code %d != WSA_IO_INCOMPLETE!", 
 				Network::GetErrorString(error).c_str(), error);
 			writeOpen = false;
 			return 0;
@@ -889,7 +891,7 @@ bool Socket::EndSend(OverlappedTransferBuffer *sendBuffer)
 	{
 		if (error != KNET_EWOULDBLOCK)
 		{
-			LOG(LogError, "Socket::EndSend() failed! Error: %s.", Network::GetErrorString(error).c_str());
+			KNET_LOG(LogError, "Socket::EndSend() failed! Error: %s.", Network::GetErrorString(error).c_str());
 			if (!IsUDPServerSocket())
 				writeOpen = false;
 		}
@@ -900,7 +902,7 @@ bool Socket::EndSend(OverlappedTransferBuffer *sendBuffer)
 	bool success = queuedSendBuffers.Insert(sendBuffer);
 	if (!success)
 	{
-		LOG(LogError, "queuedSendBuffers.Insert(send); failed!");
+		KNET_LOG(LogError, "queuedSendBuffers.Insert(send); failed!");
 		///\todo WARNING: Deleting a buffer that is submitted to WSASend. This crashes. The alternative
 		/// is to leak. Refactor so that the above queuedSendBuffers.Insert is tried for success before calling WSASend.
 		DeleteOverlappedTransferBuffer(sendBuffer);
@@ -908,7 +910,7 @@ bool Socket::EndSend(OverlappedTransferBuffer *sendBuffer)
 	}
 	return true;
 
-#elif defined(UNIX) || defined(ANDROID)
+#elif defined(KNET_UNIX) || defined(ANDROID)
 	bool success = Send(sendBuffer->buffer.buf, sendBuffer->buffer.len);
 	DeleteOverlappedTransferBuffer(sendBuffer);
 	return success;
@@ -927,14 +929,14 @@ void Socket::AbortSend(OverlappedTransferBuffer *send)
 	// Set the event flag so as to signal that this buffer is completed immediately.
 	if (WSASetEvent(send->overlapped.hEvent) != TRUE)
 	{
-		LOG(LogError, "Socket::AbortSend: WSASetEvent failed!");
+		KNET_LOG(LogError, "Socket::AbortSend: WSASetEvent failed!");
 		DeleteOverlappedTransferBuffer(send);
 		return;
 	}
 	bool success = queuedSendBuffers.Insert(send);
 	if (!success)
 	{
-		LOG(LogError, "queuedSendBuffers.Insert(send); failed! AbortOverlappedSend");
+		KNET_LOG(LogError, "queuedSendBuffers.Insert(send); failed! AbortOverlappedSend");
 		DeleteOverlappedTransferBuffer(send);
 	}
 #else
@@ -968,12 +970,12 @@ void Socket::SetNaglesAlgorithmEnabled(bool enabled)
 {
 	if (connectSocket == INVALID_SOCKET)
 	{
-		LOG(LogError, "Socket::SetNaglesAlgorithmEnabled called for invalid socket object!");
+		KNET_LOG(LogError, "Socket::SetNaglesAlgorithmEnabled called for invalid socket object!");
 		return;
 	}
 	if (transport != SocketOverTCP)
 	{
-		LOG(LogError, "Calling Socket::SetNaglesAlgorithmEnabled is only valid for TCP sockets!");
+		KNET_LOG(LogError, "Calling Socket::SetNaglesAlgorithmEnabled is only valid for TCP sockets!");
 		return;
 	}
 
@@ -985,7 +987,7 @@ void Socket::SetNaglesAlgorithmEnabled(bool enabled)
 	int ret = setsockopt(connectSocket, IPPROTO_TCP, TCP_NODELAY, &nagleEnabled, sizeof(nagleEnabled));
 #endif
 	if (ret != 0)
-		LOG(LogError, "Setting TCP_NODELAY=%s for socket %d failed. Reason: %s.",
+		KNET_LOG(LogError, "Setting TCP_NODELAY=%s for socket %d failed. Reason: %s.",
 			enabled ? "true" : "false", (int)connectSocket, Network::GetLastErrorString().c_str());
 }
 

+ 12 - 12
Source/ThirdParty/kNet/src/TCPMessageConnection.cpp

@@ -68,7 +68,7 @@ MessageConnection::SocketReadResult TCPMessageConnection::ReadSocket(size_t &tot
 
 	if (inboundMessageQueue.CapacityLeft() < arbitraryInboundMessageCapacityLimit) 
 	{
-		LOG(LogVerbose, "TCPMessageConnection::ReadSocket: Read throttled! Application cannot consume data fast enough.");
+		KNET_LOG(LogVerbose, "TCPMessageConnection::ReadSocket: Read throttled! Application cannot consume data fast enough.");
 		return SocketReadThrottled; // Can't read in new data, since the client app can't process it so fast.
 	}
 
@@ -104,12 +104,12 @@ MessageConnection::SocketReadResult TCPMessageConnection::ReadSocket(size_t &tot
 				// Even compacting didn't get enough space to fit the message, so resize the ring buffer to be able to contain the message.
 				// At least always double the capacity of the buffer, so that we don't waste effort incrementing the capacity by too small amounts at a time.
 				tcpInboundSocketData.Resize(max(tcpInboundSocketData.Capacity()*2, tcpInboundSocketData.Capacity() + buffer->bytesContains - tcpInboundSocketData.ContiguousFreeBytesLeft()));
-				LOG(LogWaits, "TCPMessageConnection::ReadSocket: Performance warning! Resized the capacity of the receive ring buffer to %d bytes to accommodate a message of size %d (now have %d bytes of free space)",
+				KNET_LOG(LogWaits, "TCPMessageConnection::ReadSocket: Performance warning! Resized the capacity of the receive ring buffer to %d bytes to accommodate a message of size %d (now have %d bytes of free space)",
 					tcpInboundSocketData.Capacity(), buffer->bytesContains, tcpInboundSocketData.ContiguousFreeBytesLeft());
 			}
 		}
 
-		LOG(LogData, "TCPMessageConnection::ReadSocket: Received %d bytes from the network from peer %s.", 
+		KNET_LOG(LogData, "TCPMessageConnection::ReadSocket: Received %d bytes from the network from peer %s.", 
 			buffer->bytesContains, socket->ToString().c_str());
 
 		assert((size_t)buffer->bytesContains <= (size_t)tcpInboundSocketData.ContiguousFreeBytesLeft());
@@ -166,7 +166,7 @@ MessageConnection::PacketSendResult TCPMessageConnection::SendOutPacket()
 
 	if (!socket || !socket->IsWriteOpen())
 	{
-		LOG(LogVerbose, "TCPMessageConnection::SendOutPacket: Socket is not write open %p!", socket);
+		KNET_LOG(LogVerbose, "TCPMessageConnection::SendOutPacket: Socket is not write open %p!", socket);
 		if (connectionState == ConnectionOK) ///\todo This is slightly annoying to manually update the state here,
 			connectionState = ConnectionPeerClosed; /// reorganize to be able to have this automatically apply.
 		if (connectionState == ConnectionDisconnecting)
@@ -216,8 +216,8 @@ MessageConnection::PacketSendResult TCPMessageConnection::SendOutPacket()
             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);
+		        KNET_LOG(LogError, "TCPMessageConnection::SendOutPacket: Starting an overlapped send failed!");
+                assert(serializedMessages.empty());
 		        return PacketSendSocketClosed;
 	        }
             writer = DataSerializer(overlappedTransfer->buffer.buf, overlappedTransfer->buffer.len);
@@ -244,7 +244,7 @@ MessageConnection::PacketSendResult TCPMessageConnection::SendOutPacket()
 //	assert(ContainerUniqueAndNoNullElements(serializedMessages)); // This precondition should always hold (but very heavy to test, uncomment to debug)
 
 	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().c_str());
+		KNET_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->bytesContains = writer.BytesFilled();
 	bool success = socket->EndSend(overlappedTransfer);
@@ -259,12 +259,12 @@ MessageConnection::PacketSendResult TCPMessageConnection::SendOutPacket()
 #endif
 //		assert(ContainerUniqueAndNoNullElements(outboundQueue));
 
-		LOG(LogError, "TCPMessageConnection::SendOutPacket() failed: Could not initiate overlapped transfer!");
+		KNET_LOG(LogError, "TCPMessageConnection::SendOutPacket() failed: Could not initiate overlapped transfer!");
 
 		return PacketSendSocketFull;
 	}
 
-	LOG(LogData, "TCPMessageConnection::SendOutPacket: Sent %d bytes (%d messages) to peer %s.", (int)writer.BytesFilled(), (int)serializedMessages.size(), socket->ToString().c_str());
+	KNET_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);
 	ADDEVENT("tcpDataOut", (float)writer.BytesFilled(), "bytes");
 
@@ -333,7 +333,7 @@ void TCPMessageConnection::ExtractMessages()
 
 			if (messageSize == 0 || messageSize > cMaxReceivableTCPMessageSize)
 			{
-				LOG(LogError, "Received an invalid message size %d!", (int)messageSize);
+				KNET_LOG(LogError, "Received an invalid message size %d!", (int)messageSize);
 				throw NetException("Malformed TCP data! Received an invalid message size!");
 			}
 
@@ -354,7 +354,7 @@ void TCPMessageConnection::ExtractMessages()
 		AddInboundStats(0, 0, numMessagesReceived);
 	} catch(const NetException &e)
 	{
-		LOG(LogError, "TCPMessageConnection::ExtractMessages() caught a network exception: \"%s\"!", e.what());
+		KNET_LOG(LogError, "TCPMessageConnection::ExtractMessages() caught a network exception: \"%s\"!", e.what());
 		if (socket)
 			socket->Close();
 		connectionState = ConnectionClosed;
@@ -382,7 +382,7 @@ void TCPMessageConnection::DumpConnectionStatus() const
 		tcpInboundSocketData.Size(), 
 		tcpInboundSocketData.ContiguousFreeBytesLeft());
 
-	LOGUSER(str);
+	KNET_LOGUSER(str);
 
 
 }

+ 3 - 3
Source/ThirdParty/kNet/src/Thread.cpp

@@ -56,7 +56,7 @@ void Thread::Hold()
 		if (success)
 			break;
 	}
-	LOG(LogWaits, "Thread::Hold: Took %f msecs.", timer.MSecsElapsed());
+	KNET_LOG(LogWaits, "Thread::Hold: Took %f msecs.", timer.MSecsElapsed());
 }
 
 /// Resumes the thread that is being held.
@@ -71,7 +71,7 @@ void Thread::CheckHold()
 {
 	if (threadHoldEvent.Test())
 	{
-		LOG(LogVerbose, "Thread::CheckHold(): suspending thread. this: %p.", this);
+		KNET_LOG(LogVerbose, "Thread::CheckHold(): suspending thread. this: %p.", this);
 
 		PolledTimer timer;
 		while(!ShouldQuit())
@@ -81,7 +81,7 @@ void Thread::CheckHold()
 			if (success)
 				break;
 		}
-		LOG(LogWaits, "Thread::CheckHold: Slept for %f msecs.", timer.MSecsElapsed());
+		KNET_LOG(LogWaits, "Thread::CheckHold: Slept for %f msecs.", timer.MSecsElapsed());
 		threadHoldEventAcked.Reset();
 	}
 }

+ 50 - 52
Source/ThirdParty/kNet/src/UDPMessageConnection.cpp

@@ -68,7 +68,7 @@ datagramSendRate(50.f), lowestDatagramSendRateOnPacketLoss(50.f), slowModeDelay(
 receivedPacketIDs(64 * 1024), outboundPacketAckTrack(1024),
 previousReceivedPacketID(0), queuedInboundDatagrams(128)
 {
-	LOG(LogObjectAlloc, "Allocated UDPMessageConnection %p.", this);
+	KNET_LOG(LogObjectAlloc, "Allocated UDPMessageConnection %p.", this);
 
 	lastFrameTime = Clock::Tick();
 	lastDatagramSendTime = Clock::Tick();
@@ -76,7 +76,7 @@ previousReceivedPacketID(0), queuedInboundDatagrams(128)
 
 UDPMessageConnection::~UDPMessageConnection()
 {
-	LOG(LogObjectAlloc, "Deleted UDPMessageConnection %p.", this);
+	KNET_LOG(LogObjectAlloc, "Deleted UDPMessageConnection %p.", this);
 
 	// The first thing we do when starting to close down a connection is to ensure that this connection gets detached from its worker thread.
 	// Therefore, as the first thing, invoke CloseConnection which achieves this.
@@ -95,12 +95,12 @@ void UDPMessageConnection::QueueInboundDatagram(const char *data, size_t numByte
 {
 	if (!data || numBytes == 0)
 	{
-		LOG(LogError, "UDPMessageConnection::QueueInboundDatagram: Ignoring received zero-sized datagram!");
+		KNET_LOG(LogError, "UDPMessageConnection::QueueInboundDatagram: Ignoring received zero-sized datagram!");
 		return;
 	}
 	if (numBytes > cDatagramBufferSize)
 	{
-		LOG(LogError, "UDPMessageConnection::QueueInboundDatagram: Discarding received over-sized datagram (%d bytes)!", (int)numBytes);
+		KNET_LOG(LogError, "UDPMessageConnection::QueueInboundDatagram: Discarding received over-sized datagram (%d bytes)!", (int)numBytes);
 		return;
 	}
 
@@ -110,7 +110,7 @@ void UDPMessageConnection::QueueInboundDatagram(const char *data, size_t numByte
 	bool success = queuedInboundDatagrams.Insert(d);
 	if (!success)
 	{
-		LOG(LogError, "UDPMessageConnection::QueueInboundDatagram: Dropping received datagram, since the client receive buffer is full!");
+		KNET_LOG(LogError, "UDPMessageConnection::QueueInboundDatagram: Dropping received datagram, since the client receive buffer is full!");
 		return;
 	}
 }
@@ -133,15 +133,13 @@ UDPMessageConnection::SocketReadResult UDPMessageConnection::ReadSocket(size_t &
 
 	assert(!socket || socket->TransportLayer() == SocketOverUDP);
 
-	SocketReadResult readResult = SocketReadOK;
-		
-	readResult = UDPReadSocket(bytesRead);
+	SocketReadResult readResult = UDPReadSocket(bytesRead);
 
 	///\todo Replace with ConnectSyn,ConnectSynAck and ConnectAck.
 	if (bytesRead > 0 && connectionState == ConnectionPending)
 	{
 		connectionState = ConnectionOK;
-		LOG(LogUser, "UDPMessageConnection::ReadSocket: Received data from socket %s. Transitioned from ConnectionPending to ConnectionOK state.", 
+		KNET_LOG(LogUser, "UDPMessageConnection::ReadSocket: Received data from socket %s. Transitioned from ConnectionPending to ConnectionOK state.", 
 			(socket ? socket->ToString().c_str() : "(null)"));
 	}
 	if (readResult == SocketReadError)
@@ -149,7 +147,7 @@ UDPMessageConnection::SocketReadResult UDPMessageConnection::ReadSocket(size_t &
 	if (readResult == SocketReadThrottled)
 		return SocketReadThrottled;
 	if (bytesRead > 0)
-		LOG(LogData, "Received %d bytes from UDP socket.", (int)bytesRead);
+		KNET_LOG(LogData, "Received %d bytes from UDP socket.", (int)bytesRead);
 	return SocketReadOK;
 }
 
@@ -158,7 +156,7 @@ void UDPMessageConnection::PerformPacketAckSends()
 	AssertInWorkerThreadContext();
 
 	tick_t now = Clock::Tick();
-	while(inboundPacketAckTrack.size() > 0)
+	while(!inboundPacketAckTrack.empty())
 	{
 		if (Clock::TimespanToMillisecondsF(inboundPacketAckTrack.begin()->second.sentTick, now) < maxAckDelay &&
 			inboundPacketAckTrack.size() < 33)
@@ -190,7 +188,7 @@ UDPMessageConnection::SocketReadResult UDPMessageConnection::UDPReadSocket(size_
 
 		totalBytesRead += data->bytesContains;
 
-		LOG(LogData, "UDPReadSocket: Received %d bytes from Begin/EndReceive.", data->bytesContains);
+		KNET_LOG(LogData, "UDPReadSocket: Received %d bytes from Begin/EndReceive.", data->bytesContains);
 		ExtractMessages(data->buffer.buf, data->bytesContains);
 
 		// Done with the received data buffer. Free it up for a future socket read.
@@ -199,7 +197,7 @@ UDPMessageConnection::SocketReadResult UDPMessageConnection::UDPReadSocket(size_
 
 	if (maxReads == 0)
 	{
-		LOG(LogError, "Warning: Too many inbound messages: Datagram read loop throttled!");
+		KNET_LOG(LogError, "Warning: Too many inbound messages: Datagram read loop throttled!");
 		return SocketReadThrottled;
 	}
 	else
@@ -229,7 +227,7 @@ void UDPMessageConnection::ProcessPacketTimeouts() // [worker thread]
 
 		++numPacketsTimedOut;
 			
-		LOG(LogVerbose, "A packet with ID %d timed out. Age: %.2fms. Contains %d messages.", 
+		KNET_LOG(LogVerbose, "A packet with ID %d timed out. Age: %.2fms. Contains %d messages.", 
 			(int)track->packetID, (float)Clock::TimespanToMillisecondsD(track->sentTick, now), (int)track->messages.size());
 		ADDEVENT("datagramsLost", 1, "");
 
@@ -280,8 +278,7 @@ void UDPMessageConnection::HandleFlowControl()
 		{
 			float oldRate = datagramSendRate;
 			datagramSendRate = min(datagramSendRate, max(minBandwidthOnLoss, lowestDatagramSendRateOnPacketLoss * 0.9f)); // Multiplicative decreases.
-			//std::cout << "Loss!" << std::endl;
-			LOG(LogVerbose, "Received %d losses. datagramSendRate backed to %.2f from %.2f", (int)numLossesLastFrame, datagramSendRate, oldRate);
+			KNET_LOG(LogVerbose, "Received %d losses. datagramSendRate backed to %.2f from %.2f", (int)numLossesLastFrame, datagramSendRate, oldRate);
 		}
 		else
 		{
@@ -299,6 +296,7 @@ void UDPMessageConnection::HandleFlowControl()
 					delta *= 0.2f;
 				datagramSendRate = min(datagramSendRate + delta, maxBandwidth);
 			lowestDatagramSendRateOnPacketLoss = datagramSendRate;
+//			KNET_LOG(LogVerbose, "Incremented sendRate by %.2f to %.2f", increment, datagramSendRate);
 		}
 			// Need less: decrease sendrate if not already at minimum
 			else if (needLess && datagramSendRate > minBandwidth)
@@ -368,7 +366,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 	if (!data)
 		return PacketSendThrottled;
 
-	const size_t minSendSize = 1;
+//	const size_t minSendSize = 1;
 	const size_t maxSendSize = socket->MaxSendSize();
 
 	// Push out all the pending data to the socket.
@@ -406,7 +404,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 		// or skip it if there are no transferIDs free.
 		if (msg->transfer)
 		{
-			LOG(LogVerbose, "Sending out a fragmented transfer.");
+			KNET_LOG(LogVerbose, "Sending out a fragmented transfer.");
 			Lock<FragmentedSendManager> sends = fragmentedSends.Acquire();
 			if (msg->transfer->id == -1)
 			{
@@ -414,7 +412,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 
 				if (!success) // No transferIDs free - skip this message for now.
 				{
-					LOG(LogError, "Throttling fragmented transfer send! No free TransferID to start a new fragmented transfer with!");
+					KNET_LOG(LogError, "Throttling fragmented transfer send! No free TransferID to start a new fragmented transfer with!");
 					outboundQueue.PopFront();
 					skippedMessages.push_back(msg);
 					continue;
@@ -428,11 +426,11 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 		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 (datagramSerializedMessages.size() > 0 && (size_t)packetSizeInBytes + totalMessageSize >= maxSendSize)
+		if (!datagramSerializedMessages.empty() && (size_t)packetSizeInBytes + totalMessageSize >= maxSendSize)
 			break;
 
 		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);
+			KNET_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_back(msg);
 		outboundQueue.PopFront();
@@ -456,7 +454,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 			u32 reliableDelta = (u32)(datagramSerializedMessages[i]->reliableMessageNumber - smallestReliableMessageNumber);
 			if (reliableDelta > VLE8_16::maxValue) // We use a VLE8_16 to store deltas, so 32767 is the largest delta we can store. If two messages have a delta larger than this,
 			{                                      // 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)",
+				KNET_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);
 				skippedMessages.push_back(datagramSerializedMessages[i]);
 				datagramSerializedMessages.erase(datagramSerializedMessages.begin() + i);
@@ -555,7 +553,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 		for(size_t i = 0; i < datagramSerializedMessages.size(); ++i)
 			outboundQueue.Insert(datagramSerializedMessages[i]);
 
-		LOG(LogError, "UDPMessageConnection::SendOutPacket: Socket::EndSend failed to socket %s!", socket->ToString().c_str());
+		KNET_LOG(LogError, "UDPMessageConnection::SendOutPacket: Socket::EndSend failed to socket %s!", socket->ToString().c_str());
 		return PacketSendSocketFull;
 	}
 
@@ -637,7 +635,7 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 			connectionState = ConnectionClosed;
 		if (socket)
 			socket->MarkWriteClosed();
-		LOG(LogInfo, "UDPMessageConnection::SendOutPacket: Send Disconnect from connection %s.", ToString().c_str());
+		KNET_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 (sentDisconnectAckMessage)
@@ -648,10 +646,10 @@ MessageConnection::PacketSendResult UDPMessageConnection::SendOutPacket()
 			socket->MarkWriteClosed();
 		}
 		connectionState = ConnectionClosed;
-		LOG(LogInfo, "UDPMessageConnection::SendOutPacket: Send DisconnectAck from connection %s.", ToString().c_str());
+		KNET_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());
+	KNET_LOG(LogVerbose, "UDPMessageConnection::SendOutPacket: Socket::EndSend succeeded with %d bytes.", (int)writer.BytesFilled());
 	return PacketSendOK;
 }
 
@@ -728,7 +726,7 @@ void UDPMessageConnection::AddReceivedPacketIDStats(packet_id_t packetID)
 	ConnectionStatistics::DatagramIDTrack &t = cs.recvPacketIDs.back();
 	t.tick = Clock::Tick();
 	t.packetID = packetID;
-//	LOG(LogVerbose, "Marked packet with ID %d received.", (int)packetID);
+//	KNET_LOG(LogVerbose, "Marked packet with ID %d received.", (int)packetID);
 	statistics.Unlock();
 */
 	// Remember this packet ID for duplicacy detection and pruning purposes.
@@ -759,7 +757,7 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 
 	if (numBytes < 3)
 	{
-		LOG(LogError, "Malformed UDP packet when reading packet header! Size = %d bytes, no space for packet header, which is at least 3 bytes.", (int)numBytes);
+		KNET_LOG(LogError, "Malformed UDP packet when reading packet header! Size = %d bytes, no space for packet header, which is at least 3 bytes.", (int)numBytes);
 		throw NetException("Malformed UDP packet received! No packed header present.");
 	}
 
@@ -789,7 +787,7 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 	if (HaveReceivedPacketID(packetID))
 	{
 		ADDEVENT("duplicateReceived", (float)numBytes, "bytes");
-		LOG(LogVerbose, "Duplicate datagram with packet ID %d received!", (int)packetID);
+		KNET_LOG(LogVerbose, "Duplicate datagram with packet ID %d received!", (int)packetID);
 		return;
 	}
 	if (packetID != previousReceivedPacketID + 1)
@@ -803,7 +801,7 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 //		inOrderID = reader.ReadVLE<VLE8_16>();
 		if (inOrderID == DataDeserializer::VLEReadError)
 		{
-			LOG(LogError, "Malformed UDP packet! Size = %d bytes, no space for packet header field 'inOrder'!", (int)numBytes);
+			KNET_LOG(LogError, "Malformed UDP packet! Size = %d bytes, no space for packet header field 'inOrder'!", (int)numBytes);
 			throw NetException("Malformed UDP packet received! The inOrder field was invalid.");
 		}
 	}
@@ -813,7 +811,7 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 	{
 		if (reader.BytesLeft() < 2)
 		{
-			LOG(LogError, "Malformed UDP packet! Parsed %d messages ok, but after that there's not enough space for UDP message header! BytePos %d, total size %d",
+			KNET_LOG(LogError, "Malformed UDP packet! Parsed %d messages ok, but after that there's not enough space for UDP message header! BytePos %d, total size %d",
 				(int)reader.BytePos(), (int)numBytes);
 			throw NetException("Malformed UDP packet received! Message header was not present.");
 		}
@@ -834,7 +832,7 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 		if (messageReliable)
 		{
 			if (!packetReliable)
-				LOG(LogError, "Received reliable message on a packet that is not reliable!");
+				KNET_LOG(LogError, "Received reliable message on a packet that is not reliable!");
 
 			reliableMessageNumber = reliableMessageIndexBase + reader.ReadVLE<VLE8_16>();
 
@@ -846,7 +844,7 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 
 		if (contentLength == 0)
 		{
-			LOG(LogError, "Malformed UDP packet! Byteofs %d, Packet length %d. Message had zero length (Length must be at least one byte)!", (int)reader.BytePos(), (int)numBytes);
+			KNET_LOG(LogError, "Malformed UDP packet! Byteofs %d, Packet length %d. Message had zero length (Length must be at least one byte)!", (int)reader.BytePos(), (int)numBytes);
 			throw NetException("Malformed UDP packet received! Messages with zero content length are not valid.");
 		}
 
@@ -856,7 +854,7 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 
 		if (reader.BytesLeft() < contentLength)
 		{
-			LOG(LogError, "Malformed UDP packet! Byteofs %d, Packet length %d. Expected %d bytes of message content, but only %d bytes left!",
+			KNET_LOG(LogError, "Malformed UDP packet! Byteofs %d, Packet length %d. Expected %d bytes of message content, but only %d bytes left!",
 				(int)reader.BytePos(), (int)numBytes, (int)contentLength, (int)reader.BytesLeft());
 			throw NetException("Malformed UDP packet received! Message payload missing.");
 		}
@@ -868,7 +866,7 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 			{
 				if (numTotalFragments == DataDeserializer::VLEReadError || numTotalFragments <= 1)
 				{
-					LOG(LogError, "Malformed UDP packet! This packet had fragmentStart bit on, but parsing numTotalFragments VLE failed!");
+					KNET_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!");
 				}
 
@@ -882,7 +880,7 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 			{
 				if (fragmentNumber == DataDeserializer::VLEReadError)
 				{
-					LOG(LogError, "Malformed UDP packet! This packet has fragment flag on, but parsing the fragment number failed!");
+					KNET_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!");
 				}
 
@@ -895,7 +893,7 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 					// the client to handle.
 					assembledData.clear();
 					fragmentedReceives.AssembleMessage(fragmentTransferID, assembledData);
-					assert(assembledData.size() > 0);
+					assert(!assembledData.empty());
 					///\todo InOrder.
 					HandleInboundMessage(packetID, &assembledData[0], assembledData.size());
 					++numMessagesReceived;
@@ -912,7 +910,7 @@ void UDPMessageConnection::ExtractMessages(const char *data, size_t numBytes)
 		else // this is a duplicate reliable message, ignore it.
 		{
 			///\todo Can we remove this duplicate reliable message checking?
-			LOG(LogVerbose, "Received a duplicate reliable message with message number %d!", (int)reliableMessageNumber);
+			KNET_LOG(LogVerbose, "Received a duplicate reliable message with message number %d!", (int)reliableMessageNumber);
 		}
 
 		reader.SkipBytes(contentLength);
@@ -963,7 +961,7 @@ void UDPMessageConnection::SendDisconnectMessage(bool isInternal)
 #endif
 	EndAndQueueMessage(msg, 0, isInternal);
 
-	LOG(LogInfo, "UDPMessageConnection::SendDisconnectMessage: Sent Disconnect.");
+	KNET_LOG(LogInfo, "UDPMessageConnection::SendDisconnectMessage: Sent Disconnect.");
 }
 
 void UDPMessageConnection::SendDisconnectAckMessage()
@@ -978,10 +976,10 @@ void UDPMessageConnection::SendDisconnectAckMessage()
 #endif
 	EndAndQueueMessage(msg, 0, true); ///\todo Check this flag!
 
-	LOG(LogInfo, "UDPMessageConnection::SendDisconnectAckMessage: Sent DisconnectAck.");
+	KNET_LOG(LogInfo, "UDPMessageConnection::SendDisconnectAckMessage: Sent DisconnectAck.");
 }
 
-int UDPMessageConnection::BiasedBinarySearchFindPacketIndex(PacketAckTrackQueue &queue, int packetID)
+int UDPMessageConnection::BiasedBinarySearchFindPacketIndex(PacketAckTrackQueue &queue, packet_id_t packetID)
 {
 	///\bug Make this all packetID wrap-around -aware.
 
@@ -994,7 +992,7 @@ int UDPMessageConnection::BiasedBinarySearchFindPacketIndex(PacketAckTrackQueue
 	if (tailItem->packetID == packetID)
 		return tailIdx;
 	assert(headItem->packetID < tailItem->packetID);
-	if ((int)headItem->packetID > packetID || (int)tailItem->packetID < packetID)
+	if (headItem->packetID > packetID || tailItem->packetID < packetID)
 		return -1;
 	while(headIdx < tailIdx)
 	{
@@ -1003,7 +1001,7 @@ int UDPMessageConnection::BiasedBinarySearchFindPacketIndex(PacketAckTrackQueue
 		PacketAckTrack *newItem = queue.ItemAt(newIdx);
 		if (newItem->packetID == packetID)
 			return newIdx;
-		else if ((int)newItem->packetID < packetID)
+		else if (newItem->packetID < packetID)
 		{
 			headIdx = newIdx;
 			headItem = newItem;
@@ -1088,20 +1086,20 @@ void UDPMessageConnection::UpdateRTOCounterOnPacketLoss()
 
 	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.
 	rttVariation = 0.f;
 
 	++numLossesLastFrame;
 
-//	LOG(LogVerbose, "Packet loss event: RTO: %.3f sec. datagramSendRate: %.2f", retransmissionTimeout, datagramSendRate);
+//	KNET_LOG(LogVerbose, "Packet loss event: RTO: %.3f sec. datagramSendRate: %.2f", retransmissionTimeout, datagramSendRate);
 }
 
 void UDPMessageConnection::SendPacketAckMessage()
 {
 	AssertInWorkerThreadContext();
 
-	while(inboundPacketAckTrack.size() > 0)
+	while(!inboundPacketAckTrack.empty())
 	{
 		packet_id_t packetID = inboundPacketAckTrack.begin()->first;
 		u32 sequence = 0;
@@ -1138,7 +1136,7 @@ void UDPMessageConnection::HandlePacketAckMessage(const char *data, size_t numBy
 
 	if (numBytes != 7)
 	{
-		LOG(LogError, "Malformed PacketAck message received! Size was %d bytes, expected 7 bytes!", (int)numBytes);
+		KNET_LOG(LogError, "Malformed PacketAck message received! Size was %d bytes, expected 7 bytes!", (int)numBytes);
 		throw NetException("Received a PacketAck message of wrong size! (expected 7 bytes)");
 	}
 
@@ -1164,7 +1162,7 @@ void UDPMessageConnection::HandleDisconnectMessage()
 	if (connectionState != ConnectionClosed)
 		connectionState = ConnectionDisconnecting;
 	else
-		LOG(LogError, "UDPMessageConnection::HandleDisconnectMessage: Received Disconnect message when in ConnectionClosed state!");
+		KNET_LOG(LogError, "UDPMessageConnection::HandleDisconnectMessage: Received Disconnect message when in ConnectionClosed state!");
 
 	if (socket)
 	{
@@ -1184,10 +1182,10 @@ void UDPMessageConnection::HandleDisconnectAckMessage()
 	}
 
 	if (connectionState != ConnectionDisconnecting)
-		LOG(LogInfo, "Received DisconnectAck message on a MessageConnection not in ConnectionDisconnecting state! (state was %d)",
+		KNET_LOG(LogInfo, "Received DisconnectAck message on a MessageConnection not in ConnectionDisconnecting state! (state was %d)",
 		(int)connectionState);
 	else
-		LOG(LogInfo, "UDPMessageConnection::HandleDisconnectAckMessage: Connection closed to %s.", ToString().c_str());
+		KNET_LOG(LogInfo, "UDPMessageConnection::HandleDisconnectAckMessage: Connection closed to %s.", ToString().c_str());
 
 	connectionState = ConnectionClosed;
 }
@@ -1280,7 +1278,7 @@ bool UDPMessageConnection::HandleMessage(packet_id_t packetID, message_id_t mess
 			u32 contentID = inboundMessageHandler->ComputeContentID(messageID, data, numBytes);
 			if (contentID != 0 && CheckAndSaveContentIDStamp(messageID, contentID, packetID) == false)
 			{
-				LOG(LogVerbose, "MessageID %d in packetID %d and contentID %d is obsolete! Skipped.", (int)messageID, (int)packetID, (int)contentID);
+				KNET_LOG(LogVerbose, "MessageID %d in packetID %d and contentID %d is obsolete! Skipped.", (int)messageID, (int)packetID, (int)contentID);
 				return true;
 			}
 			return false;
@@ -1313,7 +1311,7 @@ void UDPMessageConnection::DumpConnectionStatus() const
 	PacketsInPerSec(), 
 	PacketsOutPerSec());
 
-	LOGUSER(str);
+	KNET_LOGUSER(str);
 }
 
 } // ~kNet

+ 3 - 2
Source/ThirdParty/kNet/src/boost/BoostThread.cpp

@@ -14,13 +14,12 @@
 
 /** @file BoostThread.cpp
 	@brief */
+#ifdef KNET_USE_BOOST
 
 #include <cassert>
 #include <exception>
 
-#ifdef KNET_USE_BOOST
 #include <boost/thread/thread.hpp>
-#endif
 
 #include "kNet/DebugMemoryLeakCheck.h"
 
@@ -127,3 +126,5 @@ ThreadId Thread::NullThreadId()
 }
 
 } // ~kNet
+
+#endif // ~KNET_USE_BOOST

+ 0 - 142
Source/ThirdParty/kNet/src/unix/UnixClock.cpp

@@ -1,142 +0,0 @@
-/* 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 UnixClock.cpp
-	@brief */
-
-#include <cassert>
-
-#include <time.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/time.h>
-
-#include "kNet/Clock.h"
-#include "kNet/NetworkLogging.h"
-
-namespace kNet
-{
-
-tick_t Clock::appStartTime = 0;
-
-Clock impl;
-
-void Clock::InitClockData()
-{
-	if (appStartTime == 0)
-		appStartTime = Tick();
-}
-
-Clock::Clock()
-{
-	InitClockData();
-}
-
-void Clock::Sleep(int milliseconds)
-{
-	// http://linux.die.net/man/2/nanosleep
-	timespec ts;
-	ts.tv_sec = milliseconds / 1000;
-	ts.tv_nsec = (milliseconds - ts.tv_sec * 1000) * 1000 * 1000;
-	int ret = nanosleep(&ts, NULL);
-	if (ret == -1)
-		LOG(LogError, "nanosleep returned -1! Reason: %s(%d).", strerror(errno), (int)errno);
-}
-
-int Clock::Year()
-{
-	///\todo.
-	return 0;
-}
-
-int Clock::Month()
-{
-	///\todo.
-	return 0;
-}
-
-int Clock::Day()
-{
-	///\todo.
-	return 0;
-}
-
-int Clock::Hour()
-{
-	///\todo.
-	return 0;
-}
-
-int Clock::Min()
-{
-	///\todo.
-	return 0;
-}
-
-int Clock::Sec()
-{
-	///\todo.
-	return 0;
-}
-
-unsigned long Clock::SystemTime()
-{
-	return TickU32();
-}
-
-unsigned long Clock::Time()
-{
-	return (unsigned long)(Tick() - appStartTime);
-}
-
-tick_t Clock::Tick()
-{
-#if defined(ANDROID)
-	struct timespec res;
-	clock_gettime(CLOCK_REALTIME, &res);
-	return 1000000000ULL*res.tv_sec + (tick_t)res.tv_nsec;
-#elif defined(_POSIX_MONOTONIC_CLOCK)
-	timespec t;
-	clock_gettime(CLOCK_MONOTONIC, &t);
-	return (tick_t)t.tv_sec * 1000 * 1000 * 1000 + (tick_t)t.tv_nsec;
-//_POSIX_C_SOURCE is not defined on OSX
-#elif defined(_POSIX_C_SOURCE) || defined(__APPLE__)
-	timeval t;
-	gettimeofday(&t, NULL);
-	return (tick_t)t.tv_sec * 1000 * 1000 + (tick_t)t.tv_usec;
-#else
-	return (tick_t)time(NULL);
-#endif
-}
-
-unsigned long Clock::TickU32()
-{
-	return (unsigned long)Tick();
-}
-
-tick_t Clock::TicksPerSec()
-{
-#if defined(ANDROID)
-	return 1000000000ULL; // 1e9 == nanoseconds.
-#elif defined(_POSIX_MONOTONIC_CLOCK)
-	return 1000 * 1000 * 1000;
-//_POSIX_C_SOURCE is not defined on OSX
-#elif defined(_POSIX_C_SOURCE) || defined(__APPLE__)
-	return 1000 * 1000;
-#else
-	return 1;
-#endif
-}
-
-} // ~kNet

+ 13 - 13
Source/ThirdParty/kNet/src/unix/UnixEvent.cpp

@@ -63,20 +63,20 @@ void Event::Create(EventWaitType type_)
 	{
 		if (pipe(fd) == -1)
 		{
-			LOG(LogError, "Error in Event::Create: %s(%d)!", strerror(errno), errno);
+			KNET_LOG(LogError, "Error in Event::Create: %s(%d)!", strerror(errno), errno);
 			return;
 		}
 
 		int ret = fcntl(fd[0], F_SETFL, O_NONBLOCK);
 		if (ret == -1)
 		{
-			LOG(LogError, "Event::Create: fcntl failed to set fd[0] in nonblocking mode: %s(%d)", strerror(errno), errno);
+			KNET_LOG(LogError, "Event::Create: fcntl failed to set fd[0] in nonblocking mode: %s(%d)", strerror(errno), errno);
 			return;
 		}
 		ret = fcntl(fd[1], F_SETFL, O_NONBLOCK);
 		if (ret == -1)
 		{
-			LOG(LogError, "Event::Create: fcntl failed to set fd[1] in nonblocking mode: %s(%d)", strerror(errno), errno);
+			KNET_LOG(LogError, "Event::Create: fcntl failed to set fd[1] in nonblocking mode: %s(%d)", strerror(errno), errno);
 			return;
 		}
 	}
@@ -109,7 +109,7 @@ void Event::Reset()
 {
 	if (IsNull())
 	{
-		LOG(LogError, "Event::Reset() failed! Tried to reset an uninitialized Event!");
+		KNET_LOG(LogError, "Event::Reset() failed! Tried to reset an uninitialized Event!");
 		return;
 	}
 	if (type == EventWaitDummy)
@@ -126,28 +126,28 @@ void Event::Reset()
 		{
 			ret = read(fd[0], &val, sizeof(val));
 			if (ret == -1 && errno != EAGAIN)
-				LOG(LogError, "Event::Reset() read() failed: %s(%d)!", strerror(errno), (int)errno);
+				KNET_LOG(LogError, "Event::Reset() read() failed: %s(%d)!", strerror(errno), (int)errno);
 		}
 	}
 	else
-		LOG(LogError, "Event::Reset() called on an Event of type %d! (should have been of type EventWaitSignal)", (int)type); ///\todo int to string.
+		KNET_LOG(LogError, "Event::Reset() called on an Event of type %d! (should have been of type EventWaitSignal)", (int)type); ///\todo int to string.
 }
 
 void Event::Set()
 {
 	if (IsNull())
 	{
-		LOG(LogError, "Event::Set() failed! Tried to set an uninitialized Event!");
+		KNET_LOG(LogError, "Event::Set() failed! Tried to set an uninitialized Event!");
 		return;
 	}
 	if (type != EventWaitSignal)
 	{
-		LOG(LogError, "Event::Set() failed! Tried to set an event that is of type %d (should have been of type EventWaitSignal)", (int)type);
+		KNET_LOG(LogError, "Event::Set() failed! Tried to set an event that is of type %d (should have been of type EventWaitSignal)", (int)type);
 		return;
 	}
 	if (fd[1] == -1)
 	{
-		LOG(LogError, "Event::Set() failed! Tried to set a read-only Event! (This event is probably a Socket read descriptor");
+		KNET_LOG(LogError, "Event::Set() failed! Tried to set a read-only Event! (This event is probably a Socket read descriptor");
 		return;
 	}
 
@@ -161,7 +161,7 @@ void Event::Set()
 	int ret = write(fd[1], &val, sizeof(val));
 	if (ret == -1)
 	{
-		LOG(LogError, "Event::Set() write() failed: %s(%d)!", strerror(errno), (int)errno);
+		KNET_LOG(LogError, "Event::Set() write() failed: %s(%d)!", strerror(errno), (int)errno);
 		return;
 	}
 }
@@ -194,7 +194,7 @@ bool Event::Wait(unsigned long msecs) const
 		int ret = select(fd[0]+1, &fds, NULL, NULL, &tv); // http://linux.die.net/man/2/select
 		if (ret == -1)
 		{
-			LOG(LogError, "Event::Wait: select() failed on a pipe: %s(%d)!", strerror(errno), (int)errno);
+			KNET_LOG(LogError, "Event::Wait: select() failed on a pipe: %s(%d)!", strerror(errno), (int)errno);
 			return false;
 		}
 		return ret != 0;
@@ -204,14 +204,14 @@ bool Event::Wait(unsigned long msecs) const
 		int ret = select(fd[0]+1, NULL, &fds, NULL, &tv);
 		if (ret == -1)
 		{
-			LOG(LogError, "Event::Wait: select() failed for Event of type EventWaitWrite: %s(%d)!", strerror(errno), (int)errno);
+			KNET_LOG(LogError, "Event::Wait: select() failed for Event of type EventWaitWrite: %s(%d)!", strerror(errno), (int)errno);
 			return false;
 		}
 		return ret != 0;
 	}
 	else
 	{
-		LOG(LogError, "Event::Wait called for even of invalid type %d!", (int)type);
+		KNET_LOG(LogError, "Event::Wait called for even of invalid type %d!", (int)type);
 		return false;
 	}
 }

+ 6 - 6
Source/ThirdParty/kNet/src/unix/UnixEventArray.cpp

@@ -56,7 +56,7 @@ void EventArray::AddEvent(const Event &e)
 {
 	if (e.IsNull())
 	{
-		LOG(LogError, "Error: Tried to add a null event to event array at index %d!", numAdded);
+		KNET_LOG(LogError, "Error: Tried to add a null event to event array at index %d!", numAdded);
 		return;
 	}
 	assert(numAdded < maxEvents);
@@ -64,7 +64,7 @@ void EventArray::AddEvent(const Event &e)
 	switch(e.Type())
 	{
 	case EventWaitInvalid:
-		LOG(LogError, "Error: Tried to add an invalid event to a wait event array!");
+		KNET_LOG(LogError, "Error: Tried to add an invalid event to a wait event array!");
 		return;
 	case EventWaitRead:
 	case EventWaitSignal:
@@ -90,7 +90,7 @@ int EventArray::Wait(int msecs)
 {
 	if (numAdded == 0)
 	{
-		LOG(LogError, "EventArray::Wait failed! Tried to wait for an empty array of events! (EventArray=0x%p)", this);
+		KNET_LOG(LogError, "EventArray::Wait failed! Tried to wait for an empty array of events! (EventArray=0x%p)", this);
 		return WaitFailed;
 	}
 
@@ -111,7 +111,7 @@ int EventArray::Wait(int msecs)
 	int ret = select(nfds, &readfds, &writefds, NULL, &tv); // http://linux.die.net/man/2/select
 	if (ret == -1)
 	{
-		LOG(LogError, "EventArray::Wait(%d, %p, %p, NULL, {%d, %d}: select() failed on an array of %d events: %s(%d)", 
+		KNET_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);
@@ -124,7 +124,7 @@ int EventArray::Wait(int msecs)
 		return WaitTimedOut;
 	else if (ret < 0)
 	{
-		LOG(LogError, "EventArray::Wait: select() returned a negative value, which it shouldn't!");
+		KNET_LOG(LogError, "EventArray::Wait: select() returned a negative value, which it shouldn't!");
 		return WaitFailed;
 	}
 
@@ -143,7 +143,7 @@ int EventArray::Wait(int msecs)
 			break; // The dummy events are skipped over.
 		}
 
-	LOG(LogError, "EventArray::Wait error! No events were set, but select() returned a positive value!");
+	KNET_LOG(LogError, "EventArray::Wait error! No events were set, but select() returned a positive value!");
 	return WaitFailed;
 }
 

+ 12 - 8
Source/ThirdParty/kNet/src/unix/UnixThread.cpp

@@ -15,6 +15,8 @@
 /** @file UnixThread.cpp
 	@brief */
 
+#ifdef KNET_UNIX
+
 #include <cassert>
 #include <exception>
 
@@ -72,7 +74,7 @@ void Thread::Stop()
 	pthread_join(thread, 0);
 	thread = 0;
 
-	LOG(LogInfo, "Thread::Stop() called.");
+	KNET_LOG(LogInfo, "Thread::Stop() called.");
 
 	delete invoker;
 	invoker = 0;
@@ -84,12 +86,12 @@ void Thread::Stop()
 
 void* ThreadEntryPoint(void* data)
 {
-	LOG(LogInfo, "ThreadEntryPoint: Thread started with param 0x%p.", data);
+	KNET_LOG(LogInfo, "ThreadEntryPoint: Thread started with param 0x%p.", data);
 
 	Thread *thread = reinterpret_cast<Thread*>(data);
 	if (!thread)
 	{
-		LOG(LogError, "Invalid thread start parameter 0!");
+		KNET_LOG(LogError, "Invalid thread start parameter 0!");
 		return 0;
 	}
 	thread->_ThreadRun();
@@ -103,20 +105,20 @@ void Thread::_ThreadRun()
 	{
 		if (!threadEnabled)
 		{
-			LOG(LogError, "ThreadEntryPoint: Thread immediately requested to quit.");
+			KNET_LOG(LogError, "ThreadEntryPoint: Thread immediately requested to quit.");
 			return;
 		}
 
 		invoker->Invoke();
 	} catch(NetException &e)
 	{
-		LOG(LogError, "NetException thrown in thread: %s.", e.what());
+		KNET_LOG(LogError, "NetException thrown in thread: %s.", e.what());
 	} catch(std::exception &e)
 	{
-		LOG(LogError, "std::exception thrown in thread: %s.", e.what());
+		KNET_LOG(LogError, "std::exception thrown in thread: %s.", e.what());
 	} catch(...)
 	{
-		LOG(LogError, "Unknown exception thrown in thread.");
+		KNET_LOG(LogError, "Unknown exception thrown in thread.");
 	}
 }
 
@@ -136,7 +138,7 @@ void Thread::StartThread()
 	if (pthread_create(&thread, &type, ThreadEntryPoint, this))
 		throw NetException("Failed to create thread!");
 	else
-		LOG(LogInfo, "Thread::Run(): Thread created.");
+		KNET_LOG(LogInfo, "Thread::Run(): Thread created.");
 
     SetName("kNet Thread");
 }
@@ -163,3 +165,5 @@ ThreadId Thread::NullThreadId()
 }
 
 } // ~kNet
+
+#endif // ~KNET_UNIX

+ 6 - 3
Source/ThirdParty/kNet/src/win32/W32Event.cpp

@@ -14,6 +14,7 @@
 
 /** @file W32Event.cpp
 	@brief */
+#ifdef WIN32
 
 #include <cassert>
 
@@ -26,7 +27,7 @@ namespace kNet
 {
 
 Event::Event()
-:wsaEvent(NULL)
+:wsaEvent(NULL), type(EventWaitInvalid)
 {
 }
 
@@ -63,7 +64,7 @@ bool Event::IsNull() const
 void Event::Reset()
 {
 	if (wsaEvent == NULL)
-		LOG(LogError, "Event::Reset called on a null event!");
+		KNET_LOG(LogError, "Event::Reset called on a null event!");
 	else
 		WSAResetEvent(wsaEvent);
 }
@@ -71,7 +72,7 @@ void Event::Reset()
 void Event::Set()
 {
 	if (wsaEvent == NULL)
-		LOG(LogError, "Event::Set called on a null event!");
+		KNET_LOG(LogError, "Event::Set called on a null event!");
 	else
 		WSASetEvent(wsaEvent);
 }
@@ -101,3 +102,5 @@ bool Event::IsValid() const
 }
 
 } // ~kNet
+
+#endif // ~WIN32

+ 4 - 4
Source/ThirdParty/kNet/src/win32/W32EventArray.cpp

@@ -44,12 +44,12 @@ void EventArray::AddEvent(const Event &e)
 {
 	if (e.IsNull())
 	{
-		LOG(LogError, "EventArray::AddEvent: Error! Tried to add a null event to event array at index %d!", numAdded);
+		KNET_LOG(LogError, "EventArray::AddEvent: Error! Tried to add a null event to event array at index %d!", numAdded);
 		return;
 	}
 	if (numAdded >= maxEvents)
 	{
-		LOG(LogError, "EventArray::AddEvent: Error! Tried to add too many events to event array! (max: %d)", numAdded);
+		KNET_LOG(LogError, "EventArray::AddEvent: Error! Tried to add too many events to event array! (max: %d)", numAdded);
 		return;
 	}
 	assert(numAdded < maxEvents);
@@ -68,10 +68,10 @@ int EventArray::Wait(int msecs)
 		return WaitTimedOut;
 	else
 	{
-		LOG(LogError, "EventArray::Wait: WSAWaitForMultipleEvents failed with error code %d (WSAGetLastError: %d)!", (int)ret, (int)WSAGetLastError());
+		KNET_LOG(LogError, "EventArray::Wait: WSAWaitForMultipleEvents failed with error code %d (WSAGetLastError: %d)!", (int)ret, (int)WSAGetLastError());
 		for(int i = 0; i < numAdded; ++i)
 			if (WSAWaitForMultipleEvents(1, events+i, FALSE, 0, FALSE) == WSA_WAIT_FAILED)
-				LOG(LogError, "EventArray::Wait: EventArray event at index %d is not valid!", i);
+				KNET_LOG(LogError, "EventArray::Wait: EventArray event at index %d is not valid!", i);
 
 		return WaitFailed;
 	}

+ 14 - 14
Source/ThirdParty/kNet/src/win32/W32Thread.cpp

@@ -18,11 +18,11 @@
 #include <cassert>
 #include <exception>
 
-#include "kNet/Network.h"
 #include "kNet/Thread.h"
 #include "kNet/NetworkLogging.h"
 #include "kNet/Clock.h"
 #include "kNet/NetException.h"
+#include "kNet/Network.h"
 
 #include "kNet/DebugMemoryLeakCheck.h"
 
@@ -55,7 +55,7 @@ bool Thread::IsRunning() const
 
 	if (result == 0)
 	{
-		LOG(LogError, "Warning: Received error %d from GetExitCodeThread in Thread::IsRunning!", GetLastError());
+		KNET_LOG(LogError, "Warning: Received error %d from GetExitCodeThread in Thread::IsRunning!", GetLastError());
 		return false;
 	}
 
@@ -89,7 +89,7 @@ void Thread::Stop()
 
 		if (result == 0)
 		{
-			LOG(LogError, "Warning: Received error %d from GetExitCodeThread in Thread::Stop()!", GetLastError());
+			KNET_LOG(LogError, "Warning: Received error %d from GetExitCodeThread in Thread::Stop()!", GetLastError());
 			break;
 		}
 		else if (exitCode != STILL_ACTIVE)
@@ -103,12 +103,12 @@ void Thread::Stop()
 
 	if (threadHandle != NULL)
 	{
-		TerminateThread(threadHandle, -1);
+		TerminateThread(threadHandle, (DWORD)-1);
 //		CloseHandle(threadHandle);
-		LOG(LogError, "Warning: Had to forcibly terminate thread!");
+		KNET_LOG(LogError, "Warning: Had to forcibly terminate thread!");
 	}
 
-	LOG(LogInfo, "Thread::Stop() called.");
+	KNET_LOG(LogInfo, "Thread::Stop() called.");
 
 	threadHandle = NULL;
 	threadId = 0;
@@ -123,13 +123,13 @@ void Thread::Stop()
 
 DWORD WINAPI ThreadEntryPoint(LPVOID lpParameter)
 {
-	LOG(LogInfo, "ThreadEntryPoint: Thread started with param 0x%08X.", lpParameter);
+	KNET_LOG(LogInfo, "ThreadEntryPoint: Thread started with param 0x%08X.", lpParameter);
 
 	Thread *thread = reinterpret_cast<Thread*>(lpParameter);
 	if (!thread)
 	{
-		LOG(LogError, "Invalid thread start parameter 0!");
-		return -1;
+		KNET_LOG(LogError, "Invalid thread start parameter 0!");
+		return (DWORD)-1;
 	}
 	thread->_ThreadRun();
 
@@ -142,20 +142,20 @@ void Thread::_ThreadRun()
 	{
 		if (!threadEnabled)
 		{
-			LOG(LogError, "ThreadEntryPoint: Thread immediately requested to quit.");
+			KNET_LOG(LogError, "ThreadEntryPoint: Thread immediately requested to quit.");
 			return;
 		}
 
 		invoker->Invoke();
 	} catch(NetException &e)
 	{
-		LOG(LogError, "NetException thrown in thread: %s.", e.what());
+		KNET_LOG(LogError, "NetException thrown in thread: %s.", e.what());
 	} catch(std::exception &e)
 	{
-		LOG(LogError, "std::exception thrown in thread: %s.", e.what());
+		KNET_LOG(LogError, "std::exception thrown in thread: %s.", e.what());
 	} catch(...)
 	{
-		LOG(LogError, "Unknown exception thrown in thread.");
+		KNET_LOG(LogError, "Unknown exception thrown in thread.");
 	}
 }
 
@@ -173,7 +173,7 @@ void Thread::StartThread()
 	if (threadHandle == NULL)
 		throw NetException("Failed to create thread!");
 	else
-		LOG(LogInfo, "Thread::Run(): Thread created.");
+		KNET_LOG(LogInfo, "Thread::Run(): Thread created.");
 
 	SetName("kNet Thread");
 }