Ticket #405: los.patch
File los.patch, 15.9 KB (added by , 15 years ago) |
---|
-
simulation/EntityManager.cpp
37 37 #include "PathfindEngine.h" 38 38 #include "ps/GameSetup/Config.h" 39 39 40 #include <cstdlib> 41 40 42 int AURA_CIRCLE_POINTS; 41 43 int SELECTION_CIRCLE_POINTS; 42 44 int SELECTION_BOX_POINTS; … … 336 338 results.push_back( m_entities[i].m_entity ); 337 339 } 338 340 341 // This is a function designed to be used for the next method. 342 int EntityMoveCompare(const void* a, const void* b) { 343 return ((CEntity*) a)->GetLastMoveTime() - ((CEntity*) b)->GetLastMoveTime(); 344 } 345 346 void CEntityManager::GetMovedExtant( std::vector<CEntity*>& results, size_t maxEntities ) 347 { 348 results.clear(); 349 CEntity* heap[MAX_HANDLES]; 350 size_t heap_pointer = 0; 351 for( size_t i = 0; i < MAX_HANDLES; i++ ) 352 if( IsEntityRefd(i) && m_entities[i].m_entity->HasMoved() ) 353 heap[heap_pointer++] = m_entities[i].m_entity; 354 qsort( heap, sizeof(CEntity*), heap_pointer, EntityMoveCompare ); 355 // If this is the first update then its ok simply to return all the entities. 356 // This only happens in the load screen, and thats not a time sensitive area. 357 if ( heap_pointer > 0 && heap[0]->GetLastMoveTime() == -100 ) 358 for ( size_t i = 0; i < heap_pointer; ++i ) 359 results.push_back( heap[i] ); 360 else 361 for (size_t i = 0; i < maxEntities && i < heap_pointer; ++i ) 362 results.push_back( heap[i] ); 363 } 364 339 365 void CEntityManager::GetInRange( float x, float z, float radius, std::vector<CEntity*>& results ) 340 366 { 341 367 results.clear(); -
simulation/Entity.cpp
99 99 m_graphics_position = m_position; 100 100 m_graphics_orientation = m_orientation; 101 101 m_actor_transform_valid = false; 102 m_actor_has_moved = true; 102 103 entf_clear(ENTF_HAS_RALLY_POINT); 103 104 104 105 entf_clear(ENTF_DESTROYED); … … 113 114 m_frameCheck = 0; 114 115 m_lastCombatTime = -100; 115 116 m_lastRunTime = -100; 117 m_lastMoveTime = -100; 116 118 m_currentNotification = 0; 117 119 m_currentRequest = 0; 118 120 entf_set(ENTF_DESTROY_NOTIFIERS); … … 1073 1075 ) 1074 1076 { 1075 1077 m_actor_transform_valid = false; 1078 if( !m_actor_has_moved ) { 1079 m_actor_has_moved = true; 1080 m_lastMoveTime = g_Game->GetSimulation()->GetTime(); 1081 } 1076 1082 } 1077 1083 // Update the actor transform data when necessary. 1078 1084 if( !m_actor_transform_valid ) … … 1088 1094 m_actor_transform_valid = false; 1089 1095 } 1090 1096 1097 bool CEntity::HasMoved() 1098 { 1099 return m_actor_has_moved; 1100 } 1101 1102 void CEntity::ResetHasMoved() 1103 { 1104 m_actor_has_moved = false; 1105 } 1106 1107 double CEntity::GetLastMoveTime() 1108 { 1109 return m_lastMoveTime; 1110 } 1111 1112 CVector3D CEntity::GetLastPosition() 1113 { 1114 // if the entity has never moved then its probably safter to get the current position. 1115 if ( m_lastMoveTime == -100) { 1116 m_last_position = m_position; 1117 return m_last_position; 1118 } else { 1119 CVector3D temp = m_last_position; 1120 m_last_position = m_position; 1121 return temp; 1122 } 1123 } 1124 1125 ssize_t CEntity::GetLastLOS() 1126 { 1127 // if the entity has never moved then its probably safter to get the current los. 1128 if ( m_lastMoveTime == -100) { 1129 m_last_los = m_los; 1130 return m_last_los; 1131 } else { 1132 ssize_t temp = m_last_los; 1133 m_last_los = m_los; 1134 return temp; 1135 } 1136 } 1137 1091 1138 float CEntity::GetAnchorLevel( float x, float z ) 1092 1139 { 1093 1140 CTerrain *pTerrain = g_Game->GetWorld()->GetTerrain(); -
simulation/LOSManager.cpp
31 31 #include "lib/allocators/allocators.h" // matrix_alloc 32 32 #include "lib/timer.h" 33 33 34 // rather than using a single constant representing the max_players, to save memory we should 35 // only allocate as much memory as there are players. this works for now however. 36 #define MAX_PLAYERS 32 34 37 35 38 CLOSManager::CLOSManager() : m_LOSSetting(LOS_SETTING_NORMAL), m_FogOfWar(true) 36 39 { 37 #ifdef _2_los38 40 m_Explored = 0; 39 41 m_Visible = 0; 40 #else41 m_VisibilityMatrix = 0;42 #endif43 42 } 44 43 45 44 CLOSManager::~CLOSManager() 46 45 { 47 #ifdef _2_los48 46 matrix_free((void**)m_Explored); 49 47 m_Explored = 0; 50 matrix_free((void**)m_Visible); 48 49 for ( int i = 0; i < MAX_PLAYERS; ++i ) 50 matrix_free((void**)m_Visible[i]); 51 free( m_Visible ); 51 52 m_Visible = 0; 52 #else53 matrix_free((void**)m_VisibilityMatrix);54 m_VisibilityMatrix = 0;55 #endif56 53 } 57 54 58 55 void CLOSManager::Initialize(ELOSSetting losSetting, bool fogOfWar) … … 64 61 CTerrain* terrain = g_Game->GetWorld()->GetTerrain(); 65 62 m_TilesPerSide = terrain->GetVerticesPerSide() - 1; 66 63 m_TilesPerSide_1 = m_TilesPerSide-1; 64 // REMOVE! 65 std::cout << "Total Tiles: " << m_TilesPerSide * m_TilesPerSide << std::endl; 67 66 68 69 67 // Create the LOS data arrays 70 #ifdef _2_los71 68 m_Explored = (int**)matrix_alloc(m_TilesPerSide, m_TilesPerSide, sizeof(int)); 72 m_Visible = (int**)matrix_alloc(m_TilesPerSide, m_TilesPerSide, sizeof(int)); 73 #else 74 m_VisibilityMatrix = (u16**)matrix_alloc(m_TilesPerSide, m_TilesPerSide, sizeof(u16)); 75 #endif 69 m_Visible = (int16_t***)malloc( sizeof(int16_t**) * MAX_PLAYERS ); 70 for ( int i = 0; i < MAX_PLAYERS; ++i ) 71 m_Visible[i] = (int16_t**)matrix_alloc(m_TilesPerSide, m_TilesPerSide, sizeof(int16_t)); 76 72 77 73 // TODO: This memory should be freed somewhere when the engine supports 78 74 // multiple sessions without restarting the program. 79 75 // JW: currently free it in the dtor 80 76 81 77 // Set initial values 82 #ifdef _2_los83 78 int explored_value = (m_LOSSetting == LOS_SETTING_EXPLORED || m_LOSSetting == LOS_SETTING_ALL_VISIBLE)? 0xFF : 0; 84 int vis_value = (m_LOSSetting == LOS_SETTING_ALL_VISIBLE)? 0xFF : 0; 85 #else 86 u16 vis_value = 0; 87 if(m_LOSSetting == LOS_SETTING_EXPLORED || m_LOSSetting == LOS_SETTING_ALL_VISIBLE) 88 for(int i = 0; i < 8; i++) vis_value |= LOS_EXPLORED << (i*2); 89 if(m_LOSSetting == LOS_SETTING_ALL_VISIBLE || (m_LOSSetting == LOS_SETTING_EXPLORED && !m_FogOfWar) ) 90 for(int i = 0; i < 8; i++) vis_value |= LOS_VISIBLE << (i*2); 91 #endif 79 int vis_value = (m_LOSSetting == LOS_SETTING_ALL_VISIBLE)? 1 : 0; 92 80 for(size_t x=0; x<m_TilesPerSide; x++) 93 81 { 94 #ifdef _2_los95 82 memset(m_Explored[x], explored_value, m_TilesPerSide*sizeof(int)); 96 memset(m_Visible [x], vis_value , m_TilesPerSide*sizeof(int)); 97 #else 98 for(size_t y=0; y<m_TilesPerSide; y++) 99 for(size_t x=0; x<m_TilesPerSide; x++) 100 m_VisibilityMatrix[y][x] = vis_value; 101 #endif 83 for (size_t p = 0; p < MAX_PLAYERS; ++p) 84 memset(m_Visible[p][x], vis_value, m_TilesPerSide*sizeof(int16_t)); 102 85 } 103 86 104 87 // Just Update() to set the visible array and also mark currently visible tiles as explored. 105 88 // NOTE: this will have to be changed if we decide to use incremental LOS 106 Update();89 InitialUpdate(); 107 90 } 108 91 109 // NOTE: this will have to be changed if we decide to use incremental LOS110 void CLOSManager:: Update()92 // This is only called in the constructor to set the visibility matrix. 93 void CLOSManager::InitialUpdate() 111 94 { 112 95 if(m_LOSSetting == LOS_SETTING_ALL_VISIBLE) 113 96 return; 114 97 115 // Clear the visible array 116 #ifdef _2_los 117 if( m_FogOfWar ) 98 // Set visibility for each entity 99 std::vector<CEntity*> extant; 100 g_EntityManager.GetMovedExtant(extant); 101 for(size_t i=0; i<extant.size(); i++) 118 102 { 119 for(int x=0; x<m_TilesPerSide; x++) 120 { 121 memset(m_Visible[x], 0, m_TilesPerSide*sizeof(int)); 103 CEntity* e = extant[i]; 104 105 ssize_t los = e->GetLastLOS(); 106 size_t player_id = e->GetPlayer()->GetPlayerID(); 107 int mask = (1 << player_id); 108 if(los == 0) 109 continue; 110 111 ssize_t cx, cz; 112 CTerrain::CalcFromPosition(e->GetLastPosition().X, e->GetLastPosition().Z, cx, cz); 113 114 ssize_t minX = std::max(cx-los, ssize_t(0)); 115 ssize_t minZ = std::max(cz-los, ssize_t(0)); 116 ssize_t maxX = std::min(cx+los, ssize_t(m_TilesPerSide_1)); 117 ssize_t maxZ = std::min(cz+los, ssize_t(m_TilesPerSide_1)); 118 119 //Set the visibility for the current entities. 120 for(ssize_t x=minX; x<=maxX; x++) { 121 for(ssize_t z=minZ; z<=maxZ; z++) { 122 if((x-cx)*(x-cx) + (z-cz)*(z-cz) <= los*los) { 123 ++m_Visible[player_id][x][z]; 124 m_Explored[x][z] |= mask; 125 } 126 } 122 127 } 128 e->ResetHasMoved(); 123 129 } 124 #else 125 if( m_FogOfWar ) 126 { 127 u16 not_all_vis = 0xFFFF; 128 for(int i = 0; i < 8; i++) 129 not_all_vis &= ~(LOS_VISIBLE << (i*2)); 130 for(size_t y=0; y<m_TilesPerSide; y++) 131 for(size_t x=0; x<m_TilesPerSide; x++) 132 m_VisibilityMatrix[y][x] &= not_all_vis; 133 } 134 #endif 130 } 135 131 132 // NOTE: this will have to be changed if we decide to use incremental LOS 133 void CLOSManager::Update() 134 { 135 if(m_LOSSetting == LOS_SETTING_ALL_VISIBLE) 136 return; 137 136 138 // Set visibility for each entity 137 139 std::vector<CEntity*> extant; 138 g_EntityManager.Get Extant(extant);140 g_EntityManager.GetMovedExtant(extant); 139 141 for(size_t i=0; i<extant.size(); i++) 140 142 { 141 143 CEntity* e = extant[i]; 142 144 143 145 ssize_t los = e->m_los; 146 ssize_t llos = e->GetLastLOS(); 147 size_t player_id = e->GetPlayer()->GetPlayerID(); 148 int mask = (1 << player_id); 144 149 if(los == 0) 145 150 continue; 146 151 147 #ifdef _2_los 148 size_t mask = (size_t(1) << e->GetPlayer()->GetPlayerID()); 149 #else 150 size_t shift = e->GetPlayer()->GetPlayerID()*2; 151 #endif 152 153 ssize_t cx, cz; 152 ssize_t cx, cz; 154 153 CTerrain::CalcFromPosition(e->m_position.X, e->m_position.Z, cx, cz); 155 154 156 155 ssize_t minX = std::max(cx-los, ssize_t(0)); … … 158 157 ssize_t maxX = std::min(cx+los, ssize_t(m_TilesPerSide_1)); 159 158 ssize_t maxZ = std::min(cz+los, ssize_t(m_TilesPerSide_1)); 160 159 161 for(ssize_t x=minX; x<=maxX; x++) 162 { 163 for(ssize_t z=minZ; z<=maxZ; z++) 164 { 165 if((x-cx)*(x-cx) + (z-cz)*(z-cz) <= los*los) 166 { 167 #ifdef _2_los 168 m_Visible[x][z] |= mask; 160 // First the reference count is increased for each new visible square. 161 for(ssize_t x=minX; x<=maxX; x++) { 162 for(ssize_t z=minZ; z<=maxZ; z++) { 163 if((x-cx)*(x-cx) + (z-cz)*(z-cz) <= los*los) { 164 ++m_Visible[player_id][x][z]; 169 165 m_Explored[x][z] |= mask; 170 #else171 m_VisibilityMatrix[x][z] |= (LOS_EXPLORED|LOS_VISIBLE) << shift;172 #endif173 166 } 174 167 } 175 168 } 169 170 ssize_t lcx, lcz; 171 CTerrain::CalcFromPosition(e->GetLastPosition().X, e->GetLastPosition().Z, lcx, lcz); 172 173 minX = std::max(lcx-los, ssize_t(0)); 174 minZ = std::max(lcz-los, ssize_t(0)); 175 maxX = std::min(lcx+los, ssize_t(m_TilesPerSide_1)); 176 maxZ = std::min(lcz+los, ssize_t(m_TilesPerSide_1)); 177 178 // Now the reference count is decremented for every square left. 179 for(ssize_t x=minX; x<=maxX; x++) 180 for(ssize_t z=minZ; z<=maxZ; z++) 181 if((x-lcx)*(x-lcx) + (z-lcz)*(z-lcz) <= llos*llos) 182 --m_Visible[player_id][x][z]; 183 e->ResetHasMoved(); 176 184 } 177 185 } 178 186 179 187 // As far as I know this function along with CPlayer::GetLOSToken are useless and should be removed. 180 188 size_t LOS_GetTokenFor(size_t player_id) 181 189 { 182 #ifdef _2_los183 190 return size_t(1) << player_id; 184 #else185 return player_id*2;186 #endif187 191 } 188 192 189 193 //TIMER_ADD_CLIENT(tc_getstatus); … … 199 203 200 204 // TODO: Make the mask depend on the player's diplomacy (just OR all his allies' masks) 201 205 202 #ifdef _2_los 203 204 const int mask = player->GetLOSToken(); 205 if((m_Visible[tx][tz] & mask) || m_LOSSetting == LOS_SETTING_ALL_VISIBLE) 206 { 206 const int id = player->GetPlayerID(); 207 if(m_Visible[id][tx][tz] || m_LOSSetting == LOS_SETTING_ALL_VISIBLE) 207 208 return LOS_VISIBLE; 208 } 209 else if((m_Explored[tx][tz] & mask) || m_LOSSetting == LOS_SETTING_EXPLORED) 210 { 209 else if((m_Explored[tx][tz] & (1 << id)) || m_LOSSetting == LOS_SETTING_EXPLORED) 211 210 return LOS_EXPLORED; 212 } 213 else 214 { 211 else 215 212 return LOS_UNEXPLORED; 216 }217 #else218 const size_t shift = player->GetLOSToken();219 return (ELOSStatus)((m_VisibilityMatrix[tx][tz] >> shift) & 3);220 #endif221 213 } 222 214 223 215 -
simulation/EntityManager.h
53 53 // collision patch size, in graphics units, not tiles (1 tile = 4 units) 54 54 #define COLLISION_PATCH_SIZE 8 55 55 56 // The max number of entities to be recieved by GetQueuedExtant 57 #define MAX_QUEUED_EXTANT 50 58 56 59 #define g_EntityManager g_Game->GetWorld()->GetEntityManager() 57 60 58 61 class CEntityManager … … 140 143 void GetMatchingAsHandles( std::vector<HEntity>& matchlist, EntityPredicate predicate, void* userdata = 0 ); 141 144 void GetExtantAsHandles( std::vector<HEntity>& results ); 142 145 void GetExtant( std::vector<CEntity*>& results ); 146 147 // returns entities who have been moved since the last update. 148 void GetMovedExtant( std::vector<CEntity*>& results, size_t maxEntities = MAX_QUEUED_EXTANT ); 143 149 static inline bool IsExtant() // True if the singleton is actively maintaining handles. When false, system is shutting down, handles are quietly dumped. 144 150 { 145 151 return( m_extant ); -
simulation/Entity.h
160 160 161 161 double m_lastCombatTime; 162 162 double m_lastRunTime; 163 // This represents the last time the field m_actor_has_moved was set to true; 164 double m_lastMoveTime; 163 165 164 166 // Building to convert to if this is a foundation, or "" otherwise 165 167 CStrW m_building; … … 181 183 // LOS distance/range 182 184 ssize_t m_los; 183 185 186 184 187 // If the object is a territory centre, this points to its territory 185 188 CTerritory* m_associatedTerritory; 186 189 … … 214 217 // moved since it was last calculated, and the terrain hasn't been changed). 215 218 bool m_actor_transform_valid; 216 219 220 // True if the actor has moved. This value can only be reset to false via ResetHasMoved 221 bool m_actor_has_moved; 222 223 // Values saved since the last time ResetHasMoved was called. 224 CVector3D m_last_position; 225 ssize_t m_last_los; 226 217 227 // Our current collision patch in CEntityManager 218 228 std::vector<CEntity*>* m_collisionPatch; 219 229 … … 290 300 // (Necessary when terrain might move underneath the actor.) 291 301 void InvalidateActor(); 292 302 303 // Checks if the player has moved since the last call to ResetHasMoved. 304 bool HasMoved(); 305 // Resets the move state. 306 void ResetHasMoved(); 307 // Gets the time of movement during last movement since the call to ResetHasMoved. 308 double GetLastMoveTime(); 309 // Gets the position since the last call to GetLastPosition. 310 CVector3D GetLastPosition(); 311 // Gets the los since the last call to GetLastLOS. 312 ssize_t GetLastLOS(); 313 293 314 // Updates auras 294 315 void UpdateAuras( int timestep_millis ); 295 316 -
simulation/LOSManager.h
31 31 #ifndef INCLUDED_LOSMANAGER 32 32 #define INCLUDED_LOSMANAGER 33 33 34 #include <cstdlib> 35 34 36 class CUnit; 35 37 class CEntity; 36 38 class CPlayer; … … 63 65 64 66 class CLOSManager 65 67 { 66 #ifdef _2_los 68 protected: 69 67 70 int** m_Explored; // (m_Explored[x][z] & (1<<p) says whether player p has explored tile (x,z), 68 71 // i.e. has removed Shroud of Darkness from it. 69 int ** m_Visible; // (m_Visible[x][z] & (1<<p)) says whether player p currently sees tile (x,z).72 int16_t*** m_Visible; // (m_Visible[p][x][z]) says whether player p currently sees tile (x,z). 70 73 // NOTE: This will have to be changed to a 3D array where each element stores the number of units 71 74 // of a certain player that can see a certain tile if we want to use incremental LOS. 72 #else73 u16** m_VisibilityMatrix;74 #endif75 75 76 76 size_t m_TilesPerSide; 77 77 size_t m_TilesPerSide_1; // as above, -1 78 // used internally to initially set the visibility matrix. 79 void InitialUpdate(); 78 80 79 public:81 public: 80 82 81 83 82 84 ELOSSetting m_LOSSetting;