From 6972926b66c7bc97bb23f44c0303a66821824fad Mon Sep 17 00:00:00 2001
From: Jack Andersen <jackoalan@gmail.com>
Date: Tue, 9 Aug 2016 09:30:23 -1000
Subject: [PATCH 1/2] More blender crash fixes

---
 DataSpec/DNACommon/MAPA.cpp | 5 +++--
 DataSpec/DNACommon/MLVL.cpp | 5 +++--
 DataSpec/DNAMP1/FRME.cpp    | 5 +++--
 DataSpec/DNAMP1/MREA.cpp    | 5 +++--
 DataSpec/DNAMP2/MREA.cpp    | 5 +++--
 DataSpec/DNAMP3/MREA.cpp    | 5 +++--
 6 files changed, 18 insertions(+), 12 deletions(-)

diff --git a/DataSpec/DNACommon/MAPA.cpp b/DataSpec/DNACommon/MAPA.cpp
index 0c3d489b0..472b53854 100644
--- a/DataSpec/DNACommon/MAPA.cpp
+++ b/DataSpec/DNACommon/MAPA.cpp
@@ -116,8 +116,9 @@ bool ReadMAPAToBlender(hecl::BlenderConnection& conn,
           "\n"
           "# Clear Scene\n"
           "for ob in bpy.data.objects:\n"
-          "    bpy.context.scene.objects.unlink(ob)\n"
-          "    bpy.data.objects.remove(ob)\n"
+          "    if ob.type != 'CAMERA':\n"
+          "        bpy.context.scene.objects.unlink(ob)\n"
+          "        bpy.data.objects.remove(ob)\n"
           "\n"
           "def add_triangle(bm, verts):\n"
           "    verts = [bm.verts[vi] for vi in verts]\n"
diff --git a/DataSpec/DNACommon/MLVL.cpp b/DataSpec/DNACommon/MLVL.cpp
index 2e9d53cfd..1bbb6244f 100644
--- a/DataSpec/DNACommon/MLVL.cpp
+++ b/DataSpec/DNACommon/MLVL.cpp
@@ -39,8 +39,9 @@ bool ReadMLVLToBlender(hecl::BlenderConnection& conn,
               "\n"
               "# Clear Scene\n"
               "for ob in bpy.data.objects:\n"
-              "    bpy.context.scene.objects.unlink(ob)\n"
-              "    bpy.data.objects.remove(ob)\n");
+              "    if ob.type != 'CAMERA':\n"
+              "        bpy.context.scene.objects.unlink(ob)\n"
+              "        bpy.data.objects.remove(ob)\n");
 
     /* Insert area empties */
     int areaIdx = 0;
