metaforce/Runtime/World/CWorld.cpp

769 lines
22 KiB
C++
Raw Normal View History

2016-04-24 02:46:13 +00:00
#include "CWorld.hpp"
#include "CSimplePool.hpp"
2016-07-24 04:46:32 +00:00
#include "CStateManager.hpp"
#include "CInGameTweakManagerBase.hpp"
2016-08-01 04:35:42 +00:00
#include "Audio/CAudioGroupSet.hpp"
2017-02-08 06:48:43 +00:00
#include "CGameState.hpp"
#include "Graphics/CBooRenderer.hpp"
#include "World/CScriptAreaAttributes.hpp"
2017-11-27 05:06:53 +00:00
#include "IMain.hpp"
#include "Audio/CStreamAudioManager.hpp"
#include "CScriptRoomAcoustics.hpp"
2016-04-24 02:46:13 +00:00
namespace urde
{
2017-08-13 05:26:14 +00:00
CWorld::CSoundGroupData::CSoundGroupData(int grpId, CAssetId agsc) : x0_groupId(grpId), x4_agscId(agsc)
{
x1c_groupData = g_SimplePool->GetObj(SObjectTag{FOURCC('AGSC'), agsc});
}
2017-08-13 05:26:14 +00:00
CDummyWorld::CDummyWorld(CAssetId mlvlId, bool loadMap) : x4_loadMap(loadMap), xc_mlvlId(mlvlId)
{
SObjectTag tag{FOURCC('MLVL'), mlvlId};
2017-10-27 10:10:32 +00:00
x34_loadBuf.reset(new u8[g_ResFactory->ResourceSize(tag)]);
2017-10-28 07:08:48 +00:00
x30_loadToken = g_ResFactory->LoadResourceAsync(tag, x34_loadBuf.get());
2018-05-08 05:10:24 +00:00
}
CDummyWorld::~CDummyWorld()
{
if (x30_loadToken)
x30_loadToken->PostCancelRequest();
}
2017-08-13 05:26:14 +00:00
CAssetId CDummyWorld::IGetWorldAssetId() const { return xc_mlvlId; }
2017-08-13 05:26:14 +00:00
CAssetId CDummyWorld::IGetStringTableAssetId() const { return x10_strgId; }
2017-08-13 05:26:14 +00:00
CAssetId CDummyWorld::IGetSaveWorldAssetId() const { return x14_savwId; }
2017-01-07 01:58:05 +00:00
const CMapWorld* CDummyWorld::IGetMapWorld() const { return x2c_mapWorld.GetObj(); }
2017-01-07 01:58:05 +00:00
CMapWorld* CDummyWorld::IMapWorld() { return x2c_mapWorld.GetObj(); }
2017-01-07 01:58:05 +00:00
const IGameArea* CDummyWorld::IGetAreaAlways(TAreaId id) const { return &x18_areas.at(id); }
2017-01-07 01:58:05 +00:00
TAreaId CDummyWorld::IGetCurrentAreaId() const { return x3c_curAreaId; }
2017-08-13 05:26:14 +00:00
TAreaId CDummyWorld::IGetAreaId(CAssetId id) const
{
2016-07-24 04:46:32 +00:00
int ret = 0;
2017-11-15 04:12:13 +00:00
if (!id.IsValid())
2016-07-24 04:46:32 +00:00
return kInvalidAreaId;
for (const CDummyGameArea& area : x18_areas)
{
if (area.xc_mrea == id)
return ret;
++ret;
}
return kInvalidAreaId;
}
2016-08-09 03:58:19 +00:00
CWorld::CRelay::CRelay(CInputStream& in)
{
x0_relay = in.readUint32Big();
x4_target = in.readUint32Big();
x8_msg = in.readUint16Big();
xa_active = in.readBool();
}
2016-07-24 04:46:32 +00:00
std::vector<CWorld::CRelay> CWorld::CRelay::ReadMemoryRelays(athena::io::MemoryReader& r)
{
std::vector<CWorld::CRelay> ret;
u32 count = r.readUint32Big();
ret.reserve(count);
2017-01-07 01:58:05 +00:00
for (u32 i = 0; i < count; ++i)
ret.emplace_back(r);
return ret;
}
2017-08-13 05:26:14 +00:00
void CWorldLayers::ReadWorldLayers(athena::io::MemoryReader& r, int version, CAssetId mlvlId)
{
2017-02-08 06:48:43 +00:00
if (version <= 14)
return;
CWorldLayers ret;
u32 areaCount = r.readUint32Big();
ret.m_areas.reserve(areaCount);
2017-01-07 01:58:05 +00:00
for (u32 i = 0; i < areaCount; ++i)
{
ret.m_areas.emplace_back();
ret.m_areas.back().m_layerCount = r.readUint32Big();
ret.m_areas.back().m_layerBits = r.readUint64Big();
}
u32 nameCount = r.readUint32Big();
ret.m_names.reserve(areaCount);
2017-01-07 01:58:05 +00:00
for (u32 i = 0; i < nameCount; ++i)
ret.m_names.push_back(r.readString());
areaCount = r.readUint32Big();
2017-01-07 01:58:05 +00:00
for (u32 i = 0; i < areaCount; ++i)
ret.m_areas[i].m_startNameIdx = r.readUint32Big();
2017-02-08 06:48:43 +00:00
CWorldState& wldState = g_GameState->StateForWorld(mlvlId);
wldState.GetLayerState()->InitializeWorldLayers(ret.m_areas);
}
bool CDummyWorld::ICheckWorldComplete()
{
switch (x8_phase)
{
case Phase::Loading:
{
2017-10-28 07:08:48 +00:00
if (x30_loadToken && !x30_loadToken->IsComplete())
return false;
2017-10-28 07:08:48 +00:00
x30_loadToken.reset();
athena::io::MemoryReader r(x34_loadBuf.get(), UINT32_MAX, false);
r.readUint32Big();
int version = r.readUint32Big();
x10_strgId = r.readUint32Big();
if (version >= 15)
x14_savwId = r.readUint32Big();
if (version >= 12)
r.readUint32Big();
if (version >= 17)
2016-07-24 04:46:32 +00:00
CWorld::CRelay::ReadMemoryRelays(r);
u32 areaCount = r.readUint32Big();
r.readUint32Big();
x18_areas.reserve(areaCount);
2017-01-07 01:58:05 +00:00
for (u32 i = 0; i < areaCount; ++i)
x18_areas.emplace_back(r, i, version);
x28_mapWorldId = r.readUint32Big();
if (x4_loadMap)
x2c_mapWorld = g_SimplePool->GetObj(SObjectTag{FOURCC('MAPW'), x28_mapWorldId});
r.readByte();
r.readUint32Big();
if (version > 10)
{
u32 audioGroupCount = r.readUint32Big();
2017-01-07 01:58:05 +00:00
for (u32 i = 0; i < audioGroupCount; ++i)
{
r.readUint32Big();
r.readUint32Big();
}
}
if (version > 12)
r.readString();
2017-02-08 06:48:43 +00:00
CWorldLayers::ReadWorldLayers(r, version, xc_mlvlId);
if (x4_loadMap)
x8_phase = Phase::LoadingMap;
else
{
x8_phase = Phase::Done;
return false;
}
}
case Phase::LoadingMap:
{
if (!x2c_mapWorld.IsLoaded() || !x2c_mapWorld.GetObj())
return false;
x2c_mapWorld->SetWhichMapAreasLoaded(*this, 0, 9999);
x8_phase = Phase::LoadingMapAreas;
}
case Phase::LoadingMapAreas:
{
if (x2c_mapWorld->IsMapAreasStreaming())
return false;
x8_phase = Phase::Done;
}
case Phase::Done:
return true;
default:
return false;
}
}
2017-01-07 01:58:05 +00:00
std::string CDummyWorld::IGetDefaultAudioTrack() const { return {}; }
2017-01-07 01:58:05 +00:00
int CDummyWorld::IGetAreaCount() const { return x18_areas.size(); }
2016-07-24 04:46:32 +00:00
2017-08-13 05:26:14 +00:00
CWorld::CWorld(IObjectStore& objStore, IFactory& resFactory, CAssetId mlvlId)
2017-02-14 04:27:20 +00:00
: x8_mlvlId(mlvlId), x60_objectStore(objStore), x64_resFactory(resFactory)
2016-07-24 04:46:32 +00:00
{
2017-04-13 19:28:31 +00:00
x70_24_currentAreaNeedsAllocation = true;
2016-07-24 04:46:32 +00:00
SObjectTag tag{FOURCC('MLVL'), mlvlId};
2017-10-27 10:10:32 +00:00
x40_loadBuf.reset(new u8[resFactory.ResourceSize(tag)]);
resFactory.LoadResourceAsync(tag, x40_loadBuf.get());
}
2017-11-27 05:06:53 +00:00
CWorld::~CWorld()
{
StopSounds();
if (g_GameState->GetWorldTransitionManager()->IsTransitionEnabled() &&
g_Main->GetFlowState() == EFlowState::None)
CStreamAudioManager::StopOneShot();
else
CStreamAudioManager::StopAll();
UnloadSoundGroups();
CScriptRoomAcoustics::DisableAuxCallbacks();
}
2017-08-13 05:26:14 +00:00
CAssetId CWorld::IGetWorldAssetId() const { return x8_mlvlId; }
2017-08-13 05:26:14 +00:00
CAssetId CWorld::IGetStringTableAssetId() const { return xc_strgId; }
2017-08-13 05:26:14 +00:00
CAssetId CWorld::IGetSaveWorldAssetId() const { return x10_savwId; }
2017-01-07 01:58:05 +00:00
const CMapWorld* CWorld::IGetMapWorld() const { return const_cast<CWorld*>(this)->GetMapWorld(); }
2017-01-07 01:58:05 +00:00
CMapWorld* CWorld::IMapWorld() { return const_cast<CMapWorld*>(GetMapWorld()); }
2017-01-07 01:58:05 +00:00
const CGameArea* CWorld::GetAreaAlways(TAreaId id) const { return x18_areas.at(id).get(); }
2017-01-07 01:58:05 +00:00
CGameArea* CWorld::GetArea(TAreaId id) { return const_cast<CGameArea*>(GetAreaAlways(id)); }
2016-08-09 03:58:19 +00:00
2017-01-07 01:58:05 +00:00
const IGameArea* CWorld::IGetAreaAlways(TAreaId id) const { return GetAreaAlways(id); }
2016-08-09 03:58:19 +00:00
2017-01-07 01:58:05 +00:00
TAreaId CWorld::IGetCurrentAreaId() const { return x68_curAreaId; }
2017-08-13 05:26:14 +00:00
TAreaId CWorld::IGetAreaId(CAssetId id) const
{
2016-07-24 04:46:32 +00:00
int ret = 0;
2017-11-15 04:12:13 +00:00
if (!id.IsValid())
2016-07-24 04:46:32 +00:00
return kInvalidAreaId;
for (const std::unique_ptr<CGameArea>& area : x18_areas)
{
if (area->x84_mrea == id)
return ret;
++ret;
}
return kInvalidAreaId;
}
void CWorld::MoveToChain(CGameArea* area, EChain chain)
{
if (area->x138_curChain == chain)
return;
if (area->x138_curChain != EChain::Invalid)
2017-11-12 05:14:57 +00:00
if (x4c_chainHeads[int(area->x138_curChain)] == area)
x4c_chainHeads[int(area->x138_curChain)] = area->x130_next;
area->SetChain(x4c_chainHeads[int(chain)], chain);
x4c_chainHeads[int(chain)] = area;
2016-07-24 04:46:32 +00:00
}
2017-11-12 05:14:57 +00:00
void CWorld::MoveAreaToAliveChain(TAreaId aid)
2017-02-19 09:27:01 +00:00
{
MoveToChain(x18_areas[aid].get(), EChain::Alive);
2017-02-19 09:27:01 +00:00
}
2017-11-27 05:06:53 +00:00
void CWorld::LoadSoundGroup(int groupId, CAssetId agscId, CSoundGroupData& data)
{
if (!CAudioSys::SysLoadGroupSet(g_SimplePool, agscId))
{
auto name = CAudioSys::SysGetGroupSetName(agscId);
CAudioSys::SysAddGroupIntoAmuse(name);
data.xc_name = name;
++x6c_loadedAudioGrpCount;
}
}
2017-01-07 01:58:05 +00:00
void CWorld::LoadSoundGroups() {}
2017-11-27 05:06:53 +00:00
void CWorld::UnloadSoundGroups()
{
for (CSoundGroupData& data : x74_soundGroupData)
{
CAudioSys::SysRemoveGroupFromAmuse(data.xc_name);
CAudioSys::SysUnloadAudioGroupSet(data.xc_name);
}
}
void CWorld::StopSounds()
{
for (CSfxHandle& hnd : xc8_globalSfxHandles)
CSfxManager::RemoveEmitter(hnd);
xc8_globalSfxHandles.clear();
}
2017-08-13 05:26:14 +00:00
bool CWorld::CheckWorldComplete(CStateManager* mgr, TAreaId id, CAssetId mreaId)
2016-07-24 04:46:32 +00:00
{
2017-11-15 04:12:13 +00:00
if (mreaId.IsValid())
2016-07-24 04:46:32 +00:00
{
x68_curAreaId = 0;
TAreaId aid = 0;
for (const std::unique_ptr<CGameArea>& area : x18_areas)
{
if (area->x84_mrea == mreaId)
{
x68_curAreaId = aid;
break;
}
++aid;
}
}
else
x68_curAreaId = id;
switch (x4_phase)
{
case Phase::Loading:
{
if (!x40_loadBuf)
return false;
2017-02-14 04:27:20 +00:00
athena::io::MemoryReader r(x40_loadBuf.get(), UINT32_MAX);
2016-07-24 04:46:32 +00:00
r.readUint32Big();
int version = r.readUint32Big();
xc_strgId = r.readUint32Big();
if (version >= 15)
x10_savwId = r.readUint32Big();
if (version >= 12)
{
2017-08-13 05:26:14 +00:00
CAssetId skyboxId = r.readUint32Big();
2017-11-15 04:12:13 +00:00
if (skyboxId.IsValid() && mgr)
2017-11-12 05:14:57 +00:00
x94_skyboxWorld = g_SimplePool->GetObj(SObjectTag{FOURCC('CMDL'), skyboxId});
2016-07-24 04:46:32 +00:00
}
if (version >= 17)
x2c_relays = CWorld::CRelay::ReadMemoryRelays(r);
u32 areaCount = r.readUint32Big();
r.readUint32Big();
x18_areas.reserve(areaCount);
2017-01-07 01:58:05 +00:00
for (u32 i = 0; i < areaCount; ++i)
2016-07-24 04:46:32 +00:00
x18_areas.push_back(std::make_unique<CGameArea>(r, i, version));
if (x48_chainCount < 5)
{
2017-01-07 01:58:05 +00:00
for (int i = x48_chainCount; i < 5; ++i)
2016-07-24 04:46:32 +00:00
x4c_chainHeads[i] = nullptr;
x48_chainCount = 5;
}
for (std::unique_ptr<CGameArea>& area : x18_areas)
2017-04-13 19:28:31 +00:00
MoveToChain(area.get(), EChain::Deallocated);
2016-07-24 04:46:32 +00:00
x24_mapwId = r.readUint32Big();
x28_mapWorld = g_SimplePool->GetObj(SObjectTag{FOURCC('MAPW'), x24_mapwId});
if (mgr)
{
std::vector<TEditorId> ids;
mgr->LoadScriptObjects(kInvalidAreaId, r, ids);
mgr->InitScriptObjects(ids);
}
if (version > 10)
{
u32 audioGroupCount = r.readUint32Big();
x74_soundGroupData.reserve(audioGroupCount);
2017-01-07 01:58:05 +00:00
for (u32 i = 0; i < audioGroupCount; ++i)
2016-07-24 04:46:32 +00:00
{
int grpId = r.readUint32Big();
2017-08-13 05:26:14 +00:00
CAssetId agscId = r.readUint32Big();
2016-07-24 04:46:32 +00:00
x74_soundGroupData.emplace_back(grpId, agscId);
}
}
if (version > 12)
{
x84_defAudioTrack = r.readString();
2017-08-13 05:26:14 +00:00
std::string trackKey = hecl::Format("WorldDefault: %8.8x", u32(x8_mlvlId.Value()));
2016-07-24 04:46:32 +00:00
if (g_TweakManager->HasTweakValue(trackKey))
x84_defAudioTrack = g_TweakManager->GetTweakValue(trackKey)->GetAudio().GetFileName();
2016-07-24 04:46:32 +00:00
}
2017-02-08 06:48:43 +00:00
CWorldLayers::ReadWorldLayers(r, version, x8_mlvlId);
2016-07-24 04:46:32 +00:00
x4_phase = Phase::LoadingMap;
}
case Phase::LoadingMap:
{
if (!x28_mapWorld.IsLoaded() || !x28_mapWorld.GetObj())
return false;
if (x68_curAreaId == kInvalidAreaId)
x28_mapWorld->SetWhichMapAreasLoaded(*this, 0, 9999);
else
x28_mapWorld->SetWhichMapAreasLoaded(*this, x68_curAreaId, 3);
2016-07-24 04:46:32 +00:00
x4_phase = Phase::LoadingMapAreas;
}
case Phase::LoadingMapAreas:
{
if (x28_mapWorld->IsMapAreasStreaming())
return false;
x4_phase = Phase::LoadingSkyBox;
}
case Phase::LoadingSkyBox:
{
2017-11-12 05:14:57 +00:00
x70_26_skyboxActive = true;
x70_27_skyboxVisible = false;
2017-11-12 05:14:57 +00:00
if (!x94_skyboxWorld.IsLoaded())
return false;
2017-11-12 05:14:57 +00:00
CModel* skybox = x94_skyboxWorld.GetObj();
if (!skybox)
return false;
skybox->GetInstance().Touch(0);
if (!skybox->IsLoaded(0))
return false;
2017-11-12 05:14:57 +00:00
xa4_skyboxWorldLoaded = x94_skyboxWorld;
for (CSoundGroupData& group : x74_soundGroupData)
group.x1c_groupData.Lock();
x4_phase = Phase::LoadingSoundGroups;
}
case Phase::LoadingSoundGroups:
{
bool allLoaded = true;
for (CSoundGroupData& group : x74_soundGroupData)
{
bool loaded = group.x1c_groupData.IsLoaded();
allLoaded &= loaded;
if (loaded)
{
CAudioGroupSet* groupData = group.x1c_groupData.GetObj();
if (groupData)
LoadSoundGroup(group.x0_groupId, group.x4_agscId, group);
}
}
if (!allLoaded)
return false;
LoadSoundGroups();
2016-07-24 04:46:32 +00:00
x4_phase = Phase::Done;
}
case Phase::Done:
return true;
default:
return false;
}
return false;
}
bool CWorld::ScheduleAreaToLoad(CGameArea* area, CStateManager& mgr)
{
if (!area->IsPostConstructed())
{
2017-04-13 19:28:31 +00:00
MoveToChain(area, EChain::Loading);
return true;
}
else
{
if (area->x138_curChain != EChain::Alive)
{
2017-04-13 19:28:31 +00:00
if (area->x138_curChain != EChain::AliveJudgement)
{
2017-04-13 19:28:31 +00:00
x70_24_currentAreaNeedsAllocation = true;
}
MoveToChain(area, EChain::Alive);
}
return false;
}
}
void CWorld::TravelToArea(TAreaId aid, CStateManager& mgr, bool skipLoadOther)
{
if (aid < 0 || aid >= x18_areas.size())
return;
2017-04-13 19:28:31 +00:00
x70_24_currentAreaNeedsAllocation = false;
x68_curAreaId = aid;
CGameArea* toDeallocateAreas = x4c_chainHeads[0];
while (toDeallocateAreas)
{
if (toDeallocateAreas->Invalidate(&mgr))
{
2017-04-13 19:28:31 +00:00
MoveToChain(toDeallocateAreas, EChain::Deallocated);
break;
}
2017-04-13 19:28:31 +00:00
toDeallocateAreas = toDeallocateAreas->x130_next;
}
CGameArea* aliveAreas = x4c_chainHeads[3];
while (aliveAreas)
{
CGameArea* aliveArea = aliveAreas;
2017-04-13 19:28:31 +00:00
aliveAreas = aliveAreas->x130_next;
MoveToChain(aliveArea, EChain::AliveJudgement);
}
CGameArea* loadingAreas = x4c_chainHeads[2];
while (loadingAreas)
{
CGameArea* loadingArea = loadingAreas;
2017-04-13 19:28:31 +00:00
loadingAreas = loadingAreas->x130_next;
MoveToChain(loadingArea, EChain::ToDeallocate);
}
CGameArea* area = x18_areas[aid].get();
2017-04-13 19:28:31 +00:00
if (area->x138_curChain != EChain::AliveJudgement)
x70_24_currentAreaNeedsAllocation = true;
area->Validate(mgr);
MoveToChain(area, EChain::Alive);
area->SetOcclusionState(CGameArea::EOcclusionState::Visible);
CGameArea* otherLoadArea = nullptr;
if (!skipLoadOther)
{
bool otherLoading = false;
for (CGameArea::Dock& dock : area->xcc_docks)
{
u32 dockRefCount = dock.GetDockRefs().size();
2017-01-07 01:58:05 +00:00
for (u32 i = 0; i < dockRefCount; ++i)
{
if (!dock.ShouldLoadOtherArea(i))
continue;
TAreaId connArea = dock.GetConnectedAreaId(i);
CGameArea* cArea = x18_areas[connArea].get();
if (!cArea->xf0_25_active)
continue;
if (!otherLoading)
{
otherLoading = ScheduleAreaToLoad(cArea, mgr);
if (!otherLoading)
continue;
otherLoadArea = cArea;
}
else
ScheduleAreaToLoad(cArea, mgr);
}
}
}
CGameArea* judgementAreas = x4c_chainHeads[4];
while (judgementAreas)
{
CGameArea* judgementArea = judgementAreas;
judgementAreas = judgementArea->x130_next;
2017-04-13 19:28:31 +00:00
MoveToChain(judgementArea, EChain::ToDeallocate);
}
size_t toStreamCount = 0;
toDeallocateAreas = x4c_chainHeads[0];
while (toDeallocateAreas)
{
2017-04-13 19:28:31 +00:00
toDeallocateAreas->RemoveStaticGeometry();
toDeallocateAreas = toDeallocateAreas->x130_next;
++toStreamCount;
}
2017-02-18 02:19:50 +00:00
if (!toStreamCount && otherLoadArea && !x70_25_paused)
otherLoadArea->StartStreamIn(mgr);
2017-04-15 05:32:25 +00:00
x28_mapWorld->SetWhichMapAreasLoaded(*this, aid, 3);
}
2017-02-18 02:19:50 +00:00
void CWorld::SetPauseState(bool paused)
{
2017-04-13 19:28:31 +00:00
for (auto it = GetChainHead(EChain::Loading) ; it != AliveAreasEnd() ; ++it)
it->SetPauseState(paused);
2017-02-18 02:19:50 +00:00
x70_25_paused = paused;
}
2017-01-07 01:58:05 +00:00
bool CWorld::ICheckWorldComplete() { return CheckWorldComplete(nullptr, kInvalidAreaId, -1); }
2017-01-07 01:58:05 +00:00
std::string CWorld::IGetDefaultAudioTrack() const { return x84_defAudioTrack; }
2017-01-07 01:58:05 +00:00
int CWorld::IGetAreaCount() const { return x18_areas.size(); }
bool CWorld::DoesAreaExist(TAreaId area) const { return (area >= 0 && area < x18_areas.size()); }
2017-01-07 01:58:05 +00:00
void CWorld::PropogateAreaChain(CGameArea::EOcclusionState occlusionState, CGameArea* area, CWorld* world)
2016-04-24 02:46:13 +00:00
{
2017-01-07 01:58:05 +00:00
if (!area->GetPostConstructed() || occlusionState == area->GetOcclusionState())
return;
2016-04-24 02:46:13 +00:00
if (occlusionState == CGameArea::EOcclusionState::Visible)
area->SetOcclusionState(CGameArea::EOcclusionState::Visible);
2017-01-07 01:58:05 +00:00
for (CGameArea& areaItr : *world)
2017-01-07 01:58:05 +00:00
{
if (&areaItr == area)
2017-01-07 01:58:05 +00:00
continue;
if (areaItr.IsPostConstructed() && areaItr.GetOcclusionState() == CGameArea::EOcclusionState::Visible)
2017-11-05 02:08:05 +00:00
areaItr.OtherAreaOcclusionChanged();
2017-01-07 01:58:05 +00:00
}
for (CGameArea& areaItr : *world)
2017-01-07 01:58:05 +00:00
{
if (&areaItr == area)
2017-01-07 01:58:05 +00:00
continue;
if (areaItr.IsPostConstructed() && areaItr.GetOcclusionState() == CGameArea::EOcclusionState::Occluded)
2017-11-05 02:08:05 +00:00
areaItr.OtherAreaOcclusionChanged();
2017-01-07 01:58:05 +00:00
}
if (occlusionState == CGameArea::EOcclusionState::Occluded)
area->SetOcclusionState(CGameArea::EOcclusionState::Occluded);
2017-01-07 01:58:05 +00:00
}
2017-03-24 05:30:16 +00:00
void CWorld::Update(float dt)
{
xc4_neededFx = EEnvFxType::None;
2017-11-12 05:14:57 +00:00
CAssetId overrideSkyId;
bool needsSky = false;
2017-11-12 05:14:57 +00:00
bool skyVisible = false;
2017-03-24 05:30:16 +00:00
2017-11-12 05:14:57 +00:00
u32 areaCount = 0;
for (CGameArea* head = x4c_chainHeads[3] ;
head != skGlobalNonConstEnd ;
2017-11-12 05:14:57 +00:00
head = head->x130_next, ++areaCount)
{
head->AliveUpdate(dt);
if (head->DoesAreaNeedSkyNow())
{
const CScriptAreaAttributes* attrs = head->GetPostConstructed()->x10d8_areaAttributes;
if (attrs && attrs->GetSkyModel().IsValid())
2017-11-12 05:14:57 +00:00
overrideSkyId = attrs->GetSkyModel();
needsSky = true;
2017-11-12 05:14:57 +00:00
CGameArea::EOcclusionState occlusionState = (head->IsPostConstructed()
? head->GetPostConstructed()->x10dc_occlusionState
: CGameArea::EOcclusionState::Occluded);
2017-11-12 05:14:57 +00:00
if (occlusionState == CGameArea::EOcclusionState::Visible)
skyVisible = true;
}
EEnvFxType envFxType = head->DoesAreaNeedEnvFx();
if (envFxType != EEnvFxType::None)
xc4_neededFx = envFxType;
}
2017-11-12 05:14:57 +00:00
if (areaCount == 0)
return;
2017-11-12 05:14:57 +00:00
if (overrideSkyId.IsValid() && needsSky)
{
2017-11-12 05:14:57 +00:00
x70_26_skyboxActive = true;
x70_27_skyboxVisible = skyVisible;
xb4_skyboxOverride = g_SimplePool->GetObj({SBIG('CMDL'), overrideSkyId});
xa4_skyboxWorldLoaded = TLockedToken<CModel>();
if (x94_skyboxWorld)
x94_skyboxWorld.Unlock();
}
else
{
xb4_skyboxOverride = TLockedToken<CModel>();
if (!x94_skyboxWorld)
{
x70_26_skyboxActive = false;
x70_27_skyboxVisible = false;
}
else if (!needsSky)
{
xa4_skyboxWorldLoaded = TLockedToken<CModel>();
x94_skyboxWorld.Unlock();
x70_26_skyboxActive = false;
x70_27_skyboxVisible = false;
}
else
{
if (!xa4_skyboxWorldLoaded)
{
x94_skyboxWorld.Lock();
if (x94_skyboxWorld.IsLoaded())
{
x94_skyboxWorld->Touch(0);
if (x94_skyboxWorld->IsLoaded(0))
xa4_skyboxWorldLoaded = x94_skyboxWorld;
}
}
x70_26_skyboxActive = true;
x70_27_skyboxVisible = skyVisible;
}
}
2017-03-24 05:30:16 +00:00
}
void CWorld::PreRender()
{
2017-03-04 04:58:33 +00:00
for (CGameArea* head = x4c_chainHeads[3] ;
head != skGlobalNonConstEnd ;
head = head->x130_next)
{
head->PreRender();
}
}
void CWorld::TouchSky()
{
2017-11-27 05:06:53 +00:00
if (xa4_skyboxWorldLoaded.IsLoaded())
xa4_skyboxWorldLoaded->Touch(0);
if (xb4_skyboxOverride.IsLoaded())
xb4_skyboxOverride->Touch(0);
}
void CWorld::DrawSky(const zeus::CTransform& xf) const
{
const CModel* model;
2017-11-12 05:14:57 +00:00
if (xa4_skyboxWorldLoaded)
model = xa4_skyboxWorldLoaded.GetObj();
else if (xb4_skyboxOverride)
model = xb4_skyboxOverride.GetObj();
else
return;
2017-11-12 05:14:57 +00:00
if (!x70_27_skyboxVisible)
return;
CGraphics::DisableAllLights();
CGraphics::SetModelMatrix(xf);
g_Renderer->SetAmbientColor(zeus::CColor::skWhite);
2018-01-06 06:50:42 +00:00
CGraphics::SetDepthRange(DEPTH_SKY, DEPTH_FAR);
CModelFlags flags(0, 0, 1, zeus::CColor::skWhite);
model->Draw(flags);
2018-01-06 06:50:42 +00:00
CGraphics::SetDepthRange(DEPTH_WORLD, DEPTH_FAR);
}
2017-07-07 12:23:20 +00:00
2017-11-27 05:06:53 +00:00
void CWorld::StopGlobalSound(u16 id)
2017-07-07 12:23:20 +00:00
{
2017-11-27 05:06:53 +00:00
auto search = std::find_if(xc8_globalSfxHandles.begin(), xc8_globalSfxHandles.end(),
[id](CSfxHandle& hnd) { return hnd->GetSfxId() == id; });
if (search != xc8_globalSfxHandles.end())
{
CSfxManager::RemoveEmitter(*search);
xc8_globalSfxHandles.erase(search);
}
}
bool CWorld::HasGlobalSound(u16 id) const
{
auto search = std::find_if(xc8_globalSfxHandles.begin(), xc8_globalSfxHandles.end(),
[id](const CSfxHandle& hnd) { return hnd->GetSfxId() == id; });
return search != xc8_globalSfxHandles.end();
}
void CWorld::AddGlobalSound(const CSfxHandle& hnd)
{
if (xc8_globalSfxHandles.size() >= xc8_globalSfxHandles.capacity())
return;
xc8_globalSfxHandles.push_back(hnd);
2017-07-07 12:23:20 +00:00
}
bool CWorld::AreSkyNeedsMet() const
{
if (!x70_26_skyboxActive)
return true;
if (xb4_skyboxOverride && xb4_skyboxOverride->IsLoaded(0))
return true;
if (xa4_skyboxWorldLoaded && xa4_skyboxWorldLoaded->IsLoaded(0))
return true;
if (x94_skyboxWorld && x94_skyboxWorld->IsLoaded(0))
return true;
return false;
}
2016-04-24 02:46:13 +00:00
}