Index: components/CCmpRangeManager.cpp
===================================================================
--- components/CCmpRangeManager.cpp	(revision 13451)
+++ components/CCmpRangeManager.cpp	(working copy)
@@ -26,6 +26,7 @@
 #include "simulation2/components/ICmpVision.h"
 #include "simulation2/helpers/Render.h"
 #include "simulation2/helpers/Spatial.h"
+#include "simulation2/helpers/EntityMap.h"
 
 #include "graphics/Overlay.h"
 #include "graphics/Terrain.h"
@@ -149,7 +150,7 @@
  */
 struct EntityDistanceOrdering
 {
-	EntityDistanceOrdering(const std::map<entity_id_t, EntityData>& entities, const CFixedVector2D& source) :
+	EntityDistanceOrdering(const EntityMap<EntityData>& entities, const CFixedVector2D& source) :
 		m_EntityData(entities), m_Source(source)
 	{
 	}
@@ -163,7 +164,7 @@
 		return (vecA.CompareLength(vecB) < 0);
 	}
 
-	const std::map<entity_id_t, EntityData>& m_EntityData;
+	const EntityMap<EntityData>& m_EntityData;
 	CFixedVector2D m_Source;
 
 private:
@@ -210,7 +211,7 @@
 	// Range query state:
 	tag_t m_QueryNext; // next allocated id
 	std::map<tag_t, Query> m_Queries;
-	std::map<entity_id_t, EntityData> m_EntityData;
+	EntityMap<EntityData> m_EntityData;
 	SpatialSubdivision<entity_id_t> m_Subdivision; // spatial index of m_EntityData
 
 	// LOS state:
@@ -284,7 +285,7 @@
 
 		serialize.NumberU32_Unbounded("query next", m_QueryNext);
 		SerializeMap<SerializeU32_Unbounded, SerializeQuery>()(serialize, "queries", m_Queries);
-		SerializeMap<SerializeU32_Unbounded, SerializeEntityData>()(serialize, "entity data", m_EntityData);
+		SerializeEntityMap<SerializeEntityData>()(serialize, "entity data", m_EntityData);
 
 		SerializeMap<SerializeI32_Unbounded, SerializeBool>()(serialize, "los reveal all", m_LosRevealAll);
 		serialize.Bool("los circular", m_LosCircular);
@@ -355,7 +356,7 @@
 			const CMessagePositionChanged& msgData = static_cast<const CMessagePositionChanged&> (msg);
 			entity_id_t ent = msgData.entity;
 
-			std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
+			EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
 
 			// Ignore if we're not already tracking this entity
 			if (it == m_EntityData.end())
@@ -402,7 +403,7 @@
 			const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg);
 			entity_id_t ent = msgData.entity;
 
-			std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
+			EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
 
 			// Ignore if we're not already tracking this entity
 			if (it == m_EntityData.end())
@@ -425,7 +426,7 @@
 			const CMessageDestroy& msgData = static_cast<const CMessageDestroy&> (msg);
 			entity_id_t ent = msgData.entity;
 
-			std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
+			EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
 
 			// Ignore if we're not already tracking this entity
 			if (it == m_EntityData.end())
@@ -447,7 +448,7 @@
 			const CMessageVisionRangeChanged& msgData = static_cast<const CMessageVisionRangeChanged&> (msg);
 			entity_id_t ent = msgData.entity;
 
-			std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
+			EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
 
 			// Ignore if we're not already tracking this entity
 			if (it == m_EntityData.end())
@@ -555,7 +556,7 @@
 		m_LosStateRevealed.clear();
 		m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide);
 
-		for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
+		for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
 		{
 			if (it->second.inWorld)
 				LosAdd(it->second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z));
@@ -572,7 +573,7 @@
 		// (TODO: find the optimal number instead of blindly guessing)
 		m_Subdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE));
 