diff --git a/DataSpec/DNAMP1/FRME.cpp b/DataSpec/DNAMP1/FRME.cpp
index 4b219ccb9..305c9e740 100644
--- a/DataSpec/DNAMP1/FRME.cpp
+++ b/DataSpec/DNAMP1/FRME.cpp
@@ -353,8 +353,9 @@ bool FRME::Extract(const SpecBase &dataSpec,
           "bpy.types.Object.retro_widget_model_draw_flags = bpy.props.EnumProperty(items=model_draw_flags, name='Retro: Model Draw Flags', default='RETRO_ALPHA')\n"
           "# Clear Scene\n"
           "for ob in bpy.data.objects:\n"
-          "    bpy.context.scene.objects.unlink(ob)\n"
-          "    bpy.data.objects.remove(ob)\n"
+          "    if ob.type != 'CAMERA':\n"
+          "        bpy.context.scene.objects.unlink(ob)\n"
+          "        bpy.data.objects.remove(ob)\n"
           "\n"
           "def duplicateObject(copy_obj):\n"
           "    # Create new mesh\n"
diff --git a/DataSpec/DNAMP1/MREA.cpp b/DataSpec/DNAMP1/MREA.cpp
index a5a77dffd..1e8231ac5 100644
--- a/DataSpec/DNAMP1/MREA.cpp
+++ b/DataSpec/DNAMP1/MREA.cpp
@@ -95,8 +95,9 @@ bool MREA::Extract(const SpecBase& dataSpec,
     MaterialSet::RegisterMaterialProps(os);
     os << "# Clear Scene\n"
           "for ob in bpy.data.objects:\n"
-          "    bpy.context.scene.objects.unlink(ob)\n"
-          "    bpy.data.objects.remove(ob)\n"
+          "    if ob.type != 'CAMERA':\n"
+          "        bpy.context.scene.objects.unlink(ob)\n"
+          "        bpy.data.objects.remove(ob)\n"
           "bpy.types.Lamp.retro_layer = bpy.props.IntProperty(name='Retro: Light Layer')\n"
           "bpy.types.Lamp.retro_origtype = bpy.props.IntProperty(name='Retro: Original Type')\n"
           "bpy.types.Object.retro_disable_enviro_visor = bpy.props.BoolProperty(name='Retro: Disable in Combat/Scan Visor')\n"
diff --git a/DataSpec/DNAMP2/MREA.cpp b/DataSpec/DNAMP2/MREA.cpp
index 8bfff0716..719ce5220 100644
--- a/DataSpec/DNAMP2/MREA.cpp
+++ b/DataSpec/DNAMP2/MREA.cpp
@@ -227,8 +227,9 @@ bool MREA::Extract(const SpecBase& dataSpec,
     MaterialSet::RegisterMaterialProps(os);
     os << "# Clear Scene\n"
           "for ob in bpy.data.objects:\n"
-          "    bpy.context.scene.objects.unlink(ob)\n"
-          "    bpy.data.objects.remove(ob)\n"
+          "    if ob.type != 'CAMERA':\n"
+          "        bpy.context.scene.objects.unlink(ob)\n"
+          "        bpy.data.objects.remove(ob)\n"
           "bpy.types.Lamp.retro_layer = bpy.props.IntProperty(name='Retro: Light Layer')\n"
           "bpy.types.Lamp.retro_origtype = bpy.props.IntProperty(name='Retro: Original Type')\n"
           "bpy.types.Object.retro_disable_enviro_visor = bpy.props.BoolProperty(name='Retro: Disable in Combat/Scan Visor')\n"
diff --git a/DataSpec/DNAMP3/MREA.cpp b/DataSpec/DNAMP3/MREA.cpp
index 62e4d3542..b8cfd5ad0 100644
--- a/DataSpec/DNAMP3/MREA.cpp
+++ b/DataSpec/DNAMP3/MREA.cpp
@@ -126,8 +126,9 @@ bool MREA::Extract(const SpecBase& dataSpec,
     MaterialSet::RegisterMaterialProps(os);
     os << "# Clear Scene\n"
           "for ob in bpy.data.objects:\n"
-          "    bpy.context.scene.objects.unlink(ob)\n"
-          "    bpy.data.objects.remove(ob)\n"
+          "    if ob.type != 'CAMERA':\n"
+          "        bpy.context.scene.objects.unlink(ob)\n"
+          "        bpy.data.objects.remove(ob)\n"
           "bpy.types.Lamp.retro_layer = bpy.props.IntProperty(name='Retro: Light Layer')\n"
           "bpy.types.Lamp.retro_origtype = bpy.props.IntProperty(name='Retro: Original Type')\n"
           "\n";

From 7740af2b046a6babdb927200bc367cd59617e321 Mon Sep 17 00:00:00 2001
From: Phillip Stephens <antidote.crk@gmail.com>
Date: Tue, 9 Aug 2016 17:46:53 -0700
Subject: [PATCH 2/2] More CGameArea and CActor imps

---
 Runtime/CStateManager.cpp   |  4 ++--
 Runtime/World/CActor.cpp    | 11 +++++++++++
 Runtime/World/CActor.hpp    | 36 ++++++++++++------------------------
 Runtime/World/CGameArea.cpp | 29 ++++++++++++++++++++++++-----
 Runtime/World/CGameArea.hpp | 13 +++++++++----
 5 files changed, 58 insertions(+), 35 deletions(-)

diff --git a/Runtime/CStateManager.cpp b/Runtime/CStateManager.cpp
index ee29876b5..8eb9267a0 100644
--- a/Runtime/CStateManager.cpp
+++ b/Runtime/CStateManager.cpp
@@ -197,8 +197,8 @@ void CStateManager::UpdateThermalVisor()
                     std::unique_ptr<CGameArea>& connArea = x850_world->GetGameAreas()[x8cc_nextAreaId];
                     if (connArea->IsPostConstructed())
                     {
-                        u32 something = connArea->GetPostConstructed()->x10dc_;
-                        if (something == 1)
+                        CGameArea::EOcclusionState occState = connArea->GetPostConstructed()->x10dc_occlusionState;
+                        if (occState == CGameArea::EOcclusionState::Occluded)
                         {
                             closestDist = dist;
                             lastArea = connArea.get();
diff --git a/Runtime/World/CActor.cpp b/Runtime/World/CActor.cpp
index 7ffb8af0a..5d9f36a9c 100644
--- a/Runtime/World/CActor.cpp
+++ b/Runtime/World/CActor.cpp
@@ -223,4 +223,15 @@ void CActor::SetSfxPitchBend(s32 val)
     CSfxManager::PitchBend(*x8c_sfxHandle.get(), val);
 }
 
+void CActor::OnScanStateChanged(EScanState state, CStateManager& mgr)
+{
+    if (state == EScanState::Zero)
+        SendScriptMsgs(EScriptObjectState::UNKS7, mgr, EScriptObjectMessage::None);
+    else if (state == EScanState::One)
+        SendScriptMsgs(EScriptObjectState::UNKS8, mgr, EScriptObjectMessage::None);
+    else if (state == EScanState::Two)
+        SendScriptMsgs(EScriptObjectState::ScanDone, mgr, EScriptObjectMessage::None);
+
+}
+
 }
diff --git a/Runtime/World/CActor.hpp b/Runtime/World/CActor.hpp
index 097809c0c..aa6ae9d06 100644
--- a/Runtime/World/CActor.hpp
+++ b/Runtime/World/CActor.hpp
@@ -45,43 +45,28 @@ protected:
             bool xe4_28_ : 1;
             bool xe4_29_ : 1;
             bool xe4_30_ : 1;
-        };
-        u8 _dummy1 = 0;
-    };
-
-    union
-    {
-        struct
-        {
             bool xe5_0_opaque : 1;
             bool xe5_26_muted : 1;
             bool xe5_27_useInSortedLists : 1;
             bool xe5_28_callTouch : 1;
-        };
-        u8 _dummy2 = 0;
-    };
-    union
-    {
-        struct
-        {
             bool xe6_26_inFluid : 1;
             bool xe6_30_enablePitchBend : 1;
-        };
-        u8 _dummy3 = 0;
-    };
-    union
-    {
-        struct
-        {
             bool xe7_29_ : 1;
         };
-        u8 _dummy4 = 0;
+        u32 dummy = 0;
     };
 public:
     enum class EFluidState
     {
     };
 
+    enum class EScanState
+    {
+        Zero,
+        One,
+        Two,
+    };
+
     CActor(TUniqueId, bool, const std::string&, const CEntityInfo&,
            const zeus::CTransform&, CModelData&&, const CMaterialList&,
            const CActorParameters&, TUniqueId);
@@ -111,7 +96,8 @@ public:
     void RemoveEmitter();
 
     virtual rstl::optional_object<zeus::CAABox> GetTouchBounds() const { return {} ; }
-    virtual EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&, CWeaponMode&, int);
+    virtual EWeaponCollisionResponseTypes GetCollisionResponseType(const zeus::CVector3f&, const zeus::CVector3f&,
+                                                                   CWeaponMode&, int);
 
     void RemoveMaterial(EMaterialTypes, EMaterialTypes, EMaterialTypes, EMaterialTypes, CStateManager&);
     void RemoveMaterial(EMaterialTypes, EMaterialTypes, EMaterialTypes, CStateManager&);
@@ -138,6 +124,8 @@ public:
     bool HasModelData() const;
     const CSfxHandle* GetSfxHandle() const;
     void SetSfxPitchBend(s32);
+
+    virtual void OnScanStateChanged(EScanState, CStateManager&);
 };
 
 }
