Ticket #599: proxywip.patch

File proxywip.patch, 29.5 KB (added by Josh Matthews, 12 years ago)

WIP patch

  • binaries/data/mods/public/simulation/components/Foundation.js

    diff --git a/binaries/data/mods/public/simulation/components/Foundation.js b/binaries/data/mods/public/simulation/components/Foundation.js
    index 14029da..a5df7a8 100644
    a b Foundation.prototype.IsFinished = function()  
    5656    return (this.buildProgress >= 1.0);
    5757};
    5858
     59Foundation.prototype.OnVisibilityChanged = function(msg)
     60{
     61  if (msg.source != this.entity)
     62      return;
     63  var building = msg.source;
     64  var cmpPosition = Engine.QueryInterface(this.entity, IID_Position);
     65  var cmpBuildingPosition = Engine.QueryInterface(building, IID_Position);
     66  var pos = cmpPosition.GetPosition();
     67  cmpBuildingPosition.JumpTo(pos.x, pos.z);
     68  var rot = cmpPosition.GetRotation();
     69  cmpBuildingPosition.SetYRotation(rot.y);
     70  cmpBuildingPosition.SetXZRotation(rot.x, rot.z);
     71  // TODO: should add a ICmpPosition::CopyFrom() instead of all this
     72 
     73  var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     74  var cmpBuildingOwnership = Engine.QueryInterface(building, IID_Ownership);
     75  cmpBuildingOwnership.SetOwner(cmpOwnership.GetOwner());
     76 
     77  var cmpHealth = Engine.QueryInterface(this.entity, IID_Health);
     78  var cmpBuildingHealth = Engine.QueryInterface(building, IID_Health);
     79  cmpBuildingHealth.SetHitpoints(cmpHealth.GetHitpoints());
     80}
     81
    5982Foundation.prototype.OnDestroy = function()
    6083{
    6184    // Refund a portion of the construction cost, proportional to the amount of build progress remaining
  • binaries/data/mods/public/simulation/components/GuiInterface.js

    diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js
    index 16ee222..1c9513e 100644
    a b GuiInterface.prototype.Init = function()  
    2121    this.rallyPoints = undefined;
    2222    this.notifications = [];
    2323    this.renamedEntities = [];
     24        this.proxiedEntities = {};
    2425};
    2526
    2627/*
    GuiInterface.prototype.GetExtendedSimulationState = function(player)  
    111112
    112113GuiInterface.prototype.GetRenamedEntities = function(player)
    113114{
    114     return this.renamedEntities;
     115        var proxied = this.proxiedEntities[player];
     116        if (!proxied) proxied = [];
     117        return this.renamedEntities.concat(proxied);
    115118};
    116119
    117120GuiInterface.prototype.ClearRenamedEntities = function(player)
    118121{
    119122    this.renamedEntities = [];
     123        this.proxiedEntities[player] = [];
    120124};
    121125
    122126GuiInterface.prototype.GetEntityState = function(player, ent)
    GuiInterface.prototype.OnGlobalEntityRenamed = function(msg)  
    713717    this.renamedEntities.push(msg);
    714718}
    715719
     720GuiInterface.prototype.OnGlobalDestroy = function(msg)
     721{
     722  var cmpVisual = Engine.QueryInterface(msg.entity, IID_Visual);
     723  if (!cmpVisual)
     724    return;
     725  var proxy = cmpVisual.GetProxyOwner();
     726  if (proxy == INVALID_ENTITY)
     727    return;
     728  // FIXME: we could end up flooding the list if there are lots of proxies coming into view
     729  //        at the same time, since we don't have a way of checking the target player
     730  this.renamedEntities.push({"type": "EntityRenamed", "entity": msg.entity, "newentity": proxy});
     731}
     732
     733GuiInterface.prototype.OnGlobalVisibilityChanged = function(msg)
     734{
     735    if (msg.source != INVALID_ENTITY)
     736        this.proxiedEntities[msg.player].push({"type": "EntityRenamed", "entity": msg.source, "newentity": msg.proxy});
     737}
     738
     739GuiInterface.prototype.GetProxiedEntities = function(player)
     740{
     741    return this.proxiedEntities[player];
     742}
     743
     744GuiInterface.prototype.ClearProxiedEntities = function(player)
     745{
     746    this.proxiedEntities[player] = [];
     747}
     748
    716749// List the GuiInterface functions that can be safely called by GUI scripts.
    717750// (GUI scripts are non-deterministic and untrusted, so these functions must be
    718751// appropriately careful. They are called with a first argument "player", which is
    var exposedFunctions = {  
    742775    "SetPathfinderDebugOverlay": 1,
    743776    "SetObstructionDebugOverlay": 1,
    744777    "SetMotionDebugOverlay": 1,
    745     "SetRangeDebugOverlay": 1,
     778    "SetRangeDebugOverlay": 1
    746779};
    747780
    748781GuiInterface.prototype.ScriptCall = function(player, name, args)
  • binaries/data/mods/public/simulation/components/ResourceSupply.js

    diff --git a/binaries/data/mods/public/simulation/components/ResourceSupply.js b/binaries/data/mods/public/simulation/components/ResourceSupply.js
    index 6dede9f..6a6830c 100644
    a b ResourceSupply.prototype.GetType = function()  
    8282    return { "generic": type, "specific": subtype };
    8383};
    8484
     85ResourceSupply.prototype.OnVisibilityChanged = function(msg)
     86{
     87    if (msg.source != this.entity)
     88        return;
     89    var entity = msg.proxy;
     90    var supply = Engine.QueryInterface(entity, IID_ResourceSupply);
     91    supply.amount = this.amount;
     92    var proxyPosition = Engine.QueryInterface(entity, IID_Position);
     93    var position = Engine.QueryInterface(this.entity, IID_Position);
     94    var pos = position.GetPosition();
     95    proxyPosition.JumpTo(pos.x, pos.z);
     96    var rot = position.GetRotation();
     97    proxyPosition.SetYRotation(rot.y);
     98    proxyPosition.SetXZRotation(rot.x, rot.z);
     99    // TODO: should add a ICmpPosition::CopyFrom() instead of all this
     100
     101    var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership);
     102    var cmpProxyOwnership = Engine.QueryInterface(entity, IID_Ownership);
     103    cmpProxyOwnership.SetOwner(cmpOwnership.GetOwner());
     104}
     105
    85106Engine.RegisterComponentType(IID_ResourceSupply, "ResourceSupply", ResourceSupply);
  • binaries/data/mods/public/simulation/components/UnitAI.js

    diff --git a/binaries/data/mods/public/simulation/components/UnitAI.js b/binaries/data/mods/public/simulation/components/UnitAI.js
    index 515707a..979ff58 100644
    a b var UnitFsmSpec = {  
    790790        },
    791791
    792792        "GATHER": {
     793            "EntityRenamed": function(msg) {
     794                if (this.order.data.target == msg.entity)
     795                    this.order.data.target = msg.newentity;
     796            },
     797
    793798            "APPROACHING": {
    794799                "enter": function() {
    795800                    this.SelectAnimation("move");
    UnitAI.prototype.OnDestroy = function()  
    14541459        rangeMan.DestroyActiveQuery(this.losRangeQuery);
    14551460};
    14561461
     1462UnitAI.prototype.OnGlobalDestroy = function(msg)
     1463{
     1464    var cmpVisual = Engine.QueryInterface(msg.entity, IID_Visual);
     1465    if (!cmpVisual)
     1466        return;
     1467    var proxy = cmpVisual.GetProxyOwner();
     1468    if (proxy == INVALID_ENTITY)
     1469        return;
     1470    this.OnGlobalEntityRenamed({entity: msg.entity, newentity: proxy});
     1471}
     1472
    14571473// Set up a range query for all enemy units within LOS range
    14581474// which can be attacked.
    14591475// This should be called whenever our ownership changes.
    UnitAI.prototype.OnGlobalEntityRenamed = function(msg)  
    16991715    UnitFsm.ProcessMessage(this, {"type": "EntityRenamed", "entity": msg.entity, "newentity": msg.newentity});
    17001716}
    17011717
     1718UnitAI.prototype.OnGlobalVisibilityChanged = function(msg)
     1719{
     1720    if (msg.source == INVALID_ENTITY)
     1721        return;
     1722    var cmpVisual = Engine.QueryInterface(msg.proxy, IID_Visual);
     1723    var cmpOwner = Engine.QueryInterface(this.entity, IID_Ownership);
     1724    if (cmpVisual.GetProxyPlayerTarget() == cmpOwner.GetOwner())
     1725        this.OnGlobalEntityRenamed({entity: msg.source, newentity: msg.proxy});
     1726}
     1727
    17021728UnitAI.prototype.OnAttacked = function(msg)
    17031729{
    17041730    UnitFsm.ProcessMessage(this, {"type": "Attacked", "data": msg});
  • source/network/NetTurnManager.cpp

    diff --git a/source/network/NetTurnManager.cpp b/source/network/NetTurnManager.cpp
    index e80ae74..128b374 100644
    a b  
    3232#include "ps/SavedGame.h"
    3333#include "scriptinterface/ScriptInterface.h"
    3434#include "simulation2/Simulation2.h"
     35#include "simulation2/system/SimContext.h"
    3536
    3637#include <sstream>
    3738#include <fstream>
    void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash)  
    232233    bool ok = m_Simulation2.ComputeStateHash(hash, quick);
    233234    ENSURE(ok);
    234235
    235     OsPath path = psLogDir()/"oos_dump.txt";
     236    std::stringstream fname;
     237    fname << "oos_dump_" << m_Simulation2.GetSimContext().GetCurrentDisplayedPlayer() << ".txt";
     238    OsPath path = psLogDir()/fname.str();
    236239    std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc);
    237240    m_Simulation2.DumpDebugState(file);
    238241    file.close();
  • source/simulation2/MessageTypes.h

    diff --git a/source/simulation2/MessageTypes.h b/source/simulation2/MessageTypes.h
    index 7d4eefe..47233a3 100644
    a b  
    2323#include "simulation2/system/Message.h"
    2424
    2525#include "simulation2/helpers/Position.h"
     26#include "simulation2/helpers/Player.h"
    2627
    2728#include "simulation2/components/ICmpPathfinder.h"
    2829
    public:  
    99100    fixed turnLength;
    100101};
    101102
     103class CMessageUpdate_Visibility : public CMessage
     104{
     105public:
     106    DEFAULT_MESSAGE_IMPL(Update_Visibility)
     107
     108    CMessageUpdate_Visibility()
     109    {
     110    }
     111};
     112
    102113/**
    103114 * Final update phase, after all other updates.
    104115 */
    public:  
    357368    ICmpPathfinder::Path path;
    358369};
    359370
     371class CMessageVisibilityChanged : public CMessage
     372{
     373public:
     374    DEFAULT_MESSAGE_IMPL(VisibilityChanged)
     375
     376    CMessageVisibilityChanged(entity_id_t source, entity_id_t proxy, player_id_t player) :
     377        source(source), proxy(proxy), player(player)
     378    {
     379    }
     380
     381    CMessageVisibilityChanged() :
     382        source(INVALID_ENTITY), proxy(INVALID_ENTITY), player(INVALID_PLAYER)
     383    {
     384    }
     385
     386    entity_id_t source, proxy;
     387    player_id_t player;
     388};
     389
    360390#endif // INCLUDED_MESSAGETYPES
  • source/simulation2/Simulation2.cpp

    diff --git a/source/simulation2/Simulation2.cpp b/source/simulation2/Simulation2.cpp
    index 5586805..b1562bc 100644
    a b void CSimulation2Impl::UpdateComponents(CSimContext& simContext, fixed turnLengt  
    499499        CMessageUpdate_MotionUnit msgUpdate(turnLengthFixed);
    500500        componentManager.BroadcastMessage(msgUpdate);
    501501    }
     502    {
     503        CMessageUpdate_Visibility msgUpdate;
     504        componentManager.BroadcastMessage(msgUpdate);
     505    }
    502506    {
    503507        CMessageUpdate_Final msgUpdate(turnLengthFixed);
    504508        componentManager.BroadcastMessage(msgUpdate);
  • source/simulation2/TypeList.h

    diff --git a/source/simulation2/TypeList.h b/source/simulation2/TypeList.h
    index 696d2e0..fee3182 100644
    a b MESSAGE(TurnStart)  
    3434MESSAGE(Update)
    3535MESSAGE(Update_MotionFormation)
    3636MESSAGE(Update_MotionUnit)
     37MESSAGE(Update_Visibility)
    3738MESSAGE(Update_Final)
    3839MESSAGE(Interpolate) // non-deterministic (use with caution)
    3940MESSAGE(RenderSubmit) // non-deterministic (use with caution)
    MESSAGE(RangeUpdate)  
    4748MESSAGE(TerrainChanged)
    4849MESSAGE(TerritoriesChanged)
    4950MESSAGE(PathResult)
     51MESSAGE(VisibilityChanged)
    5052
    5153// TemplateManager must come before all other (non-test) components,
    5254// so that it is the first to be (de)serialized
  • source/simulation2/components/CCmpRangeManager.cpp

    diff --git a/source/simulation2/components/CCmpRangeManager.cpp b/source/simulation2/components/CCmpRangeManager.cpp
    index e9c275b..c003768 100644
    a b  
    1818#include "precompiled.h"
    1919
    2020#include "simulation2/system/Component.h"
     21#include "simulation2/Simulation2.h"
    2122#include "ICmpRangeManager.h"
    2223
    2324#include "simulation2/MessageTypes.h"
    2425#include "simulation2/components/ICmpPosition.h"
    2526#include "simulation2/components/ICmpTerritoryManager.h"
    2627#include "simulation2/components/ICmpVision.h"
     28#include "simulation2/components/ICmpVisual.h"
    2729#include "simulation2/helpers/Render.h"
    2830#include "simulation2/helpers/Spatial.h"
    2931
     
    3436#include "ps/CLogger.h"
    3537#include "ps/Overlay.h"
    3638#include "ps/Profile.h"
     39#include "ps/Game.h"
    3740#include "renderer/Scene.h"
    3841
    3942#define DEBUG_RANGE_MANAGER_BOUNDS 0
    public:  
    164167        componentManager.SubscribeGloballyToMessageType(MT_Destroy);
    165168
    166169        componentManager.SubscribeToMessageType(MT_Update);
     170        componentManager.SubscribeToMessageType(MT_Update_Visibility);
    167171
    168172        componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays
    169173    }
    public:  
    186190    std::map<entity_id_t, EntityData> m_EntityData;
    187191    SpatialSubdivision<entity_id_t> m_Subdivision; // spatial index of m_EntityData
    188192
     193  std::set<entity_id_t> m_DirtyVisibility;
    189194    // LOS state:
    190195
    191196    std::map<player_id_t, bool> m_LosRevealAll;
    public:  
    413418            ExecuteActiveQueries();
    414419            break;
    415420        }
     421        case MT_Update_Visibility:
     422        {
     423            CMessageVisibilityChanged msg;
     424            for (std::set<entity_id_t>::iterator it = m_DirtyVisibility.begin(); it != m_DirtyVisibility.end(); ++it)
     425            {
     426                g_Game->GetSimulation2()->PostMessage(*it, msg);
     427            }
     428            m_DirtyVisibility.clear();
     429            break;
     430        }
    416431        case MT_RenderSubmit:
    417432        {
    418433            const CMessageRenderSubmit& msgData = static_cast<const CMessageRenderSubmit&> (msg);
    public:  
    876891    {
    877892        // (We can't use m_EntityData since this needs to handle LOCAL entities too)
    878893
     894        CmpPtr<ICmpVisual> cmpVisual(GetSimContext(), ent);
     895        if (!cmpVisual.null())
     896        {
     897          // Proxy entities for other players are never visible
     898          player_id_t target = cmpVisual->GetProxyPlayerTarget();
     899          if (target != INVALID_PLAYER && target != player)
     900            return VIS_HIDDEN;
     901        }
     902
    879903        // Entities not with positions in the world are never visible
    880904        CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), ent);
    881905        if (cmpPosition.null() || !cmpPosition->IsInWorld())
    public:  
    902926        if (los.IsVisible(i, j))
    903927            return VIS_VISIBLE;
    904928
     929        // If a proxy exists, we should never show this actor
     930        if (!cmpVisual.null() && cmpVisual->GetProxyForPlayer(player) != INVALID_ENTITY)
     931        {
     932            return VIS_HIDDEN;
     933        }
     934
    905935        // Fogged if the 'retain in fog' flag is set, and in a non-visible explored region
    906936        if (los.IsExplored(i, j))
    907937        {
    public:  
    9711001                    m_LosState[i+1 + j*m_TerrainVerticesPerSide] |= (LOS_EXPLORED << (2*(p-1)));
    9721002                    m_LosState[i + (j+1)*m_TerrainVerticesPerSide] |= (LOS_EXPLORED << (2*(p-1)));
    9731003                    m_LosState[i+1 + (j+1)*m_TerrainVerticesPerSide] |= (LOS_EXPLORED << (2*(p-1)));
     1004
     1005                    CFixedVector2D start(fixed::FromInt(i*CELL_SIZE), fixed::FromInt(j*CELL_SIZE));
     1006                    CFixedVector2D end(fixed::FromInt((i+1)*CELL_SIZE), fixed::FromInt((j+1)*CELL_SIZE));
     1007                    std::vector<entity_id_t> ents = m_Subdivision.GetInRange(start, end);
     1008                    m_DirtyVisibility.insert(ents.begin(), ents.end());
    9741009                }
    9751010            }
    9761011        }
    public:  
    10251060            {
    10261061                i32 i = i0 + idx - idx0;
    10271062                if (!LosIsOffWorld(i, j))
     1063                {
    10281064                    m_LosState[idx] |= ((LOS_VISIBLE | LOS_EXPLORED) << (2*(owner-1)));
     1065                }
    10291066            }
    10301067
    10311068            ASSERT(counts[idx] < 65535);
    10321069            counts[idx] = (u16)(counts[idx] + 1); // ignore overflow; the player should never have 64K units
    10331070        }
     1071
     1072        CFixedVector2D start(fixed::FromInt(i0*CELL_SIZE), fixed::FromInt(j*CELL_SIZE));
     1073        CFixedVector2D end(fixed::FromInt(i1*CELL_SIZE), fixed::FromInt(j*CELL_SIZE));
     1074        std::vector<entity_id_t> ents = m_Subdivision.GetInRange(start, end);
     1075        m_DirtyVisibility.insert(ents.begin(), ents.end());
    10341076    }
    10351077
    10361078    /**
    public:  
    10541096            {
    10551097                // (If LosIsOffWorld then this is a no-op, so don't bother doing the check)
    10561098                m_LosState[idx] &= ~(LOS_VISIBLE << (2*(owner-1)));
    1057             }
     1099            }
    10581100        }
     1101
     1102        CFixedVector2D start(fixed::FromInt(i0*CELL_SIZE), fixed::FromInt(j*CELL_SIZE));
     1103        CFixedVector2D end(fixed::FromInt(i1*CELL_SIZE), fixed::FromInt(j*CELL_SIZE));
     1104        std::vector<entity_id_t> ents = m_Subdivision.GetInRange(start, end);
     1105        m_DirtyVisibility.insert(ents.begin(), ents.end());
    10591106    }
    10601107
    10611108    /**
  • source/simulation2/components/CCmpUnitMotion.cpp

    diff --git a/source/simulation2/components/CCmpUnitMotion.cpp b/source/simulation2/components/CCmpUnitMotion.cpp
    index 9175d88..7b0c382 100644
    a b bool CCmpUnitMotion::MoveToTargetRange(entity_id_t target, entity_pos_t minRange  
    13111311    CmpPtr<ICmpObstructionManager> cmpObstructionManager(GetSimContext(), SYSTEM_ENTITY);
    13121312    if (cmpObstructionManager.null())
    13131313        return false;
    1314 
    13151314    bool hasObstruction = false;
    13161315    ICmpObstructionManager::ObstructionSquare obstruction;
    13171316    CmpPtr<ICmpObstruction> cmpObstruction(GetSimContext(), target);
  • source/simulation2/components/CCmpVisualActor.cpp

    diff --git a/source/simulation2/components/CCmpVisualActor.cpp b/source/simulation2/components/CCmpVisualActor.cpp
    index 4285666..a73d10c 100644
    a b  
    1717
    1818#include "precompiled.h"
    1919
     20#include <sstream>
     21
     22#include "simulation2/Simulation2.h"
    2023#include "simulation2/system/Component.h"
    2124#include "ICmpVisual.h"
    2225
     
    2427#include "ICmpPosition.h"
    2528#include "ICmpRangeManager.h"
    2629#include "ICmpVision.h"
     30#include "ICmpTemplateManager.h"
    2731#include "simulation2/MessageTypes.h"
    2832#include "simulation2/components/ICmpFootprint.h"
     33#include "simulation2/serialization/SerializeTemplates.h"
    2934
    3035#include "graphics/Frustum.h"
    3136#include "graphics/Model.h"
     
    3742#include "maths/Matrix3D.h"
    3843#include "maths/Vector3D.h"
    3944#include "ps/CLogger.h"
     45#include "ps/Game.h"
    4046#include "renderer/Scene.h"
     47#include "lib/utf8.h"
    4148
    4249class CCmpVisualActor : public ICmpVisual
    4350{
    public:  
    4855        componentManager.SubscribeToMessageType(MT_Interpolate);
    4956        componentManager.SubscribeToMessageType(MT_RenderSubmit);
    5057        componentManager.SubscribeToMessageType(MT_OwnershipChanged);
     58        componentManager.SubscribeToMessageType(MT_VisibilityChanged);
    5159        componentManager.SubscribeGloballyToMessageType(MT_TerrainChanged);
    5260    }
    5361
    public:  
    5967    fixed m_R, m_G, m_B; // shading colour
    6068
    6169    ICmpRangeManager::ELosVisibility m_Visibility; // only valid between Interpolate and RenderSubmit
     70    ICmpRangeManager::ELosVisibility m_LastVisibility;
     71    bool m_FirstVisUpdate;
     72
     73    typedef std::map<player_id_t, entity_id_t> ProxyEntityMap;
     74    ProxyEntityMap m_ProxyEntities;
     75    entity_id_t m_ProxiedEntity;
     76    player_id_t m_ProxyPlayerTarget;
     77
     78    int32_t m_ActorSeed;
    6279
    6380    // Current animation state
    6481    fixed m_AnimRunThreshold; // if non-zero this is the special walk/run mode
    public:  
    138155
    139156        m_R = m_G = m_B = fixed::FromInt(1);
    140157
     158        m_FirstVisUpdate = true;
     159        m_LastVisibility = ICmpRangeManager::VIS_VISIBLE;
     160
     161        m_ProxyPlayerTarget = INVALID_PLAYER;
     162        m_ProxiedEntity = INVALID_ENTITY;
     163
     164        m_ActorSeed = GetEntityId();
     165
    141166        if (!GetSimContext().HasUnitManager())
    142167            return; // do nothing further if graphics are disabled
    143168
    public:  
    148173        else
    149174            m_ActorName = paramNode.GetChild("Actor").ToString();
    150175
    151         std::set<CStr> selections;
    152         m_Unit = GetSimContext().GetUnitManager().CreateUnit(m_ActorName, GetActorSeed(), selections);
    153         if (m_Unit)
     176        ResetUnitSeed(m_ActorSeed);
     177        if (m_Unit)
    154178        {
    155             u32 modelFlags = 0;
    156             if (paramNode.GetChild("SilhouetteDisplay").ToBool())
    157                 modelFlags |= MODELFLAG_SILHOUETTE_DISPLAY;
    158             if (paramNode.GetChild("SilhouetteOccluder").ToBool())
    159                 modelFlags |= MODELFLAG_SILHOUETTE_OCCLUDER;
    160 
    161             CModelAbstract& model = m_Unit->GetModel();
    162             if (model.ToCModel())
    163                 model.ToCModel()->AddFlagsRec(modelFlags);
    164 
    165             // Initialize the model's selection shape descriptor. This currently relies on the component initialization order; the
    166             // Footprint component must be initialized before this component (VisualActor) to support the ability to use the footprint
    167             // shape for the selection box (instead of the default recursive bounding box). See TypeList.h for the order in
    168             // which components are initialized; if for whatever reason you need to get rid of this dependency, you can always just
    169             // initialize the selection shape descriptor on-demand.
    170             InitSelectionShapeDescriptor(model, paramNode);
    171 
    172             m_Unit->SetID(GetEntityId());
     179          u32 modelFlags = 0;
     180          if (paramNode.GetChild("SilhouetteDisplay").ToBool())
     181            modelFlags |= MODELFLAG_SILHOUETTE_DISPLAY;
     182          if (paramNode.GetChild("SilhouetteOccluder").ToBool())
     183            modelFlags |= MODELFLAG_SILHOUETTE_OCCLUDER;
     184
     185          CModelAbstract& model = m_Unit->GetModel();
     186          if (model.ToCModel())
     187            model.ToCModel()->AddFlagsRec(modelFlags);
     188
     189          // Initialize the model's selection shape descriptor. This currently relies on the component initialization order; the
     190          // Footprint component must be initialized before this component (VisualActor) to support the ability to use the footprint
     191          // shape for the selection box (instead of the default recursive bounding box). See TypeList.h for the order in
     192          // which components are initialized; if for whatever reason you need to get rid of this dependency, you can always just
     193          // initialize the selection shape descriptor on-demand.
     194          InitSelectionShapeDescriptor(model, paramNode);
    173195        }
    174196
    175197        SelectAnimation("idle", false, fixed::FromInt(1), L"");
    public:  
    206228        serialize.NumberFixed_Unbounded("anim desync", m_AnimDesync);
    207229        serialize.NumberFixed_Unbounded("anim sync repeat time", m_AnimSyncRepeatTime);
    208230
     231        serialize.NumberI32_Unbounded("seed", m_ActorSeed);
     232        //serialize.Bool("first vis update", m_FirstVisUpdate);
     233        /*  serialize.NumberU8("last visibility state", *(uint8_t*)&m_LastVisibility, (uint8_t)ICmpRangeManager::VIS_HIDDEN, (uint8_t)ICmpRangeManager::VIS_VISIBLE);*/
     234        serialize.NumberU32_Unbounded("proxied entity", m_ProxiedEntity);
     235        serialize.NumberI32_Unbounded("proxy player target", m_ProxyPlayerTarget);
     236        SerializeMap<SerializeI32_Unbounded, SerializeU32_Unbounded>()(serialize, "per-player proxy entities", m_ProxyEntities);
    209237        // TODO: store actor variables?
    210238    }
    211239
    public:  
    226254        Init(paramNode);
    227255
    228256        SerializeCommon(deserialize);
    229 
     257       
    230258        fixed repeattime = m_AnimSyncRepeatTime; // save because SelectAnimation overwrites it
    231259
    232260        if (m_AnimRunThreshold.IsZero())
    public:  
    246274
    247275    virtual void HandleMessage(const CMessage& msg, bool UNUSED(global))
    248276    {
     277        if (msg.GetType() == MT_VisibilityChanged)
     278        {
     279            const CMessageVisibilityChanged& msgData = static_cast<const CMessageVisibilityChanged&> (msg);
     280            if (msgData.source == INVALID_ENTITY)
     281                VisibilityChanged();
     282            return;
     283        }
     284
    249285        // Quick exit for running in non-graphical mode
    250286        if (m_Unit == NULL)
    251287            return;
    public:  
    456492
    457493        // TODO: should copy/reset silhouette flags
    458494    }
     495 
     496    virtual entity_id_t GetProxyForPlayer(player_id_t player)
     497    {
     498        ProxyEntityMap::iterator result = m_ProxyEntities.find(player);
     499        if (result != m_ProxyEntities.end()) {
     500            return result->second;
     501        }
     502        return INVALID_ENTITY;
     503    }
     504
     505    virtual entity_id_t GetProxyOwner()
     506    {
     507        return m_ProxiedEntity;
     508    }
     509
     510    virtual player_id_t GetProxyPlayerTarget()
     511    {
     512        return m_ProxyPlayerTarget;
     513    }
     514
     515    virtual void SetProxyData(entity_id_t entity, player_id_t player)
     516    {
     517        m_ProxiedEntity = entity;
     518        m_ProxyPlayerTarget = player;
     519    }
     520
     521    virtual void ResetUnitSeed(int32_t seed)
     522    {
     523        m_ActorSeed = seed;
     524        if (!GetSimContext().HasUnitManager())
     525            return;
     526        if (m_Unit)
     527            GetSimContext().GetUnitManager().DeleteUnit(m_Unit);
    459528
     529        std::set<CStr> selections;
     530        m_Unit = GetSimContext().GetUnitManager().CreateUnit(m_ActorName, GetActorSeed(), selections);
     531        if (m_Unit)
     532            m_Unit->SetID(GetEntityId());
     533    }
     534 
    460535private:
    461536    int32_t GetActorSeed()
    462537    {
    463         return GetEntityId();
     538        return m_ActorSeed;
    464539    }
    465540
    466541    /// Helper method; initializes the model selection shape descriptor from XML. Factored out for readability of @ref Init.
    private:  
    471546    void InitSelectionShapeDescriptor(CModelAbstract& model, const CParamNode& paramNode);
    472547
    473548    void Update(fixed turnLength);
     549    void VisibilityChanged();
    474550    void Interpolate(float frameTime, float frameOffset);
    475551    void RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling);
    476552};
    void CCmpVisualActor::Update(fixed turnLength)  
    584660    }
    585661}
    586662
     663void CCmpVisualActor::VisibilityChanged()
     664{
     665  player_id_t player = GetSimContext().GetCurrentDisplayedPlayer();
     666
     667  CmpPtr<ICmpRangeManager> cmpRangeManager(GetSimContext(), SYSTEM_ENTITY);
     668  ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(GetEntityId(), player);
     669
     670  bool forceProxy = false;
     671  if (m_FirstVisUpdate)
     672  {
     673    m_LastVisibility = vis;
     674    if (vis == ICmpRangeManager::VIS_FOGGED)
     675    {
     676      forceProxy = true;
     677    }
     678    m_FirstVisUpdate = false;
     679  }
     680
     681  if (vis != m_LastVisibility || forceProxy)
     682  {
     683    CSimulation2& simulation = *g_Game->GetSimulation2();
     684    if (vis == ICmpRangeManager::VIS_FOGGED && m_ProxiedEntity == INVALID_ENTITY)
     685    {
     686      CmpPtr<ICmpTemplateManager> cmpTemplateManager(simulation, SYSTEM_ENTITY);
     687      std::string templ = cmpTemplateManager->GetCurrentTemplateName(GetEntityId());
     688      std::wstring wtempl = wstring_from_utf8(templ);
     689      entity_id_t proxy = simulation.AddEntity(wtempl);
     690      CmpPtr<ICmpVisual> proxyVis(simulation, proxy);
     691      proxyVis->SetProxyData(GetEntityId(), player);
     692      proxyVis->ResetUnitSeed(GetActorSeed());
     693      m_ProxyEntities[player] = proxy;
     694
     695      CMessageVisibilityChanged msg(GetEntityId(), proxy, player);
     696      simulation.BroadcastMessage(msg);
     697    }
     698    else if (vis == ICmpRangeManager::VIS_VISIBLE)
     699    {
     700      ProxyEntityMap::iterator it = m_ProxyEntities.find(player);
     701      if (it != m_ProxyEntities.end())
     702      {
     703        simulation.DestroyEntity(it->second);
     704        m_ProxyEntities.erase(it);
     705      }
     706
     707      if (m_ProxiedEntity != INVALID_ENTITY)
     708      {
     709        CmpPtr<ICmpVisual> proxyVis(simulation, m_ProxiedEntity);
     710        if (proxyVis.null())
     711          simulation.DestroyEntity(GetEntityId());
     712      }
     713    }
     714  }
     715
     716  m_LastVisibility = vis;
     717}
     718
    587719void CCmpVisualActor::Interpolate(float frameTime, float frameOffset)
    588720{
    589721    if (m_Unit == NULL)
  • source/simulation2/components/ICmpVisual.cpp

    diff --git a/source/simulation2/components/ICmpVisual.cpp b/source/simulation2/components/ICmpVisual.cpp
    index 2a6e580..37ab0f2 100644
    a b DEFINE_INTERFACE_METHOD_1("SetAnimationSyncRepeat", void, ICmpVisual, SetAnimati  
    2828DEFINE_INTERFACE_METHOD_1("SetAnimationSyncOffset", void, ICmpVisual, SetAnimationSyncOffset, fixed)
    2929DEFINE_INTERFACE_METHOD_4("SetShadingColour", void, ICmpVisual, SetShadingColour, fixed, fixed, fixed, fixed)
    3030DEFINE_INTERFACE_METHOD_2("SetVariable", void, ICmpVisual, SetVariable, std::string, float)
     31DEFINE_INTERFACE_METHOD_0("GetProxyPlayerTarget", player_id_t, ICmpVisual, GetProxyPlayerTarget)
     32DEFINE_INTERFACE_METHOD_0("GetProxyOwner", entity_id_t, ICmpVisual, GetProxyOwner)
    3133END_INTERFACE_WRAPPER(Visual)
  • source/simulation2/components/ICmpVisual.h

    diff --git a/source/simulation2/components/ICmpVisual.h b/source/simulation2/components/ICmpVisual.h
    index ade286e..8be583c 100644
    a b  
    1919#define INCLUDED_ICMPVISUAL
    2020
    2121#include "simulation2/system/Interface.h"
     22#include "simulation2/helpers/Player.h"
    2223
    2324#include "ps/CStr.h"
    2425#include "maths/BoundingBoxOriented.h"
    public:  
    138139     */
    139140    virtual void Hotload(const VfsPath& name) = 0;
    140141
    141     DECLARE_INTERFACE_TYPE(Visual)
     142    /**
     143     *
     144     */
     145    virtual entity_id_t GetProxyForPlayer(player_id_t player) = 0;
     146
     147    virtual entity_id_t GetProxyOwner() = 0;
     148    virtual player_id_t GetProxyPlayerTarget() = 0;
     149    virtual void SetProxyData(entity_id_t entity, player_id_t player) = 0;
     150    virtual void ResetUnitSeed(int32_t seed) = 0;
     151 
     152    DECLARE_INTERFACE_TYPE(Visual)
    142153};
    143154
    144155// TODO: rename this to VisualActor, because the interface is actor-specific, maybe?
  • source/simulation2/scripting/MessageTypeConversions.cpp

    diff --git a/source/simulation2/scripting/MessageTypeConversions.cpp b/source/simulation2/scripting/MessageTypeConversions.cpp
    index d976a09..668a020 100644
    a b MESSAGE_1(Update_MotionFormation, fixed, turnLength)  
    9090MESSAGE_1(Update_MotionUnit, fixed, turnLength)
    9191MESSAGE_1(Update_Final, fixed, turnLength)
    9292
     93jsval CMessageUpdate_Visibility::ToJSVal(ScriptInterface& scriptInterface) const
     94{
     95  TOJSVAL_SETUP();
     96  return OBJECT_TO_JSVAL(obj);
     97}
     98
     99CMessage* CMessageUpdate_Visibility::FromJSVal(ScriptInterface& UNUSED(scriptInterface), jsval UNUSED(val))
     100{
     101  return NULL;
     102}
     103
    93104////////////////////////////////
    94105
    95106jsval CMessageInterpolate::ToJSVal(ScriptInterface& scriptInterface) const
    CMessage* CMessagePathResult::FromJSVal(ScriptInterface& UNUSED(scriptInterface)  
    296307    return NULL;
    297308}
    298309
     310////////////////////////////////
     311
     312jsval CMessageVisibilityChanged::ToJSVal(ScriptInterface& scriptInterface) const
     313{
     314  TOJSVAL_SETUP();
     315  SET_MSG_PROPERTY(source);
     316  SET_MSG_PROPERTY(proxy);
     317  SET_MSG_PROPERTY(player);
     318  return OBJECT_TO_JSVAL(obj);
     319}
     320
     321CMessage* CMessageVisibilityChanged::FromJSVal(ScriptInterface& UNUSED(scriptInterface), jsval UNUSED(val))
     322{
     323  LOGWARNING(L"CMessageVisibilityChanged::FromJSVal not implemented");
     324  return NULL;
     325}
     326
    299327////////////////////////////////////////////////////////////////
    300328
    301329CMessage* CMessageFromJSVal(int mtid, ScriptInterface& scriptingInterface, jsval val)