Ticket #405: los.patch

File los.patch, 15.9 KB (added by Philip Taylor, 14 years ago)

a patch from telaviv

  • simulation/EntityManager.cpp

     
    3737#include "PathfindEngine.h"
    3838#include "ps/GameSetup/Config.h"
    3939
     40#include <cstdlib>
     41
    4042int AURA_CIRCLE_POINTS;
    4143int SELECTION_CIRCLE_POINTS;
    4244int SELECTION_BOX_POINTS;
     
    336338            results.push_back( m_entities[i].m_entity );
    337339}
    338340
     341// This is a function designed to be used for the next method.
     342int EntityMoveCompare(const void* a, const void* b) {
     343    return ((CEntity*) a)->GetLastMoveTime() - ((CEntity*) b)->GetLastMoveTime();
     344}
     345
     346void 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
    339365void CEntityManager::GetInRange( float x, float z, float radius, std::vector<CEntity*>& results )
    340366{
    341367    results.clear();
  • simulation/Entity.cpp

     
    9999    m_graphics_position = m_position;
    100100    m_graphics_orientation = m_orientation;
    101101    m_actor_transform_valid = false;
     102    m_actor_has_moved = true;
    102103    entf_clear(ENTF_HAS_RALLY_POINT);
    103104
    104105    entf_clear(ENTF_DESTROYED);
     
    113114    m_frameCheck = 0;
    114115    m_lastCombatTime = -100;
    115116    m_lastRunTime = -100;
     117    m_lastMoveTime = -100;
    116118    m_currentNotification = 0;
    117119    m_currentRequest = 0;
    118120    entf_set(ENTF_DESTROY_NOTIFIERS);
     
    10731075        )
    10741076    {                                                           
    10751077        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        }
    10761082    }
    10771083    // Update the actor transform data when necessary.
    10781084    if( !m_actor_transform_valid )
     
    10881094    m_actor_transform_valid = false;
    10891095}
    10901096
     1097bool CEntity::HasMoved()
     1098{
     1099    return m_actor_has_moved;
     1100}
     1101
     1102void CEntity::ResetHasMoved()
     1103{
     1104    m_actor_has_moved = false;
     1105}
     1106
     1107double CEntity::GetLastMoveTime()
     1108{
     1109    return m_lastMoveTime;
     1110}
     1111
     1112CVector3D 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
     1125ssize_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
    10911138float CEntity::GetAnchorLevel( float x, float z )
    10921139{
    10931140    CTerrain *pTerrain = g_Game->GetWorld()->GetTerrain();
  • simulation/LOSManager.cpp

     
    3131#include "lib/allocators/allocators.h"  // matrix_alloc
    3232#include "lib/timer.h"
    3333
     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
    3437
    3538CLOSManager::CLOSManager() : m_LOSSetting(LOS_SETTING_NORMAL), m_FogOfWar(true)
    3639{
    37 #ifdef _2_los
    3840    m_Explored = 0;
    3941    m_Visible  = 0;
    40 #else
    41     m_VisibilityMatrix = 0;
    42 #endif
    4342}
    4443
    4544CLOSManager::~CLOSManager()
    4645{
    47 #ifdef _2_los
    4846    matrix_free((void**)m_Explored);
    4947    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 );
    5152    m_Visible = 0;
    52 #else
    53     matrix_free((void**)m_VisibilityMatrix);
    54     m_VisibilityMatrix = 0;
    55 #endif
    5653}
    5754
    5855void CLOSManager::Initialize(ELOSSetting losSetting, bool fogOfWar)
     
    6461    CTerrain* terrain = g_Game->GetWorld()->GetTerrain();
    6562    m_TilesPerSide = terrain->GetVerticesPerSide() - 1;
    6663    m_TilesPerSide_1 = m_TilesPerSide-1;
     64    // REMOVE!
     65    std::cout << "Total Tiles: " << m_TilesPerSide * m_TilesPerSide << std::endl;
    6766
    68 
    6967    // Create the LOS data arrays
    70 #ifdef _2_los
    7168    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));
    7672
    7773    // TODO: This memory should be freed somewhere when the engine supports
    7874    // multiple sessions without restarting the program.
    7975    // JW: currently free it in the dtor
    8076
    8177    // Set initial values
    82 #ifdef _2_los
    8378    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;
    9280    for(size_t x=0; x<m_TilesPerSide; x++)
    9381    {
    94 #ifdef _2_los
    9582        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));
    10285    }
    10386
    10487    // Just Update() to set the visible array and also mark currently visible tiles as explored.
    10588    // NOTE: this will have to be changed if we decide to use incremental LOS
    106     Update();
     89    InitialUpdate();
    10790}
    10891
    109 // NOTE: this will have to be changed if we decide to use incremental LOS
    110 void CLOSManager::Update()
     92// This is only called in the constructor to set the visibility matrix.
     93void CLOSManager::InitialUpdate()
    11194{
    11295    if(m_LOSSetting == LOS_SETTING_ALL_VISIBLE)
    11396        return;
    11497
    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++)
    118102    {
    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            }
    122127        }
     128        e->ResetHasMoved();
    123129    }
    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}
    135131
     132// NOTE: this will have to be changed if we decide to use incremental LOS
     133void CLOSManager::Update()
     134{
     135    if(m_LOSSetting == LOS_SETTING_ALL_VISIBLE)
     136        return;
     137
    136138    // Set visibility for each entity
    137139    std::vector<CEntity*> extant;
    138     g_EntityManager.GetExtant(extant);
     140    g_EntityManager.GetMovedExtant(extant);
    139141    for(size_t i=0; i<extant.size(); i++)
    140142    {
    141143        CEntity* e = extant[i];
    142144
    143145        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);
    144149        if(los == 0)
    145150            continue;
    146151
    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;
    154153        CTerrain::CalcFromPosition(e->m_position.X, e->m_position.Z, cx, cz);
    155154
    156155        ssize_t minX = std::max(cx-los, ssize_t(0));
     
    158157        ssize_t maxX = std::min(cx+los, ssize_t(m_TilesPerSide_1));
    159158        ssize_t maxZ = std::min(cz+los, ssize_t(m_TilesPerSide_1));
    160159
    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];
    169165                    m_Explored[x][z] |= mask;
    170 #else
    171                     m_VisibilityMatrix[x][z] |= (LOS_EXPLORED|LOS_VISIBLE) << shift;
    172 #endif
    173166                }
    174167            }
    175168        }
     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();
    176184    }
    177185}
    178186
    179 
     187// As far as I know this function along with CPlayer::GetLOSToken are useless and should be removed.
    180188size_t LOS_GetTokenFor(size_t player_id)
    181189{
    182 #ifdef _2_los
    183190    return size_t(1) << player_id;
    184 #else
    185     return player_id*2;
    186 #endif
    187191}
    188192
    189193//TIMER_ADD_CLIENT(tc_getstatus);
     
    199203
    200204    // TODO: Make the mask depend on the player's diplomacy (just OR all his allies' masks)
    201205
    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)
    207208        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)
    211210        return LOS_EXPLORED;
    212     }
    213     else
    214     {
     211    else
    215212        return LOS_UNEXPLORED;
    216     }
    217 #else
    218     const size_t shift = player->GetLOSToken();
    219     return (ELOSStatus)((m_VisibilityMatrix[tx][tz] >> shift) & 3);
    220 #endif
    221213}
    222214
    223215
  • simulation/EntityManager.h

     
    5353// collision patch size, in graphics units, not tiles (1 tile = 4 units)
    5454#define COLLISION_PATCH_SIZE 8
    5555
     56// The max number of entities to be recieved by GetQueuedExtant
     57#define MAX_QUEUED_EXTANT 50
     58
    5659#define g_EntityManager g_Game->GetWorld()->GetEntityManager()
    5760
    5861class CEntityManager
     
    140143    void GetMatchingAsHandles( std::vector<HEntity>& matchlist, EntityPredicate predicate, void* userdata = 0 );
    141144    void GetExtantAsHandles( std::vector<HEntity>& results );
    142145    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 );
    143149    static inline bool IsExtant()   // True if the singleton is actively maintaining handles. When false, system is shutting down, handles are quietly dumped.
    144150    {
    145151        return( m_extant );
  • simulation/Entity.h

     
    160160
    161161    double m_lastCombatTime;
    162162    double m_lastRunTime;
     163    // This represents the last time the field m_actor_has_moved was set to true;
     164    double m_lastMoveTime;
    163165
    164166    // Building to convert to if this is a foundation, or "" otherwise
    165167    CStrW m_building;
     
    181183    // LOS distance/range
    182184    ssize_t m_los;
    183185
     186
    184187    // If the object is a territory centre, this points to its territory
    185188    CTerritory* m_associatedTerritory;
    186189
     
    214217    // moved since it was last calculated, and the terrain hasn't been changed).
    215218    bool m_actor_transform_valid;
    216219
     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
    217227    // Our current collision patch in CEntityManager
    218228    std::vector<CEntity*>* m_collisionPatch;
    219229
     
    290300    // (Necessary when terrain might move underneath the actor.)
    291301    void InvalidateActor();
    292302
     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
    293314    // Updates auras
    294315    void UpdateAuras( int timestep_millis );
    295316
  • simulation/LOSManager.h

     
    3131#ifndef INCLUDED_LOSMANAGER
    3232#define INCLUDED_LOSMANAGER
    3333
     34#include <cstdlib>
     35
    3436class CUnit;
    3537class CEntity;
    3638class CPlayer;
     
    6365
    6466class CLOSManager
    6567{
    66 #ifdef _2_los
     68 protected:
     69
    6770    int** m_Explored;       // (m_Explored[x][z] & (1<<p) says whether player p has explored tile (x,z),
    6871                            // 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).
    7073    // NOTE: This will have to be changed to a 3D array where each element stores the number of units
    7174    // of a certain player that can see a certain tile if we want to use incremental LOS.
    72 #else
    73     u16** m_VisibilityMatrix;
    74 #endif
    7575
    7676    size_t m_TilesPerSide;
    7777    size_t m_TilesPerSide_1;    // as above, -1
     78    // used internally to initially set the visibility matrix.
     79    void InitialUpdate();
    7880
    79 public:
     81 public:
    8082
    8183
    8284    ELOSSetting m_LOSSetting;