diff --git a/Runtime/World/CGameArea.cpp b/Runtime/World/CGameArea.cpp
index b62fc4ab5..69366e79c 100644
--- a/Runtime/World/CGameArea.cpp
+++ b/Runtime/World/CGameArea.cpp
@@ -504,7 +504,7 @@ void CGameArea::UpdateThermalVisor(float dt)
 
 void CGameArea::AliveUpdate(float dt)
 {
-    if (!x12c_postConstructed->x10dc_)
+    if (x12c_postConstructed->x10dc_occlusionState == EOcclusionState::NotOccluded)
         x12c_postConstructed->x10e4_ += dt;
     else
         x12c_postConstructed->x10e4_ = 0.f;
@@ -515,23 +515,38 @@ void CGameArea::AliveUpdate(float dt)
 
 void CGameArea::SetOcclusionState(EOcclusionState state)
 {
+    if (!xf0_24_postConstructed || x12c_postConstructed->x10dc_occlusionState == state)
+        return;
+
+    if (state == EOcclusionState::NotOccluded)
+    {
+        ReloadAllUnloadedTextures();
+        AddStaticGeometry();
+    }
+    else
+    {
+        x12c_postConstructed->x1108_26_ = true;
+        x12c_postConstructed->x1108_27_ = false;
+        RemoveStaticGeometry();
+    }
 }
 
 void CGameArea::RemoveStaticGeometry()
 {
-    if (!xf0_24_postConstructed || !x12c_postConstructed || !x12c_postConstructed->x10dc_)
+    if (!xf0_24_postConstructed || !x12c_postConstructed ||
+        x12c_postConstructed->x10dc_occlusionState == EOcclusionState::NotOccluded)
         return;
     x12c_postConstructed->x10e0_ = 0;
-    x12c_postConstructed->x10dc_ = 0;
+    x12c_postConstructed->x10dc_occlusionState = EOcclusionState::NotOccluded;
     g_Renderer->RemoveStaticGeometry(&x12c_postConstructed->x4c_insts);
 }
 
 void CGameArea::AddStaticGeometry()
 {
-    if (x12c_postConstructed->x10dc_ != 1)
+    if (x12c_postConstructed->x10dc_occlusionState != EOcclusionState::Occluded)
     {
         x12c_postConstructed->x10e0_ = 0;
-        x12c_postConstructed->x10dc_ = 1;
+        x12c_postConstructed->x10dc_occlusionState = EOcclusionState::Occluded;
         if (!x12c_postConstructed->x1108_25_)
             FillInStaticGeometry();
         g_Renderer->AddStaticGeometry(&x12c_postConstructed->x4c_insts,
@@ -620,6 +635,10 @@ bool CGameArea::StartStreamingMainArea()
     return true;
 }
 
+void CGameArea::ReloadAllUnloadedTextures()
+{
+}
+
 u32 CGameArea::GetNumPartSizes() const
 {
     return hecl::SBig(*reinterpret_cast<u32*>(x110_mreaSecBufs[0].first.get() + 60));
diff --git a/Runtime/World/CGameArea.hpp b/Runtime/World/CGameArea.hpp
index a0bf993e3..88b1d1969 100644
--- a/Runtime/World/CGameArea.hpp
+++ b/Runtime/World/CGameArea.hpp
@@ -122,6 +122,12 @@ class CGameArea : public IGameArea
     std::list<std::shared_ptr<ProjectResourceFactoryBase::AsyncTask>> xf8_loadTransactions;
 
 public:
+    enum class EOcclusionState
+    {
+        NotOccluded,
+        Occluded
+    };
+
     class CAreaFog
     {
         ERglFogMode x0_fogMode = ERglFogMode::None;
@@ -170,7 +176,7 @@ public:
         u32 x10d0_sclySize = 0;
         u32 x10d4_ = 0;
         u32 x10d8_ = 0;
-        u32 x10dc_ = 0;
+        EOcclusionState x10dc_occlusionState = EOcclusionState::NotOccluded;
         u32 x10e0_ = 0;
         float x10e4_ = 5.f;
         u32 x10e8_ = -1;
@@ -185,6 +191,7 @@ public:
                 bool x1108_24_ : 1;
                 bool x1108_25_ : 1;
                 bool x1108_26_ : 1;
+                bool x1108_27_ : 1;
                 bool x1108_28_ : 1;
                 bool x1108_29_ : 1;
                 bool x1108_30_ : 1;
@@ -236,9 +243,6 @@ public:
         bool IsQualified(const CEntity& ent);
     };
 
-    enum class EOcclusionState
-    {
-    };
 
     CGameArea(CInputStream& in, int idx, int mlvlVersion);
 
@@ -274,6 +278,7 @@ public:
     bool StartStreamingMainArea();
     //void UnloadAllLoadedTextures();
     //void ReloadAllLoadedTextures();
+    void ReloadAllUnloadedTextures();
     u32 GetNumPartSizes() const;
     void AllocNewAreaData(int, int);
     void Invalidate(CStateManager& mgr);