-		for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
+		for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
 		{
 			if (it->second.inWorld)
 				m_Subdivision.Add(it->first, CFixedVector2D(it->second.x, it->second.z));
@@ -693,7 +694,7 @@
 
 		u32 ownerMask = CalcOwnerMask(player);
 
-		for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
+		for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
 		{
 			// Check owner and add to list if it matches
 			if (CalcOwnerMask(it->second.owner) & ownerMask)
@@ -804,7 +805,7 @@
 		// Special case: range -1.0 means check all entities ignoring distance
 		if (q.maxRange == entity_pos_t::FromInt(-1))
 		{
-			for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
+			for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)
 			{
 				if (!TestEntityQuery(q, it->first, it->second))
 					continue;
@@ -819,7 +820,7 @@
 
 			for (size_t i = 0; i < ents.size(); ++i)
 			{
-				std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.find(ents[i]);
+				EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);
 				ENSURE(it != m_EntityData.end());
 
 				if (!TestEntityQuery(q, it->first, it->second))
@@ -945,7 +946,7 @@
 	
 	virtual void SetEntityFlag(entity_id_t ent, std::string identifier, bool value)
 	{
-		std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);
+		EntityMap<EntityData>::iterator it = m_EntityData.find(ent);
 
 		// We don't have this entity
 		if (it == m_EntityData.end())
Index: helpers/EntityMap.h
===================================================================
--- helpers/EntityMap.h	(revision 0)
+++ helpers/EntityMap.h	(working copy)
@@ -0,0 +1,163 @@
+#ifndef INCLUDED_ENTITYMAP
+#define INCLUDED_ENTITYMAP
+
+#ifndef NDEBUG
+#define ENTITYMAP_INSERTION_CHECK
+#endif
+
+/**
+ * A fast replacement for map<entity_id_t, T>.
+ * We make the following assumptions:
+ *  - entity id's (keys) are unique and are inserted in increasing order
+ *  - an entity id that was removed is never added again
+ *  - modifications (add / delete) are far less frequent then look-ups
+ *  - preformance for iteration is important
+ */
+template<typename T>
+class EntityMap
+{
+
+public:
+	EntityMap() : m_Data(), m_Lookup()
+	{
+	}
+
+	EntityMap(const EntityMap& m) : m_Data(m.m_Data), m_Lookup(m.m_Lookup)
+	{
+	}
+
+	// Map interface:
+	// Member types
+	typedef entity_id_t key_type;
+	typedef T mapped_type;
+	typedef std::pair<entity_id_t, T> value_type;
+
+	typedef typename std::vector<value_type>::difference_type difference_type;
+	typedef typename std::vector<value_type>::size_type size_type;
+
+	typedef typename std::vector<value_type>::iterator iterator;
+	typedef typename std::vector<value_type>::const_iterator const_iterator;
+	typedef typename std::vector<value_type>::reverse_iterator reverse_iterator;
+	typedef typename std::vector<value_type>::const_reverse_iterator const_reverse_iterator;
+
+	// Iterators
+	iterator begin()
+	{ return m_Data.begin(); }
+	
+	const_iterator begin() const
+	{ return m_Data.begin(); }
+
+	iterator end()
+	{ return m_Data.end(); }
+	
+	const_iterator end() const
+	{ return m_Data.end(); }
+
+	reverse_iterator rbegin()
+	{ return m_Data.rbegin(); }
+
+	const_reverse_iterator rbegin() const
+	{ return m_Data.rbegin(); }
+
+	reverse_iterator rend()
+	{ return m_Data.rend(); }
+	
+	const_reverse_iterator rend() const
+	{ return m_Data.rend(); }
+
+	// Capacity
+	bool empty() const
+	{ return m_Data.empty(); }
+	
+	size_type size() const
+	{ return m_Data.size(); }
+	
+	size_type max_size() const
+	{ return std::min<size_type>(m_Data.max_size(), std::numeric_limits<difference_type>::max()); }
+
+	// Modification
+	std::pair<iterator, bool> insert(const value_type& val)
+	{
+#ifdef ENTITYMAP_INSERTION_CHECK
+		ENSURE(val.first >= size());
+		ENSURE(val.first <= std::numeric_limits<difference_type>::max());
+#endif
+		m_Data.push_back(val);
+		difference_type pos = m_Data.size() - 1;
+		m_Lookup.resize(val.first + 1, -1);
+		m_Lookup[val.first] = pos;
+		return std::make_pair(m_Data.begin() + pos, true);
+	}
+	
+	void erase(iterator it)
+	{
+		// update all lookup indices
+		m_Lookup[it->first] = -1;
+		for(entity_id_t ent = it->first + 1; ent < m_Lookup.size(); ent++)
+		{
+			if (m_Lookup[ent] >= 0) m_Lookup[ent]--;
+		}
+		m_Data.erase(it);
+	}
+	
+	size_type erase(const key_type& key)
+	{
+		size_type count = 0;
+		iterator it = find(key);
+		if (it != end())
+		{
+			erase(it);
+			count = 1;
+		}
+		return count;
+	}
+	
+	void swap(EntityMap &map)
+	{
+		m_Data.swap(map.m_Data);
+		m_Lookup.swap(map.m_Lookup);
+	}
+
+	void clear()
+	{
+		m_Data.clear();
+		m_Lookup.clear();
+	}
+
+	// Operations
+	iterator find(const key_type& key)
+	{
+		if (key < m_Lookup.size())
+		{
+			difference_type pos = m_Lookup[key];
+			if (pos >= 0)
+			{
+				return m_Data.begin() + pos;
+			}
+		}
+		return m_Data.end();
+	}
+
+	const_iterator find(const key_type& key) const
+	{
+		if (key < m_Lookup.size())
+		{
+			difference_type pos = m_Lookup[key];
+			if (pos >= 0)
+			{
+				return m_Data.begin() + pos;
+			}
+		}
+		return m_Data.end();
+	}
+
+	size_type count(const key_type& key) const
+	{ 
+		return find(key) == end() ? 0 : 1;
+	}
+	
+private:
+	std::vector<value_type> m_Data;
+	std::vector<difference_type> m_Lookup;
+};
+#endif
Index: serialization/SerializeTemplates.h
===================================================================
--- serialization/SerializeTemplates.h	(revision 13451)
+++ serialization/SerializeTemplates.h	(working copy)
@@ -24,6 +24,7 @@
  */
 
 #include "simulation2/components/ICmpPathfinder.h"
+#include "simulation2/helpers/EntityMap.h"
 
 template<typename ELEM>
 struct SerializeVector
@@ -87,6 +88,38 @@
 	}
 };
 
+template<typename VS>
+struct SerializeEntityMap
+{
+	template<typename V>
+	void operator()(ISerializer& serialize, const char* UNUSED(name), EntityMap<V>& value)
+	{
+		size_t len = value.size();
+		serialize.NumberU32_Unbounded("length", (u32)len);
+		for (typename EntityMap<V>::iterator it = value.begin(); it != value.end(); ++it)
+		{
+			serialize.NumberU32_Unbounded("key", it->first);
+			VS()(serialize, "value", it->second);
+		}
+	}
+
+	template<typename V>
+	void operator()(IDeserializer& deserialize, const char* UNUSED(name), EntityMap<V>& value)
+	{
+		value.clear();
+		u32 len;
+		deserialize.NumberU32_Unbounded("length", len);
+		for (size_t i = 0; i < len; ++i)
+		{
+			entity_id_t k;
+			deserialize.NumberU32_Unbounded("key", k);
+			V v; 
+			VS()(deserialize, "value", v);
+			value.insert(std::make_pair(k, v));
+		}
+	}
+};
+
 // We have to order the map before serializing to make things consistent
 template<typename KS, typename VS>
 struct SerializeUnorderedMap
