From 8f525b571be08c0ebba83c3266e57ce936e7a251 Mon Sep 17 00:00:00 2001 From: Hyper <34012267+hyperbx@users.noreply.github.com> Date: Mon, 25 Nov 2024 10:50:10 +0000 Subject: [PATCH 1/8] Implemented guest-to-host function pointers (#7) * Implemented guest-to-host function pointers (WIP) Co-Authored-By: Skyth (Asilkan) <19259897+blueskythlikesclouds@users.noreply.github.com> * function: support more types for function pointers * api: ported BlueBlur headers and misc. research * Move over function-pointers changes from options-menu branch. --------- Co-authored-by: Skyth (Asilkan) <19259897+blueskythlikesclouds@users.noreply.github.com> --- UnleashedRecomp/api/CSD/Manager/csdmBase.h | 6 + .../api/CSD/Manager/csdmMotionPattern.h | 8 + UnleashedRecomp/api/CSD/Manager/csdmNode.h | 33 ++ UnleashedRecomp/api/CSD/Manager/csdmNode.inl | 51 ++ .../api/CSD/Manager/csdmNodeObserver.h | 10 + .../api/CSD/Manager/csdmObserverBase.h | 23 + .../api/CSD/Manager/csdmObserverBase.inl | 8 + UnleashedRecomp/api/CSD/Manager/csdmProject.h | 31 ++ .../api/CSD/Manager/csdmProject.inl | 40 ++ .../api/CSD/Manager/csdmRCObject.h | 28 ++ .../api/CSD/Manager/csdmRCObject.inl | 35 ++ .../api/CSD/Manager/csdmRCObjectImp.h | 9 + .../api/CSD/Manager/csdmRCObjectImp.inl | 14 + UnleashedRecomp/api/CSD/Manager/csdmRCPtr.h | 32 ++ UnleashedRecomp/api/CSD/Manager/csdmRCPtr.inl | 45 ++ .../api/CSD/Manager/csdmRCPtrAbs.h | 42 ++ .../api/CSD/Manager/csdmRCPtrAbs.inl | 58 +++ .../api/CSD/Manager/csdmResourceBase.h | 26 + .../api/CSD/Manager/csdmResourceBase.inl | 15 + UnleashedRecomp/api/CSD/Manager/csdmScene.h | 53 +++ UnleashedRecomp/api/CSD/Manager/csdmScene.inl | 53 +++ .../api/CSD/Manager/csdmSceneObserver.h | 10 + .../api/CSD/Manager/csdmSubjectBase.h | 25 + .../api/CSD/Manager/csdmSubjectBase.inl | 14 + UnleashedRecomp/api/CSD/Platform/csdTexList.h | 23 + .../api/CSD/Platform/csdTexList.inl | 7 + .../api/Hedgehog/Base/System/hhAllocator.h | 36 ++ .../api/Hedgehog/Base/Thread/hhHolder.h | 20 + .../api/Hedgehog/Base/Thread/hhHolderBase.h | 28 ++ .../Base/Thread/hhSynchronizedObject.h | 12 + .../Hedgehog/Base/Thread/hhSynchronizedPtr.h | 27 ++ .../Base/Type/detail/hhStringHolder.h | 44 ++ .../Base/Type/detail/hhStringHolder.inl | 134 ++++++ .../api/Hedgehog/Base/Type/hhSharedString.h | 88 ++++ .../api/Hedgehog/Base/Type/hhSharedString.inl | 444 ++++++++++++++++++ UnleashedRecomp/api/Hedgehog/Base/hhObject.h | 23 + .../Hedgehog/Database/System/hhDatabaseData.h | 39 ++ .../Database/System/hhDatabaseData.inl | 36 ++ UnleashedRecomp/api/Hedgehog/Math/Vector2.h | 13 + .../MirageCore/Renderable/hhRenderable.h | 14 + .../Hedgehog/Universe/Engine/hhMessageActor.h | 14 + .../Universe/Engine/hhMessageProcess.h | 14 + .../Hedgehog/Universe/Engine/hhUpdateInfo.h | 13 + .../Hedgehog/Universe/Engine/hhUpdateUnit.h | 25 + .../Hedgehog/Universe/Thread/hhParallelJob.h | 21 + UnleashedRecomp/api/SWA.h | 58 +++ UnleashedRecomp/api/SWA.inl | 7 + .../api/SWA/CSD/CsdDatabaseWrapper.h | 25 + .../api/SWA/CSD/CsdDatabaseWrapper.inl | 9 + UnleashedRecomp/api/SWA/CSD/CsdProject.h | 18 + .../api/SWA/CSD/CsdTexListMirage.h | 18 + UnleashedRecomp/api/SWA/CSD/GameObjectCSD.h | 20 + UnleashedRecomp/api/SWA/Camera/Camera.h | 11 +- .../api/SWA/HUD/GeneralWindow/GeneralWindow.h | 18 + UnleashedRecomp/api/SWA/HUD/Loading/Loading.h | 30 ++ UnleashedRecomp/api/SWA/HUD/Pause/HudPause.h | 67 +++ .../api/SWA/HUD/Sonic/HudSonicStage.h | 22 + .../api/SWA/Movie/MovieDisplayer.h | 14 + UnleashedRecomp/api/SWA/Movie/MovieManager.h | 17 + .../api/SWA/Movie/MovieManager.inl | 7 + .../Player/Character/EvilSonic/EvilSonic.h | 2 +- .../Character/EvilSonic/Hud/EvilHudGuide.h | 7 +- .../api/SWA/Sequence/Unit/SequenceUnitBase.h | 13 + .../SWA/Sequence/Unit/SequenceUnitPlayMovie.h | 8 + .../Utility/SequencePlayMovieWrapper.h | 39 ++ UnleashedRecomp/api/SWA/Sound/Sound.h | 56 +++ .../api/SWA/Sound/SoundBGMActSonic.h | 21 + UnleashedRecomp/api/SWA/Sound/SoundBGMBase.h | 15 + UnleashedRecomp/api/SWA/System/Application.h | 21 + .../api/SWA/System/ApplicationD3D9.h | 8 + .../api/SWA/System/ApplicationDocument.h | 42 +- .../api/SWA/System/ApplicationXenon.h | 12 + UnleashedRecomp/api/SWA/System/Game.h | 10 + UnleashedRecomp/api/SWA/System/GameDocument.h | 15 +- .../api/SWA/System/GameMode/GameMode.h | 13 + .../api/SWA/System/GameMode/GameModeStage.h | 13 + .../SWA/System/GameMode/GameModeStageMovie.h | 20 + .../api/SWA/System/GameMode/Title/TitleMenu.h | 13 + .../System/GameMode/Title/TitleStateBase.h | 22 + UnleashedRecomp/api/SWA/System/GameObject.h | 27 ++ UnleashedRecomp/api/SWA/System/InputState.h | 6 +- UnleashedRecomp/api/SWA/System/InputState.inl | 2 +- UnleashedRecomp/api/SWA/System/PadState.h | 6 +- UnleashedRecomp/api/SWA/System/World.h | 20 + .../api/boost/smart_ptr/make_shared_object.h | 12 + .../api/boost/smart_ptr/shared_ptr.h | 164 +++++++ UnleashedRecomp/cpu/guest_stack_var.h | 123 +++++ UnleashedRecomp/gpu/video.cpp | 40 +- UnleashedRecomp/kernel/function.h | 174 ++++++- UnleashedRecomp/kernel/heap.h | 1 - UnleashedRecomp/kernel/memory.h | 6 + UnleashedRecomp/stdafx.h | 1 + thirdparty/PowerRecomp | 2 +- 93 files changed, 2957 insertions(+), 62 deletions(-) create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmBase.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmMotionPattern.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmNode.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmNode.inl create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmNodeObserver.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmObserverBase.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmObserverBase.inl create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmProject.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmProject.inl create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmRCObject.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmRCObject.inl create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmRCObjectImp.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmRCObjectImp.inl create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmRCPtr.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmRCPtr.inl create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmRCPtrAbs.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmRCPtrAbs.inl create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmResourceBase.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmResourceBase.inl create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmScene.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmScene.inl create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmSceneObserver.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmSubjectBase.h create mode 100644 UnleashedRecomp/api/CSD/Manager/csdmSubjectBase.inl create mode 100644 UnleashedRecomp/api/CSD/Platform/csdTexList.h create mode 100644 UnleashedRecomp/api/CSD/Platform/csdTexList.inl create mode 100644 UnleashedRecomp/api/Hedgehog/Base/System/hhAllocator.h create mode 100644 UnleashedRecomp/api/Hedgehog/Base/Thread/hhHolder.h create mode 100644 UnleashedRecomp/api/Hedgehog/Base/Thread/hhHolderBase.h create mode 100644 UnleashedRecomp/api/Hedgehog/Base/Thread/hhSynchronizedObject.h create mode 100644 UnleashedRecomp/api/Hedgehog/Base/Thread/hhSynchronizedPtr.h create mode 100644 UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.h create mode 100644 UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.inl create mode 100644 UnleashedRecomp/api/Hedgehog/Base/Type/hhSharedString.h create mode 100644 UnleashedRecomp/api/Hedgehog/Base/Type/hhSharedString.inl create mode 100644 UnleashedRecomp/api/Hedgehog/Base/hhObject.h create mode 100644 UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.h create mode 100644 UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.inl create mode 100644 UnleashedRecomp/api/Hedgehog/Math/Vector2.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/Renderable/hhRenderable.h create mode 100644 UnleashedRecomp/api/Hedgehog/Universe/Engine/hhMessageActor.h create mode 100644 UnleashedRecomp/api/Hedgehog/Universe/Engine/hhMessageProcess.h create mode 100644 UnleashedRecomp/api/Hedgehog/Universe/Engine/hhUpdateInfo.h create mode 100644 UnleashedRecomp/api/Hedgehog/Universe/Engine/hhUpdateUnit.h create mode 100644 UnleashedRecomp/api/Hedgehog/Universe/Thread/hhParallelJob.h create mode 100644 UnleashedRecomp/api/SWA/CSD/CsdDatabaseWrapper.h create mode 100644 UnleashedRecomp/api/SWA/CSD/CsdDatabaseWrapper.inl create mode 100644 UnleashedRecomp/api/SWA/CSD/CsdProject.h create mode 100644 UnleashedRecomp/api/SWA/CSD/CsdTexListMirage.h create mode 100644 UnleashedRecomp/api/SWA/CSD/GameObjectCSD.h create mode 100644 UnleashedRecomp/api/SWA/HUD/GeneralWindow/GeneralWindow.h create mode 100644 UnleashedRecomp/api/SWA/HUD/Loading/Loading.h create mode 100644 UnleashedRecomp/api/SWA/HUD/Pause/HudPause.h create mode 100644 UnleashedRecomp/api/SWA/HUD/Sonic/HudSonicStage.h create mode 100644 UnleashedRecomp/api/SWA/Movie/MovieDisplayer.h create mode 100644 UnleashedRecomp/api/SWA/Movie/MovieManager.h create mode 100644 UnleashedRecomp/api/SWA/Movie/MovieManager.inl create mode 100644 UnleashedRecomp/api/SWA/Sequence/Unit/SequenceUnitBase.h create mode 100644 UnleashedRecomp/api/SWA/Sequence/Unit/SequenceUnitPlayMovie.h create mode 100644 UnleashedRecomp/api/SWA/Sequence/Utility/SequencePlayMovieWrapper.h create mode 100644 UnleashedRecomp/api/SWA/Sound/Sound.h create mode 100644 UnleashedRecomp/api/SWA/Sound/SoundBGMActSonic.h create mode 100644 UnleashedRecomp/api/SWA/Sound/SoundBGMBase.h create mode 100644 UnleashedRecomp/api/SWA/System/Application.h create mode 100644 UnleashedRecomp/api/SWA/System/ApplicationD3D9.h create mode 100644 UnleashedRecomp/api/SWA/System/ApplicationXenon.h create mode 100644 UnleashedRecomp/api/SWA/System/Game.h create mode 100644 UnleashedRecomp/api/SWA/System/GameMode/GameMode.h create mode 100644 UnleashedRecomp/api/SWA/System/GameMode/GameModeStage.h create mode 100644 UnleashedRecomp/api/SWA/System/GameMode/GameModeStageMovie.h create mode 100644 UnleashedRecomp/api/SWA/System/GameMode/Title/TitleMenu.h create mode 100644 UnleashedRecomp/api/SWA/System/GameMode/Title/TitleStateBase.h create mode 100644 UnleashedRecomp/api/SWA/System/GameObject.h create mode 100644 UnleashedRecomp/api/SWA/System/World.h create mode 100644 UnleashedRecomp/api/boost/smart_ptr/make_shared_object.h create mode 100644 UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h create mode 100644 UnleashedRecomp/cpu/guest_stack_var.h diff --git a/UnleashedRecomp/api/CSD/Manager/csdmBase.h b/UnleashedRecomp/api/CSD/Manager/csdmBase.h new file mode 100644 index 00000000..d2ffca59 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmBase.h @@ -0,0 +1,6 @@ +#pragma once + +namespace Chao::CSD +{ + class CBase {}; +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmMotionPattern.h b/UnleashedRecomp/api/CSD/Manager/csdmMotionPattern.h new file mode 100644 index 00000000..dd5df27b --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmMotionPattern.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace Chao::CSD +{ + class CMotionPattern : CBase {}; +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmNode.h b/UnleashedRecomp/api/CSD/Manager/csdmNode.h new file mode 100644 index 00000000..08942f7a --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmNode.h @@ -0,0 +1,33 @@ +#pragma once + +#include "SWA.inl" +#include "CSD/Manager/csdmBase.h" +#include "CSD/Manager/csdmResourceBase.h" +#include "CSD/Manager/csdmNodeObserver.h" +#include "CSD/Manager/csdmSubjectBase.h" + +namespace Chao::CSD +{ + struct Node; + + class CNode : public CResourceBase, SubjectBase, CBase + { + public: + SWA_INSERT_PADDING(0x34); + xpointer m_pMotionPattern; + SWA_INSERT_PADDING(0x18); + + ~CNode(); + + void SetText(const char* in_pText); + void SetText(const wchar_t* in_pText); + Hedgehog::Math::CVector2* GetPosition() const; + void SetPosition(float in_X, float in_Y); + void SetHideFlag(uint32_t in_HideFlag); + void SetRotation(float in_Rotation); + void SetScale(float in_X, float in_Y); + void SetPatternIndex(uint32_t in_PatternIndex); + }; +} + +#include "CSD/Manager/csdmNode.inl" diff --git a/UnleashedRecomp/api/CSD/Manager/csdmNode.inl b/UnleashedRecomp/api/CSD/Manager/csdmNode.inl new file mode 100644 index 00000000..92e64079 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmNode.inl @@ -0,0 +1,51 @@ +#include "SWA.inl" + +namespace Chao::CSD +{ + inline CNode::~CNode() + { + SWA_VIRTUAL_FUNCTION(void, 0, this); + } + + inline void CNode::SetText(const char* in_pText) + { + GuestToHostFunction(0x830BF640, this, in_pText); + } + + inline void CNode::SetText(const wchar_t* in_pText) + { + GuestToHostFunction(0x830BF640, this, in_pText); + } + + inline Hedgehog::Math::CVector2* CNode::GetPosition() const + { + guest_stack_var pos; + GuestToHostFunction(0x830BF008, pos.get(), this); + return pos.get(); + } + + inline void CNode::SetPosition(float in_X, float in_Y) + { + GuestToHostFunction(0x830BF078, this, in_X, in_Y); + } + + inline void CNode::SetHideFlag(uint32_t in_HideFlag) + { + GuestToHostFunction(0x830BF080, this, in_HideFlag); + } + + inline void CNode::SetRotation(float in_Rotation) + { + GuestToHostFunction(0x830BF088, this, in_Rotation); + } + + inline void CNode::SetScale(float in_X, float in_Y) + { + GuestToHostFunction(0x830BF090, this, in_X, in_Y); + } + + inline void CNode::SetPatternIndex(uint32_t in_PatternIndex) + { + GuestToHostFunction(0x830BF300, this, in_PatternIndex); + } +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmNodeObserver.h b/UnleashedRecomp/api/CSD/Manager/csdmNodeObserver.h new file mode 100644 index 00000000..abfba980 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmNodeObserver.h @@ -0,0 +1,10 @@ +#pragma once + +#include "CSD/Manager/csdmObserverBase.h" + +namespace Chao::CSD +{ + class CNode; + + class CNodeObserver : public CObserverBase {}; +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmObserverBase.h b/UnleashedRecomp/api/CSD/Manager/csdmObserverBase.h new file mode 100644 index 00000000..63daf398 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmObserverBase.h @@ -0,0 +1,23 @@ +#pragma once + +#include "SWA.inl" + +namespace Chao::CSD +{ + template + class CObserverBase + { + public: + struct Vftable + { + be m_fpDtor; + }; + + xpointer m_pVftable; + SWA_INSERT_PADDING(0x08); + + ~CObserverBase(); + }; +} + +#include "CSD/Manager/csdmObserverBase.inl" diff --git a/UnleashedRecomp/api/CSD/Manager/csdmObserverBase.inl b/UnleashedRecomp/api/CSD/Manager/csdmObserverBase.inl new file mode 100644 index 00000000..beeabb4f --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmObserverBase.inl @@ -0,0 +1,8 @@ +namespace Chao::CSD +{ + template + inline CObserverBase::~CObserverBase() + { + GuestToHostFunction(m_pVftable->m_fpDtor, this); + } +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmProject.h b/UnleashedRecomp/api/CSD/Manager/csdmProject.h new file mode 100644 index 00000000..ed01cd3b --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmProject.h @@ -0,0 +1,31 @@ +#pragma once + +#include "SWA.inl" +#include "CSD/Manager/csdmBase.h" +#include "CSD/Manager/csdmResourceBase.h" + +namespace Chao::CSD +{ + struct Project; + class CProject; + class CScene; + class CTexList; + + class CProject : public CResourceBase, CBase + { + public: + SWA_INSERT_PADDING(0x1C); + RCPtr m_rcTexList; + SWA_INSERT_PADDING(0x1C); + + RCPtr CreateScene(const char* in_pName) const; + RCPtr CreateScene(const char* in_pName, const char* in_pMotionName) const; + + void DestroyScene(CScene* in_pScene); + void DestroyScene(RCPtr& inout_rcScene); + + static void DestroyScene(CProject* in_pProject, RCPtr& inout_rcScene); + }; +} + +#include "CSD/Manager/csdmProject.inl" diff --git a/UnleashedRecomp/api/CSD/Manager/csdmProject.inl b/UnleashedRecomp/api/CSD/Manager/csdmProject.inl new file mode 100644 index 00000000..c579789e --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmProject.inl @@ -0,0 +1,40 @@ +#include "kernel/function.h" + +namespace Chao::CSD +{ + inline RCPtr CProject::CreateScene(const char* in_pName) const + { + RCPtr rcScene; + GuestToHostFunction(0x830BEE00, this, rcScene, in_pName, nullptr); + return rcScene; + } + + inline RCPtr CProject::CreateScene(const char* in_pName, const char* in_pMotionName) const + { + RCPtr rcScene; + GuestToHostFunction(0x830BECE0, this, rcScene, in_pName, in_pMotionName, nullptr); + return rcScene; + } + + inline void CProject::DestroyScene(CScene* in_pScene) + { + GuestToHostFunction(0x830BE298, this, in_pScene); + } + + inline void CProject::DestroyScene(RCPtr& inout_rcScene) + { + if (!inout_rcScene) + return; + + DestroyScene(inout_rcScene.Get()); + inout_rcScene = nullptr; + } + + inline void CProject::DestroyScene(CProject* in_pProject, RCPtr& inout_rcScene) + { + if (in_pProject) + in_pProject->DestroyScene(inout_rcScene); + else + inout_rcScene = nullptr; + } +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmRCObject.h b/UnleashedRecomp/api/CSD/Manager/csdmRCObject.h new file mode 100644 index 00000000..143dcb07 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmRCObject.h @@ -0,0 +1,28 @@ +#pragma once + +#include "CSD/Manager/csdmRCPtrAbs.h" + +namespace Chao::CSD +{ + class RCPtrAbs::RCObject + { + public: + struct Vftable + { + be m_fpDtor; + be m_fpDeallocate; + }; + + xpointer m_pVftable; + xpointer m_pMemory; + be m_RefCount; + xpointer m_pDealloctor; + be m_eDealloctor; + + ~RCObject(); + void Deallocate(void* in_pMemory); + void Release(); + }; +} + +#include "CSD/Manager/csdmRCObject.inl" diff --git a/UnleashedRecomp/api/CSD/Manager/csdmRCObject.inl b/UnleashedRecomp/api/CSD/Manager/csdmRCObject.inl new file mode 100644 index 00000000..60909972 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmRCObject.inl @@ -0,0 +1,35 @@ +namespace Chao::CSD +{ + inline RCPtrAbs::RCObject::~RCObject() + { + GuestToHostFunction(m_pVftable->m_fpDtor, this); + } + + inline RCPtrAbs::~RCPtrAbs() + { + RCPtrAbs::RCObject* pObj = m_pObject; + + m_pObject = nullptr; + + if (pObj) + pObj->Release(); + } + + inline void* RCPtrAbs::GetAbs() const + { + if (!m_pObject) + return nullptr; + + return m_pObject->m_pMemory; + } + + inline void RCPtrAbs::RCObject::Deallocate(void* in_pMemory) + { + GuestToHostFunction(m_pVftable->m_fpDeallocate, this, in_pMemory); + } + + inline void RCPtrAbs::RCObject::Release() + { + GuestToHostFunction(0x830BA068, this); + } +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmRCObjectImp.h b/UnleashedRecomp/api/CSD/Manager/csdmRCObjectImp.h new file mode 100644 index 00000000..aa814cfa --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmRCObjectImp.h @@ -0,0 +1,9 @@ +#pragma once + +#include "CSD/Manager/csdmRCPtr.h" + +namespace Chao::CSD +{ + template + class RCPtr::RCObjectImp : public RCObject {}; +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmRCObjectImp.inl b/UnleashedRecomp/api/CSD/Manager/csdmRCObjectImp.inl new file mode 100644 index 00000000..74465e61 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmRCObjectImp.inl @@ -0,0 +1,14 @@ +namespace Chao::CSD +{ + template + void RCPtr::RCObjectImp::Deallocate(void* in_pMemory) + { + // delete static_cast(in_pMemory); + } + + template + RCPtrAbs::RCObject* RCPtr::CreateRCObject() + { + return new RCObjectImp(); + } +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmRCPtr.h b/UnleashedRecomp/api/CSD/Manager/csdmRCPtr.h new file mode 100644 index 00000000..10878100 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmRCPtr.h @@ -0,0 +1,32 @@ +#pragma once + +#include "CSD/Manager/csdmRCPtrAbs.h" + +namespace Chao::CSD +{ + template + class RCPtr : RCPtrAbs + { + public: + class RCObjectImp; + + RCPtr() : RCPtrAbs() {} + RCPtr(T* in_pMemory) : RCPtrAbs(in_pMemory) {} + RCPtr(const RCPtr& in_rOther) : RCPtrAbs(in_rOther) {} + RCPtr(RCPtr&& in_rOther) : RCPtrAbs(std::move(in_rOther)) {} + + void Attach(T* in_pObject); + + T* Get() const; + void Set(const RCPtr& in_rOther); + + T* operator*() const; + T* operator->() const; + + RCPtr& operator=(const RCPtr& in_rOther); + + operator bool() const; + }; +} + +#include "CSD/Manager/csdmRCPtr.inl" diff --git a/UnleashedRecomp/api/CSD/Manager/csdmRCPtr.inl b/UnleashedRecomp/api/CSD/Manager/csdmRCPtr.inl new file mode 100644 index 00000000..01bcd6e1 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmRCPtr.inl @@ -0,0 +1,45 @@ +namespace Chao::CSD +{ + template + void RCPtr::Attach(T* in_pObject) + { + RCPtrAbs::AttachAbs(in_pObject); + } + + template + T* RCPtr::Get() const + { + return static_cast(RCPtrAbs::GetAbs()); + } + + template + void RCPtr::Set(const RCPtr& in_rOther) + { + RCPtrAbs::SetAbs(in_rOther); + } + + template + T* RCPtr::operator*() const + { + return Get(); + } + + template + T* RCPtr::operator->() const + { + return Get(); + } + + template + RCPtr& RCPtr::operator=(const RCPtr& in_rOther) + { + Set(in_rOther); + return *this; + } + + template + RCPtr::operator bool() const + { + return m_pObject != nullptr; + } +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmRCPtrAbs.h b/UnleashedRecomp/api/CSD/Manager/csdmRCPtrAbs.h new file mode 100644 index 00000000..e1e46be8 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmRCPtrAbs.h @@ -0,0 +1,42 @@ +#pragma once + +#include "SWA.inl" + +namespace Chao::CSD +{ + class RCPtrAbs + { + public: + class RCObject; + + struct Vftable + { + be m_fpDtor; + be m_fpCreateRCObject; + }; + + xpointer m_pVftable; + xpointer m_pObject; + + RCPtrAbs(); + RCPtrAbs(void* in_pMemory); + RCPtrAbs(const RCPtrAbs& in_rOther); + RCPtrAbs(RCPtrAbs&& in_rPtr); + + ~RCPtrAbs(); + RCObject* CreateRCObject(); + + void AttachAbs(void* in_pMemory); + void* GetAbs() const; + void SetAbs(const RCPtrAbs& in_rPtr); + + void* operator*() const; + void* operator->() const; + + RCPtrAbs& operator=(const RCPtrAbs& in_rPtr); + + operator bool() const; + }; +} + +#include "CSD/Manager/csdmRCPtrAbs.inl" diff --git a/UnleashedRecomp/api/CSD/Manager/csdmRCPtrAbs.inl b/UnleashedRecomp/api/CSD/Manager/csdmRCPtrAbs.inl new file mode 100644 index 00000000..2925fc54 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmRCPtrAbs.inl @@ -0,0 +1,58 @@ +namespace Chao::CSD +{ + inline RCPtrAbs::RCPtrAbs() + { + AttachAbs(nullptr); + } + + inline RCPtrAbs::RCPtrAbs(void* in_pMemory) + { + AttachAbs(in_pMemory); + } + + inline RCPtrAbs::RCPtrAbs(const RCPtrAbs& in_rOther) + { + SetAbs(in_rOther); + } + + inline RCPtrAbs::RCPtrAbs(RCPtrAbs&& in_rPtr) : m_pObject(in_rPtr.m_pObject) + { + in_rPtr.m_pObject = nullptr; + } + + inline RCPtrAbs::RCObject* RCPtrAbs::CreateRCObject() + { + return GuestToHostFunction(m_pVftable->m_fpCreateRCObject, this); + } + + inline void RCPtrAbs::AttachAbs(void* in_pMemory) + { + GuestToHostFunction(0x830BA298, this, in_pMemory); + } + + inline void RCPtrAbs::SetAbs(const RCPtrAbs& in_rPtr) + { + GuestToHostFunction(0x830BA328, this, in_rPtr); + } + + inline void* RCPtrAbs::operator*() const + { + return GetAbs(); + } + + inline void* RCPtrAbs::operator->() const + { + return GetAbs(); + } + + inline RCPtrAbs& RCPtrAbs::operator=(const RCPtrAbs& in_rPtr) + { + SetAbs(in_rPtr); + return *this; + } + + inline RCPtrAbs::operator bool() const + { + return m_pObject != nullptr; + } +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmResourceBase.h b/UnleashedRecomp/api/CSD/Manager/csdmResourceBase.h new file mode 100644 index 00000000..094ed06f --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmResourceBase.h @@ -0,0 +1,26 @@ +#pragma once + +#include "CSD/Manager/csdmRCPtr.h" + +namespace Chao::CSD +{ + template + class CResourceBase + { + public: + struct Vftable + { + be m_fpDtor; + be m_fpCopyResource; + }; + + xpointer m_pVftable; + RCPtr m_rcResourceHolder; + xpointer m_pResource; + + ~CResourceBase(); + void CopyResource(const CResourceBase& in_rOther); + }; +} + +#include "CSD/Manager/csdmResourceBase.h" diff --git a/UnleashedRecomp/api/CSD/Manager/csdmResourceBase.inl b/UnleashedRecomp/api/CSD/Manager/csdmResourceBase.inl new file mode 100644 index 00000000..d459e3c9 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmResourceBase.inl @@ -0,0 +1,15 @@ +namespace Chao::CSD +{ + template + inline CResourceBase::~CResourceBase() + { + GuestToHostFunction(m_pVftable->m_fpDtor, this); + } + + template + inline void CResourceBase::CopyResource(const CResourceBase& in_rOther) + { + m_rcResourceHolder = in_rOther.m_rcResourceHolder; + m_pResource = in_rOther.m_pResource; + } +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmScene.h b/UnleashedRecomp/api/CSD/Manager/csdmScene.h new file mode 100644 index 00000000..e26f2b91 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmScene.h @@ -0,0 +1,53 @@ +#pragma once + +#include "SWA.inl" +#include "CSD/Manager/csdmBase.h" +#include "CSD/Manager/csdmResourceBase.h" +#include "CSD/Manager/csdmSceneObserver.h" +#include "CSD/Manager/csdmSubjectBase.h" + +namespace Chao::CSD +{ + struct Scene; + class CScene; + class CNode; + + enum EMotionRepeatType : uint32_t + { + eMotionRepeatType_PlayOnce = 0, + eMotionRepeatType_Loop = 1, + eMotionRepeatType_PingPong = 2, + eMotionRepeatType_PlayThenDestroy = 3 + }; + + class CScene : public CResourceBase, SubjectBase, CBase + { + public: + SWA_INSERT_PADDING(0x60); + be m_PrevMotionFrame; + be m_MotionFrame; + be m_MotionSpeed; + be m_MotionStartFrame; + be m_MotionEndFrame; + SWA_INSERT_PADDING(0x0C); + be m_MotionDisableFlag; + SWA_INSERT_PADDING(0x10); + be m_MotionRepeatType; + SWA_INSERT_PADDING(0x2C); + + ~CScene(); + void Update(float in_DeltaTime = 0.0f); + void Render(void* in_pUnk); + + void GetNode(RCPtr& out_rResult, const char* in_pName); + + bool SetMotion(const char* in_pName); + void SetMotionFrame(float in_MotionFrame); + void SetPosition(float in_X, float in_Y); + void SetHideFlag(uint32_t in_HideFlag); + void SetRotation(float in_Angle); + void SetScale(float in_X, float in_Y); + }; +} + +#include "CSD/Manager/csdmScene.inl" diff --git a/UnleashedRecomp/api/CSD/Manager/csdmScene.inl b/UnleashedRecomp/api/CSD/Manager/csdmScene.inl new file mode 100644 index 00000000..a44a6cda --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmScene.inl @@ -0,0 +1,53 @@ +namespace Chao::CSD +{ + inline CScene::~CScene() + { + SWA_VIRTUAL_FUNCTION(void, 0, this); + } + + inline void CScene::Update(float in_DeltaTime) + { + SWA_VIRTUAL_FUNCTION(void, 2, this, in_DeltaTime); + } + + inline void CScene::Render(void* in_pUnk) + { + SWA_VIRTUAL_FUNCTION(void, 3, this, in_pUnk); + } + + inline void CScene::GetNode(RCPtr& out_rResult, const char* in_pName) + { + GuestToHostFunction(sub_830BCCA8, &out_rResult, this, in_pName); + } + + inline bool CScene::SetMotion(const char* in_pName) + { + return GuestToHostFunction(0x830BA760, this, in_pName); + } + + inline void CScene::SetMotionFrame(float in_MotionFrame) + { + m_PrevMotionFrame = in_MotionFrame; + m_MotionFrame = in_MotionFrame; + } + + inline void CScene::SetPosition(float in_X, float in_Y) + { + GuestToHostFunction(0x830BB550, this, in_X, in_Y); + } + + inline void CScene::SetHideFlag(uint32_t in_HideFlag) + { + GuestToHostFunction(0x830BB378, this, in_HideFlag); + } + + inline void CScene::SetRotation(float in_Angle) + { + GuestToHostFunction(0x830BB5F8, this, in_Angle); + } + + inline void CScene::SetScale(float in_X, float in_Y) + { + GuestToHostFunction(0x830BB650, this, in_X, in_Y); + } +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmSceneObserver.h b/UnleashedRecomp/api/CSD/Manager/csdmSceneObserver.h new file mode 100644 index 00000000..2e6abb2c --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmSceneObserver.h @@ -0,0 +1,10 @@ +#pragma once + +#include "CSD/Manager/csdmObserverBase.h" + +namespace Chao::CSD +{ + class CScene; + + class CSceneObserver : public CObserverBase {}; +} diff --git a/UnleashedRecomp/api/CSD/Manager/csdmSubjectBase.h b/UnleashedRecomp/api/CSD/Manager/csdmSubjectBase.h new file mode 100644 index 00000000..cb420c30 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmSubjectBase.h @@ -0,0 +1,25 @@ +#pragma once + +#include "SWA.inl" + +namespace Chao::CSD +{ + template + class SubjectBase + { + public: + struct Vftable + { + be m_fpDtor; + be m_fpGetObservee; + }; + + xpointer m_pVftable; + SWA_INSERT_PADDING(0x0C); + + ~SubjectBase(); + TObservee* GetObservee() const; + }; +} + +#include "CSD/Manager/csdmSubjectBase.inl" diff --git a/UnleashedRecomp/api/CSD/Manager/csdmSubjectBase.inl b/UnleashedRecomp/api/CSD/Manager/csdmSubjectBase.inl new file mode 100644 index 00000000..9c9b7f8f --- /dev/null +++ b/UnleashedRecomp/api/CSD/Manager/csdmSubjectBase.inl @@ -0,0 +1,14 @@ +namespace Chao::CSD +{ + template + inline SubjectBase::~SubjectBase() + { + GuestToHostFunction(m_pVftable->m_fpDtor, this); + } + + template + inline TObservee* SubjectBase::GetObservee() const + { + return nullptr; + } +} diff --git a/UnleashedRecomp/api/CSD/Platform/csdTexList.h b/UnleashedRecomp/api/CSD/Platform/csdTexList.h new file mode 100644 index 00000000..88fb7c81 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Platform/csdTexList.h @@ -0,0 +1,23 @@ +#pragma once + +#include "CSD/Manager/csdmBase.h" +#include "CSD/Manager/csdmRCPtr.h" + +namespace Chao::CSD +{ + class CTexList : public CBase + { + public: + struct Vftable + { + be m_fpDtor; + }; + + xpointer m_pVftable; + RCPtr m_rcData; + + ~CTexList(); + }; +} + +#include "CSD/Platform/csdTexList.inl" diff --git a/UnleashedRecomp/api/CSD/Platform/csdTexList.inl b/UnleashedRecomp/api/CSD/Platform/csdTexList.inl new file mode 100644 index 00000000..14835026 --- /dev/null +++ b/UnleashedRecomp/api/CSD/Platform/csdTexList.inl @@ -0,0 +1,7 @@ +namespace Chao::CSD +{ + inline CTexList::~CTexList() + { + GuestToHostFunction(m_pVftable->m_fpDtor, this); + } +} diff --git a/UnleashedRecomp/api/Hedgehog/Base/System/hhAllocator.h b/UnleashedRecomp/api/Hedgehog/Base/System/hhAllocator.h new file mode 100644 index 00000000..baa56d99 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/System/hhAllocator.h @@ -0,0 +1,36 @@ +#pragma once + +#include "SWA.inl" + +inline static void* __HH_ALLOC(const uint32_t in_Size) +{ + return GuestToHostFunction(0x82DFA0B0, in_Size, nullptr, 0, 0); +} + +inline static void __HH_FREE(const void* in_pData) +{ + GuestToHostFunction(0x82DF9E50, in_pData); +} + +namespace Hedgehog::Base +{ + template + class TAllocator + { + public: + using value_type = T; + + TAllocator() noexcept {} + template TAllocator(TAllocator const&) noexcept {} + + value_type* allocate(std::size_t n) + { + return reinterpret_cast(__HH_ALLOC(n * sizeof(value_type))); + } + + void deallocate(value_type* p, std::size_t) noexcept + { + __HH_FREE(p); + } + }; +} diff --git a/UnleashedRecomp/api/Hedgehog/Base/Thread/hhHolder.h b/UnleashedRecomp/api/Hedgehog/Base/Thread/hhHolder.h new file mode 100644 index 00000000..1e23c78c --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/Thread/hhHolder.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Hedgehog/Base/Thread/hhHolderBase.h" + +#define HH_BASE_HOLDER(x) \ + Hedgehog::Base::THolder(x) + +namespace Hedgehog::Base +{ + template + class THolder : public CHolderBase + { + public: + THolder(T* in_pObject) : CHolderBase(in_pObject, ForceSync) {} + + T* get() const; + T* operator->() const; + T* operator*() const; + }; +} diff --git a/UnleashedRecomp/api/Hedgehog/Base/Thread/hhHolderBase.h b/UnleashedRecomp/api/Hedgehog/Base/Thread/hhHolderBase.h new file mode 100644 index 00000000..2d5d80a1 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/Thread/hhHolderBase.h @@ -0,0 +1,28 @@ +#pragma once + +#include "SWA.inl" + +namespace Hedgehog::Base +{ + class CSynchronizedObject; + + class CHolderBase + { + protected: + xpointer m_pSynchronizedObject; + bool m_Locked; + + public: + CHolderBase() : m_pSynchronizedObject(nullptr), m_Locked(false) {} + CHolderBase(CSynchronizedObject* in_pSynchronizedObject, bool in_ForceSync = false); + CHolderBase(CHolderBase&& io_rOther); + CHolderBase(const CHolderBase& in_rOther); + ~CHolderBase(); + + CSynchronizedObject* get() const; + CSynchronizedObject* operator->() const; + CSynchronizedObject* operator*() const; + + explicit operator bool() const; + }; +} diff --git a/UnleashedRecomp/api/Hedgehog/Base/Thread/hhSynchronizedObject.h b/UnleashedRecomp/api/Hedgehog/Base/Thread/hhSynchronizedObject.h new file mode 100644 index 00000000..d84df970 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/Thread/hhSynchronizedObject.h @@ -0,0 +1,12 @@ +#pragma once + +#include "SWA.inl" + +namespace Hedgehog::Base +{ + class CSynchronizedObject + { + public: + SWA_INSERT_PADDING(0x04); + }; +} diff --git a/UnleashedRecomp/api/Hedgehog/Base/Thread/hhSynchronizedPtr.h b/UnleashedRecomp/api/Hedgehog/Base/Thread/hhSynchronizedPtr.h new file mode 100644 index 00000000..53889dd1 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/Thread/hhSynchronizedPtr.h @@ -0,0 +1,27 @@ +#pragma once + +#include "SWA.inl" +#include "Hedgehog/Base/Thread/hhHolder.h" + +namespace Hedgehog::Base +{ + template + class TSynchronizedPtr + { + xpointer m_pObject; + + public: + TSynchronizedPtr(T* in_pObject); + TSynchronizedPtr(); + TSynchronizedPtr(const TSynchronizedPtr& in_rOther); + TSynchronizedPtr(TSynchronizedPtr&& io_rOther); + + TSynchronizedPtr& operator=(T* const in_pObject); + + THolder get() const; + THolder operator->() const; + THolder operator*() const; + + explicit operator bool() const; + }; +} diff --git a/UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.h b/UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.h new file mode 100644 index 00000000..087de601 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.h @@ -0,0 +1,44 @@ +#pragma once + +#include "SWA.inl" + +namespace Hedgehog::Base +{ + struct SStringHolder + { + union + { + struct + { + be Length; + be RefCount; + }; + + be RefCountAndLength; + }; + + char aStr[1u]; + + static SStringHolder* GetHolder(const char* in_pStr); + + static size_t GetMemorySize(const size_t in_Length); + static size_t GetMemorySizeAligned(const size_t in_Length); + + static SStringHolder* Make(const char* in_pStr, const size_t in_Length); + + static SStringHolder* Concat( + const char* in_pStrA, const size_t in_LengthA, + const char* in_pStrB, const size_t in_LengthB); + + void AddRef(); + void Release(); + + bool IsUnique() const; + + bool TryInplaceAssign(const char* in_pStr, const size_t in_Length); + bool TryInplaceAppend(const char* in_pStr, const size_t in_Length); + bool TryInplacePrepend(const char* in_pStr, const size_t in_Length); + }; +} + +#include "Hedgehog/Base/Type/detail/hhStringHolder.inl" diff --git a/UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.inl b/UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.inl new file mode 100644 index 00000000..5fede682 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.inl @@ -0,0 +1,134 @@ +namespace Hedgehog::Base +{ + inline SStringHolder* SStringHolder::GetHolder(const char* in_pStr) + { + return (SStringHolder*)((size_t)in_pStr - sizeof(RefCountAndLength)); + } + + inline size_t SStringHolder::GetMemorySize(const size_t in_Length) + { + return sizeof(RefCountAndLength) + in_Length; + } + + inline size_t SStringHolder::GetMemorySizeAligned(const size_t in_Length) + { + return (GetMemorySize(in_Length) + 0x10) & ~0x0F; + } + + inline SStringHolder* SStringHolder::Make(const char* in_pStr, const size_t in_Length) + { + const size_t memSize = GetMemorySize(in_Length); + const size_t memSizeAligned = GetMemorySizeAligned(in_Length); + + auto pHolder = (SStringHolder*)__HH_ALLOC(memSizeAligned); + pHolder->RefCount = 1; + pHolder->Length = (uint16_t)in_Length; + + if (in_pStr) + memcpy(pHolder->aStr, in_pStr, in_Length); + + memset(&pHolder->aStr[in_Length], 0, memSizeAligned - memSize); + + return pHolder; + } + + inline SStringHolder* SStringHolder::Concat(const char* in_pStrA, const size_t in_LengthA, const char* in_pStrB, const size_t in_LengthB) + { + SStringHolder* pHolder = Make(nullptr, in_LengthA + in_LengthB); + + memcpy(pHolder->aStr, in_pStrA, in_LengthA); + memcpy(&pHolder->aStr[in_LengthA], in_pStrB, in_LengthB); + + return pHolder; + } + + inline void SStringHolder::AddRef() + { + uint32_t originalValue, incrementedValue; + do + { + originalValue = RefCountAndLength.value; + incrementedValue = std::byteswap(std::byteswap(originalValue) + 1); + } while (InterlockedCompareExchange(reinterpret_cast(&RefCountAndLength), incrementedValue, originalValue) != originalValue); + } + + inline void SStringHolder::Release() + { + uint32_t originalValue, decrementedValue; + do + { + originalValue = RefCountAndLength.value; + decrementedValue = std::byteswap(std::byteswap(originalValue) - 1); + } while (InterlockedCompareExchange(reinterpret_cast(&RefCountAndLength), decrementedValue, originalValue) != originalValue); + + if (RefCountAndLength == 0) + __HH_FREE(this); + } + + inline bool SStringHolder::IsUnique() const + { + return RefCount == 1; + } + + inline bool SStringHolder::TryInplaceAssign(const char* in_pStr, const size_t in_Length) + { + if (!IsUnique()) + return false; + + const size_t memSizeAligned = GetMemorySizeAligned(in_Length); + + if (memSizeAligned > GetMemorySizeAligned(Length)) + return false; + + if (in_pStr) + memcpy(aStr, in_pStr, in_Length); + + memset(&aStr[in_Length], 0, memSizeAligned - GetMemorySize(in_Length)); + + Length = (uint16_t)in_Length; + + return true; + } + + inline bool SStringHolder::TryInplaceAppend(const char* in_pStr, const size_t in_Length) + { + if (!IsUnique()) + return false; + + const size_t memSizeAligned = GetMemorySizeAligned(Length + in_Length); + + if (memSizeAligned > GetMemorySizeAligned(Length)) + return false; + + if (in_pStr) + memcpy(&aStr[Length], in_pStr, in_Length); + + memset(&aStr[Length + in_Length], 0, memSizeAligned - GetMemorySize(Length + in_Length)); + + Length = (uint16_t)(Length + in_Length); + + return true; + } + + inline bool SStringHolder::TryInplacePrepend(const char* in_pStr, const size_t in_Length) + { + if (!IsUnique()) + return false; + + const size_t memSizeAligned = GetMemorySizeAligned(in_Length + Length); + + if (memSizeAligned > GetMemorySizeAligned(Length)) + return false; + + memmove(&aStr[in_Length], aStr, Length); + + if (in_pStr) + memcpy(aStr, in_pStr, in_Length); + + memset(&aStr[in_Length + Length], 0, memSizeAligned - GetMemorySize(in_Length + Length)); + + Length = (uint16_t)(in_Length + Length); + + return true; + } +} diff --git a/UnleashedRecomp/api/Hedgehog/Base/Type/hhSharedString.h b/UnleashedRecomp/api/Hedgehog/Base/Type/hhSharedString.h new file mode 100644 index 00000000..54a22e5b --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/Type/hhSharedString.h @@ -0,0 +1,88 @@ +#pragma once + +#include + +namespace Hedgehog::Base +{ + class CSharedString + { + private: + xpointer m_pStr; + + SStringHolder* GetHolder() const; + + CSharedString(SStringHolder* in_pHolder); + + public: + static constexpr size_t npos = ~0u; + + CSharedString(); + CSharedString(const char* in_pStr); + CSharedString(const CSharedString& in_rOther); + CSharedString(CSharedString&& io_rOther); + ~CSharedString(); + + const char* get() const; + const char* c_str() const; + const char* data() const; + + size_t size() const; + size_t length() const; + bool empty() const; + + const char* begin() const; + const char* end() const; + + CSharedString substr(size_t pos = 0, size_t len = npos) const; + + size_t find(char c, size_t pos = 0) const; + size_t find(const char* s, size_t pos = 0) const; + size_t rfind(char c, size_t pos = npos) const; + + size_t find_first_of(const char* s, size_t pos = 0) const; + size_t find_last_of(const char* s, size_t pos = npos) const; + size_t find_first_not_of(const char* s, size_t pos = 0) const; + size_t find_last_not_of(const char* s, size_t pos = npos) const; + + size_t find(const CSharedString& str, size_t pos = 0) const; + size_t rfind(const CSharedString& str, size_t pos = npos) const; + + size_t find_first_of(const CSharedString& str, size_t pos = 0) const; + size_t find_last_of(const CSharedString& str, size_t pos = npos) const; + size_t find_first_not_of(const CSharedString& str, size_t pos = 0) const; + size_t find_last_not_of(const CSharedString& str, size_t pos = npos) const; + + void assign(const CSharedString& in_rOther); + void assign(const char* in_pStr); + void assign(CSharedString&& io_rOther); + + void append(const CSharedString& in_rOther); + void append(const char* in_pStr); + + void prepend(const CSharedString& in_rOther); + void prepend(const char* in_pStr); + + int compare(const CSharedString& in_rOther) const; + + CSharedString& operator=(const CSharedString& in_rOther); + CSharedString& operator=(const char* in_pStr); + CSharedString& operator=(CSharedString&& io_rOther); + CSharedString& operator+=(const CSharedString& in_rOther); + CSharedString& operator+=(const char* in_pStr); + + friend CSharedString operator+(const CSharedString& in_rLeft, const CSharedString& in_rRight); + friend CSharedString operator+(const CSharedString& in_rLeft, const char* in_pRight); + friend CSharedString operator+(const char* in_pLeft, const CSharedString& in_pRight); + + bool operator>(const CSharedString& in_rOther) const; + bool operator>=(const CSharedString& in_rOther) const; + bool operator<(const CSharedString& in_rOther) const; + bool operator<=(const CSharedString& in_rOther) const; + bool operator==(const CSharedString& in_rOther) const; + bool operator!=(const CSharedString& in_rOther) const; + bool operator==(const char* in_pOther) const; + bool operator!=(const char* in_pOther) const; + }; +} + +#include diff --git a/UnleashedRecomp/api/Hedgehog/Base/Type/hhSharedString.inl b/UnleashedRecomp/api/Hedgehog/Base/Type/hhSharedString.inl new file mode 100644 index 00000000..67013585 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/Type/hhSharedString.inl @@ -0,0 +1,444 @@ +namespace Hedgehog::Base +{ + inline SStringHolder* CSharedString::GetHolder() const + { + return SStringHolder::GetHolder(m_pStr); + } + + inline CSharedString::CSharedString(SStringHolder* in_pHolder) : m_pStr(in_pHolder->aStr) + { + } + + inline CSharedString::CSharedString() : m_pStr(nullptr) + { + } + + inline CSharedString::CSharedString(const char* in_pStr) : m_pStr(nullptr) + { + size_t length; + + if (in_pStr && (length = strlen(in_pStr)) != 0) + m_pStr.ptr = g_memory.MapVirtual(SStringHolder::Make(in_pStr, length)->aStr); + } + + inline CSharedString::CSharedString(const CSharedString& in_rOther) : m_pStr(in_rOther.m_pStr) + { + GetHolder()->AddRef(); + } + + inline CSharedString::CSharedString(CSharedString&& io_rOther) : m_pStr(io_rOther.m_pStr) + { + io_rOther.m_pStr = nullptr; + } + + inline CSharedString::~CSharedString() + { + GetHolder()->Release(); + } + + inline const char* CSharedString::get() const + { + return m_pStr; + } + + inline const char* CSharedString::c_str() const + { + return get(); + } + + inline const char* CSharedString::data() const + { + return get(); + } + + inline size_t CSharedString::size() const + { + return GetHolder()->Length; + } + + inline size_t CSharedString::length() const + { + return size(); + } + + inline bool CSharedString::empty() const + { + return size() == 0; + } + + inline const char* CSharedString::begin() const + { + return get(); + } + + inline const char* CSharedString::end() const + { + return &m_pStr[GetHolder()->Length]; + } + + inline CSharedString CSharedString::substr(size_t pos, size_t len) const + { + if (len == 0) + return CSharedString(); + + if (len > (GetHolder()->Length - pos)) + len = GetHolder()->Length - pos; + + if (pos == 0 && len == GetHolder()->Length) + return *this; + + return SStringHolder::Make(&m_pStr[pos], len); + } + + inline size_t CSharedString::find(char c, size_t pos) const + { + for (size_t i = pos; i < GetHolder()->Length; i++) + { + if (m_pStr[i] == c) + return i; + } + + return npos; + } + + inline size_t CSharedString::find(const char* s, size_t pos) const + { + size_t len = strlen(s); + for (size_t i = pos; i < GetHolder()->Length - len + 1; i++) + { + if (strncmp(m_pStr + i, s, len) == 0) + return i; + } + + return npos; + } + + inline size_t CSharedString::rfind(char c, size_t pos) const + { + if (pos >= GetHolder()->Length) + pos = GetHolder()->Length - 1; + + for (size_t i = pos; i != static_cast(-1); i--) + { + if (m_pStr[i] == c) + return i; + } + + return npos; + } + + inline size_t CSharedString::find_first_of(const char* s, size_t pos) const + { + size_t len = strlen(s); + for (size_t i = pos; i < GetHolder()->Length; i++) + { + for (size_t j = 0; j < len; j++) + { + if (m_pStr[i] == s[j]) + return i; + } + } + + return npos; + } + + inline size_t CSharedString::find_last_of(const char* s, size_t pos) const + { + if (pos >= GetHolder()->Length) + pos = GetHolder()->Length - 1; + + size_t len = strlen(s); + for (size_t i = pos; i != static_cast(-1); i--) + { + for (size_t j = 0; j < len; j++) + { + if (m_pStr[i] == s[j]) + return i; + } + } + + return npos; + } + + inline size_t CSharedString::find_first_not_of(const char* s, size_t pos) const + { + size_t len = strlen(s); + for (size_t i = pos; i < GetHolder()->Length; i++) + { + bool found = false; + for (size_t j = 0; j < len; j++) + { + if (m_pStr[i] == s[j]) + { + found = true; + break; + } + } + + if (!found) + return i; + } + + return npos; + } + + inline size_t CSharedString::find_last_not_of(const char* s, size_t pos) const + { + if (pos >= GetHolder()->Length) + pos = GetHolder()->Length - 1; + + size_t len = strlen(s); + for (size_t i = pos; i != static_cast(-1); i--) + { + bool found = false; + for (size_t j = 0; j < len; j++) + { + if (m_pStr[i] == s[j]) + { + found = true; + break; + } + } + + if (!found) + return i; + } + + return npos; + } + + inline size_t CSharedString::find(const CSharedString& str, size_t pos) const + { + return find(str.c_str(), pos); + } + + inline size_t CSharedString::rfind(const CSharedString& str, size_t pos) const + { + return rfind(str.c_str(), pos); + } + + inline size_t CSharedString::find_first_of(const CSharedString& str, size_t pos) const + { + return find_first_of(str.c_str(), pos); + } + + inline size_t CSharedString::find_last_of(const CSharedString& str, size_t pos) const + { + return find_last_of(str.c_str(), pos); + } + + inline size_t CSharedString::find_first_not_of(const CSharedString& str, size_t pos) const + { + return find_first_not_of(str.c_str(), pos); + } + + inline size_t CSharedString::find_last_not_of(const CSharedString& str, size_t pos) const + { + return find_last_not_of(str.c_str(), pos); + } + + inline void CSharedString::assign(const CSharedString& in_rOther) + { + GetHolder()->Release(); + m_pStr = in_rOther.m_pStr; + GetHolder()->AddRef(); + } + + inline void CSharedString::assign(const char* in_pStr) + { + size_t length; + + if (in_pStr && (length = strlen(in_pStr)) != 0) + { + if (!GetHolder()->TryInplaceAssign(in_pStr, length)) + { + GetHolder()->Release(); + m_pStr = SStringHolder::Make(in_pStr, length)->aStr; + } + } + else + { + GetHolder()->Release(); + m_pStr = nullptr; + } + } + + inline void CSharedString::assign(CSharedString&& io_rOther) + { + m_pStr = io_rOther.m_pStr; + io_rOther.m_pStr = nullptr; + } + + inline void CSharedString::append(const CSharedString& in_rOther) + { + if (!GetHolder()->TryInplaceAppend(in_rOther.GetHolder()->aStr, in_rOther.GetHolder()->Length)) + { + SStringHolder* pHolder = SStringHolder::Concat( + GetHolder()->aStr, GetHolder()->Length, + in_rOther.GetHolder()->aStr, in_rOther.GetHolder()->Length); + + GetHolder()->Release(); + m_pStr = pHolder->aStr; + } + } + + inline void CSharedString::append(const char* in_pStr) + { + size_t length; + + if (in_pStr && (length = strlen(in_pStr)) != 0) + { + if (!GetHolder()->TryInplaceAppend(in_pStr, length)) + { + SStringHolder* pHolder = SStringHolder::Concat( + GetHolder()->aStr, GetHolder()->Length, in_pStr, length); + + GetHolder()->Release(); + m_pStr = pHolder->aStr; + } + } + } + + inline void CSharedString::prepend(const CSharedString& in_rOther) + { + if (!GetHolder()->TryInplacePrepend(in_rOther.GetHolder()->aStr, in_rOther.GetHolder()->Length)) + { + SStringHolder* pHolder = SStringHolder::Concat( + in_rOther.GetHolder()->aStr, in_rOther.GetHolder()->Length, + GetHolder()->aStr, GetHolder()->Length); + + GetHolder()->Release(); + m_pStr = pHolder->aStr; + } + } + + inline void CSharedString::prepend(const char* in_pStr) + { + size_t length; + + if (in_pStr && (length = strlen(in_pStr)) != 0) + { + if (!GetHolder()->TryInplacePrepend(in_pStr, length)) + { + SStringHolder* pHolder = SStringHolder::Concat( + in_pStr, length, GetHolder()->aStr, GetHolder()->Length); + + GetHolder()->Release(); + m_pStr = pHolder->aStr; + } + } + } + + inline int CSharedString::compare(const CSharedString& in_rOther) const + { + // TODO: DO NOT PASS BY REFERENCE. + return GuestToHostFunction(0x82DFB028, this, &in_rOther); + } + + inline CSharedString& CSharedString::operator=(const CSharedString& in_rOther) + { + assign(in_rOther); + return *this; + } + + inline CSharedString& CSharedString::operator=(const char* in_pStr) + { + assign(in_pStr); + return *this; + } + + inline CSharedString& CSharedString::operator=(CSharedString&& io_rOther) + { + assign(std::move(io_rOther)); + return *this; + } + + inline CSharedString& CSharedString::operator+=(const CSharedString& in_rOther) + { + append(in_rOther); + return *this; + } + + inline CSharedString& CSharedString::operator+=(const char* in_pStr) + { + append(in_pStr); + return *this; + } + + inline CSharedString operator+(const CSharedString& in_rLeft, const CSharedString& in_rRight) + { + return SStringHolder::Concat( + in_rLeft.GetHolder()->aStr, in_rLeft.GetHolder()->Length, + in_rRight.GetHolder()->aStr, in_rRight.GetHolder()->Length); + } + + inline CSharedString operator+(const CSharedString& in_rLeft, const char* in_pRight) + { + size_t length; + + if (in_pRight && (length = strlen(in_pRight)) != 0) + { + return SStringHolder::Concat( + in_rLeft.GetHolder()->aStr, in_rLeft.GetHolder()->Length, in_pRight, length); + } + else + { + return in_rLeft; + } + } + + inline CSharedString operator+(const char* in_pLeft, const CSharedString& in_pRight) + { + size_t length; + + if (in_pLeft && (length = strlen(in_pLeft)) != 0) + { + return SStringHolder::Concat( + in_pLeft, length, in_pRight.GetHolder()->aStr, in_pRight.GetHolder()->Length); + } + else + { + return in_pRight; + } + } + + inline bool CSharedString::operator>(const CSharedString& in_rOther) const + { + return compare(in_rOther) > 0; + } + + inline bool CSharedString::operator>=(const CSharedString& in_rOther) const + { + return compare(in_rOther) >= 0; + } + + inline bool CSharedString::operator<(const CSharedString& in_rOther) const + { + return compare(in_rOther) < 0; + } + + inline bool CSharedString::operator<=(const CSharedString& in_rOther) const + { + return compare(in_rOther) <= 0; + } + + inline bool CSharedString::operator==(const CSharedString& in_rOther) const + { + return compare(in_rOther) == 0; + } + + inline bool CSharedString::operator!=(const CSharedString& in_rOther) const + { + return !(*this == in_rOther); + } + + inline bool CSharedString::operator==(const char* in_pOther) const + { + return strcmp(c_str(), in_pOther) == 0; + } + + inline bool CSharedString::operator!=(const char* in_pOther) const + { + return !(*this == in_pOther); + } +} diff --git a/UnleashedRecomp/api/Hedgehog/Base/hhObject.h b/UnleashedRecomp/api/Hedgehog/Base/hhObject.h new file mode 100644 index 00000000..80723ee2 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/hhObject.h @@ -0,0 +1,23 @@ +#pragma once + +#include "SWA.inl" + +namespace Hedgehog::Base +{ + class CObject + { + public: + CObject(); + CObject(const swa_null_ctor&); + + void* operator new(const size_t in_Size); + void* operator new(const size_t in_Size, const size_t in_Align); + + void operator delete(void* in_pMem); + + void* operator new(const size_t in_Size, void* in_pObj); + void* operator new(const size_t in_Size, const size_t in_Align, void* in_pObj); + + void operator delete(void* in_pMem, void* in_pObj); + }; +} diff --git a/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.h b/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.h new file mode 100644 index 00000000..8552a514 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.h @@ -0,0 +1,39 @@ +#pragma once + +#include "Hedgehog/Base/hhObject.h" + +namespace Hedgehog::Database +{ + enum EDatabaseDataFlags : uint8_t + { + eDatabaseDataFlags_IsMadeOne = 0x1, + eDatabaseDataFlags_IsMadeAll = 0x2, + eDatabaseDataFlags_CreatedFromArchive = 0x4, + eDatabaseDataFlags_IsMadeMakingOne = 0x8 + }; + + class CDatabaseData : public Base::CObject + { + public: + struct Vftable + { + be m_fpDtor; + be m_fpCheckMadeAll; + }; + + xpointer m_pVftable; + uint8_t m_Flags; + Base::CSharedString m_TypeAndName; + + ~CDatabaseData(); + bool CheckMadeAll(); + + bool IsMadeOne() const; + void SetMadeOne(); + + bool IsMadeAllInternal(); + bool IsMadeAll(); + }; +} + +#include "Hedgehog/Database/System/hhDatabaseData.inl" diff --git a/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.inl b/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.inl new file mode 100644 index 00000000..7e3e383f --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.inl @@ -0,0 +1,36 @@ +namespace Hedgehog::Database +{ + inline CDatabaseData::~CDatabaseData() + { + GuestToHostFunction(m_pVftable->m_fpDtor, this); + } + + inline bool CDatabaseData::CheckMadeAll() + { + return true; + } + + inline bool CDatabaseData::IsMadeOne() const + { + return (m_Flags & eDatabaseDataFlags_IsMadeOne) != 0; + } + + inline void CDatabaseData::SetMadeOne() + { + m_Flags |= eDatabaseDataFlags_IsMadeOne; + } + + inline bool CDatabaseData::IsMadeAllInternal() + { + if ((m_Flags & eDatabaseDataFlags_IsMadeOne) == 0 || !CheckMadeAll()) + return false; + + m_Flags |= eDatabaseDataFlags_IsMadeAll; + return true; + } + + inline bool CDatabaseData::IsMadeAll() + { + return (m_Flags & eDatabaseDataFlags_IsMadeAll) != 0 || IsMadeAllInternal(); + } +} diff --git a/UnleashedRecomp/api/Hedgehog/Math/Vector2.h b/UnleashedRecomp/api/Hedgehog/Math/Vector2.h new file mode 100644 index 00000000..bc167197 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Math/Vector2.h @@ -0,0 +1,13 @@ +#pragma once + +#include "SWA.inl" + +namespace Hedgehog::Math +{ + class CVector2 + { + public: + be X; + be Y; + }; +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/Renderable/hhRenderable.h b/UnleashedRecomp/api/Hedgehog/MirageCore/Renderable/hhRenderable.h new file mode 100644 index 00000000..73fd409e --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/Renderable/hhRenderable.h @@ -0,0 +1,14 @@ +#pragma once + +#include "SWA.inl" +#include "Hedgehog/Base/hhObject.h" + +namespace Hedgehog::Mirage +{ + class CRenderable : public Base::CObject + { + public: + xpointer m_pVftable; + bool m_Enabled; + }; +} diff --git a/UnleashedRecomp/api/Hedgehog/Universe/Engine/hhMessageActor.h b/UnleashedRecomp/api/Hedgehog/Universe/Engine/hhMessageActor.h new file mode 100644 index 00000000..c7d55493 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Universe/Engine/hhMessageActor.h @@ -0,0 +1,14 @@ +#pragma once + +#include "SWA.inl" +#include "Hedgehog/Universe/Engine/hhMessageProcess.h" +#include "Hedgehog/Universe/Thread/hhParallelJob.h" + +namespace Hedgehog::Universe +{ + class CMessageActor : public IMessageProcess, public IParallelJob + { + public: + SWA_INSERT_PADDING(0x88); + }; +} diff --git a/UnleashedRecomp/api/Hedgehog/Universe/Engine/hhMessageProcess.h b/UnleashedRecomp/api/Hedgehog/Universe/Engine/hhMessageProcess.h new file mode 100644 index 00000000..b5b42d49 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Universe/Engine/hhMessageProcess.h @@ -0,0 +1,14 @@ +#pragma once + +#include "SWA.inl" +#include "Hedgehog/Base/hhObject.h" + +namespace Hedgehog::Universe +{ + class IMessageProcess : public Base::CObject + { + public: + IMessageProcess() {} + IMessageProcess(const swa_null_ctor& nil) : CObject(nil) {} + }; +} diff --git a/UnleashedRecomp/api/Hedgehog/Universe/Engine/hhUpdateInfo.h b/UnleashedRecomp/api/Hedgehog/Universe/Engine/hhUpdateInfo.h new file mode 100644 index 00000000..4369392e --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Universe/Engine/hhUpdateInfo.h @@ -0,0 +1,13 @@ +#pragma once + +#include "SWA.inl" + +namespace Hedgehog::Universe +{ + struct SUpdateInfo + { + be DeltaTime; + be Frame; + Base::CSharedString Category; + }; +} diff --git a/UnleashedRecomp/api/Hedgehog/Universe/Engine/hhUpdateUnit.h b/UnleashedRecomp/api/Hedgehog/Universe/Engine/hhUpdateUnit.h new file mode 100644 index 00000000..64513e66 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Universe/Engine/hhUpdateUnit.h @@ -0,0 +1,25 @@ +#pragma once + +#include "SWA.inl" +#include "Hedgehog/Universe/Thread/hhParallelJob.h" + +namespace Hedgehog::Universe +{ + class CUpdateUnit : public Base::CObject, public IParallelJob + { + public: + xpointer m_pVftable; + SWA_INSERT_PADDING(0x20); + + CUpdateUnit(const swa_null_ctor& nil) : CObject(nil), IParallelJob(nil) {} + CUpdateUnit(); + + // TODO: implement virtual functions. + // virtual ~CUpdateUnit(); + // + // virtual void ExecuteParallelJob(const SUpdateInfo& in_rUpdateInfo) override; + // + // virtual void UpdateParallel(const SUpdateInfo& in_rUpdateInfo) {} + // virtual void UpdateSerial(const SUpdateInfo& in_rUpdateInfo) {} + }; +} diff --git a/UnleashedRecomp/api/Hedgehog/Universe/Thread/hhParallelJob.h b/UnleashedRecomp/api/Hedgehog/Universe/Thread/hhParallelJob.h new file mode 100644 index 00000000..60b59be3 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Universe/Thread/hhParallelJob.h @@ -0,0 +1,21 @@ +#pragma once + +#include "SWA.inl" +#include "Hedgehog/Universe/Engine/hhUpdateInfo.h" + +namespace Hedgehog::Universe +{ + class IParallelJob + { + public: + xpointer m_pVftable; + + IParallelJob() {} + IParallelJob(const swa_null_ctor&) {} + + // TODO: implement virtual functions. + // virtual ~IParallelJob() = default; + // + // virtual void ExecuteParallelJob(const SUpdateInfo& in_rUpdateInfo) = 0; + }; +} diff --git a/UnleashedRecomp/api/SWA.h b/UnleashedRecomp/api/SWA.h index 7a93b527..305f36d4 100644 --- a/UnleashedRecomp/api/SWA.h +++ b/UnleashedRecomp/api/SWA.h @@ -1,10 +1,68 @@ #pragma once +#include "Hedgehog/Base/hhObject.h" +#include "Hedgehog/Base/System/hhAllocator.h" +#include "Hedgehog/Base/Thread/hhHolder.h" +#include "Hedgehog/Base/Thread/hhHolderBase.h" +#include "Hedgehog/Base/Thread/hhSynchronizedObject.h" +#include "Hedgehog/Base/Thread/hhSynchronizedPtr.h" +#include "Hedgehog/Base/Type/hhSharedString.h" +#include "Hedgehog/Database/System/hhDatabaseData.h" +#include "Hedgehog/Math/Vector2.h" +#include "Hedgehog/MirageCore/Renderable/hhRenderable.h" +#include "Hedgehog/Universe/Engine/hhMessageActor.h" +#include "Hedgehog/Universe/Engine/hhMessageProcess.h" +#include "Hedgehog/Universe/Engine/hhUpdateInfo.h" +#include "Hedgehog/Universe/Engine/hhUpdateUnit.h" +#include "Hedgehog/Universe/Thread/hhParallelJob.h" + +#include "CSD/Manager/csdmBase.h" +#include "CSD/Manager/csdmMotionPattern.h" +#include "CSD/Manager/csdmNode.h" +#include "CSD/Manager/csdmNodeObserver.h" +#include "CSD/Manager/csdmObserverBase.h" +#include "CSD/Manager/csdmProject.h" +#include "CSD/Manager/csdmRCObject.h" +#include "CSD/Manager/csdmRCObjectImp.h" +#include "CSD/Manager/csdmRCPtr.h" +#include "CSD/Manager/csdmRCPtrAbs.h" +#include "CSD/Manager/csdmResourceBase.h" +#include "CSD/Manager/csdmScene.h" +#include "CSD/Manager/csdmSceneObserver.h" +#include "CSD/Manager/csdmSubjectBase.h" +#include "CSD/Platform/csdTexList.h" + #include "SWA/Camera/Camera.h" +#include "SWA/CSD/CsdDatabaseWrapper.h" +#include "SWA/CSD/CsdProject.h" +#include "SWA/CSD/CsdTexListMirage.h" +#include "SWA/CSD/GameObjectCSD.h" +#include "SWA/HUD/GeneralWindow/GeneralWindow.h" +#include "SWA/HUD/Loading/Loading.h" +#include "SWA/HUD/Pause/HudPause.h" +#include "SWA/HUD/Sonic/HudSonicStage.h" +#include "SWA/Movie/MovieDisplayer.h" +#include "SWA/Movie/MovieManager.h" #include "SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h" #include "SWA/Player/Character/EvilSonic/EvilSonic.h" #include "SWA/Player/Character/EvilSonic/EvilSonicContext.h" +#include "SWA/Sequence/Unit/SequenceUnitBase.h" +#include "SWA/Sequence/Unit/SequenceUnitPlayMovie.h" +#include "SWA/Sequence/Utility/SequencePlayMovieWrapper.h" +#include "SWA/Sound/Sound.h" +#include "SWA/Sound/SoundBGMActSonic.h" +#include "SWA/Sound/SoundBGMBase.h" +#include "SWA/System/GameMode/Title/TitleMenu.h" +#include "SWA/System/GameMode/Title/TitleStateBase.h" +#include "SWA/System/GameMode/GameMode.h" +#include "SWA/System/GameMode/GameModeStage.h" +#include "SWA/System/GameMode/GameModeStageMovie.h" +#include "SWA/System/Application.h" +#include "SWA/System/ApplicationD3D9.h" +#include "SWA/System/ApplicationXenon.h" #include "SWA/System/ApplicationDocument.h" +#include "SWA/System/Game.h" #include "SWA/System/GameDocument.h" +#include "SWA/System/GameObject.h" #include "SWA/System/InputState.h" #include "SWA/System/PadState.h" diff --git a/UnleashedRecomp/api/SWA.inl b/UnleashedRecomp/api/SWA.inl index 005c0c83..3c6261f8 100644 --- a/UnleashedRecomp/api/SWA.inl +++ b/UnleashedRecomp/api/SWA.inl @@ -1,9 +1,16 @@ #pragma once #include +#include +#include #define SWA__CONCAT2(x, y) x##y #define SWA_CONCAT2(x, y) _CONCAT(x, y) #define SWA_INSERT_PADDING(length) \ uint8_t SWA_CONCAT2(pad, __LINE__)[length] + +#define SWA_VIRTUAL_FUNCTION(returnType, virtualIndex, ...) \ + GuestToHostFunction(*(be*)(g_memory.Translate(*(be*)(this) + (4 * virtualIndex))), __VA_ARGS__) + +struct swa_null_ctor {}; diff --git a/UnleashedRecomp/api/SWA/CSD/CsdDatabaseWrapper.h b/UnleashedRecomp/api/SWA/CSD/CsdDatabaseWrapper.h new file mode 100644 index 00000000..94abf973 --- /dev/null +++ b/UnleashedRecomp/api/SWA/CSD/CsdDatabaseWrapper.h @@ -0,0 +1,25 @@ +#pragma once + +#include "boost/smart_ptr/shared_ptr.h" + +namespace Hedgehog::Database +{ + class CDatabase; +} + +namespace SWA +{ + class CCsdProject; + + class CCsdDatabaseWrapper + { + public: + Hedgehog::Database::CDatabase* m_pDatabase; + + CCsdDatabaseWrapper(Hedgehog::Database::CDatabase* in_pDatabase) : m_pDatabase(in_pDatabase) {} + + boost::shared_ptr GetCsdProject(const Hedgehog::Base::CSharedString& in_rName); + }; +} + +#include "SWA/CSD/CsdDatabaseWrapper.inl" diff --git a/UnleashedRecomp/api/SWA/CSD/CsdDatabaseWrapper.inl b/UnleashedRecomp/api/SWA/CSD/CsdDatabaseWrapper.inl new file mode 100644 index 00000000..414c6465 --- /dev/null +++ b/UnleashedRecomp/api/SWA/CSD/CsdDatabaseWrapper.inl @@ -0,0 +1,9 @@ +namespace SWA +{ + inline boost::shared_ptr CCsdDatabaseWrapper::GetCsdProject(const Hedgehog::Base::CSharedString& in_rName) + { + boost::shared_ptr spCsdProject; + GuestToHostFunction(0x825E2B40, &in_rName, this, &spCsdProject, 0); + return spCsdProject; + } +} diff --git a/UnleashedRecomp/api/SWA/CSD/CsdProject.h b/UnleashedRecomp/api/SWA/CSD/CsdProject.h new file mode 100644 index 00000000..0211933a --- /dev/null +++ b/UnleashedRecomp/api/SWA/CSD/CsdProject.h @@ -0,0 +1,18 @@ +#pragma once + +#include "CSD/Manager/csdmRCPtr.h" +#include "Hedgehog/Database/System/hhDatabaseData.h" + +namespace Chao::CSD +{ + class CProject; +} + +namespace SWA +{ + class CCsdProject : public Hedgehog::Database::CDatabaseData + { + public: + Chao::CSD::RCPtr m_rcProject; + }; +} diff --git a/UnleashedRecomp/api/SWA/CSD/CsdTexListMirage.h b/UnleashedRecomp/api/SWA/CSD/CsdTexListMirage.h new file mode 100644 index 00000000..ee0be919 --- /dev/null +++ b/UnleashedRecomp/api/SWA/CSD/CsdTexListMirage.h @@ -0,0 +1,18 @@ +#pragma once + +#include "CSD/Platform/csdTexList.h" + +namespace Hedgehog::Mirage +{ + class CTexsetData; +} + +namespace SWA +{ + class CCsdTexListMirage : public Chao::CSD::CTexList + { + public: + boost::shared_ptr m_spTexsetData; + SWA_INSERT_PADDING(0x04); + }; +} diff --git a/UnleashedRecomp/api/SWA/CSD/GameObjectCSD.h b/UnleashedRecomp/api/SWA/CSD/GameObjectCSD.h new file mode 100644 index 00000000..5049fdb0 --- /dev/null +++ b/UnleashedRecomp/api/SWA/CSD/GameObjectCSD.h @@ -0,0 +1,20 @@ +#pragma once + +#include "SWA.inl" +#include "CSD/Manager/csdmRCPtr.h" +#include "SWA/System/GameObject.h" + +namespace Chao::CSD +{ + class CProject; +} + +namespace SWA +{ + class CGameObjectCSD : public CGameObject + { + public: + xpointer m_pVftable; + Chao::CSD::RCPtr m_rcProject; + }; +} diff --git a/UnleashedRecomp/api/SWA/Camera/Camera.h b/UnleashedRecomp/api/SWA/Camera/Camera.h index 7737d9cb..1d3db6c6 100644 --- a/UnleashedRecomp/api/SWA/Camera/Camera.h +++ b/UnleashedRecomp/api/SWA/Camera/Camera.h @@ -1,13 +1,15 @@ #pragma once -#include "SWA.inl" +#include +#include namespace SWA { - class CCamera // : public CGameObject, public Hedgehog::Universe::TStateMachine + class CCamera : public CGameObject // , public Hedgehog::Universe::TStateMachine { public: - SWA_INSERT_PADDING(0x184); + xpointer m_pVftable; + SWA_INSERT_PADDING(0xC4); be m_VertAspectRatio; SWA_INSERT_PADDING(0x48); be m_HorzAspectRatio; @@ -15,5 +17,8 @@ namespace SWA be m_FieldOfView; be m_VertFieldOfView; be m_HorzFieldOfView; + SWA_INSERT_PADDING(0x18); + bool m_InvertY; + bool m_InvertX; }; } diff --git a/UnleashedRecomp/api/SWA/HUD/GeneralWindow/GeneralWindow.h b/UnleashedRecomp/api/SWA/HUD/GeneralWindow/GeneralWindow.h new file mode 100644 index 00000000..6728eba1 --- /dev/null +++ b/UnleashedRecomp/api/SWA/HUD/GeneralWindow/GeneralWindow.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace SWA +{ + class CGeneralWindow + { + public: + SWA_INSERT_PADDING(0xD0); + Chao::CSD::RCPtr m_rcGeneral; + Chao::CSD::RCPtr m_rcBg; + Chao::CSD::RCPtr m_rcWindow; + Chao::CSD::RCPtr m_rcWindow_2; + Chao::CSD::RCPtr m_rcWindowSelect; + Chao::CSD::RCPtr m_rcFooter; + }; +} diff --git a/UnleashedRecomp/api/SWA/HUD/Loading/Loading.h b/UnleashedRecomp/api/SWA/HUD/Loading/Loading.h new file mode 100644 index 00000000..a70dad0d --- /dev/null +++ b/UnleashedRecomp/api/SWA/HUD/Loading/Loading.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +namespace SWA +{ + enum ELoadingDisplayType + { + eLoadingDisplayType_MilesElectric, + eLoadingDisplayType_None, + eLoadingDisplayType_WerehogMovie, + eLoadingDisplayType_MilesElectricContext, + eLoadingDisplayType_Arrows, + eLoadingDisplayType_NowLoading, + eLoadingDisplayType_EventGallery, + eLoadingDisplayType_ChangeTimeOfDay, + eLoadingDisplayType_Blank + }; + + class CLoading + { + public: + SWA_INSERT_PADDING(0x128); + bool m_IsVisible; + SWA_INSERT_PADDING(0x0C); + be m_LoadingDisplayType; + SWA_INSERT_PADDING(0x65); + bool m_IsNightToDay; + }; +} diff --git a/UnleashedRecomp/api/SWA/HUD/Pause/HudPause.h b/UnleashedRecomp/api/SWA/HUD/Pause/HudPause.h new file mode 100644 index 00000000..f4e67093 --- /dev/null +++ b/UnleashedRecomp/api/SWA/HUD/Pause/HudPause.h @@ -0,0 +1,67 @@ +#pragma once + +#include + +using namespace Chao::CSD; + +namespace SWA +{ + enum EActionType : uint32_t + { + eActionType_Undefined, + eActionType_Status, + eActionType_Return, + eActionType_Inventory, + eActionType_Skills, + eActionType_Lab, + eActionType_Wait, + eActionType_Restart = 8, + eActionType_Continue + }; + + enum EMenuType : uint32_t + { + eMenuType_WorldMap, + eMenuType_Village, + eMenuType_Stage, + eMenuType_Hub, + eMenuType_Misc + }; + + enum EStatusType : uint32_t + { + eStatusType_Idle, + eStatusType_Accept, + eStatusType_Decline + }; + + enum ETransitionType : uint32_t + { + eTransitionType_Undefined, + eTransitionType_Quit = 2, + eTransitionType_Dialog = 5, + eTransitionType_Hide, + eTransitionType_Abort, + eTransitionType_SubMenu + }; + + class CHudPause : public CGameObject + { + public: + xpointer m_pVftable; + SWA_INSERT_PADDING(0x2C); + RCPtr m_rcPause; + RCPtr m_rcBg; + RCPtr m_rcBg1; + RCPtr m_rcBg1_2; + RCPtr m_rcBg1Select; + RCPtr m_rcBg1Select_2; + RCPtr m_rcStatusTitle; + RCPtr m_rcFooterA; + SWA_INSERT_PADDING(0x5C); + be m_Action; + be m_Menu; + be m_Status; + be m_Transition; + }; +} diff --git a/UnleashedRecomp/api/SWA/HUD/Sonic/HudSonicStage.h b/UnleashedRecomp/api/SWA/HUD/Sonic/HudSonicStage.h new file mode 100644 index 00000000..59e2d070 --- /dev/null +++ b/UnleashedRecomp/api/SWA/HUD/Sonic/HudSonicStage.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace SWA +{ + class CHudSonicStage + { + public: + SWA_INSERT_PADDING(0xE0); + Chao::CSD::RCPtr m_rcPlayScreen; + Chao::CSD::RCPtr m_rcSpeedGauge; + Chao::CSD::RCPtr m_rcRingEnergyGauge; + Chao::CSD::RCPtr m_rcGaugeFrame; + SWA_INSERT_PADDING(0x28); + Chao::CSD::RCPtr m_rcScoreCount; + Chao::CSD::RCPtr m_rcTimeCount; + Chao::CSD::RCPtr m_rcTimeCount2; + Chao::CSD::RCPtr m_rcTimeCount3; + Chao::CSD::RCPtr m_rcPlayerCount; + }; +} diff --git a/UnleashedRecomp/api/SWA/Movie/MovieDisplayer.h b/UnleashedRecomp/api/SWA/Movie/MovieDisplayer.h new file mode 100644 index 00000000..64e13e34 --- /dev/null +++ b/UnleashedRecomp/api/SWA/Movie/MovieDisplayer.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +namespace SWA +{ + class CMovieDisplayer : public Hedgehog::Universe::CUpdateUnit, public Hedgehog::Mirage::CRenderable + { + public: + SWA_INSERT_PADDING(0x04); + be m_MovieWidth; + be m_MovieHeight; + }; +} diff --git a/UnleashedRecomp/api/SWA/Movie/MovieManager.h b/UnleashedRecomp/api/SWA/Movie/MovieManager.h new file mode 100644 index 00000000..4de3429e --- /dev/null +++ b/UnleashedRecomp/api/SWA/Movie/MovieManager.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace SWA +{ + class CMovieManager // : Hedgehog::Base::TSingleton + { + public: + static CMovieManager* GetInstance(); + + xpointer m_pVftable; + SWA_INSERT_PADDING(0x330); + }; +} + +#include "SWA/Movie/MovieManager.inl" diff --git a/UnleashedRecomp/api/SWA/Movie/MovieManager.inl b/UnleashedRecomp/api/SWA/Movie/MovieManager.inl new file mode 100644 index 00000000..e9412070 --- /dev/null +++ b/UnleashedRecomp/api/SWA/Movie/MovieManager.inl @@ -0,0 +1,7 @@ +namespace SWA +{ + inline CMovieManager* CMovieManager::GetInstance() + { + return *(xpointer*)MmGetHostAddress(0x8336758C); + } +} diff --git a/UnleashedRecomp/api/SWA/Player/Character/EvilSonic/EvilSonic.h b/UnleashedRecomp/api/SWA/Player/Character/EvilSonic/EvilSonic.h index d6b510ea..bee25d07 100644 --- a/UnleashedRecomp/api/SWA/Player/Character/EvilSonic/EvilSonic.h +++ b/UnleashedRecomp/api/SWA/Player/Character/EvilSonic/EvilSonic.h @@ -5,7 +5,7 @@ namespace SWA::Player { - class CEvilSonic + class CEvilSonic // : public CPlayer { public: SWA_INSERT_PADDING(0xC4); diff --git a/UnleashedRecomp/api/SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h b/UnleashedRecomp/api/SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h index 090d5b09..d872fe48 100644 --- a/UnleashedRecomp/api/SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h +++ b/UnleashedRecomp/api/SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h @@ -18,12 +18,13 @@ namespace SWA::Player eGuideType_Y }; - class CEvilHudGuide + class CEvilHudGuide : public CGameObject { public: - SWA_INSERT_PADDING(0x14D); + xpointer m_pVftable; + SWA_INSERT_PADDING(0x8D); bool m_IsShown; bool m_IsVisible; - EGuideType m_GuideType; + be m_GuideType; }; } diff --git a/UnleashedRecomp/api/SWA/Sequence/Unit/SequenceUnitBase.h b/UnleashedRecomp/api/SWA/Sequence/Unit/SequenceUnitBase.h new file mode 100644 index 00000000..d45387f2 --- /dev/null +++ b/UnleashedRecomp/api/SWA/Sequence/Unit/SequenceUnitBase.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace SWA::Sequence::Unit +{ + class CUnitBase : public Hedgehog::Base::CObject + { + public: + xpointer m_pVftable; + SWA_INSERT_PADDING(0x14); + }; +} diff --git a/UnleashedRecomp/api/SWA/Sequence/Unit/SequenceUnitPlayMovie.h b/UnleashedRecomp/api/SWA/Sequence/Unit/SequenceUnitPlayMovie.h new file mode 100644 index 00000000..b7f64e36 --- /dev/null +++ b/UnleashedRecomp/api/SWA/Sequence/Unit/SequenceUnitPlayMovie.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace SWA::Sequence::Unit +{ + class CPlayMovieUnit : public CUnitBase {}; +} diff --git a/UnleashedRecomp/api/SWA/Sequence/Utility/SequencePlayMovieWrapper.h b/UnleashedRecomp/api/SWA/Sequence/Utility/SequencePlayMovieWrapper.h new file mode 100644 index 00000000..a73c7add --- /dev/null +++ b/UnleashedRecomp/api/SWA/Sequence/Utility/SequencePlayMovieWrapper.h @@ -0,0 +1,39 @@ +#pragma once + +#include "SWA.inl" +#include "Hedgehog/MirageCore/Renderable/hhRenderable.h" + +namespace SWA::Sequence::Utility +{ + class CPlayMovieWrapper + { + public: + class CRender : public Hedgehog::Mirage::CRenderable + { + public: + be m_ScreenWidth; + be m_ScreenHeight; + be m_MovieWidth; + be m_MovieHeight; + SWA_INSERT_PADDING(0x74); + be m_TopLeftX; + be m_TopLeftY; + SWA_INSERT_PADDING(0x0C); + be m_TopRightX; + be m_TopRightY; + SWA_INSERT_PADDING(0x0C); + be m_BottomRightX; + be m_BottomRightY; + SWA_INSERT_PADDING(0x0C); + be m_BottomLeftX; + be m_BottomLeftY; + SWA_INSERT_PADDING(0xD4); + bool m_MaintainAspectRatio; + SWA_INSERT_PADDING(0x18); + be m_TimeElapsed; + }; + + SWA_INSERT_PADDING(0x18); + xpointer m_pRender; + }; +} diff --git a/UnleashedRecomp/api/SWA/Sound/Sound.h b/UnleashedRecomp/api/SWA/Sound/Sound.h new file mode 100644 index 00000000..d43c43a7 --- /dev/null +++ b/UnleashedRecomp/api/SWA/Sound/Sound.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +namespace SWA +{ + class CSoundAdministrator : public CGameObject + { + public: + class CSimplePlayer {}; + + class CBgm + { + public: + xpointer m_pThis; + boost::shared_ptr m_spSoundBGM; + be m_Volume1; + be m_Volume2; + be m_Volume3; + be m_Volume4; + SWA_INSERT_PADDING(0x10); + }; + + class CCommunicator + { + public: + class CCommunicatorDevice : Hedgehog::Base::CSynchronizedObject + { + public: + SWA_INSERT_PADDING(0x08); + Hedgehog::Base::CSharedString m_HostName; + SWA_INSERT_PADDING(0x04); + Hedgehog::Base::CSharedString m_Category; + Hedgehog::Base::CSharedString m_Command; + SWA_INSERT_PADDING(0x04); + }; + + xpointer m_pThis; + boost::shared_ptr m_spCommunicatorDevice; + }; + + class CMember + { + public: + boost::shared_ptr m_spSimplePlayer; + boost::shared_ptr m_spBgm; + boost::shared_ptr m_spCommunicator; + SWA_INSERT_PADDING(0x58); + }; + + xpointer m_pVftable; + SWA_INSERT_PADDING(0x04); + xpointer m_pMember; + }; +} diff --git a/UnleashedRecomp/api/SWA/Sound/SoundBGMActSonic.h b/UnleashedRecomp/api/SWA/Sound/SoundBGMActSonic.h new file mode 100644 index 00000000..5f3371ac --- /dev/null +++ b/UnleashedRecomp/api/SWA/Sound/SoundBGMActSonic.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace SWA +{ + class CSoundBGMActSonic : public CSoundBGMBase + { + public: + class CMember + { + public: + SWA_INSERT_PADDING(0x58); + be m_Volume1; + be m_Volume2; + }; + + xpointer m_pMember; + }; +} diff --git a/UnleashedRecomp/api/SWA/Sound/SoundBGMBase.h b/UnleashedRecomp/api/SWA/Sound/SoundBGMBase.h new file mode 100644 index 00000000..3f8a7c2f --- /dev/null +++ b/UnleashedRecomp/api/SWA/Sound/SoundBGMBase.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +namespace SWA +{ + class CSoundBGMBase : Hedgehog::Universe::CMessageActor + { + public: + SWA_INSERT_PADDING(0x04); // vftable ptr + SWA_INSERT_PADDING(0x04); + xpointer m_pGameDocument; + bool m_Unk; + }; +} diff --git a/UnleashedRecomp/api/SWA/System/Application.h b/UnleashedRecomp/api/SWA/System/Application.h new file mode 100644 index 00000000..5efd399a --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/Application.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +namespace SWA +{ + class CApplication : public Hedgehog::Base::CObject + { + public: + class CMember + { + public: + xpointer m_pApplicationDocument; + }; + + xpointer m_pVftable; + xpointer m_pMember; + SWA_INSERT_PADDING(0x18); + }; +} diff --git a/UnleashedRecomp/api/SWA/System/ApplicationD3D9.h b/UnleashedRecomp/api/SWA/System/ApplicationD3D9.h new file mode 100644 index 00000000..ef88f297 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/ApplicationD3D9.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +namespace SWA +{ + class CApplicationD3D9 : public CApplication {}; +} diff --git a/UnleashedRecomp/api/SWA/System/ApplicationDocument.h b/UnleashedRecomp/api/SWA/System/ApplicationDocument.h index 598c4715..6dfdc7da 100644 --- a/UnleashedRecomp/api/SWA/System/ApplicationDocument.h +++ b/UnleashedRecomp/api/SWA/System/ApplicationDocument.h @@ -1,24 +1,54 @@ #pragma once +#include +#include + namespace SWA { - class CApplicationDocument // : public Hedgehog::Base::CSynchronizedObject + enum ELanguage : uint32_t + { + eLanguage_English, + eLanguage_Japanese, + eLanguage_German, + eLanguage_French, + eLanguage_Italian, + eLanguage_Spanish + }; + + enum EVoiceLanguage : uint32_t + { + eVoiceLanguage_English, + eVoiceLanguage_Japanese + }; + + enum ERegion : uint32_t + { + eRegion_Japan, + eRegion_RestOfWorld + }; + + class CApplicationDocument : public Hedgehog::Base::CSynchronizedObject { public: class CMember { public: - SWA_INSERT_PADDING(0x138); - void* m_spGameParameter; + SWA_INSERT_PADDING(0x20); + boost::shared_ptr m_pGame; + SWA_INSERT_PADDING(0x114); + xpointer m_spGameParameter; }; // TODO: Hedgehog::Base::TSynchronizedPtr static CApplicationDocument* GetInstance(); - SWA_INSERT_PADDING(0x04); xpointer m_pMember; - SWA_INSERT_PADDING(0x14); - be m_Region; + be m_Language; + be m_VoiceLanguage; + SWA_INSERT_PADDING(0x08); + be m_Region; + bool m_InspireVoices; + bool m_InspireSubtitles; }; } diff --git a/UnleashedRecomp/api/SWA/System/ApplicationXenon.h b/UnleashedRecomp/api/SWA/System/ApplicationXenon.h new file mode 100644 index 00000000..ed5d6c1c --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/ApplicationXenon.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace SWA +{ + class CApplicationXenon : public CApplicationD3D9 + { + public: + SWA_INSERT_PADDING(0x1B4); + }; +} diff --git a/UnleashedRecomp/api/SWA/System/Game.h b/UnleashedRecomp/api/SWA/System/Game.h new file mode 100644 index 00000000..9e0101ae --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/Game.h @@ -0,0 +1,10 @@ +#pragma once + +namespace SWA +{ + class CGame // : Hedgehog::Universe::TStateMachine + { + public: + SWA_INSERT_PADDING(0xFC); + }; +} diff --git a/UnleashedRecomp/api/SWA/System/GameDocument.h b/UnleashedRecomp/api/SWA/System/GameDocument.h index e13f6071..f07c3240 100644 --- a/UnleashedRecomp/api/SWA/System/GameDocument.h +++ b/UnleashedRecomp/api/SWA/System/GameDocument.h @@ -1,21 +1,30 @@ #pragma once +namespace Hedgehog::Database +{ + class CDatabase; +} + namespace SWA { - class CGameDocument // : public Hedgehog::Base::CSynchronizedObject + class CGameDocument : public Hedgehog::Base::CSynchronizedObject { public: class CMember { public: - SWA_INSERT_PADDING(0x20C); + SWA_INSERT_PADDING(0x1C); + boost::shared_ptr m_spDatabase; + SWA_INSERT_PADDING(0x8C); + xpointer m_pSoundAdministrator; + SWA_INSERT_PADDING(0x158); be m_Score; }; // TODO: Hedgehog::Base::TSynchronizedPtr static CGameDocument* GetInstance(); - SWA_INSERT_PADDING(0x08); + xpointer m_pVftable; xpointer m_pMember; }; } diff --git a/UnleashedRecomp/api/SWA/System/GameMode/GameMode.h b/UnleashedRecomp/api/SWA/System/GameMode/GameMode.h new file mode 100644 index 00000000..5b6c35dc --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/GameMode/GameMode.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace SWA +{ + class CGameMode // : Hedgehog::Universe::TStateMachine::TState + { + public: + SWA_INSERT_PADDING(0x60); // base + SWA_INSERT_PADDING(0x08); + }; +} diff --git a/UnleashedRecomp/api/SWA/System/GameMode/GameModeStage.h b/UnleashedRecomp/api/SWA/System/GameMode/GameModeStage.h new file mode 100644 index 00000000..eeba70c5 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/GameMode/GameModeStage.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace SWA +{ + class CGameModeStage : public CGameMode + { + public: + xpointer m_pVftable; + SWA_INSERT_PADDING(0x1B4); + }; +} diff --git a/UnleashedRecomp/api/SWA/System/GameMode/GameModeStageMovie.h b/UnleashedRecomp/api/SWA/System/GameMode/GameModeStageMovie.h new file mode 100644 index 00000000..e1a95df4 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/GameMode/GameModeStageMovie.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace SWA +{ + class CGameModeStageMovie : public CGameModeStage + { + public: + class CRender : public Hedgehog::Mirage::CRenderable + { + public: + xpointer m_pThis; + }; + + xpointer m_pVftable; + SWA_INSERT_PADDING(0x224); + xpointer m_pRender; + }; +} diff --git a/UnleashedRecomp/api/SWA/System/GameMode/Title/TitleMenu.h b/UnleashedRecomp/api/SWA/System/GameMode/Title/TitleMenu.h new file mode 100644 index 00000000..a533e260 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/GameMode/Title/TitleMenu.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace SWA +{ + class CTitleMenu + { + public: + SWA_INSERT_PADDING(0x44); + be m_CursorIndex; + }; +} diff --git a/UnleashedRecomp/api/SWA/System/GameMode/Title/TitleStateBase.h b/UnleashedRecomp/api/SWA/System/GameMode/Title/TitleStateBase.h new file mode 100644 index 00000000..6782f3b5 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/GameMode/Title/TitleStateBase.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace SWA +{ + class CTitleStateBase // : Hedgehog::Universe::TStateMachine::TState + { + public: + class CMember + { + public: + SWA_INSERT_PADDING(0x1E8); + xpointer m_pTitleMenu; + }; + + SWA_INSERT_PADDING(0x08); + xpointer m_pMember; + SWA_INSERT_PADDING(0x5C); + be m_State; + }; +} diff --git a/UnleashedRecomp/api/SWA/System/GameObject.h b/UnleashedRecomp/api/SWA/System/GameObject.h new file mode 100644 index 00000000..dd4f7fd1 --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/GameObject.h @@ -0,0 +1,27 @@ +#pragma once + +#include "SWA.inl" +#include "Hedgehog/Base/Thread/hhSynchronizedPtr.h" +#include "Hedgehog/Universe/Engine/hhMessageActor.h" +#include "Hedgehog/Universe/Engine/hhUpdateUnit.h" + +namespace SWA +{ + class CGameDocument; + class CWorld; + + class CGameObject : public Hedgehog::Universe::CUpdateUnit, public Hedgehog::Universe::CMessageActor + { + public: + class CMember + { + public: + Hedgehog::Base::TSynchronizedPtr m_pGameDocument; + Hedgehog::Base::TSynchronizedPtr m_pWorld; + SWA_INSERT_PADDING(0x70); + }; + + xpointer m_pVftable; + xpointer m_pMember; + }; +} diff --git a/UnleashedRecomp/api/SWA/System/InputState.h b/UnleashedRecomp/api/SWA/System/InputState.h index defe936e..b42c67eb 100644 --- a/UnleashedRecomp/api/SWA/System/InputState.h +++ b/UnleashedRecomp/api/SWA/System/InputState.h @@ -5,16 +5,14 @@ namespace SWA { - class CInputState // : public Hedgehog::Base::CSynchronizedObject + class CInputState : public Hedgehog::Base::CSynchronizedObject { public: // TODO: Hedgehog::Base::TSynchronizedPtr static CInputState* GetInstance(); - SPadState m_PadStates[40]; - SWA_INSERT_PADDING(0x50); + SPadState m_PadStates[8]; be m_CurrentPadStateIndex; - SWA_INSERT_PADDING(0x04); const SPadState& GetPadState() const; }; diff --git a/UnleashedRecomp/api/SWA/System/InputState.inl b/UnleashedRecomp/api/SWA/System/InputState.inl index 5eba9408..7b961c4d 100644 --- a/UnleashedRecomp/api/SWA/System/InputState.inl +++ b/UnleashedRecomp/api/SWA/System/InputState.inl @@ -3,7 +3,7 @@ namespace SWA // TODO: Hedgehog::Base::TSynchronizedPtr inline CInputState* CInputState::GetInstance() { - return *(xpointer*)MmGetHostAddress(0x833671EC); + return *(xpointer*)MmGetHostAddress(0x83361F5C); } inline const SPadState& CInputState::GetPadState() const diff --git a/UnleashedRecomp/api/SWA/System/PadState.h b/UnleashedRecomp/api/SWA/System/PadState.h index eca4a5a8..a27df47d 100644 --- a/UnleashedRecomp/api/SWA/System/PadState.h +++ b/UnleashedRecomp/api/SWA/System/PadState.h @@ -43,15 +43,11 @@ namespace SWA struct SPadState { - SWA_INSERT_PADDING(0x20); - be DownState; be UpState; be TappedState; be ReleasedState; - SWA_INSERT_PADDING(0x04); - be LeftStickHorizontal; be LeftStickVertical; @@ -65,7 +61,7 @@ namespace SWA be LeftTrigger; be RightTrigger; - SWA_INSERT_PADDING(0x20); + SWA_INSERT_PADDING(0x08); bool IsDown(const EKeyState in_Keys) const; bool IsUp(const EKeyState in_Keys) const; diff --git a/UnleashedRecomp/api/SWA/System/World.h b/UnleashedRecomp/api/SWA/System/World.h new file mode 100644 index 00000000..aafbcd2f --- /dev/null +++ b/UnleashedRecomp/api/SWA/System/World.h @@ -0,0 +1,20 @@ +#pragma once + +#include "SWA.inl" +#include "Hedgehog/Base/Thread/hhSynchronizedObject.h" +#include "Hedgehog/Universe/Engine/hhMessageActor.h" + +namespace SWA +{ + class CWorld : public Hedgehog::Base::CSynchronizedObject, public Hedgehog::Universe::CMessageActor + { + public: + class CMember + { + public: + SWA_INSERT_PADDING(0x80); + }; + + xpointer m_pMember; + }; +} diff --git a/UnleashedRecomp/api/boost/smart_ptr/make_shared_object.h b/UnleashedRecomp/api/boost/smart_ptr/make_shared_object.h new file mode 100644 index 00000000..9bba6b4b --- /dev/null +++ b/UnleashedRecomp/api/boost/smart_ptr/make_shared_object.h @@ -0,0 +1,12 @@ +#pragma once + +#include "boost/smart_ptr/shared_ptr.h" + +namespace boost +{ + template + shared_ptr make_shared(TArgs&&... args) + { + return shared_ptr(new T(std::forward(args)...)); + } +} diff --git a/UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h b/UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h new file mode 100644 index 00000000..ecea043a --- /dev/null +++ b/UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h @@ -0,0 +1,164 @@ +#pragma once + +#include +#include + +namespace boost +{ + namespace detail + { + class sp_counted_base + { + protected: + struct vftable_t + { + be destructor; + be dispose; + be destroy; + be get_deleter; + }; + + xpointer vftable_; + be use_count_; + be weak_count_; + + public: + // TODO + sp_counted_base() = delete; + + void add_ref() + { + be original, incremented; + do + { + original = use_count_; + incremented = original + 1; + } while (InterlockedCompareExchange((unsigned long*)&use_count_, incremented.value, original.value) != original.value); + } + + void release() + { + be original, decremented; + do + { + original = use_count_; + decremented = original - 1; + } while (InterlockedCompareExchange((unsigned long*)&use_count_, decremented.value, original.value) != original.value); + + if (decremented == 0) + { + GuestToHostFunction(vftable_->dispose, this); + weak_release(); + } + } + + void weak_release() + { + be original, decremented; + do + { + original = weak_count_; + decremented = original - 1; + } while (InterlockedCompareExchange((unsigned long*)&weak_count_, decremented.value, original.value) != original.value); + + if (decremented == 0) + { + GuestToHostFunction(vftable_->destroy, this); + } + } + + uint32_t use_count() const + { + return use_count_; + } + }; + + template< class T > struct sp_dereference + { + typedef T& type; + }; + + template<> struct sp_dereference< void > + { + typedef void type; + }; + } + + template + class shared_ptr + { + private: + xpointer px; + xpointer pn; + + void add_ref() + { + if (pn) + pn->add_ref(); + } + + void release() + { + if (pn) + pn->release(); + } + + public: + shared_ptr() : px(nullptr), pn(nullptr) {} + + // TODO + explicit shared_ptr(T* p) = delete; + + shared_ptr(const shared_ptr& other) : px(other.px), pn(other.pn) + { + add_ref(); + } + + shared_ptr(shared_ptr&& other) noexcept : px(std::exchange(other.px, nullptr)), + pn(std::exchange(other.pn, nullptr)) {} + + ~shared_ptr() + { + release(); + } + + shared_ptr& operator=(const shared_ptr& other) + { + if (this != &other) + { + release(); + + px = other.px; + pn = other.pn; + + add_ref(); + } + + return *this; + } + + shared_ptr& operator=(shared_ptr&& other) noexcept + { + if (this != &other) + { + release(); + + px = std::exchange(other.px, nullptr); + pn = std::exchange(other.pn, nullptr); + } + + return *this; + } + + T* get() const { return px; } + + detail::sp_dereference operator*() const { assert(px); return *px; } + T* operator->() const { assert(px); return px; } + + explicit operator bool() const { return px != nullptr; } + + size_t use_count() const { return pn ? pn->use_count() : 0; } + }; + + using anonymous_shared_ptr = shared_ptr; +} diff --git a/UnleashedRecomp/cpu/guest_stack_var.h b/UnleashedRecomp/cpu/guest_stack_var.h new file mode 100644 index 00000000..e4e9406d --- /dev/null +++ b/UnleashedRecomp/cpu/guest_stack_var.h @@ -0,0 +1,123 @@ +#pragma once + +#include "ppc_context.h" +#include + +// DO NOT use this type as anything other than a local variable. +// This includes returning. It'll cause memory to leak in the guest stack! + +template +class guest_stack_var +{ +private: + uint32_t m_ptr = NULL; + uint32_t m_oldStackPtr = NULL; + + void AllocGuestStackMemory() + { + auto ctx = GetPPCContext(); + m_oldStackPtr = ctx->r1.u32; + m_ptr = (ctx->r1.u32 - sizeof(T)) & ~(std::max(alignof(T), 8) - 1); + ctx->r1.u32 = m_ptr; + } + +public: + T* get() + { + return reinterpret_cast(g_memory.Translate(m_ptr)); + } + + const T* get() const + { + return reinterpret_cast(g_memory.Translate(m_ptr)); + } + + template + guest_stack_var(Args&&... args) + { + AllocGuestStackMemory(); + + if (Init) + new (get()) T(std::forward(args)...); + } + + guest_stack_var(const guest_stack_var& other) + { + AllocGuestStackMemory(); + + if (Init) + new (get()) T(*other->get()); + } + + guest_stack_var(guest_stack_var&& other) + { + AllocGuestStackMemory(); + + if (Init) + new (get()) T(std::move(*other->get())); + } + + ~guest_stack_var() + { + get()->~T(); + + auto ctx = GetPPCContext(); + // This assert will fail if the type was used as anything other than a local variable. + assert(ctx->r1.u32 == m_ptr); + ctx->r1.u32 = m_oldStackPtr; + } + + void operator=(const guest_stack_var& other) + { + if (this != &other) + *get() = *other->get(); + } + + void operator=(guest_stack_var&& other) + { + if (this != &other) + *get() = std::move(*other->get()); + } + + void operator=(const T& other) + { + if (get() != &other) + *get() = *other; + } + + void operator=(T&& other) + { + if (get() != &other) + *get() = std::move(*other); + } + + operator const T* () const + { + return get(); + } + + operator T* () + { + return get(); + } + + const T* operator->() const + { + return get(); + } + + T* operator->() + { + return get(); + } + + const T& operator*() const + { + return *get(); + } + + T& operator*() + { + return *get(); + } +}; diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index 5f27f32b..109468e0 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -935,23 +935,23 @@ static void ProcSetRenderState(const RenderCommand& cmd) static const std::pair g_setRenderStateFunctions[] = { - { D3DRS_ZENABLE, GuestFunction> }, - { D3DRS_ZWRITEENABLE, GuestFunction> }, - { D3DRS_ALPHATESTENABLE, GuestFunction> }, - { D3DRS_SRCBLEND, GuestFunction> }, - { D3DRS_DESTBLEND, GuestFunction> }, - { D3DRS_CULLMODE, GuestFunction> }, - { D3DRS_ZFUNC, GuestFunction> }, - { D3DRS_ALPHAREF, GuestFunction> }, - { D3DRS_ALPHABLENDENABLE, GuestFunction> }, - { D3DRS_BLENDOP, GuestFunction> }, - { D3DRS_SCISSORTESTENABLE, GuestFunction> }, - { D3DRS_SLOPESCALEDEPTHBIAS, GuestFunction> }, - { D3DRS_DEPTHBIAS, GuestFunction> }, - { D3DRS_SRCBLENDALPHA, GuestFunction> }, - { D3DRS_DESTBLENDALPHA, GuestFunction> }, - { D3DRS_BLENDOPALPHA, GuestFunction> }, - { D3DRS_COLORWRITEENABLE, GuestFunction> } + { D3DRS_ZENABLE, HostToGuestFunction> }, + { D3DRS_ZWRITEENABLE, HostToGuestFunction> }, + { D3DRS_ALPHATESTENABLE, HostToGuestFunction> }, + { D3DRS_SRCBLEND, HostToGuestFunction> }, + { D3DRS_DESTBLEND, HostToGuestFunction> }, + { D3DRS_CULLMODE, HostToGuestFunction> }, + { D3DRS_ZFUNC, HostToGuestFunction> }, + { D3DRS_ALPHAREF, HostToGuestFunction> }, + { D3DRS_ALPHABLENDENABLE, HostToGuestFunction> }, + { D3DRS_BLENDOP, HostToGuestFunction> }, + { D3DRS_SCISSORTESTENABLE, HostToGuestFunction> }, + { D3DRS_SLOPESCALEDEPTHBIAS, HostToGuestFunction> }, + { D3DRS_DEPTHBIAS, HostToGuestFunction> }, + { D3DRS_SRCBLENDALPHA, HostToGuestFunction> }, + { D3DRS_DESTBLENDALPHA, HostToGuestFunction> }, + { D3DRS_BLENDOPALPHA, HostToGuestFunction> }, + { D3DRS_COLORWRITEENABLE, HostToGuestFunction> } }; static std::unique_ptr g_resolveMsaaDepthPipelines[3]; @@ -1407,7 +1407,7 @@ static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, memset(device, 0, sizeof(*device)); uint32_t functionOffset = 0x443344; // D3D - g_codeCache.Insert(functionOffset, reinterpret_cast(GuestFunction)); + g_codeCache.Insert(functionOffset, reinterpret_cast(HostToGuestFunction)); for (size_t i = 0; i < _countof(device->setRenderStateFunctions); i++) device->setRenderStateFunctions[i] = functionOffset; @@ -3831,8 +3831,8 @@ void SetShadowResolutionMidAsmHook(PPCRegister& r11) static void SetResolution(be* device) { - uint32_t width = uint32_t(g_swapChain->getWidth() * Config::ResolutionScale); - uint32_t height = uint32_t(g_swapChain->getHeight() * Config::ResolutionScale); + uint32_t width = uint32_t(round(g_swapChain->getWidth() * Config::ResolutionScale)); + uint32_t height = uint32_t(round(g_swapChain->getHeight() * Config::ResolutionScale)); device[46] = width == 0 ? 880 : width; device[47] = height == 0 ? 720 : height; } diff --git a/UnleashedRecomp/kernel/function.h b/UnleashedRecomp/kernel/function.h index 14eb09cc..14e88ea7 100644 --- a/UnleashedRecomp/kernel/function.h +++ b/UnleashedRecomp/kernel/function.h @@ -1,7 +1,9 @@ #pragma once + #include #include #include "xbox.h" +#include "memory.h" template constexpr std::tuple function_args(R(*)(T...)) noexcept @@ -78,10 +80,54 @@ struct ArgTranslator [[unlikely]] default: break; } - // how did you end up here + // TODO: get value from stack. return 0; } + FORCEINLINE constexpr static void SetIntegerArgumentValue(PPCContext& ctx, uint8_t* base, size_t arg, uint64_t value) noexcept + { + if (arg <= 7) + { + switch (arg) + { + case 0: ctx.r3.u64 = value; return; + case 1: ctx.r4.u64 = value; return; + case 2: ctx.r5.u64 = value; return; + case 3: ctx.r6.u64 = value; return; + case 4: ctx.r7.u64 = value; return; + case 5: ctx.r8.u64 = value; return; + case 6: ctx.r9.u64 = value; return; + case 7: ctx.r10.u64 = value; return; + [[unlikely]] default: break; + } + } + + assert(arg < 7 && "Pushing to stack memory is not yet supported."); + } + + FORCEINLINE static void SetPrecisionArgumentValue(PPCContext& ctx, uint8_t* base, size_t arg, double value) noexcept + { + switch (arg) + { + case 0: ctx.f1.f64 = value; return; + case 1: ctx.f2.f64 = value; return; + case 2: ctx.f3.f64 = value; return; + case 3: ctx.f4.f64 = value; return; + case 4: ctx.f5.f64 = value; return; + case 5: ctx.f6.f64 = value; return; + case 6: ctx.f7.f64 = value; return; + case 7: ctx.f8.f64 = value; return; + case 8: ctx.f9.f64 = value; return; + case 9: ctx.f10.f64 = value; return; + case 10: ctx.f11.f64 = value; return; + case 11: ctx.f12.f64 = value; return; + case 12: ctx.f13.f64 = value; return; + [[unlikely]] default: break; + } + + assert(arg < 12 && "Pushing to stack memory is not yet supported."); + } + template FORCEINLINE constexpr static std::enable_if_t, T> GetValue(PPCContext& ctx, uint8_t* base, size_t idx) noexcept { @@ -106,6 +152,39 @@ struct ArgTranslator return reinterpret_cast(base + static_cast(v)); } + + template + FORCEINLINE constexpr static std::enable_if_t, void> SetValue(PPCContext& ctx, uint8_t* base, size_t idx, T value) noexcept + { + if constexpr (is_precise_v) + { + SetPrecisionArgumentValue(ctx, base, idx, value); + } + else if constexpr (std::is_null_pointer_v) + { + SetIntegerArgumentValue(ctx, base, idx, 0); + } + else if constexpr (std::is_pointer_v) + { + SetIntegerArgumentValue(ctx, base, idx, g_memory.MapVirtual(value)); + } + else + { + SetIntegerArgumentValue(ctx, base, idx, value); + } + } + + template + FORCEINLINE constexpr static std::enable_if_t, void> SetValue(PPCContext& ctx, uint8_t* base, size_t idx, T value) noexcept + { + const auto v = g_memory.MapVirtual((void*)value); + if (!v) + { + return; + } + + SetValue(ctx, base, idx, v); + } }; struct Argument @@ -114,10 +193,10 @@ struct Argument int ordinal{}; }; -template -constexpr std::array::value> GatherFunctionArguments() +template +constexpr std::array> GatherFunctionArguments(const T1& tpl) { - std::array::value> args{}; + std::array> args{}; int floatOrdinal{}; size_t i{}; @@ -126,9 +205,9 @@ constexpr std::array::value> GatherFunctionArguments { std::apply([&](const auto& first, const auto&... rest) { - auto append = [&](const T & v) + auto append = [&](const T2& v) { - if constexpr (is_precise_v) + if constexpr (is_precise_v) { args[i] = { 1, floatOrdinal++ }; } @@ -142,12 +221,18 @@ constexpr std::array::value> GatherFunctionArguments append(first); (append(rest), ...); - }, function_args(Func)); + }, tpl); } return args; } +template +constexpr std::array::value> GatherFunctionArguments() +{ + return GatherFunctionArguments(function_args(Func)); +} + template struct arg_ordinal_t { @@ -155,27 +240,42 @@ struct arg_ordinal_t }; template -FORCEINLINE void _translate_args(PPCContext& ctx, uint8_t* base, std::tuple&) noexcept -requires (I >= sizeof...(TArgs)) +FORCEINLINE void _translate_args_to_host(PPCContext& ctx, uint8_t* base, std::tuple&) noexcept + requires (I >= sizeof...(TArgs)) { } template -FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args(PPCContext& ctx, uint8_t* base, std::tuple& tpl) noexcept +FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args_to_host(PPCContext& ctx, uint8_t* base, std::tuple& tpl) noexcept { using T = std::tuple_element_t>; std::get(tpl) = ArgTranslator::GetValue(ctx, base, arg_ordinal_t::value); - _translate_args(ctx, base, tpl); + _translate_args_to_host(ctx, base, tpl); +} + +template +FORCEINLINE void _translate_args_to_guest(PPCContext& ctx, uint8_t* base, std::tuple&) noexcept + requires (I >= sizeof...(TArgs)) +{ +} + +template +FORCEINLINE std::enable_if_t<(I < sizeof...(TArgs)), void> _translate_args_to_guest(PPCContext& ctx, uint8_t* base, std::tuple& tpl) noexcept +{ + using T = std::tuple_element_t>; + ArgTranslator::SetValue(ctx, base, GatherFunctionArguments(std::tuple{})[I].ordinal, std::get(tpl)); + + _translate_args_to_guest(ctx, base, tpl); } template -FORCEINLINE PPC_FUNC(GuestFunction) +FORCEINLINE PPC_FUNC(HostToGuestFunction) { using ret_t = decltype(std::apply(Func, function_args(Func))); auto args = function_args(Func); - _translate_args(ctx, base, args); + _translate_args_to_host(ctx, base, args); if constexpr (std::is_same_v) { @@ -207,8 +307,54 @@ FORCEINLINE PPC_FUNC(GuestFunction) } } +template +FORCEINLINE T GuestToHostFunction(const TFunction& func, TArgs&&... argv) +{ + auto args = std::make_tuple(std::forward(argv)...); + auto& currentCtx = *GetPPCContext(); + + PPCContext newCtx; // NOTE: No need for zero initialization, has lots of unnecessary code generation. + newCtx.fn = currentCtx.fn; + newCtx.r1 = currentCtx.r1; + newCtx.r13 = currentCtx.r13; + newCtx.fpscr = currentCtx.fpscr; + + _translate_args_to_guest(newCtx, (uint8_t*)g_memory.base, args); + + SetPPCContext(newCtx); + + if constexpr (std::is_function_v) + func(newCtx, (uint8_t*)g_memory.base); + else + (*(PPCFunc**)(newCtx.fn + uint64_t(func) * 2))(newCtx, (uint8_t*)g_memory.base); + + currentCtx.fpscr = newCtx.fpscr; + SetPPCContext(currentCtx); + + if constexpr (std::is_void_v) + { + return; + } + else if constexpr (std::is_pointer_v) + { + return reinterpret_cast((uint64_t)g_memory.Translate(newCtx.r3.u32)); + } + else if constexpr (is_precise_v) + { + return static_cast(newCtx.f1.f64); + } + else if constexpr (std::is_integral_v) + { + return static_cast(newCtx.r3.u64); + } + else + { + static_assert(false, "Unsupported return type."); + } +} + #define GUEST_FUNCTION_HOOK(subroutine, function) \ - PPC_FUNC(subroutine) { GuestFunction(ctx, base); } + PPC_FUNC(subroutine) { HostToGuestFunction(ctx, base); } #define GUEST_FUNCTION_STUB(subroutine) \ PPC_FUNC(subroutine) { } diff --git a/UnleashedRecomp/kernel/heap.h b/UnleashedRecomp/kernel/heap.h index 90da8e64..4e583be5 100644 --- a/UnleashedRecomp/kernel/heap.h +++ b/UnleashedRecomp/kernel/heap.h @@ -1,7 +1,6 @@ #pragma once #include "mutex.h" -#include struct Heap { diff --git a/UnleashedRecomp/kernel/memory.h b/UnleashedRecomp/kernel/memory.h index 8cea4c4f..0a1eba22 100644 --- a/UnleashedRecomp/kernel/memory.h +++ b/UnleashedRecomp/kernel/memory.h @@ -16,11 +16,17 @@ public: void* Translate(size_t offset) const noexcept { + if (offset) + assert(offset < 0x100000000ull); + return base + offset; } uint32_t MapVirtual(void* host) const noexcept { + if (host) + assert(host >= base && host < (base + size)); + return static_cast(static_cast(host) - base); } }; diff --git a/UnleashedRecomp/stdafx.h b/UnleashedRecomp/stdafx.h index 96152f7b..4eabefad 100644 --- a/UnleashedRecomp/stdafx.h +++ b/UnleashedRecomp/stdafx.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "framework.h" #include "mutex.h" diff --git a/thirdparty/PowerRecomp b/thirdparty/PowerRecomp index d8676283..7dd4f91a 160000 --- a/thirdparty/PowerRecomp +++ b/thirdparty/PowerRecomp @@ -1 +1 @@ -Subproject commit d8676283fd1e8990b415cc0e4810c6db895b9fba +Subproject commit 7dd4f91ac635b001a56cc7a27af48f0436bbad3f From 49b0dbe4db4e3dac850ace723c82afdfa6e6090d Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Mon, 25 Nov 2024 16:48:58 +0300 Subject: [PATCH 2/8] Auto generate SWA.h, add offsetof/sizeof asserts. --- UnleashedRecomp/CMakeLists.txt | 29 ++++++++++ UnleashedRecomp/api/CSD/Manager/csdmNode.h | 15 +++--- UnleashedRecomp/api/CSD/Manager/csdmNode.inl | 6 +-- UnleashedRecomp/api/SWA.h | 57 ++++++++++---------- UnleashedRecomp/api/SWA.inl | 28 ++++++++-- 5 files changed, 93 insertions(+), 42 deletions(-) diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 6fb3e98b..14ae843a 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -197,3 +197,32 @@ compile_vertex_shader(movie_vs) compile_pixel_shader(resolve_msaa_depth_2x) compile_pixel_shader(resolve_msaa_depth_4x) compile_pixel_shader(resolve_msaa_depth_8x) + +function(generate_aggregate_header INPUT_DIRECTORY OUTPUT_FILE) + get_filename_component(ABS_OUTPUT_FILE "${OUTPUT_FILE}" ABSOLUTE) + file(GLOB_RECURSE HEADER_FILES "${INPUT_DIRECTORY}/*.h") + set(HEADER_CONTENT "#pragma once\n\n") + + foreach(HEADER_FILE IN LISTS HEADER_FILES) + get_filename_component(ABS_HEADER_FILE "${HEADER_FILE}" ABSOLUTE) + if (ABS_HEADER_FILE STREQUAL ABS_OUTPUT_FILE) + continue() + endif() + file(RELATIVE_PATH RELATIVE_HEADER_FILE "${INPUT_DIRECTORY}" "${HEADER_FILE}") + string(APPEND HEADER_CONTENT "#include \"${RELATIVE_HEADER_FILE}\"\n") + endforeach() + + if (EXISTS "${OUTPUT_FILE}") + file(READ "${OUTPUT_FILE}" EXISTING_CONTENT) + if (EXISTING_CONTENT STREQUAL HEADER_CONTENT) + return() + endif() + endif() + + file(WRITE "${OUTPUT_FILE}" "${HEADER_CONTENT}") +endfunction() + +generate_aggregate_header( + "${CMAKE_CURRENT_SOURCE_DIR}/api" + "${CMAKE_CURRENT_SOURCE_DIR}/api/SWA.h" +) diff --git a/UnleashedRecomp/api/CSD/Manager/csdmNode.h b/UnleashedRecomp/api/CSD/Manager/csdmNode.h index 08942f7a..e4d6b53b 100644 --- a/UnleashedRecomp/api/CSD/Manager/csdmNode.h +++ b/UnleashedRecomp/api/CSD/Manager/csdmNode.h @@ -1,10 +1,11 @@ #pragma once -#include "SWA.inl" -#include "CSD/Manager/csdmBase.h" -#include "CSD/Manager/csdmResourceBase.h" -#include "CSD/Manager/csdmNodeObserver.h" -#include "CSD/Manager/csdmSubjectBase.h" +#include +#include +#include +#include +#include +#include namespace Chao::CSD { @@ -21,7 +22,7 @@ namespace Chao::CSD void SetText(const char* in_pText); void SetText(const wchar_t* in_pText); - Hedgehog::Math::CVector2* GetPosition() const; + void GetPosition(Hedgehog::Math::CVector2& out_rResult) const; void SetPosition(float in_X, float in_Y); void SetHideFlag(uint32_t in_HideFlag); void SetRotation(float in_Rotation); @@ -30,4 +31,4 @@ namespace Chao::CSD }; } -#include "CSD/Manager/csdmNode.inl" +#include diff --git a/UnleashedRecomp/api/CSD/Manager/csdmNode.inl b/UnleashedRecomp/api/CSD/Manager/csdmNode.inl index 92e64079..c420167c 100644 --- a/UnleashedRecomp/api/CSD/Manager/csdmNode.inl +++ b/UnleashedRecomp/api/CSD/Manager/csdmNode.inl @@ -17,11 +17,9 @@ namespace Chao::CSD GuestToHostFunction(0x830BF640, this, in_pText); } - inline Hedgehog::Math::CVector2* CNode::GetPosition() const + inline void CNode::GetPosition(Hedgehog::Math::CVector2& out_rResult) const { - guest_stack_var pos; - GuestToHostFunction(0x830BF008, pos.get(), this); - return pos.get(); + GuestToHostFunction(0x830BF008, &out_rResult, this); } inline void CNode::SetPosition(float in_X, float in_Y) diff --git a/UnleashedRecomp/api/SWA.h b/UnleashedRecomp/api/SWA.h index 305f36d4..00939ff7 100644 --- a/UnleashedRecomp/api/SWA.h +++ b/UnleashedRecomp/api/SWA.h @@ -1,21 +1,5 @@ #pragma once -#include "Hedgehog/Base/hhObject.h" -#include "Hedgehog/Base/System/hhAllocator.h" -#include "Hedgehog/Base/Thread/hhHolder.h" -#include "Hedgehog/Base/Thread/hhHolderBase.h" -#include "Hedgehog/Base/Thread/hhSynchronizedObject.h" -#include "Hedgehog/Base/Thread/hhSynchronizedPtr.h" -#include "Hedgehog/Base/Type/hhSharedString.h" -#include "Hedgehog/Database/System/hhDatabaseData.h" -#include "Hedgehog/Math/Vector2.h" -#include "Hedgehog/MirageCore/Renderable/hhRenderable.h" -#include "Hedgehog/Universe/Engine/hhMessageActor.h" -#include "Hedgehog/Universe/Engine/hhMessageProcess.h" -#include "Hedgehog/Universe/Engine/hhUpdateInfo.h" -#include "Hedgehog/Universe/Engine/hhUpdateUnit.h" -#include "Hedgehog/Universe/Thread/hhParallelJob.h" - #include "CSD/Manager/csdmBase.h" #include "CSD/Manager/csdmMotionPattern.h" #include "CSD/Manager/csdmNode.h" @@ -31,38 +15,57 @@ #include "CSD/Manager/csdmSceneObserver.h" #include "CSD/Manager/csdmSubjectBase.h" #include "CSD/Platform/csdTexList.h" - -#include "SWA/Camera/Camera.h" +#include "Hedgehog/Base/Container/hhVector.h" +#include "Hedgehog/Base/System/hhAllocator.h" +#include "Hedgehog/Base/Thread/hhHolder.h" +#include "Hedgehog/Base/Thread/hhHolderBase.h" +#include "Hedgehog/Base/Thread/hhSynchronizedObject.h" +#include "Hedgehog/Base/Thread/hhSynchronizedPtr.h" +#include "Hedgehog/Base/Type/detail/hhStringHolder.h" +#include "Hedgehog/Base/Type/hhSharedString.h" +#include "Hedgehog/Base/hhObject.h" +#include "Hedgehog/Database/System/hhDatabaseData.h" +#include "Hedgehog/Math/Vector2.h" +#include "Hedgehog/MirageCore/Renderable/hhRenderable.h" +#include "Hedgehog/Universe/Engine/hhMessageActor.h" +#include "Hedgehog/Universe/Engine/hhMessageProcess.h" +#include "Hedgehog/Universe/Engine/hhUpdateInfo.h" +#include "Hedgehog/Universe/Engine/hhUpdateUnit.h" +#include "Hedgehog/Universe/Thread/hhParallelJob.h" #include "SWA/CSD/CsdDatabaseWrapper.h" #include "SWA/CSD/CsdProject.h" #include "SWA/CSD/CsdTexListMirage.h" #include "SWA/CSD/GameObjectCSD.h" +#include "SWA/Camera/Camera.h" #include "SWA/HUD/GeneralWindow/GeneralWindow.h" #include "SWA/HUD/Loading/Loading.h" #include "SWA/HUD/Pause/HudPause.h" #include "SWA/HUD/Sonic/HudSonicStage.h" #include "SWA/Movie/MovieDisplayer.h" #include "SWA/Movie/MovieManager.h" -#include "SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h" #include "SWA/Player/Character/EvilSonic/EvilSonic.h" #include "SWA/Player/Character/EvilSonic/EvilSonicContext.h" +#include "SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h" #include "SWA/Sequence/Unit/SequenceUnitBase.h" #include "SWA/Sequence/Unit/SequenceUnitPlayMovie.h" #include "SWA/Sequence/Utility/SequencePlayMovieWrapper.h" #include "SWA/Sound/Sound.h" #include "SWA/Sound/SoundBGMActSonic.h" #include "SWA/Sound/SoundBGMBase.h" -#include "SWA/System/GameMode/Title/TitleMenu.h" -#include "SWA/System/GameMode/Title/TitleStateBase.h" +#include "SWA/System/Application.h" +#include "SWA/System/ApplicationD3D9.h" +#include "SWA/System/ApplicationDocument.h" +#include "SWA/System/ApplicationXenon.h" +#include "SWA/System/Game.h" +#include "SWA/System/GameDocument.h" #include "SWA/System/GameMode/GameMode.h" #include "SWA/System/GameMode/GameModeStage.h" #include "SWA/System/GameMode/GameModeStageMovie.h" -#include "SWA/System/Application.h" -#include "SWA/System/ApplicationD3D9.h" -#include "SWA/System/ApplicationXenon.h" -#include "SWA/System/ApplicationDocument.h" -#include "SWA/System/Game.h" -#include "SWA/System/GameDocument.h" +#include "SWA/System/GameMode/Title/TitleMenu.h" +#include "SWA/System/GameMode/Title/TitleStateBase.h" #include "SWA/System/GameObject.h" #include "SWA/System/InputState.h" #include "SWA/System/PadState.h" +#include "SWA/System/World.h" +#include "boost/smart_ptr/make_shared_object.h" +#include "boost/smart_ptr/shared_ptr.h" diff --git a/UnleashedRecomp/api/SWA.inl b/UnleashedRecomp/api/SWA.inl index 3c6261f8..22f1117c 100644 --- a/UnleashedRecomp/api/SWA.inl +++ b/UnleashedRecomp/api/SWA.inl @@ -4,13 +4,33 @@ #include #include -#define SWA__CONCAT2(x, y) x##y -#define SWA_CONCAT2(x, y) _CONCAT(x, y) +#define SWA_CONCAT2(x, y) x##y +#define SWA_CONCAT(x, y) SWA_CONCAT2(x, y) #define SWA_INSERT_PADDING(length) \ - uint8_t SWA_CONCAT2(pad, __LINE__)[length] + uint8_t SWA_CONCAT(pad, __LINE__)[length] + +#define SWA_ASSERT_OFFSETOF(type, field, offset) \ + static inline swa_assert_offsetof SWA_CONCAT(_, __COUNTER__) + +#define SWA_ASSERT_SIZEOF(type, size) \ + static inline swa_assert_sizeof SWA_CONCAT(_, __COUNTER__) #define SWA_VIRTUAL_FUNCTION(returnType, virtualIndex, ...) \ GuestToHostFunction(*(be*)(g_memory.Translate(*(be*)(this) + (4 * virtualIndex))), __VA_ARGS__) -struct swa_null_ctor {}; +struct swa_null_ctor +{ +}; + +template +struct swa_assert_offsetof +{ + static_assert(TActual == TExpected, "offsetof assertion failed"); +}; + +template +struct swa_assert_sizeof +{ + static_assert(TActual == TExpected, "sizeof assertion failed"); +}; From 349f07cf77c370be0b9f93a1fd874e5b4bf515d6 Mon Sep 17 00:00:00 2001 From: Skyth <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Mon, 25 Nov 2024 18:29:15 +0300 Subject: [PATCH 3/8] Fix sizeof/offsetof assertions. --- UnleashedRecomp/CMakeLists.txt | 1 + UnleashedRecomp/api/SWA.h | 1 - UnleashedRecomp/api/SWA.inl | 20 +++----------------- UnleashedRecomp/stdafx.h | 1 + 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 14ae843a..d3fd5a9e 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -12,6 +12,7 @@ add_compile_options( -Wno-unused-but-set-variable -Wno-void-pointer-to-int-cast -Wno-int-to-void-pointer-cast + -Wno-invalid-offsetof ) add_compile_definitions( diff --git a/UnleashedRecomp/api/SWA.h b/UnleashedRecomp/api/SWA.h index 00939ff7..bf18f4b2 100644 --- a/UnleashedRecomp/api/SWA.h +++ b/UnleashedRecomp/api/SWA.h @@ -15,7 +15,6 @@ #include "CSD/Manager/csdmSceneObserver.h" #include "CSD/Manager/csdmSubjectBase.h" #include "CSD/Platform/csdTexList.h" -#include "Hedgehog/Base/Container/hhVector.h" #include "Hedgehog/Base/System/hhAllocator.h" #include "Hedgehog/Base/Thread/hhHolder.h" #include "Hedgehog/Base/Thread/hhHolderBase.h" diff --git a/UnleashedRecomp/api/SWA.inl b/UnleashedRecomp/api/SWA.inl index 22f1117c..d6ef4c5a 100644 --- a/UnleashedRecomp/api/SWA.inl +++ b/UnleashedRecomp/api/SWA.inl @@ -11,26 +11,12 @@ uint8_t SWA_CONCAT(pad, __LINE__)[length] #define SWA_ASSERT_OFFSETOF(type, field, offset) \ - static inline swa_assert_offsetof SWA_CONCAT(_, __COUNTER__) + static_assert(offsetof(type, field) == offset) #define SWA_ASSERT_SIZEOF(type, size) \ - static inline swa_assert_sizeof SWA_CONCAT(_, __COUNTER__) + static_assert(sizeof(type) == size) #define SWA_VIRTUAL_FUNCTION(returnType, virtualIndex, ...) \ GuestToHostFunction(*(be*)(g_memory.Translate(*(be*)(this) + (4 * virtualIndex))), __VA_ARGS__) -struct swa_null_ctor -{ -}; - -template -struct swa_assert_offsetof -{ - static_assert(TActual == TExpected, "offsetof assertion failed"); -}; - -template -struct swa_assert_sizeof -{ - static_assert(TActual == TExpected, "sizeof assertion failed"); -}; +struct swa_null_ctor {}; diff --git a/UnleashedRecomp/stdafx.h b/UnleashedRecomp/stdafx.h index 4eabefad..f23df682 100644 --- a/UnleashedRecomp/stdafx.h +++ b/UnleashedRecomp/stdafx.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "framework.h" #include "mutex.h" From d36aa26bac532b78166b95863a6265203b0b5486 Mon Sep 17 00:00:00 2001 From: "Skyth (Asilkan)" <19259897+blueskythlikesclouds@users.noreply.github.com> Date: Fri, 29 Nov 2024 23:30:48 +0300 Subject: [PATCH 4/8] Specialization constants, reverse Z and async PSO implementation. (#9) * Specialization constant implementation for Vulkan. * Implement DXIL library linking. * Implement proper reverse Z & fix motion blur flicker. * Mirage API mapping. * Initial work for async PSO. * Further async PSO work. * Set pipeline names. * Handle special layers writing depth. * Handle bones in shadow pipeline. * Fix additive mode setting wrong pipeline field. * Pass models to compilation threads through shared pointers. * Safety improvements. * Allow DXIL linking to happen in parallel. * Display more debug information. * Queue unique models for compilation immediately. * Put async PSO debug printing behind a macro. * Kick off terrain models to pipeline compilation thread the moment they are made. * Hook a different function to do waiting in. * Fix pipelines getting dropped. * Account for ConstTexCoord. * Fix async PSO accounting for alpha to coverage even when MSAA is off. * Remove "has bone" specialization constant. * Sky shader compilation & more debugging helpers. * Assign names to shaders during loading. * Fix string symbol definitions. * Print description of recently compiled render thread pipelines. * Switch to an enum library that doesn't murder IntelliSense. * Precompile pipelines for object icons. * Skip fur pipelines. * Skip printing info for pipelines compiled during loading. * Precompile pipelines for Sonic's mouth, motion blur, and forced transparent objects. * Precompile planar reflection shaders. * Precompile sparkle shaders in loading screens. * Precompile fur shader. * Refactor model traversing to enqueue every single compilation to worker threads. * Dynamically create pipeline threads depending on hardware concurrency. * Fix MSAA depth resolve not accounting for reverse Z. * Integrate smol-v. * Implement PSO caching. * Update ShaderRecomp & remove unused function. --- UnleashedRecomp/CMakeLists.txt | 10 + .../api/Hedgehog/Base/Container/hhMap.h | 378 ++++ .../api/Hedgehog/Base/Container/hhVector.h | 255 +++ .../api/Hedgehog/Base/System/hhSymbol.h | 27 + .../api/Hedgehog/Base/System/hhSymbol.inl | 31 + .../Base/Type/detail/hhStringHolder.h | 4 +- .../Hedgehog/Database/System/hhDatabaseData.h | 3 +- .../Database/System/hhDatabaseData.inl | 2 +- .../MirageCore/Misc/hhVertexDeclarationPtr.h | 19 + .../MirageCore/RenderData/hhMaterialData.h | 39 + .../MirageCore/RenderData/hhMeshData.h | 43 + .../MirageCore/RenderData/hhModelData.h | 46 + .../RenderData/hhNodeGroupModelData.h | 30 + .../RenderData/hhPixelShaderCodeData.h | 30 + .../MirageCore/RenderData/hhPixelShaderData.h | 22 + .../MirageCore/RenderData/hhShaderListData.h | 46 + .../RenderData/hhTerrainModelData.h | 29 + .../MirageCore/RenderData/hhTexsetData.h | 24 + .../MirageCore/RenderData/hhTextureData.h | 17 + .../RenderData/hhVertexShaderCodeData.h | 30 + .../RenderData/hhVertexShaderData.h | 22 + .../api/Hedgehog/Sparkle/hhParticleMaterial.h | 41 + UnleashedRecomp/api/SWA.h | 17 + .../api/boost/smart_ptr/shared_ptr.h | 18 +- .../gpu/cache/pipeline_state_cache.h | 65 + .../gpu/cache/vertex_declaration_cache.h | 14 + .../gpu/cache/vertex_element_cache.h | 14 + UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp | 12 + UnleashedRecomp/gpu/rhi/rt64_d3d12.h | 3 + .../gpu/rhi/rt64_render_interface.h | 1 + UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp | 12 + UnleashedRecomp/gpu/rhi/rt64_vulkan.h | 3 + .../gpu/shader/gamma_correction_ps.hlsl | 2 +- UnleashedRecomp/gpu/shader/movie_common.hlsli | 2 +- .../gpu/shader/resolve_msaa_depth.hlsli | 2 +- UnleashedRecomp/gpu/video.cpp | 1707 +++++++++++++++-- UnleashedRecomp/gpu/video.h | 33 +- UnleashedRecomp/natvis.natvis | 21 + UnleashedRecomp/stdafx.h | 6 + UnleashedRecomp/ui/window.cpp | 6 +- UnleashedRecompLib/CMakeLists.txt | 2 +- UnleashedRecompLib/config/SWA.toml | 25 + UnleashedRecompLib/shader/shader_cache.h | 3 +- thirdparty/ShaderRecomp | 2 +- vcpkg.json | 3 +- 45 files changed, 2959 insertions(+), 162 deletions(-) create mode 100644 UnleashedRecomp/api/Hedgehog/Base/Container/hhMap.h create mode 100644 UnleashedRecomp/api/Hedgehog/Base/Container/hhVector.h create mode 100644 UnleashedRecomp/api/Hedgehog/Base/System/hhSymbol.h create mode 100644 UnleashedRecomp/api/Hedgehog/Base/System/hhSymbol.inl create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/Misc/hhVertexDeclarationPtr.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhMaterialData.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhMeshData.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhModelData.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhNodeGroupModelData.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhPixelShaderCodeData.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhPixelShaderData.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhShaderListData.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhTerrainModelData.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhTexsetData.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhTextureData.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhVertexShaderCodeData.h create mode 100644 UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhVertexShaderData.h create mode 100644 UnleashedRecomp/api/Hedgehog/Sparkle/hhParticleMaterial.h create mode 100644 UnleashedRecomp/gpu/cache/pipeline_state_cache.h create mode 100644 UnleashedRecomp/gpu/cache/vertex_declaration_cache.h create mode 100644 UnleashedRecomp/gpu/cache/vertex_element_cache.h create mode 100644 UnleashedRecomp/natvis.natvis diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index d3fd5a9e..75512991 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -79,6 +79,8 @@ set(SWA_UI_CXX_SOURCES "ui/window.cpp" ) +set(SMOLV_SOURCE_DIR "${SWA_THIRDPARTY_ROOT}/ShaderRecomp/thirdparty/smol-v/source") + set(SWA_CXX_SOURCES "app.cpp" "main.cpp" @@ -93,6 +95,8 @@ set(SWA_CXX_SOURCES ${SWA_HID_CXX_SOURCES} ${SWA_PATCHES_CXX_SOURCES} ${SWA_UI_CXX_SOURCES} + + "${SMOLV_SOURCE_DIR}/smolv.cpp" ) if (WIN32) @@ -122,6 +126,7 @@ find_package(zstd CONFIG REQUIRED) find_package(Stb REQUIRED) find_package(unofficial-concurrentqueue REQUIRED) find_package(imgui CONFIG REQUIRED) +find_package(magic_enum CONFIG REQUIRED) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12) add_custom_command(TARGET UnleashedRecomp POST_BUILD @@ -130,10 +135,13 @@ add_custom_command(TARGET UnleashedRecomp POST_BUILD COMMAND_EXPAND_LISTS ) +file(COPY ${PACKAGE_PREFIX_DIR}/bin/dxil.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(UnleashedRecomp PRIVATE Microsoft::DirectX-Headers Microsoft::DirectX-Guids Microsoft::DirectX12-Agility + Microsoft::DirectXShaderCompiler comctl32 dxgi Vulkan::Headers @@ -154,6 +162,7 @@ target_link_libraries(UnleashedRecomp PRIVATE unofficial::concurrentqueue::concurrentqueue Synchronization imgui::imgui + magic_enum::magic_enum ) target_include_directories(UnleashedRecomp PRIVATE @@ -161,6 +170,7 @@ target_include_directories(UnleashedRecomp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/api ${SWA_THIRDPARTY_ROOT}/ddspp ${Stb_INCLUDE_DIR} + ${SMOLV_SOURCE_DIR} ) target_precompile_headers(UnleashedRecomp PUBLIC ${SWA_PRECOMPILED_HEADERS}) diff --git a/UnleashedRecomp/api/Hedgehog/Base/Container/hhMap.h b/UnleashedRecomp/api/Hedgehog/Base/Container/hhMap.h new file mode 100644 index 00000000..a38ba356 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/Container/hhMap.h @@ -0,0 +1,378 @@ +#pragma once + +#include + +namespace hh +{ + template< + class Key, + class T, + class Compare = std::less, + class Allocator = Hedgehog::Base::TAllocator>> + class map + { + protected: + enum EColor + { + eColor_Red, + eColor_Black + }; + + struct SNode + { + using allocator_type = typename std::allocator_traits::template rebind_alloc; + + xpointer pLeft; + xpointer pParent; + xpointer pRight; + std::pair Value; + uint8_t Color; + bool IsNil; + }; + + Compare m_Comp; + typename SNode::allocator_type m_Alloc; + xpointer m_pHead; + be m_Count; + + struct SFindResult + { + SNode* pParent; + bool IsRight; + SNode* pBound; + }; + + bool LowerBoundDuplicate(const SNode* pBound, const Key& in_rKey) const + { + return !pBound->IsNil && !m_Comp(in_rKey, pBound->Value.first); + } + + SFindResult FindLowerBound(const Key& in_rKey) const + { + SFindResult result{ m_pHead->pParent, true, m_pHead }; + SNode* pNode = result.pParent; + + while (!pNode->IsNil) + { + result.pParent = pNode; + if (m_Comp(pNode->Value.first, in_rKey)) + { + result.IsRight = true; + pNode = pNode->pRight; + } + else + { + result.IsRight = false; + result.pBound = pNode; + pNode = pNode->pLeft; + } + } + + return result; + } + + SNode* Find(const Key& in_rKey) const + { + const SFindResult result = FindLowerBound(in_rKey); + return LowerBoundDuplicate(result.pBound, in_rKey) ? result.pBound : m_pHead.get(); + } + + static SNode* Max(SNode* pNode) + { + while (!pNode->pRight->IsNil) + pNode = pNode->pRight; + + return pNode; + } + + static SNode* Min(SNode* pNode) + { + while (!pNode->pLeft->IsNil) + pNode = pNode->pLeft; + + return pNode; + } + + public: + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using key_compare = Compare; + using allocator_type = Allocator; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + + class iterator + { + public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = std::pair; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + + iterator(const std::nullptr_t&) = delete; + iterator(SNode* pNode) : m_pNode(pNode) {} + + reference operator*() const { return m_pNode->Value; } + pointer operator->() const { return &m_pNode->Value; } + + iterator& operator++() + { + if (m_pNode->pRight->IsNil) + { + SNode* pNode; + while (!(pNode = m_pNode->pParent)->IsNil && m_pNode == pNode->pRight) + m_pNode = pNode; + + m_pNode = pNode; + } + else + { + m_pNode = map::Min(m_pNode->pRight); + } + + return *this; + } + + iterator operator++(int) + { + iterator temp(*this); + ++(*this); + return temp; + } + + iterator& operator--() + { + if (m_pNode->IsNil) + { + m_pNode = m_pNode->pRight; + } + else if (m_pNode->pLeft->IsNil) + { + SNode* pNode; + while (!(pNode = m_pNode->pParent)->IsNil && m_pNode == pNode->pLeft) + m_pNode = pNode; + + if (!m_pNode->IsNil) + m_pNode = pNode; + } + else + { + m_pNode = map::Max(m_pNode->pLeft); + } + + return *this; + } + + iterator operator--(int) + { + iterator temp(*this); + --(*this); + return temp; + } + + bool operator==(const iterator& rhs) const { return m_pNode == rhs.m_pNode; } + bool operator!=(const iterator& rhs) const { return !(*this == rhs); } + + private: + SNode* m_pNode; + friend class iterator; + friend class map; + }; + + class const_iterator + { + public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = std::pair; + using difference_type = std::ptrdiff_t; + using pointer = const value_type*; + using reference = const value_type&; + + const_iterator(const std::nullptr_t&) = delete; + const_iterator(SNode* pNode) : m_pNode(pNode) {} + const_iterator(const iterator& iterator) : m_pNode(iterator.m_pNode) {} + + reference operator*() const { return m_pNode->Value; } + pointer operator->() const { return &m_pNode->Value; } + + const_iterator& operator++() + { + if (m_pNode->pRight->IsNil) + { + SNode* pNode; + while (!(pNode = m_pNode->pParent)->IsNil && m_pNode == pNode->pRight) + m_pNode = pNode; + + m_pNode = pNode; + } + else + { + m_pNode = map::Min(m_pNode->pRight); + } + + return *this; + } + + const_iterator operator++(int) + { + const_iterator temp(*this); + ++(*this); + return temp; + } + + const_iterator& operator--() + { + if (m_pNode->IsNil) + { + m_pNode = m_pNode->pRight; + } + else if (m_pNode->pLeft->IsNil) + { + SNode* pNode; + while (!(pNode = m_pNode->pParent)->IsNil && m_pNode == pNode->pLeft) + m_pNode = pNode; + + if (!m_pNode->IsNil) + m_pNode = pNode; + } + else + { + m_pNode = map::Max(m_pNode->pLeft); + } + + return *this; + } + + const_iterator operator--(int) + { + const_iterator temp(*this); + --(*this); + return temp; + } + + bool operator==(const const_iterator& rhs) const { return m_pNode == rhs.m_pNode; } + bool operator!=(const const_iterator& rhs) const { return !(*this == rhs); } + + private: + SNode* m_pNode; + friend class map; + }; + + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + public: + allocator_type get_allocator() const + { + return m_Alloc; + } + + T& at(const Key& key) + { + return Find(key)->Value.second; + } + + const T& at(const Key& key) const + { + return Find(key)->Value.second; + } + + iterator begin() + { + return iterator(m_pHead->pLeft); + } + + const_iterator begin() const + { + return const_iterator(m_pHead->pLeft); + } + + const_iterator cbegin() const + { + return const_iterator(m_pHead->pLeft); + } + + iterator end() + { + return iterator(m_pHead); + } + + const_iterator end() const + { + return const_iterator(m_pHead); + } + + const_iterator cend() const + { + return const_iterator(m_pHead); + } + + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(cend()); + } + + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + + const_reverse_iterator crend() const + { + return const_reverse_iterator(cbegin()); + } + + bool empty() const + { + return m_Count == 0; + } + + size_type size() const + { + return m_Count; + } + + size_type max_size() const + { + return ~0u; + } + + size_type count(const Key& key) const + { + return LowerBoundDuplicate(FindLowerBound(key).pBound, key) ? 1u : 0u; + } + + iterator find(const Key& key) + { + return iterator(Find(key)); + } + + const_iterator find(const Key& key) const + { + return const_iterator(Find(key)); + } + }; + + static_assert(sizeof(map) == 0xC); +} diff --git a/UnleashedRecomp/api/Hedgehog/Base/Container/hhVector.h b/UnleashedRecomp/api/Hedgehog/Base/Container/hhVector.h new file mode 100644 index 00000000..42f3b959 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/Container/hhVector.h @@ -0,0 +1,255 @@ +#pragma once + +#include + +namespace hh +{ + template> + class vector + { + protected: + Allocator m_Alloc; + xpointer m_pFirst; + xpointer m_pLast; + xpointer m_pEnd; + + public: + using value_type = T; + using allocator_type = Allocator; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + + class iterator + { + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = T*; + using reference = T&; + + iterator() : m_pPtr(nullptr) {} + iterator(T* p) : m_pPtr(p) {} + + reference operator*() const { return *m_pPtr; } + pointer operator->() const { return m_pPtr; } + + iterator& operator++() { ++m_pPtr; return *this; } + iterator operator++(int) { iterator tmp = *this; ++(*this); return tmp; } + + iterator& operator--() { --m_pPtr; return *this; } + iterator operator--(int) { iterator tmp = *this; --(*this); return tmp; } + + iterator& operator+=(difference_type n) { m_pPtr += n; return *this; } + iterator operator+(difference_type n) const { iterator tmp = *this; return tmp += n; } + friend iterator operator+(difference_type n, iterator it) { return it + n; } + + iterator& operator-=(difference_type n) { return *this += -n; } + iterator operator-(difference_type n) const { iterator tmp = *this; return tmp -= n; } + difference_type operator-(const iterator& other) const { return m_pPtr - other.m_pPtr; } + + reference operator[](difference_type n) const { return *(*this + n); } + + bool operator==(const iterator& other) const { return m_pPtr == other.m_pPtr; } + bool operator!=(const iterator& other) const { return !(*this == other); } + bool operator<(const iterator& other) const { return m_pPtr < other.m_pPtr; } + bool operator<=(const iterator& other) const { return !(other < *this); } + bool operator>(const iterator& other) const { return other < *this; } + bool operator>=(const iterator& other) const { return !(*this < other); } + + private: + T* m_pPtr; + + friend class vector; + friend class const_iterator; + }; + + class const_iterator + { + public: + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = const T*; + using reference = const T&; + + const_iterator() : m_pPtr(nullptr) {} + const_iterator(T* p) : m_pPtr(p) {} + const_iterator(const iterator& other) : m_pPtr(other.m_pPtr) {} + + reference operator*() const { return *m_pPtr; } + pointer operator->() const { return m_pPtr; } + + const_iterator& operator++() { ++m_pPtr; return *this; } + const_iterator operator++(int) { const_iterator tmp = *this; ++(*this); return tmp; } + + const_iterator& operator--() { --m_pPtr; return *this; } + const_iterator operator--(int) { const_iterator tmp = *this; --(*this); return tmp; } + + const_iterator& operator+=(difference_type n) { m_pPtr += n; return *this; } + const_iterator operator+(difference_type n) const { const_iterator tmp = *this; return tmp += n; } + friend const_iterator operator+(difference_type n, const_iterator it) { return it + n; } + + const_iterator& operator-=(difference_type n) { return *this += -n; } + const_iterator operator-(difference_type n) const { const_iterator tmp = *this; return tmp -= n; } + difference_type operator-(const const_iterator& other) const { return m_pPtr - other.m_pPtr; } + + reference operator[](difference_type n) const { return *(*this + n); } + + bool operator==(const const_iterator& other) const { return m_pPtr == other.m_pPtr; } + bool operator!=(const const_iterator& other) const { return !(*this == other); } + bool operator<(const const_iterator& other) const { return m_pPtr < other.m_pPtr; } + bool operator<=(const const_iterator& other) const { return !(other < *this); } + bool operator>(const const_iterator& other) const { return other < *this; } + bool operator>=(const const_iterator& other) const { return !(*this < other); } + + private: + T* m_pPtr; + friend class vector; + }; + + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + allocator_type get_allocator() const + { + return m_Alloc; + } + + reference at(size_type pos) + { + return m_pFirst[pos]; + } + + const_reference at(size_type pos) const + { + return m_pFirst[pos]; + } + + reference operator[](size_type pos) + { + return m_pFirst[pos]; + } + + const_reference operator[](size_type pos) const + { + return m_pFirst[pos]; + } + + reference front() + { + return m_pFirst[0]; + } + + const_reference front() const + { + return m_pFirst[0]; + } + + reference back() + { + return m_pLast[-1]; + } + + const_reference back() const + { + return m_pLast[-1]; + } + + T* data() + { + return m_pFirst; + } + + const T* data() const + { + return m_pFirst; + } + + iterator begin() + { + return iterator(m_pFirst); + } + + const_iterator begin() const + { + return const_iterator(m_pFirst); + } + + const_iterator cbegin() const + { + return const_iterator(m_pFirst); + } + + iterator end() + { + return iterator(m_pLast); + } + + const_iterator end() const + { + return const_iterator(m_pLast); + } + + const_iterator cend() const + { + return const_iterator(m_pLast); + } + + reverse_iterator rbegin() + { + return reverse_iterator(end()); + } + + const_reverse_iterator rbegin() const + { + return const_reverse_iterator(end()); + } + + const_reverse_iterator crbegin() const + { + return const_reverse_iterator(cend()); + } + + reverse_iterator rend() + { + return reverse_iterator(begin()); + } + + const_reverse_iterator rend() const + { + return const_reverse_iterator(begin()); + } + + const_reverse_iterator crend() const + { + return const_reverse_iterator(cbegin()); + } + + bool empty() const + { + return m_pFirst == m_pLast; + } + + size_type size() const + { + return m_pLast - m_pFirst; + } + + size_type max_size() const + { + return ~0u; + } + + size_type capacity() const + { + return m_pEnd - m_pFirst; + } + }; + + SWA_ASSERT_SIZEOF(vector, 0x10); +} diff --git a/UnleashedRecomp/api/Hedgehog/Base/System/hhSymbol.h b/UnleashedRecomp/api/Hedgehog/Base/System/hhSymbol.h new file mode 100644 index 00000000..2b874e9c --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/System/hhSymbol.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace Hedgehog::Base +{ + class CSharedString; + + class CStringSymbol + { + public: + be m_Index; + + CStringSymbol(); + CStringSymbol(const char* in_pName); + CStringSymbol(const CSharedString& in_rName); + + bool operator==(const CStringSymbol& in_rOther) const; + bool operator!=(const CStringSymbol& in_rOther) const; + bool operator<(const CStringSymbol& in_rOther) const; + }; + + SWA_ASSERT_OFFSETOF(CStringSymbol, m_Index, 0); + SWA_ASSERT_SIZEOF(CStringSymbol, 4); +} + +#include diff --git a/UnleashedRecomp/api/Hedgehog/Base/System/hhSymbol.inl b/UnleashedRecomp/api/Hedgehog/Base/System/hhSymbol.inl new file mode 100644 index 00000000..b0acc103 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Base/System/hhSymbol.inl @@ -0,0 +1,31 @@ +namespace Hedgehog::Base +{ + inline CStringSymbol::CStringSymbol() + { + } + + inline CStringSymbol::CStringSymbol(const char* in_pName) + { + GuestToHostFunction(sub_82E014D8, this, in_pName); + } + + inline CStringSymbol::CStringSymbol(const CSharedString& in_rName) + { + GuestToHostFunction(sub_82E013B0, this, &in_rName); + } + + inline bool CStringSymbol::operator==(const CStringSymbol& in_rOther) const + { + return m_Index == in_rOther.m_Index; + } + + inline bool CStringSymbol::operator!=(const CStringSymbol& in_rOther) const + { + return m_Index != in_rOther.m_Index; + } + + inline bool CStringSymbol::operator<(const CStringSymbol& in_rOther) const + { + return m_Index < in_rOther.m_Index; + } +} diff --git a/UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.h b/UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.h index 087de601..4fd1cd25 100644 --- a/UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.h +++ b/UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.h @@ -1,6 +1,6 @@ #pragma once -#include "SWA.inl" +#include namespace Hedgehog::Base { @@ -41,4 +41,4 @@ namespace Hedgehog::Base }; } -#include "Hedgehog/Base/Type/detail/hhStringHolder.inl" +#include diff --git a/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.h b/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.h index 8552a514..3a7ac2b0 100644 --- a/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.h +++ b/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.h @@ -1,6 +1,7 @@ #pragma once -#include "Hedgehog/Base/hhObject.h" +#include +#include namespace Hedgehog::Database { diff --git a/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.inl b/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.inl index 7e3e383f..6132b394 100644 --- a/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.inl +++ b/UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.inl @@ -7,7 +7,7 @@ namespace Hedgehog::Database inline bool CDatabaseData::CheckMadeAll() { - return true; + return GuestToHostFunction(m_pVftable->m_fpCheckMadeAll, this); } inline bool CDatabaseData::IsMadeOne() const diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/Misc/hhVertexDeclarationPtr.h b/UnleashedRecomp/api/Hedgehog/MirageCore/Misc/hhVertexDeclarationPtr.h new file mode 100644 index 00000000..bf0c4917 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/Misc/hhVertexDeclarationPtr.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace Hedgehog::Mirage +{ + class CRenderingInfrastructure; + + class CVertexDeclarationPtr + { + public: + xpointer m_pD3DVertexDeclaration; + xpointer m_pRenderingInfrastructure; + }; + + SWA_ASSERT_OFFSETOF(CVertexDeclarationPtr, m_pD3DVertexDeclaration, 0x0); + SWA_ASSERT_OFFSETOF(CVertexDeclarationPtr, m_pRenderingInfrastructure, 0x4); + SWA_ASSERT_SIZEOF(CVertexDeclarationPtr, 0x8); +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhMaterialData.h b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhMaterialData.h new file mode 100644 index 00000000..0be6a3e2 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhMaterialData.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +#include +#include + +namespace Hedgehog::Mirage +{ + class CMaterialData; + class CTexsetData; + class CShaderListData; + class CParameterFloat4Element; + class CParameterInt4Element; + class CParameterBoolElement; + + class CMaterialData : public Database::CDatabaseData + { + public: + boost::shared_ptr m_spShaderListData; + boost::shared_ptr m_spTexsetData; + hh::vector> m_Float4Params; + hh::vector> m_Int4Params; + hh::vector> m_Bool4Params; + uint8_t m_AlphaThreshold; + bool m_DoubleSided; + bool m_Additive; + }; + + SWA_ASSERT_OFFSETOF(CMaterialData, m_spShaderListData, 0xC); + SWA_ASSERT_OFFSETOF(CMaterialData, m_spTexsetData, 0x14); + SWA_ASSERT_OFFSETOF(CMaterialData, m_Float4Params, 0x1C); + SWA_ASSERT_OFFSETOF(CMaterialData, m_Int4Params, 0x2C); + SWA_ASSERT_OFFSETOF(CMaterialData, m_Bool4Params, 0x3C); + SWA_ASSERT_OFFSETOF(CMaterialData, m_AlphaThreshold, 0x4C); + SWA_ASSERT_OFFSETOF(CMaterialData, m_DoubleSided, 0x4D); + SWA_ASSERT_OFFSETOF(CMaterialData, m_Additive, 0x4E); + SWA_ASSERT_SIZEOF(CMaterialData, 0x50); +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhMeshData.h b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhMeshData.h new file mode 100644 index 00000000..3fc6a9f9 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhMeshData.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include +#include +#include + +namespace Hedgehog::Mirage +{ + class CMaterialData; + + class CMeshData : public Database::CDatabaseData + { + public: + be m_IndexNum; + be m_VertexNum; + be m_VertexSize; + be m_NodeNum; + xpointer m_pNodeIndices; + be m_VertexOffset; + be m_IndexOffset; + xpointer m_pD3DIndexBuffer; + xpointer m_pD3DVertexBuffer; + CVertexDeclarationPtr m_VertexDeclarationPtr; + SWA_INSERT_PADDING(0x4); + boost::shared_ptr m_spMaterial; + SWA_INSERT_PADDING(0xC); + }; + + SWA_ASSERT_OFFSETOF(CMeshData, m_IndexNum, 0xC); + SWA_ASSERT_OFFSETOF(CMeshData, m_VertexNum, 0x10); + SWA_ASSERT_OFFSETOF(CMeshData, m_VertexSize, 0x14); + SWA_ASSERT_OFFSETOF(CMeshData, m_NodeNum, 0x18); + SWA_ASSERT_OFFSETOF(CMeshData, m_pNodeIndices, 0x1C); + SWA_ASSERT_OFFSETOF(CMeshData, m_VertexOffset, 0x20); + SWA_ASSERT_OFFSETOF(CMeshData, m_IndexOffset, 0x24); + SWA_ASSERT_OFFSETOF(CMeshData, m_pD3DIndexBuffer, 0x28); + SWA_ASSERT_OFFSETOF(CMeshData, m_pD3DVertexBuffer, 0x2C); + SWA_ASSERT_OFFSETOF(CMeshData, m_VertexDeclarationPtr, 0x30); + SWA_ASSERT_OFFSETOF(CMeshData, m_spMaterial, 0x3C); + SWA_ASSERT_SIZEOF(CMeshData, 0x50); +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhModelData.h b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhModelData.h new file mode 100644 index 00000000..d29bc11f --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhModelData.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include + +namespace Hedgehog::Mirage +{ + class CNodeGroupModelData; + class CMeshData; + class CModelNodeData; + class CMatrixData; + class CAabbData; + class CSphereData; + class CMorphModelData; + + class CModelData : public Database::CDatabaseData + { + public: + be m_NodeGroupModelNum; + hh::vector> m_NodeGroupModels; + hh::vector> m_OpaqueMeshes; + hh::vector> m_TransparentMeshes; + hh::vector> m_PunchThroughMeshes; + be m_NodeNum; + boost::shared_ptr m_spNodeParentIndices; + boost::shared_ptr m_spNodes; + boost::shared_ptr m_spNodeMatrices; + boost::shared_ptr m_spAabb; + boost::shared_ptr m_spSphere; + hh::vector> m_MorphModels; + }; + + SWA_ASSERT_OFFSETOF(CModelData, m_NodeGroupModelNum, 0xC); + SWA_ASSERT_OFFSETOF(CModelData, m_NodeGroupModels, 0x10); + SWA_ASSERT_OFFSETOF(CModelData, m_OpaqueMeshes, 0x20); + SWA_ASSERT_OFFSETOF(CModelData, m_TransparentMeshes, 0x30); + SWA_ASSERT_OFFSETOF(CModelData, m_PunchThroughMeshes, 0x40); + SWA_ASSERT_OFFSETOF(CModelData, m_NodeNum, 0x50); + SWA_ASSERT_OFFSETOF(CModelData, m_spNodeParentIndices, 0x54); + SWA_ASSERT_OFFSETOF(CModelData, m_spNodes, 0x5C); + SWA_ASSERT_OFFSETOF(CModelData, m_spNodeMatrices, 0x64); + SWA_ASSERT_OFFSETOF(CModelData, m_spAabb, 0x6C); + SWA_ASSERT_OFFSETOF(CModelData, m_spSphere, 0x74); + SWA_ASSERT_OFFSETOF(CModelData, m_MorphModels, 0x7C); + SWA_ASSERT_SIZEOF(CModelData, 0x8C); +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhNodeGroupModelData.h b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhNodeGroupModelData.h new file mode 100644 index 00000000..1c37548b --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhNodeGroupModelData.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +namespace Hedgehog::Mirage +{ + class CMeshData; + + class CNodeGroupModelData : public Database::CDatabaseData + { + public: + hh::vector> m_OpaqueMeshes; + hh::vector> m_TransparentMeshes; + hh::vector> m_PunchThroughMeshes; + be m_SpecialMeshGroupNum; + boost::shared_ptr> m_SpecialMeshGroupModes; + hh::vector>> m_SpecialMeshGroups; + Base::CSharedString m_Name; + }; + + SWA_ASSERT_OFFSETOF(CNodeGroupModelData, m_OpaqueMeshes, 0xC); + SWA_ASSERT_OFFSETOF(CNodeGroupModelData, m_TransparentMeshes, 0x1C); + SWA_ASSERT_OFFSETOF(CNodeGroupModelData, m_PunchThroughMeshes, 0x2C); + SWA_ASSERT_OFFSETOF(CNodeGroupModelData, m_SpecialMeshGroupNum, 0x3C); + SWA_ASSERT_OFFSETOF(CNodeGroupModelData, m_SpecialMeshGroupModes, 0x40); + SWA_ASSERT_OFFSETOF(CNodeGroupModelData, m_SpecialMeshGroups, 0x48); + SWA_ASSERT_OFFSETOF(CNodeGroupModelData, m_Name, 0x58); + SWA_ASSERT_SIZEOF(CNodeGroupModelData, 0x5C); +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhPixelShaderCodeData.h b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhPixelShaderCodeData.h new file mode 100644 index 00000000..ab275e28 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhPixelShaderCodeData.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include + +namespace Hedgehog::Base +{ + class CCriticalSectionD3D9; +} + +namespace Hedgehog::Mirage +{ + class CRenderingInfrastructure; + + class CPixelShaderCodeData : public Database::CDatabaseData + { + public: + xpointer m_pD3DPixelShader; + xpointer m_spFunction; + boost::shared_ptr m_spCriticalSection; + xpointer m_pRenderingInfrastructure; + }; + + SWA_ASSERT_OFFSETOF(CPixelShaderCodeData, m_pD3DPixelShader, 0xC); + SWA_ASSERT_OFFSETOF(CPixelShaderCodeData, m_spFunction, 0x10); + SWA_ASSERT_OFFSETOF(CPixelShaderCodeData, m_spCriticalSection, 0x14); + SWA_ASSERT_OFFSETOF(CPixelShaderCodeData, m_pRenderingInfrastructure, 0x1C); + SWA_ASSERT_SIZEOF(CPixelShaderCodeData, 0x20); +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhPixelShaderData.h b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhPixelShaderData.h new file mode 100644 index 00000000..e2740243 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhPixelShaderData.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +namespace Hedgehog::Mirage +{ + class CPixelShaderCodeData; + class CPixelShaderParameterData; + + class CPixelShaderData : public Hedgehog::Database::CDatabaseData + { + public: + boost::shared_ptr m_spCode; + SWA_INSERT_PADDING(0x4); + hh::vector> m_ParameterList; + }; + + SWA_ASSERT_OFFSETOF(CPixelShaderData, m_spCode, 0xC); + SWA_ASSERT_OFFSETOF(CPixelShaderData, m_ParameterList, 0x18); + SWA_ASSERT_SIZEOF(CPixelShaderData, 0x28); +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhShaderListData.h b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhShaderListData.h new file mode 100644 index 00000000..3731fff8 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhShaderListData.h @@ -0,0 +1,46 @@ +#pragma once + +#include + +#include +#include +#include + +namespace Hedgehog::Mirage +{ + class CVertexShaderData; + class CPixelShaderData; + + class CVertexShaderPermutationData + { + public: + hh::map, boost::shared_ptr> m_VertexShaders; + be m_SubPermutations; + }; + + SWA_ASSERT_OFFSETOF(CVertexShaderPermutationData, m_VertexShaders, 0x0); + SWA_ASSERT_OFFSETOF(CVertexShaderPermutationData, m_SubPermutations, 0xC); + SWA_ASSERT_SIZEOF(CVertexShaderPermutationData, 0x10); + + class CPixelShaderPermutationData + { + public: + hh::map> m_VertexShaderPermutations; + hh::map, boost::shared_ptr> m_PixelShaders; + be m_SubPermutations; + }; + + SWA_ASSERT_OFFSETOF(CPixelShaderPermutationData, m_VertexShaderPermutations, 0x0); + SWA_ASSERT_OFFSETOF(CPixelShaderPermutationData, m_PixelShaders, 0xC); + SWA_ASSERT_OFFSETOF(CPixelShaderPermutationData, m_SubPermutations, 0x18); + SWA_ASSERT_SIZEOF(CPixelShaderPermutationData, 0x1C); + + class CShaderListData : public Database::CDatabaseData + { + public: + hh::map m_PixelShaderPermutations; + }; + + SWA_ASSERT_OFFSETOF(CShaderListData, m_PixelShaderPermutations, 0xC); + SWA_ASSERT_SIZEOF(CShaderListData, 0x18); +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhTerrainModelData.h b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhTerrainModelData.h new file mode 100644 index 00000000..5f0d6b33 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhTerrainModelData.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +namespace Hedgehog::Mirage +{ + class CSphereData; + class CNodeGroupModelData; + class CMeshData; + + class CTerrainModelData : public Database::CDatabaseData + { + public: + SWA_INSERT_PADDING(0x4); + hh::vector> m_NodeGroupModels; + hh::vector> m_OpaqueMeshes; + hh::vector> m_TransparentMeshes; + hh::vector> m_PunchThroughMeshes; + boost::shared_ptr m_spSphere; + }; + + SWA_ASSERT_OFFSETOF(CTerrainModelData, m_NodeGroupModels, 0x10); + SWA_ASSERT_OFFSETOF(CTerrainModelData, m_OpaqueMeshes, 0x20); + SWA_ASSERT_OFFSETOF(CTerrainModelData, m_TransparentMeshes, 0x30); + SWA_ASSERT_OFFSETOF(CTerrainModelData, m_PunchThroughMeshes, 0x40); + SWA_ASSERT_OFFSETOF(CTerrainModelData, m_spSphere, 0x50); + SWA_ASSERT_SIZEOF(CTerrainModelData, 0x58); +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhTexsetData.h b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhTexsetData.h new file mode 100644 index 00000000..627bf04d --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhTexsetData.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include +#include + +namespace Hedgehog::Mirage +{ + class CTextureData; + + class CTexsetData : public Database::CDatabaseData + { + public: + hh::vector> m_TextureList; + hh::vector m_TextureNameList; + bool m_ConstTexCoord; + }; + + SWA_ASSERT_OFFSETOF(CTexsetData, m_TextureList, 0xC); + SWA_ASSERT_OFFSETOF(CTexsetData, m_TextureNameList, 0x1C); + SWA_ASSERT_OFFSETOF(CTexsetData, m_ConstTexCoord, 0x2C); + SWA_ASSERT_SIZEOF(CTexsetData, 0x30); +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhTextureData.h b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhTextureData.h new file mode 100644 index 00000000..cf8abbee --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhTextureData.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +namespace Hedgehog::Mirage +{ + class CTextureData : public Database::CDatabaseData + { + public: + SWA_INSERT_PADDING(0x8); + uint8_t m_TexcoordIndex; + SWA_INSERT_PADDING(0x1B); + }; + + SWA_ASSERT_OFFSETOF(CTextureData, m_TexcoordIndex, 0x14); + SWA_ASSERT_SIZEOF(CTextureData, 0x30); +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhVertexShaderCodeData.h b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhVertexShaderCodeData.h new file mode 100644 index 00000000..9956d2e2 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhVertexShaderCodeData.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include + +namespace Hedgehog::Base +{ + class CCriticalSectionD3D9; +} + +namespace Hedgehog::Mirage +{ + class CRenderingInfrastructure; + + class CVertexShaderCodeData : public Database::CDatabaseData + { + public: + xpointer m_pD3DVertexShader; + xpointer m_spFunction; + boost::shared_ptr m_spCriticalSection; + xpointer m_pRenderingInfrastructure; + }; + + SWA_ASSERT_OFFSETOF(CVertexShaderCodeData, m_pD3DVertexShader, 0xC); + SWA_ASSERT_OFFSETOF(CVertexShaderCodeData, m_spFunction, 0x10); + SWA_ASSERT_OFFSETOF(CVertexShaderCodeData, m_spCriticalSection, 0x14); + SWA_ASSERT_OFFSETOF(CVertexShaderCodeData, m_pRenderingInfrastructure, 0x1C); + SWA_ASSERT_SIZEOF(CVertexShaderCodeData, 0x20); +} diff --git a/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhVertexShaderData.h b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhVertexShaderData.h new file mode 100644 index 00000000..f9509952 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/MirageCore/RenderData/hhVertexShaderData.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +namespace Hedgehog::Mirage +{ + class CVertexShaderCodeData; + class CVertexShaderParameterData; + + class CVertexShaderData : public Hedgehog::Database::CDatabaseData + { + public: + boost::shared_ptr m_spCode; + SWA_INSERT_PADDING(0x4); + hh::vector> m_ParameterList; + }; + + SWA_ASSERT_OFFSETOF(CVertexShaderData, m_spCode, 0xC); + SWA_ASSERT_OFFSETOF(CVertexShaderData, m_ParameterList, 0x18); + SWA_ASSERT_SIZEOF(CVertexShaderData, 0x28); +} diff --git a/UnleashedRecomp/api/Hedgehog/Sparkle/hhParticleMaterial.h b/UnleashedRecomp/api/Hedgehog/Sparkle/hhParticleMaterial.h new file mode 100644 index 00000000..75bb1b33 --- /dev/null +++ b/UnleashedRecomp/api/Hedgehog/Sparkle/hhParticleMaterial.h @@ -0,0 +1,41 @@ +#pragma once + +#include + +#include +#include + +namespace Hedgehog::Mirage +{ + class CShaderListData; +} + +namespace Hedgehog::Sparkle +{ + class CParticleMaterial : public Hedgehog::Database::CDatabaseData + { + public: + enum EBlendMode + { + eBlendMode_Zero, + eBlendMode_Typical, + eBlendMode_Add, + eBlendMode_Subtract + }; + + hh::vector m_spFieldC; + boost::shared_ptr m_spDefaultShaderListData; // BillboardParticle_d[v] + boost::shared_ptr m_spShaderListData; + bool m_Field2C; + be m_BlendMode; + be m_AddressMode; + Hedgehog::Base::CSharedString m_MaterialName; + Hedgehog::Base::CSharedString m_TextureName; + Hedgehog::Base::CSharedString m_DeflectionTextureName; + Hedgehog::Base::CSharedString m_ShaderName; + be m_Field48; + be m_Field4C; + }; + + SWA_ASSERT_SIZEOF(CParticleMaterial, 0x50); +} diff --git a/UnleashedRecomp/api/SWA.h b/UnleashedRecomp/api/SWA.h index bf18f4b2..f72f0e19 100644 --- a/UnleashedRecomp/api/SWA.h +++ b/UnleashedRecomp/api/SWA.h @@ -15,7 +15,10 @@ #include "CSD/Manager/csdmSceneObserver.h" #include "CSD/Manager/csdmSubjectBase.h" #include "CSD/Platform/csdTexList.h" +#include "Hedgehog/Base/Container/hhMap.h" +#include "Hedgehog/Base/Container/hhVector.h" #include "Hedgehog/Base/System/hhAllocator.h" +#include "Hedgehog/Base/System/hhSymbol.h" #include "Hedgehog/Base/Thread/hhHolder.h" #include "Hedgehog/Base/Thread/hhHolderBase.h" #include "Hedgehog/Base/Thread/hhSynchronizedObject.h" @@ -25,7 +28,21 @@ #include "Hedgehog/Base/hhObject.h" #include "Hedgehog/Database/System/hhDatabaseData.h" #include "Hedgehog/Math/Vector2.h" +#include "Hedgehog/MirageCore/Misc/hhVertexDeclarationPtr.h" +#include "Hedgehog/MirageCore/RenderData/hhMaterialData.h" +#include "Hedgehog/MirageCore/RenderData/hhMeshData.h" +#include "Hedgehog/MirageCore/RenderData/hhModelData.h" +#include "Hedgehog/MirageCore/RenderData/hhNodeGroupModelData.h" +#include "Hedgehog/MirageCore/RenderData/hhPixelShaderCodeData.h" +#include "Hedgehog/MirageCore/RenderData/hhPixelShaderData.h" +#include "Hedgehog/MirageCore/RenderData/hhShaderListData.h" +#include "Hedgehog/MirageCore/RenderData/hhTerrainModelData.h" +#include "Hedgehog/MirageCore/RenderData/hhTexsetData.h" +#include "Hedgehog/MirageCore/RenderData/hhTextureData.h" +#include "Hedgehog/MirageCore/RenderData/hhVertexShaderCodeData.h" +#include "Hedgehog/MirageCore/RenderData/hhVertexShaderData.h" #include "Hedgehog/MirageCore/Renderable/hhRenderable.h" +#include "Hedgehog/Sparkle/hhParticleMaterial.h" #include "Hedgehog/Universe/Engine/hhMessageActor.h" #include "Hedgehog/Universe/Engine/hhMessageProcess.h" #include "Hedgehog/Universe/Engine/hhUpdateInfo.h" diff --git a/UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h b/UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h index ecea043a..55043597 100644 --- a/UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h +++ b/UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h @@ -69,7 +69,12 @@ namespace boost uint32_t use_count() const { - return use_count_; + return std::byteswap(static_cast(use_count_.value)); + } + + bool unique() const + { + return use_count() == 1; } }; @@ -150,6 +155,16 @@ namespace boost return *this; } + shared_ptr& operator=(std::nullptr_t) + { + release(); + + px = NULL; + pn = NULL; + + return *this; + } + T* get() const { return px; } detail::sp_dereference operator*() const { assert(px); return *px; } @@ -158,6 +173,7 @@ namespace boost explicit operator bool() const { return px != nullptr; } size_t use_count() const { return pn ? pn->use_count() : 0; } + bool unique() const { return !pn || pn->unique(); } }; using anonymous_shared_ptr = shared_ptr; diff --git a/UnleashedRecomp/gpu/cache/pipeline_state_cache.h b/UnleashedRecomp/gpu/cache/pipeline_state_cache.h new file mode 100644 index 00000000..e26e1741 --- /dev/null +++ b/UnleashedRecomp/gpu/cache/pipeline_state_cache.h @@ -0,0 +1,65 @@ +{ reinterpret_cast(0x135289E4F64C6EEA),reinterpret_cast(0x6B812461EA74928D),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x8,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x135289E4F64C6EEA),reinterpret_cast(0x7C6A695E4296FA3B),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x135289E4F64C6EEA),reinterpret_cast(0xC20BFEE4B086F5EF),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x8,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x1D29E1386144A506),reinterpret_cast(0x22CDDA5C6346A97),reinterpret_cast(0x5A2395E29F93DA3C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_FAN,{ 32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 }, +{ reinterpret_cast(0x36DB3B40FA419EF6),reinterpret_cast(0x3BF885B6A8263F78),reinterpret_cast(0xFFFDDC62D86892F1),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_LIST,{ 32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 }, +{ reinterpret_cast(0x36DB3B40FA419EF6),reinterpret_cast(0x3BF885B6A8263F78),reinterpret_cast(0xFFFDDC62D86892F1),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 }, +{ reinterpret_cast(0x681C97662BFE9150),reinterpret_cast(0xDC635C4E7013864E),reinterpret_cast(0x6196BF64CB935CA5),false,true,false,RenderBlend::ONE,RenderBlend::ONE,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 }, +{ reinterpret_cast(0x681E682667303C76),reinterpret_cast(0x38771885AC644B5),reinterpret_cast(0xC64D046063DE2F63),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::ONE,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 }, +{ reinterpret_cast(0x681E682667303C76),reinterpret_cast(0x604349CBF72CCF8C),reinterpret_cast(0xC64D046063DE2F63),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::ONE,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x132D2F2079D74CB3),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x198E2B57B47DAF53),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16_FLOAT,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x3016DA5F348C87A7),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16_FLOAT,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x3016DA5F348C87A7),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x3016DA5F348C87A7),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x4294510C775F4EE8),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x48BE63A8F5F1C78A),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16_FLOAT,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x50700665A5F55DFE),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x605C1E349CC4CAAB),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x65325B9C7DA3DB04),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x67064E6EA39B439E),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x7D9F06B0E048B75D),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x891B8684FB17752B),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0x9FA5AACB5B14A226),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0xC47F2F91BA2A5D86),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x6DE86503F8AA38E2),reinterpret_cast(0xFB79F59782376846),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x720D6E5EDA78433B),reinterpret_cast(0x96EACBACDE1AAFAA),reinterpret_cast(0xA81F28FA43A9B511),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::ONE,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 }, +{ reinterpret_cast(0x7C34DB46DEEFB0C2),reinterpret_cast(0xDBD8B29544AC9277),reinterpret_cast(0xB22B7B7B968141C6),false,false,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x7CC3A0B01523741B),reinterpret_cast(0x315BB80DAE685834),reinterpret_cast(0xB22B7B7B968141C6),false,false,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x86FE3502D5EC24AA),reinterpret_cast(0x68FCC0B90EBC457B),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x86FE3502D5EC24AA),reinterpret_cast(0x94A71CC9B94E3101),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16_FLOAT,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x88F67387B88F932F),reinterpret_cast(0x49101E452DF2FE98),reinterpret_cast(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 }, +{ reinterpret_cast(0x8A459F1CE0E957D3),reinterpret_cast(0x5D7ACAE543747185),reinterpret_cast(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::ONE,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::D32_FLOAT,1,false,0x10 }, +{ reinterpret_cast(0x8E4BB23465BD909E),reinterpret_cast(0x0),reinterpret_cast(0xFFFDDC62D86892F1),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS_EQUAL,false,RenderBlendOperation::ADD,1,33554,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x0,RenderPrimitiveTopology::TRIANGLE_LIST,{ 32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::UNKNOWN,RenderFormat::D32_FLOAT,1,false,0x0 }, +{ reinterpret_cast(0x8E4BB23465BD909E),reinterpret_cast(0x0),reinterpret_cast(0xFFFDDC62D86892F1),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS_EQUAL,false,RenderBlendOperation::ADD,1,33554,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x0,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::UNKNOWN,RenderFormat::D32_FLOAT,1,false,0x0 }, +{ reinterpret_cast(0x965929BAA69F0AE),reinterpret_cast(0x66578F29004F8FD0),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x965929BAA69F0AE),reinterpret_cast(0x6B9732B4CD7E7740),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x965929BAA69F0AE),reinterpret_cast(0x6C50210CBDA8A23A),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ONE,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x965929BAA69F0AE),reinterpret_cast(0x6C50210CBDA8A23A),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x965929BAA69F0AE),reinterpret_cast(0x6C50210CBDA8A23A),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16_FLOAT,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x965929BAA69F0AE),reinterpret_cast(0x6C50210CBDA8A23A),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x965929BAA69F0AE),reinterpret_cast(0x6C50210CBDA8A23A),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x965929BAA69F0AE),reinterpret_cast(0x6C50210CBDA8A23A),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x965929BAA69F0AE),reinterpret_cast(0x92940FDD115733E1),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x965929BAA69F0AE),reinterpret_cast(0xA305C47ED9FB58CF),reinterpret_cast(0xD452411D3FB80A0D),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::ALWAYS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x0,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::UNKNOWN,RenderFormat::D32_FLOAT,1,false,0x0 }, +{ reinterpret_cast(0x965929BAA69F0AE),reinterpret_cast(0xD44C189D5067922E),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0x965929BAA69F0AE),reinterpret_cast(0xD736237D80908063),reinterpret_cast(0xD452411D3FB80A0D),false,false,false,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::LESS,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R8G8B8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0xA3CD49F172D99214),reinterpret_cast(0xD5EA32DB758EF0B8),reinterpret_cast(0x7F12180DC3A24B53),true,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 32,24,4,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 }, +{ reinterpret_cast(0xA3FD368C62079765),reinterpret_cast(0xE8E3FF65F2356201),reinterpret_cast(0xB22B7B7B968141C6),false,false,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0xA3FD368C62079765),reinterpret_cast(0xE8E3FF65F2356201),reinterpret_cast(0xB22B7B7B968141C6),false,false,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::LESS,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x0 }, +{ reinterpret_cast(0xA4CF0215A03D9571),reinterpret_cast(0xA3A659F1590CC180),reinterpret_cast(0x5A2395E29F93DA3C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_FAN,{ 32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 }, +{ reinterpret_cast(0xB1086A4947A797DE),reinterpret_cast(0x996F5A774A646D92),reinterpret_cast(0x6FAE71C7134074A4),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x4 }, +{ reinterpret_cast(0xB1086A4947A797DE),reinterpret_cast(0x996F5A774A646D92),reinterpret_cast(0x6FAE71C7134074A4),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x4 }, +{ reinterpret_cast(0xB1086A4947A797DE),reinterpret_cast(0x996F5A774A646D92),reinterpret_cast(0x6FAE71C7134074A4),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::ONE,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x4 }, +{ reinterpret_cast(0xB1EA909C660122A7),reinterpret_cast(0xC96708D6F26CC6D9),reinterpret_cast(0x84BACD816D86543C),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 }, +{ reinterpret_cast(0xB4CAFC034A37C8A8),reinterpret_cast(0x31173204A896098A),reinterpret_cast(0x5A22D93C543DF925),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x4 }, +{ reinterpret_cast(0xB4CAFC034A37C8A8),reinterpret_cast(0x31173204A896098A),reinterpret_cast(0x5A22D93C543DF925),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x4 }, +{ reinterpret_cast(0xB4CAFC034A37C8A8),reinterpret_cast(0x31173204A896098A),reinterpret_cast(0x5A22D93C543DF925),false,true,false,RenderBlend::SRC_ALPHA,RenderBlend::ONE,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::B8G8R8A8_UNORM,RenderFormat::UNKNOWN,1,false,0x4 }, +{ reinterpret_cast(0xBBD01C46D72EDC37),reinterpret_cast(0x4E1399E5E0E40511),reinterpret_cast(0xE6B3B3D286909AB9),true,true,false,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,true,RenderBlendOperation::ADD,0,0,RenderBlend::SRC_ALPHA,RenderBlend::INV_SRC_ALPHA,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 32,24,4,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x10 }, +{ reinterpret_cast(0xBDA992649419F2DD),reinterpret_cast(0x5A4CFA9D29441E0),reinterpret_cast(0x25B8F9D92644DAE0),true,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,24,4,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x11 }, +{ reinterpret_cast(0xBDA992649419F2DD),reinterpret_cast(0x5A4CFA9D29441E0),reinterpret_cast(0x25B8F9D92644DAE0),true,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,24,4,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 }, +{ reinterpret_cast(0xCF28F33974EC44F6),reinterpret_cast(0xD5EA32DB758EF0B8),reinterpret_cast(0x7F12180DC3A24B53),true,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 32,24,4,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 }, +{ reinterpret_cast(0xD6EA5D49CB1F965C),reinterpret_cast(0x2FE1A3913EF3EE8A),reinterpret_cast(0x25B8F9D92644DAE0),true,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,24,4,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 }, +{ reinterpret_cast(0xD6EA5D49CB1F965C),reinterpret_cast(0x53EF4B071D1B59D3),reinterpret_cast(0x25B8F9D92644DAE0),true,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 44,24,4,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x15 }, +{ reinterpret_cast(0xD738D79626374EBE),reinterpret_cast(0xAAE40F54746EB116),reinterpret_cast(0xB7BBCC93738C9DE4),false,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::BACK,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0x0,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::UNKNOWN,RenderFormat::D32_FLOAT,1,false,0x11 }, +{ reinterpret_cast(0xFF5A2C4C81AA6FDF),reinterpret_cast(0xE105CB09EA634E60),reinterpret_cast(0x7F12180DC3A24B53),true,true,true,RenderBlend::ONE,RenderBlend::ZERO,RenderCullMode::NONE,RenderComparisonFunction::GREATER_EQUAL,false,RenderBlendOperation::ADD,0,0,RenderBlend::ONE,RenderBlend::ZERO,RenderBlendOperation::ADD,0xF,RenderPrimitiveTopology::TRIANGLE_STRIP,{ 32,24,4,0,0,0,0,0,0,0,0,0,0,0,0,0 },RenderFormat::R16G16B16A16_FLOAT,RenderFormat::D32_FLOAT,1,false,0x14 }, diff --git a/UnleashedRecomp/gpu/cache/vertex_declaration_cache.h b/UnleashedRecomp/gpu/cache/vertex_declaration_cache.h new file mode 100644 index 00000000..dbf9eabc --- /dev/null +++ b/UnleashedRecomp/gpu/cache/vertex_declaration_cache.h @@ -0,0 +1,14 @@ +g_vertexElements_25B8F9D92644DAE0, +g_vertexElements_5A22D93C543DF925, +g_vertexElements_5A2395E29F93DA3C, +g_vertexElements_6196BF64CB935CA5, +g_vertexElements_6FAE71C7134074A4, +g_vertexElements_7F12180DC3A24B53, +g_vertexElements_84BACD816D86543C, +g_vertexElements_A81F28FA43A9B511, +g_vertexElements_B22B7B7B968141C6, +g_vertexElements_B7BBCC93738C9DE4, +g_vertexElements_C64D046063DE2F63, +g_vertexElements_D452411D3FB80A0D, +g_vertexElements_E6B3B3D286909AB9, +g_vertexElements_FFFDDC62D86892F1, \ No newline at end of file diff --git a/UnleashedRecomp/gpu/cache/vertex_element_cache.h b/UnleashedRecomp/gpu/cache/vertex_element_cache.h new file mode 100644 index 00000000..0d152f08 --- /dev/null +++ b/UnleashedRecomp/gpu/cache/vertex_element_cache.h @@ -0,0 +1,14 @@ +static uint8_t g_vertexElements_25B8F9D92644DAE0[] = {0x0,0x0,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0x0,0x2A,0x21,0x90,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x2A,0x21,0x90,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x14,0x0,0x2A,0x21,0x90,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x18,0x0,0x2C,0x23,0x5F,0x0,0x5,0x0,0x0,0x0,0x0,0x0,0x1C,0x0,0x2C,0x23,0x5F,0x0,0x5,0x1,0x0,0x0,0x0,0x0,0x20,0x0,0x1A,0x20,0x86,0x0,0xA,0x0,0x0,0x0,0x0,0x0,0x24,0x0,0x1A,0x22,0x86,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x28,0x0,0x1A,0x20,0x86,0x0,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x5,0x4,0x0,0x0,0x1,0x0,0xC,0x0,0x2C,0x21,0x59,0x0,0x5,0x5,0x0,0x0,0x1,0x0,0x10,0x0,0x2C,0x21,0x59,0x0,0x5,0x6,0x0,0x0,0x1,0x0,0x14,0x0,0x18,0x28,0x86,0x0,0xA,0x1,0x0,0x0,0x2,0x0,0x0,0x0,0x2C,0x82,0xA1,0x0,0x0,0x1,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_5A22D93C543DF925[] = {0x0,0x0,0x0,0x0,0x0,0x2C,0x23,0xA5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x18,0x28,0x86,0x0,0xA,0x0,0x0,0x0,0x0,0x0,0xC,0x0,0x2C,0x23,0xA5,0x0,0x5,0x0,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_5A2395E29F93DA3C[] = {0x0,0x0,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0x0,0x2A,0x23,0xB9,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x18,0x0,0x2C,0x23,0xA5,0x0,0x5,0x0,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_6196BF64CB935CA5[] = {0x0,0x0,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0x0,0x2C,0x23,0xA5,0x0,0x5,0x0,0x0,0x0,0x0,0x0,0x14,0x0,0x18,0x28,0x86,0x0,0xA,0x0,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_6FAE71C7134074A4[] = {0x0,0x0,0x0,0x0,0x0,0x2C,0x23,0xA5,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x8,0x0,0x18,0x28,0x86,0x0,0xA,0x0,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_7F12180DC3A24B53[] = {0x0,0x0,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0x0,0x2A,0x23,0xB9,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x18,0x0,0x2C,0x23,0xA5,0x0,0x5,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x5,0x1,0x0,0x0,0x1,0x0,0xC,0x0,0x1A,0x22,0x86,0x0,0x5,0x2,0x0,0x0,0x1,0x0,0x10,0x0,0x2C,0x21,0x59,0x0,0x5,0x3,0x0,0x0,0x1,0x0,0x14,0x0,0x18,0x28,0x86,0x0,0xA,0x1,0x0,0x0,0x2,0x0,0x0,0x0,0x2C,0x82,0xA1,0x0,0x0,0x1,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_84BACD816D86543C[] = {0x0,0x0,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0x0,0x2A,0x23,0xB9,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x18,0x0,0x2A,0x23,0xB9,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x24,0x0,0x2A,0x23,0xB9,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x30,0x0,0x2C,0x23,0xA5,0x0,0x5,0x0,0x0,0x0,0x0,0x0,0x38,0x0,0x2C,0x23,0xA5,0x0,0x5,0x1,0x0,0x0,0x0,0x0,0x40,0x0,0x2C,0x23,0xA5,0x0,0x5,0x2,0x0,0x0,0x0,0x0,0x48,0x0,0x2C,0x23,0xA5,0x0,0x5,0x3,0x0,0x0,0x0,0x0,0x50,0x0,0x1A,0x23,0xA6,0x0,0xA,0x0,0x0,0x0,0x0,0x0,0x60,0x0,0x1A,0x23,0x86,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x64,0x0,0x1A,0x20,0x86,0x0,0x1,0x0,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_A81F28FA43A9B511[] = {0x0,0x0,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0x0,0x2A,0x23,0xB9,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x18,0x0,0x2C,0x23,0xA5,0x0,0x5,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x18,0x28,0x86,0x0,0xA,0x0,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_B22B7B7B968141C6[] = {0x0,0x0,0x0,0x0,0x0,0x1A,0x23,0xA6,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x18,0x28,0x86,0x0,0xA,0x0,0x0,0x0,0x0,0x0,0x14,0x0,0x2C,0x23,0xA5,0x0,0x5,0x0,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_B7BBCC93738C9DE4[] = {0x0,0x0,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0x0,0x1A,0x22,0x86,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x1A,0x20,0x86,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x14,0x0,0x2A,0x21,0x90,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x18,0x0,0x2A,0x21,0x90,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x1C,0x0,0x2A,0x21,0x90,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x2C,0x23,0x5F,0x0,0x5,0x0,0x0,0x0,0x0,0x0,0x24,0x0,0x1A,0x20,0x86,0x0,0xA,0x0,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_C64D046063DE2F63[] = {0x0,0x0,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0x0,0x1A,0x22,0x86,0x0,0x2,0x0,0x0,0x0,0x0,0x0,0x10,0x0,0x1A,0x20,0x86,0x0,0x1,0x0,0x0,0x0,0x0,0x0,0x14,0x0,0x2A,0x21,0x90,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x18,0x0,0x2A,0x21,0x90,0x0,0x6,0x0,0x0,0x0,0x0,0x0,0x1C,0x0,0x2A,0x21,0x90,0x0,0x7,0x0,0x0,0x0,0x0,0x0,0x20,0x0,0x2C,0x23,0x5F,0x0,0x5,0x0,0x0,0x0,0x0,0x0,0x24,0x0,0x2C,0x23,0x5F,0x0,0x5,0x1,0x0,0x0,0x0,0x0,0x28,0x0,0x1A,0x20,0x86,0x0,0xA,0x0,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_D452411D3FB80A0D[] = {0x0,0x0,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0x0,0x2C,0x23,0xA5,0x0,0x5,0x0,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_E6B3B3D286909AB9[] = {0x0,0x0,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0x0,0x2A,0x23,0xB9,0x0,0x3,0x0,0x0,0x0,0x0,0x0,0x18,0x0,0x2C,0x23,0xA5,0x0,0x5,0x0,0x0,0x0,0x1,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x5,0x1,0x0,0x0,0x1,0x0,0xC,0x0,0x1A,0x22,0x86,0x0,0x5,0x2,0x0,0x0,0x1,0x0,0x10,0x0,0x2C,0x83,0xA4,0x0,0x5,0x3,0x0,0x0,0x1,0x0,0x14,0x0,0x18,0x28,0x86,0x0,0xA,0x1,0x0,0x0,0x2,0x0,0x0,0x0,0x2C,0x82,0xA1,0x0,0x0,0x1,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0x0,}; +static uint8_t g_vertexElements_FFFDDC62D86892F1[] = {0x0,0x0,0x0,0x0,0x0,0x2A,0x23,0xB9,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xC,0x0,0x2C,0x23,0xA5,0x0,0x5,0x0,0x0,0x0,0x0,0x0,0x14,0x0,0x2A,0x23,0xB9,0x0,0x3,0x0,0x0,0x0,0xFF,0x0,0x0,0xFF,0xFF,0xFF,0xFF,0x0,0x0,0x0,0xC9,}; \ No newline at end of file diff --git a/UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp b/UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp index 310e5358..eccf3cc3 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp +++ b/UnleashedRecomp/gpu/rhi/rt64_d3d12.cpp @@ -2672,6 +2672,10 @@ namespace RT64 { } } + void D3D12ComputePipeline::setName(const std::string& name) const { + setObjectName(d3d, name); + } + RenderPipelineProgram D3D12ComputePipeline::getProgram(const std::string &name) const { assert(false && "Compute pipelines can't retrieve shader programs."); return RenderPipelineProgram(); @@ -2791,6 +2795,10 @@ namespace RT64 { } } + void D3D12GraphicsPipeline::setName(const std::string& name) const { + setObjectName(d3d, name); + } + RenderPipelineProgram D3D12GraphicsPipeline::getProgram(const std::string &name) const { assert(false && "Graphics pipelines can't retrieve shader programs."); return RenderPipelineProgram(); @@ -3011,6 +3019,10 @@ namespace RT64 { } } + void D3D12RaytracingPipeline::setName(const std::string& name) const { + setObjectName(stateObject, name); + } + RenderPipelineProgram D3D12RaytracingPipeline::getProgram(const std::string &name) const { auto it = nameProgramMap.find(name); assert((it != nameProgramMap.end()) && "Program must exist in the PSO."); diff --git a/UnleashedRecomp/gpu/rhi/rt64_d3d12.h b/UnleashedRecomp/gpu/rhi/rt64_d3d12.h index ff62d1b8..96f98bd4 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_d3d12.h +++ b/UnleashedRecomp/gpu/rhi/rt64_d3d12.h @@ -355,6 +355,7 @@ namespace RT64 { D3D12ComputePipeline(D3D12Device *device, const RenderComputePipelineDesc &desc); ~D3D12ComputePipeline() override; + virtual void setName(const std::string& name) const override; virtual RenderPipelineProgram getProgram(const std::string &name) const override; }; @@ -365,6 +366,7 @@ namespace RT64 { D3D12GraphicsPipeline(D3D12Device *device, const RenderGraphicsPipelineDesc &desc); ~D3D12GraphicsPipeline() override; + virtual void setName(const std::string& name) const override; virtual RenderPipelineProgram getProgram(const std::string &name) const override; }; @@ -377,6 +379,7 @@ namespace RT64 { D3D12RaytracingPipeline(D3D12Device *device, const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline); ~D3D12RaytracingPipeline() override; + virtual void setName(const std::string& name) const override; virtual RenderPipelineProgram getProgram(const std::string &name) const override; }; diff --git a/UnleashedRecomp/gpu/rhi/rt64_render_interface.h b/UnleashedRecomp/gpu/rhi/rt64_render_interface.h index 438590b1..a01b70e1 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_render_interface.h +++ b/UnleashedRecomp/gpu/rhi/rt64_render_interface.h @@ -53,6 +53,7 @@ namespace RT64 { struct RenderPipeline { virtual ~RenderPipeline() { } + virtual void setName(const std::string& name) const = 0; virtual RenderPipelineProgram getProgram(const std::string &name) const = 0; }; diff --git a/UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp b/UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp index 19da76d4..d5e9db1e 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp +++ b/UnleashedRecomp/gpu/rhi/rt64_vulkan.cpp @@ -1316,6 +1316,10 @@ namespace RT64 { } } + void VulkanComputePipeline::setName(const std::string& name) const { + setObjectName(device->vk, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, uint64_t(vk), name); + } + RenderPipelineProgram VulkanComputePipeline::getProgram(const std::string &name) const { assert(false && "Compute pipelines can't retrieve shader programs."); return RenderPipelineProgram(); @@ -1552,6 +1556,10 @@ namespace RT64 { } } + void VulkanGraphicsPipeline::setName(const std::string& name) const { + setObjectName(device->vk, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, uint64_t(vk), name); + } + RenderPipelineProgram VulkanGraphicsPipeline::getProgram(const std::string &name) const { assert(false && "Graphics pipelines can't retrieve shader programs."); return RenderPipelineProgram(); @@ -1752,6 +1760,10 @@ namespace RT64 { } } + void VulkanRaytracingPipeline::setName(const std::string& name) const { + setObjectName(device->vk, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT, uint64_t(vk), name); + } + RenderPipelineProgram VulkanRaytracingPipeline::getProgram(const std::string &name) const { auto it = nameProgramMap.find(name); assert((it != nameProgramMap.end()) && "Program must exist in the PSO."); diff --git a/UnleashedRecomp/gpu/rhi/rt64_vulkan.h b/UnleashedRecomp/gpu/rhi/rt64_vulkan.h index ef2f1ff2..20f6fe0b 100644 --- a/UnleashedRecomp/gpu/rhi/rt64_vulkan.h +++ b/UnleashedRecomp/gpu/rhi/rt64_vulkan.h @@ -158,6 +158,7 @@ namespace RT64 { VulkanComputePipeline(VulkanDevice *device, const RenderComputePipelineDesc &desc); ~VulkanComputePipeline() override; + void setName(const std::string& name) const override; RenderPipelineProgram getProgram(const std::string &name) const override; }; @@ -167,6 +168,7 @@ namespace RT64 { VulkanGraphicsPipeline(VulkanDevice *device, const RenderGraphicsPipelineDesc &desc); ~VulkanGraphicsPipeline() override; + void setName(const std::string& name) const override; RenderPipelineProgram getProgram(const std::string &name) const override; static VkRenderPass createRenderPass(VulkanDevice *device, const VkFormat *renderTargetFormat, uint32_t renderTargetCount, VkFormat depthTargetFormat, VkSampleCountFlagBits sampleCount); }; @@ -179,6 +181,7 @@ namespace RT64 { VulkanRaytracingPipeline(VulkanDevice *device, const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline); ~VulkanRaytracingPipeline() override; + void setName(const std::string& name) const override; RenderPipelineProgram getProgram(const std::string &name) const override; }; diff --git a/UnleashedRecomp/gpu/shader/gamma_correction_ps.hlsl b/UnleashedRecomp/gpu/shader/gamma_correction_ps.hlsl index dfed91b0..b1e2f993 100644 --- a/UnleashedRecomp/gpu/shader/gamma_correction_ps.hlsl +++ b/UnleashedRecomp/gpu/shader/gamma_correction_ps.hlsl @@ -1,4 +1,4 @@ -#include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.hlsli" +#include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.h" #ifdef __spirv__ diff --git a/UnleashedRecomp/gpu/shader/movie_common.hlsli b/UnleashedRecomp/gpu/shader/movie_common.hlsli index d890e48e..02e92e9c 100644 --- a/UnleashedRecomp/gpu/shader/movie_common.hlsli +++ b/UnleashedRecomp/gpu/shader/movie_common.hlsli @@ -1,6 +1,6 @@ #pragma once -#include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.hlsli" +#include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.h" #ifdef __spirv__ diff --git a/UnleashedRecomp/gpu/shader/resolve_msaa_depth.hlsli b/UnleashedRecomp/gpu/shader/resolve_msaa_depth.hlsli index bc04695a..d413717b 100644 --- a/UnleashedRecomp/gpu/shader/resolve_msaa_depth.hlsli +++ b/UnleashedRecomp/gpu/shader/resolve_msaa_depth.hlsli @@ -14,7 +14,7 @@ float main(in float4 position : SV_Position) : SV_Depth float result = g_Texture2DMSDescriptorHeap[g_PushConstants.ResourceDescriptorIndex].Load(int2(position.xy), 0); [unroll] for (int i = 1; i < SAMPLE_COUNT; i++) - result = max(result, g_Texture2DMSDescriptorHeap[g_PushConstants.ResourceDescriptorIndex].Load(int2(position.xy), i)); + result = min(result, g_Texture2DMSDescriptorHeap[g_PushConstants.ResourceDescriptorIndex].Load(int2(position.xy), i)); return result; } diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index 109468e0..36c5ddeb 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -4,15 +4,19 @@ #include #include #include +#include #include #include #include #include "imgui_snapshot.h" #include "video.h" -#include +#include #include +#include + +#include "../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.h" #include "shader/copy_vs.hlsl.dxil.h" #include "shader/copy_vs.hlsl.spirv.h" #include "shader/gamma_correction_ps.hlsl.dxil.h" @@ -32,6 +36,10 @@ #include "shader/resolve_msaa_depth_8x.hlsl.dxil.h" #include "shader/resolve_msaa_depth_8x.hlsl.spirv.h" +#if defined(ASYNC_PSO_DEBUG) || defined(PSO_CACHING) +#include +#endif + extern "C" { __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; @@ -44,6 +52,7 @@ namespace RT64 extern std::unique_ptr CreateVulkanInterface(); } +#pragma pack(push, 1) struct PipelineState { GuestShader* vertexShader = nullptr; @@ -70,14 +79,9 @@ struct PipelineState RenderFormat depthStencilFormat{}; RenderSampleCounts sampleCount = RenderSampleCount::COUNT_1; bool enableAlphaToCoverage = false; + uint32_t specConstants = 0; }; - -enum class AlphaTestMode : uint32_t -{ - Disabled, - AlphaThreshold, - AlphaToCoverage -}; +#pragma pack(pop) struct SharedConstants { @@ -85,12 +89,9 @@ struct SharedConstants uint32_t texture3DIndices[16]{}; uint32_t textureCubeIndices[16]{}; uint32_t samplerIndices[16]{}; - AlphaTestMode alphaTestMode{}; - float alphaThreshold{}; uint32_t booleans{}; uint32_t swappedTexcoords{}; - uint32_t inputLayoutFlags{}; - uint32_t enableGIBicubicFiltering{}; + float alphaThreshold{}; }; static GuestSurface* g_renderTarget; @@ -98,7 +99,6 @@ static GuestSurface* g_depthStencil; static RenderFramebuffer* g_framebuffer; static RenderViewport g_viewport(0.0f, 0.0f, 1280.0f, 720.0f); static bool g_halfPixel = true; -static uint32_t g_zFunc; static PipelineState g_pipelineState; static SharedConstants g_sharedConstants; static RenderSamplerDesc g_samplerDescs[16]; @@ -239,6 +239,37 @@ static TextureDescriptorAllocator g_textureDescriptorAllocator; static std::unique_ptr g_pipelineLayout; static xxHashMap> g_pipelines; +#ifdef ASYNC_PSO_DEBUG +static std::atomic g_pipelinesCreatedInRenderThread; +static std::atomic g_pipelinesCreatedAsynchronously; +static std::atomic g_pipelinesDropped; +static std::atomic g_pipelinesCurrentlyCompiling; +static std::string g_pipelineDebugText; +static Mutex g_debugMutex; +#endif + +#ifdef PSO_CACHING +static std::vector g_pipelineStatesToCache; +static Mutex g_pipelineCacheMutex; +#endif + +static std::atomic g_compilingDataCount; +static std::atomic g_pendingDataCount; + +static const PipelineState g_pipelineStateCache[] = +{ +#include "cache/pipeline_state_cache.h" +}; + +static bool g_pendingPipelineStateCache = true; + +#include "cache/vertex_element_cache.h" + +static uint8_t* const g_vertexDeclarationCache[] = +{ +#include "cache/vertex_declaration_cache.h" +}; + static xxHashMap>> g_samplerStates; static Mutex g_vertexDeclarationMutex; @@ -472,9 +503,11 @@ static void DestructTempResources() case ResourceType::VertexShader: case ResourceType::PixelShader: + { reinterpret_cast(resource)->~GuestShader(); break; } + } g_userHeap.Free(resource); } @@ -545,6 +578,7 @@ enum class RenderCommandType SetBooleans, SetVertexShaderConstants, SetPixelShaderConstants, + AddPipeline, DrawPrimitive, DrawIndexedPrimitive, DrawPrimitiveUP, @@ -652,6 +686,12 @@ struct RenderCommand UploadAllocation allocation; } setPixelShaderConstants; + struct + { + XXH64_hash_t hash; + RenderPipeline* pipeline; + } addPipeline; + struct { uint32_t primitiveType; @@ -723,18 +763,23 @@ static void SetRenderStateUnimplemented(GuestDevice* device, uint32_t value) static void SetAlphaTestMode(bool enable) { - AlphaTestMode alphaTestMode = AlphaTestMode::Disabled; + uint32_t specConstants = 0; + bool enableAlphaToCoverage = false; if (enable) { - if (Config::AlphaToCoverage && g_renderTarget != nullptr && g_renderTarget->sampleCount != RenderSampleCount::COUNT_1) - alphaTestMode = AlphaTestMode::AlphaToCoverage; + enableAlphaToCoverage = Config::AlphaToCoverage && g_renderTarget != nullptr && g_renderTarget->sampleCount != RenderSampleCount::COUNT_1; + + if (enableAlphaToCoverage) + specConstants = SPEC_CONSTANT_ALPHA_TO_COVERAGE; else - alphaTestMode = AlphaTestMode::AlphaThreshold; + specConstants = SPEC_CONSTANT_ALPHA_TEST; } - SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.alphaTestMode, alphaTestMode); - SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.enableAlphaToCoverage, alphaTestMode == AlphaTestMode::AlphaToCoverage); + specConstants |= (g_pipelineState.specConstants & ~(SPEC_CONSTANT_ALPHA_TEST | SPEC_CONSTANT_ALPHA_TO_COVERAGE)); + + SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.enableAlphaToCoverage, enableAlphaToCoverage); + SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.specConstants, specConstants); } static RenderBlend ConvertBlendMode(uint32_t blendMode) @@ -767,36 +812,6 @@ static RenderBlend ConvertBlendMode(uint32_t blendMode) } } -// The game renders the main scene with reverse Z where the viewport's minDepth and maxDepth -// values are swapped. We negate this to improve compatibility with old hardware. -static RenderComparisonFunction ConvertComparisonFunc(uint32_t cmpFunc, bool reverseZ) -{ - switch (cmpFunc) - { - case D3DCMP_LESS: - return reverseZ ? RenderComparisonFunction::GREATER : RenderComparisonFunction::LESS; - case D3DCMP_LESSEQUAL: - return reverseZ ? RenderComparisonFunction::GREATER_EQUAL : RenderComparisonFunction::LESS_EQUAL; - case D3DCMP_GREATER: - return reverseZ ? RenderComparisonFunction::LESS : RenderComparisonFunction::GREATER; - case D3DCMP_GREATEREQUAL: - return reverseZ ? RenderComparisonFunction::LESS_EQUAL : RenderComparisonFunction::GREATER_EQUAL; - - case D3DCMP_NEVER: - return RenderComparisonFunction::NEVER; - case D3DCMP_EQUAL: - return RenderComparisonFunction::EQUAL; - case D3DCMP_NOTEQUAL: - return RenderComparisonFunction::NOT_EQUAL; - case D3DCMP_ALWAYS: - return RenderComparisonFunction::ALWAYS; - - default: - assert(false && "Unknown comparison function"); - return RenderComparisonFunction::NEVER; - } -} - static RenderBlendOperation ConvertBlendOp(uint32_t blendOp) { switch (blendOp) @@ -875,8 +890,41 @@ static void ProcSetRenderState(const RenderCommand& cmd) } case D3DRS_ZFUNC: { - g_zFunc = value; - SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.zFunc, ConvertComparisonFunc(value, g_viewport.minDepth >= g_viewport.maxDepth)); + RenderComparisonFunction comparisonFunc; + + switch (value) + { + case D3DCMP_NEVER: + comparisonFunc = RenderComparisonFunction::NEVER; + break; + case D3DCMP_LESS: + comparisonFunc = RenderComparisonFunction::LESS; + break; + case D3DCMP_EQUAL: + comparisonFunc = RenderComparisonFunction::EQUAL; + break; + case D3DCMP_LESSEQUAL: + comparisonFunc = RenderComparisonFunction::LESS_EQUAL; + break; + case D3DCMP_GREATER: + comparisonFunc = RenderComparisonFunction::GREATER; + break; + case D3DCMP_NOTEQUAL: + comparisonFunc = RenderComparisonFunction::NOT_EQUAL; + break; + case D3DCMP_GREATEREQUAL: + comparisonFunc = RenderComparisonFunction::GREATER_EQUAL; + break; + case D3DCMP_ALWAYS: + comparisonFunc = RenderComparisonFunction::ALWAYS; + break; + default: + assert(false && "Unknown comparison function"); + comparisonFunc = RenderComparisonFunction::NEVER; + break; + } + + SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.zFunc, comparisonFunc); break; } case D3DRS_ALPHAREF: @@ -1373,7 +1421,10 @@ static void BeginCommandList() g_sharedConstants.textureCubeIndices[i] = TEXTURE_DESCRIPTOR_NULL_TEXTURE_CUBE; } - g_sharedConstants.enableGIBicubicFiltering = (Config::GITextureFiltering == EGITextureFiltering::Bicubic); + if (Config::GITextureFiltering == EGITextureFiltering::Bicubic) + g_pipelineState.specConstants |= SPEC_CONSTANT_BICUBIC_GI_FILTER; + else + g_pipelineState.specConstants &= ~SPEC_CONSTANT_BICUBIC_GI_FILTER; auto& commandList = g_commandLists[g_frame]; @@ -1616,7 +1667,23 @@ static void DrawImGui() { ImGui_ImplSDL2_NewFrame(); ImGui::NewFrame(); - // ImGui logic here + +#ifdef ASYNC_PSO_DEBUG + if (ImGui::Begin("Async PSO Stats")) + { + ImGui::Text("Pipelines Created In Render Thread: %d", g_pipelinesCreatedInRenderThread.load()); + ImGui::Text("Pipelines Created Asynchronously: %d", g_pipelinesCreatedAsynchronously.load()); + ImGui::Text("Pipelines Dropped: %d", g_pipelinesDropped.load()); + ImGui::Text("Pipelines Currently Compiling: %d", g_pipelinesCurrentlyCompiling.load()); + ImGui::Text("Compiling Data Count: %d", g_compilingDataCount.load()); + ImGui::Text("Pending Data Count: %d", g_pendingDataCount.load()); + + std::lock_guard lock(g_debugMutex); + ImGui::TextUnformatted(g_pipelineDebugText.c_str()); + } + ImGui::End(); +#endif + ImGui::Render(); auto drawData = ImGui::GetDrawData(); @@ -1680,6 +1747,8 @@ static void ProcDrawImGui(const RenderCommand& cmd) } } +static bool g_precompiledPipelineStateCache = false; + static void Present() { DrawImGui(); @@ -1690,6 +1759,18 @@ static void Present() RenderCommand cmd; cmd.type = RenderCommandType::Present; g_renderQueue.enqueue(cmd); + + // All the shaders are available at this point. We can precompile embedded PSOs then. + if (!g_precompiledPipelineStateCache) + { + // This is all the model consumer thread needs to see. + ++g_compilingDataCount; + + if ((++g_pendingDataCount) == 1) + g_pendingDataCount.notify_all(); + + g_precompiledPipelineStateCache = true; + } } static void SetRootDescriptor(const UploadAllocation& allocation, size_t index) @@ -1998,11 +2079,8 @@ static void FlushViewport() viewport.height *= height / 720.0f; } - if (viewport.minDepth >= viewport.maxDepth) - { - viewport.minDepth = 1.0f - viewport.minDepth; - viewport.maxDepth = 1.0f - viewport.maxDepth; - } + if (viewport.minDepth > viewport.maxDepth) + std::swap(viewport.minDepth, viewport.maxDepth); commandList->setViewports(viewport); @@ -2190,7 +2268,7 @@ static void ProcSetRenderTarget(const RenderCommand& cmd) SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.sampleCount, args.renderTarget != nullptr ? args.renderTarget->sampleCount : RenderSampleCount::COUNT_1); // When alpha to coverage is enabled, update the alpha test mode as it's dependent on sample count. - SetAlphaTestMode(g_sharedConstants.alphaTestMode != AlphaTestMode::Disabled); + SetAlphaTestMode((g_pipelineState.specConstants & (SPEC_CONSTANT_ALPHA_TEST | SPEC_CONSTANT_ALPHA_TO_COVERAGE)) != 0); } static void SetDepthStencilSurface(GuestDevice* device, GuestSurface* depthStencil) @@ -2314,8 +2392,7 @@ static void ProcClear(const RenderCommand& cmd) if (!canClearInOnePass) SetFramebuffer(nullptr, g_depthStencil, true); - // The condition here is done by the game to determine reverse Z. - commandList->clearDepth(true, g_depthStencil->guestFormat == D3DFMT_D24FS8 ? (1.0f - args.z) : args.z); + commandList->clearDepth(true, args.z); } } @@ -2349,11 +2426,16 @@ static void ProcSetViewport(const RenderCommand& cmd) SetDirtyValue(g_dirtyStates.viewport, g_viewport.height, args.height); SetDirtyValue(g_dirtyStates.viewport, g_viewport.minDepth, args.minDepth); SetDirtyValue(g_dirtyStates.viewport, g_viewport.maxDepth, args.maxDepth); + + uint32_t specConstants = g_pipelineState.specConstants; + if (args.minDepth > args.maxDepth) + specConstants |= SPEC_CONSTANT_REVERSE_Z; + else + specConstants &= ~SPEC_CONSTANT_REVERSE_Z; + + SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.specConstants, specConstants); g_dirtyStates.scissorRect |= g_dirtyStates.viewport; - - // Update Z function as it's dependent on reverse Z. - SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.zFunc, ConvertComparisonFunc(g_zFunc, args.minDepth >= args.maxDepth)); } static void SetTexture(GuestDevice* device, uint32_t index, GuestTexture* texture) @@ -2404,9 +2486,163 @@ static void ProcSetScissorRect(const RenderCommand& cmd) SetDirtyValue(g_dirtyStates.scissorRect, g_scissorRect.right, args.right); } -static RenderPipeline* CreateGraphicsPipeline(PipelineState pipelineState) +static Mutex g_compiledSpecConstantLibraryBlobMutex; +static ankerl::unordered_dense::map> g_compiledSpecConstantLibraryBlobs; + +static RenderShader* GetOrLinkShader(GuestShader* guestShader, uint32_t specConstants) +{ + if (g_vulkan || + guestShader->shaderCacheEntry == nullptr || + guestShader->shaderCacheEntry->specConstantsMask == 0) + { + std::lock_guard lock(guestShader->mutex); + + if (guestShader->shader == nullptr) + { + assert(guestShader->shaderCacheEntry != nullptr); + + if (g_vulkan) + { + auto compressedSpirvData = g_shaderCache.get() + guestShader->shaderCacheEntry->spirvOffset; + + std::vector decoded(smolv::GetDecodedBufferSize(compressedSpirvData, guestShader->shaderCacheEntry->spirvSize)); + bool result = smolv::Decode(compressedSpirvData, guestShader->shaderCacheEntry->spirvSize, decoded.data(), decoded.size()); + assert(result); + + guestShader->shader = g_device->createShader(decoded.data(), decoded.size(), "main", RenderShaderFormat::SPIRV); + } + else + { + guestShader->shader = g_device->createShader(g_shaderCache.get() + guestShader->shaderCacheEntry->dxilOffset, + guestShader->shaderCacheEntry->dxilSize, "main", RenderShaderFormat::DXIL); + } + } + + return guestShader->shader.get(); + } + + specConstants &= guestShader->shaderCacheEntry->specConstantsMask; + + RenderShader* shader; + { + std::lock_guard lock(guestShader->mutex); + shader = guestShader->linkedShaders[specConstants].get(); + } + + if (shader == nullptr) + { + thread_local ComPtr s_dxcCompiler; + thread_local ComPtr s_dxcLinker; + thread_local ComPtr s_dxcUtils; + + wchar_t specConstantsLibName[0x100]; + swprintf_s(specConstantsLibName, L"SpecConstants_%d", specConstants); + + ComPtr specConstantLibraryBlob; + { + std::lock_guard lock(g_compiledSpecConstantLibraryBlobMutex); + specConstantLibraryBlob = g_compiledSpecConstantLibraryBlobs[specConstants]; + } + + if (specConstantLibraryBlob == nullptr) + { + if (s_dxcCompiler == nullptr) + { + HRESULT hr = DxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(s_dxcCompiler.GetAddressOf())); + assert(SUCCEEDED(hr) && s_dxcCompiler != nullptr); + } + + char libraryHlsl[0x100]; + sprintf_s(libraryHlsl, "export uint g_SpecConstants() { return %d; }", specConstants); + + DxcBuffer buffer{}; + buffer.Ptr = libraryHlsl; + buffer.Size = strlen(libraryHlsl); + + const wchar_t* args[1]; + args[0] = L"-T lib_6_3"; + + ComPtr result; + HRESULT hr = s_dxcCompiler->Compile(&buffer, args, std::size(args), nullptr, IID_PPV_ARGS(result.GetAddressOf())); + assert(SUCCEEDED(hr) && result != nullptr); + + hr = result->GetResult(specConstantLibraryBlob.GetAddressOf()); + assert(SUCCEEDED(hr) && specConstantLibraryBlob != nullptr); + + std::lock_guard lock(g_compiledSpecConstantLibraryBlobMutex); + g_compiledSpecConstantLibraryBlobs.emplace(specConstants, specConstantLibraryBlob); + } + + if (s_dxcLinker == nullptr) + { + HRESULT hr = DxcCreateInstance(CLSID_DxcLinker, IID_PPV_ARGS(s_dxcLinker.GetAddressOf())); + assert(SUCCEEDED(hr) && s_dxcLinker != nullptr); + } + + s_dxcLinker->RegisterLibrary(specConstantsLibName, specConstantLibraryBlob.Get()); + + wchar_t shaderLibName[0x100]; + swprintf_s(shaderLibName, L"Shader_%d", guestShader->shaderCacheEntry->dxilOffset); + + ComPtr shaderLibraryBlob; + { + std::lock_guard lock(guestShader->mutex); + shaderLibraryBlob = guestShader->libraryBlob; + } + + if (shaderLibraryBlob == nullptr) + { + if (s_dxcUtils == nullptr) + { + HRESULT hr = DxcCreateInstance(CLSID_DxcUtils, IID_PPV_ARGS(s_dxcUtils.GetAddressOf())); + assert(SUCCEEDED(hr) && s_dxcUtils != nullptr); + } + + HRESULT hr = s_dxcUtils->CreateBlobFromPinned( + g_shaderCache.get() + guestShader->shaderCacheEntry->dxilOffset, + guestShader->shaderCacheEntry->dxilSize, + DXC_CP_ACP, + shaderLibraryBlob.GetAddressOf()); + + assert(SUCCEEDED(hr) && shaderLibraryBlob != nullptr); + + std::lock_guard lock(guestShader->mutex); + guestShader->libraryBlob = shaderLibraryBlob; + } + + s_dxcLinker->RegisterLibrary(shaderLibName, shaderLibraryBlob.Get()); + + const wchar_t* libraryNames[] = { specConstantsLibName, shaderLibName }; + + ComPtr result; + HRESULT hr = s_dxcLinker->Link(L"main", guestShader->type == ResourceType::VertexShader ? L"vs_6_0" : L"ps_6_0", + libraryNames, std::size(libraryNames), nullptr, 0, result.GetAddressOf()); + + assert(SUCCEEDED(hr) && result != nullptr); + + ComPtr blob; + hr = result->GetResult(blob.GetAddressOf()); + assert(SUCCEEDED(hr) && blob != nullptr); + + { + std::lock_guard lock(guestShader->mutex); + + auto& linkedShader = guestShader->linkedShaders[specConstants]; + if (linkedShader == nullptr) + { + linkedShader = g_device->createShader(blob->GetBufferPointer(), blob->GetBufferSize(), "main", RenderShaderFormat::DXIL); + guestShader->shaderBlobs.push_back(std::move(blob)); + } + + shader = linkedShader.get(); + } + } + + return shader; +} + +static void SanitizePipelineState(PipelineState& pipelineState) { - // Sanitize to prevent state leaking. if (!pipelineState.zEnable) { pipelineState.zWriteEnable = false; @@ -2416,6 +2652,9 @@ static RenderPipeline* CreateGraphicsPipeline(PipelineState pipelineState) pipelineState.depthStencilFormat = RenderFormat::UNKNOWN; } + if (pipelineState.slopeScaledDepthBias == 0.0f) + pipelineState.slopeScaledDepthBias = 0.0f; // Remove sign. + if (!pipelineState.colorWriteEnable) { pipelineState.alphaBlendEnable = false; @@ -2432,64 +2671,186 @@ static RenderPipeline* CreateGraphicsPipeline(PipelineState pipelineState) pipelineState.blendOpAlpha = RenderBlendOperation::ADD; } - auto& pipeline = g_pipelines[XXH3_64bits(&pipelineState, sizeof(PipelineState))]; + uint32_t specConstantsMask = 0; + if (pipelineState.vertexShader->shaderCacheEntry != nullptr) + specConstantsMask |= pipelineState.vertexShader->shaderCacheEntry->specConstantsMask; + + if (pipelineState.pixelShader != nullptr && pipelineState.pixelShader->shaderCacheEntry != nullptr) + specConstantsMask |= pipelineState.pixelShader->shaderCacheEntry->specConstantsMask; + + pipelineState.specConstants &= specConstantsMask; +} + +static std::unique_ptr CreateGraphicsPipeline(const PipelineState& pipelineState) +{ +#ifdef ASYNC_PSO_DEBUG + ++g_pipelinesCurrentlyCompiling; +#endif + + RenderGraphicsPipelineDesc desc; + desc.pipelineLayout = g_pipelineLayout.get(); + desc.vertexShader = GetOrLinkShader(pipelineState.vertexShader, pipelineState.specConstants); + desc.pixelShader = pipelineState.pixelShader != nullptr ? GetOrLinkShader(pipelineState.pixelShader, pipelineState.specConstants) : nullptr; + desc.depthFunction = pipelineState.zFunc; + desc.depthEnabled = pipelineState.zEnable; + desc.depthWriteEnabled = pipelineState.zWriteEnable; + desc.depthBias = pipelineState.depthBias; + desc.slopeScaledDepthBias = pipelineState.slopeScaledDepthBias; + desc.depthClipEnabled = true; + desc.primitiveTopology = pipelineState.primitiveTopology; + desc.cullMode = pipelineState.cullMode; + desc.renderTargetFormat[0] = pipelineState.renderTargetFormat; + desc.renderTargetBlend[0].blendEnabled = pipelineState.alphaBlendEnable; + desc.renderTargetBlend[0].srcBlend = pipelineState.srcBlend; + desc.renderTargetBlend[0].dstBlend = pipelineState.destBlend; + desc.renderTargetBlend[0].blendOp = pipelineState.blendOp; + desc.renderTargetBlend[0].srcBlendAlpha = pipelineState.srcBlendAlpha; + desc.renderTargetBlend[0].dstBlendAlpha = pipelineState.destBlendAlpha; + desc.renderTargetBlend[0].blendOpAlpha = pipelineState.blendOpAlpha; + desc.renderTargetBlend[0].renderTargetWriteMask = pipelineState.colorWriteEnable; + desc.renderTargetCount = pipelineState.renderTargetFormat != RenderFormat::UNKNOWN ? 1 : 0; + desc.depthTargetFormat = pipelineState.depthStencilFormat; + desc.multisampling.sampleCount = pipelineState.sampleCount; + desc.alphaToCoverageEnabled = pipelineState.enableAlphaToCoverage; + desc.inputElements = pipelineState.vertexDeclaration->inputElements.get(); + desc.inputElementsCount = pipelineState.vertexDeclaration->inputElementCount; + + RenderSpecConstant specConstant{}; + specConstant.value = pipelineState.specConstants; + + if (pipelineState.specConstants != 0) + { + desc.specConstants = &specConstant; + desc.specConstantsCount = 1; + } + + RenderInputSlot inputSlots[16]{}; + uint32_t inputSlotIndices[16]{}; + uint32_t inputSlotCount = 0; + + for (size_t i = 0; i < pipelineState.vertexDeclaration->inputElementCount; i++) + { + auto& inputElement = pipelineState.vertexDeclaration->inputElements[i]; + auto& inputSlotIndex = inputSlotIndices[inputElement.slotIndex]; + + if (inputSlotIndex == NULL) + inputSlotIndex = ++inputSlotCount; + + auto& inputSlot = inputSlots[inputSlotIndex - 1]; + inputSlot.index = inputElement.slotIndex; + inputSlot.stride = pipelineState.vertexStrides[inputElement.slotIndex]; + + if (pipelineState.instancing && inputElement.slotIndex != 0 && inputElement.slotIndex != 15) + inputSlot.classification = RenderInputSlotClassification::PER_INSTANCE_DATA; + else + inputSlot.classification = RenderInputSlotClassification::PER_VERTEX_DATA; + } + + desc.inputSlots = inputSlots; + desc.inputSlotsCount = inputSlotCount; + + auto pipeline = g_device->createGraphicsPipeline(desc); + +#ifdef ASYNC_PSO_DEBUG + --g_pipelinesCurrentlyCompiling; +#endif + + return pipeline; +} + +static RenderPipeline* CreateGraphicsPipelineInRenderThread(PipelineState pipelineState) +{ + SanitizePipelineState(pipelineState); + + XXH64_hash_t hash = XXH3_64bits(&pipelineState, sizeof(pipelineState)); + auto& pipeline = g_pipelines[hash]; if (pipeline == nullptr) { - RenderGraphicsPipelineDesc desc; - desc.pipelineLayout = g_pipelineLayout.get(); - desc.vertexShader = pipelineState.vertexShader->shader.get(); - desc.pixelShader = pipelineState.pixelShader != nullptr ? pipelineState.pixelShader->shader.get() : nullptr; - desc.depthFunction = pipelineState.zFunc; - desc.depthEnabled = pipelineState.zEnable; - desc.depthWriteEnabled = pipelineState.zWriteEnable; - desc.depthBias = pipelineState.depthBias; - desc.slopeScaledDepthBias = pipelineState.slopeScaledDepthBias; - desc.depthClipEnabled = true; - desc.primitiveTopology = pipelineState.primitiveTopology; - desc.cullMode = pipelineState.cullMode; - desc.renderTargetFormat[0] = pipelineState.renderTargetFormat; - desc.renderTargetBlend[0].blendEnabled = pipelineState.alphaBlendEnable; - desc.renderTargetBlend[0].srcBlend = pipelineState.srcBlend; - desc.renderTargetBlend[0].dstBlend = pipelineState.destBlend; - desc.renderTargetBlend[0].blendOp = pipelineState.blendOp; - desc.renderTargetBlend[0].srcBlendAlpha = pipelineState.srcBlendAlpha; - desc.renderTargetBlend[0].dstBlendAlpha = pipelineState.destBlendAlpha; - desc.renderTargetBlend[0].blendOpAlpha = pipelineState.blendOpAlpha; - desc.renderTargetBlend[0].renderTargetWriteMask = pipelineState.colorWriteEnable; - desc.renderTargetCount = pipelineState.renderTargetFormat != RenderFormat::UNKNOWN ? 1 : 0; - desc.depthTargetFormat = pipelineState.depthStencilFormat; - desc.multisampling.sampleCount = pipelineState.sampleCount; - desc.alphaToCoverageEnabled = pipelineState.enableAlphaToCoverage; - desc.inputElements = pipelineState.vertexDeclaration->inputElements.get(); - desc.inputElementsCount = pipelineState.vertexDeclaration->inputElementCount; + pipeline = CreateGraphicsPipeline(pipelineState); - RenderInputSlot inputSlots[16]{}; - uint32_t inputSlotIndices[16]{}; - uint32_t inputSlotCount = 0; +#ifdef ASYNC_PSO_DEBUG + bool loading = *reinterpret_cast(g_memory.Translate(0x83367A4C)); - for (size_t i = 0; i < pipelineState.vertexDeclaration->inputElementCount; i++) + if (loading) + ++g_pipelinesCreatedAsynchronously; + else + ++g_pipelinesCreatedInRenderThread; + + pipeline->setName(std::format("{} {} {} {:X}", loading ? "ASYNC" : "", + pipelineState.vertexShader->name, pipelineState.pixelShader != nullptr ? pipelineState.pixelShader->name : "", hash)); + + if (!loading) { - auto& inputElement = pipelineState.vertexDeclaration->inputElements[i]; - auto& inputSlotIndex = inputSlotIndices[inputElement.slotIndex]; - - if (inputSlotIndex == NULL) - inputSlotIndex = ++inputSlotCount; - - auto& inputSlot = inputSlots[inputSlotIndex - 1]; - inputSlot.index = inputElement.slotIndex; - inputSlot.stride = pipelineState.vertexStrides[inputElement.slotIndex]; - - if (pipelineState.instancing && inputElement.slotIndex != 0 && inputElement.slotIndex != 15) - inputSlot.classification = RenderInputSlotClassification::PER_INSTANCE_DATA; - else - inputSlot.classification = RenderInputSlotClassification::PER_VERTEX_DATA; + std::lock_guard lock(g_debugMutex); + g_pipelineDebugText = std::format( + "PipelineState {:X}:\n" + " vertexShader: {}\n" + " pixelShader: {}\n" + " vertexDeclaration: {:X}\n" + " instancing: {}\n" + " zEnable: {}\n" + " zWriteEnable: {}\n" + " srcBlend: {}\n" + " destBlend: {}\n" + " cullMode: {}\n" + " zFunc: {}\n" + " alphaBlendEnable: {}\n" + " blendOp: {}\n" + " slopeScaledDepthBias: {}\n" + " depthBias: {}\n" + " srcBlendAlpha: {}\n" + " destBlendAlpha: {}\n" + " blendOpAlpha: {}\n" + " colorWriteEnable: {:X}\n" + " primitiveTopology: {}\n" + " vertexStrides[0]: {}\n" + " vertexStrides[1]: {}\n" + " vertexStrides[2]: {}\n" + " vertexStrides[3]: {}\n" + " renderTargetFormat: {}\n" + " depthStencilFormat: {}\n" + " sampleCount: {}\n" + " enableAlphaToCoverage: {}\n" + " specConstants: {:X}\n", + hash, + pipelineState.vertexShader->name, + pipelineState.pixelShader != nullptr ? pipelineState.pixelShader->name : "", + reinterpret_cast(pipelineState.vertexDeclaration), + pipelineState.instancing, + pipelineState.zEnable, + pipelineState.zWriteEnable, + magic_enum::enum_name(pipelineState.srcBlend), + magic_enum::enum_name(pipelineState.destBlend), + magic_enum::enum_name(pipelineState.cullMode), + magic_enum::enum_name(pipelineState.zFunc), + pipelineState.alphaBlendEnable, + magic_enum::enum_name(pipelineState.blendOp), + pipelineState.slopeScaledDepthBias, + pipelineState.depthBias, + magic_enum::enum_name(pipelineState.srcBlendAlpha), + magic_enum::enum_name(pipelineState.destBlendAlpha), + magic_enum::enum_name(pipelineState.blendOpAlpha), + pipelineState.colorWriteEnable, + magic_enum::enum_name(pipelineState.primitiveTopology), + pipelineState.vertexStrides[0], + pipelineState.vertexStrides[1], + pipelineState.vertexStrides[2], + pipelineState.vertexStrides[3], + magic_enum::enum_name(pipelineState.renderTargetFormat), + magic_enum::enum_name(pipelineState.depthStencilFormat), + pipelineState.sampleCount, + pipelineState.enableAlphaToCoverage, + pipelineState.specConstants) + + g_pipelineDebugText; } +#endif - desc.inputSlots = inputSlots; - desc.inputSlotsCount = inputSlotCount; - - pipeline = g_device->createGraphicsPipeline(desc); +#ifdef PSO_CACHING + std::lock_guard lock(g_pipelineCacheMutex); + g_pipelineStatesToCache.push_back(pipelineState); +#endif } + return pipeline.get(); } @@ -2672,6 +3033,27 @@ static void ProcSetPixelShaderConstants(const RenderCommand& cmd) SetRootDescriptor(cmd.setPixelShaderConstants.allocation, 1); } +static void ProcAddPipeline(const RenderCommand& cmd) +{ + auto& args = cmd.addPipeline; + auto& pipeline = g_pipelines[args.hash]; + + if (pipeline == nullptr) + { + pipeline = std::unique_ptr(args.pipeline); +#ifdef ASYNC_PSO_DEBUG + ++g_pipelinesCreatedAsynchronously; +#endif + } + else + { +#ifdef ASYNC_PSO_DEBUG + ++g_pipelinesDropped; +#endif + delete args.pipeline; + } +} + static void FlushRenderStateForRenderThread() { auto renderTarget = g_pipelineState.colorWriteEnable ? g_renderTarget : nullptr; @@ -2686,7 +3068,7 @@ static void FlushRenderStateForRenderThread() auto& commandList = g_commandLists[g_frame]; if (g_dirtyStates.pipelineState) - commandList->setPipeline(CreateGraphicsPipeline(g_pipelineState)); + commandList->setPipeline(CreateGraphicsPipelineInRenderThread(g_pipelineState)); if (g_dirtyStates.sharedConstants) { @@ -2947,7 +3329,7 @@ static RenderFormat ConvertDeclType(uint32_t type) } } -static GuestVertexDeclaration* CreateVertexDeclaration(GuestVertexElement* vertexElements) +static GuestVertexDeclaration* CreateVertexDeclarationWithoutAddRef(GuestVertexElement* vertexElements) { size_t vertexElementCount = 0; auto vertexElement = vertexElements; @@ -2961,12 +3343,13 @@ static GuestVertexDeclaration* CreateVertexDeclaration(GuestVertexElement* verte std::lock_guard lock(g_vertexDeclarationMutex); - auto& vertexDeclaration = g_vertexDeclarations[ - XXH3_64bits(vertexElements, vertexElementCount * sizeof(GuestVertexElement))]; + XXH64_hash_t hash = XXH3_64bits(vertexElements, vertexElementCount * sizeof(GuestVertexElement)); + auto& vertexDeclaration = g_vertexDeclarations[hash]; if (vertexDeclaration == nullptr) { vertexDeclaration = g_userHeap.AllocPhysical(ResourceType::VertexDeclaration); + vertexDeclaration->hash = hash; static std::vector inputElements; inputElements.clear(); @@ -3036,18 +3419,13 @@ static GuestVertexDeclaration* CreateVertexDeclaration(GuestVertexElement* verte vertexDeclaration->indexVertexStream = vertexElement->stream; break; - case D3DDECLUSAGE_BLENDWEIGHT: - case D3DDECLUSAGE_BLENDINDICES: - vertexDeclaration->inputLayoutFlags |= INPUT_LAYOUT_FLAG_HAS_BONE_WEIGHTS; - break; - case D3DDECLUSAGE_NORMAL: case D3DDECLUSAGE_TANGENT: case D3DDECLUSAGE_BINORMAL: if (vertexElement->type == D3DDECLTYPE_FLOAT3) inputElement.format = RenderFormat::R32G32B32_UINT; else - vertexDeclaration->inputLayoutFlags |= INPUT_LAYOUT_FLAG_HAS_R11G11B10_NORMAL; + vertexDeclaration->hasR11G11B10Normal = true; break; case D3DDECLUSAGE_TEXCOORD: @@ -3132,6 +3510,13 @@ static GuestVertexDeclaration* CreateVertexDeclaration(GuestVertexElement* verte return vertexDeclaration; } +static GuestVertexDeclaration* CreateVertexDeclaration(GuestVertexElement* vertexElements) +{ + auto vertexDeclaration = CreateVertexDeclarationWithoutAddRef(vertexElements); + vertexDeclaration->AddRef(); + return vertexDeclaration; +} + static void SetVertexDeclaration(GuestDevice* device, GuestVertexDeclaration* vertexDeclaration) { RenderCommand cmd; @@ -3149,39 +3534,48 @@ static void ProcSetVertexDeclaration(const RenderCommand& cmd) if (args.vertexDeclaration != nullptr) { SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.swappedTexcoords, args.vertexDeclaration->swappedTexcoords); - SetDirtyValue(g_dirtyStates.sharedConstants, g_sharedConstants.inputLayoutFlags, args.vertexDeclaration->inputLayoutFlags); + + uint32_t specConstants = g_pipelineState.specConstants; + if (args.vertexDeclaration->hasR11G11B10Normal) + specConstants |= SPEC_CONSTANT_R11G11B10_NORMAL; + else + specConstants &= ~SPEC_CONSTANT_R11G11B10_NORMAL; + + SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.specConstants, specConstants); } SetDirtyValue(g_dirtyStates.pipelineState, g_pipelineState.vertexDeclaration, args.vertexDeclaration); } -static GuestShader* CreateShader(const be* function, ResourceType resourceType) +static ShaderCacheEntry* FindShaderCacheEntry(XXH64_hash_t hash) { - XXH64_hash_t hash = XXH3_64bits(function, function[1] + function[2]); - auto end = g_shaderCacheEntries + g_shaderCacheEntryCount; auto findResult = std::lower_bound(g_shaderCacheEntries, end, hash, [](ShaderCacheEntry& lhs, XXH64_hash_t rhs) { return lhs.hash < rhs; }); + return findResult != end && findResult->hash == hash ? findResult : nullptr; +} + +static GuestShader* CreateShader(const be* function, ResourceType resourceType) +{ + XXH64_hash_t hash = XXH3_64bits(function, function[1] + function[2]); + + auto findResult = FindShaderCacheEntry(hash); GuestShader* shader = nullptr; - if (findResult != end && findResult->hash == hash) + if (findResult != nullptr) { - if (findResult->userData == nullptr) + if (findResult->guestShader == nullptr) { shader = g_userHeap.AllocPhysical(resourceType); + shader->shaderCacheEntry = findResult; - if (g_vulkan) - shader->shader = g_device->createShader(g_shaderCache.get() + findResult->spirvOffset, findResult->spirvSize, "main", RenderShaderFormat::SPIRV); - else - shader->shader = g_device->createShader(g_shaderCache.get() + findResult->dxilOffset, findResult->dxilSize, "main", RenderShaderFormat::DXIL); - - findResult->userData = shader; + findResult->guestShader = shader; } else { - shader = reinterpret_cast(findResult->userData); + shader = findResult->guestShader; } } @@ -3278,6 +3672,8 @@ static void ProcSetPixelShader(const RenderCommand& cmd) static std::thread g_renderThread([] { + GuestThread::SetThreadName(GetCurrentThreadId(), "Render Thread"); + RenderCommand commands[32]; while (true) @@ -3306,6 +3702,7 @@ static std::thread g_renderThread([] case RenderCommandType::SetBooleans: ProcSetBooleans(cmd); break; case RenderCommandType::SetVertexShaderConstants: ProcSetVertexShaderConstants(cmd); break; case RenderCommandType::SetPixelShaderConstants: ProcSetPixelShaderConstants(cmd); break; + case RenderCommandType::AddPipeline: ProcAddPipeline(cmd); break; case RenderCommandType::DrawPrimitive: ProcDrawPrimitive(cmd); break; case RenderCommandType::DrawIndexedPrimitive: ProcDrawIndexedPrimitive(cmd); break; case RenderCommandType::DrawPrimitiveUP: ProcDrawPrimitiveUP(cmd); break; @@ -3644,7 +4041,7 @@ static RenderFormat ConvertDXGIFormat(ddspp::DXGIFormat format) static void MakePictureData(GuestPictureData* pictureData, uint8_t* data, uint32_t dataSize) { - if ((pictureData->flags & 0x1) == 0) + if ((pictureData->flags & 0x1) == 0 && data != nullptr) { ddspp::Descriptor ddsDesc; if (ddspp::decode_header(data, ddsDesc) != ddspp::Error) @@ -3865,7 +4262,7 @@ static void ScreenShaderInit(be* a1, uint32_t a2, uint32_t a3, GuestVe } if (g_movieVertexDeclaration == nullptr) - g_movieVertexDeclaration = CreateVertexDeclaration(vertexElements); + g_movieVertexDeclaration = CreateVertexDeclarationWithoutAddRef(vertexElements); g_moviePixelShader->AddRef(); g_movieVertexShader->AddRef(); @@ -3976,6 +4373,1034 @@ void ParticleTestDrawIndexedPrimitiveMidAsmHook(PPCRegister& r7) r7.u64 = std::size(g_particleTestIndexBuffer); } +void MotionBlurPrevInvViewProjectionMidAsmHook(PPCRegister& r10) +{ + auto mtxProjection = reinterpret_cast*>(g_memory.Translate(r10.u32)); + + // Reverse Z. Have to be done on CPU side because the matrix multiplications + // add up and it loses precision by the time it's sent to GPU. + mtxProjection[10] = -(mtxProjection[10] + 1.0f); + mtxProjection[14] = -mtxProjection[14]; +} + +// Normally, we could delay setting IsMadeOne, but the game relies on that flag +// being present to handle load priority. To work around that, we can prevent +// IsMadeAll from being set until the compilation is finished. Time for a custom flag! +enum +{ + eDatabaseDataFlags_CompilingPipelines = 0x80 +}; + +// This is passed to pipeline compilation threads to keep the loading screen busy until +// all of them are finished. A shared pointer makes sure the destructor is called only once. +struct DatabaseDataHolder +{ + boost::shared_ptr databaseData; + + DatabaseDataHolder() : databaseData() + { + } + + DatabaseDataHolder(const DatabaseDataHolder&) = delete; + DatabaseDataHolder(DatabaseDataHolder&& other) + : databaseData(std::exchange(other.databaseData, nullptr)) + { + } + + ~DatabaseDataHolder() + { + if (databaseData.get() != nullptr) + { + databaseData->m_Flags &= ~eDatabaseDataFlags_CompilingPipelines; + + if ((--g_compilingDataCount) == 0) + g_compilingDataCount.notify_all(); + } + } +}; + +struct PipelineStateQueueItem +{ + XXH64_hash_t pipelineHash; + PipelineState pipelineState; + std::shared_ptr databaseDataHolder; +#ifdef ASYNC_PSO_DEBUG + std::string pipelineName; +#endif +}; + +static moodycamel::BlockingConcurrentQueue g_pipelineStateQueue; + +struct MinimalGuestThreadContext +{ + uint8_t* stack = nullptr; + PPCContext ppcContext{}; + + ~MinimalGuestThreadContext() + { + if (stack != nullptr) + g_userHeap.Free(stack); + } + + void ensureValid() + { + if (stack == nullptr) + { + stack = reinterpret_cast(g_userHeap.Alloc(0x4000)); + ppcContext.fn = (uint8_t*)g_codeCache.bucket; + ppcContext.r1.u64 = g_memory.MapVirtual(stack + 0x4000); + SetPPCContext(ppcContext); + } + } +}; + +static void PipelineCompilerThread() +{ + GuestThread::SetThreadName(GetCurrentThreadId(), "Pipeline Compiler Thread"); + MinimalGuestThreadContext ctx; + + while (true) + { + PipelineStateQueueItem queueItem; + g_pipelineStateQueue.wait_dequeue(queueItem); + + ctx.ensureValid(); + + auto pipeline = CreateGraphicsPipeline(queueItem.pipelineState); +#ifdef ASYNC_PSO_DEBUG + pipeline->setName(queueItem.pipelineName); +#endif + + // Will get dropped in render thread if a different thread already managed to compile this. + RenderCommand cmd; + cmd.type = RenderCommandType::AddPipeline; + cmd.addPipeline.hash = queueItem.pipelineHash; + cmd.addPipeline.pipeline = pipeline.release(); + g_renderQueue.enqueue(cmd); + } +} + +static std::vector> g_pipelineCompilerThreads = []() + { + size_t threadCount = std::max(2u, (std::thread::hardware_concurrency() * 2) / 3); + + std::vector> threads(threadCount); + for (auto& thread : threads) + thread = std::make_unique(PipelineCompilerThread); + + return threads; + }(); + +static constexpr uint32_t MODEL_DATA_VFTABLE = 0x82073A44; +static constexpr uint32_t TERRAIN_MODEL_DATA_VFTABLE = 0x8211D25C; +static constexpr uint32_t PARTICLE_MATERIAL_VFTABLE = 0x8211F198; + +// Allocate the shared pointer only when new compilations are happening. +// If nothing was compiled, the local "holder" variable will get destructed with RAII instead. +struct DatabaseDataHolderPair +{ + DatabaseDataHolder holder; + std::shared_ptr counter; +}; + +// Having this separate, because I don't want to lock a mutex in the render thread before +// every single draw. Might be worth profiling to see if it actually has an impact and merge them. +static ankerl::unordered_dense::set g_asyncPipelines; + +static void EnqueueGraphicsPipelineCompilation(const PipelineState& pipelineState, DatabaseDataHolderPair& databaseDataHolderPair, const char* name) +{ + XXH64_hash_t hash = XXH3_64bits(&pipelineState, sizeof(pipelineState)); + bool shouldCompile = g_asyncPipelines.emplace(hash).second; + + if (shouldCompile) + { + if (databaseDataHolderPair.counter == nullptr && databaseDataHolderPair.holder.databaseData.get() != nullptr) + databaseDataHolderPair.counter = std::make_unique(std::move(databaseDataHolderPair.holder)); + + PipelineStateQueueItem queueItem; + queueItem.pipelineHash = hash; + queueItem.pipelineState = pipelineState; + queueItem.databaseDataHolder = databaseDataHolderPair.counter; +#ifdef ASYNC_PSO_DEBUG + queueItem.pipelineName = std::format("ASYNC {} {:X}", name, hash); +#endif + g_pipelineStateQueue.enqueue(queueItem); + } +} + +struct CompilationArgs +{ + DatabaseDataHolderPair holderPair; + bool noGI{}; + bool hasMoreThanOneBone{}; + bool velocityMapQuickStep{}; + bool objectIcon{}; +}; + +enum class MeshLayer +{ + Opaque, + Transparent, + PunchThrough, + Special +}; + +static void CompileMeshPipeline(Hedgehog::Mirage::CMeshData* mesh, MeshLayer layer, CompilationArgs& args) +{ + if (mesh->m_spMaterial.get() == nullptr || mesh->m_spMaterial->m_spShaderListData.get() == nullptr) + return; + + auto& material = mesh->m_spMaterial; + auto& shaderList = material->m_spShaderListData; + + bool isFur = strstr(shaderList->m_TypeAndName.c_str(), "Fur") != nullptr; + bool isSky = strstr(shaderList->m_TypeAndName.c_str(), "Sky") != nullptr; + bool isSonicMouth = strcmp(material->m_TypeAndName.c_str() + 2, "sonic_gm_mouth_duble") == 0 && + strcmp(shaderList->m_TypeAndName.c_str() + 3, "SonicSkin_dspf[b]") == 0; + + bool compiledOutsideMainFramebuffer = !isFur && !isSky; + + bool constTexCoord = true; + if (material->m_spTexsetData.get() != nullptr) + { + for (size_t i = 1; i < material->m_spTexsetData->m_TextureList.size(); i++) + { + if (material->m_spTexsetData->m_TextureList[i]->m_TexcoordIndex != + material->m_spTexsetData->m_TextureList[0]->m_TexcoordIndex) + { + constTexCoord = false; + break; + } + } + } + + auto vertexDeclaration = reinterpret_cast(mesh->m_VertexDeclarationPtr.m_pD3DVertexDeclaration.get()); + + // Shadow pipeline. + if (compiledOutsideMainFramebuffer && (layer == MeshLayer::Opaque || layer == MeshLayer::PunchThrough)) + { + PipelineState pipelineState{}; + + if (layer == MeshLayer::PunchThrough) + { + pipelineState.vertexShader = FindShaderCacheEntry(0xDD4FA7BB53876300)->guestShader; + pipelineState.pixelShader = FindShaderCacheEntry(0xE2ECA594590DDE8B)->guestShader; + } + else + { + pipelineState.vertexShader = FindShaderCacheEntry(0x8E4BB23465BD909E)->guestShader; + } + + pipelineState.vertexDeclaration = vertexDeclaration; + pipelineState.cullMode = material->m_DoubleSided ? RenderCullMode::NONE : RenderCullMode::BACK; + pipelineState.zFunc = RenderComparisonFunction::LESS_EQUAL; + pipelineState.depthBias = (1 << 24) * (*reinterpret_cast*>(g_memory.Translate(0x83302760))); + pipelineState.slopeScaledDepthBias = *reinterpret_cast*>(g_memory.Translate(0x83302764)); + pipelineState.colorWriteEnable = 0; + pipelineState.primitiveTopology = RenderPrimitiveTopology::TRIANGLE_STRIP; + pipelineState.vertexStrides[0] = mesh->m_VertexSize; + pipelineState.depthStencilFormat = RenderFormat::D32_FLOAT; + + if (layer == MeshLayer::PunchThrough) + pipelineState.specConstants |= SPEC_CONSTANT_ALPHA_TEST; + + SanitizePipelineState(pipelineState); + EnqueueGraphicsPipelineCompilation(pipelineState, args.holderPair, layer == MeshLayer::PunchThrough ? "MakeShadowMapTransparent" : "MakeShadowMap"); + } + + // Motion blur pipeline. We could normally do the player here only, but apparently Werehog enemies also have object blur. + // TODO: Do punch through meshes get rendered? + if (compiledOutsideMainFramebuffer && args.hasMoreThanOneBone && layer == MeshLayer::Opaque) + { + PipelineState pipelineState{}; + pipelineState.vertexShader = FindShaderCacheEntry(0x4620B236DC38100C)->guestShader; + pipelineState.pixelShader = FindShaderCacheEntry(0xBBDB735BEACC8F41)->guestShader; + pipelineState.vertexDeclaration = vertexDeclaration; + pipelineState.cullMode = RenderCullMode::NONE; + pipelineState.zFunc = RenderComparisonFunction::GREATER_EQUAL; + pipelineState.primitiveTopology = RenderPrimitiveTopology::TRIANGLE_STRIP; + pipelineState.vertexStrides[0] = mesh->m_VertexSize; + pipelineState.renderTargetFormat = RenderFormat::R8G8B8A8_UNORM; + pipelineState.depthStencilFormat = RenderFormat::D32_FLOAT; + pipelineState.specConstants = SPEC_CONSTANT_REVERSE_Z; + + SanitizePipelineState(pipelineState); + EnqueueGraphicsPipelineCompilation(pipelineState, args.holderPair, "FxVelocityMap"); + + if (args.velocityMapQuickStep) + { + pipelineState.vertexShader = FindShaderCacheEntry(0x99DC3F27E402700D)->guestShader; + SanitizePipelineState(pipelineState); + EnqueueGraphicsPipelineCompilation(pipelineState, args.holderPair, "FxVelocityMapQuickStep"); + } + } + + guest_stack_var defaultSymbol(reinterpret_cast(g_memory.Translate(0x8202DDBC))); + auto defaultFindResult = shaderList->m_PixelShaderPermutations.find(*defaultSymbol); + if (defaultFindResult == shaderList->m_PixelShaderPermutations.end()) + return; + + uint32_t pixelShaderSubPermutationsToCompile = 0; + if (constTexCoord) pixelShaderSubPermutationsToCompile |= 0x1; + if (args.noGI) pixelShaderSubPermutationsToCompile |= 0x2; + + if ((defaultFindResult->second.m_SubPermutations.get() & (1 << pixelShaderSubPermutationsToCompile)) == 0) pixelShaderSubPermutationsToCompile &= ~0x1; + if ((defaultFindResult->second.m_SubPermutations.get() & (1 << pixelShaderSubPermutationsToCompile)) == 0) pixelShaderSubPermutationsToCompile &= ~0x2; + + guest_stack_var noneSymbol(reinterpret_cast(g_memory.Translate(0x8200D938))); + auto noneFindResult = defaultFindResult->second.m_VertexShaderPermutations.find(*noneSymbol); + if (noneFindResult == defaultFindResult->second.m_VertexShaderPermutations.end()) + return; + + uint32_t vertexShaderSubPermutationsToCompile = 0; + if (constTexCoord) vertexShaderSubPermutationsToCompile |= 0x1; + + if ((noneFindResult->second->m_SubPermutations.get() & (1 << vertexShaderSubPermutationsToCompile)) == 0) + vertexShaderSubPermutationsToCompile &= ~0x1; + + // Fur requires an instanced variant of the vertex declaration. + if (isFur) + { + GuestVertexElement vertexElements[64]; + memcpy(vertexElements, vertexDeclaration->vertexElements.get(), (vertexDeclaration->vertexElementCount - 1) * sizeof(GuestVertexElement)); + + vertexElements[vertexDeclaration->vertexElementCount - 1] = { 1, 0, 0x2C82A1, 0, 0, 1 }; + vertexElements[vertexDeclaration->vertexElementCount] = { 2, 0, 0x2C83A4, 0, 0, 2 }; + vertexElements[vertexDeclaration->vertexElementCount + 1] = D3DDECL_END(); + + vertexDeclaration = CreateVertexDeclarationWithoutAddRef(vertexElements); + } + + for (auto& [pixelShaderSubPermutations, pixelShader] : defaultFindResult->second.m_PixelShaders) + { + if (pixelShader.get() == nullptr || (pixelShaderSubPermutations & 0x3) != pixelShaderSubPermutationsToCompile) + continue; + + for (auto& [vertexShaderSubPermutations, vertexShader] : noneFindResult->second->m_VertexShaders) + { + if (vertexShader.get() == nullptr || (vertexShaderSubPermutations & 0x1) != vertexShaderSubPermutationsToCompile) + continue; + + PipelineState pipelineState{}; + pipelineState.vertexShader = reinterpret_cast(vertexShader->m_spCode->m_pD3DVertexShader.get()); + pipelineState.pixelShader = reinterpret_cast(pixelShader->m_spCode->m_pD3DPixelShader.get()); + pipelineState.vertexDeclaration = vertexDeclaration; + pipelineState.instancing = isFur; + pipelineState.zWriteEnable = !isSky && layer != MeshLayer::Transparent; + pipelineState.srcBlend = RenderBlend::SRC_ALPHA; + pipelineState.destBlend = material->m_Additive ? RenderBlend::ONE : RenderBlend::INV_SRC_ALPHA; + pipelineState.cullMode = material->m_DoubleSided ? RenderCullMode::NONE : RenderCullMode::BACK; + pipelineState.zFunc = RenderComparisonFunction::GREATER_EQUAL; // Reverse Z + pipelineState.alphaBlendEnable = layer == MeshLayer::Transparent || layer == MeshLayer::Special; + pipelineState.srcBlendAlpha = RenderBlend::SRC_ALPHA; + pipelineState.destBlendAlpha = RenderBlend::INV_SRC_ALPHA; + pipelineState.primitiveTopology = RenderPrimitiveTopology::TRIANGLE_STRIP; + pipelineState.vertexStrides[0] = mesh->m_VertexSize; + pipelineState.vertexStrides[1] = isFur ? 4 : 0; + pipelineState.vertexStrides[2] = isFur ? 4 : 0; + pipelineState.renderTargetFormat = RenderFormat::R16G16B16A16_FLOAT; + pipelineState.depthStencilFormat = RenderFormat::D32_FLOAT; + pipelineState.sampleCount = Config::MSAA > 1 ? Config::MSAA : 1; + + if (pipelineState.vertexDeclaration->hasR11G11B10Normal) + pipelineState.specConstants |= SPEC_CONSTANT_R11G11B10_NORMAL; + + if (Config::GITextureFiltering == EGITextureFiltering::Bicubic) + pipelineState.specConstants |= SPEC_CONSTANT_BICUBIC_GI_FILTER; + + if (layer == MeshLayer::PunchThrough) + { + if (Config::MSAA > 1 && Config::AlphaToCoverage) + { + pipelineState.enableAlphaToCoverage = true; + pipelineState.specConstants |= SPEC_CONSTANT_ALPHA_TO_COVERAGE; + } + else + { + pipelineState.specConstants |= SPEC_CONSTANT_ALPHA_TEST; + } + } + + if (!isSky) + pipelineState.specConstants |= SPEC_CONSTANT_REVERSE_Z; + + auto createGraphicsPipeline = [&](PipelineState& pipelineStateToCreate) + { + SanitizePipelineState(pipelineStateToCreate); + EnqueueGraphicsPipelineCompilation(pipelineStateToCreate, args.holderPair, shaderList->m_TypeAndName.c_str() + 3); + }; + + createGraphicsPipeline(pipelineState); + + bool planarReflectionEnabled = reinterpret_cast(g_memory.Translate(0x832FA0D8)); + + auto noMsaaPipeline = pipelineState; + noMsaaPipeline.sampleCount = 1; + noMsaaPipeline.enableAlphaToCoverage = false; + + if ((noMsaaPipeline.specConstants & SPEC_CONSTANT_ALPHA_TO_COVERAGE) != 0) + { + noMsaaPipeline.specConstants &= ~SPEC_CONSTANT_ALPHA_TO_COVERAGE; + noMsaaPipeline.specConstants |= SPEC_CONSTANT_ALPHA_TEST; + } + + if (planarReflectionEnabled) + { + // Planar reflections don't use MSAA. + createGraphicsPipeline(noMsaaPipeline); + } + + if (args.objectIcon) + { + // Object icons get rendered to a SDR buffer without MSAA. + auto iconPipelineState = noMsaaPipeline; + iconPipelineState.renderTargetFormat = RenderFormat::R8G8B8A8_UNORM; + createGraphicsPipeline(iconPipelineState); + } + + if (isSonicMouth) + { + // Sonic's mouth switches between "SonicSkin_dspf[b]" or "SonicSkinNodeInvX_dspf[b]" depending on the view angle. + auto mouthPipelineState = pipelineState; + mouthPipelineState.vertexShader = FindShaderCacheEntry(0x689AA3140AB9EBAA)->guestShader; + createGraphicsPipeline(mouthPipelineState); + + if (planarReflectionEnabled) + { + auto noMsaaMouthPipelineState = noMsaaPipeline; + noMsaaMouthPipelineState.vertexShader = mouthPipelineState.vertexShader; + createGraphicsPipeline(noMsaaMouthPipelineState); + } + } + } + } +} + +template +static void CompileMeshPipelines(const T& modelData, CompilationArgs& args) +{ + for (auto& meshGroup : modelData.m_NodeGroupModels) + { + for (auto& mesh : meshGroup->m_OpaqueMeshes) + { + CompileMeshPipeline(mesh.get(), MeshLayer::Opaque, args); + + if (args.noGI) // For models that can be shown transparent (eg. medals) + CompileMeshPipeline(mesh.get(), MeshLayer::Transparent, args); + } + + for (auto& mesh : meshGroup->m_TransparentMeshes) + CompileMeshPipeline(mesh.get(), MeshLayer::Transparent, args); + + for (auto& mesh : meshGroup->m_PunchThroughMeshes) + CompileMeshPipeline(mesh.get(), MeshLayer::PunchThrough, args); + + for (auto& specialMeshGroup : meshGroup->m_SpecialMeshGroups) + { + for (auto& mesh : specialMeshGroup) + CompileMeshPipeline(mesh.get(), MeshLayer::Special, args); // TODO: Are there layer types other than water in this game?? + } + } + + for (auto& mesh : modelData.m_OpaqueMeshes) + { + CompileMeshPipeline(mesh.get(), MeshLayer::Opaque, args); + + if (args.noGI) + CompileMeshPipeline(mesh.get(), MeshLayer::Transparent, args); + } + + for (auto& mesh : modelData.m_TransparentMeshes) + CompileMeshPipeline(mesh.get(), MeshLayer::Transparent, args); + + for (auto& mesh : modelData.m_PunchThroughMeshes) + CompileMeshPipeline(mesh.get(), MeshLayer::PunchThrough, args); +} + +static void CompileParticleMaterialPipeline(const Hedgehog::Sparkle::CParticleMaterial& material, DatabaseDataHolderPair& holderPair) +{ + auto& shaderList = material.m_spShaderListData; + if (shaderList.get() == nullptr) + return; + + guest_stack_var defaultSymbol(reinterpret_cast(g_memory.Translate(0x8202DDBC))); + auto defaultFindResult = shaderList->m_PixelShaderPermutations.find(*defaultSymbol); + if (defaultFindResult == shaderList->m_PixelShaderPermutations.end()) + return; + + guest_stack_var noneSymbol(reinterpret_cast(g_memory.Translate(0x8200D938))); + auto noneFindResult = defaultFindResult->second.m_VertexShaderPermutations.find(*noneSymbol); + if (noneFindResult == defaultFindResult->second.m_VertexShaderPermutations.end()) + return; + + // All the particle models in the game come with the unoptimized format, so we can assume it. + uint8_t unoptimizedVertexElements[144] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2A, 0x23, 0xB9, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0C, 0x00, 0x2A, 0x23, 0xB9, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x18, 0x00, 0x2A, 0x23, 0xB9, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x00, 0x2A, 0x23, 0xB9, 0x00, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x2C, 0x23, 0xA5, 0x00, 0x05, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x38, 0x00, 0x2C, 0x23, 0xA5, 0x00, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x40, 0x00, 0x2C, 0x23, 0xA5, 0x00, 0x05, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x48, 0x00, 0x2C, 0x23, 0xA5, 0x00, 0x05, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x50, 0x00, 0x1A, 0x23, 0xA6, 0x00, 0x0A, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x60, 0x00, 0x1A, 0x23, 0x86, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x64, 0x00, 0x1A, 0x20, 0x86, 0x00, 0x01, 0x00, 0x00, + 0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 + }; + + auto unoptimizedVertexDeclaration = CreateVertexDeclarationWithoutAddRef(reinterpret_cast(unoptimizedVertexElements)); + auto sparkleVertexDeclaration = CreateVertexDeclarationWithoutAddRef(reinterpret_cast(g_memory.Translate(0x8211F540))); + + bool isMeshShader = strstr(shaderList->m_TypeAndName.c_str(), "Mesh") != nullptr; + + PipelineState pipelineState{}; + pipelineState.vertexShader = reinterpret_cast(noneFindResult->second->m_VertexShaders.begin()->second->m_spCode->m_pD3DVertexShader.get()); + pipelineState.pixelShader = reinterpret_cast(defaultFindResult->second.m_PixelShaders.begin()->second->m_spCode->m_pD3DPixelShader.get()); + pipelineState.vertexDeclaration = isMeshShader ? unoptimizedVertexDeclaration : sparkleVertexDeclaration; + pipelineState.zWriteEnable = false; + pipelineState.srcBlend = RenderBlend::SRC_ALPHA; + pipelineState.destBlend = RenderBlend::INV_SRC_ALPHA; + pipelineState.zFunc = RenderComparisonFunction::GREATER_EQUAL; + pipelineState.alphaBlendEnable = true; + pipelineState.srcBlendAlpha = RenderBlend::SRC_ALPHA; + pipelineState.destBlendAlpha = RenderBlend::INV_SRC_ALPHA; + pipelineState.primitiveTopology = RenderPrimitiveTopology::TRIANGLE_STRIP; + pipelineState.vertexStrides[0] = isMeshShader ? 104 : 28; + pipelineState.renderTargetFormat = RenderFormat::R16G16B16A16_FLOAT; + pipelineState.depthStencilFormat = RenderFormat::D32_FLOAT; + pipelineState.sampleCount = Config::MSAA > 1 ? Config::MSAA : 1; + pipelineState.specConstants = SPEC_CONSTANT_REVERSE_Z; + + if (pipelineState.vertexDeclaration->hasR11G11B10Normal) + pipelineState.specConstants |= SPEC_CONSTANT_R11G11B10_NORMAL; + + switch (material.m_BlendMode.get()) + { + case Hedgehog::Sparkle::CParticleMaterial::eBlendMode_Zero: + // TODO: What are the render states for this?? + break; + case Hedgehog::Sparkle::CParticleMaterial::eBlendMode_Typical: + // Leave default. + break; + case Hedgehog::Sparkle::CParticleMaterial::eBlendMode_Add: + pipelineState.destBlend = RenderBlend::ONE; + break; + case Hedgehog::Sparkle::CParticleMaterial::eBlendMode_Subtract: + // TODO: Is this correct? + pipelineState.destBlend = RenderBlend::ONE; + pipelineState.blendOp = RenderBlendOperation::SUBTRACT; + break; + } + + auto createGraphicsPipeline = [&](PipelineState& pipelineStateToCreate) + { + SanitizePipelineState(pipelineStateToCreate); + EnqueueGraphicsPipelineCompilation(pipelineStateToCreate, holderPair, shaderList->m_TypeAndName.c_str() + 3); + }; + + // TODO: See if this is necessary for everything. + RenderCullMode cullModes[] = { RenderCullMode::NONE, RenderCullMode::BACK }; + + for (auto cullMode : cullModes) + { + pipelineState.cullMode = cullMode; + createGraphicsPipeline(pipelineState); + + bool planarReflectionEnabled = reinterpret_cast(g_memory.Translate(0x832FA0D8)); + + auto noMsaaPipelineState = pipelineState; + noMsaaPipelineState.sampleCount = 1; + + if (planarReflectionEnabled) + createGraphicsPipeline(noMsaaPipelineState); + + if (!isMeshShader) + { + // Previous compilation was for locus particles. This one will be for quads. + auto quadPipelineState = pipelineState; + quadPipelineState.primitiveTopology = RenderPrimitiveTopology::TRIANGLE_LIST; + createGraphicsPipeline(quadPipelineState); + + if (planarReflectionEnabled) + { + auto noMsaaQuadPipelineState = noMsaaPipelineState; + noMsaaQuadPipelineState.primitiveTopology = RenderPrimitiveTopology::TRIANGLE_LIST; + createGraphicsPipeline(noMsaaQuadPipelineState); + } + } + } +} + +// SWA::CGameModeStage::ExitLoading +PPC_FUNC_IMPL(__imp__sub_825369A0); +PPC_FUNC(sub_825369A0) +{ + // Wait for pipeline compilations to finish. + uint32_t value; + while ((value = g_compilingDataCount.load()) != 0) + g_compilingDataCount.wait(value); + + __imp__sub_825369A0(ctx, base); +} + +// CModelData::CheckMadeAll +PPC_FUNC_IMPL(__imp__sub_82E2EFB0); +PPC_FUNC(sub_82E2EFB0) +{ + if (reinterpret_cast(base + ctx.r3.u32)->m_Flags & eDatabaseDataFlags_CompilingPipelines) + { + ctx.r3.u64 = 0; + } + else + { + __imp__sub_82E2EFB0(ctx, base); + } +} + +// CTerrainModelData::CheckMadeAll +PPC_FUNC_IMPL(__imp__sub_82E243D8); +PPC_FUNC(sub_82E243D8) +{ + if (reinterpret_cast(base + ctx.r3.u32)->m_Flags & eDatabaseDataFlags_CompilingPipelines) + { + ctx.r3.u64 = 0; + } + else + { + __imp__sub_82E243D8(ctx, base); + } +} + +// CParticleMaterial::CheckMadeAll +PPC_FUNC_IMPL(__imp__sub_82E87598); +PPC_FUNC(sub_82E87598) +{ + if (reinterpret_cast(base + ctx.r3.u32)->m_Flags & eDatabaseDataFlags_CompilingPipelines) + { + ctx.r3.u64 = 0; + } + else + { + __imp__sub_82E87598(ctx, base); + } +} + +static Mutex g_pendingModelMutex; +static std::vector> g_pendingDataQueue; + +void GetDatabaseDataMidAsmHook(PPCRegister& r1, PPCRegister& r4) +{ + auto& databaseData = *reinterpret_cast*>( + g_memory.Translate(r1.u32 + 0x58)); + + if (!databaseData->IsMadeOne() && r4.u32 != NULL) + { + if (databaseData->m_pVftable.ptr == MODEL_DATA_VFTABLE) + { + // Ignore particle models, the materials they point at don't actually + // get used and give the threads unnecessary work. + bool isParticleModel = *reinterpret_cast*>(g_memory.Translate(r4.u32 + 4)) != 5 && + strncmp(databaseData->m_TypeAndName.c_str() + 2, "eff_", 4) == 0; + + if (isParticleModel) + return; + } + + ++g_compilingDataCount; + databaseData->m_Flags |= eDatabaseDataFlags_CompilingPipelines; + + { + std::lock_guard lock(g_pendingModelMutex); + g_pendingDataQueue.push_back(databaseData); + } + + if ((++g_pendingDataCount) == 1) + g_pendingDataCount.notify_all(); + } +} + +static bool CheckMadeAll(Hedgehog::Mirage::CMeshData* meshData) +{ + if (!meshData->IsMadeOne()) + return false; + + if (meshData->m_spMaterial.get() != nullptr) + { + if (!meshData->m_spMaterial->IsMadeOne()) + return false; + + if (meshData->m_spMaterial->m_spTexsetData.get() != nullptr) + { + if (!meshData->m_spMaterial->m_spTexsetData->IsMadeOne()) + return false; + + for (auto& texture : meshData->m_spMaterial->m_spTexsetData->m_TextureList) + { + if (!texture->IsMadeOne()) + return false; + } + } + } + + return true; +} + +template +static bool CheckMadeAll(const T& modelData) +{ + if (!modelData.IsMadeOne()) + return false; + + for (auto& meshGroup : modelData.m_NodeGroupModels) + { + for (auto& mesh : meshGroup->m_OpaqueMeshes) + { + if (!CheckMadeAll(mesh.get())) + return false; + } + + for (auto& mesh : meshGroup->m_TransparentMeshes) + { + if (!CheckMadeAll(mesh.get())) + return false; + } + + for (auto& mesh : meshGroup->m_PunchThroughMeshes) + { + if (!CheckMadeAll(mesh.get())) + return false; + } + + for (auto& specialMeshGroup : meshGroup->m_SpecialMeshGroups) + { + for (auto& mesh : specialMeshGroup) + { + if (!CheckMadeAll(mesh.get())) + return false; + } + } + } + + for (auto& mesh : modelData.m_OpaqueMeshes) + { + if (!CheckMadeAll(mesh.get())) + return false; + } + + for (auto& mesh : modelData.m_TransparentMeshes) + { + if (!CheckMadeAll(mesh.get())) + return false; + } + + for (auto& mesh : modelData.m_PunchThroughMeshes) + { + if (!CheckMadeAll(mesh.get())) + return false; + } + + return true; +} + +static void ModelConsumerThread() +{ + GuestThread::SetThreadName(GetCurrentThreadId(), "Model Consumer Thread"); + + std::vector> localPendingDataQueue; + MinimalGuestThreadContext ctx; + + while (true) + { + // Wait for models to arrive. + uint32_t pendingDataCount; + while ((pendingDataCount = g_pendingDataCount.load()) == 0) + g_pendingDataCount.wait(pendingDataCount); + + ctx.ensureValid(); + + if (g_pendingPipelineStateCache) + { + DatabaseDataHolderPair emptyHolderPair; + + for (auto vertexElements : g_vertexDeclarationCache) + CreateVertexDeclarationWithoutAddRef(reinterpret_cast(vertexElements)); + + for (auto pipelineState : g_pipelineStateCache) + { + // The hashes were reinterpret casted to pointers in the cache. + pipelineState.vertexShader = FindShaderCacheEntry(reinterpret_cast(pipelineState.vertexShader))->guestShader; + + if (pipelineState.pixelShader != nullptr) + pipelineState.pixelShader = FindShaderCacheEntry(reinterpret_cast(pipelineState.pixelShader))->guestShader; + + { + std::lock_guard lock(g_vertexDeclarationMutex); + pipelineState.vertexDeclaration = g_vertexDeclarations[reinterpret_cast(pipelineState.vertexDeclaration)]; + } + + if (Config::GITextureFiltering == EGITextureFiltering::Bicubic) + pipelineState.specConstants |= SPEC_CONSTANT_BICUBIC_GI_FILTER; + + // Compile both MSAA and non MSAA variants to work with reflection maps. The render formats are an assumption but it should hold true. + if (Config::MSAA > 1 && + pipelineState.renderTargetFormat == RenderFormat::R16G16B16A16_FLOAT && + pipelineState.depthStencilFormat == RenderFormat::D32_FLOAT) + { + auto msaaPipelineState = pipelineState; + msaaPipelineState.sampleCount = Config::MSAA; + + if (Config::AlphaToCoverage && (msaaPipelineState.specConstants & SPEC_CONSTANT_ALPHA_TEST) != 0) + { + msaaPipelineState.enableAlphaToCoverage = true; + msaaPipelineState.specConstants &= ~SPEC_CONSTANT_ALPHA_TEST; + msaaPipelineState.specConstants |= SPEC_CONSTANT_ALPHA_TO_COVERAGE; + } + + SanitizePipelineState(msaaPipelineState); + EnqueueGraphicsPipelineCompilation(msaaPipelineState, emptyHolderPair, "Precompiled Pipeline MSAA"); + } + + SanitizePipelineState(pipelineState); + EnqueueGraphicsPipelineCompilation(pipelineState, emptyHolderPair, "Precompiled Pipeline"); + } + + g_pendingPipelineStateCache = false; + --g_pendingDataCount; + + if ((--g_compilingDataCount) == 0) + g_compilingDataCount.notify_all(); + } + + { + std::lock_guard lock(g_pendingModelMutex); + localPendingDataQueue.insert(localPendingDataQueue.end(), g_pendingDataQueue.begin(), g_pendingDataQueue.end()); + g_pendingDataQueue.clear(); + } + + bool allHandled = true; + + for (auto& pendingData : localPendingDataQueue) + { + if (pendingData.get() != nullptr) + { + bool ready = false; + + if (pendingData->m_pVftable.ptr == MODEL_DATA_VFTABLE) + ready = CheckMadeAll(*reinterpret_cast(pendingData.get())); + else + ready = pendingData->IsMadeOne(); + + if (ready || pendingData.unique()) + { + if (pendingData->m_pVftable.ptr == TERRAIN_MODEL_DATA_VFTABLE) + { + CompilationArgs args{}; + args.holderPair.holder.databaseData = pendingData; + CompileMeshPipelines(*reinterpret_cast(pendingData.get()), args); + } + else if (pendingData->m_pVftable.ptr == PARTICLE_MATERIAL_VFTABLE) + { + DatabaseDataHolderPair holderPair; + holderPair.holder.databaseData = pendingData; + CompileParticleMaterialPipeline(*reinterpret_cast(pendingData.get()), holderPair); + } + else + { + assert(pendingData->m_pVftable.ptr == MODEL_DATA_VFTABLE); + + auto modelData = reinterpret_cast(pendingData.get()); + + CompilationArgs args{}; + args.holderPair.holder.databaseData = pendingData; + args.noGI = true; + args.hasMoreThanOneBone = modelData->m_NodeNum > 1; + args.velocityMapQuickStep = strcmp(pendingData->m_TypeAndName.c_str() + 2, "SonicRoot") == 0; + + // Check for the on screen items, eg. rings going to HUD. + auto items = reinterpret_cast*>(g_memory.Translate(0x832A8DD0)); + for (size_t i = 0; i < 50; i++) + { + if (strcmp(pendingData->m_TypeAndName.c_str() + 2, (*items).get()) == 0) + { + args.objectIcon = true; + break; + } + items += 7; + } + + CompileMeshPipelines(*modelData, args); + } + + pendingData = nullptr; + --g_pendingDataCount; + } + else + { + allHandled = false; + } + } + } + + if (allHandled) + localPendingDataQueue.clear(); + } +} + +static std::thread g_modelConsumerThread(ModelConsumerThread); + +#ifdef ASYNC_PSO_DEBUG + +PPC_FUNC_IMPL(__imp__sub_82E33330); +PPC_FUNC(sub_82E33330) +{ + auto vertexShaderCode = reinterpret_cast(g_memory.Translate(ctx.r4.u32)); + __imp__sub_82E33330(ctx, base); + reinterpret_cast(vertexShaderCode->m_pD3DVertexShader.get())->name = vertexShaderCode->m_TypeAndName.c_str() + 3; +} + +PPC_FUNC_IMPL(__imp__sub_82E328D8); +PPC_FUNC(sub_82E328D8) +{ + auto pixelShaderCode = reinterpret_cast(g_memory.Translate(ctx.r4.u32)); + __imp__sub_82E328D8(ctx, base); + reinterpret_cast(pixelShaderCode->m_pD3DPixelShader.get())->name = pixelShaderCode->m_TypeAndName.c_str() + 2; +} + +#endif + +#ifdef PSO_CACHING +class SDLEventListenerForPSOCaching : public SDLEventListener +{ +public: + void OnSDLEvent(SDL_Event* event) override + { + if (event->type != SDL_QUIT) + return; + + std::lock_guard lock(g_pipelineCacheMutex); + if (g_pipelineStatesToCache.empty()) + return; + + FILE* f = fopen("send_this_file_to_skyth.txt", "ab"); + if (f != nullptr) + { + ankerl::unordered_dense::set vertexDeclarations; + xxHashMap pipelineStatesToCache; + + for (auto& pipelineState : g_pipelineStatesToCache) + { + if (pipelineState.vertexShader->shaderCacheEntry == nullptr || + (pipelineState.pixelShader != nullptr && pipelineState.pixelShader->shaderCacheEntry == nullptr)) + { + continue; + } + + vertexDeclarations.emplace(pipelineState.vertexDeclaration); + + // Mask out the config options. + pipelineState.sampleCount = 1; + pipelineState.enableAlphaToCoverage = false; + + pipelineState.specConstants &= ~SPEC_CONSTANT_BICUBIC_GI_FILTER; + if ((pipelineState.specConstants & SPEC_CONSTANT_ALPHA_TO_COVERAGE) != 0) + { + pipelineState.specConstants &= ~SPEC_CONSTANT_ALPHA_TO_COVERAGE; + pipelineState.specConstants |= SPEC_CONSTANT_ALPHA_TEST; + } + + pipelineStatesToCache.emplace(XXH3_64bits(&pipelineState, sizeof(pipelineState)), pipelineState); + } + + for (auto vertexDeclaration : vertexDeclarations) + { + std::print(f, "static uint8_t g_vertexElements_{:016X}[] = {{", vertexDeclaration->hash); + + auto bytes = reinterpret_cast(vertexDeclaration->vertexElements.get()); + for (size_t i = 0; i < vertexDeclaration->vertexElementCount * sizeof(GuestVertexElement); i++) + std::print(f, "0x{:X},", bytes[i]); + + std::println(f, "}};"); + } + + for (auto& [pipelineHash, pipelineState] : pipelineStatesToCache) + { + std::println(f, "{{ " + "reinterpret_cast(0x{:X})," + "reinterpret_cast(0x{:X})," + "reinterpret_cast(0x{:X})," + "{}," + "{}," + "{}," + "RenderBlend::{}," + "RenderBlend::{}," + "RenderCullMode::{}," + "RenderComparisonFunction::{}," + "{}," + "RenderBlendOperation::{}," + "{}," + "{}," + "RenderBlend::{}," + "RenderBlend::{}," + "RenderBlendOperation::{}," + "0x{:X}," + "RenderPrimitiveTopology::{}," + "{{ {},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{} }}," + "RenderFormat::{}," + "RenderFormat::{}," + "{}," + "{}," + "0x{:X} }},", + pipelineState.vertexShader->shaderCacheEntry->hash, + pipelineState.pixelShader != nullptr ? pipelineState.pixelShader->shaderCacheEntry->hash : 0, + pipelineState.vertexDeclaration->hash, + pipelineState.instancing, + pipelineState.zEnable, + pipelineState.zWriteEnable, + magic_enum::enum_name(pipelineState.srcBlend), + magic_enum::enum_name(pipelineState.destBlend), + magic_enum::enum_name(pipelineState.cullMode), + magic_enum::enum_name(pipelineState.zFunc), + pipelineState.alphaBlendEnable, + magic_enum::enum_name(pipelineState.blendOp), + pipelineState.slopeScaledDepthBias, + pipelineState.depthBias, + magic_enum::enum_name(pipelineState.srcBlendAlpha), + magic_enum::enum_name(pipelineState.destBlendAlpha), + magic_enum::enum_name(pipelineState.blendOpAlpha), + pipelineState.colorWriteEnable, + magic_enum::enum_name(pipelineState.primitiveTopology), + pipelineState.vertexStrides[0], + pipelineState.vertexStrides[1], + pipelineState.vertexStrides[2], + pipelineState.vertexStrides[3], + pipelineState.vertexStrides[4], + pipelineState.vertexStrides[5], + pipelineState.vertexStrides[6], + pipelineState.vertexStrides[7], + pipelineState.vertexStrides[8], + pipelineState.vertexStrides[9], + pipelineState.vertexStrides[10], + pipelineState.vertexStrides[11], + pipelineState.vertexStrides[12], + pipelineState.vertexStrides[13], + pipelineState.vertexStrides[14], + pipelineState.vertexStrides[15], + magic_enum::enum_name(pipelineState.renderTargetFormat), + magic_enum::enum_name(pipelineState.depthStencilFormat), + pipelineState.sampleCount, + pipelineState.enableAlphaToCoverage, + pipelineState.specConstants); + } + + fclose(f); + } + } +}; +SDLEventListenerForPSOCaching g_sdlEventListenerForPSOCaching; +#endif + GUEST_FUNCTION_HOOK(sub_82BD99B0, CreateDevice); GUEST_FUNCTION_HOOK(sub_82BE6230, DestructResource); diff --git a/UnleashedRecomp/gpu/video.h b/UnleashedRecomp/gpu/video.h index 4b1b512b..90b14411 100644 --- a/UnleashedRecomp/gpu/video.h +++ b/UnleashedRecomp/gpu/video.h @@ -1,5 +1,8 @@ #pragma once +//#define ASYNC_PSO_DEBUG +#define PSO_CACHING + #include "rhi/rt64_render_interface.h" #define D3DCLEAR_TARGET 0x1 @@ -78,6 +81,19 @@ struct GuestResource incrementedValue = std::byteswap(std::byteswap(originalValue) + 1); } while (InterlockedCompareExchange(reinterpret_cast(&refCount), incrementedValue, originalValue) != originalValue); } + + void Release() + { + uint32_t originalValue, decrementedValue; + do + { + originalValue = refCount.value; + decrementedValue = std::byteswap(std::byteswap(originalValue) - 1); + } while (InterlockedCompareExchange(reinterpret_cast(&refCount), decrementedValue, originalValue) != originalValue); + + // Normally we are supposed to release here, so only use this + // function when you know you won't be the one destructing it. + } }; enum GuestFormat @@ -226,27 +242,32 @@ struct GuestVertexElement uint8_t padding; }; -enum InputLayoutFlags -{ - INPUT_LAYOUT_FLAG_HAS_R11G11B10_NORMAL = 1 << 0, - INPUT_LAYOUT_FLAG_HAS_BONE_WEIGHTS = 1 << 1 -}; +#define D3DDECL_END() { 255, 0, 0xFFFFFFFF, 0, 0, 0 } struct GuestVertexDeclaration : GuestResource { + XXH64_hash_t hash = 0; std::unique_ptr inputElements; std::unique_ptr vertexElements; uint32_t inputElementCount = 0; uint32_t vertexElementCount = 0; uint32_t swappedTexcoords = 0; - uint32_t inputLayoutFlags = 0; + bool hasR11G11B10Normal = false; uint32_t indexVertexStream = 0; }; // VertexShader/PixelShader struct GuestShader : GuestResource { + Mutex mutex; std::unique_ptr shader; + struct ShaderCacheEntry* shaderCacheEntry = nullptr; + ankerl::unordered_dense::map> linkedShaders; + std::vector> shaderBlobs; + ComPtr libraryBlob; +#ifdef ASYNC_PSO_DEBUG + const char* name = ""; +#endif }; struct GuestViewport diff --git a/UnleashedRecomp/natvis.natvis b/UnleashedRecomp/natvis.natvis new file mode 100644 index 00000000..f55dca1d --- /dev/null +++ b/UnleashedRecomp/natvis.natvis @@ -0,0 +1,21 @@ + + + + {get()} + + get() + + + + {get()} + + get() + + + + {get()} + + get() + + + diff --git a/UnleashedRecomp/stdafx.h b/UnleashedRecomp/stdafx.h index f23df682..8fd5bb22 100644 --- a/UnleashedRecomp/stdafx.h +++ b/UnleashedRecomp/stdafx.h @@ -3,6 +3,7 @@ #define NOMINMAX #include +#include #include #include #include @@ -28,6 +29,11 @@ #include #include #include +#include +#include +#include + +using Microsoft::WRL::ComPtr; #include "framework.h" #include "mutex.h" diff --git a/UnleashedRecomp/ui/window.cpp b/UnleashedRecomp/ui/window.cpp index 2df75973..304b93ee 100644 --- a/UnleashedRecomp/ui/window.cpp +++ b/UnleashedRecomp/ui/window.cpp @@ -10,6 +10,9 @@ int Window_OnSDLEvent(void*, SDL_Event* event) if (ImGui::GetIO().BackendPlatformUserData != nullptr) ImGui_ImplSDL2_ProcessEvent(event); + for (auto listener : Window::s_eventListeners) + listener->OnSDLEvent(event); + switch (event->type) { case SDL_QUIT: @@ -114,9 +117,6 @@ int Window_OnSDLEvent(void*, SDL_Event* event) } } - for (auto listener : Window::s_eventListeners) - listener->OnSDLEvent(event); - return 0; } diff --git a/UnleashedRecompLib/CMakeLists.txt b/UnleashedRecompLib/CMakeLists.txt index 6db04470..21ea8609 100644 --- a/UnleashedRecompLib/CMakeLists.txt +++ b/UnleashedRecompLib/CMakeLists.txt @@ -26,7 +26,7 @@ add_custom_command( ) set(SHADER_RECOMP_ROOT "${SWA_THIRDPARTY_ROOT}/ShaderRecomp/ShaderRecomp") -set(SHADER_RECOMP_INCLUDE "${SHADER_RECOMP_ROOT}/shader_common.hlsli") +set(SHADER_RECOMP_INCLUDE "${SHADER_RECOMP_ROOT}/shader_common.h") target_compile_definitions(ShaderRecomp PRIVATE SHADER_RECOMP_INPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/private\" diff --git a/UnleashedRecompLib/config/SWA.toml b/UnleashedRecompLib/config/SWA.toml index e154e37b..0e2e975e 100644 --- a/UnleashedRecompLib/config/SWA.toml +++ b/UnleashedRecompLib/config/SWA.toml @@ -422,3 +422,28 @@ registers = ["r7"] name = "LoadingScreenSpeedFixMidAsmHook" address = 0x824DAB60 registers = ["r4"] + +[[midasm_hook]] +name = "MotionBlurPrevInvViewProjectionMidAsmHook" +address = 0x82BA9E7C +registers = ["r10"] + +[[midasm_hook]] +name = "GetDatabaseDataMidAsmHook" +address = 0x82E38688 # Model +registers = ["r1", "r31"] + +[[midasm_hook]] +name = "GetDatabaseDataMidAsmHook" +address = 0x82E39650 # Terrain Model +registers = ["r1", "r31"] + +[[midasm_hook]] +name = "GetDatabaseDataMidAsmHook" +address = 0x827D614C # Particle Material Binary +registers = ["r1", "r29"] + +[[midasm_hook]] +name = "GetDatabaseDataMidAsmHook" +address = 0x827D6018 # Particle Material XML +registers = ["r1", "r30"] diff --git a/UnleashedRecompLib/shader/shader_cache.h b/UnleashedRecompLib/shader/shader_cache.h index dd3f671e..43439403 100644 --- a/UnleashedRecompLib/shader/shader_cache.h +++ b/UnleashedRecompLib/shader/shader_cache.h @@ -7,7 +7,8 @@ struct ShaderCacheEntry const uint32_t dxilSize; const uint32_t spirvOffset; const uint32_t spirvSize; - void* userData; + const uint32_t specConstantsMask; + struct GuestShader* guestShader; }; extern ShaderCacheEntry g_shaderCacheEntries[]; diff --git a/thirdparty/ShaderRecomp b/thirdparty/ShaderRecomp index 30f59860..f936ed22 160000 --- a/thirdparty/ShaderRecomp +++ b/thirdparty/ShaderRecomp @@ -1 +1 @@ -Subproject commit 30f598604767602e3afce56b947e99dba2b51211 +Subproject commit f936ed2212d8291439003eb0c0d8edc0ecafd24d diff --git a/vcpkg.json b/vcpkg.json index 46ee79ad..85e32c2d 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -19,6 +19,7 @@ { "name": "imgui", "features": [ "sdl2-binding" ] - } + }, + "magic-enum" ] } From 3215e472798831f63b280d58c1a22549096480ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dar=C3=ADo?= Date: Fri, 29 Nov 2024 17:47:30 -0300 Subject: [PATCH 5/8] Implement installer with support for ISO, STFS and SVOD. Also implement XEX Patcher. (#5) --- .gitmodules | 3 + UnleashedRecomp/CMakeLists.txt | 33 +- .../install/directory_file_system.h | 65 + .../install/hashes/apotos_shamar.cpp | 297 + .../install/hashes/apotos_shamar.h | 10 + UnleashedRecomp/install/hashes/chunnan.cpp | 211 + UnleashedRecomp/install/hashes/chunnan.h | 10 + .../install/hashes/empire_city_adabat.cpp | 301 + .../install/hashes/empire_city_adabat.h | 10 + UnleashedRecomp/install/hashes/game.cpp | 8436 +++++++++++++++++ UnleashedRecomp/install/hashes/game.h | 10 + UnleashedRecomp/install/hashes/holoska.cpp | 198 + UnleashedRecomp/install/hashes/holoska.h | 10 + UnleashedRecomp/install/hashes/mazuri.cpp | 207 + UnleashedRecomp/install/hashes/mazuri.h | 10 + UnleashedRecomp/install/hashes/spagonia.cpp | 207 + UnleashedRecomp/install/hashes/spagonia.h | 10 + UnleashedRecomp/install/hashes/update.cpp | 89 + UnleashedRecomp/install/hashes/update.h | 10 + UnleashedRecomp/install/installer.cpp | 492 + UnleashedRecomp/install/installer.h | 76 + UnleashedRecomp/install/iso_file_system.cpp | 191 + UnleashedRecomp/install/iso_file_system.h | 33 + .../install/memory_mapped_file.cpp | 169 + UnleashedRecomp/install/memory_mapped_file.h | 32 + UnleashedRecomp/install/virtual_file_system.h | 24 + .../install/xcontent_file_system.cpp | 641 ++ .../install/xcontent_file_system.h | 61 + UnleashedRecomp/install/xex_patcher.cpp | 693 ++ UnleashedRecomp/install/xex_patcher.h | 35 + UnleashedRecomp/main.cpp | 17 +- thirdparty/CMakeLists.txt | 5 +- thirdparty/PowerRecomp | 2 +- thirdparty/ShaderRecomp | 2 +- thirdparty/TinySHA1/TinySHA1.hpp | 223 + thirdparty/fshasher/CMakeLists.txt | 7 + thirdparty/fshasher/fshasher.cpp | 203 + thirdparty/fshasher/plainargs.h | 147 + thirdparty/libmspack | 1 + vcpkg.json | 1 + 40 files changed, 13171 insertions(+), 11 deletions(-) create mode 100644 UnleashedRecomp/install/directory_file_system.h create mode 100644 UnleashedRecomp/install/hashes/apotos_shamar.cpp create mode 100644 UnleashedRecomp/install/hashes/apotos_shamar.h create mode 100644 UnleashedRecomp/install/hashes/chunnan.cpp create mode 100644 UnleashedRecomp/install/hashes/chunnan.h create mode 100644 UnleashedRecomp/install/hashes/empire_city_adabat.cpp create mode 100644 UnleashedRecomp/install/hashes/empire_city_adabat.h create mode 100644 UnleashedRecomp/install/hashes/game.cpp create mode 100644 UnleashedRecomp/install/hashes/game.h create mode 100644 UnleashedRecomp/install/hashes/holoska.cpp create mode 100644 UnleashedRecomp/install/hashes/holoska.h create mode 100644 UnleashedRecomp/install/hashes/mazuri.cpp create mode 100644 UnleashedRecomp/install/hashes/mazuri.h create mode 100644 UnleashedRecomp/install/hashes/spagonia.cpp create mode 100644 UnleashedRecomp/install/hashes/spagonia.h create mode 100644 UnleashedRecomp/install/hashes/update.cpp create mode 100644 UnleashedRecomp/install/hashes/update.h create mode 100644 UnleashedRecomp/install/installer.cpp create mode 100644 UnleashedRecomp/install/installer.h create mode 100644 UnleashedRecomp/install/iso_file_system.cpp create mode 100644 UnleashedRecomp/install/iso_file_system.h create mode 100644 UnleashedRecomp/install/memory_mapped_file.cpp create mode 100644 UnleashedRecomp/install/memory_mapped_file.h create mode 100644 UnleashedRecomp/install/virtual_file_system.h create mode 100644 UnleashedRecomp/install/xcontent_file_system.cpp create mode 100644 UnleashedRecomp/install/xcontent_file_system.h create mode 100644 UnleashedRecomp/install/xex_patcher.cpp create mode 100644 UnleashedRecomp/install/xex_patcher.h create mode 100644 thirdparty/TinySHA1/TinySHA1.hpp create mode 100644 thirdparty/fshasher/CMakeLists.txt create mode 100644 thirdparty/fshasher/fshasher.cpp create mode 100644 thirdparty/fshasher/plainargs.h create mode 160000 thirdparty/libmspack diff --git a/.gitmodules b/.gitmodules index 11693b91..df7c0a6b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "thirdparty/ShaderRecomp"] path = thirdparty/ShaderRecomp url = https://github.com/hedge-dev/ShaderRecomp.git +[submodule "thirdparty/libmspack"] + path = thirdparty/libmspack + url = https://github.com/kyz/libmspack diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 75512991..f736fbea 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -79,6 +79,30 @@ set(SWA_UI_CXX_SOURCES "ui/window.cpp" ) +set(SWA_INSTALL_CXX_SOURCES + "install/installer.cpp" + "install/iso_file_system.cpp" + "install/memory_mapped_file.cpp" + "install/xcontent_file_system.cpp" + "install/xex_patcher.cpp" + "install/hashes/apotos_shamar.cpp" + "install/hashes/chunnan.cpp" + "install/hashes/empire_city_adabat.cpp" + "install/hashes/game.cpp" + "install/hashes/holoska.cpp" + "install/hashes/mazuri.cpp" + "install/hashes/spagonia.cpp" + "install/hashes/update.cpp" +) + +set(LIBMSPACK_PATH ${SWA_THIRDPARTY_ROOT}/libmspack/libmspack/mspack) + +set(LIBMSPACK_C_SOURCES + ${LIBMSPACK_PATH}/lzxd.c +) + +set_source_files_properties(${LIBMSPACK_C_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON) + set(SMOLV_SOURCE_DIR "${SWA_THIRDPARTY_ROOT}/ShaderRecomp/thirdparty/smol-v/source") set(SWA_CXX_SOURCES @@ -95,7 +119,8 @@ set(SWA_CXX_SOURCES ${SWA_HID_CXX_SOURCES} ${SWA_PATCHES_CXX_SOURCES} ${SWA_UI_CXX_SOURCES} - + ${SWA_INSTALL_CXX_SOURCES} + ${LIBMSPACK_C_SOURCES} "${SMOLV_SOURCE_DIR}/smolv.cpp" ) @@ -127,6 +152,7 @@ find_package(Stb REQUIRED) find_package(unofficial-concurrentqueue REQUIRED) find_package(imgui CONFIG REQUIRED) find_package(magic_enum CONFIG REQUIRED) +find_package(unofficial-tiny-aes-c CONFIG REQUIRED) file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12) add_custom_command(TARGET UnleashedRecomp POST_BUILD @@ -163,12 +189,15 @@ target_link_libraries(UnleashedRecomp PRIVATE Synchronization imgui::imgui magic_enum::magic_enum + unofficial::tiny-aes-c::tiny-aes-c ) target_include_directories(UnleashedRecomp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/api - ${SWA_THIRDPARTY_ROOT}/ddspp + ${SWA_THIRDPARTY_ROOT}/ddspp + ${SWA_THIRDPARTY_ROOT}/TinySHA1 + ${LIBMSPACK_PATH} ${Stb_INCLUDE_DIR} ${SMOLV_SOURCE_DIR} ) diff --git a/UnleashedRecomp/install/directory_file_system.h b/UnleashedRecomp/install/directory_file_system.h new file mode 100644 index 00000000..3dadca6b --- /dev/null +++ b/UnleashedRecomp/install/directory_file_system.h @@ -0,0 +1,65 @@ +#pragma once + +#include + +#include "virtual_file_system.h" + +struct DirectoryFileSystem : VirtualFileSystem +{ + std::filesystem::path directoryPath; + + DirectoryFileSystem(const std::filesystem::path &directoryPath) + { + this->directoryPath = directoryPath; + } + + bool load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const override + { + std::ifstream fileStream(directoryPath / std::filesystem::path(std::u8string_view((const char8_t *)(path.c_str()))), std::ios::binary); + if (fileStream.is_open()) + { + fileStream.read((char *)(fileData), fileDataMaxByteCount); + return !fileStream.bad(); + } + else + { + return false; + } + } + + size_t getSize(const std::string &path) const override + { + std::error_code ec; + size_t fileSize = std::filesystem::file_size(directoryPath / std::filesystem::path(std::u8string_view((const char8_t *)(path.c_str()))), ec); + if (!ec) + { + return fileSize; + } + else + { + return 0; + } + } + + bool exists(const std::string &path) const override + { + if (path.empty()) + { + return false; + } + + return std::filesystem::exists(directoryPath / std::filesystem::path(std::u8string_view((const char8_t *)(path.c_str())))); + } + + static std::unique_ptr create(const std::filesystem::path &directoryPath) + { + if (std::filesystem::exists(directoryPath)) + { + return std::make_unique(directoryPath); + } + else + { + return nullptr; + } + } +}; diff --git a/UnleashedRecomp/install/hashes/apotos_shamar.cpp b/UnleashedRecomp/install/hashes/apotos_shamar.cpp new file mode 100644 index 00000000..2cbab1d8 --- /dev/null +++ b/UnleashedRecomp/install/hashes/apotos_shamar.cpp @@ -0,0 +1,297 @@ +// File automatically generated by fshasher + +#include + +extern const uint64_t ApotosShamarHashes[]; +extern const std::pair ApotosShamarFiles[]; +extern const size_t ApotosShamarFilesSize; + +const uint64_t ApotosShamarHashes[] = { + 5161782899687054855ULL, + 10848638096963692019ULL, + 9473129523580090227ULL, + 14507476319569850326ULL, + 7984304958810014204ULL, + 17285119940264119717ULL, + 2388648365684266872ULL, + 7072117265505496768ULL, + 7300804046379422574ULL, + 11024341213616898389ULL, + 2269719192208918419ULL, + 11277103027538800966ULL, + 3503444980189584178ULL, + 4165664752696059934ULL, + 7145613245284078465ULL, + 8956692682572097337ULL, + 467673557758517075ULL, + 5865394160581371462ULL, + 2388648365684266872ULL, + 7072117265505496768ULL, + 4651933531844120545ULL, + 16366432125719702966ULL, + 6204045984421832366ULL, + 7455071839519300924ULL, + 1601475090088501102ULL, + 6476812967046504881ULL, + 10110818077789761124ULL, + 12473493932267894529ULL, + 192734448958995711ULL, + 4979345902860045881ULL, + 2388648365684266872ULL, + 7072117265505496768ULL, + 7354426500253318588ULL, + 13436608285401838874ULL, + 5455808863724849103ULL, + 13912048957214708709ULL, + 3577115447410096717ULL, + 9167108726914458134ULL, + 269064862329040576ULL, + 13733247789252130917ULL, + 1908075175783995052ULL, + 17569164706309240857ULL, + 2687257361293581496ULL, + 15703575149297583018ULL, + 13596487015352587574ULL, + 15226982905233731417ULL, + 7318040371083150448ULL, + 14626638887488090768ULL, + 1919723919369387380ULL, + 17373239717886557228ULL, + 8218928162239233105ULL, + 12366520936282200873ULL, + 10467517237606579536ULL, + 11504181969379809881ULL, + 913379962765093751ULL, + 13184977455228849096ULL, + 994534313191316773ULL, + 1161598282996799627ULL, + 8028384967928659483ULL, + 9167275059460261476ULL, + 12329170430565474464ULL, + 14614493918698922602ULL, + 8835009808275053059ULL, + 9227869334598201915ULL, + 6637379186446622324ULL, + 9397642730708705852ULL, + 10630484262545617745ULL, + 10797068556411890259ULL, + 6361872786799807915ULL, + 7387444947377556158ULL, + 8230353453873378338ULL, + 12403999963358558507ULL, + 232254748410986870ULL, + 13070561742440061598ULL, + 10958136070207580182ULL, + 15790689719855919515ULL, + 14585362614190785186ULL, + 17761667637871173377ULL, + 9234510757818947078ULL, + 15427471912569301087ULL, + 9320397015075772917ULL, + 5202741620127019351ULL, + 6987027253392466959ULL, + 5818570466966793416ULL, + 11818189498451458264ULL, + 8227907329904191071ULL, + 8485734709208759762ULL, + 7322832926430412082ULL, + 252821791924020792ULL, + 10750524204772481581ULL, + 9618439767240157908ULL, + 6136980604454707359ULL, + 7851876072887711328ULL, + 7126123337902320477ULL, + 16732438051503528656ULL, + 9626404695949647173ULL, + 14630178898376646697ULL, + 18071570395979705668ULL, + 14290188031476453509ULL, + 5082129473071351035ULL, + 226647428045111345ULL, + 11645732680053564481ULL, + 5363987804539005071ULL, + 15998860607353466394ULL, + 9167368126469307383ULL, + 2744550015698589133ULL, + 10260598734212408368ULL, + 2300802232392089767ULL, + 10949176600743863488ULL, + 1118205454506633106ULL, + 5969867951434607877ULL, + 6671314176692954687ULL, + 14530713737956734950ULL, + 2004571052229566869ULL, + 9708958471851417571ULL, + 2142992686316263474ULL, + 7168715241575146342ULL, + 1976917309517312226ULL, + 18038718853485103300ULL, + 7044835724604442413ULL, + 15531130920102660109ULL, + 4462669497430426931ULL, + 13428469011561492337ULL, + 3214238300098346592ULL, + 16176599498653256643ULL, + 5326927580226746490ULL, + 15047534843332950162ULL, + 11636822788287294319ULL, + 12554314680841874379ULL, + 13981752751371535335ULL, + 12254474770223375774ULL, + 7961887113788376965ULL, + 5360854891214543592ULL, + 9184741739495532010ULL, + 1210820029035423219ULL, + 3779694736357686174ULL, + 7289857685129858177ULL, + 17552766072613442781ULL, + 878947465360421687ULL, + 7265659051859092189ULL, + 11427964425552083037ULL, + 12982062630479208399ULL, + 11441566204903265308ULL, + 14705280727085431572ULL, + 455364757374368469ULL, + 5573968245771556687ULL, + 1250381038431950088ULL, + 2410996856079368646ULL, + 5259209343569281884ULL, + 8112015537375387576ULL, + 6878422699214478955ULL, + 8949331867975860441ULL, + 1985690755616441830ULL, + 9351064623690489389ULL, + 8896435929557957139ULL, + 11542596339951462459ULL, + 1985690755616441830ULL, + 9351064623690489389ULL, + 3185071971562944151ULL, + 9949170060646427581ULL, + 3811554303412706475ULL, + 13858258875735338844ULL, + 11056011717482380676ULL, + 16815456012040865536ULL, + 7271530458034274660ULL, + 13079014928873717024ULL, + 5685165921037143623ULL, + 18141751546323874463ULL, + 6983633615275701371ULL, + 13085359633765678358ULL, + 6682199648914577543ULL, + 16715523554730788031ULL, + 9945450437595332438ULL, + 14162527193937280238ULL, + 2442142878432699094ULL, + 9645678184877844291ULL, + 10217667783481469232ULL, + 12548875758281895729ULL, +}; + +const std::pair ApotosShamarFiles[] = { + { "#ActD_SubMykonos_02.ar.00", 2 }, + { "#ActD_SubMykonos_02.arl", 2 }, + { "#ActD_SubMykonos_03.ar.00", 2 }, + { "#ActD_SubMykonos_03.arl", 2 }, + { "#ActD_SubMykonos_04.ar.00", 2 }, + { "#ActD_SubMykonos_04.arl", 2 }, + { "#ActD_SubMykonos_05.ar.00", 2 }, + { "#ActD_SubMykonos_05.arl", 2 }, + { "#ActD_SubMykonos_06.ar.00", 2 }, + { "#ActD_SubMykonos_06.arl", 2 }, + { "#ActD_SubPetra_02.ar.00", 2 }, + { "#ActD_SubPetra_02.arl", 2 }, + { "#ActD_SubPetra_04.ar.00", 2 }, + { "#ActD_SubPetra_04.arl", 2 }, + { "#ActN_SubMykonos_02.ar.00", 2 }, + { "#ActN_SubMykonos_02.arl", 2 }, + { "#ActN_SubMykonos_03.ar.00", 2 }, + { "#ActN_SubMykonos_03.arl", 2 }, + { "#ActN_SubMykonos_04.ar.00", 2 }, + { "#ActN_SubMykonos_04.arl", 2 }, + { "#ActN_SubPetra_02.ar.00", 2 }, + { "#ActN_SubPetra_02.arl", 2 }, + { "#ActN_SubPetra_03.ar.00", 2 }, + { "#ActN_SubPetra_03.arl", 2 }, + { "#Application.ar.00", 2 }, + { "#Application.arl", 2 }, + { "ActD_SubMykonos_02.ar.00", 2 }, + { "ActD_SubMykonos_02.arl", 2 }, + { "ActD_SubPetra_02.ar.00", 2 }, + { "ActD_SubPetra_02.arl", 2 }, + { "ActN_SubMykonos_03.ar.00", 2 }, + { "ActN_SubMykonos_03.arl", 2 }, + { "ActN_SubMykonos_04.ar.00", 2 }, + { "ActN_SubMykonos_04.arl", 2 }, + { "ActN_SubPetra_02.ar.00", 2 }, + { "ActN_SubPetra_02.ar.01", 2 }, + { "ActN_SubPetra_02.arl", 2 }, + { "ActN_SubPetra_03.ar.00", 2 }, + { "ActN_SubPetra_03.arl", 2 }, + { "Additional/ActD_MykonosAct1/Stage-Add.pfd", 1 }, + { "Additional/ActD_MykonosAct2/Stage-Add.pfd", 1 }, + { "Additional/ActD_Petra/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubMykonos_01/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubMykonos_02/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubPetra_01/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubPetra_02/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubPetra_03/Stage-Add.pfd", 1 }, + { "Additional/ActN_MykonosEvil/Stage-Add.pfd", 1 }, + { "Additional/ActN_SubMykonos_01/Stage-Add.pfd", 1 }, + { "Additional/BossPetra/Stage-Add.pfd", 1 }, + { "Additional/Event_M0_06_myk/Stage-Add.pfd", 1 }, + { "Additional/Event_M6_01_temple/Stage-Add.pfd", 1 }, + { "Additional/Event_M8_16_myk/Stage-Add.pfd", 1 }, + { "Additional/ExStageTails1/Stage-Add.pfd", 1 }, + { "Additional/ExStageTails2/Stage-Add.pfd", 1 }, + { "Additional/Town_Mykonos/Stage-Add.pfd", 1 }, + { "Additional/Town_MykonosETF/Stage-Add.pfd", 1 }, + { "Additional/Town_MykonosETF_Night/Stage-Add.pfd", 1 }, + { "Additional/Town_Mykonos_Night/Stage-Add.pfd", 1 }, + { "Additional/Town_PetraCapital/Stage-Add.pfd", 1 }, + { "Additional/Town_PetraCapitalETF/Stage-Add.pfd", 1 }, + { "Additional/Town_PetraCapitalETF_Night/Stage-Add.pfd", 1 }, + { "Additional/Town_PetraCapital_Night/Stage-Add.pfd", 1 }, + { "Additional/Town_PetraLabo/Stage-Add.pfd", 1 }, + { "Additional/Town_PetraLabo_Night/Stage-Add.pfd", 1 }, + { "DLC.xml", 1 }, + { "Languages/English/WorldMap.ar.00", 2 }, + { "Languages/English/WorldMap.arl", 2 }, + { "Languages/French/WorldMap.ar.00", 2 }, + { "Languages/French/WorldMap.arl", 2 }, + { "Languages/German/WorldMap.ar.00", 2 }, + { "Languages/German/WorldMap.arl", 2 }, + { "Languages/Italian/WorldMap.ar.00", 2 }, + { "Languages/Italian/WorldMap.arl", 2 }, + { "Languages/Japanese/WorldMap.ar.00", 2 }, + { "Languages/Japanese/WorldMap.arl", 2 }, + { "Languages/Spanish/WorldMap.ar.00", 2 }, + { "Languages/Spanish/WorldMap.arl", 2 }, + { "Packed/ActD_SubMykonos_02/Stage.pfd", 1 }, + { "Packed/ActD_SubPetra_02/Stage.pfd", 1 }, + { "Packed/ActN_SubPetra_02/Stage.pfd", 1 }, + { "WorldMap.ar.00", 2 }, + { "WorldMap.arl", 2 }, + { "work/ActD_MykonosAct1/Terrain.prm.xml", 2 }, + { "work/ActD_MykonosAct2/Terrain.prm.xml", 2 }, + { "work/ActD_Petra/Terrain.prm.xml", 2 }, + { "work/ActD_SubMykonos_01/Terrain.prm.xml", 2 }, + { "work/ActD_SubPetra_03/Terrain.prm.xml", 2 }, + { "work/ActN_MykonosEvil/Terrain.prm.xml", 2 }, + { "work/ActN_PetraEvil/Terrain.prm.xml", 2 }, + { "work/ActN_SubMykonos_01/Terrain.prm.xml", 2 }, + { "work/Event_M8_16_myk/Terrain.prm.xml", 2 }, + { "work/Event_temple/Terrain.prm.xml", 2 }, + { "work/StaffRoll/Terrain.prm.xml", 2 }, + { "work/Town_Mykonos/Terrain.prm.xml", 2 }, + { "work/Town_MykonosETF/Terrain.prm.xml", 2 }, + { "work/Town_MykonosETF_Night/Terrain.prm.xml", 2 }, + { "work/Town_Mykonos_Night/Terrain.prm.xml", 2 }, + { "work/Town_PetraCapital/Terrain.prm.xml", 2 }, + { "work/Town_PetraCapitalETF/Terrain.prm.xml", 2 }, + { "work/Town_PetraCapitalETF_Night/Terrain.prm.xml", 2 }, + { "work/Town_PetraCapital_Night/Terrain.prm.xml", 2 }, + { "work/Town_PetraLabo/Terrain.prm.xml", 2 }, + { "work/Town_PetraLabo_Night/Terrain.prm.xml", 2 }, +}; + +const size_t ApotosShamarFilesSize = std::size(ApotosShamarFiles); diff --git a/UnleashedRecomp/install/hashes/apotos_shamar.h b/UnleashedRecomp/install/hashes/apotos_shamar.h new file mode 100644 index 00000000..ee371733 --- /dev/null +++ b/UnleashedRecomp/install/hashes/apotos_shamar.h @@ -0,0 +1,10 @@ +// File automatically generated by fshasher + +#pragma once + +#include + +extern const uint64_t ApotosShamarHashes[]; +extern const std::pair ApotosShamarFiles[]; +extern const size_t ApotosShamarFilesSize; + diff --git a/UnleashedRecomp/install/hashes/chunnan.cpp b/UnleashedRecomp/install/hashes/chunnan.cpp new file mode 100644 index 00000000..2c49f464 --- /dev/null +++ b/UnleashedRecomp/install/hashes/chunnan.cpp @@ -0,0 +1,211 @@ +// File automatically generated by fshasher + +#include + +extern const uint64_t ChunnanHashes[]; +extern const std::pair ChunnanFiles[]; +extern const size_t ChunnanFilesSize; + +const uint64_t ChunnanHashes[] = { + 4916287666769501565ULL, + 11970519140178822377ULL, + 1036602527484778521ULL, + 14798433086191189521ULL, + 10646557629458609476ULL, + 10713656744393722857ULL, + 763540214073867667ULL, + 3077520808973995505ULL, + 3650022750694984496ULL, + 17646887566993148783ULL, + 5922433511303640285ULL, + 6042200465914054108ULL, + 10857350734717065794ULL, + 14989231061973888057ULL, + 1039624040955487627ULL, + 14044814300419760090ULL, + 5803112655842355018ULL, + 6547906886493755080ULL, + 2653940158411132556ULL, + 6001214908824901338ULL, + 12495882025135198599ULL, + 12639105290841965223ULL, + 8006441485547456063ULL, + 17680405693218986079ULL, + 787195009054753821ULL, + 6894519290185704169ULL, + 8761940786378535518ULL, + 14409827195925710801ULL, + 9932979175820467217ULL, + 17354914869214236495ULL, + 7393046528943419306ULL, + 10318961341152276648ULL, + 15227553401250387405ULL, + 16697499576601945061ULL, + 2725724513251979147ULL, + 2959262702089257674ULL, + 13005022849156685393ULL, + 15761951700770049152ULL, + 1543933356731858728ULL, + 11918274797446795400ULL, + 8565138620607953150ULL, + 12303972293118122590ULL, + 3894262225055971808ULL, + 15748923097789202806ULL, + 7445113579724918237ULL, + 9352139437145177775ULL, + 13354327698439508785ULL, + 14395299404885352996ULL, + 1717181541369804485ULL, + 13580134637576898558ULL, + 7869123835192762123ULL, + 17965909040401498617ULL, + 8052995111566596790ULL, + 12914551890455320561ULL, + 4117682086191216416ULL, + 6338289071186062965ULL, + 5814176097875431103ULL, + 14826385593100095233ULL, + 10541047035071991113ULL, + 6190214339491074327ULL, + 10842054931648009233ULL, + 5939715546527939616ULL, + 7892483490571988259ULL, + 5706834027745974113ULL, + 5279702511609911835ULL, + 9429007351441093145ULL, + 9003299904399604102ULL, + 17387825652548649779ULL, + 15599237468898715461ULL, + 9636847268497273922ULL, + 6553990919897350057ULL, + 13702604427410293191ULL, + 2951702790388654203ULL, + 11840626484159722915ULL, + 2545196762095857746ULL, + 3245381935646466890ULL, + 14924004818419014054ULL, + 17307026898787526320ULL, + 505706103741995403ULL, + 1910775063020669898ULL, + 7076255593390973200ULL, + 12112449858466219362ULL, + 14742510104650318633ULL, + 18061657763370298501ULL, + 481489007567700054ULL, + 16400619344256757493ULL, + 2276480650877074293ULL, + 17657490758851414958ULL, + 10375576356736793341ULL, + 11978364073664959090ULL, + 6962787816486957283ULL, + 8945389641396629891ULL, + 10333276603165380084ULL, + 10766868630468389150ULL, + 13638842475286731623ULL, + 7586779683423382399ULL, + 7959765828778244231ULL, + 809929751227234334ULL, + 2646002627166349152ULL, + 11780180320854559998ULL, + 13855197810473133678ULL, + 5061966727887963421ULL, + 8831329945074475835ULL, + 1092659380955694324ULL, + 8406669250393168781ULL, + 1210820029035423219ULL, + 3779694736357686174ULL, + 8953286534157132517ULL, + 15926591678820634559ULL, + 6892281684169093025ULL, + 11798154340507794264ULL, + 3383667935658249174ULL, + 8090374027476087947ULL, + 1344287774476569420ULL, + 16036817376283104799ULL, + 15708461104025072747ULL, + 17647438730951324648ULL, + 3271559932170326270ULL, + 3440032660435501456ULL, + 15209001562045336524ULL, + 16527226617411200894ULL, + 16083303942902816114ULL, + 16998804538680658636ULL, + 211876019454739059ULL, + 17900510319720696725ULL, +}; + +const std::pair ChunnanFiles[] = { + { "#ActD_SubChina_01.ar.00", 2 }, + { "#ActD_SubChina_01.arl", 2 }, + { "#ActD_SubChina_02.ar.00", 2 }, + { "#ActD_SubChina_02.arl", 2 }, + { "#ActD_SubChina_05.ar.00", 2 }, + { "#ActD_SubChina_05.arl", 2 }, + { "#ActD_SubChina_06.ar.00", 2 }, + { "#ActD_SubChina_06.arl", 2 }, + { "#ActN_SubChina_02.ar.00", 2 }, + { "#ActN_SubChina_02.arl", 2 }, + { "#ActN_SubChina_03.ar.00", 2 }, + { "#ActN_SubChina_03.arl", 2 }, + { "#Application.ar.00", 2 }, + { "#Application.arl", 2 }, + { "#SonicActionCommon_China.ar.00", 2 }, + { "#SonicActionCommon_China.arl", 2 }, + { "ActD_SubChina_01.ar.00", 2 }, + { "ActD_SubChina_01.arl", 2 }, + { "ActD_SubChina_02.ar.00", 2 }, + { "ActD_SubChina_02.arl", 2 }, + { "ActD_SubChina_06.ar.00", 2 }, + { "ActD_SubChina_06.arl", 2 }, + { "ActN_SubChina_02.ar.00", 2 }, + { "ActN_SubChina_02.ar.01", 2 }, + { "ActN_SubChina_02.ar.02", 2 }, + { "ActN_SubChina_02.arl", 2 }, + { "ActN_SubChina_03.ar.00", 2 }, + { "ActN_SubChina_03.arl", 2 }, + { "Additional/ActD_China/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubChina_01/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubChina_02/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubChina_03/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubChina_04/Stage-Add.pfd", 1 }, + { "Additional/ActN_ChinaEvil/Stage-Add.pfd", 1 }, + { "Additional/ActN_SubChina_01/Stage-Add.pfd", 1 }, + { "Additional/ActN_SubChina_02/Stage-Add.pfd", 1 }, + { "Additional/Town_China/Stage-Add.pfd", 1 }, + { "Additional/Town_ChinaETF/Stage-Add.pfd", 1 }, + { "Additional/Town_ChinaETF_Night/Stage-Add.pfd", 1 }, + { "Additional/Town_China_Night/Stage-Add.pfd", 1 }, + { "China.dmy", 1 }, + { "DLC.xml", 1 }, + { "Languages/English/WorldMap.ar.00", 2 }, + { "Languages/English/WorldMap.arl", 2 }, + { "Languages/French/WorldMap.ar.00", 2 }, + { "Languages/French/WorldMap.arl", 2 }, + { "Languages/German/WorldMap.ar.00", 2 }, + { "Languages/German/WorldMap.arl", 2 }, + { "Languages/Italian/WorldMap.ar.00", 2 }, + { "Languages/Italian/WorldMap.arl", 2 }, + { "Languages/Japanese/WorldMap.ar.00", 2 }, + { "Languages/Japanese/WorldMap.arl", 2 }, + { "Languages/Spanish/WorldMap.ar.00", 2 }, + { "Languages/Spanish/WorldMap.arl", 2 }, + { "Packed/ActD_SubChina_01/Stage.pfd", 1 }, + { "Packed/ActD_SubChina_02/Stage.pfd", 1 }, + { "Packed/ActN_SubChina_02/Stage.pfd", 1 }, + { "SonicActionCommon_China.ar.00", 2 }, + { "SonicActionCommon_China.ar.01", 2 }, + { "SonicActionCommon_China.arl", 2 }, + { "WorldMap.ar.00", 2 }, + { "WorldMap.arl", 2 }, + { "work/ActD_China/Terrain.prm.xml", 2 }, + { "work/ActD_SubChina_03/Terrain.prm.xml", 2 }, + { "work/ActD_SubChina_04/Terrain.prm.xml", 2 }, + { "work/ActN_ChinaEvil/Terrain.prm.xml", 2 }, + { "work/ActN_SubChina_01/Terrain.prm.xml", 2 }, + { "work/Town_China/Terrain.prm.xml", 2 }, + { "work/Town_ChinaETF/Terrain.prm.xml", 2 }, + { "work/Town_ChinaETF_Night/Terrain.prm.xml", 2 }, + { "work/Town_China_Night/Terrain.prm.xml", 2 }, +}; + +const size_t ChunnanFilesSize = std::size(ChunnanFiles); diff --git a/UnleashedRecomp/install/hashes/chunnan.h b/UnleashedRecomp/install/hashes/chunnan.h new file mode 100644 index 00000000..ecf4ef52 --- /dev/null +++ b/UnleashedRecomp/install/hashes/chunnan.h @@ -0,0 +1,10 @@ +// File automatically generated by fshasher + +#pragma once + +#include + +extern const uint64_t ChunnanHashes[]; +extern const std::pair ChunnanFiles[]; +extern const size_t ChunnanFilesSize; + diff --git a/UnleashedRecomp/install/hashes/empire_city_adabat.cpp b/UnleashedRecomp/install/hashes/empire_city_adabat.cpp new file mode 100644 index 00000000..b7bc3766 --- /dev/null +++ b/UnleashedRecomp/install/hashes/empire_city_adabat.cpp @@ -0,0 +1,301 @@ +// File automatically generated by fshasher + +#include + +extern const uint64_t EmpireCityAdabatHashes[]; +extern const std::pair EmpireCityAdabatFiles[]; +extern const size_t EmpireCityAdabatFilesSize; + +const uint64_t EmpireCityAdabatHashes[] = { + 4618484507458881259ULL, + 8182943251133517605ULL, + 4541536790551220736ULL, + 17406849580710840362ULL, + 13446786864141547866ULL, + 18394961398924760842ULL, + 7232487182893775796ULL, + 14381110835230961016ULL, + 4274945889038837581ULL, + 7808510065756945406ULL, + 1610509086024531696ULL, + 8803475239916562653ULL, + 10167668386744802426ULL, + 13956299527641656682ULL, + 996767587458817188ULL, + 1288788687784703445ULL, + 1545319301186643948ULL, + 3463553283246285904ULL, + 2329886274870127790ULL, + 10808429212560901966ULL, + 1527041476422438351ULL, + 2162146429294502965ULL, + 15296556067580089ULL, + 16098667829436141937ULL, + 744838819720957427ULL, + 7423469708976263310ULL, + 3529776342881389937ULL, + 4461759958287006047ULL, + 8807875940438298613ULL, + 16843338913535213802ULL, + 58256850107590821ULL, + 13358292493270923606ULL, + 3407070953812175890ULL, + 17745212169422172237ULL, + 7003077550452454334ULL, + 8088383338758466757ULL, + 1919723919369387380ULL, + 17373239717886557228ULL, + 8218928162239233105ULL, + 12366520936282200873ULL, + 11042839363452044257ULL, + 15356169009822064376ULL, + 9138597922789664708ULL, + 16547445367137541751ULL, + 13108520045170224668ULL, + 15310644750109062057ULL, + 777887060161745667ULL, + 13298530423883017862ULL, + 10405571379268351804ULL, + 17852400551605150551ULL, + 8485124434733981977ULL, + 12177189339342254810ULL, + 3082211076406596763ULL, + 6711541791173565389ULL, + 1392400380375046924ULL, + 8082351014158359034ULL, + 9938956644170626460ULL, + 16820751035068431553ULL, + 6498223167578513931ULL, + 15573567680447777044ULL, + 818541743678319259ULL, + 13162066552036570425ULL, + 4470546825230084927ULL, + 16933853415047689351ULL, + 17047164819104329366ULL, + 11164964391272112273ULL, + 10214344852494979677ULL, + 8749232225003494592ULL, + 10588995228676795372ULL, + 17946424022152922370ULL, + 7684379787895597340ULL, + 17137410643095877226ULL, + 2892218193839563307ULL, + 17360308384459188410ULL, + 9618439767240157908ULL, + 12538237685986535590ULL, + 10783954654629912125ULL, + 11628381209642954065ULL, + 1492167910272475344ULL, + 2464069474108457492ULL, + 13481409826628489247ULL, + 6970423075361710992ULL, + 6267765362270814284ULL, + 9012032776579276367ULL, + 2744550015698589133ULL, + 10260598734212408368ULL, + 2300802232392089767ULL, + 10949176600743863488ULL, + 1118205454506633106ULL, + 5969867951434607877ULL, + 6671314176692954687ULL, + 14530713737956734950ULL, + 2004571052229566869ULL, + 9708958471851417571ULL, + 2142992686316263474ULL, + 7168715241575146342ULL, + 1976917309517312226ULL, + 18038718853485103300ULL, + 7044835724604442413ULL, + 15531130920102660109ULL, + 4462669497430426931ULL, + 13428469011561492337ULL, + 3214238300098346592ULL, + 16176599498653256643ULL, + 5326927580226746490ULL, + 15047534843332950162ULL, + 11636822788287294319ULL, + 12554314680841874379ULL, + 8706113903054062682ULL, + 18207042628229284597ULL, + 5213300754710184598ULL, + 8479681542825232071ULL, + 5360854891214543592ULL, + 9184741739495532010ULL, + 1210820029035423219ULL, + 3779694736357686174ULL, + 3837095400824054399ULL, + 9794004182896121787ULL, + 12515494881385509791ULL, + 15063249629029871557ULL, + 13061295136017828432ULL, + 17824323001364842093ULL, + 1014938187367296966ULL, + 1452881609817169700ULL, + 3555492069376698022ULL, + 12805106068875273513ULL, + 10312311736007919080ULL, + 17030922443332175658ULL, + 10695305817718672781ULL, + 13804284662675589878ULL, + 9089169043898385347ULL, + 13234787173486497799ULL, + 8604409041610624441ULL, + 12146239465411938672ULL, + 2721757041275179953ULL, + 11198739556793737443ULL, + 15712221005744556715ULL, + 18094691449976637288ULL, + 15547655397439064196ULL, + 17270814844989703830ULL, + 3140658107263566967ULL, + 4592986651443127450ULL, + 5456798863030720610ULL, + 15886814922191774691ULL, + 3949234515704675807ULL, + 11955725616840921688ULL, + 275537481032843773ULL, + 9312649863415127630ULL, + 10341982185761145488ULL, + 11616013853856219024ULL, + 747890237293655409ULL, + 16207842125850922960ULL, + 7337489688872005573ULL, + 9028255494965930705ULL, + 15360353024836444627ULL, + 16078477132817971317ULL, + 3457659339231167623ULL, + 15718276630192910248ULL, + 9554347366501308641ULL, + 9964745841368142774ULL, + 12984301129292863167ULL, + 15594004427009479633ULL, + 8763624932769278216ULL, + 9531499636450705927ULL, + 6901020296706243673ULL, + 6939812494265815615ULL, + 3081980174784719188ULL, + 17328496666218534737ULL, + 2803515411835567103ULL, + 4886896048325757224ULL, + 16083303942902816114ULL, + 16998804538680658636ULL, + 4511521600139320416ULL, + 13420895488136723132ULL, + 16636596484105747721ULL, + 18203853164184025820ULL, + 15091774185752181796ULL, + 16492958331247638847ULL, + 3414648039055001172ULL, + 16364348268655095621ULL, + 3485883307755363459ULL, + 10861246708191214529ULL, +}; + +const std::pair EmpireCityAdabatFiles[] = { + { "#ActD_SubBeach_01.ar.00", 2 }, + { "#ActD_SubBeach_01.arl", 2 }, + { "#ActD_SubBeach_03.ar.00", 2 }, + { "#ActD_SubBeach_03.arl", 2 }, + { "#ActD_SubBeach_05.ar.00", 2 }, + { "#ActD_SubBeach_05.arl", 2 }, + { "#ActD_SubNY_02.ar.00", 2 }, + { "#ActD_SubNY_02.arl", 2 }, + { "#ActD_SubNY_03.ar.00", 2 }, + { "#ActD_SubNY_03.arl", 2 }, + { "#ActN_SubBeach_02.ar.00", 2 }, + { "#ActN_SubBeach_02.arl", 2 }, + { "#ActN_SubBeach_03.ar.00", 2 }, + { "#ActN_SubBeach_03.arl", 2 }, + { "#ActN_SubNY_01.ar.00", 2 }, + { "#ActN_SubNY_01.arl", 2 }, + { "#ActN_SubNY_02.ar.00", 2 }, + { "#ActN_SubNY_02.arl", 2 }, + { "#Application.ar.00", 2 }, + { "#Application.arl", 2 }, + { "ActD_SubBeach_01.ar.00", 2 }, + { "ActD_SubBeach_01.arl", 2 }, + { "ActD_SubBeach_03.ar.00", 2 }, + { "ActD_SubBeach_03.arl", 2 }, + { "ActD_SubBeach_05.ar.00", 2 }, + { "ActD_SubBeach_05.arl", 2 }, + { "ActD_SubNY_02.ar.00", 2 }, + { "ActD_SubNY_02.arl", 2 }, + { "ActN_SubNY_01.ar.00", 2 }, + { "ActN_SubNY_01.ar.01", 2 }, + { "ActN_SubNY_01.arl", 2 }, + { "Additional/ActD_Beach/Stage-Add.pfd", 1 }, + { "Additional/ActD_NY/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubBeach_01/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubBeach_02/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubBeach_03/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubBeach_04/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubNY_01/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubNY_02/Stage-Add.pfd", 1 }, + { "Additional/ActN_BeachEvil/Stage-Add.pfd", 1 }, + { "Additional/ActN_NYEvil/Stage-Add.pfd", 1 }, + { "Additional/ActN_SubBeach_01/Stage-Add.pfd", 1 }, + { "Additional/ActN_SubNY_01/Stage-Add.pfd", 1 }, + { "Additional/Event_M6_01_temple/Stage-Add.pfd", 1 }, + { "Additional/Town_NYCity/Stage-Add.pfd", 1 }, + { "Additional/Town_NYCityETF/Stage-Add.pfd", 1 }, + { "Additional/Town_NYCityETF_Night/Stage-Add.pfd", 1 }, + { "Additional/Town_NYCity_Night/Stage-Add.pfd", 1 }, + { "Additional/Town_SouthEastAsia/Stage-Add.pfd", 1 }, + { "Additional/Town_SouthEastAsiaETF/Stage-Add.pfd", 1 }, + { "Additional/Town_SouthEastAsiaETF_Night/Stage-Add.pfd", 1 }, + { "Additional/Town_SouthEastAsia_Night/Stage-Add.pfd", 1 }, + { "DLC.xml", 1 }, + { "Languages/English/WorldMap.ar.00", 2 }, + { "Languages/English/WorldMap.arl", 2 }, + { "Languages/French/WorldMap.ar.00", 2 }, + { "Languages/French/WorldMap.arl", 2 }, + { "Languages/German/WorldMap.ar.00", 2 }, + { "Languages/German/WorldMap.arl", 2 }, + { "Languages/Italian/WorldMap.ar.00", 2 }, + { "Languages/Italian/WorldMap.arl", 2 }, + { "Languages/Japanese/WorldMap.ar.00", 2 }, + { "Languages/Japanese/WorldMap.arl", 2 }, + { "Languages/Spanish/WorldMap.ar.00", 2 }, + { "Languages/Spanish/WorldMap.arl", 2 }, + { "Packed/ActD_SubBeach_01/Stage.pfd", 1 }, + { "Packed/ActD_SubBeach_03/Stage.pfd", 1 }, + { "Packed/ActD_SubNY_02/Stage.pfd", 1 }, + { "Packed/ActN_SubNY_01/Stage.pfd", 1 }, + { "WorldMap.ar.00", 2 }, + { "WorldMap.arl", 2 }, + { "work/ActD_Beach/Terrain.prm.xml", 2 }, + { "work/ActD_NY/Terrain.prm.xml", 2 }, + { "work/ActD_SubBeach_02/Terrain.prm.xml", 2 }, + { "work/ActD_SubBeach_04/Terrain.prm.xml", 2 }, + { "work/ActD_SubNY_01/Terrain.prm.xml", 2 }, + { "work/ActN_BeachEvil/Terrain.prm.xml", 2 }, + { "work/ActN_BeachEvil/evl_sea_obj_st_waterCircle.model", 2 }, + { "work/ActN_BeachEvil/sea_water_circle-0000.texture", 2 }, + { "work/ActN_BeachEvil/sea_water_circle-0000.uv-anim", 2 }, + { "work/ActN_BeachEvil/sea_water_circle-0001.texture", 2 }, + { "work/ActN_BeachEvil/sea_water_circle-0001.uv-anim", 2 }, + { "work/ActN_BeachEvil/sea_water_circle-0002.texture", 2 }, + { "work/ActN_BeachEvil/sea_water_circle-0002.uv-anim", 2 }, + { "work/ActN_BeachEvil/sea_water_circle-0003.texture", 2 }, + { "work/ActN_BeachEvil/sea_water_circle.material", 2 }, + { "work/ActN_BeachEvil/sea_water_circle.texset", 2 }, + { "work/ActN_BeachEvil/sea_water_kt_MotionWater_dif.dds", 2 }, + { "work/ActN_BeachEvil/sea_water_kt_MotionWater_env.dds", 2 }, + { "work/ActN_NYEvil/Terrain.prm.xml", 2 }, + { "work/ActN_SubBeach_01/Terrain.prm.xml", 2 }, + { "work/ActN_SubNY_01/Terrain.prm.xml", 2 }, + { "work/BossEggLancer/Terrain.prm.xml", 2 }, + { "work/Event_M4_01_egb_hideout/Terrain.prm.xml", 2 }, + { "work/Event_M6_01_temple/Terrain.prm.xml", 2 }, + { "work/Event_egb_hidout_exterior/Terrain.prm.xml", 2 }, + { "work/Town_NYCity/Terrain.prm.xml", 2 }, + { "work/Town_NYCityETF/Terrain.prm.xml", 2 }, + { "work/Town_NYCityETF_Night/Terrain.prm.xml", 2 }, + { "work/Town_NYCity_Night/Terrain.prm.xml", 2 }, + { "work/Town_SouthEastAsia/Terrain.prm.xml", 2 }, + { "work/Town_SouthEastAsiaETF/Terrain.prm.xml", 2 }, + { "work/Town_SouthEastAsiaETF_Night/Terrain.prm.xml", 2 }, + { "work/Town_SouthEastAsia_Night/Terrain.prm.xml", 2 }, +}; + +const size_t EmpireCityAdabatFilesSize = std::size(EmpireCityAdabatFiles); diff --git a/UnleashedRecomp/install/hashes/empire_city_adabat.h b/UnleashedRecomp/install/hashes/empire_city_adabat.h new file mode 100644 index 00000000..285c7a5e --- /dev/null +++ b/UnleashedRecomp/install/hashes/empire_city_adabat.h @@ -0,0 +1,10 @@ +// File automatically generated by fshasher + +#pragma once + +#include + +extern const uint64_t EmpireCityAdabatHashes[]; +extern const std::pair EmpireCityAdabatFiles[]; +extern const size_t EmpireCityAdabatFilesSize; + diff --git a/UnleashedRecomp/install/hashes/game.cpp b/UnleashedRecomp/install/hashes/game.cpp new file mode 100644 index 00000000..81a9daff --- /dev/null +++ b/UnleashedRecomp/install/hashes/game.cpp @@ -0,0 +1,8436 @@ +// File automatically generated by fshasher + +#include + +extern const uint64_t GameHashes[]; +extern const std::pair GameFiles[]; +extern const size_t GameFilesSize; + +const uint64_t GameHashes[] = { + 9217621634848118158ULL, + 15317665572267126848ULL, + 4458626307778670654ULL, + 13108270535636839370ULL, + 10908347273376065354ULL, + 14824412096969662770ULL, + 278408659673994752ULL, + 2285808654108979709ULL, + 13458616248161204038ULL, + 17929352335497602186ULL, + 2222284706405990979ULL, + 10117783342305711822ULL, + 8036064585642495347ULL, + 14699120059841976810ULL, + 11024823948457199198ULL, + 15400735314704287496ULL, + 12257326909357484268ULL, + 18185839765680528008ULL, + 12149925291843664518ULL, + 14665080869584094381ULL, + 1000755795749057120ULL, + 15621142594354647085ULL, + 12687504317395886177ULL, + 15195764623785370646ULL, + 2387349055206159503ULL, + 12631317777031124347ULL, + 3438354363223640084ULL, + 14068850201053970291ULL, + 989313108622384677ULL, + 16019476620978936817ULL, + 13385995961494433657ULL, + 15808193812923172999ULL, + 2924214086414982704ULL, + 12428721747597297655ULL, + 9266479263710983319ULL, + 11785832198386716677ULL, + 2832771161985377904ULL, + 8422570403194853694ULL, + 10025704896828708977ULL, + 12536243609672248803ULL, + 7333519599516165853ULL, + 17248175310468021177ULL, + 16471040161676361832ULL, + 17957463118964997340ULL, + 3509674790636064480ULL, + 17254343633075426505ULL, + 7669632333630204994ULL, + 17959800155590239762ULL, + 4341848656199339788ULL, + 7549162173042586381ULL, + 745905284676226735ULL, + 11121579809231958637ULL, + 10713108012865692446ULL, + 17780686803563136121ULL, + 10120985710253247084ULL, + 14403268787697192274ULL, + 8468986345593275694ULL, + 14778662775625970826ULL, + 15916752223375287423ULL, + 16541713562079294011ULL, + 3668282008680130182ULL, + 7223810989937140637ULL, + 4177383712338065672ULL, + 12622507696503791758ULL, + 8431840130278883742ULL, + 14563186544529277651ULL, + 8380939392246939054ULL, + 8572677923921336564ULL, + 8310146974726336702ULL, + 16680977549614230874ULL, + 3013808632219919872ULL, + 4677936159396170551ULL, + 1484533171290517502ULL, + 11544906409830656981ULL, + 10100916613949267172ULL, + 17748082902713065084ULL, + 7216309071710706120ULL, + 10242112466009832312ULL, + 2009350399656203842ULL, + 6259615259983216651ULL, + 5114406082224878848ULL, + 6992479038277656079ULL, + 3516173115610842573ULL, + 8954050871747816274ULL, + 2373111544324332692ULL, + 9224816974864990564ULL, + 1405350071475663512ULL, + 11756895172458791164ULL, + 6026860690125749928ULL, + 9005248337811657794ULL, + 1674923773102589900ULL, + 13237978076531084502ULL, + 15016739826749893131ULL, + 15126399169062025210ULL, + 9301941225730578585ULL, + 11176459936576266207ULL, + 9143144216708133373ULL, + 16267746325687948228ULL, + 5035450529704541542ULL, + 11979452518268211457ULL, + 6691322330738482866ULL, + 9248711138475816790ULL, + 1340465013224055988ULL, + 13026407606607765839ULL, + 2507123461316750304ULL, + 5062222866898446157ULL, + 12065464725264552751ULL, + 17731340317748779760ULL, + 8278832131690183410ULL, + 11176468495388050800ULL, + 10808955537907758817ULL, + 11989805890997537387ULL, + 2957554962749711377ULL, + 9687142543490589453ULL, + 8905332554133273341ULL, + 15597898373702439777ULL, + 4644215317183382910ULL, + 7958805460363673540ULL, + 6284634551803068597ULL, + 15272306002120300447ULL, + 11344064273076482175ULL, + 14966677898224010538ULL, + 10877844379854655369ULL, + 13276412695661856390ULL, + 3931753478122653784ULL, + 4447561157327491489ULL, + 14886394764849023992ULL, + 15817564502823585503ULL, + 1174073081130353986ULL, + 11791362088587370447ULL, + 12356093842287240444ULL, + 16763782701288236610ULL, + 5642326559025366427ULL, + 16915023571181379726ULL, + 9065122669702734762ULL, + 11130336836287432984ULL, + 5921321991315329117ULL, + 7813215112232441486ULL, + 5939693135199751050ULL, + 13774366931873169166ULL, + 12008190501277593753ULL, + 18139443639173572296ULL, + 3010890938797286249ULL, + 6119577544006845281ULL, + 11285772956996491190ULL, + 16803790372729080132ULL, + 8982258098744982019ULL, + 16001149930665494338ULL, + 2421478867974032230ULL, + 8447142380449901180ULL, + 2562250039116041168ULL, + 6526518533157435913ULL, + 71179902150130577ULL, + 4685550656763397082ULL, + 15320592175839423398ULL, + 16037192571026728874ULL, + 33905015355935466ULL, + 2981356684964157551ULL, + 5860786387255684462ULL, + 11590439921260790674ULL, + 12722534456368521711ULL, + 14176235599002764940ULL, + 2137512129975890104ULL, + 12824911398507076786ULL, + 1069499593701761841ULL, + 14224502890178577618ULL, + 3484403924289659709ULL, + 11484813800367510462ULL, + 5613723390860937407ULL, + 12315341794973853695ULL, + 4049590346243786885ULL, + 7063695668732787798ULL, + 7672153813378223700ULL, + 17403775610860416858ULL, + 2447905232310438502ULL, + 5376884422620598720ULL, + 7992739993688161927ULL, + 12365712583858558035ULL, + 1028147824735900648ULL, + 2425039318210927510ULL, + 10132350002549444037ULL, + 14439766117226165518ULL, + 3405113971822300518ULL, + 5185096940552836530ULL, + 5828251748828979131ULL, + 10543141322306372436ULL, + 3236022439387054344ULL, + 13297748587161158363ULL, + 13446471067338609041ULL, + 16859057150758794797ULL, + 5610668467161530328ULL, + 17194812537835375049ULL, + 7906179539823341863ULL, + 8342973085920339641ULL, + 4087766043478633526ULL, + 15405054706491927071ULL, + 16156510203767945913ULL, + 16591360828001474161ULL, + 8617238550756047593ULL, + 9535000370870387521ULL, + 3541996830681904310ULL, + 5350726222358205196ULL, + 7751699295700679735ULL, + 9069368914428566133ULL, + 8560156737410637940ULL, + 12312661292414316955ULL, + 5675368918904086032ULL, + 10229212419622130527ULL, + 12817112894072047873ULL, + 17577205697901061824ULL, + 6408234644190149036ULL, + 11314177134721361395ULL, + 4524295981505344020ULL, + 16021577191778085627ULL, + 16050237424622924484ULL, + 16628390739220089264ULL, + 1514698008845751493ULL, + 7893384003773728882ULL, + 3992972288602733407ULL, + 11935586711809342196ULL, + 5461684198248332810ULL, + 9900089241677220009ULL, + 9028288432483540583ULL, + 14388812822958501189ULL, + 1154240269232766784ULL, + 6433346805624681599ULL, + 7748612235282861688ULL, + 12110052888040884849ULL, + 191734347562208284ULL, + 4043318996002151529ULL, + 2486913668840352147ULL, + 12476584005955244061ULL, + 10333471688104526530ULL, + 13339626900418933342ULL, + 6477282133027668251ULL, + 10511232185346612287ULL, + 2282113124821313940ULL, + 13154739800243771100ULL, + 7213523911135400816ULL, + 8998289536233596398ULL, + 4297652420966099661ULL, + 12480582177529720819ULL, + 14605629376551960738ULL, + 15285638270186731950ULL, + 1084541048370856145ULL, + 9729091026651747092ULL, + 10164133375876164467ULL, + 15914143230317388833ULL, + 4490084167313371250ULL, + 11657167685209843496ULL, + 6890095315212241782ULL, + 10928719784940185348ULL, + 8739839847761486357ULL, + 10872504631045235240ULL, + 756252221937964714ULL, + 13647445405522592553ULL, + 2020945729825150092ULL, + 4801621828941513539ULL, + 1814525893438650404ULL, + 12662241777786565002ULL, + 8747343150352965505ULL, + 16386240513978511731ULL, + 3980653068288917683ULL, + 14520064307390133276ULL, + 10318495828892909009ULL, + 15388776930358470335ULL, + 633616820770116853ULL, + 15962188015446680072ULL, + 5844587747294195342ULL, + 6373064953189761750ULL, + 3970430193234520851ULL, + 16882880578631600890ULL, + 4024432149268636107ULL, + 8643478829325658396ULL, + 9113083761527853320ULL, + 12561270423659662785ULL, + 11042012361689474323ULL, + 18319323849970630777ULL, + 5028078700160080192ULL, + 13227528125940320051ULL, + 1081610632167475926ULL, + 15791878879071211997ULL, + 10546573069891484124ULL, + 17889840196448232838ULL, + 9275572835012242053ULL, + 14648913796604262392ULL, + 2296800220993726814ULL, + 9469930452067331973ULL, + 7797135657299699093ULL, + 15578906533215742378ULL, + 9653012277277070637ULL, + 14414954174697235690ULL, + 15605239974940315390ULL, + 17457585947564154222ULL, + 16953363633177391768ULL, + 18170330839202152473ULL, + 6822213579659689052ULL, + 10061265419155738657ULL, + 330380023902820164ULL, + 400225907626576290ULL, + 3967460562505212290ULL, + 9676947727952298692ULL, + 3500953200234507035ULL, + 9676880706083476632ULL, + 4854315436229877215ULL, + 13210445148464013521ULL, + 2620496240076479674ULL, + 3904354604209449835ULL, + 2822993384006760660ULL, + 4040919785686671528ULL, + 7037909898830716003ULL, + 9065614985755300618ULL, + 1666278489865802676ULL, + 2901855381374450637ULL, + 857230711414493746ULL, + 16301084477891559297ULL, + 2348515806452284664ULL, + 11668972984125169888ULL, + 2175039559928192538ULL, + 9504292140859890806ULL, + 2683729897417346919ULL, + 12023720611948964653ULL, + 3377189850280719423ULL, + 8891343079454003063ULL, + 13601668692330526453ULL, + 17468333328328348298ULL, + 2575044218606508902ULL, + 2706239984153969550ULL, + 170880364332676460ULL, + 13747913612223818671ULL, + 10000848857854313541ULL, + 13495693662841531007ULL, + 7908661535573321355ULL, + 11417044259131060277ULL, + 11487037024469551906ULL, + 13529708737815424945ULL, + 13991972906894603283ULL, + 14745660230730896158ULL, + 1657098260140186829ULL, + 15731295054534041363ULL, + 5069356162190728063ULL, + 9762959449822686503ULL, + 9246310088157167004ULL, + 11386358111816615708ULL, + 4966604952096104766ULL, + 16788409725907994256ULL, + 15550904160491980293ULL, + 17828872651554520926ULL, + 8186729920523418968ULL, + 11974959959567691553ULL, + 12574133229647316359ULL, + 13179549514474518566ULL, + 671267421519225992ULL, + 14984837039875201568ULL, + 210228495891582752ULL, + 10538099358735222202ULL, + 872244177361413251ULL, + 8650294788447105018ULL, + 2262517144368249499ULL, + 3353532651938027324ULL, + 8213566431250009347ULL, + 16625866393537346869ULL, + 14115286313344452347ULL, + 17416368554687327016ULL, + 4142345173591694497ULL, + 9226588144155293301ULL, + 3088970185148357732ULL, + 17390895970843040908ULL, + 2599962143166298659ULL, + 14841422939736637389ULL, + 3125257947946372992ULL, + 13753685190367120144ULL, + 10980127184977359520ULL, + 14492115135600150349ULL, + 8200621637815576305ULL, + 18287804670354837687ULL, + 902754358311436507ULL, + 5956732248786898984ULL, + 6206186932459661859ULL, + 13688189633498606759ULL, + 9672364332071699034ULL, + 14845103943390759725ULL, + 10669434280488735933ULL, + 14962019145464658883ULL, + 9529880283611057210ULL, + 17082934234815762266ULL, + 4158249739050283112ULL, + 14672801317244779435ULL, + 4934479922634295021ULL, + 15693443580395004629ULL, + 7222176228690433158ULL, + 15111778105514182224ULL, + 6182531505561691217ULL, + 6839618010535544427ULL, + 431463907768133322ULL, + 12207982852996479325ULL, + 1672425513991788730ULL, + 9523662558482924607ULL, + 9977146029680964795ULL, + 11691949091157419425ULL, + 1624296170977297882ULL, + 3855321680941140984ULL, + 8771512326974630233ULL, + 12672532031516318657ULL, + 11009010811911151342ULL, + 16238960594960541532ULL, + 4408723408301701272ULL, + 15529029525929520536ULL, + 1262585449442104263ULL, + 14574790333309740630ULL, + 4012098452910129319ULL, + 13642704442770095841ULL, + 3724150128665676626ULL, + 15479653342976529040ULL, + 3863901070228445133ULL, + 14683408353745187452ULL, + 4242867873147400543ULL, + 11154677845434901071ULL, + 8896928963163106629ULL, + 16267483256706209207ULL, + 4454998996972126460ULL, + 10736279208358553725ULL, + 11576920004920534641ULL, + 17147068056078250042ULL, + 1117296220306967567ULL, + 3408661021270443579ULL, + 509808228076137377ULL, + 6927212018450727087ULL, + 17349155453094707849ULL, + 18027974085066770031ULL, + 3362079280495903348ULL, + 4673446304573570834ULL, + 16344790835884137996ULL, + 17360202942740238502ULL, + 6926966681040172368ULL, + 8232969105044360866ULL, + 4117722072760535293ULL, + 16527397479209558661ULL, + 14030594910006549730ULL, + 14896183729013097561ULL, + 15421359706838655970ULL, + 16782156896401590059ULL, + 4213813667484383544ULL, + 13655486806922223191ULL, + 17142632182142280516ULL, + 17694473248814153853ULL, + 2457942825616218336ULL, + 18142441417938475819ULL, + 10017926060829241908ULL, + 10550699584720019568ULL, + 7902569406270460343ULL, + 14872382568756713951ULL, + 5877932746499198751ULL, + 13384953123246923345ULL, + 16856323959059680306ULL, + 17333537704030659057ULL, + 4807442774874275197ULL, + 14572454031198203195ULL, + 2629586467763566683ULL, + 9306550589755624986ULL, + 1230631861133700667ULL, + 8963866597325825059ULL, + 16131323499442160030ULL, + 18111977185206822363ULL, + 1739679600073158257ULL, + 17978706651634250296ULL, + 10865917073005468293ULL, + 16980269219202322731ULL, + 8481919657422729613ULL, + 12201565528117088469ULL, + 4586884348740466313ULL, + 14657034015202049432ULL, + 3625437206540951167ULL, + 6921374987126764417ULL, + 6102907670099108784ULL, + 8937672498802194700ULL, + 5451700116501840757ULL, + 15251611162804353608ULL, + 5060468789029027495ULL, + 15829843285517440934ULL, + 4945603070793410950ULL, + 5172085180487318467ULL, + 9785014950186688813ULL, + 17193316524481629659ULL, + 4370212066803529447ULL, + 7866252987930737297ULL, + 7533921298233189692ULL, + 13417850763051367156ULL, + 15373679014867448589ULL, + 16418400483458265443ULL, + 11469704354513512001ULL, + 13396189733666185582ULL, + 6329903016095170114ULL, + 12078363527022252545ULL, + 7393046528943419306ULL, + 10318961341152276648ULL, + 14162953847253755188ULL, + 14702978463496077067ULL, + 1434366230817934461ULL, + 3436024840256579751ULL, + 14288949696920431218ULL, + 14358188498924027107ULL, + 4170527077591052442ULL, + 16738991455483577488ULL, + 4009495924471230644ULL, + 10858738235273573693ULL, + 3240165855699778947ULL, + 5968207270829890120ULL, + 8366732107770974325ULL, + 15091226790323210400ULL, + 6761446567584825627ULL, + 8456236697033494567ULL, + 485438459488704270ULL, + 13012429876256856194ULL, + 1630148789765066505ULL, + 8990798050038093195ULL, + 10136880909343084651ULL, + 10192729072215479653ULL, + 6314798833786186098ULL, + 18183930942790585851ULL, + 9278477332223870893ULL, + 9744780750247414231ULL, + 3194180433562354850ULL, + 8424793732643554004ULL, + 3560038230126326512ULL, + 16676357014234285866ULL, + 7002054034884216169ULL, + 11275673741911828548ULL, + 12212751856543127461ULL, + 13410588168459544641ULL, + 8384393487652734845ULL, + 17997497640956275857ULL, + 588452717313115483ULL, + 17761054290283840507ULL, + 8015280259593706540ULL, + 8310139314897168556ULL, + 4936270031057846314ULL, + 10837371253413218889ULL, + 9213677535966950729ULL, + 10683601454999179330ULL, + 16555303471876543686ULL, + 17493455426984246142ULL, + 11681065667477649249ULL, + 13794237366600166504ULL, + 17600475737267873207ULL, + 17758725748762986117ULL, + 14203932582715135007ULL, + 16840501122199952287ULL, + 4739422481945861699ULL, + 10735672177242819713ULL, + 1565677163447707385ULL, + 9978873577464002596ULL, + 13469443074709994181ULL, + 17017393736489808841ULL, + 8321846318555797701ULL, + 17355302697305045648ULL, + 3052898904478642131ULL, + 10728845600359411807ULL, + 11686290573098779498ULL, + 17864909136257103421ULL, + 3658226700487746708ULL, + 18433423412091991310ULL, + 6313407596167689472ULL, + 10655812597886881011ULL, + 5587757055504539876ULL, + 9692781163831519959ULL, + 3873472159305395777ULL, + 17424803364530514881ULL, + 5569707002485831617ULL, + 11731100666434668772ULL, + 12314141709576052921ULL, + 12779017801620469422ULL, + 9262737126758588114ULL, + 11643889080172724638ULL, + 13641549350662110362ULL, + 14516738264171435997ULL, + 11141389297303717327ULL, + 12905028766653646413ULL, + 5671042608188196767ULL, + 11532430280790594740ULL, + 1524785705218969506ULL, + 16058961597741689543ULL, + 15412431887928694393ULL, + 18006451599642382283ULL, + 4017531313153286421ULL, + 10888754748944015939ULL, + 7908763798745619633ULL, + 14723435695223835123ULL, + 6380734279489634967ULL, + 16927532337735840731ULL, + 11188313971630249182ULL, + 15457282681274900424ULL, + 13395214388483639216ULL, + 14885393568221452071ULL, + 3363894207013647327ULL, + 14351604798417885442ULL, + 2230987822262875618ULL, + 11374879332573497175ULL, + 2477435580170083074ULL, + 16618878754375652664ULL, + 749042764351331073ULL, + 2392214210795849860ULL, + 98418162389024740ULL, + 1033013147279125086ULL, + 7555770972525310785ULL, + 15992989774920148693ULL, + 8421650439962956757ULL, + 8424155562149445308ULL, + 11821424167401295158ULL, + 17188492148790016259ULL, + 1910524360901147292ULL, + 8988152900547091279ULL, + 5642689966605296049ULL, + 14176399897830537152ULL, + 4096007346985776059ULL, + 15434311025914087995ULL, + 2974480465513236286ULL, + 5360615879374641649ULL, + 11788053567052889511ULL, + 15711084313683380087ULL, + 5334633940892836339ULL, + 11906215312471382929ULL, + 4961249573480143854ULL, + 13418125206297571561ULL, + 576494801130289943ULL, + 14569435191865285623ULL, + 174084099623945598ULL, + 1041034568127340859ULL, + 970142468904520631ULL, + 18244470981656644758ULL, + 3558374455201115703ULL, + 17955447225672144569ULL, + 572118659426778671ULL, + 14424447534115148244ULL, + 906344390579189143ULL, + 12928526241330850994ULL, + 8108172998856684499ULL, + 12108422568520797833ULL, + 2662252276124038301ULL, + 4184864875587834516ULL, + 10601241086605648635ULL, + 13339721442567348858ULL, + 2822052306154029789ULL, + 18221274498143252920ULL, + 4963657482882761003ULL, + 16584718311439478492ULL, + 4642850212652705219ULL, + 13429746308502707994ULL, + 5725167548648427552ULL, + 8280625472646068860ULL, + 8064375240572144405ULL, + 12419783746431642963ULL, + 452979812895651827ULL, + 12335534585772727239ULL, + 1579551317899844669ULL, + 17014669247735779564ULL, + 11660024683732604444ULL, + 12832549890660855781ULL, + 14300568273511587741ULL, + 15942822521362225791ULL, + 4867753655887522537ULL, + 14158479222202549233ULL, + 8123407844406065852ULL, + 12872537487568165338ULL, + 11868428670843948301ULL, + 17841091754090419876ULL, + 1613436748603504298ULL, + 4193526094085009214ULL, + 11786508326089090701ULL, + 12297035343054294038ULL, + 5562061998278424833ULL, + 14001478691726549447ULL, + 12603347436162023624ULL, + 15396227727670677390ULL, + 15014817946453356327ULL, + 18387826797946767925ULL, + 1598035411298025577ULL, + 11400752703441686971ULL, + 6411508238470335215ULL, + 17470875644932585672ULL, + 11576894051948901228ULL, + 12145585861986187628ULL, + 8100026084849633778ULL, + 17711013042951534661ULL, + 7603878233376954806ULL, + 8787907778473770170ULL, + 9032248981747239649ULL, + 18137087766712008799ULL, + 14435387188346988590ULL, + 17530182379893202791ULL, + 6934658968876339928ULL, + 8123617609285080848ULL, + 1414607384337201483ULL, + 7005352675947896896ULL, + 1818425092374741768ULL, + 11621175780482998797ULL, + 329043453809029403ULL, + 8158277674911417760ULL, + 1377221316131897037ULL, + 12057536669893762140ULL, + 1601543634951771480ULL, + 4628422042589312004ULL, + 4547584754921971871ULL, + 13545633398708169761ULL, + 1361824761992813881ULL, + 1530912350838170506ULL, + 7585689943279618929ULL, + 13424135408495974151ULL, + 2999946873506185955ULL, + 11793593652607205018ULL, + 4243792896234385878ULL, + 10463854805697021640ULL, + 513503179522680378ULL, + 14478568584746625668ULL, + 4774848568913076691ULL, + 11823232564224279476ULL, + 4450490104714071905ULL, + 12110872557364295600ULL, + 7719791271312930700ULL, + 16264575886858760012ULL, + 7384237401835085297ULL, + 16320781269373166360ULL, + 7198496454176871447ULL, + 17946775529133740368ULL, + 7330382614709629517ULL, + 11026004327305562426ULL, + 7351606581246467046ULL, + 7539940970658753465ULL, + 1527509949361899812ULL, + 15662439534112950055ULL, + 7126614805620896675ULL, + 15193868152839747417ULL, + 3522982518723493026ULL, + 14368344917465796993ULL, + 3582796363389954871ULL, + 12660455297163492505ULL, + 2699922508003706536ULL, + 8563008221198205404ULL, + 1582215934957874139ULL, + 7464429036805437763ULL, + 2324837371369430695ULL, + 12537349437580694830ULL, + 1714821319228942653ULL, + 6116217202660805360ULL, + 8724164579998671087ULL, + 9925340800540874683ULL, + 6296471531029836246ULL, + 18417468920499950944ULL, + 11184996981946753157ULL, + 13694313226928793710ULL, + 16424832829136498862ULL, + 17258876679836368124ULL, + 324368956838519013ULL, + 7395202646662243153ULL, + 9382355378686562112ULL, + 17075458524961829855ULL, + 12331552955058399579ULL, + 13540212956006860668ULL, + 11839011931784568895ULL, + 12794260373023790067ULL, + 9132156980530410594ULL, + 11686319921388185272ULL, + 9726270239966554414ULL, + 15559416258709224247ULL, + 3894151844366648806ULL, + 12379745764337914866ULL, + 721329012115732224ULL, + 2580053524276777376ULL, + 6926486152939650797ULL, + 11715676150715706843ULL, + 14115025603823061579ULL, + 15895248608003538116ULL, + 6109834696689617971ULL, + 12139082885613365546ULL, + 18066070087240207342ULL, + 18204189940969330538ULL, + 8708707902220926875ULL, + 12239239041039873646ULL, + 9709082295549054018ULL, + 17573051840638067846ULL, + 11182204287658804397ULL, + 14781939715459316358ULL, + 10265762791199356061ULL, + 15486622828249904418ULL, + 622923333170324907ULL, + 1818719535472570735ULL, + 9799094743201582240ULL, + 17737707712020444379ULL, + 3496406828666797073ULL, + 16735798671366780012ULL, + 1156757217504203978ULL, + 15624085053599788309ULL, + 473399358549218612ULL, + 13773575028192377167ULL, + 3409210534356194936ULL, + 14310132893953058568ULL, + 123471037922225609ULL, + 5088814295342051763ULL, + 4482525106825832759ULL, + 14757879867410702195ULL, + 883976245468939458ULL, + 14636486038675507208ULL, + 4472157222850160933ULL, + 6091261559029898729ULL, + 11855328968870173087ULL, + 18042286152291102160ULL, + 9752228751537656218ULL, + 15412811151420451038ULL, + 8238688248110810718ULL, + 9391187543488332786ULL, + 388673946624316574ULL, + 15072505400344911787ULL, + 3061524090031461032ULL, + 5457144598041698221ULL, + 379775832595064689ULL, + 6352299734066131632ULL, + 1453907869037395954ULL, + 14482575935743951107ULL, + 38281513702525746ULL, + 2419889699903888045ULL, + 4457851442911301244ULL, + 5033339066676868119ULL, + 2391686895435242544ULL, + 17199030058142405188ULL, + 753679564764796312ULL, + 3373926720157527971ULL, + 4001554122135408106ULL, + 16634137795381184985ULL, + 225257752513897317ULL, + 7409943778648775978ULL, + 2937730178601377096ULL, + 12742781119589527292ULL, + 745772184602023374ULL, + 10986178379576121586ULL, + 195868952644897561ULL, + 4692781033105233864ULL, + 10210219276546184612ULL, + 11310553343372252718ULL, + 10237401944997067071ULL, + 14236190647962608454ULL, + 10758107167276987738ULL, + 16009713400575113153ULL, + 3008405565910100093ULL, + 16984321611346886550ULL, + 16768126874457806335ULL, + 18432257137898496094ULL, + 6373735382196877547ULL, + 9862014811101777523ULL, + 3183312192704393665ULL, + 15311417827950227064ULL, + 5123251151131731724ULL, + 10514723534449721489ULL, + 11659137053919980556ULL, + 14848502851824441929ULL, + 274758548623473365ULL, + 5342817438548560487ULL, + 917457112976024281ULL, + 14006275339071011577ULL, + 1043968285000644372ULL, + 6298671063603832058ULL, + 6884326227927878188ULL, + 14494687967541827525ULL, + 11794254078206850506ULL, + 16371370633510221349ULL, + 287392500463434925ULL, + 12848112043848883976ULL, + 344074449642710658ULL, + 5898419256059216043ULL, + 6952441940572993832ULL, + 17180739862900579901ULL, + 3262610313157558237ULL, + 6501922722236281663ULL, + 6243891749677255591ULL, + 9168003259331169371ULL, + 324450588097947356ULL, + 14609620206534750046ULL, + 8408270607034763577ULL, + 9921145198384866295ULL, + 10896720621729710206ULL, + 15886240470671108582ULL, + 7750868406307888386ULL, + 15304190294947609231ULL, + 9705138304948894358ULL, + 11939195825772484641ULL, + 10052558015784435702ULL, + 16750593769549631829ULL, + 4344168812304269940ULL, + 10522030483524362040ULL, + 6266948128430081412ULL, + 11994992603421652175ULL, + 10868797812519924312ULL, + 13381274702969060418ULL, + 5635077105835922096ULL, + 10158227936256698046ULL, + 7855474713561232438ULL, + 9588842372601755858ULL, + 3168340019112274585ULL, + 7835657888080894382ULL, + 6234388085256568934ULL, + 10623469753243808688ULL, + 7230454499071638681ULL, + 17091992466933061771ULL, + 11623436225439928697ULL, + 17755287285685643264ULL, + 6027826241580464148ULL, + 7937299854515878420ULL, + 8859942598114679691ULL, + 11692509888780458832ULL, + 870438714395647933ULL, + 3136783535757285200ULL, + 3913304352359710738ULL, + 9485186580220466297ULL, + 14872669671594587094ULL, + 17867603619657550254ULL, + 3684041810356429505ULL, + 13360249630569589983ULL, + 3120064614730888238ULL, + 16943544395553718729ULL, + 11420857691457472546ULL, + 13790718326619640099ULL, + 515839942705265585ULL, + 11208691199277450250ULL, + 3856674654730802558ULL, + 6517990143818381391ULL, + 8585724134795884874ULL, + 12594128783953341906ULL, + 6187923269606094780ULL, + 17395570779435073206ULL, + 7368887307508219068ULL, + 13856732168257674342ULL, + 2754240758989044149ULL, + 17335675846609294632ULL, + 9417630690546039574ULL, + 16028973125879741180ULL, + 8889901553505146877ULL, + 17244822840247684447ULL, + 2287798503973179620ULL, + 10633061558909393609ULL, + 14488775320994451660ULL, + 16074552724475125428ULL, + 4608575407859406502ULL, + 16386811593740610383ULL, + 2868375305303088098ULL, + 15131883231985428266ULL, + 4818766209481227043ULL, + 10852381057145554668ULL, + 9698973179852794425ULL, + 17823779420512080231ULL, + 4101339296927460588ULL, + 4270244603274713359ULL, + 13121212663256805692ULL, + 17039608497168451518ULL, + 1173883546726693014ULL, + 7526664435412404052ULL, + 2972886431448831950ULL, + 8954325249602430917ULL, + 5620702883886216140ULL, + 16225420630546359969ULL, + 10976319878364004276ULL, + 11979119318535923986ULL, + 11869285133510471714ULL, + 12421701154531857333ULL, + 10122904883064480167ULL, + 16978689497636049982ULL, + 3862283306333031196ULL, + 9547376503223324124ULL, + 5334232813508945986ULL, + 17971330531479868247ULL, + 42613143110576712ULL, + 401328657957706840ULL, + 3200008158267549019ULL, + 7382391018712296497ULL, + 380461174460908800ULL, + 1972393635348586799ULL, + 3762125159222895607ULL, + 17203237478787038124ULL, + 2946579716771967161ULL, + 6442034037065878834ULL, + 12664408109620903403ULL, + 15163539793622459022ULL, + 712815935776743063ULL, + 17994772683638767844ULL, + 4360352829614139282ULL, + 4920648973426643295ULL, + 5785426389397360463ULL, + 17010357492569371114ULL, + 9551085539728382007ULL, + 17287944103811991873ULL, + 2595911882773117697ULL, + 10415687048245292220ULL, + 10319370414766969776ULL, + 12630919555934983169ULL, + 13882774854139165792ULL, + 17113123967512201648ULL, + 13267437741465250754ULL, + 15682440529042329261ULL, + 9936822802653324670ULL, + 16646957419989067978ULL, + 3536743404914425692ULL, + 3644045115732367158ULL, + 405537041669072209ULL, + 3660163373862494303ULL, + 8994804409666166898ULL, + 9515887515526937788ULL, + 3171216154222194632ULL, + 16357489386978787688ULL, + 8520009740332757709ULL, + 13745074946779300697ULL, + 2155177536025345089ULL, + 2744282773133655987ULL, + 834423305172105255ULL, + 4127603111852667651ULL, + 12593414067457811123ULL, + 17242806764388652516ULL, + 12061790724762485141ULL, + 13087976602329123400ULL, + 11274122420854885393ULL, + 15947221261697663941ULL, + 4304708996023027003ULL, + 12101681384315130797ULL, + 11050469242000165855ULL, + 11253694920397026500ULL, + 4744085040278347873ULL, + 13163543495978770449ULL, + 3188741544084693028ULL, + 15604933590392195198ULL, + 4462449251188240894ULL, + 13489390966826966924ULL, + 8303978031838261118ULL, + 15091461323702112444ULL, + 1378871346488174218ULL, + 17538132437356034540ULL, + 2624168570743885151ULL, + 12855025033510600204ULL, + 6089441831278973490ULL, + 17605677889174594795ULL, + 1708032608360116096ULL, + 17062387535728798161ULL, + 3954662292747917648ULL, + 10656251449910382355ULL, + 2217860590449906285ULL, + 3690114302490721050ULL, + 7291735267433078386ULL, + 12052570002423967752ULL, + 12010911026467352285ULL, + 13887808407912724285ULL, + 13415919122299803198ULL, + 17048744778879625152ULL, + 2604118945122139300ULL, + 8626118235468428776ULL, + 15244878875684270188ULL, + 17557764822330026971ULL, + 2063601746424346264ULL, + 11637718474673822760ULL, + 8798240045414950221ULL, + 13479817193151868190ULL, + 10329695886791916326ULL, + 13939726972681111519ULL, + 7318256117829242966ULL, + 9292450674127966697ULL, + 2819489574293300310ULL, + 6902258727664275801ULL, + 1574859931879568856ULL, + 8288101076299013259ULL, + 12832251079797215069ULL, + 17665945657079451774ULL, + 1894503319649063271ULL, + 13117438831431921246ULL, + 6777100474434364604ULL, + 18229839451024275944ULL, + 9857503589982918700ULL, + 12539018170684940094ULL, + 6772265330569910975ULL, + 13188874777913826695ULL, + 10984508524200669287ULL, + 12408417573928951075ULL, + 3560769985985865440ULL, + 18147324123695970078ULL, + 5501318070787849178ULL, + 9002048825438516593ULL, + 11212291087918480708ULL, + 15144483045586157854ULL, + 4296436862932804011ULL, + 7257512178499894874ULL, + 4695763393347275827ULL, + 16262727526952028124ULL, + 3198839375328188791ULL, + 5218105954384380077ULL, + 12496697343544529401ULL, + 14359183278214088293ULL, + 8253303593351411428ULL, + 11757991701773038353ULL, + 15697867284446271005ULL, + 18017716132767492735ULL, + 5904958711868213691ULL, + 13412189325913685331ULL, + 2922847819283370456ULL, + 3253245925598708162ULL, + 6588071589702174639ULL, + 13671996947352960204ULL, + 17189739687636693986ULL, + 18099789595864308261ULL, + 13815909061908072729ULL, + 14287663181952891376ULL, + 4874229668687333325ULL, + 14958206435548469419ULL, + 7657298048887279380ULL, + 13148334580555821240ULL, + 14880302699191675451ULL, + 16612604320617481336ULL, + 4945689699500212181ULL, + 17525065968691582831ULL, + 542767441903914390ULL, + 7846426119548645861ULL, + 3251954107823418827ULL, + 15693880794516519461ULL, + 654561036123234218ULL, + 10315346972656448868ULL, + 7050313331268741666ULL, + 16302222679317379031ULL, + 2883713622112540638ULL, + 10011922888896710823ULL, + 13161115662199601330ULL, + 14238707959810438594ULL, + 3554857204201190421ULL, + 8562525110428503814ULL, + 5689737639467133206ULL, + 8696709842614192884ULL, + 9566814272132760480ULL, + 16643708838992971613ULL, + 6140785365329584301ULL, + 7470282102971318652ULL, + 4873483133690187153ULL, + 6852044021125533322ULL, + 3948367628769617526ULL, + 9387934001198127473ULL, + 5182654035507276805ULL, + 11149703646893914759ULL, + 3597896556708661316ULL, + 10508230929887020018ULL, + 16137885853644348571ULL, + 17849271415667791280ULL, + 2809213179163999970ULL, + 16767660637389593487ULL, + 3407569792990564621ULL, + 10630884077082081828ULL, + 4911032142950127328ULL, + 7935750039919613891ULL, + 5622851687518937034ULL, + 15577993365780365904ULL, + 1456399389011126390ULL, + 5928422759070696085ULL, + 960447180314684192ULL, + 10235372211374020744ULL, + 4741117846302211367ULL, + 16170251952274779107ULL, + 4904996800751841645ULL, + 6864850481883701264ULL, + 6597021932511276059ULL, + 7802396601379964607ULL, + 37213376597905795ULL, + 9960950998719807792ULL, + 13199157148405932627ULL, + 17688559721663617411ULL, + 8932898865137241023ULL, + 10577535935144748982ULL, + 165515925683308676ULL, + 8142200471593933026ULL, + 15675515871511930268ULL, + 17137940649723110529ULL, + 9378250979437317068ULL, + 17406193680812833900ULL, + 12451813564217872566ULL, + 15174986717485373420ULL, + 11269737279288737282ULL, + 13267946161116994911ULL, + 13121927376538247391ULL, + 13996125872994912084ULL, + 10693460740170976836ULL, + 14500419413534381441ULL, + 895037984800335253ULL, + 6547817751838016973ULL, + 5156446304513327246ULL, + 8832178523478395708ULL, + 8734852219763111594ULL, + 17523817086686565268ULL, + 2213040420645686783ULL, + 12845017805629054426ULL, + 6254043467115120261ULL, + 10980940297148938060ULL, + 3766919260227607972ULL, + 10497741432205526515ULL, + 5301428702458417619ULL, + 11203575824711644690ULL, + 7385135262933789302ULL, + 15475776528978567069ULL, + 4105428993309760888ULL, + 11745448303069620721ULL, + 9583069005981379019ULL, + 14331964928642222167ULL, + 9885350890547538013ULL, + 10360100469941760645ULL, + 3235469832744245200ULL, + 10778938149779760289ULL, + 15577777063788114475ULL, + 17070111144485443464ULL, + 10019749318855586930ULL, + 11799672101576821709ULL, + 8513296831445852705ULL, + 10551333950558088170ULL, + 7479573000585398823ULL, + 16172289894994536688ULL, + 2511105992642876229ULL, + 14123120660961691043ULL, + 14181289202495000957ULL, + 15975396089053789862ULL, + 5598716239090096231ULL, + 11901490170114074394ULL, + 1533970284249374052ULL, + 1550394675378507110ULL, + 684882829548635456ULL, + 3602582388730886150ULL, + 3424328564371506719ULL, + 7325002940611763115ULL, + 2080640763959717752ULL, + 16122878554512427496ULL, + 3756001449999970435ULL, + 4421658161081905113ULL, + 1404309665254150968ULL, + 10413842387525557592ULL, + 1043963281247752009ULL, + 18163241234343861047ULL, + 1154313103667872106ULL, + 1408343110655421720ULL, + 13045365088068966161ULL, + 13158988592157636234ULL, + 8454082356235168750ULL, + 14266557794002733698ULL, + 1788261227300237284ULL, + 3426758348788564070ULL, + 15973069154744618900ULL, + 17875832737439219706ULL, + 7861410345504071331ULL, + 15502651524391850556ULL, + 4274201906345131566ULL, + 11663643446851213764ULL, + 14562268374483750938ULL, + 15265123477554606824ULL, + 12599419472891955337ULL, + 18412435206759134383ULL, + 14096744749503105549ULL, + 15331174766786254433ULL, + 10922459062098750203ULL, + 13507331311202957245ULL, + 1191252506720521678ULL, + 13204442964805429191ULL, + 4696142242751131907ULL, + 13832040274166009825ULL, + 3634935076257127417ULL, + 3887534569972426021ULL, + 9985639187105722665ULL, + 13867885970356179395ULL, + 7162120224185115001ULL, + 18438944648418258302ULL, + 9119056369810027273ULL, + 10556592364571446703ULL, + 14752726465053334574ULL, + 18003555374889179459ULL, + 4105428993309760888ULL, + 11745448303069620721ULL, + 15766504060922805151ULL, + 17420365250743708387ULL, + 3280505077448569474ULL, + 12875110465887419895ULL, + 8022473976718448781ULL, + 14493783529554595490ULL, + 628987081687499869ULL, + 5677394968358277532ULL, + 2031811254992868721ULL, + 6764541316398770343ULL, + 3614800008009942908ULL, + 17781708410006508364ULL, + 1180061830395257076ULL, + 16679596269930347375ULL, + 1361394962933774616ULL, + 17867465476128161166ULL, + 3034638865669120362ULL, + 4767479863845780296ULL, + 4604466443214359640ULL, + 12360780250871135524ULL, + 8378368801843682163ULL, + 15436557518118307620ULL, + 3329668892250564835ULL, + 7467556466271650358ULL, + 9603377335903972895ULL, + 14088542361081596561ULL, + 1538997001156284849ULL, + 3884561092702088229ULL, + 4862941592431808914ULL, + 7161019990882760655ULL, + 1567211594284134559ULL, + 16053665460486829612ULL, + 7411682401435146816ULL, + 12847358587189101247ULL, + 1017313297919167372ULL, + 4837977056376848467ULL, + 5865159536792012969ULL, + 11171160157776550219ULL, + 4338596687252747340ULL, + 10535682416336927468ULL, + 6322423186272144980ULL, + 8791342745008004951ULL, + 14886131021350580605ULL, + 15170093636659691872ULL, + 6815328970076760488ULL, + 8842439194224603391ULL, + 1928130387888463871ULL, + 1953032067131950165ULL, + 5636071042546953435ULL, + 9064594189018624913ULL, + 3513286284974603255ULL, + 12080886799021028310ULL, + 2239604178278245106ULL, + 3471394217748511302ULL, + 8420805162309840018ULL, + 13581228879506095271ULL, + 14446526434057206841ULL, + 14821012635538641325ULL, + 14679220114967209976ULL, + 14786717287419638879ULL, + 5701970124727606201ULL, + 13025225375764679262ULL, + 1312025129274764232ULL, + 1653665903944811025ULL, + 775762432450382141ULL, + 16266767097632115770ULL, + 677169583129490592ULL, + 12187136580976420662ULL, + 12900505394526350334ULL, + 16265256399319417748ULL, + 3024256996730697936ULL, + 4699779285870895171ULL, + 1210771413215926598ULL, + 15014053275752199031ULL, + 2602677432843056327ULL, + 11747302991672915990ULL, + 16258957310342219794ULL, + 18333041634248284862ULL, + 419365015678277030ULL, + 4817814412819972553ULL, + 1499321096671792752ULL, + 13986713848337673950ULL, + 11843751767166046732ULL, + 11947763048087583376ULL, + 799187252691945210ULL, + 10801416396882716784ULL, + 13626782850928533376ULL, + 17543209889095884915ULL, + 8987358304072587350ULL, + 17595230776282119817ULL, + 8419635522836460822ULL, + 16462852794210866168ULL, + 15381631760425039077ULL, + 16119801098533523818ULL, + 6592536818055041663ULL, + 10488941970409740192ULL, + 5615175173326790931ULL, + 10970845267066291745ULL, + 10819350265942871199ULL, + 15523141034647331070ULL, + 10937729002795368144ULL, + 12298691157987168442ULL, + 561039068028810008ULL, + 12507846240243583446ULL, + 10697983382526869386ULL, + 15769436749096081376ULL, + 10363686228639548553ULL, + 13380397168891632585ULL, + 14314502115511449919ULL, + 18071155754901400100ULL, + 5716798304443835667ULL, + 15210697492016661273ULL, + 17541139647272565392ULL, + 17667133901055536322ULL, + 2213094752377096016ULL, + 12311368325695268499ULL, + 3328787416874279754ULL, + 10912486260649761039ULL, + 15931893791694177113ULL, + 16266201769779344281ULL, + 3828426243115804174ULL, + 8554528299412685655ULL, + 7927703247469901937ULL, + 9053714706369398654ULL, + 319391177516281174ULL, + 10616593653593755029ULL, + 17258800363113768ULL, + 11306116174815097830ULL, + 2956410117832413330ULL, + 11881696793645196140ULL, + 8551914970542682268ULL, + 16273704242111446640ULL, + 2638622575823726924ULL, + 9452529693507068247ULL, + 3704457422415501358ULL, + 6231998785652088013ULL, + 3708015302323247462ULL, + 17432768974096000063ULL, + 1251813580384104610ULL, + 1923298098147850400ULL, + 5269087332221059722ULL, + 10182077941491372120ULL, + 4799192837324485598ULL, + 5847939450194419254ULL, + 5721640326490741756ULL, + 10024657322836723010ULL, + 4200123654446803829ULL, + 16925849091712275968ULL, + 6101645778751742556ULL, + 8871409209395527033ULL, + 4995382881263170663ULL, + 11495114402589559420ULL, + 5044991705157013397ULL, + 17348450979580013675ULL, + 7636035293512731749ULL, + 17533333146686885496ULL, + 8856438943924868268ULL, + 12062635091429540058ULL, + 10765088745832611522ULL, + 12032067143006998822ULL, + 8578668695533656982ULL, + 17527422018624911441ULL, + 9753201255130391617ULL, + 10761341710169889735ULL, + 1425024429147040094ULL, + 10232622424663557028ULL, + 10851238138319174870ULL, + 11265882876583782728ULL, + 4062064121651945266ULL, + 11461575332009072605ULL, + 2229223741155940689ULL, + 14676043719862154891ULL, + 5594993642241610189ULL, + 12086980816351107041ULL, + 11411916596045266261ULL, + 14218660027636909534ULL, + 7303706622830141018ULL, + 17767119532285196947ULL, + 8108915810260811781ULL, + 15640559434877335245ULL, + 10245183651123140353ULL, + 17588343251304135078ULL, + 9928151900951691193ULL, + 14912980625347666647ULL, + 9904508102073023325ULL, + 13661241921457930609ULL, + 3929795659270623722ULL, + 14924906189567836816ULL, + 5835106568443507535ULL, + 8769937080426699953ULL, + 4099752057490688842ULL, + 16531891473596596997ULL, + 2947641076387126339ULL, + 12734214807826187780ULL, + 7185008292006235448ULL, + 10245757499130895055ULL, + 1320736816270253517ULL, + 16958740678686756094ULL, + 10679149797287994012ULL, + 13284371084013862491ULL, + 2228092791263095965ULL, + 12970516567671177133ULL, + 4405346465823232181ULL, + 7581397147784817847ULL, + 2971267943490729940ULL, + 10598007966793741291ULL, + 15867266295684884202ULL, + 18299552373474742298ULL, + 7192101121304890221ULL, + 14955763386507514265ULL, + 4652929592517497706ULL, + 15401836827946180666ULL, + 5201522138004701393ULL, + 13652214915165622099ULL, + 15372454529769585937ULL, + 16968649936534008913ULL, + 2373569879390738918ULL, + 13048893608802938415ULL, + 11413188404027794151ULL, + 11514607506466265950ULL, + 7018788990951394389ULL, + 8090584991627642799ULL, + 8290317394540213930ULL, + 16868140958837683659ULL, + 5410267091626249996ULL, + 10228203918939896516ULL, + 5831400034685214337ULL, + 8347632441554055261ULL, + 11973230379596743886ULL, + 12814337483874901031ULL, + 717422265988022088ULL, + 6669457563750062694ULL, + 9309082423057602539ULL, + 15214240301590758275ULL, + 3574614591830686884ULL, + 11666427106116389939ULL, + 254209793485286919ULL, + 4277552444810989117ULL, + 6244399729885254704ULL, + 14054448566557179372ULL, + 11922553583483885617ULL, + 15533172753812010753ULL, + 5171225572537286617ULL, + 7107209486646425178ULL, + 2270915070312626433ULL, + 16458438554319242426ULL, + 687425134826121842ULL, + 2049246945749841999ULL, + 1378745967837677038ULL, + 2549510778604988858ULL, + 10450775543850108895ULL, + 11876551053038515983ULL, + 1417759031861973491ULL, + 13928098292640806365ULL, + 3767508876557933511ULL, + 5395975148345526278ULL, + 10676582033037315594ULL, + 16694434812183239773ULL, + 9887123563039386857ULL, + 11616246531555683872ULL, + 1563708079878070404ULL, + 14088948432820641360ULL, + 9886992075994798068ULL, + 17761780731944170405ULL, + 7136404435860530313ULL, + 7435550789076413339ULL, + 4926968004606713584ULL, + 16785834894830777823ULL, + 10068773339038831935ULL, + 11195832681501061002ULL, + 9745312101427624234ULL, + 17868856758210450266ULL, + 4496992938760192509ULL, + 6867812906899778682ULL, + 8304776705453001112ULL, + 9803131673216617444ULL, + 5189134731113004592ULL, + 17560568764949857772ULL, + 2550722135135755854ULL, + 6078295225287885875ULL, + 3892066534262448694ULL, + 12945062861245381500ULL, + 7861278869233711260ULL, + 15976393999950694640ULL, + 17501008779870482952ULL, + 18407767142199556947ULL, + 59832681690582484ULL, + 4902549229925572300ULL, + 15574130662838519708ULL, + 18133842571553532814ULL, + 15718985223300429776ULL, + 15830409636100854444ULL, + 11675026084540066161ULL, + 11705919134740213049ULL, + 5108890375339942298ULL, + 5983746863253828920ULL, + 16393097933936085287ULL, + 16951430634550233447ULL, + 2036279252660543524ULL, + 5526391671350539005ULL, + 10375155772394161970ULL, + 11823970980495411907ULL, + 8235106483256158726ULL, + 17546507545637001057ULL, + 8795590165145612814ULL, + 18169393264707502954ULL, + 3917958354232147805ULL, + 5650496039889604176ULL, + 1356354796146494543ULL, + 12971383074365378011ULL, + 750482068332870870ULL, + 18195391492995978921ULL, + 8706779472809173161ULL, + 18203058239762306363ULL, + 8953885583951377535ULL, + 13564869447158180019ULL, + 3545416403056803165ULL, + 9346047279081844093ULL, + 8420812448380614945ULL, + 9748643986925982381ULL, + 5642913488910445742ULL, + 6241659191426470022ULL, + 1273675234206863996ULL, + 2061186951445894219ULL, + 718436210717933806ULL, + 4403186654682071504ULL, + 14481904904131241318ULL, + 16912081184451137046ULL, + 13063453846925189ULL, + 11694444380739629757ULL, + 760228705757512814ULL, + 10157663360597962467ULL, + 2749011743495884908ULL, + 7224332565429263399ULL, + 11366913625085880131ULL, + 13751330877024314220ULL, + 7304865484455372395ULL, + 18000573153651236509ULL, + 9774447958977040259ULL, + 12027864055371376107ULL, + 7347523676289909131ULL, + 17755476729467894656ULL, + 78505289996979127ULL, + 7072582004470304055ULL, + 9857328076287259694ULL, + 15213311271697471662ULL, + 3415155878669903804ULL, + 11778479995496717137ULL, + 6225708545929366685ULL, + 7617230455798250346ULL, + 2741377305219482425ULL, + 12628807300863819168ULL, + 8249619675412665382ULL, + 10098302912551725555ULL, + 5911979553238896216ULL, + 14242104918081070028ULL, + 3796315478183091943ULL, + 13308786686956128875ULL, + 1913405057903640827ULL, + 4069641533439229559ULL, + 10603304095853879870ULL, + 15168473757250040436ULL, + 761453951835145544ULL, + 14289489715837727622ULL, + 4830319238434383044ULL, + 10649428592829957377ULL, + 8942540177615403593ULL, + 13589704015584671424ULL, + 14043856227940208228ULL, + 16252996375960286349ULL, + 6029739876133105583ULL, + 12885709098025482787ULL, + 6159277686001198374ULL, + 9452110549763881154ULL, + 11356811871819469858ULL, + 18304398860499571564ULL, + 3498292171610415087ULL, + 10563770787289907878ULL, + 6149929820397974072ULL, + 16973902195543747278ULL, + 8645259455844608235ULL, + 10188572707354897754ULL, + 16297064615030160328ULL, + 17308666274138505566ULL, + 7569945718688795921ULL, + 15882071227806260147ULL, + 6272183480230453653ULL, + 11497964209686750004ULL, + 93594116204837224ULL, + 8471852142732087873ULL, + 3784883367874759416ULL, + 16999555425883570250ULL, + 9178256058365419535ULL, + 11210215229802008332ULL, + 13453970662154905214ULL, + 14652768649537111267ULL, + 1825763472608027446ULL, + 9702286925354500417ULL, + 1289690434797595052ULL, + 1492517259231415805ULL, + 7885145269633660948ULL, + 15055194644058003825ULL, + 5695793529055770798ULL, + 15437268366961619805ULL, + 910482064681722821ULL, + 8772321882486014097ULL, + 2044966687482781675ULL, + 2596009506265114538ULL, + 648278693468696977ULL, + 10404174622389712242ULL, + 1846023872063480277ULL, + 12166295869921538437ULL, + 9300159380416507320ULL, + 12803184644972500254ULL, + 2076506207096759857ULL, + 15330926384482553691ULL, + 3009354507966072224ULL, + 18298214339026579882ULL, + 7456991203920453395ULL, + 12352011749190650850ULL, + 11873138404294543271ULL, + 16868209742041622787ULL, + 8315143835254452772ULL, + 15694679663718831749ULL, + 9446671813444054052ULL, + 12466837385504157428ULL, + 2327342930971216282ULL, + 17261172862230044554ULL, + 2147707394226208828ULL, + 5894060924254401751ULL, + 8063008723020049549ULL, + 15672248885997570287ULL, + 9298783805245020207ULL, + 17977488006063241219ULL, + 2751724636285891502ULL, + 13900296867294067689ULL, + 4402905358087431813ULL, + 5936777451076588296ULL, + 6117888695276140589ULL, + 17830145053352581744ULL, + 9074741053139312990ULL, + 16981857148448186164ULL, + 5335246422407577753ULL, + 6417529635032216316ULL, + 3064206149977639162ULL, + 17246114441220534588ULL, + 2156254969536042040ULL, + 16850912026465206173ULL, + 1180273425986285962ULL, + 14299337544627271040ULL, + 402430523454782753ULL, + 15238763006468762389ULL, + 5620462450763991480ULL, + 12252532121271382151ULL, + 3651987577881117362ULL, + 9615036175441726247ULL, + 8327586762767311215ULL, + 12767543016895751719ULL, + 10673153598421379451ULL, + 11557935961890261846ULL, + 6293634325866396414ULL, + 6621295742152502801ULL, + 1177735922802453573ULL, + 17886639198320645642ULL, + 527943075084955235ULL, + 7223015207980014513ULL, + 8904661670311098222ULL, + 16421158603910444148ULL, + 17582108700156192939ULL, + 17976697538217370242ULL, + 11678262422031988870ULL, + 12209502242993290954ULL, + 1424101699730831546ULL, + 4768089629443759220ULL, + 652962732812998378ULL, + 5482125596604883147ULL, + 11997331674124738966ULL, + 15430091375080963166ULL, + 4651241883975426740ULL, + 11000044251076583101ULL, + 373819546778608967ULL, + 2551774542686962505ULL, + 9852435899023120958ULL, + 13683776078902448040ULL, + 468270676438410231ULL, + 15982905814419609333ULL, + 7356144319093835033ULL, + 15630696502787667507ULL, + 5944250471099107141ULL, + 14159508103935597610ULL, + 12026178723223376500ULL, + 17587692647426218607ULL, + 2049284517831181859ULL, + 3001271083078114356ULL, + 2560637438351276158ULL, + 3964265468292835054ULL, + 9134165137635412661ULL, + 15179699518868393476ULL, + 2868542270897147229ULL, + 12765273340435895726ULL, + 1725524618951022919ULL, + 5330028520014919955ULL, + 9521979522258806555ULL, + 14788173345062546380ULL, + 449922960305229212ULL, + 8319641285052642171ULL, + 11347256998272531687ULL, + 17925790080953292341ULL, + 7417232395828936434ULL, + 11477824533486409713ULL, + 14477164463420271384ULL, + 14882268894127652142ULL, + 8450110299261636616ULL, + 13025488198379387727ULL, + 12684462272199858463ULL, + 17205473402112854618ULL, + 7125515707094404092ULL, + 12172624167152673540ULL, + 11411594609788369080ULL, + 15584531626598358444ULL, + 2622414368899243974ULL, + 3668764946365809178ULL, + 6784655195694050706ULL, + 15857235238117351591ULL, + 5754873849819321924ULL, + 16438181561190445933ULL, + 1199742843434821819ULL, + 6848277363614467355ULL, + 6522252111406683047ULL, + 10463363898399746476ULL, + 9858335093517053604ULL, + 11766824545278824676ULL, + 7231376369401556470ULL, + 17271585975726895089ULL, + 4966020576022490623ULL, + 10298566544077732144ULL, + 5754873849819321924ULL, + 16438181561190445933ULL, + 8485120166818682552ULL, + 11144093048818467862ULL, + 7299901560236645393ULL, + 16743502888462839854ULL, + 4665761783178064945ULL, + 13726136307985976289ULL, + 343290070626590585ULL, + 13181045436974117090ULL, + 7294526597014083974ULL, + 8278629481665738188ULL, + 3300034280457109443ULL, + 4482637828350374927ULL, + 120557129019319085ULL, + 3130802622988955103ULL, + 15438179553489462328ULL, + 15500362746283075976ULL, + 8977995444033201803ULL, + 16544410789111701297ULL, + 9521427179248516769ULL, + 13140966933354578195ULL, + 740830960175569924ULL, + 4011676978197933850ULL, + 4028329111209914655ULL, + 7198101705065857893ULL, + 14766527986054732091ULL, + 15288776408782698854ULL, + 5629687743300467723ULL, + 11655822823524968566ULL, + 4649165826559513487ULL, + 14156913171849236037ULL, + 1611218635054057661ULL, + 10910441125163559839ULL, + 3702414661036098285ULL, + 6505767814472564071ULL, + 12057501229080431203ULL, + 13945074379822894423ULL, + 8025115035240355919ULL, + 17761031492775751141ULL, + 2770425037038159044ULL, + 5483575579333380627ULL, + 13180564409255051042ULL, + 15586795420892317935ULL, + 14276501032411053060ULL, + 15521448080325565920ULL, + 2733903209013183033ULL, + 8912850457284864792ULL, + 6532148221846239677ULL, + 15671517361158666235ULL, + 3879851295743969436ULL, + 12695276273660547657ULL, + 16114483984932847297ULL, + 18018664068343574319ULL, + 7431263895180557573ULL, + 15138644678845977548ULL, + 13376229351037069150ULL, + 16879268318926366679ULL, + 6407522032994459415ULL, + 18298479798349200410ULL, + 2387679961851860010ULL, + 17230066871418424930ULL, + 7369678616576190270ULL, + 8953257235127559875ULL, + 1080562338119892401ULL, + 17012819563338740914ULL, + 12584094720634110178ULL, + 12586364222630799604ULL, + 3328339641184205612ULL, + 4777948815408274792ULL, + 3088944540086084724ULL, + 18413830135384168810ULL, + 2901870624317772224ULL, + 5532568461197006832ULL, + 6049069250193082371ULL, + 13138769664640875792ULL, + 3825057291435233074ULL, + 6562530695388842179ULL, + 14545878834687111837ULL, + 14818164764293777577ULL, + 7323791245418794563ULL, + 17980943133381340229ULL, + 2233781272611018192ULL, + 6600333514831345330ULL, + 1389022012964520609ULL, + 5991298698533618479ULL, + 10631881601895325637ULL, + 17946860800005084485ULL, + 8547356525380181710ULL, + 10490524007129684469ULL, + 13243995742429985121ULL, + 14713518592962339353ULL, + 2069873048245991408ULL, + 7277875139044997854ULL, + 1514174877355636373ULL, + 6716568047716002505ULL, + 13839276197221447690ULL, + 15742060408021019757ULL, + 4251228961455974030ULL, + 8959811022361602405ULL, + 13673784782035435663ULL, + 17199213674079741775ULL, + 1436075269436435344ULL, + 12818956867403848748ULL, + 16463581760691063739ULL, + 17011459927138150294ULL, + 14598483547439802043ULL, + 18269418001770849368ULL, + 10328217859628115373ULL, + 18370794147234336456ULL, + 1628886614292932439ULL, + 8730863813034266790ULL, + 6033844930011274786ULL, + 13698076376847722586ULL, + 8062928185531170643ULL, + 15697892245231442530ULL, + 2060805382779409042ULL, + 3384381001435157628ULL, + 8233769284389597436ULL, + 16565299724162474559ULL, + 2769961977985880707ULL, + 8799177238654534913ULL, + 3586458973719280279ULL, + 13574674652783898171ULL, + 17717634297629917876ULL, + 17847976995515123381ULL, + 13310656535646357282ULL, + 16969090198938415494ULL, + 7633816355716673012ULL, + 9252758083025221368ULL, + 1085380752284836535ULL, + 2598643174861375768ULL, + 14660769729822831943ULL, + 16703616595052884504ULL, + 3227011077102352137ULL, + 9145213797654788267ULL, + 3368413644381716636ULL, + 13955015608611421144ULL, + 1864575562636889885ULL, + 5762145419529335485ULL, + 3536062599496248086ULL, + 7981849505060773192ULL, + 7369331352260498939ULL, + 13697582926119721617ULL, + 6081263676759415567ULL, + 16642666595939550386ULL, + 11040079936360038422ULL, + 12493883441667604718ULL, + 13101916372867648350ULL, + 18359743429559921774ULL, + 6425410546857480042ULL, + 11109623849058412774ULL, + 417154605923653569ULL, + 7029207464762891837ULL, + 12733937503274329159ULL, + 17387897056653172373ULL, + 7212325270261788046ULL, + 7901853943139046117ULL, + 11892530248446568803ULL, + 13579247630908528344ULL, + 14666489919610088818ULL, + 15486917957392520282ULL, + 7167326153540908814ULL, + 13553986662960123392ULL, + 10038854860558284243ULL, + 16484471986825658792ULL, + 11410729540171368490ULL, + 18371397697681518306ULL, + 696332744461984080ULL, + 14466034616530812871ULL, + 1856043775171370490ULL, + 9359244398792907613ULL, + 6444998482619132676ULL, + 14487974256800300917ULL, + 914792593157131040ULL, + 3017952180596955666ULL, + 10521693750816092531ULL, + 14225103397987832129ULL, + 12679548449352857964ULL, + 14630995170094771462ULL, + 754796039502746784ULL, + 8396005035755840542ULL, + 5694146783140407476ULL, + 16018161393341400116ULL, + 10242605270564264506ULL, + 13234550042682461687ULL, + 7389579753346606057ULL, + 15460614060509350581ULL, + 9134374792758158742ULL, + 18105054999475314947ULL, + 2897704162911417443ULL, + 16326374036444867940ULL, + 14299050162142241416ULL, + 14729055761610641826ULL, + 5558122023968935072ULL, + 7977033224815341569ULL, + 11061803271712185426ULL, + 17757782496575196864ULL, + 2908099800082038691ULL, + 11086648171188413063ULL, + 2001497453816112384ULL, + 6807378834065824546ULL, + 3537305928299292037ULL, + 9354747392346301460ULL, + 14060860745115378882ULL, + 17917341050806220194ULL, + 954558234708119948ULL, + 5357272279265523594ULL, + 5290519946024602579ULL, + 15067641282193125411ULL, + 3049657133660926824ULL, + 12419286595170481473ULL, + 15358596302229945444ULL, + 15783986165517700866ULL, + 12549142959038834845ULL, + 15938111255384086047ULL, + 7222444333812018975ULL, + 16117123671160573320ULL, + 15148395721899011521ULL, + 15937052981611454657ULL, + 771691894544337695ULL, + 15732808071276702162ULL, + 6382494246771539473ULL, + 14361503011113043900ULL, + 6551274311935509739ULL, + 12646788775350512447ULL, + 2626892530390333427ULL, + 5832810197957623073ULL, + 3867981237109409022ULL, + 13765000782862118971ULL, + 6775712663692802558ULL, + 16336530951670772705ULL, + 4520874519858982860ULL, + 7254674974105937741ULL, + 16710239929600714266ULL, + 18219794922455691879ULL, + 6197092883583111812ULL, + 15919716045153714967ULL, + 10466851009845181557ULL, + 11695182565019239294ULL, + 2007285910367552362ULL, + 16346110063238976020ULL, + 11411423118125589279ULL, + 13682463721113829974ULL, + 8510822282118891485ULL, + 10758520618348447548ULL, + 11600939946521831857ULL, + 14169719968526243052ULL, + 2170522969782415325ULL, + 11673005578334587316ULL, + 1850126237880474649ULL, + 16205146987786614918ULL, + 2271479735447699862ULL, + 6326740721441889719ULL, + 3447657403195926960ULL, + 14616299369846899320ULL, + 11127565504101840189ULL, + 15588545414118202506ULL, + 11299219783921596809ULL, + 16223569643222111094ULL, + 487468524681622969ULL, + 6459977036964114488ULL, + 4509461363934596932ULL, + 9243496741304323259ULL, + 8585044503396213119ULL, + 12011828616842694821ULL, + 7832345560797405787ULL, + 9006571594626212084ULL, + 9542461733885586436ULL, + 17912556832547787554ULL, + 5032496244215583462ULL, + 11912905966288566419ULL, + 2491684996661921770ULL, + 15335230800451090658ULL, + 15301998727492447183ULL, + 16137448371637728263ULL, + 8830084561014677117ULL, + 15315139250962402975ULL, + 4370995979261772868ULL, + 13790432539107586090ULL, + 1052429233008810699ULL, + 13866290707373917842ULL, + 8685139714875993605ULL, + 12070482100805568785ULL, + 204030110339418797ULL, + 6710253271317442081ULL, + 4244040953865358093ULL, + 17223510197695471967ULL, + 1019313284538440242ULL, + 14267220847836452309ULL, + 105414022015569554ULL, + 13554497482663032831ULL, + 12847879028377404172ULL, + 15526159473266351604ULL, + 319930845578264748ULL, + 3492004048052503242ULL, + 8092114892214644563ULL, + 8254664183252679376ULL, + 678064168790758838ULL, + 8126861361669291279ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 13855343165958644377ULL, + 16090300326686602845ULL, + 5234901492273193450ULL, + 15870357169164895402ULL, + 8119188349283536370ULL, + 14928339402434068451ULL, + 660163740487407320ULL, + 3861087306237632959ULL, + 7550497186031216880ULL, + 10443335691586816420ULL, + 8988821600547985684ULL, + 14439870142259330642ULL, + 16790668845750581699ULL, + 17274199779678985870ULL, + 5505186260740107368ULL, + 6516566394393323042ULL, + 12420685444092129259ULL, + 17719382315627041151ULL, + 1358387869000651403ULL, + 10713635266309955107ULL, + 10648751890926703937ULL, + 18418519283672344008ULL, + 4460760219819991388ULL, + 13506806677242191201ULL, + 7754668015695373722ULL, + 16151670899289302095ULL, + 2657276438623211303ULL, + 8703830050004946674ULL, + 3450750517739124784ULL, + 11544745401324960055ULL, + 9516592989624276123ULL, + 9766316917004809126ULL, + 144485545979427947ULL, + 597868178916422718ULL, + 1680779384563970885ULL, + 2687084606911270310ULL, + 2097311566034394227ULL, + 3853922938111935115ULL, + 657395217702512176ULL, + 14589569688968839058ULL, + 707886725037718067ULL, + 18031517709705567798ULL, + 5561432562776486096ULL, + 6472824742859429817ULL, + 10412206759930373711ULL, + 15013182736689998552ULL, + 7056081827738046985ULL, + 17825106810165300884ULL, + 477175782227861043ULL, + 4453473022174437394ULL, + 11560897162975762264ULL, + 17927776410663888648ULL, + 7207571615019952198ULL, + 7592286974270886017ULL, + 9547002284650671342ULL, + 11783450703997684814ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 513187002362129947ULL, + 13324480802165712005ULL, + 5367219578890230196ULL, + 17113236742066978862ULL, + 3176671460359377627ULL, + 11625875713394489426ULL, + 11853049979181920335ULL, + 13861889514213202385ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 13702818785361467540ULL, + 15592103307258242474ULL, + 295425748200659461ULL, + 15205806965578301103ULL, + 3078733794521388009ULL, + 12816115108088571881ULL, + 1170587018219974618ULL, + 18222047794261069373ULL, + 3113609064895233852ULL, + 7258047906513415765ULL, + 11354140351391477917ULL, + 14339183633462643487ULL, + 9973820933667199901ULL, + 15671663215472587916ULL, + 1996131924623827661ULL, + 2262034449743008782ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 6658877982802873843ULL, + 14208378316356221553ULL, + 2647932601734061964ULL, + 18313602138525600509ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 11662380207497776331ULL, + 18042198882849497922ULL, + 1323065055939150177ULL, + 5736965899010493176ULL, + 3035678426946535848ULL, + 6600917061211466245ULL, + 11984320686560651489ULL, + 15427184893344764711ULL, + 219270867731183974ULL, + 951448793618780166ULL, + 1764643725640957119ULL, + 5775204849651170779ULL, + 4704671644076660666ULL, + 16751843739349442365ULL, + 10120174753633322257ULL, + 13552064205284081448ULL, + 15172707725336014514ULL, + 15393800576568194536ULL, + 5588309186701819112ULL, + 18388710581811009554ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7294036059393246501ULL, + 13596228335399322765ULL, + 5656514611507861576ULL, + 11703789363112709506ULL, + 12101156628036151466ULL, + 14082721957950446690ULL, + 13567028712707186722ULL, + 14883634557304685226ULL, + 5456641709871407070ULL, + 14614564909070312477ULL, + 10979469397931763841ULL, + 11712855711166225595ULL, + 1680430608613965743ULL, + 16413623483182862994ULL, + 15301660774956880679ULL, + 17848049777288346070ULL, + 9096559894339613670ULL, + 11431190230887238283ULL, + 9518881062945330506ULL, + 16449341644606937034ULL, + 3181513054664995382ULL, + 10412368419401129082ULL, + 904847062793774595ULL, + 7576905415133014730ULL, + 3069882850578191902ULL, + 17490822052170843030ULL, + 11173862057739419406ULL, + 12822008544894151338ULL, + 372586741844929841ULL, + 14112114337297630165ULL, + 7000146899241849858ULL, + 11987464802878461368ULL, + 12013249039846509728ULL, + 17648442266509601140ULL, + 7181156392284046536ULL, + 17994183693921443389ULL, + 2101039901724545366ULL, + 10948013720963135039ULL, + 1235893050754292628ULL, + 1747968551895957984ULL, + 7134696392309182184ULL, + 14166541394822160064ULL, + 3145231414904323297ULL, + 12629343031535200073ULL, + 7678006100846492790ULL, + 10858423567382938072ULL, + 10539784861920261562ULL, + 11090255562756013559ULL, + 204263315559664463ULL, + 4198357338598084015ULL, + 3911326291113446497ULL, + 17057529898719348756ULL, + 4178156448074313454ULL, + 7719881550010338905ULL, + 3619750078589381931ULL, + 4117003784478100676ULL, + 534266410620387703ULL, + 3127822901810682431ULL, + 2869698754024529346ULL, + 7933759720918803158ULL, + 8790745431141795749ULL, + 10508130141249543182ULL, + 7712796756380926171ULL, + 8058490154618347874ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 11770201608285591924ULL, + 11979019474756442057ULL, + 304657865181467265ULL, + 2950924373253244764ULL, + 2569621201739781775ULL, + 8671144966728156038ULL, + 5402771463155187165ULL, + 5417012573197895225ULL, + 8286475510898652726ULL, + 14188601339690098561ULL, + 3995564393502409818ULL, + 17968821460117676862ULL, + 16162097043830863279ULL, + 17170274631207195357ULL, + 14596355873098693781ULL, + 16592168292175997509ULL, + 4933162300647853867ULL, + 8054862226801069796ULL, + 1400596334501814736ULL, + 5241125802659164588ULL, + 8819922372806519287ULL, + 13133949792046268021ULL, + 7140006277097608482ULL, + 10655086965878149884ULL, + 3849917836277450210ULL, + 12069863899663949209ULL, + 4888849677805482662ULL, + 9199671157337374243ULL, + 9208481425872662182ULL, + 17218490116291427935ULL, + 7276133305721361843ULL, + 12493200605237302491ULL, + 11644730871298633638ULL, + 15083354965950560821ULL, + 1003574485633014618ULL, + 11951183201194433857ULL, + 6755963519799736498ULL, + 9622283781627346807ULL, + 4501142454062933315ULL, + 5502343650830042515ULL, + 2409753982597578565ULL, + 9895669528436017820ULL, + 160180209349679263ULL, + 7528170025968598618ULL, + 11489969653347052384ULL, + 15827151265480044025ULL, + 3354581810122780874ULL, + 5085009514635456007ULL, + 16717347317432256745ULL, + 16888191417150973849ULL, + 1403370948268789092ULL, + 2130253501652841495ULL, + 14385153564221911137ULL, + 16352245143912404170ULL, + 16295725904523518605ULL, + 17667491421025089788ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 2086971265547720976ULL, + 18032508336592793442ULL, + 1812080233377957912ULL, + 14192959230861257765ULL, + 1391131290672929203ULL, + 3883549300302455524ULL, + 16540689892087761181ULL, + 17678015400157385000ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 8562629301816961881ULL, + 15967604526845099781ULL, + 1262725512943571917ULL, + 16165793692758132349ULL, + 10828527194898078883ULL, + 15986461889167411656ULL, + 12307948411028882996ULL, + 13130996381667463866ULL, + 7963706678858306995ULL, + 14720043650247835978ULL, + 334791192661790217ULL, + 2629746805257765172ULL, + 8772076359071351860ULL, + 17195488374304044746ULL, + 741486340601082299ULL, + 14303871580602999847ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 668056436643815698ULL, + 5723116695781203793ULL, + 13142250949367528714ULL, + 14854384430654822963ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 5823492045289779519ULL, + 7120781518215231185ULL, + 12829261857893319927ULL, + 16581873980544282164ULL, + 856886039410338065ULL, + 6864175801562003337ULL, + 15050995478377279796ULL, + 15960951278213685814ULL, + 6473434551030371333ULL, + 7350492145604074607ULL, + 8161587237496734278ULL, + 12225884841290636989ULL, + 6065767902481489098ULL, + 7984112716619303673ULL, + 9697978700856424889ULL, + 13069881921543027324ULL, + 8575041973286641986ULL, + 16851302295986097480ULL, + 178497531035751632ULL, + 1134776629452614236ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 354752684946922183ULL, + 11073377310981197292ULL, + 1624557344647275638ULL, + 4314615054802548144ULL, + 7931778101807716205ULL, + 13385396507666135792ULL, + 7247826772308609973ULL, + 18307924334166671050ULL, + 5758532736117625264ULL, + 11191458937226850180ULL, + 14408604018544410076ULL, + 17124970057359236784ULL, + 13359429157890840839ULL, + 14613605013037938871ULL, + 9700176834409918066ULL, + 14149267994737620878ULL, + 11265962551157513347ULL, + 14127537853016806194ULL, + 12416118268558961016ULL, + 13926119029697506855ULL, + 4254356821814454749ULL, + 14143666428763006130ULL, + 4960039389508512134ULL, + 7465652699815723608ULL, + 5519702344300711908ULL, + 11287240010908093012ULL, + 7782481653779938979ULL, + 14044333909434668164ULL, + 17814108657379143666ULL, + 17926739960571757483ULL, + 7868914240512591865ULL, + 13470464870255591162ULL, + 4072979394893548123ULL, + 9118994173270500364ULL, + 1428211889968327354ULL, + 3455176807272423700ULL, + 2522600616962068467ULL, + 3814620934259369844ULL, + 1381178506287611724ULL, + 18066202810530211737ULL, + 2979702412724314657ULL, + 9715960267837294133ULL, + 11332208957278682786ULL, + 13840886104273278127ULL, + 13153987886424962264ULL, + 18355151138495236558ULL, + 2090936690970633048ULL, + 15737279485265327370ULL, + 2272707833960050868ULL, + 13522326832112897739ULL, + 7434440823578655920ULL, + 14239948504570788001ULL, + 3531291529278131015ULL, + 16872627649390664032ULL, + 5758936987223292001ULL, + 17569437358570707329ULL, + 9196155880040683949ULL, + 10903044021617269177ULL, + 2759013285140530322ULL, + 2981202338298945421ULL, + 7974279712457281600ULL, + 17705652034250839412ULL, + 3684174528285542058ULL, + 5390745287121185402ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 11101537072377219843ULL, + 16371828419760459110ULL, + 11840254880681305506ULL, + 14867269818212485187ULL, + 2369638935961711117ULL, + 13691207385535240073ULL, + 6740854647726703938ULL, + 14702206443253863926ULL, + 13387788826095897620ULL, + 13604610580747957501ULL, + 3597266979300465855ULL, + 16956287600381848993ULL, + 3208360348741821202ULL, + 4601562565837328679ULL, + 8102734922290605545ULL, + 16366400399851686876ULL, + 9844402650067532882ULL, + 14018391052570507592ULL, + 1111012099144450340ULL, + 9721375843608841386ULL, + 11862581283979381008ULL, + 15940949885473728937ULL, + 936608274201045520ULL, + 4710075939730805723ULL, + 9662339813921799574ULL, + 14370719970846072436ULL, + 274079190453060880ULL, + 1813040686604012446ULL, + 3216044075124124540ULL, + 11677947110350478468ULL, + 8041803768478839125ULL, + 10793029264446515432ULL, + 14076636186264564106ULL, + 16110432809124072215ULL, + 2544842319630323126ULL, + 3218750802211375284ULL, + 2632152574262991440ULL, + 17458487237153384532ULL, + 1482710073345716093ULL, + 17326682294424179352ULL, + 8937636279460468843ULL, + 9735471400347095588ULL, + 7354698640549396909ULL, + 16458778691756531180ULL, + 10945715952694355176ULL, + 11297341264351192277ULL, + 6553176991538243229ULL, + 7610067120789083620ULL, + 4391657037677928726ULL, + 14557329017161169313ULL, + 1642595348497425915ULL, + 4539533290657615060ULL, + 163076136780222648ULL, + 3976656077149751198ULL, + 12909912898176736233ULL, + 13532365238732367025ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7401079117225413955ULL, + 18433211078019059195ULL, + 783549421181455744ULL, + 2963902703357198675ULL, + 3080563904182535222ULL, + 11681109363970241262ULL, + 15937257145841166884ULL, + 18306645900469967389ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 5046010222722996310ULL, + 8933377349611964889ULL, + 4133958210407230398ULL, + 9390097688159718563ULL, + 3613712636225626149ULL, + 5502969202827361627ULL, + 2076440651576074846ULL, + 8241033049623910280ULL, + 11574062747014378884ULL, + 16482548448999687699ULL, + 14986942976512588876ULL, + 15536145249392330436ULL, + 902031084619373066ULL, + 2712200328632293266ULL, + 4167604316340365863ULL, + 10012269905504217103ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 13257495754795413914ULL, + 16839645060897449196ULL, + 11731218870265459152ULL, + 14035892324846894566ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7258545326244508256ULL, + 9353648250042124589ULL, + 15405243077452434326ULL, + 15964585263932456630ULL, + 8083453259932445002ULL, + 18230105295900942872ULL, + 15166354895326527757ULL, + 15488025107498603501ULL, + 5504190920095759886ULL, + 14146449804274585582ULL, + 3214463329160901765ULL, + 8292935042118535777ULL, + 4684182920463277769ULL, + 12071034892916738065ULL, + 8746318003887690473ULL, + 11527189170045866674ULL, + 2908573650565444579ULL, + 9294433132565008094ULL, + 349272959667650109ULL, + 12390426094553655903ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 2367212620679128400ULL, + 3721377453960975754ULL, + 14335845701550681367ULL, + 15780124137378865257ULL, + 4713267461980970386ULL, + 8486448214715517013ULL, + 11083781632648670883ULL, + 13754496844853014303ULL, + 40658631789516357ULL, + 13781399343778900260ULL, + 10969355855474236537ULL, + 14360185771037017169ULL, + 6665399417637047057ULL, + 15554882604932532417ULL, + 4559374736286861834ULL, + 4635955133034626324ULL, + 6976794496550224731ULL, + 11280535032025372170ULL, + 3625839640924399309ULL, + 4499530131070370732ULL, + 2456112435139062898ULL, + 12646150302193816715ULL, + 1233792601482303145ULL, + 9859984287023445255ULL, + 14926828974450275181ULL, + 15694602548578084558ULL, + 3234361681943325830ULL, + 14765852179855193912ULL, + 16530590346235346843ULL, + 16883163620174184416ULL, + 11138673895761100583ULL, + 11500339275855812563ULL, + 141219743132233655ULL, + 17515274321577767703ULL, + 8811755205787542901ULL, + 14703525517427342158ULL, + 576589594289958947ULL, + 18266602494484813266ULL, + 3318303561317954439ULL, + 6756850042244613115ULL, + 2751364297711752573ULL, + 12416162967556487587ULL, + 4691047931915489223ULL, + 13403682583949241916ULL, + 2814459424753848157ULL, + 3093021889593360507ULL, + 4216679758167721957ULL, + 4667427564192913532ULL, + 6683864826958670458ULL, + 14782969764159450767ULL, + 1562932941712341167ULL, + 15007355211784798646ULL, + 8331769371713063075ULL, + 17952571423853746766ULL, + 907741760331007424ULL, + 1475976860295243832ULL, + 9416176360294652049ULL, + 10469574742330653377ULL, + 3688632830187684001ULL, + 12662534225182124459ULL, + 908336504636870905ULL, + 7068653647098181050ULL, + 6983750357893898954ULL, + 17717357764673209980ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 5550447522880829532ULL, + 15205397800915020780ULL, + 1109437096093169373ULL, + 13065971061563934484ULL, + 3794139052430368424ULL, + 12876609108682049214ULL, + 7281537297208994801ULL, + 18260536436993078781ULL, + 8260499151457304386ULL, + 13750458412535915281ULL, + 7776891227212037193ULL, + 16948836935854157917ULL, + 4137936821208407855ULL, + 17647346714541929354ULL, + 7538808209332471416ULL, + 14969433658709106901ULL, + 16019912153560131463ULL, + 17378461771696159569ULL, + 3186017074645005149ULL, + 15547740666931563504ULL, + 8485760732890505786ULL, + 9122257309457042903ULL, + 13951114215492283973ULL, + 16565020515096537452ULL, + 567810458286151072ULL, + 4022102380034231345ULL, + 9851576551063461895ULL, + 12663628122873637141ULL, + 6672106487202206301ULL, + 10112725058614154953ULL, + 6602830086720836465ULL, + 13542447746879421205ULL, + 490225712351594095ULL, + 10913997187683340090ULL, + 7307280673438353914ULL, + 8261251941879060730ULL, + 12900634334213470828ULL, + 18184422178874859513ULL, + 12171925359898780958ULL, + 12274406678794355431ULL, + 3162871562872897916ULL, + 16029617656553988176ULL, + 12001536781209572333ULL, + 17653776999327320952ULL, + 1599431056952607564ULL, + 16056608589482475121ULL, + 12295921299641169586ULL, + 15463168192684088428ULL, + 1087572336028721323ULL, + 7943671715849082234ULL, + 1059384013013945592ULL, + 17572091122543603277ULL, + 1957078319095113759ULL, + 8873747733190582462ULL, + 4140131345976845366ULL, + 10912298862779578883ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 3238777727342964756ULL, + 6166041928845508360ULL, + 14486810932662676522ULL, + 18131054116069328452ULL, + 3210802834271172109ULL, + 16365997058185092242ULL, + 10754160816886071263ULL, + 13436418454993649085ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 4164519548931270077ULL, + 16221452434833067800ULL, + 5218531539970617697ULL, + 16167760103860317919ULL, + 5590956483090155290ULL, + 18140301383810287336ULL, + 612329400392569843ULL, + 14658679329120194764ULL, + 1710203229010103159ULL, + 13544820773664196630ULL, + 7407411694606322443ULL, + 12526120183906875585ULL, + 8379925111009498905ULL, + 14700960439174335557ULL, + 16237375061385382216ULL, + 18081918415903103685ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7569840731160689317ULL, + 13139423747413344873ULL, + 11496442413834766480ULL, + 16283290796516384334ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 5170779083451801005ULL, + 15077323719657948973ULL, + 2138450561134149188ULL, + 16145661394177309544ULL, + 11447304297124326411ULL, + 15957466377657185282ULL, + 16605935364602565910ULL, + 17947633764291830437ULL, + 5158683135044714858ULL, + 13545011556281430606ULL, + 4321718638799193105ULL, + 8142089469720300412ULL, + 11721538989074694866ULL, + 13154785658734609356ULL, + 12883826677070312707ULL, + 17973178794028691862ULL, + 442628019939277522ULL, + 7336797561904764581ULL, + 210888017288046498ULL, + 12828305043342729386ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 504818395941743509ULL, + 3910124900268491002ULL, + 6145880864370492229ULL, + 15153611715548036221ULL, + 11390946851176376674ULL, + 16698609346467367842ULL, + 4993420602878459270ULL, + 10838141763970197014ULL, + 5808120394782415867ULL, + 7136095760912710319ULL, + 3511270396565665389ULL, + 13962662916577387922ULL, + 4431238749048164384ULL, + 7414227265631519296ULL, + 1469102072965129141ULL, + 5373526074189544709ULL, + 1330195146768394188ULL, + 12633980478309223834ULL, + 1833028863927817256ULL, + 12624343091724732119ULL, + 13602060523449595383ULL, + 14872280014715316835ULL, + 5201516708440264198ULL, + 7094164434139819931ULL, + 894026993651912604ULL, + 5278502564754347086ULL, + 3963551956710448100ULL, + 8552273691083357326ULL, + 5247310007819325468ULL, + 11428591356395464535ULL, + 11092231222685363875ULL, + 17569711326488736167ULL, + 2713365039478425838ULL, + 4600955637949497407ULL, + 9859919782146946628ULL, + 10082893689789752529ULL, + 7295859752193608554ULL, + 7377370516218458843ULL, + 2466556315742986999ULL, + 17530657119363139309ULL, + 2611139886687406345ULL, + 10863459745734541031ULL, + 11024182839991033221ULL, + 13454031981605892576ULL, + 2107937015433972879ULL, + 14910830479585039462ULL, + 1039230939077749642ULL, + 8137905064434458259ULL, + 14882383610720354488ULL, + 17890982084991487384ULL, + 1675084622512635224ULL, + 15443013386100768036ULL, + 7605702483346873904ULL, + 14559049671148502812ULL, + 15229623333627692750ULL, + 16054895332276671761ULL, + 9662972452107826687ULL, + 14300573402236851827ULL, + 12655194803318869982ULL, + 15363277747200580273ULL, + 6515388315725992086ULL, + 11968865767312297051ULL, + 9745296919523474129ULL, + 12116972766738390266ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 3250515705286294747ULL, + 18092320137258712278ULL, + 8049096232762142475ULL, + 16042399649052724695ULL, + 8112805938169330396ULL, + 17561736175782839976ULL, + 9321215980819772565ULL, + 17632796443834804101ULL, + 9189304796115887052ULL, + 13462426714219642194ULL, + 11589482998584783802ULL, + 14216312265861942030ULL, + 1507211459788928313ULL, + 13514772411355820667ULL, + 2958835833808074269ULL, + 16672145531265080336ULL, + 6276995055503487493ULL, + 10320053796480403422ULL, + 3297144111577269153ULL, + 12230668791950927138ULL, + 8079228283553256076ULL, + 16002033435601250607ULL, + 10477552649627591981ULL, + 11525592543067983624ULL, + 3582264874160478199ULL, + 16033523839585695199ULL, + 1452613753011699463ULL, + 12832243431197109273ULL, + 2983579718875057928ULL, + 16983142437528734419ULL, + 9811480920323464255ULL, + 11242041702784154515ULL, + 3524171065185505249ULL, + 9155488296761424471ULL, + 2696589762904161702ULL, + 17879552805921092125ULL, + 1686376080884580952ULL, + 1816371770223133668ULL, + 2010727009134998806ULL, + 11914658456996505102ULL, + 4898279001983719554ULL, + 15540892478772512924ULL, + 4767880306295473742ULL, + 8372344477246043980ULL, + 4380925664290035898ULL, + 14913034448288657796ULL, + 17305805708204942843ULL, + 17496455646077859356ULL, + 3868835662098023021ULL, + 6621529207999407918ULL, + 3290111466191547456ULL, + 4381139719028319569ULL, + 3373519763552380685ULL, + 10876751635615334486ULL, + 593268205652216756ULL, + 4220864078564401342ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 2041843466201283011ULL, + 8647697056580672010ULL, + 11426061154850520313ULL, + 17849085926841613485ULL, + 2603456856293535271ULL, + 12689545500844838238ULL, + 5227660259493678739ULL, + 9691245463532864413ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 3601629016493607453ULL, + 10878018787940768740ULL, + 2496123603604594307ULL, + 10052530099568087997ULL, + 4023074456685885248ULL, + 11195065115872771205ULL, + 1388839711130730782ULL, + 4013372603261127036ULL, + 4876720607042224728ULL, + 16153238576234164672ULL, + 1328436927588002937ULL, + 10519583688298246236ULL, + 9137574948325010285ULL, + 14974958786196068102ULL, + 8455012291756796464ULL, + 11324193616094096987ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 6576386428017990700ULL, + 14006097670455741555ULL, + 6374700181940801413ULL, + 9294232254047912998ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 17461779779755471183ULL, + 18206355394954056017ULL, + 10448403041086307361ULL, + 16256851116798362383ULL, + 798708497531594717ULL, + 6848394685740221757ULL, + 6761044895834207988ULL, + 10873579158713776745ULL, + 115247633253750413ULL, + 13505971199021873838ULL, + 1796532739798109501ULL, + 16254805818964682084ULL, + 2215707864644785521ULL, + 16005474032280380198ULL, + 4426141649179798280ULL, + 8168686664268916874ULL, + 9471115230333978354ULL, + 9741091871834913841ULL, + 2408238118728361955ULL, + 4493788350993981410ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 12064758495438557303ULL, + 17644818373318932940ULL, + 8494872881314603701ULL, + 18118078059770124763ULL, + 8620588923728925489ULL, + 13267549555580588065ULL, + 6895488049265966849ULL, + 13336239132841374437ULL, + 5079414026037040450ULL, + 12744050302714163323ULL, + 6861147364622514625ULL, + 8071871111393290532ULL, + 9606577561252297154ULL, + 10680350993079629105ULL, + 8914487154764306276ULL, + 9534582210940819067ULL, + 11259266912982460067ULL, + 16955618183425401884ULL, + 3325784341926629963ULL, + 17588757156026072123ULL, + 2308698587226666752ULL, + 12667664579211037717ULL, + 14495340329947745793ULL, + 17766868508774697428ULL, + 11252898553198847231ULL, + 16141750967268458845ULL, + 3148831240133056016ULL, + 3401224670455388881ULL, + 7945475456669884949ULL, + 13023788535635614141ULL, + 4704241863365523148ULL, + 5186404602008805903ULL, + 4667140240707991402ULL, + 5389052086642465941ULL, + 12477849128828551311ULL, + 18347643249209099141ULL, + 5624542192176096023ULL, + 8137820416163652143ULL, + 647254499100337003ULL, + 12072996442087144729ULL, + 2910938631530264830ULL, + 12321089810994102866ULL, + 7517479562347679468ULL, + 13329521836105907736ULL, + 10071600998111660831ULL, + 12265396107760899624ULL, + 9624401045627814381ULL, + 12947907789261930305ULL, + 965239348146178237ULL, + 11294915653358719500ULL, + 1074546420055046519ULL, + 3044673539991190530ULL, + 13748852314552736367ULL, + 18031842017058414867ULL, + 4907122674315767463ULL, + 15954558195199691712ULL, + 12636204567040455180ULL, + 13585689342544444473ULL, + 1536898843700808789ULL, + 4077802981099418775ULL, + 9410704350212650328ULL, + 11327309812462502397ULL, + 5303774187915146041ULL, + 18173902111417058060ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 12062250914581096404ULL, + 16470785773141668820ULL, + 9421278315653665728ULL, + 17483272164760227076ULL, + 8294051096013124905ULL, + 10566182891042060997ULL, + 10681743127396606216ULL, + 16604675962527321468ULL, + 9896385331060111309ULL, + 15914098304250901620ULL, + 2704617218099626090ULL, + 17703663671547672796ULL, + 13003344626748298436ULL, + 17721701362436605871ULL, + 5595580746941836900ULL, + 8689630767405307242ULL, + 2847502754697601491ULL, + 17388098481709241326ULL, + 15895334666198302360ULL, + 17013261119640908019ULL, + 8237986150052862694ULL, + 11213426185636778850ULL, + 4178229971582094917ULL, + 8129065381129123298ULL, + 15622163817249491878ULL, + 15977012037827868885ULL, + 12780154622622409514ULL, + 17744185142764196518ULL, + 9380720358725705606ULL, + 14341787335056286689ULL, + 1954453932108830733ULL, + 10871097469804822966ULL, + 15982899578062696770ULL, + 18369999535167574905ULL, + 3131295520670406692ULL, + 13837240476735877741ULL, + 10281833574130981856ULL, + 17401902945497320037ULL, + 3436181719354558092ULL, + 12683720105860408418ULL, + 4392010313693820795ULL, + 6158233742606805624ULL, + 327149279904868339ULL, + 1505053535496595038ULL, + 14324850889186838664ULL, + 15189861091886608525ULL, + 1033766354236970083ULL, + 9811089684093738782ULL, + 10611433752284561601ULL, + 15313686008193368084ULL, + 16405759798314744798ULL, + 16589306549291278047ULL, + 4022565265852548262ULL, + 11414232046246682391ULL, + 7741179255930022554ULL, + 15573134884397712148ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 13076567381838686304ULL, + 14630428320771492568ULL, + 12428601961661519407ULL, + 18019087199125644508ULL, + 10762963597362666420ULL, + 12517353370103150928ULL, + 12805686762009722881ULL, + 15390268562882656966ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 6131715940974740167ULL, + 15354824309463220631ULL, + 9719752399211195101ULL, + 17405117249009499737ULL, + 9560457336625908666ULL, + 16759426099261610237ULL, + 6482450837833603519ULL, + 15596986205347621676ULL, + 10209527274639848846ULL, + 17407756499594320843ULL, + 6970130337666639652ULL, + 11293063657907554613ULL, + 8860419351838722401ULL, + 13385979784258964474ULL, + 1976633556850289987ULL, + 6474654274734615434ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 671022909473928985ULL, + 11168676610422392919ULL, + 3202181727775195232ULL, + 16816464651197758071ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 2285535013430314985ULL, + 2949636431462020360ULL, + 16738207642672586561ULL, + 16886155870981896428ULL, + 14050186167298171361ULL, + 15583199797896914870ULL, + 4431405630609386164ULL, + 9448377650323882163ULL, + 7524522650613799300ULL, + 16511861187519175865ULL, + 8712884631790805507ULL, + 15624074728749995916ULL, + 6050965051668825142ULL, + 14723767743484873844ULL, + 3592228242759511011ULL, + 4298751665373830317ULL, + 8693848645870669561ULL, + 17795119255432063382ULL, + 1380506420782840846ULL, + 4208051846494193083ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 7081730641819999895ULL, + 11205936879713146726ULL, + 903840776613718425ULL, + 9510696062693630561ULL, + 6020683233558943931ULL, + 17469503360559819806ULL, + 7491380935736823858ULL, + 9970357918101233105ULL, + 8208688290765994294ULL, + 16188653216770040612ULL, + 270021076507274267ULL, + 13854426035219011244ULL, + 5154706567583240998ULL, + 6872165128793815984ULL, + 17102143506735137840ULL, + 17809217635555296559ULL, + 3172939250536190791ULL, + 7507256990891557057ULL, + 630444806819205442ULL, + 15337439700854822796ULL, + 6914566603097792472ULL, + 12592151215669072592ULL, + 2200994388190217833ULL, + 6527581350360266903ULL, + 1556139627780938414ULL, + 3918878086059238659ULL, + 2960088947024122568ULL, + 13361744341011306623ULL, + 9239897243493534902ULL, + 15115868972623701064ULL, + 8488050096626391871ULL, + 15320552655965363520ULL, + 13163056959755144227ULL, + 17830849877115416532ULL, + 2033005965667329487ULL, + 15095745985921649262ULL, + 5134112811574340684ULL, + 18426172274128627454ULL, + 5964558195427972726ULL, + 8536852258799742845ULL, + 1715010093632846715ULL, + 10515300483504306206ULL, + 11071365549636497058ULL, + 14742241043646930603ULL, + 3689917888863121714ULL, + 3785544068177141750ULL, + 5429088350437049420ULL, + 8014115928620929051ULL, + 4159107017808062189ULL, + 18248161994414290839ULL, + 8425807382013732019ULL, + 18006054739672929398ULL, + 9624128225178803156ULL, + 16592036801841159466ULL, + 96647812917047750ULL, + 709391026679507672ULL, + 4161465484421313067ULL, + 16632681820919359438ULL, + 2632723500093466296ULL, + 6190465253721841482ULL, + 3713980442277601543ULL, + 4172574547216751230ULL, + 11286476715358411ULL, + 3765368068704124281ULL, + 3794768456264310041ULL, + 4003696484029900654ULL, + 4947617797123583523ULL, + 6434440319440172287ULL, + 12927837044899369506ULL, + 13313435521276462157ULL, + 6516242542881801552ULL, + 17281544606551451156ULL, + 41351040722243444ULL, + 15099007836725518739ULL, + 2876762871661296340ULL, + 3959632366811373003ULL, + 2503084669608409682ULL, + 12404170395162473338ULL, + 10413053796044140092ULL, + 14675304443505497788ULL, + 5125402236256011682ULL, + 7899109442998370237ULL, + 5182141304992263052ULL, + 5756575055488308248ULL, + 13338796967095319054ULL, + 13764824078045716483ULL, + 1457197461652085036ULL, + 13124979497146697428ULL, + 12098959920858445339ULL, + 13432595593847143675ULL, + 5423435028447179234ULL, + 5701427099449458968ULL, + 4695788495440654678ULL, + 16463576163411913526ULL, + 5030919564866077694ULL, + 10727680136157780304ULL, + 7896365259982277297ULL, + 9225873808423600358ULL, + 409839622160781340ULL, + 9841640897127767220ULL, + 7401365895310850551ULL, + 8483532101247565673ULL, + 4068398423843790828ULL, + 12625534486112652143ULL, + 8877796357915379560ULL, + 14696451182593672142ULL, + 441974442706557816ULL, + 7620555315505539408ULL, + 5511023563130348159ULL, + 8376038127455218781ULL, + 2027791808001488340ULL, + 7150706701820632592ULL, + 5408495896441494505ULL, + 10170315055646031315ULL, + 236410911410641088ULL, + 892982016332951271ULL, + 6800870684774378324ULL, + 14146144556896565127ULL, + 1067143219882902727ULL, + 8403063537753815762ULL, + 6486432957946002675ULL, + 12930115406644252850ULL, + 2140804280765107509ULL, + 16095787440174782818ULL, + 6657265715463375957ULL, + 15632358374472427057ULL, + 3883301382691425848ULL, + 11869943470701154192ULL, + 11909953227234106467ULL, + 12078973445421528572ULL, + 6879539917838885194ULL, + 11278654023777247758ULL, + 3448020793906309509ULL, + 14634519491425796269ULL, + 2300497234935834632ULL, + 7473040718396377438ULL, + 3448020793906309509ULL, + 14634519491425796269ULL, + 2300497234935834632ULL, + 7473040718396377438ULL, + 3448020793906309509ULL, + 14634519491425796269ULL, + 2300497234935834632ULL, + 7473040718396377438ULL, + 3448020793906309509ULL, + 14634519491425796269ULL, + 2300497234935834632ULL, + 7473040718396377438ULL, + 1985624399018914505ULL, + 16722972634450725128ULL, + 12295984130795129153ULL, + 17063902039557089370ULL, + 9939689000202530118ULL, + 17037118481697154281ULL, + 13765947803093737662ULL, + 16291000668083690173ULL, + 477271388969727112ULL, + 5321097195296258141ULL, + 6882797831960492131ULL, + 17240847496982941094ULL, + 11032321967282046727ULL, + 15355363887366025176ULL, + 13971635192885202512ULL, + 17895871999146004344ULL, + 4305188929758960406ULL, + 16468874216340307190ULL, + 883377933616164163ULL, + 10171180902654530064ULL, + 3947482515653655847ULL, + 18030858822278747020ULL, + 9343287325569061929ULL, + 10716717793026853047ULL, + 8255745522676848844ULL, + 12482308660473188815ULL, + 13793506789154330408ULL, + 14729446230806784100ULL, + 5268437323728456408ULL, + 6954400684179062321ULL, + 1384606914002501334ULL, + 10961402983970927907ULL, + 1048134495642424931ULL, + 13644920359353625395ULL, + 2673838107221684134ULL, + 9934139763056761667ULL, + 9281515308651341310ULL, + 12132488586584390306ULL, + 9980396435878927336ULL, + 18130426392197874399ULL, + 6598412426972334200ULL, + 11448957484572798667ULL, + 1721664969747507913ULL, + 15454600550863789031ULL, + 4148954198476152455ULL, + 13102935871171958792ULL, + 5043769964059023290ULL, + 5236494352137867122ULL, + 7450042778804013434ULL, + 15664276758287293009ULL, + 349514052202920328ULL, + 13714741068853448534ULL, + 4544802003281069967ULL, + 14767152953429012041ULL, + 378526290970392085ULL, + 13766332318712959531ULL, + 3667876235675294488ULL, + 18011060085809513354ULL, + 3226358077982734430ULL, + 10078068925699213983ULL, + 8072117076008525607ULL, + 14745956008110371380ULL, + 2107388634176612909ULL, + 8017059749662858402ULL, + 9030878819948962544ULL, + 16123735740128004119ULL, + 8939743334747827472ULL, + 17733596514381189422ULL, + 1142654065479252459ULL, + 13539788371269289539ULL, + 3716950217968259760ULL, + 14622447651689772558ULL, + 18067162018957942682ULL, + 18378850379813183017ULL, + 5912878053780974981ULL, + 10904147589928482526ULL, + 13739113909755135642ULL, + 15080200708053288804ULL, + 6321517591761892834ULL, + 13386127893263147612ULL, + 10085717451583423207ULL, + 11863269015411821128ULL, + 10965676304791944388ULL, + 11762237395949290572ULL, + 6090517165817421190ULL, + 13855686091050957715ULL, + 7825003641182679773ULL, + 14312844575063886802ULL, + 1907377967477117287ULL, + 14304962057400206486ULL, + 1273622530807565584ULL, + 3237417265932937340ULL, + 4302253834034413159ULL, + 12719308251510213975ULL, + 1114685813724992118ULL, + 5535709948471106658ULL, + 13876818099092171658ULL, + 15045444672307881976ULL, + 9970950310052765849ULL, + 15961379688382158951ULL, + 4106163845656394401ULL, + 18343178814850447605ULL, + 6816578680488645514ULL, + 11160981325378054919ULL, + 7480151245469238155ULL, + 11338668132207914982ULL, + 13436252272328347334ULL, + 17102537195225457185ULL, + 264179561959496434ULL, + 14987273120834962626ULL, + 5130220809999953334ULL, + 6833123001564999015ULL, + 2769363152604304861ULL, + 8512153920852922748ULL, + 226434488526882813ULL, + 16524336379516070656ULL, + 14415610908767894395ULL, + 17337785256483950985ULL, + 5606053808328056075ULL, + 15866036343145579814ULL, + 12873574062693958375ULL, + 13085695161716836411ULL, + 6092816362174792346ULL, + 7463765086913779199ULL, + 7398004734147268017ULL, + 18425849316692814158ULL, + 11413166991887815760ULL, + 12892439882311901467ULL, + 9286963538966990481ULL, + 13993083078076203562ULL, + 11042449747189110337ULL, + 12401325847532810150ULL, + 1320600068905048215ULL, + 17638985601380633991ULL, + 3584105118730771184ULL, + 9357303107532859500ULL, + 5378603776998927936ULL, + 10684641357618371846ULL, + 2829397050582654471ULL, + 10691585683919032976ULL, + 11207117624240306638ULL, + 15224310769747942070ULL, + 8560478383686529428ULL, + 9512765160888715991ULL, + 4429285816781050054ULL, + 17870041408724776233ULL, + 1385831979839878604ULL, + 11465499285423739775ULL, + 7167450721693202738ULL, + 13808414431949814913ULL, + 13122109575664329248ULL, + 18059038491870370446ULL, + 11645429705440109896ULL, + 17044923695160328872ULL, + 1996199019089284427ULL, + 11182061501585080346ULL, + 2136190341155757543ULL, + 13102635713657339156ULL, + 7617837189513110199ULL, + 11911513577930925017ULL, + 10391275061945726686ULL, + 13883216918203475868ULL, + 6909837389289569490ULL, + 7546970978758029240ULL, + 10036592355230453018ULL, + 11632255067481016550ULL, + 12306473612474711175ULL, + 13191692070671557397ULL, + 9460101615336151569ULL, + 14583904492051495049ULL, + 3744864979998814946ULL, + 13780889174646723772ULL, + 2626138585608780375ULL, + 14381693239780341819ULL, + 6012069900085271073ULL, + 16004324815079151784ULL, + 5596384497346610587ULL, + 11684639230221622625ULL, + 276778156592796932ULL, + 3517528429573104309ULL, + 6505297840889023573ULL, + 9609607314216589948ULL, + 10714130090716429953ULL, + 18135465268122278358ULL, + 257888847088279123ULL, + 548904757058660428ULL, + 14554604540879511802ULL, + 17745070294548377092ULL, + 710751991459198218ULL, + 11485416762356443340ULL, + 4938929649798241302ULL, + 17431968815090940058ULL, + 2057693986549822031ULL, + 10825022556031573008ULL, + 109475949781650802ULL, + 305163041190357464ULL, + 5064310199819446135ULL, + 13072838105636205899ULL, + 4987236417700401524ULL, + 5974627488880865833ULL, + 12738789522717452356ULL, + 18150397796885743681ULL, + 13197234158805379262ULL, + 18267484738280997028ULL, + 2999689730823386026ULL, + 9098689165616800663ULL, + 5364947587741218599ULL, + 15347448961387418518ULL, + 8073842817125840539ULL, + 9968191478964203868ULL, + 3595475296073914979ULL, + 13237003722753517177ULL, + 6403938850237076892ULL, + 11832076847556124908ULL, + 1153152021805813442ULL, + 2101616459160103469ULL, + 11899554640469270848ULL, + 13582469680334367745ULL, + 1439471324863607313ULL, + 2947112715650806779ULL, + 7654771529562057469ULL, + 11878733688762927977ULL, + 16179017790537575919ULL, + 17715883000479135454ULL, + 1965240346727255686ULL, + 7938449923101791252ULL, + 9006772500124194270ULL, + 9035919563996865220ULL, + 4123153806528480282ULL, + 9108160374563953415ULL, + 3935053020120175344ULL, + 18104463140898783500ULL, + 5878403412990365856ULL, + 6926604584970068907ULL, + 8189005909961093806ULL, + 14800980240631731553ULL, + 2211937722433814650ULL, + 7197943721483127884ULL, + 10912778278300093698ULL, + 12388372363157283323ULL, + 4587724182252135149ULL, + 8127571049901566747ULL, + 10429589704496877702ULL, + 11320471261589758205ULL, + 12090410390544021533ULL, + 13321681554864015074ULL, + 15575071203466831519ULL, + 17022173808800333564ULL, + 196353793852835571ULL, + 9953354866759622852ULL, + 6272070164492575142ULL, + 8400580997445180137ULL, + 8765041716730225410ULL, + 10184068795790284369ULL, + 1153152021805813442ULL, + 2101616459160103469ULL, + 4967775972529775547ULL, + 11416615080805710484ULL, + 11192863022333834818ULL, + 12282392669893539868ULL, + 4465082925031161729ULL, + 5109428563756478062ULL, + 7372850663756900911ULL, + 12702609440750120599ULL, + 64069737919527165ULL, + 3115898376087374088ULL, + 10011737209770297891ULL, + 11389844725017273731ULL, + 6814748558810661393ULL, + 17229144570668348549ULL, + 2889128855383495601ULL, + 12968404548682063094ULL, + 11725033635658594441ULL, + 14702213922011282878ULL, + 7617837189513110199ULL, + 11911513577930925017ULL, + 10391275061945726686ULL, + 13883216918203475868ULL, + 6909837389289569490ULL, + 7546970978758029240ULL, + 1338625161271714383ULL, + 8887535710417366133ULL, + 7990175697040782511ULL, + 9602906764135192091ULL, + 5573994293445841406ULL, + 10703760765436615754ULL, + 3744864979998814946ULL, + 13780889174646723772ULL, + 421267208549068584ULL, + 11334725928027711228ULL, + 9198889497103397585ULL, + 16992752587934421877ULL, + 6533707171680121225ULL, + 6541250407261015449ULL, + 276778156592796932ULL, + 3517528429573104309ULL, + 1167457768513115564ULL, + 7114414873804308650ULL, + 10714130090716429953ULL, + 18135465268122278358ULL, + 6725288794736986296ULL, + 13565795874251036967ULL, + 6377663392320494492ULL, + 11670401136570675207ULL, + 2179039418583231752ULL, + 8853337881257390245ULL, + 4938929649798241302ULL, + 17431968815090940058ULL, + 8685338074944728331ULL, + 10355366324194329105ULL, + 109475949781650802ULL, + 305163041190357464ULL, + 12329980252895799995ULL, + 15387860607219968807ULL, + 4987236417700401524ULL, + 5974627488880865833ULL, + 8640980849721331063ULL, + 14902769990546360728ULL, + 915295737085056266ULL, + 10383448560132122013ULL, + 6253202230913658005ULL, + 6856193984021149799ULL, + 4530839014246536531ULL, + 16608491996550578780ULL, + 11097826824633620898ULL, + 17327663336061586520ULL, + 3595475296073914979ULL, + 13237003722753517177ULL, + 9511449659809835913ULL, + 12962545361503649712ULL, + 583898799390193180ULL, + 17463670751539103043ULL, + 1798980092430065124ULL, + 8998781087088947014ULL, + 8923230009351338814ULL, + 11780411159198435451ULL, + 2635794383627986889ULL, + 9521982681587842237ULL, + 239432779271384384ULL, + 4576908429030297663ULL, + 11213383063380862112ULL, + 16547470678371319978ULL, + 3935053020120175344ULL, + 18104463140898783500ULL, + 4683913763550045915ULL, + 6312735823300498955ULL, + 7152770185379494197ULL, + 16749274883236598145ULL, + 10172954619689842656ULL, + 16577780972965547548ULL, + 2402632750726591551ULL, + 7637906563009958733ULL, + 15526484125097380571ULL, + 17005952349987828191ULL, + 6769995714843218740ULL, + 12110958718298995536ULL, + 12912119354467881531ULL, + 16634545303662080532ULL, + 583898799390193180ULL, + 17463670751539103043ULL, + 10715523725108767592ULL, + 18022213833308708596ULL, + 15073378595358852525ULL, + 17255128646038790067ULL, + 6489530418075329160ULL, + 10648314348564831545ULL, + 4593944710935718444ULL, + 8684405653201615336ULL, + 417545745395812143ULL, + 7092721427525900498ULL, + 10345781306421849587ULL, + 11335407050114239840ULL, + 3357174915365001288ULL, + 14278196786330692002ULL, + 7617837189513110199ULL, + 11911513577930925017ULL, + 10391275061945726686ULL, + 13883216918203475868ULL, + 6909837389289569490ULL, + 7546970978758029240ULL, + 6881444089955762797ULL, + 8937766732328416233ULL, + 6698520932785859230ULL, + 15707769838519456838ULL, + 6729717858293592998ULL, + 12456432768627815473ULL, + 3744864979998814946ULL, + 13780889174646723772ULL, + 12069483856527122708ULL, + 12294926451563223608ULL, + 6394566475720186733ULL, + 11757880906328248842ULL, + 7817789901538590399ULL, + 8590338619501309996ULL, + 276778156592796932ULL, + 3517528429573104309ULL, + 1607970637960724162ULL, + 9611911801248388914ULL, + 10714130090716429953ULL, + 18135465268122278358ULL, + 7202735102274539096ULL, + 10547934332124779831ULL, + 7238460867011841587ULL, + 9169946272900964111ULL, + 5694802671892397242ULL, + 16453437518137771985ULL, + 4938929649798241302ULL, + 17431968815090940058ULL, + 15625778649361573009ULL, + 17829088406099062950ULL, + 109475949781650802ULL, + 305163041190357464ULL, + 605270731707924331ULL, + 1545773305431304863ULL, + 4987236417700401524ULL, + 5974627488880865833ULL, + 1291297670605140054ULL, + 12185743438346314536ULL, + 7719461731668742563ULL, + 7973083364683943380ULL, + 2437362898695104664ULL, + 8536833084553084576ULL, + 3856882593361703730ULL, + 10888205905396688117ULL, + 3454111540853125558ULL, + 12135390466362384269ULL, + 3595475296073914979ULL, + 13237003722753517177ULL, + 1203346138039192594ULL, + 9003822513987001203ULL, + 9889646838775955053ULL, + 10029999613836019794ULL, + 9371250839356730844ULL, + 12312906007883199986ULL, + 8854849495994862973ULL, + 13648744740934265374ULL, + 7637042079436467695ULL, + 17659712304505415286ULL, + 1088354933142154181ULL, + 16923619939213429832ULL, + 9926559550799640400ULL, + 16996759880358433776ULL, + 3935053020120175344ULL, + 18104463140898783500ULL, + 11219544273114807225ULL, + 16475447076920521696ULL, + 2517673240914906214ULL, + 5228357121501591308ULL, + 823403068210445033ULL, + 12656092356054717663ULL, + 5441512263986354299ULL, + 7260022297773648989ULL, + 10632312126696592305ULL, + 15058304644744649144ULL, + 4290569954169336525ULL, + 13722305657451984601ULL, + 12760821389568006030ULL, + 16708315218360480626ULL, + 9889646838775955053ULL, + 10029999613836019794ULL, + 10513832207937737953ULL, + 18390593024059956742ULL, + 13087450287780145592ULL, + 16980463587205128835ULL, + 10693190936147887781ULL, + 11800813389084730138ULL, + 5102298124065654974ULL, + 13768674884180123545ULL, + 10325557602965032566ULL, + 13300583833517834979ULL, + 969705947831932849ULL, + 11843662644345302798ULL, + 10065736171474222377ULL, + 16178229155482508128ULL, + 7617837189513110199ULL, + 11911513577930925017ULL, + 10391275061945726686ULL, + 13883216918203475868ULL, + 6909837389289569490ULL, + 7546970978758029240ULL, + 2732480160867762417ULL, + 12059258099058916549ULL, + 127545218713973002ULL, + 865964620102865741ULL, + 3748269509330634011ULL, + 5566998471421614530ULL, + 3744864979998814946ULL, + 13780889174646723772ULL, + 6799747959462525631ULL, + 8911355217555977715ULL, + 7506886676086400365ULL, + 8580679031777856100ULL, + 1952594092331306750ULL, + 15940971306012745884ULL, + 276778156592796932ULL, + 3517528429573104309ULL, + 197027648898524990ULL, + 1920195859048757974ULL, + 10714130090716429953ULL, + 18135465268122278358ULL, + 14484087698274044902ULL, + 15951765600842076018ULL, + 6266347194400789361ULL, + 7576410713452502986ULL, + 5701461586040740346ULL, + 11140646369694594964ULL, + 4938929649798241302ULL, + 17431968815090940058ULL, + 2614961383134271366ULL, + 3501789704437588273ULL, + 109475949781650802ULL, + 305163041190357464ULL, + 6563138958776793650ULL, + 7557738194467841568ULL, + 4987236417700401524ULL, + 5974627488880865833ULL, + 1356573290202665401ULL, + 4892539437729179172ULL, + 14066070723699403744ULL, + 16156417668221432330ULL, + 4161405461589249227ULL, + 9334691090498644256ULL, + 527191258054353530ULL, + 812852878210069716ULL, + 4310871835917127097ULL, + 13492394073732267043ULL, + 3595475296073914979ULL, + 13237003722753517177ULL, + 1298104539263958728ULL, + 15036256386532459142ULL, + 5185790951439894848ULL, + 10029783433770968165ULL, + 3477748469315919979ULL, + 5229291309402641366ULL, + 4953604738054018374ULL, + 9869703382478714977ULL, + 14415469563005798637ULL, + 14979771022350561923ULL, + 5394336484874836371ULL, + 10961910960938578126ULL, + 4784750288621543156ULL, + 16056151322296326566ULL, + 3935053020120175344ULL, + 18104463140898783500ULL, + 3980725347109387711ULL, + 9803975891718112101ULL, + 10905625532141258124ULL, + 14050046917842410561ULL, + 7486299058793698355ULL, + 18036795809077714465ULL, + 3197831172178136742ULL, + 9825762890310274295ULL, + 4921017580978972046ULL, + 17779002540231894638ULL, + 11518784093471651401ULL, + 12291574878567489813ULL, + 10705444259589410809ULL, + 15746256322285909938ULL, + 5185790951439894848ULL, + 10029783433770968165ULL, + 1310431630602965078ULL, + 12257977063006640754ULL, + 5631722171958544188ULL, + 10156582829218336971ULL, + 16870298903279162128ULL, + 17599779550187856314ULL, + 7804521899612754454ULL, + 14069220038552058707ULL, + 9091443645396259354ULL, + 13129542671682889968ULL, + 982089941362735618ULL, + 8616319590896320865ULL, + 3516158340802078256ULL, + 18385818772309019198ULL, + 7617837189513110199ULL, + 11911513577930925017ULL, + 10391275061945726686ULL, + 13883216918203475868ULL, + 6909837389289569490ULL, + 7546970978758029240ULL, + 1893551085334188427ULL, + 12840672741056179598ULL, + 9692747828510352731ULL, + 13468156150324333025ULL, + 2658629775044545206ULL, + 3050564778776282042ULL, + 3744864979998814946ULL, + 13780889174646723772ULL, + 8159583023013741259ULL, + 8642816716781979204ULL, + 39697055165369862ULL, + 6889177041113268369ULL, + 11638389382773444582ULL, + 15771261313194727655ULL, + 276778156592796932ULL, + 3517528429573104309ULL, + 3178441516889309431ULL, + 6530837468030373797ULL, + 10714130090716429953ULL, + 18135465268122278358ULL, + 15637870165082359705ULL, + 17734234031308467326ULL, + 4431630126465510725ULL, + 13410743067113283654ULL, + 11919918386138380545ULL, + 16324367343096137637ULL, + 4938929649798241302ULL, + 17431968815090940058ULL, + 7809355784925503934ULL, + 12948967860119007120ULL, + 109475949781650802ULL, + 305163041190357464ULL, + 12490908991552552731ULL, + 13142706771131085128ULL, + 4987236417700401524ULL, + 5974627488880865833ULL, + 7111154558182740014ULL, + 16757167660157575603ULL, + 5157161944099018098ULL, + 14796588232141300073ULL, + 4431671876096881402ULL, + 9578395443620012493ULL, + 4698198829402347366ULL, + 10925684912304534632ULL, + 10156363529045680587ULL, + 10850179677778663550ULL, + 3595475296073914979ULL, + 13237003722753517177ULL, + 5245158009456284856ULL, + 14029055266898362972ULL, + 539485045861518028ULL, + 4302608361007821481ULL, + 4968660003691572924ULL, + 11250616827343394370ULL, + 1407788003072150093ULL, + 6697391257669149316ULL, + 9461251710166316258ULL, + 16286340428010238120ULL, + 11769482643285186921ULL, + 16832544656241391674ULL, + 769229921669328981ULL, + 8639955924306474934ULL, + 3935053020120175344ULL, + 18104463140898783500ULL, + 653842784991299794ULL, + 8736152644968143543ULL, + 6117836002365200807ULL, + 7462816947991418498ULL, + 1243011764018010038ULL, + 2754960959341684882ULL, + 5017496219240892974ULL, + 5118924683017196836ULL, + 8930550146108715738ULL, + 17585489894925367369ULL, + 12718063835804862625ULL, + 14918915647462223907ULL, + 7295272489728578988ULL, + 7711706655831960724ULL, + 539485045861518028ULL, + 4302608361007821481ULL, + 7304785014881464748ULL, + 12396786715048808532ULL, + 9661992610508432669ULL, + 13252884419054331070ULL, + 27953513682469016ULL, + 9047505427214127125ULL, + 8716471647270039342ULL, + 16745645561744827019ULL, + 3307725508951123037ULL, + 7124833760673088602ULL, + 6889160249940314494ULL, + 11883793807407909115ULL, + 2114063373598219794ULL, + 8072720666204148712ULL, + 7617837189513110199ULL, + 11911513577930925017ULL, + 10965919655852160652ULL, + 15354528497749144385ULL, + 6909837389289569490ULL, + 7546970978758029240ULL, + 5147934181094038817ULL, + 5981837583053678571ULL, + 14679219935846174766ULL, + 15787999130910691557ULL, + 4653370102972937299ULL, + 5776687685278897980ULL, + 3744864979998814946ULL, + 13780889174646723772ULL, + 13648164760098112901ULL, + 15123600289658880214ULL, + 5587153209943154183ULL, + 10665257132241004883ULL, + 1431628522354525975ULL, + 4891906787195563268ULL, + 276778156592796932ULL, + 3517528429573104309ULL, + 5521914503467159438ULL, + 7342788343305784447ULL, + 10714130090716429953ULL, + 18135465268122278358ULL, + 3452417330095576953ULL, + 9186362929273932282ULL, + 1426985321742099999ULL, + 14408315875984321297ULL, + 6090545617453585392ULL, + 8391259433846998717ULL, + 4938929649798241302ULL, + 17431968815090940058ULL, + 7253885299641873275ULL, + 10274227023172516359ULL, + 109475949781650802ULL, + 305163041190357464ULL, + 4243128882738589105ULL, + 4705219689730004500ULL, + 4987236417700401524ULL, + 5974627488880865833ULL, + 13817108887307535480ULL, + 17172583713339971822ULL, + 163571767702976579ULL, + 13411759730037420450ULL, + 13618037045511650760ULL, + 14733222327178261599ULL, + 4156784347846848160ULL, + 12982552785374759574ULL, + 15576671687843403197ULL, + 17192028891436333617ULL, + 3595475296073914979ULL, + 13237003722753517177ULL, + 11079729604640397386ULL, + 12723288230611209407ULL, + 1269156274087261078ULL, + 7468984143256805992ULL, + 5106161451443105271ULL, + 8547448335120523386ULL, + 6578685429355840110ULL, + 8038093797720322457ULL, + 4703162332846948922ULL, + 14329559848567299483ULL, + 871795979655469304ULL, + 15813400436714615635ULL, + 4370733145541709031ULL, + 13094307392542217285ULL, + 3935053020120175344ULL, + 18104463140898783500ULL, + 823589060376558160ULL, + 8051764948754053426ULL, + 6717539601488244757ULL, + 16490508178956688298ULL, + 5825866583497136839ULL, + 7092500087641745759ULL, + 4721768316046714364ULL, + 5772185394137274559ULL, + 7391124098860853262ULL, + 17646459307127078688ULL, + 289637200485522769ULL, + 10783163565798304546ULL, + 16676003475074479600ULL, + 17556230409449026318ULL, + 1269156274087261078ULL, + 7468984143256805992ULL, + 5860513954204257172ULL, + 8200848199578393812ULL, + 3585530088483138089ULL, + 7765153321972256009ULL, + 4526398226912731385ULL, + 9189624391587665963ULL, + 3911281757607605689ULL, + 6704991168749078758ULL, + 891476448228223983ULL, + 6768639012773239612ULL, + 6271735381562443691ULL, + 12301493869869786967ULL, + 940426033589700803ULL, + 9637023094444728189ULL, + 3240095117501300191ULL, + 6411565501321751884ULL, + 2840891085068807482ULL, + 6164565793609831017ULL, + 2635730308508295418ULL, + 14631880544163631439ULL, + 6293807447015086954ULL, + 12329213014401730696ULL, + 3539961541701537752ULL, + 6812381022579983517ULL, + 2474911698130863353ULL, + 18395581790062892233ULL, + 11388447755226640033ULL, + 17168001827939103927ULL, + 6949504396170268446ULL, + 17999978036045609638ULL, + 1686363461238418517ULL, + 2477246047824523317ULL, + 5256689592983268828ULL, + 5631112791850855162ULL, + 1726478480283089647ULL, + 2624760532609284387ULL, + 6095972274012583406ULL, + 13155487670869468684ULL, + 3658120142122745239ULL, + 9411835183970479007ULL, + 1106494705399083861ULL, + 8524198526584438274ULL, + 3743705507014495005ULL, + 12871453577312766071ULL, + 2232137156956529005ULL, + 8496086766066034399ULL, + 4318528077394790756ULL, + 15110197990632731437ULL, + 14115038326614719874ULL, + 17882099251054873747ULL, + 1321464425739714536ULL, + 8410171637492652097ULL, + 10388042593873216144ULL, + 14957730477824436801ULL, + 353958726447423787ULL, + 371130133458997400ULL, + 6553399607020901041ULL, + 8602067763771982292ULL, + 5837292909064456421ULL, + 15873020169056380018ULL, + 1810951003942298715ULL, + 12150662705726597109ULL, + 15196207893523194067ULL, + 15989215800690211847ULL, + 13184483793901343913ULL, + 13812233236564627351ULL, + 10345251458261364630ULL, + 13253852290014869339ULL, + 9058885296098953983ULL, + 11074219146900658250ULL, + 862906962249261017ULL, + 2624774152536508423ULL, + 4970730785525201989ULL, + 9137937986648568006ULL, + 9291798111568353641ULL, + 13297646330874441781ULL, + 7908992538461390546ULL, + 8879404916911989945ULL, + 3791622014205000569ULL, + 6821831304740008468ULL, + 10504405381428834611ULL, + 10517425020848064679ULL, + 5109795214191132970ULL, + 10608643749732425241ULL, + 7130348016203544971ULL, + 16413301933383534025ULL, + 2597919840124118064ULL, + 10748495650168990097ULL, + 7736897464509196705ULL, + 10902019770311021193ULL, + 7609305155207576456ULL, + 12036933381104588919ULL, + 10833514392159201066ULL, + 18283668119036656586ULL, + 14656847094314696512ULL, + 15073982428956432228ULL, + 8280655701774932681ULL, + 8470739681381623218ULL, + 8137727914319983663ULL, + 14794926547027873778ULL, + 13113202832787773221ULL, + 13750914803210876454ULL, + 1126970080385213776ULL, + 8259492900921717970ULL, + 2078703129369024146ULL, + 6577757312344727281ULL, + 13346917943095349039ULL, + 14841438124491726270ULL, + 1137081002253749160ULL, + 14586825517351488144ULL, + 10466366290573593648ULL, + 16559275445309881077ULL, + 3526526534663759580ULL, + 8263494013709847318ULL, + 14361725543119299662ULL, + 17027561502143755738ULL, + 11495025843748838187ULL, + 17393976482711985941ULL, + 3983325525230577665ULL, + 11891402828805245985ULL, + 15309851440924263784ULL, + 16116127205887517626ULL, + 3990572723261048830ULL, + 10291234573421436052ULL, + 3256774662027261463ULL, + 5985309947215255764ULL, + 5840001073381249236ULL, + 17325354371867583698ULL, + 13732057646211465578ULL, + 14447428187724193358ULL, + 2252353247605700933ULL, + 18325038456513240689ULL, + 8207523943342248015ULL, + 14875865605030738739ULL, + 5813858254002556573ULL, + 13208687369455229812ULL, + 4655046462364019542ULL, + 13026428793330792748ULL, + 15408322415855234585ULL, + 386949359633144242ULL, + 18266043565210404590ULL, + 1284063368582859172ULL, + 9475520680604370023ULL, + 5647287878189234084ULL, + 9975041678451975307ULL, + 10991104600421949135ULL, + 17996490418056910661ULL, + 4636332287922828155ULL, + 8405900459265647932ULL, + 7897676412904975297ULL, + 276726289681294616ULL, + 18365336279517633795ULL, + 6223906041682177353ULL, + 15757235290216151508ULL, + 11771401217652111707ULL, + 11449805379109728603ULL, + 5329007821277847604ULL, + 16416495927312897517ULL, + 8845428255114165399ULL, + 1590129053642129954ULL, + 14601529449684208115ULL, + 16183098742959214711ULL, + 4415835312989515264ULL, + 2612600052719790851ULL, + 15972184841728434126ULL, + 8502124924950624030ULL, + 18223718719895281680ULL, + 6618607310723778268ULL, + 9631106448414516336ULL, + 1941560109795530639ULL, + 670788235918901161ULL, + 3608109049432885720ULL, + 2409384589385977640ULL, + 13935308304768045941ULL, + 5159922560987936566ULL, + 12645344049942408182ULL, + 770031883281781308ULL, + 17700282675737523788ULL, + 17181933342637853629ULL, + 17451079350899326727ULL, + 13298068054055405809ULL, + 8809936160503778030ULL, + 9795127274358195794ULL, + 6872191646839800490ULL, + 9491185074444207998ULL, + 7572610932929952045ULL, + 17846158531866792560ULL, + 831167490519712529ULL, + 6201219854527433838ULL, + 11054320491928597564ULL, + 16903550485858106127ULL, + 17109598143273673106ULL, + 15735844067280226737ULL, + 15880013279849194208ULL, + 12980799693724143453ULL, + 5450368275517994020ULL, + 11864640809670855852ULL, + 12951387651099762394ULL, + 11088232918590788468ULL, + 3914538384724869888ULL, + 3302059533477620743ULL, + 11837274173822326953ULL, + 807575491006397278ULL, + 12058044931164975348ULL, + 3682953404979798061ULL, + 3715658708952533831ULL, + 2968020878599127258ULL, + 10528030354438088317ULL, + 6084962379048331417ULL, + 8016345745864030927ULL, + 11673159718626632030ULL, + 5283666767486552891ULL, + 12395142410570034632ULL, + 9207271708707447208ULL, + 13386188243203613285ULL, + 10159306072189417987ULL, + 1291348601596970530ULL, + 10176606024633957042ULL, + 43661285721210656ULL, + 11771797364096734048ULL, + 467252897597946250ULL, + 10188035947412106217ULL, + 10110150642793185907ULL, + 3352489384206675164ULL, + 12841592645624176196ULL, + 1227793088147132540ULL, + 7369262697782325455ULL, + 6779967146543435234ULL, + 14533119327453807420ULL, + 18094919520512571671ULL, + 473553808690815125ULL, + 13206252183283625640ULL, + 1094831862737402176ULL, + 10175674414845164112ULL, + 13262602233613683257ULL, + 14947625340514988713ULL, + 9711996165605549800ULL, + 11235434522686798628ULL, + 6387397702037047540ULL, + 14634977560933215440ULL, + 927093501259076499ULL, + 2884812162520088425ULL, + 7116358630804556734ULL, + 9092840098575588750ULL, + 2481122110499322883ULL, + 16397819709791075392ULL, + 552279830881344816ULL, + 18348670315131381510ULL, + 8342409333191168447ULL, + 13121444697297109554ULL, + 11288166411388155540ULL, + 17594986923718326298ULL, + 5660041430391457281ULL, + 12022860116069025082ULL, + 2507050845991187238ULL, + 9961393334234025066ULL, + 2637928885901388796ULL, + 10606218769106271958ULL, + 12328855812401720420ULL, + 12746168949784070746ULL, + 1920747479569722591ULL, + 9160586796917988653ULL, + 1152873032422493913ULL, + 5844921649386489430ULL, + 8699663054246735381ULL, + 13601535922138968414ULL, + 3361652096879056147ULL, + 17787731845296999305ULL, + 1160503530729140726ULL, + 2796002900084890452ULL, + 6228370781836794337ULL, + 12250602682324813995ULL, + 10849826352126744092ULL, + 17111972740119597571ULL, + 6225228994844384293ULL, + 16392322460044357873ULL, + 370101794753635054ULL, + 14256731933657706774ULL, + 877813778165190661ULL, + 10262895152637120139ULL, + 2347310721429508447ULL, + 14597382046768036522ULL, + 10665774106623326472ULL, + 16807182676938950306ULL, + 439548692971495469ULL, + 17752427373066470922ULL, + 775690136851088213ULL, + 14417977656702180227ULL, + 4231736849931337560ULL, + 13620687959343795559ULL, + 2731201508626477688ULL, + 11648768680327189007ULL, + 483276457021354901ULL, + 6651264113841945794ULL, + 8173501815489884159ULL, + 8257645164603711462ULL, + 10409786446401757820ULL, + 10908286973162521017ULL, + 5964136714057918673ULL, + 6581171353516082255ULL, + 1690588453926228842ULL, + 9723467493886318050ULL, + 3323074136732355969ULL, + 14128645344058541742ULL, + 11170163757841957659ULL, + 13373057976761676226ULL, + 10921636263461457997ULL, + 14401321300930915366ULL, + 8419792302201618175ULL, + 8843119767613238187ULL, + 887826722428030183ULL, + 8987460622330119642ULL, + 7067597060791923532ULL, + 11236404805671440463ULL, + 8127990291189988805ULL, + 8635758850136082850ULL, + 13469427657568358090ULL, + 14252511445080926134ULL, + 15678324082846152581ULL, + 17453951734756081503ULL, + 10971301307660878912ULL, + 13194543955954710265ULL, + 6265842933168179628ULL, + 6771142296839261368ULL, + 841883731012191478ULL, + 13034765154148535957ULL, + 177433709897221531ULL, + 4327641820761165923ULL, + 6524228439021511398ULL, + 17604796422150930537ULL, + 7285778482320296368ULL, + 17211632574473817317ULL, + 3468806315324348170ULL, + 17528885225332136318ULL, + 11570106688708873686ULL, + 15091349099294885773ULL, + 12777740512728379929ULL, + 14563793450509463960ULL, + 10084748525541997239ULL, + 18143112836586649710ULL, + 4328039270470636436ULL, + 11380788448558238316ULL, + 5113003449167666931ULL, + 9703642668073743334ULL, + 10802690892593510338ULL, + 15097490396535739649ULL, + 6780373649048328650ULL, + 11394815778597055383ULL, + 3354277856032132733ULL, + 7438608495389403217ULL, + 10698616548075393939ULL, + 12558129369833707845ULL, + 6920481332994233265ULL, + 10717334358940692127ULL, + 10759825150564518647ULL, + 11707834304835084706ULL, + 16788638069369218830ULL, + 17974126511947188818ULL, + 1906534759818985645ULL, + 3936124683840972740ULL, + 12973333629687904407ULL, + 7456315645006245689ULL, + 14311711717511608463ULL, + 14426334695629621915ULL, + 7621579134777882436ULL, + 1711969794178811929ULL, + 5867049480062623550ULL, + 11527084834532474818ULL, + 17366766916172117946ULL, + 9072161741682570428ULL, + 18318012440189373694ULL, + 16911803471944061412ULL, + 12563878001586179196ULL, + 9080090114965074657ULL, + 9261400835344633770ULL, + 4522430229961606876ULL, + 11101486678611826951ULL, + 10765776170340632974ULL, + 7489013554912134052ULL, + 12656885900028805934ULL, + 8580813292678286372ULL, + 8195414642782129297ULL, + 6288006710710208884ULL, + 991746626576602425ULL, + 10168031846528950430ULL, + 11051047599494085727ULL, + 15780160893579468872ULL, + 6465794722147633276ULL, + 11799935192546801413ULL, + 7382706271289002347ULL, + 4180024523765416999ULL, + 8407405666317109092ULL, + 11109791063685934458ULL, + 6888844811717934741ULL, + 14212863116129221938ULL, + 6967643374609389792ULL, + 4823518576092168497ULL, + 15487426732943259812ULL, + 17119438933466323444ULL, + 10788061177103839272ULL, + 442088280884336637ULL, + 5417492477234419636ULL, + 3098169116024233433ULL, + 15869065427882575867ULL, + 12711569478189578063ULL, + 674740875111376871ULL, + 10947132465356967433ULL, + 12589046854756680387ULL, + 16938157510420357975ULL, + 6200842374828457236ULL, + 8939512241505597695ULL, + 4777214622021224273ULL, + 13314135203945943070ULL, + 618575099429683494ULL, + 11622795574435582745ULL, + 16592375258532683719ULL, + 6168854001259798506ULL, + 13890060026692506445ULL, + 11654082903040817268ULL, + 2147551418466904282ULL, + 2147588349759794595ULL, + 2484909545371282708ULL, + 12547586434944861897ULL, + 13154552815869636314ULL, + 17644953197601219778ULL, + 17596235917233352798ULL, + 4501982451287449314ULL, + 2517515470713228255ULL, + 81986552817887326ULL, + 7201534192947229306ULL, + 6512682820042283537ULL, + 5843845815521857146ULL, + 5734086900016088886ULL, + 10062811243471966117ULL, + 16118324784043840476ULL, + 15720918269701452189ULL, + 2418437394768951785ULL, + 15587133145369624541ULL, + 3804138499621278268ULL, + 2325165961413786227ULL, + 4573742763097728069ULL, + 4084456010316431509ULL, + 2159560145942501935ULL, + 8806868809313676239ULL, + 786504296383796423ULL, + 6474308899996770828ULL, + 7312493576436875958ULL, + 4830032772376443332ULL, + 9004701885478402575ULL, + 15977326537914665828ULL, + 8194122968095501985ULL, + 7758426535684928825ULL, + 10153698865282172300ULL, + 16499336939365749615ULL, + 6988604681720120667ULL, + 2346041400942534827ULL, + 4750543616496375910ULL, + 12399511795630196082ULL, + 9999377044406161714ULL, + 6095268236890845745ULL, + 3997247995560427993ULL, + 3366077743266357994ULL, + 10924803762576222815ULL, + 16397070632023022486ULL, + 6597317417879247169ULL, + 2016270675771036338ULL, + 11767551349100737834ULL, + 6283648525068707604ULL, + 12498515816326126706ULL, + 6509596052041703372ULL, + 12090240422045531466ULL, + 17293612756301729239ULL, + 6572387953541404640ULL, + 7324154107381630362ULL, + 1722007507667849732ULL, + 4046958641491941684ULL, + 15594546431824868748ULL, + 6429681418172153407ULL, + 16164346442889363000ULL, + 4298155599959552904ULL, + 6308320370524275145ULL, + 5634837908641662462ULL, + 8414881470712175069ULL, + 15936601325866881055ULL, + 11091220500067252786ULL, + 12783137259671055283ULL, + 9745628813807812992ULL, + 8440270527968018350ULL, + 6111476804789152002ULL, + 15348482159030665479ULL, + 2909728978764061478ULL, + 17093662197854978376ULL, + 7041567004685695269ULL, + 2838122195845377324ULL, + 11763475390563009802ULL, + 8645326971560577066ULL, + 5578528637464029773ULL, + 8912028216345925339ULL, + 13629816696183048718ULL, + 11643423501374231130ULL, + 2030003209724039000ULL, + 937559781005875165ULL, + 12295577139954594840ULL, + 13067738333775332647ULL, + 15283619218701953655ULL, + 4896012699714940007ULL, + 13867330426790841890ULL, + 7822754638605654670ULL, + 10906967112713959952ULL, + 15489081388814445865ULL, + 18069558473899605532ULL, + 4422627050869503500ULL, + 11306553259837638418ULL, + 17382362942849378884ULL, + 4364420141160648251ULL, + 8004933923257962225ULL, + 2418593007336211541ULL, + 9032517844699239285ULL, + 15097963691266555560ULL, + 9013280990361196998ULL, + 15165633518481308828ULL, + 11475190067814343842ULL, + 973660164920660744ULL, + 13094071732962199954ULL, + 7501712153210178342ULL, + 15460532941141882516ULL, + 140871010945996023ULL, + 16739480402605607694ULL, + 4679854664520322671ULL, + 485648106933171109ULL, + 18007203940484373892ULL, + 2716453205284360326ULL, + 6556636775873384234ULL, + 11367393265137939333ULL, + 17135918757255264550ULL, + 6404861347370015596ULL, + 16267510282052496492ULL, + 7322578813854901205ULL, + 12169503041229640188ULL, + 6601923899809975896ULL, + 14359021944314779671ULL, + 1047083264384336019ULL, + 3254371516857996093ULL, + 6718768107286662393ULL, + 7630423198024825853ULL, + 3767695283737420966ULL, + 3526517821334800844ULL, + 18016428587047865287ULL, + 1499002563364253616ULL, + 2509392014261162571ULL, + 12957584855051548327ULL, + 14039185422451266964ULL, + 8194178399912199815ULL, + 11770536856753169052ULL, + 10235011131852468900ULL, + 1072964867822001216ULL, + 13619887703252093232ULL, + 18391649697943490473ULL, + 18093904010938109874ULL, + 11549281178545994485ULL, + 10015465696907054491ULL, + 9522424567678024659ULL, + 958562519378755243ULL, + 8815932453297826596ULL, + 3793526591342487783ULL, + 15361149787930270952ULL, + 16936900857574639414ULL, + 15139885160611612673ULL, + 15105382025433778961ULL, + 15733339691970465653ULL, + 11409124095897674590ULL, + 6111013581163483651ULL, + 9870054381414636402ULL, + 2791460873620210993ULL, + 8925042953576419475ULL, + 3167466619897242419ULL, + 7401815536436090713ULL, + 4271854768733914986ULL, + 14899911933708582966ULL, + 3060822028451953922ULL, + 9482327649482221372ULL, + 12776795845580406470ULL, + 10355053788563502996ULL, + 2186419616974263029ULL, + 7932567811822424209ULL, + 8412652544079840254ULL, + 1450744683715879429ULL, + 163524142915937711ULL, + 10857738891896952918ULL, + 7950960701748009217ULL, + 1336704191636846515ULL, + 9602697628108294898ULL, + 5237472449341287884ULL, + 3004414544783109266ULL, + 2288671354231846516ULL, + 14462048579805032841ULL, + 16497466076597921885ULL, + 2422968326997056791ULL, + 17093585686890552908ULL, + 7008260601901859897ULL, + 772387123969640815ULL, + 17257604466039307293ULL, + 6177005793806720530ULL, + 10475627877378804210ULL, + 7173179795076877537ULL, + 4511684077822430105ULL, + 6191641533832289146ULL, + 15305403538331250672ULL, + 5526308220324156010ULL, + 14672422497004718835ULL, + 12168912400829836162ULL, + 5818746340942803557ULL, + 7488040716460863238ULL, + 2059647581273923268ULL, + 15889467027030789294ULL, + 10367234624770273172ULL, + 4210010374068435599ULL, + 7337838945831991083ULL, + 10326061216419127304ULL, + 15176521264215768360ULL, + 7992999815845194130ULL, + 13458489854427135351ULL, + 9456267632359893319ULL, + 15826677899760127850ULL, + 789615342325490832ULL, + 10392147556494936760ULL, + 523988650276519953ULL, + 5942715721655074395ULL, + 4279387130933716623ULL, + 12876062619732678803ULL, + 9849972657322580428ULL, + 18241777568169768774ULL, + 3461221923646841840ULL, + 17812953816186353695ULL, + 10035437433967142392ULL, + 5829652815681008540ULL, + 1768441371440303778ULL, + 7314967576490312227ULL, + 8268757676735577511ULL, + 3463627440118742411ULL, + 13200381296958668038ULL, + 12980628773855430839ULL, + 17850769602406652193ULL, + 983260975751526386ULL, + 5282743060041635780ULL, + 9628481534517896495ULL, + 4831481600009339582ULL, + 14027513523086340880ULL, + 9799155396934816180ULL, + 850866660284251996ULL, + 1884059305190782189ULL, + 10969687849460857926ULL, + 8520820316423994487ULL, + 14210047397828859566ULL, + 3150207719604427670ULL, + 2011381390162905697ULL, + 2302677705705941711ULL, + 15415648778690979269ULL, + 2003705178534255993ULL, + 266210929326678295ULL, + 8503826411537503358ULL, + 8118899279891613837ULL, + 1909727583878668506ULL, + 18214770691185680017ULL, + 17860352232051069426ULL, + 1874649358753100233ULL, + 16150288518017844996ULL, + 10908266054085243496ULL, + 9448821761601322068ULL, + 7668102648098763997ULL, + 12084911726322979032ULL, + 11745335840501595317ULL, + 13408387385937465826ULL, + 9503140967931012096ULL, + 17305388682757492961ULL, + 13994882590480791537ULL, + 7710768143157155409ULL, + 10058934475153258452ULL, + 889529656975610367ULL, + 17501891925179045351ULL, + 2511127101502798552ULL, + 8839728548278280241ULL, + 7610157981400857721ULL, + 12329765704925272718ULL, + 15502290751436039814ULL, + 3467596558526815705ULL, + 13741715077127214418ULL, + 16071609315659602765ULL, + 4909783854943514884ULL, + 10245650141242262203ULL, + 18104431259550050027ULL, + 7509305619947907847ULL, + 8636083477580252091ULL, + 15754995469565603546ULL, + 17729918037200187793ULL, + 17806559117086019329ULL, + 8269427975913509762ULL, + 9834512220178345653ULL, + 10479389161178402976ULL, + 12902352959295155618ULL, + 9698926580229868124ULL, + 16999739755426420005ULL, + 18037065378422188524ULL, + 10339444172801917409ULL, + 18260539561992921042ULL, + 7728717400520896927ULL, + 2028310164084501042ULL, + 14786181034453013211ULL, + 15972131280930178234ULL, + 7005948717104584957ULL, + 2657253693528720718ULL, + 15140938488194780665ULL, + 1644071737192856889ULL, + 943722237332680239ULL, + 13901954349923851638ULL, + 8970542817827549399ULL, + 5632620091774612041ULL, + 16526698597433095286ULL, + 8090008055596358233ULL, + 12553586129223566287ULL, + 3468659904545987260ULL, + 2046836608625709231ULL, + 4123090275117598325ULL, + 4591355515279037897ULL, + 11961791043413958350ULL, + 7348417959200381745ULL, + 10411592048552916539ULL, + 8793326178444087793ULL, + 13876827735870195951ULL, + 6644360989480600893ULL, + 14025457629247593152ULL, + 4513272951893284540ULL, + 13128914053337671479ULL, + 13109902548704574341ULL, + 17965102580414593907ULL, + 3497785377874433468ULL, + 6592659210759850992ULL, + 849780963425040089ULL, + 13407450541085723044ULL, + 3142607466994697837ULL, + 10487362098726690676ULL, + 8000017985121402796ULL, + 16229001972616640379ULL, + 4190525388456750259ULL, + 7131736966113042130ULL, + 393754149541519950ULL, + 9021483885850257543ULL, + 880628001451069942ULL, + 2456011357860478670ULL, + 9512382357407984953ULL, + 9567445262865526187ULL, + 5622576562091547940ULL, + 12010628593542422214ULL, + 2673675480642894087ULL, + 17873876513855936010ULL, + 6400997916752595245ULL, + 17433857625895889202ULL, + 1539597315628812243ULL, + 16367691874358401541ULL, + 12972645078540496386ULL, + 16332643295563214814ULL, + 5544419382234550564ULL, + 11798638848854188314ULL, + 486689336010388240ULL, + 7317074378052836800ULL, + 8741910395652706431ULL, + 13665208404054208576ULL, + 2508078817595526498ULL, + 2872676758538201778ULL, + 3549193584688174869ULL, + 9009335680515866104ULL, + 10713411898937083823ULL, + 15464612718315985926ULL, + 7615072156271860809ULL, + 14914107511035093380ULL, + 5583311102414977360ULL, + 6956159176990685183ULL, + 8013337361816905284ULL, + 13762177540916346578ULL, + 7258326134248558308ULL, + 8086663508963934714ULL, + 11222629515295099057ULL, + 12934546986105819834ULL, + 3375336109308423287ULL, + 12716089751017182151ULL, + 12547318721692727572ULL, + 17281346430985779486ULL, + 400965970431834025ULL, + 12530855862178391327ULL, + 951577620049905892ULL, + 1314717139649793911ULL, + 1989908152766874006ULL, + 4137737603991666707ULL, + 7630077423434347245ULL, + 14369359005391472706ULL, + 13088246355448796854ULL, + 15809887090589376135ULL, + 4445611905757275511ULL, + 15016819313000923244ULL, + 9584610995364009809ULL, + 13898392893534522022ULL, + 632081359975545982ULL, + 13824793422601161277ULL, + 7546978750742936895ULL, + 12148216112548024944ULL, + 8101733006675058847ULL, + 13234442831141496925ULL, + 14503793958685224522ULL, + 16130208160871810116ULL, + 735708471483362249ULL, + 15174415054887119353ULL, + 5583311102414977360ULL, + 6956159176990685183ULL, + 8013337361816905284ULL, + 13762177540916346578ULL, + 6872792213985253883ULL, + 11866960051551136468ULL, + 3284956605510150037ULL, + 18272495014040966382ULL, + 2253874924550340375ULL, + 5361267572694740604ULL, + 3387461847468276736ULL, + 4816621589193384266ULL, + 10800689352553749447ULL, + 12960362351868905358ULL, + 3542399137389217490ULL, + 9589079103820232347ULL, + 85963991164936734ULL, + 2227852187644274474ULL, + 376957765721729739ULL, + 10642827303422387415ULL, + 6932028066601367085ULL, + 13149054136258882935ULL, + 3522067966996195358ULL, + 13351035200828128914ULL, + 5562232340339399790ULL, + 9588744675269330967ULL, + 2227449765858941725ULL, + 5114057653779050264ULL, + 10484478143241778864ULL, + 14417220749155609985ULL, + 3199353669607979588ULL, + 14489012408971012439ULL, + 268714303673955601ULL, + 1593489763833271619ULL, + 8751239511220014877ULL, + 12920163691700317364ULL, + 2842247816226035776ULL, + 4628728773878494017ULL, + 9217421833414337051ULL, + 9931085806157225967ULL, + 10300303007494722708ULL, + 18109747944875003457ULL, + 13854802172090512821ULL, + 15913288008404543087ULL, + 8406721674685601704ULL, + 12138119422365636042ULL, + 4934803708126460714ULL, + 13640238348814506447ULL, + 2252295371188677276ULL, + 4323623252638119770ULL, + 1559714830439136182ULL, + 3129384027113917805ULL, + 8205892416128030744ULL, + 12013059732770065448ULL, + 1736597541325048159ULL, + 12704921085341500057ULL, + 10786926569370648579ULL, + 10967429531679736159ULL, + 9868701286980294225ULL, + 13226807552722643352ULL, + 7457714179113167933ULL, + 17664785444522230118ULL, + 2143588703984313221ULL, + 5432220740469013417ULL, + 15050984304690947474ULL, + 18435722720567715923ULL, + 2471287981841891685ULL, + 11097324843825457366ULL, + 7870035521710867130ULL, + 17760017321126174374ULL, + 11246124607220080893ULL, + 17459030633861259631ULL, + 350445937154391169ULL, + 15433269434921126834ULL, + 5583311102414977360ULL, + 6956159176990685183ULL, + 8013337361816905284ULL, + 13762177540916346578ULL, + 15560445074040628713ULL, + 17316783551482020286ULL, + 11023129892124393575ULL, + 12740418521073480179ULL, + 7718243230082107432ULL, + 10712695294937099603ULL, + 2049946930749856095ULL, + 14682335986909469765ULL, + 386825383242076328ULL, + 11591728398066050651ULL, + 4404107260675827346ULL, + 4843235926567356613ULL, + 1391227341105983445ULL, + 13743146942910569874ULL, + 7397892285968953013ULL, + 8931545346955793229ULL, + 424463301013089419ULL, + 2847123270169497985ULL, + 11813425834042654268ULL, + 14123054681389013777ULL, + 1515887212438864144ULL, + 6648394323518632584ULL, + 13821568671215133569ULL, + 17961729739223385046ULL, + 14998607249742899988ULL, + 16144917768412576968ULL, + 3728997555119537374ULL, + 8117068499386112184ULL, + 9419571945793732805ULL, + 15098711481331992326ULL, + 4454445956957434156ULL, + 17921720099607672683ULL, + 699237918005460058ULL, + 11148447783838166587ULL, + 7451818450109775278ULL, + 12169560101362116951ULL, + 12603931958331359434ULL, + 14842481548366161729ULL, + 14492116736800912740ULL, + 16138278964589138890ULL, + 1441403774930152766ULL, + 5550922573190960100ULL, + 8424385859162442071ULL, + 11361278480870717714ULL, + 11177725332590072487ULL, + 13725328338717181849ULL, + 12148461992080744ULL, + 2547018582278349403ULL, + 4470781364907049310ULL, + 15447061967772956394ULL, + 1742578175112328061ULL, + 13948938859310030618ULL, + 3092740234469735047ULL, + 9222563256183327707ULL, + 2205539605946066285ULL, + 13632492719874620769ULL, + 3475237893523192097ULL, + 3882391735301016185ULL, + 1143016561259179119ULL, + 2426097698954597720ULL, + 3259401975160948368ULL, + 16098053132356951842ULL, + 6161394358800582878ULL, + 11393783516240760086ULL, + 15310940882298368180ULL, + 17436060388632399317ULL, + 3442384790393669236ULL, + 10633579737091414036ULL, + 5363289269962271266ULL, + 14985502196251294755ULL, + 6587125754455795537ULL, + 10040393922414315239ULL, + 12399413294818033125ULL, + 15506906115838272659ULL, + 15721509029686946391ULL, + 15754318294414387029ULL, + 1210753613532932856ULL, + 15188337242653329367ULL, + 9621387921860241543ULL, + 10022935013598545678ULL, + 5583311102414977360ULL, + 6956159176990685183ULL, + 8013337361816905284ULL, + 13762177540916346578ULL, + 1472000411760151912ULL, + 15338104034948352690ULL, + 28233558798646693ULL, + 540268673608007997ULL, + 2826211525802281318ULL, + 13773207864081653989ULL, + 12035297949179344643ULL, + 17437622499582134551ULL, + 9400728750751826011ULL, + 17212987013537429632ULL, + 5904471541918112464ULL, + 10845965522400668441ULL, + 4700788286972175527ULL, + 17218426743681445057ULL, + 13673199713827588666ULL, + 14059867479293001785ULL, + 7536060387552693602ULL, + 13483694734813910547ULL, + 2330674106585769483ULL, + 5433379576209208690ULL, + 3860892328078158089ULL, + 10539719455351997914ULL, + 7596916747274788156ULL, + 9998725085174771865ULL, + 4910821057691494999ULL, + 10379854265207041081ULL, + 4055649157388131983ULL, + 6827285710817934989ULL, + 5583311102414977360ULL, + 6956159176990685183ULL, + 8013337361816905284ULL, + 13762177540916346578ULL, + 16601876833271679128ULL, + 17933048647834100352ULL, + 9994372029108893445ULL, + 17235886551195271716ULL, + 9916956246407479923ULL, + 11310688517458467625ULL, + 15828660575126113389ULL, + 16005844041928436000ULL, + 15150887101477652590ULL, + 18139662823801878918ULL, + 5861106477829891456ULL, + 6478193003584157256ULL, + 4508826988544278276ULL, + 14346076680491364982ULL, + 1302848604526722411ULL, + 1676801411344493674ULL, + 13573284467058330968ULL, + 15771610392318201866ULL, + 5816387755254125953ULL, + 13380095146038695368ULL, + 8400877370008977028ULL, + 9596853678201723997ULL, + 10851054790269389672ULL, + 14157729107132703755ULL, + 831506358671102940ULL, + 9613582349577509657ULL, + 438089618012882720ULL, + 7151475927094984762ULL, + 1916111134778225510ULL, + 17949022266917285953ULL, + 1806548624629009301ULL, + 3991509517070584848ULL, + 354782906731362002ULL, + 7153821901187012687ULL, + 1221977353154720976ULL, + 12458183130939652666ULL, + 3357157716007903686ULL, + 6777924697473292650ULL, + 1077255318505868591ULL, + 3037082429151868605ULL, + 6921690843863051372ULL, + 18264282417604460305ULL, + 1090450176110968225ULL, + 1994649920422828337ULL, + 3648713336055536950ULL, + 5599297056790554891ULL, + 5259180912693154703ULL, + 8694194636645199801ULL, + 8920073411195063911ULL, + 16208895895165504697ULL, + 160798113954230881ULL, + 8917409258240209430ULL, + 4317697540288521561ULL, + 11586380793411943747ULL, + 961161780596367719ULL, + 16101399163556326532ULL, + 5854893038451787578ULL, + 14361100464732556800ULL, + 514593158128880588ULL, + 13063955595781974620ULL, + 10576725507725288399ULL, + 13172996163158406668ULL, + 14136179074818415187ULL, + 18168724538299929937ULL, + 15706023283429961797ULL, + 17304152442712939887ULL, + 4205102861814058866ULL, + 7951998829421737319ULL, + 7569634653764163627ULL, + 8055064556988923467ULL, + 16930807899198319847ULL, + 17475495627690394876ULL, + 11460178804765608450ULL, + 17163954454674366730ULL, + 1747686676058709609ULL, + 8399866140162745832ULL, + 5583311102414977360ULL, + 6956159176990685183ULL, + 8013337361816905284ULL, + 13762177540916346578ULL, + 5314927110113176216ULL, + 12725085861509002909ULL, + 3197897894057655618ULL, + 8262906799923532419ULL, + 7897397697705580159ULL, + 9160734563216424440ULL, + 13767520464010510168ULL, + 18078979258833386239ULL, + 10073206724900292034ULL, + 13849076872517480735ULL, + 18429668117940514005ULL, + 7440489770734063325ULL, + 1423900708842059394ULL, + 7094898889553293067ULL, + 886648277580955956ULL, + 14299071773172638904ULL, + 710525103587420439ULL, + 6620180045559973409ULL, + 5288665774066796459ULL, + 5660769278996937049ULL, + 9839713553644646245ULL, + 10969989520843757600ULL, + 15802164857382625446ULL, + 11244032945739168043ULL, + 12693031689916708649ULL, + 18405444303499384475ULL, + 16026456632814162093ULL, + 8847978430435923521ULL, + 5526438917517146232ULL, + 2246383757539244439ULL, + 1320337708119273452ULL, + 8554933506460022001ULL, + 12555692895501030879ULL, + 287001085709158758ULL, + 6704855747187151356ULL, + 10595587765337020713ULL, + 10552040695950553827ULL, + 11986083926330925446ULL, + 8603255517581384793ULL, + 1205644806060190216ULL, + 6980265981502670506ULL, + 13002562640235090711ULL, + 12390877214991177129ULL, + 2959072827274921494ULL, + 14173055219559785586ULL, + 2862231792760742738ULL, + 3786354589105614366ULL, + 9880161491145310326ULL, + 12817616178790611525ULL, + 3172925410323942536ULL, + 4525870802304008530ULL, + 10081290410599317927ULL, + 16438840523084005202ULL, + 2020446642804707180ULL, + 9467445922909992504ULL, + 9493376736330190740ULL, + 14184165738848430804ULL, + 3801310233812633186ULL, + 8507523064837735137ULL, + 1517032706130222609ULL, + 4864142816250727554ULL, + 13814178386286735374ULL, + 15541521772105781030ULL, + 8574627807615217828ULL, + 15040568176004312439ULL, + 1932827178698369563ULL, + 18317417603313955804ULL, + 2775404842614851980ULL, + 5045767340574032529ULL, + 5022260537738331048ULL, + 14474667286231720386ULL, + 6573647209722489070ULL, + 8004136303650966655ULL, + 560742635572337622ULL, + 15245902287162046782ULL, + 14167402781644531131ULL, + 15135021745053791386ULL, + 2433353285809394856ULL, + 14013523061014918213ULL, + 3927739452733298885ULL, + 17175307812527117424ULL, + 8343513849039216405ULL, + 9380033211727249636ULL, + 14124817632124204796ULL, + 15891553324720167260ULL, + 5169522641441320490ULL, + 7754907700944566759ULL, + 9702670845894230940ULL, + 14937110477244037500ULL, + 582384558709911474ULL, + 4752760370557577059ULL, + 12990202465913525228ULL, + 14877040204504612344ULL, + 1468872662009439723ULL, + 6599474490138430280ULL, + 7367028978213327327ULL, + 11806646037203235002ULL, + 7252357809340482349ULL, + 16380072760133538801ULL, + 1810189678238183519ULL, + 11952192635498982980ULL, + 6393987794231683516ULL, + 7317364050014395380ULL, + 11122981681402595457ULL, + 18119052084667581444ULL, + 3259453819947264071ULL, + 13810812294857498477ULL, + 940228929661630858ULL, + 3909306601518296994ULL, + 3314344353161995180ULL, + 10119235484491681673ULL, + 13884754652536460586ULL, + 18436818431849160009ULL, + 4536482792412525568ULL, + 5103715047343330818ULL, + 11889837525952019522ULL, + 16678698837446848916ULL, + 12502235984649306725ULL, + 14532583765549771563ULL, + 5874155848665228458ULL, + 13705074436160840521ULL, + 2402150787625053058ULL, + 7150957921327243993ULL, + 14096077986414617468ULL, + 17996119415619632171ULL, + 2506046804846075378ULL, + 15230279272502707169ULL, + 11114201292965676150ULL, + 18429896768667313635ULL, + 707370238069584808ULL, + 12237319676462201242ULL, + 7394175552056547505ULL, + 15824637942306536514ULL, + 2614870163918939068ULL, + 14536400448291492593ULL, + 11168154979907483118ULL, + 15630326732539866379ULL, + 62933783734128509ULL, + 11615800759524666719ULL, + 4976701809188543339ULL, + 16124135707739767289ULL, + 5343707318254026474ULL, + 14505662792086768224ULL, + 1042583409457797016ULL, + 17225771107202741088ULL, + 6470973811093890116ULL, + 9576864872551449313ULL, + 12919032604775488776ULL, + 13585301693808849824ULL, + 13122897494295712416ULL, + 15017125759361415086ULL, + 7869995132864960424ULL, + 16003573375832508953ULL, + 15906047576581094778ULL, +}; + +const std::pair GameFiles[] = { + { "#ActD_Africa.ar.00", 2 }, + { "#ActD_Africa.arl", 2 }, + { "#ActD_Beach.ar.00", 2 }, + { "#ActD_Beach.ar.01", 2 }, + { "#ActD_Beach.arl", 2 }, + { "#ActD_China.ar.00", 2 }, + { "#ActD_China.arl", 2 }, + { "#ActD_EU.ar.00", 2 }, + { "#ActD_EU.arl", 2 }, + { "#ActD_EggmanLand.ar.00", 2 }, + { "#ActD_EggmanLand.arl", 2 }, + { "#ActD_Mission_Africa.ar.00", 2 }, + { "#ActD_Mission_Africa.arl", 2 }, + { "#ActD_Mission_Beach.ar.00", 2 }, + { "#ActD_Mission_Beach.arl", 2 }, + { "#ActD_Mission_China.ar.00", 2 }, + { "#ActD_Mission_China.arl", 2 }, + { "#ActD_Mission_EU.ar.00", 2 }, + { "#ActD_Mission_EU.arl", 2 }, + { "#ActD_Mission_Mykonos.ar.00", 2 }, + { "#ActD_Mission_Mykonos.arl", 2 }, + { "#ActD_Mission_NY.ar.00", 2 }, + { "#ActD_Mission_NY.arl", 2 }, + { "#ActD_Mission_Petra.ar.00", 2 }, + { "#ActD_Mission_Petra.arl", 2 }, + { "#ActD_Mission_Snow.ar.00", 2 }, + { "#ActD_Mission_Snow.arl", 2 }, + { "#ActD_MykonosAct1.ar.00", 2 }, + { "#ActD_MykonosAct1.arl", 2 }, + { "#ActD_MykonosAct2.ar.00", 2 }, + { "#ActD_MykonosAct2.arl", 2 }, + { "#ActD_NY.ar.00", 2 }, + { "#ActD_NY.arl", 2 }, + { "#ActD_Petra.ar.00", 2 }, + { "#ActD_Petra.arl", 2 }, + { "#ActD_Snow.ar.00", 2 }, + { "#ActD_Snow.arl", 2 }, + { "#ActD_SubAfrica_01.ar.00", 2 }, + { "#ActD_SubAfrica_01.arl", 2 }, + { "#ActD_SubAfrica_03.ar.00", 2 }, + { "#ActD_SubAfrica_03.arl", 2 }, + { "#ActD_SubBeach_02.ar.00", 2 }, + { "#ActD_SubBeach_02.arl", 2 }, + { "#ActD_SubBeach_04.ar.00", 2 }, + { "#ActD_SubBeach_04.arl", 2 }, + { "#ActD_SubChina_03.ar.00", 2 }, + { "#ActD_SubChina_03.arl", 2 }, + { "#ActD_SubChina_04.ar.00", 2 }, + { "#ActD_SubChina_04.arl", 2 }, + { "#ActD_SubEU_01.ar.00", 2 }, + { "#ActD_SubEU_01.arl", 2 }, + { "#ActD_SubEU_02.ar.00", 2 }, + { "#ActD_SubEU_02.arl", 2 }, + { "#ActD_SubMykonos_01.ar.00", 2 }, + { "#ActD_SubMykonos_01.arl", 2 }, + { "#ActD_SubNY_01.ar.00", 2 }, + { "#ActD_SubNY_01.arl", 2 }, + { "#ActD_SubPetra_03.ar.00", 2 }, + { "#ActD_SubPetra_03.arl", 2 }, + { "#ActD_SubSnow_01.ar.00", 2 }, + { "#ActD_SubSnow_01.arl", 2 }, + { "#ActN_AfricaEvil.ar.00", 2 }, + { "#ActN_AfricaEvil.arl", 2 }, + { "#ActN_BeachEvil.ar.00", 2 }, + { "#ActN_BeachEvil.arl", 2 }, + { "#ActN_ChinaEvil.ar.00", 2 }, + { "#ActN_ChinaEvil.arl", 2 }, + { "#ActN_EUEvil.ar.00", 2 }, + { "#ActN_EUEvil.arl", 2 }, + { "#ActN_EggmanLand.ar.00", 2 }, + { "#ActN_EggmanLand.arl", 2 }, + { "#ActN_MissionEU_01.ar.00", 2 }, + { "#ActN_MissionEU_01.arl", 2 }, + { "#ActN_MissionEU_02.ar.00", 2 }, + { "#ActN_MissionEU_02.arl", 2 }, + { "#ActN_MissionEU_03.ar.00", 2 }, + { "#ActN_MissionEU_03.arl", 2 }, + { "#ActN_Mission_Africa.ar.00", 2 }, + { "#ActN_Mission_Africa.arl", 2 }, + { "#ActN_Mission_Beach.ar.00", 2 }, + { "#ActN_Mission_Beach.arl", 2 }, + { "#ActN_Mission_China.ar.00", 2 }, + { "#ActN_Mission_China.arl", 2 }, + { "#ActN_Mission_Mykonos.ar.00", 2 }, + { "#ActN_Mission_Mykonos.arl", 2 }, + { "#ActN_Mission_NY.ar.00", 2 }, + { "#ActN_Mission_NY.arl", 2 }, + { "#ActN_Mission_Petra.ar.00", 2 }, + { "#ActN_Mission_Petra.arl", 2 }, + { "#ActN_Mission_Snow.ar.00", 2 }, + { "#ActN_Mission_Snow.arl", 2 }, + { "#ActN_MykonosEvil.ar.00", 2 }, + { "#ActN_MykonosEvil.arl", 2 }, + { "#ActN_NYEvil.ar.00", 2 }, + { "#ActN_NYEvil.arl", 2 }, + { "#ActN_PetraEvil.ar.00", 2 }, + { "#ActN_PetraEvil.arl", 2 }, + { "#ActN_SnowEvil.ar.00", 2 }, + { "#ActN_SnowEvil.arl", 2 }, + { "#ActN_SubAfrica_01.ar.00", 2 }, + { "#ActN_SubAfrica_01.arl", 2 }, + { "#ActN_SubBeach_01.ar.00", 2 }, + { "#ActN_SubBeach_01.arl", 2 }, + { "#ActN_SubChina_01.ar.00", 2 }, + { "#ActN_SubChina_01.arl", 2 }, + { "#ActN_SubMykonos_01.ar.00", 2 }, + { "#ActN_SubMykonos_01.arl", 2 }, + { "#Act_EggmanLand.ar.00", 2 }, + { "#Act_EggmanLand.ar.01", 2 }, + { "#Act_EggmanLand.arl", 2 }, + { "#ActionCommon.ar.00", 2 }, + { "#ActionCommon.arl", 2 }, + { "#Application.ar.00", 2 }, + { "#Application.arl", 2 }, + { "#BossDarkGaia1_1Air.ar.00", 2 }, + { "#BossDarkGaia1_1Air.arl", 2 }, + { "#BossDarkGaia1_1Run.ar.00", 2 }, + { "#BossDarkGaia1_1Run.arl", 2 }, + { "#BossDarkGaia1_2Run.ar.00", 2 }, + { "#BossDarkGaia1_2Run.arl", 2 }, + { "#BossDarkGaia1_3Run.ar.00", 2 }, + { "#BossDarkGaia1_3Run.arl", 2 }, + { "#BossDarkGaiaMoray.ar.00", 2 }, + { "#BossDarkGaiaMoray.arl", 2 }, + { "#BossEggBeetle.ar.00", 2 }, + { "#BossEggBeetle.arl", 2 }, + { "#BossEggDragoon.ar.00", 2 }, + { "#BossEggDragoon.arl", 2 }, + { "#BossEggLancer.ar.00", 2 }, + { "#BossEggLancer.arl", 2 }, + { "#BossEggRayBird.ar.00", 2 }, + { "#BossEggRayBird.arl", 2 }, + { "#BossFinalDarkGaia.ar.00", 2 }, + { "#BossFinalDarkGaia.arl", 2 }, + { "#BossPetra.ar.00", 2 }, + { "#BossPetra.arl", 2 }, + { "#BossPhoenix.ar.00", 2 }, + { "#BossPhoenix.arl", 2 }, + { "#CmnTown_Africa.ar.00", 2 }, + { "#CmnTown_Africa.arl", 2 }, + { "#CmnTown_China.ar.00", 2 }, + { "#CmnTown_China.arl", 2 }, + { "#CmnTown_EuropeanCity.ar.00", 2 }, + { "#CmnTown_EuropeanCity.arl", 2 }, + { "#CmnTown_Mykonos.ar.00", 2 }, + { "#CmnTown_Mykonos.arl", 2 }, + { "#CmnTown_NYCity.ar.00", 2 }, + { "#CmnTown_NYCity.arl", 2 }, + { "#CmnTown_PetraCapital.ar.00", 2 }, + { "#CmnTown_PetraCapital.arl", 2 }, + { "#CmnTown_Snow.ar.00", 2 }, + { "#CmnTown_Snow.arl", 2 }, + { "#CmnTown_SouthEastAsia.ar.00", 2 }, + { "#CmnTown_SouthEastAsia.arl", 2 }, + { "#EggFighterEquipments.ar.00", 2 }, + { "#EggFighterEquipments.arl", 2 }, + { "#Event_M2_01_professor_room_new.ar.00", 2 }, + { "#Event_M2_01_professor_room_new.arl", 2 }, + { "#Event_M4_01_egb_hideout.ar.00", 2 }, + { "#Event_M4_01_egb_hideout.arl", 2 }, + { "#Event_M6_01_temple.ar.00", 2 }, + { "#Event_M6_01_temple.arl", 2 }, + { "#Event_M8_01.ar.00", 2 }, + { "#Event_M8_01.arl", 2 }, + { "#Event_M8_02_egbHall.ar.00", 2 }, + { "#Event_M8_02_egbHall.arl", 2 }, + { "#Event_M8_03.ar.00", 2 }, + { "#Event_M8_03.arl", 2 }, + { "#Event_M8_16_myk.ar.00", 2 }, + { "#Event_M8_16_myk.arl", 2 }, + { "#Event_afr_hideout.ar.00", 2 }, + { "#Event_afr_hideout.arl", 2 }, + { "#Event_egb_hidout_exterior.ar.00", 2 }, + { "#Event_egb_hidout_exterior.arl", 2 }, + { "#Event_temple.ar.00", 2 }, + { "#Event_temple.arl", 2 }, + { "#EvilActionCommon.ar.00", 2 }, + { "#EvilActionCommon.arl", 2 }, + { "#EvilActionCommonGeneral.ar.00", 2 }, + { "#EvilActionCommonGeneral.arl", 2 }, + { "#EvilActionCommon_Africa.ar.00", 2 }, + { "#EvilActionCommon_Africa.arl", 2 }, + { "#EvilActionCommon_Beach.ar.00", 2 }, + { "#EvilActionCommon_Beach.arl", 2 }, + { "#EvilActionCommon_China.ar.00", 2 }, + { "#EvilActionCommon_China.arl", 2 }, + { "#EvilActionCommon_EU.ar.00", 2 }, + { "#EvilActionCommon_EU.arl", 2 }, + { "#EvilActionCommon_EggmanLand.ar.00", 2 }, + { "#EvilActionCommon_EggmanLand.arl", 2 }, + { "#EvilActionCommon_Mykonos.ar.00", 2 }, + { "#EvilActionCommon_Mykonos.arl", 2 }, + { "#EvilActionCommon_NY.ar.00", 2 }, + { "#EvilActionCommon_NY.arl", 2 }, + { "#EvilActionCommon_Petra.ar.00", 2 }, + { "#EvilActionCommon_Petra.arl", 2 }, + { "#EvilActionCommon_Snow.ar.00", 2 }, + { "#EvilActionCommon_Snow.arl", 2 }, + { "#EvilEnemyBigMother.ar.00", 2 }, + { "#EvilEnemyBigMother.arl", 2 }, + { "#EvilEnemyChibiFighter.ar.00", 2 }, + { "#EvilEnemyChibiFighter.arl", 2 }, + { "#EvilEnemyEThunderBall.ar.00", 2 }, + { "#EvilEnemyEThunderBall.arl", 2 }, + { "#EvilEnemyEggElement.ar.00", 2 }, + { "#EvilEnemyEggElement.arl", 2 }, + { "#EvilEnemyEggFighter.ar.00", 2 }, + { "#EvilEnemyEggFighter.arl", 2 }, + { "#EvilEnemyFloat.ar.00", 2 }, + { "#EvilEnemyFloat.arl", 2 }, + { "#EvilEnemyFlower.ar.00", 2 }, + { "#EvilEnemyFlower.arl", 2 }, + { "#EvilEnemyKillerBee.ar.00", 2 }, + { "#EvilEnemyKillerBee.arl", 2 }, + { "#EvilEnemyMaster.ar.00", 2 }, + { "#EvilEnemyMaster.arl", 2 }, + { "#EvilEnemyMoleel.ar.00", 2 }, + { "#EvilEnemyMoleel.arl", 2 }, + { "#EvilEnemyNightmareR.ar.00", 2 }, + { "#EvilEnemyNightmareR.arl", 2 }, + { "#EvilEnemyReckless.ar.00", 2 }, + { "#EvilEnemyReckless.arl", 2 }, + { "#EvilEnemySpooky.ar.00", 2 }, + { "#EvilEnemySpooky.arl", 2 }, + { "#EvilEnemyTitan.ar.00", 2 }, + { "#EvilEnemyTitan.arl", 2 }, + { "#EvilSonic.ar.00", 2 }, + { "#EvilSonic.arl", 2 }, + { "#ExStageTails1.ar.00", 2 }, + { "#ExStageTails1.arl", 2 }, + { "#ExStageTails2.ar.00", 2 }, + { "#ExStageTails2.arl", 2 }, + { "#ExStageTails_Common.ar.00", 2 }, + { "#ExStageTails_Common.arl", 2 }, + { "#SelectStage.ar.00", 2 }, + { "#SelectStage.arl", 2 }, + { "#Sonic.ar.00", 2 }, + { "#Sonic.arl", 2 }, + { "#SonicActionCommon.ar.00", 2 }, + { "#SonicActionCommon.arl", 2 }, + { "#SonicActionCommonGeneral.ar.00", 2 }, + { "#SonicActionCommonGeneral.arl", 2 }, + { "#SonicActionCommon_Africa.ar.00", 2 }, + { "#SonicActionCommon_Africa.arl", 2 }, + { "#SonicActionCommon_Beach.ar.00", 2 }, + { "#SonicActionCommon_Beach.arl", 2 }, + { "#SonicActionCommon_China.ar.00", 2 }, + { "#SonicActionCommon_China.arl", 2 }, + { "#SonicActionCommon_EU.ar.00", 2 }, + { "#SonicActionCommon_EU.arl", 2 }, + { "#SonicActionCommon_EggmanLand.ar.00", 2 }, + { "#SonicActionCommon_EggmanLand.arl", 2 }, + { "#SonicActionCommon_Mykonos.ar.00", 2 }, + { "#SonicActionCommon_Mykonos.arl", 2 }, + { "#SonicActionCommon_NY.ar.00", 2 }, + { "#SonicActionCommon_NY.arl", 2 }, + { "#SonicActionCommon_Petra.ar.00", 2 }, + { "#SonicActionCommon_Petra.arl", 2 }, + { "#SonicActionCommon_Snow.ar.00", 2 }, + { "#SonicActionCommon_Snow.arl", 2 }, + { "#SonicEnemyEAirCannon.ar.00", 2 }, + { "#SonicEnemyEAirCannon.arl", 2 }, + { "#SonicEnemyEAirChaser.ar.00", 2 }, + { "#SonicEnemyEAirChaser.arl", 2 }, + { "#SonicEnemyEBigChaser.ar.00", 2 }, + { "#SonicEnemyEBigChaser.arl", 2 }, + { "#SonicEnemyEElement.ar.00", 2 }, + { "#SonicEnemyEElement.arl", 2 }, + { "#SonicEnemyEFighterG.ar.00", 2 }, + { "#SonicEnemyEFighterG.arl", 2 }, + { "#SonicEnemyEFighterK.ar.00", 2 }, + { "#SonicEnemyEFighterK.arl", 2 }, + { "#SonicEnemyEFighterN.ar.00", 2 }, + { "#SonicEnemyEFighterN.arl", 2 }, + { "#SonicEnemyEFighterS.ar.00", 2 }, + { "#SonicEnemyEFighterS.arl", 2 }, + { "#SonicEnemyEMoleCannon.ar.00", 2 }, + { "#SonicEnemyEMoleCannon.arl", 2 }, + { "#SonicEnemyEShackle.ar.00", 2 }, + { "#SonicEnemyEShackle.arl", 2 }, + { "#SonicEnemyEShooter.ar.00", 2 }, + { "#SonicEnemyEShooter.arl", 2 }, + { "#SonicEnemyESpinner.ar.00", 2 }, + { "#SonicEnemyESpinner.arl", 2 }, + { "#SonicEnemyEThunderBall.ar.00", 2 }, + { "#SonicEnemyEThunderBall.arl", 2 }, + { "#StaffRoll.ar.00", 2 }, + { "#StaffRoll.arl", 2 }, + { "#SystemCommon.ar.00", 2 }, + { "#SystemCommon.arl", 2 }, + { "#Title.ar.00", 2 }, + { "#Title.arl", 2 }, + { "#TitleE3.ar.00", 2 }, + { "#TitleE3.arl", 2 }, + { "#TitleModel.ar.00", 2 }, + { "#TitleModel.arl", 2 }, + { "#Town_Africa.ar.00", 2 }, + { "#Town_Africa.arl", 2 }, + { "#Town_AfricaETF.ar.00", 2 }, + { "#Town_AfricaETF.arl", 2 }, + { "#Town_AfricaETF_Common.ar.00", 2 }, + { "#Town_AfricaETF_Common.arl", 2 }, + { "#Town_AfricaETF_Night.ar.00", 2 }, + { "#Town_AfricaETF_Night.arl", 2 }, + { "#Town_Africa_Common.ar.00", 2 }, + { "#Town_Africa_Common.arl", 2 }, + { "#Town_Africa_Dispel.ar.00", 2 }, + { "#Town_Africa_Dispel.arl", 2 }, + { "#Town_Africa_Night.ar.00", 2 }, + { "#Town_Africa_Night.arl", 2 }, + { "#Town_China.ar.00", 2 }, + { "#Town_China.arl", 2 }, + { "#Town_ChinaETF.ar.00", 2 }, + { "#Town_ChinaETF.arl", 2 }, + { "#Town_ChinaETF_Common.ar.00", 2 }, + { "#Town_ChinaETF_Common.arl", 2 }, + { "#Town_ChinaETF_Night.ar.00", 2 }, + { "#Town_ChinaETF_Night.arl", 2 }, + { "#Town_China_Common.ar.00", 2 }, + { "#Town_China_Common.arl", 2 }, + { "#Town_China_Dispel.ar.00", 2 }, + { "#Town_China_Dispel.arl", 2 }, + { "#Town_China_Night.ar.00", 2 }, + { "#Town_China_Night.arl", 2 }, + { "#Town_Common.ar.00", 2 }, + { "#Town_Common.arl", 2 }, + { "#Town_EULabo.ar.00", 2 }, + { "#Town_EULabo.arl", 2 }, + { "#Town_EULabo_Common.ar.00", 2 }, + { "#Town_EULabo_Common.arl", 2 }, + { "#Town_EULabo_Night.ar.00", 2 }, + { "#Town_EULabo_Night.arl", 2 }, + { "#Town_EggManBase.ar.00", 2 }, + { "#Town_EggManBase.arl", 2 }, + { "#Town_EggManBase_Common.ar.00", 2 }, + { "#Town_EggManBase_Common.arl", 2 }, + { "#Town_EuropeanCity.ar.00", 2 }, + { "#Town_EuropeanCity.arl", 2 }, + { "#Town_EuropeanCityETF.ar.00", 2 }, + { "#Town_EuropeanCityETF.arl", 2 }, + { "#Town_EuropeanCityETF_Common.ar.00", 2 }, + { "#Town_EuropeanCityETF_Common.arl", 2 }, + { "#Town_EuropeanCityETF_Night.ar.00", 2 }, + { "#Town_EuropeanCityETF_Night.arl", 2 }, + { "#Town_EuropeanCity_Common.ar.00", 2 }, + { "#Town_EuropeanCity_Common.arl", 2 }, + { "#Town_EuropeanCity_Dispel.ar.00", 2 }, + { "#Town_EuropeanCity_Dispel.arl", 2 }, + { "#Town_EuropeanCity_Night.ar.00", 2 }, + { "#Town_EuropeanCity_Night.arl", 2 }, + { "#Town_Labo_Common.ar.00", 2 }, + { "#Town_Labo_Common.arl", 2 }, + { "#Town_Mykonos.ar.00", 2 }, + { "#Town_Mykonos.arl", 2 }, + { "#Town_MykonosETF.ar.00", 2 }, + { "#Town_MykonosETF.arl", 2 }, + { "#Town_MykonosETF_Common.ar.00", 2 }, + { "#Town_MykonosETF_Common.arl", 2 }, + { "#Town_MykonosETF_Night.ar.00", 2 }, + { "#Town_MykonosETF_Night.arl", 2 }, + { "#Town_Mykonos_Common.ar.00", 2 }, + { "#Town_Mykonos_Common.arl", 2 }, + { "#Town_Mykonos_Dispel.ar.00", 2 }, + { "#Town_Mykonos_Dispel.arl", 2 }, + { "#Town_Mykonos_Night.ar.00", 2 }, + { "#Town_Mykonos_Night.arl", 2 }, + { "#Town_NYCity.ar.00", 2 }, + { "#Town_NYCity.arl", 2 }, + { "#Town_NYCityETF.ar.00", 2 }, + { "#Town_NYCityETF.arl", 2 }, + { "#Town_NYCityETF_Common.ar.00", 2 }, + { "#Town_NYCityETF_Common.arl", 2 }, + { "#Town_NYCityETF_Night.ar.00", 2 }, + { "#Town_NYCityETF_Night.arl", 2 }, + { "#Town_NYCity_Common.ar.00", 2 }, + { "#Town_NYCity_Common.arl", 2 }, + { "#Town_NYCity_Dispel.ar.00", 2 }, + { "#Town_NYCity_Dispel.arl", 2 }, + { "#Town_NYCity_Night.ar.00", 2 }, + { "#Town_NYCity_Night.arl", 2 }, + { "#Town_PetraCapital.ar.00", 2 }, + { "#Town_PetraCapital.arl", 2 }, + { "#Town_PetraCapitalETF.ar.00", 2 }, + { "#Town_PetraCapitalETF.arl", 2 }, + { "#Town_PetraCapitalETF_Common.ar.00", 2 }, + { "#Town_PetraCapitalETF_Common.arl", 2 }, + { "#Town_PetraCapitalETF_Night.ar.00", 2 }, + { "#Town_PetraCapitalETF_Night.arl", 2 }, + { "#Town_PetraCapital_Common.ar.00", 2 }, + { "#Town_PetraCapital_Common.arl", 2 }, + { "#Town_PetraCapital_Dispel.ar.00", 2 }, + { "#Town_PetraCapital_Dispel.arl", 2 }, + { "#Town_PetraCapital_Night.ar.00", 2 }, + { "#Town_PetraCapital_Night.arl", 2 }, + { "#Town_PetraLabo.ar.00", 2 }, + { "#Town_PetraLabo.arl", 2 }, + { "#Town_PetraLabo_Common.ar.00", 2 }, + { "#Town_PetraLabo_Common.arl", 2 }, + { "#Town_PetraLabo_Night.ar.00", 2 }, + { "#Town_PetraLabo_Night.arl", 2 }, + { "#Town_Snow.ar.00", 2 }, + { "#Town_Snow.arl", 2 }, + { "#Town_SnowETF.ar.00", 2 }, + { "#Town_SnowETF.arl", 2 }, + { "#Town_SnowETF_Common.ar.00", 2 }, + { "#Town_SnowETF_Common.arl", 2 }, + { "#Town_SnowETF_Night.ar.00", 2 }, + { "#Town_SnowETF_Night.arl", 2 }, + { "#Town_Snow_Common.ar.00", 2 }, + { "#Town_Snow_Common.arl", 2 }, + { "#Town_Snow_Dispel.ar.00", 2 }, + { "#Town_Snow_Dispel.arl", 2 }, + { "#Town_Snow_Night.ar.00", 2 }, + { "#Town_Snow_Night.arl", 2 }, + { "#Town_SouthEastAsia.ar.00", 2 }, + { "#Town_SouthEastAsia.arl", 2 }, + { "#Town_SouthEastAsiaETF.ar.00", 2 }, + { "#Town_SouthEastAsiaETF.arl", 2 }, + { "#Town_SouthEastAsiaETF_Common.ar.00", 2 }, + { "#Town_SouthEastAsiaETF_Common.arl", 2 }, + { "#Town_SouthEastAsiaETF_Night.ar.00", 2 }, + { "#Town_SouthEastAsiaETF_Night.arl", 2 }, + { "#Town_SouthEastAsia_Common.ar.00", 2 }, + { "#Town_SouthEastAsia_Common.arl", 2 }, + { "#Town_SouthEastAsia_Dispel.ar.00", 2 }, + { "#Town_SouthEastAsia_Dispel.arl", 2 }, + { "#Town_SouthEastAsia_Night.ar.00", 2 }, + { "#Town_SouthEastAsia_Night.arl", 2 }, + { "#WorldMap.ar.00", 2 }, + { "#WorldMap.arl", 2 }, + { "ActD_Africa.ar.00", 2 }, + { "ActD_Africa.ar.01", 2 }, + { "ActD_Africa.ar.02", 2 }, + { "ActD_Africa.arl", 2 }, + { "ActD_Beach.ar.00", 2 }, + { "ActD_Beach.ar.01", 2 }, + { "ActD_Beach.ar.02", 2 }, + { "ActD_Beach.ar.03", 2 }, + { "ActD_Beach.ar.04", 2 }, + { "ActD_Beach.arl", 2 }, + { "ActD_China.ar.00", 2 }, + { "ActD_China.ar.01", 2 }, + { "ActD_China.ar.02", 2 }, + { "ActD_China.arl", 2 }, + { "ActD_EU.ar.00", 2 }, + { "ActD_EU.ar.01", 2 }, + { "ActD_EU.ar.02", 2 }, + { "ActD_EU.arl", 2 }, + { "ActD_Mission_Africa.ar.00", 2 }, + { "ActD_Mission_Africa.arl", 2 }, + { "ActD_Mission_Beach.ar.00", 2 }, + { "ActD_Mission_Beach.arl", 2 }, + { "ActD_Mission_China.ar.00", 2 }, + { "ActD_Mission_China.arl", 2 }, + { "ActD_Mission_EU.ar.00", 2 }, + { "ActD_Mission_EU.arl", 2 }, + { "ActD_Mission_Mykonos.ar.00", 2 }, + { "ActD_Mission_Mykonos.arl", 2 }, + { "ActD_Mission_NY.ar.00", 2 }, + { "ActD_Mission_NY.arl", 2 }, + { "ActD_Mission_Petra.ar.00", 2 }, + { "ActD_Mission_Petra.arl", 2 }, + { "ActD_Mission_Snow.ar.00", 2 }, + { "ActD_Mission_Snow.arl", 2 }, + { "ActD_MykonosAct1.ar.00", 2 }, + { "ActD_MykonosAct1.ar.01", 2 }, + { "ActD_MykonosAct1.arl", 2 }, + { "ActD_MykonosAct2.ar.00", 2 }, + { "ActD_MykonosAct2.ar.01", 2 }, + { "ActD_MykonosAct2.ar.02", 2 }, + { "ActD_MykonosAct2.arl", 2 }, + { "ActD_NY.ar.00", 2 }, + { "ActD_NY.ar.01", 2 }, + { "ActD_NY.ar.02", 2 }, + { "ActD_NY.ar.03", 2 }, + { "ActD_NY.arl", 2 }, + { "ActD_Petra.ar.00", 2 }, + { "ActD_Petra.ar.01", 2 }, + { "ActD_Petra.arl", 2 }, + { "ActD_Snow.ar.00", 2 }, + { "ActD_Snow.ar.01", 2 }, + { "ActD_Snow.arl", 2 }, + { "ActD_SubAfrica_01.ar.00", 2 }, + { "ActD_SubAfrica_01.ar.01", 2 }, + { "ActD_SubAfrica_01.arl", 2 }, + { "ActD_SubAfrica_03.ar.00", 2 }, + { "ActD_SubAfrica_03.arl", 2 }, + { "ActD_SubBeach_02.ar.00", 2 }, + { "ActD_SubBeach_02.arl", 2 }, + { "ActD_SubBeach_04.ar.00", 2 }, + { "ActD_SubBeach_04.arl", 2 }, + { "ActD_SubChina_03.ar.00", 2 }, + { "ActD_SubChina_03.arl", 2 }, + { "ActD_SubChina_04.ar.00", 2 }, + { "ActD_SubChina_04.ar.01", 2 }, + { "ActD_SubChina_04.arl", 2 }, + { "ActD_SubEU_01.ar.00", 2 }, + { "ActD_SubEU_01.ar.01", 2 }, + { "ActD_SubEU_01.arl", 2 }, + { "ActD_SubEU_02.ar.00", 2 }, + { "ActD_SubEU_02.ar.01", 2 }, + { "ActD_SubEU_02.arl", 2 }, + { "ActD_SubMykonos_01.ar.00", 2 }, + { "ActD_SubMykonos_01.ar.01", 2 }, + { "ActD_SubMykonos_01.arl", 2 }, + { "ActD_SubNY_01.ar.00", 2 }, + { "ActD_SubNY_01.arl", 2 }, + { "ActD_SubPetra_03.ar.00", 2 }, + { "ActD_SubPetra_03.ar.01", 2 }, + { "ActD_SubPetra_03.ar.02", 2 }, + { "ActD_SubPetra_03.arl", 2 }, + { "ActD_SubSnow_01.ar.00", 2 }, + { "ActD_SubSnow_01.arl", 2 }, + { "ActN_AfricaEvil.ar.00", 2 }, + { "ActN_AfricaEvil.ar.01", 2 }, + { "ActN_AfricaEvil.arl", 2 }, + { "ActN_BeachEvil.ar.00", 2 }, + { "ActN_BeachEvil.arl", 2 }, + { "ActN_ChinaEvil.ar.00", 2 }, + { "ActN_ChinaEvil.ar.01", 2 }, + { "ActN_ChinaEvil.ar.02", 2 }, + { "ActN_ChinaEvil.arl", 2 }, + { "ActN_EUEvil.ar.00", 2 }, + { "ActN_EUEvil.ar.01", 2 }, + { "ActN_EUEvil.arl", 2 }, + { "ActN_MissionEU_01.ar.00", 2 }, + { "ActN_MissionEU_01.arl", 2 }, + { "ActN_MissionEU_02.ar.00", 2 }, + { "ActN_MissionEU_02.arl", 2 }, + { "ActN_MissionEU_03.ar.00", 2 }, + { "ActN_MissionEU_03.arl", 2 }, + { "ActN_Mission_Africa.ar.00", 2 }, + { "ActN_Mission_Africa.arl", 2 }, + { "ActN_Mission_Beach.ar.00", 2 }, + { "ActN_Mission_Beach.arl", 2 }, + { "ActN_Mission_China.ar.00", 2 }, + { "ActN_Mission_China.arl", 2 }, + { "ActN_Mission_Mykonos.ar.00", 2 }, + { "ActN_Mission_Mykonos.arl", 2 }, + { "ActN_Mission_NY.ar.00", 2 }, + { "ActN_Mission_NY.arl", 2 }, + { "ActN_Mission_Petra.ar.00", 2 }, + { "ActN_Mission_Petra.arl", 2 }, + { "ActN_Mission_Snow.ar.00", 2 }, + { "ActN_Mission_Snow.arl", 2 }, + { "ActN_MykonosEvil.ar.00", 2 }, + { "ActN_MykonosEvil.ar.01", 2 }, + { "ActN_MykonosEvil.arl", 2 }, + { "ActN_NYEvil.ar.00", 2 }, + { "ActN_NYEvil.arl", 2 }, + { "ActN_PetraEvil.ar.00", 2 }, + { "ActN_PetraEvil.ar.01", 2 }, + { "ActN_PetraEvil.ar.02", 2 }, + { "ActN_PetraEvil.arl", 2 }, + { "ActN_SnowEvil.ar.00", 2 }, + { "ActN_SnowEvil.arl", 2 }, + { "ActN_SubAfrica_01.ar.00", 2 }, + { "ActN_SubAfrica_01.ar.01", 2 }, + { "ActN_SubAfrica_01.arl", 2 }, + { "ActN_SubBeach_01.ar.00", 2 }, + { "ActN_SubBeach_01.arl", 2 }, + { "ActN_SubChina_01.ar.00", 2 }, + { "ActN_SubChina_01.ar.01", 2 }, + { "ActN_SubChina_01.arl", 2 }, + { "ActN_SubMykonos_01.ar.00", 2 }, + { "ActN_SubMykonos_01.arl", 2 }, + { "Act_EggmanLand.ar.00", 2 }, + { "Act_EggmanLand.ar.01", 2 }, + { "Act_EggmanLand.ar.02", 2 }, + { "Act_EggmanLand.arl", 2 }, + { "ActionCommon.ar.00", 2 }, + { "ActionCommon.arl", 2 }, + { "ActionCommon_EggmanLand.ar.00", 2 }, + { "ActionCommon_EggmanLand.arl", 2 }, + { "Application.ar.00", 2 }, + { "Application.arl", 2 }, + { "AutoSave.ar.00", 2 }, + { "AutoSave.arl", 2 }, + { "BossCommon.ar.00", 2 }, + { "BossCommon.arl", 2 }, + { "BossDarkGaia1_1Air.ar.00", 2 }, + { "BossDarkGaia1_1Air.ar.01", 2 }, + { "BossDarkGaia1_1Air.ar.02", 2 }, + { "BossDarkGaia1_1Air.arl", 2 }, + { "BossDarkGaia1_1Run.ar.00", 2 }, + { "BossDarkGaia1_1Run.ar.01", 2 }, + { "BossDarkGaia1_1Run.ar.02", 2 }, + { "BossDarkGaia1_1Run.ar.03", 2 }, + { "BossDarkGaia1_1Run.arl", 2 }, + { "BossDarkGaia1_2Run.ar.00", 2 }, + { "BossDarkGaia1_2Run.ar.01", 2 }, + { "BossDarkGaia1_2Run.ar.02", 2 }, + { "BossDarkGaia1_2Run.ar.03", 2 }, + { "BossDarkGaia1_2Run.arl", 2 }, + { "BossDarkGaia1_3Run.ar.00", 2 }, + { "BossDarkGaia1_3Run.ar.01", 2 }, + { "BossDarkGaia1_3Run.ar.02", 2 }, + { "BossDarkGaia1_3Run.ar.03", 2 }, + { "BossDarkGaia1_3Run.ar.04", 2 }, + { "BossDarkGaia1_3Run.arl", 2 }, + { "BossDarkGaiaMoray.ar.00", 2 }, + { "BossDarkGaiaMoray.ar.01", 2 }, + { "BossDarkGaiaMoray.ar.02", 2 }, + { "BossDarkGaiaMoray.ar.03", 2 }, + { "BossDarkGaiaMoray.arl", 2 }, + { "BossEggBeetle.ar.00", 2 }, + { "BossEggBeetle.ar.01", 2 }, + { "BossEggBeetle.ar.02", 2 }, + { "BossEggBeetle.ar.03", 2 }, + { "BossEggBeetle.arl", 2 }, + { "BossEggDragoon.ar.00", 2 }, + { "BossEggDragoon.ar.01", 2 }, + { "BossEggDragoon.ar.02", 2 }, + { "BossEggDragoon.ar.03", 2 }, + { "BossEggDragoon.ar.04", 2 }, + { "BossEggDragoon.ar.05", 2 }, + { "BossEggDragoon.ar.06", 2 }, + { "BossEggDragoon.arl", 2 }, + { "BossEggLancer.ar.00", 2 }, + { "BossEggLancer.ar.01", 2 }, + { "BossEggLancer.ar.02", 2 }, + { "BossEggLancer.ar.03", 2 }, + { "BossEggLancer.ar.04", 2 }, + { "BossEggLancer.arl", 2 }, + { "BossEggRayBird.ar.00", 2 }, + { "BossEggRayBird.ar.01", 2 }, + { "BossEggRayBird.ar.02", 2 }, + { "BossEggRayBird.ar.03", 2 }, + { "BossEggRayBird.ar.04", 2 }, + { "BossEggRayBird.arl", 2 }, + { "BossFinalDarkGaia.ar.00", 2 }, + { "BossFinalDarkGaia.ar.01", 2 }, + { "BossFinalDarkGaia.ar.02", 2 }, + { "BossFinalDarkGaia.ar.03", 2 }, + { "BossFinalDarkGaia.ar.04", 2 }, + { "BossFinalDarkGaia.arl", 2 }, + { "BossHydra.ar.00", 2 }, + { "BossHydra.arl", 2 }, + { "BossPetra.ar.00", 2 }, + { "BossPetra.ar.01", 2 }, + { "BossPetra.ar.02", 2 }, + { "BossPetra.ar.03", 2 }, + { "BossPetra.arl", 2 }, + { "BossPhoenix.ar.00", 2 }, + { "BossPhoenix.ar.01", 2 }, + { "BossPhoenix.ar.02", 2 }, + { "BossPhoenix.ar.03", 2 }, + { "BossPhoenix.arl", 2 }, + { "CmnActD_Terrain_Africa.ar.00", 2 }, + { "CmnActD_Terrain_Africa.arl", 2 }, + { "CmnActD_Terrain_Beach.ar.00", 2 }, + { "CmnActD_Terrain_Beach.arl", 2 }, + { "CmnActD_Terrain_China.ar.00", 2 }, + { "CmnActD_Terrain_China.arl", 2 }, + { "CmnActD_Terrain_EU.ar.00", 2 }, + { "CmnActD_Terrain_EU.arl", 2 }, + { "CmnActD_Terrain_Mykonos.ar.00", 2 }, + { "CmnActD_Terrain_Mykonos.arl", 2 }, + { "CmnActD_Terrain_NY.ar.00", 2 }, + { "CmnActD_Terrain_NY.arl", 2 }, + { "CmnActD_Terrain_Petra.ar.00", 2 }, + { "CmnActD_Terrain_Petra.ar.01", 2 }, + { "CmnActD_Terrain_Petra.arl", 2 }, + { "CmnActD_Terrain_Snow.ar.00", 2 }, + { "CmnActD_Terrain_Snow.arl", 2 }, + { "CmnActN_Terrain_Africa.ar.00", 2 }, + { "CmnActN_Terrain_Africa.arl", 2 }, + { "CmnActN_Terrain_Beach.ar.00", 2 }, + { "CmnActN_Terrain_Beach.ar.01", 2 }, + { "CmnActN_Terrain_Beach.arl", 2 }, + { "CmnActN_Terrain_China.ar.00", 2 }, + { "CmnActN_Terrain_China.arl", 2 }, + { "CmnActN_Terrain_EU.ar.00", 2 }, + { "CmnActN_Terrain_EU.ar.01", 2 }, + { "CmnActN_Terrain_EU.arl", 2 }, + { "CmnActN_Terrain_Mykonos.ar.00", 2 }, + { "CmnActN_Terrain_Mykonos.arl", 2 }, + { "CmnActN_Terrain_NY.ar.00", 2 }, + { "CmnActN_Terrain_NY.ar.01", 2 }, + { "CmnActN_Terrain_NY.ar.02", 2 }, + { "CmnActN_Terrain_NY.arl", 2 }, + { "CmnActN_Terrain_Petra.ar.00", 2 }, + { "CmnActN_Terrain_Petra.arl", 2 }, + { "CmnActN_Terrain_Snow.ar.00", 2 }, + { "CmnActN_Terrain_Snow.arl", 2 }, + { "CmnAct_Beach.ar.00", 2 }, + { "CmnAct_Beach.arl", 2 }, + { "CmnAct_China.ar.00", 2 }, + { "CmnAct_China.arl", 2 }, + { "CmnAct_EU.ar.00", 2 }, + { "CmnAct_EU.arl", 2 }, + { "CmnAct_EggmanLand.ar.00", 2 }, + { "CmnAct_EggmanLand.arl", 2 }, + { "CmnAct_NY.ar.00", 2 }, + { "CmnAct_NY.arl", 2 }, + { "CmnAfrica.ar.00", 2 }, + { "CmnAfrica.arl", 2 }, + { "CmnBeach.ar.00", 2 }, + { "CmnBeach.arl", 2 }, + { "CmnChina.ar.00", 2 }, + { "CmnChina.arl", 2 }, + { "CmnEU.ar.00", 2 }, + { "CmnEU.arl", 2 }, + { "CmnEggmanLand.ar.00", 2 }, + { "CmnEggmanLand.arl", 2 }, + { "CmnEnemyNight.ar.00", 2 }, + { "CmnEnemyNight.arl", 2 }, + { "CmnEnemy_EFighterGN.ar.00", 2 }, + { "CmnEnemy_EFighterGN.arl", 2 }, + { "CmnEnemy_EggFighterEquipments.ar.00", 2 }, + { "CmnEnemy_EggFighterEquipments.arl", 2 }, + { "CmnEnemy_SonicEnemyESpinner.ar.00", 2 }, + { "CmnEnemy_SonicEnemyESpinner.arl", 2 }, + { "CmnMykonos.ar.00", 2 }, + { "CmnMykonos.ar.01", 2 }, + { "CmnMykonos.arl", 2 }, + { "CmnNY.ar.00", 2 }, + { "CmnNY.arl", 2 }, + { "CmnPetra.ar.00", 2 }, + { "CmnPetra.arl", 2 }, + { "CmnSnow.ar.00", 2 }, + { "CmnSnow.arl", 2 }, + { "CmnTown_Africa.ar.00", 2 }, + { "CmnTown_Africa.ar.01", 2 }, + { "CmnTown_Africa.ar.02", 2 }, + { "CmnTown_Africa.ar.03", 2 }, + { "CmnTown_Africa.ar.04", 2 }, + { "CmnTown_Africa.arl", 2 }, + { "CmnTown_China.ar.00", 2 }, + { "CmnTown_China.ar.01", 2 }, + { "CmnTown_China.ar.02", 2 }, + { "CmnTown_China.ar.03", 2 }, + { "CmnTown_China.ar.04", 2 }, + { "CmnTown_China.arl", 2 }, + { "CmnTown_EuropeanCity.ar.00", 2 }, + { "CmnTown_EuropeanCity.ar.01", 2 }, + { "CmnTown_EuropeanCity.ar.02", 2 }, + { "CmnTown_EuropeanCity.ar.03", 2 }, + { "CmnTown_EuropeanCity.arl", 2 }, + { "CmnTown_Mykonos.ar.00", 2 }, + { "CmnTown_Mykonos.ar.01", 2 }, + { "CmnTown_Mykonos.arl", 2 }, + { "CmnTown_NYCity.ar.00", 2 }, + { "CmnTown_NYCity.ar.01", 2 }, + { "CmnTown_NYCity.ar.02", 2 }, + { "CmnTown_NYCity.ar.03", 2 }, + { "CmnTown_NYCity.arl", 2 }, + { "CmnTown_PetraCapital.ar.00", 2 }, + { "CmnTown_PetraCapital.ar.01", 2 }, + { "CmnTown_PetraCapital.ar.02", 2 }, + { "CmnTown_PetraCapital.ar.03", 2 }, + { "CmnTown_PetraCapital.arl", 2 }, + { "CmnTown_Snow.ar.00", 2 }, + { "CmnTown_Snow.ar.01", 2 }, + { "CmnTown_Snow.ar.02", 2 }, + { "CmnTown_Snow.ar.03", 2 }, + { "CmnTown_Snow.ar.04", 2 }, + { "CmnTown_Snow.arl", 2 }, + { "CmnTown_SouthEastAsia.ar.00", 2 }, + { "CmnTown_SouthEastAsia.ar.01", 2 }, + { "CmnTown_SouthEastAsia.ar.02", 2 }, + { "CmnTown_SouthEastAsia.arl", 2 }, + { "Cmn_BossDarkGaia.ar.00", 2 }, + { "Cmn_BossDarkGaia.arl", 2 }, + { "EggFighterEquipments.ar.00", 2 }, + { "EggFighterEquipments.arl", 2 }, + { "Event_M2_01_professor_room_new.ar.00", 2 }, + { "Event_M2_01_professor_room_new.ar.01", 2 }, + { "Event_M2_01_professor_room_new.arl", 2 }, + { "Event_M4_01_egb_hideout.ar.00", 2 }, + { "Event_M4_01_egb_hideout.ar.01", 2 }, + { "Event_M4_01_egb_hideout.arl", 2 }, + { "Event_M6_01_temple.ar.00", 2 }, + { "Event_M6_01_temple.ar.01", 2 }, + { "Event_M6_01_temple.ar.02", 2 }, + { "Event_M6_01_temple.ar.03", 2 }, + { "Event_M6_01_temple.ar.04", 2 }, + { "Event_M6_01_temple.ar.05", 2 }, + { "Event_M6_01_temple.ar.06", 2 }, + { "Event_M6_01_temple.arl", 2 }, + { "Event_M8_01.ar.00", 2 }, + { "Event_M8_01.arl", 2 }, + { "Event_M8_02_egbHall.ar.00", 2 }, + { "Event_M8_02_egbHall.ar.01", 2 }, + { "Event_M8_02_egbHall.ar.02", 2 }, + { "Event_M8_02_egbHall.ar.03", 2 }, + { "Event_M8_02_egbHall.arl", 2 }, + { "Event_M8_03.ar.00", 2 }, + { "Event_M8_03.arl", 2 }, + { "Event_M8_16_myk.ar.00", 2 }, + { "Event_M8_16_myk.ar.01", 2 }, + { "Event_M8_16_myk.ar.02", 2 }, + { "Event_M8_16_myk.arl", 2 }, + { "Event_afr_hideout.ar.00", 2 }, + { "Event_afr_hideout.ar.01", 2 }, + { "Event_afr_hideout.arl", 2 }, + { "Event_egb_hidout_exterior.ar.00", 2 }, + { "Event_egb_hidout_exterior.ar.01", 2 }, + { "Event_egb_hidout_exterior.arl", 2 }, + { "Event_temple.ar.00", 2 }, + { "Event_temple.ar.01", 2 }, + { "Event_temple.arl", 2 }, + { "EvilActionCommon.ar.00", 2 }, + { "EvilActionCommon.arl", 2 }, + { "EvilActionCommonGeneral.ar.00", 2 }, + { "EvilActionCommonGeneral.arl", 2 }, + { "EvilActionCommon_Africa.ar.00", 2 }, + { "EvilActionCommon_Africa.ar.01", 2 }, + { "EvilActionCommon_Africa.arl", 2 }, + { "EvilActionCommon_Beach.ar.00", 2 }, + { "EvilActionCommon_Beach.ar.01", 2 }, + { "EvilActionCommon_Beach.arl", 2 }, + { "EvilActionCommon_China.ar.00", 2 }, + { "EvilActionCommon_China.ar.01", 2 }, + { "EvilActionCommon_China.arl", 2 }, + { "EvilActionCommon_EU.ar.00", 2 }, + { "EvilActionCommon_EU.ar.01", 2 }, + { "EvilActionCommon_EU.arl", 2 }, + { "EvilActionCommon_EggmanLand.ar.00", 2 }, + { "EvilActionCommon_EggmanLand.arl", 2 }, + { "EvilActionCommon_Mykonos.ar.00", 2 }, + { "EvilActionCommon_Mykonos.ar.01", 2 }, + { "EvilActionCommon_Mykonos.arl", 2 }, + { "EvilActionCommon_NY.ar.00", 2 }, + { "EvilActionCommon_NY.ar.01", 2 }, + { "EvilActionCommon_NY.ar.02", 2 }, + { "EvilActionCommon_NY.arl", 2 }, + { "EvilActionCommon_Petra.ar.00", 2 }, + { "EvilActionCommon_Petra.arl", 2 }, + { "EvilActionCommon_Snow.ar.00", 2 }, + { "EvilActionCommon_Snow.ar.01", 2 }, + { "EvilActionCommon_Snow.arl", 2 }, + { "EvilCommon.ar.00", 2 }, + { "EvilCommon.arl", 2 }, + { "EvilCommonGeneral.ar.00", 2 }, + { "EvilCommonGeneral.arl", 2 }, + { "EvilEnemyBigMother.ar.00", 2 }, + { "EvilEnemyBigMother.arl", 2 }, + { "EvilEnemyChibiFighter.ar.00", 2 }, + { "EvilEnemyChibiFighter.arl", 2 }, + { "EvilEnemyEThunderBall.ar.00", 2 }, + { "EvilEnemyEThunderBall.arl", 2 }, + { "EvilEnemyEggElement.ar.00", 2 }, + { "EvilEnemyEggElement.arl", 2 }, + { "EvilEnemyEggFighter.ar.00", 2 }, + { "EvilEnemyEggFighter.arl", 2 }, + { "EvilEnemyFloat.ar.00", 2 }, + { "EvilEnemyFloat.arl", 2 }, + { "EvilEnemyFlower.ar.00", 2 }, + { "EvilEnemyFlower.arl", 2 }, + { "EvilEnemyKillerBee.ar.00", 2 }, + { "EvilEnemyKillerBee.arl", 2 }, + { "EvilEnemyMaster.ar.00", 2 }, + { "EvilEnemyMaster.arl", 2 }, + { "EvilEnemyMoleel.ar.00", 2 }, + { "EvilEnemyMoleel.arl", 2 }, + { "EvilEnemyNightmareR.ar.00", 2 }, + { "EvilEnemyNightmareR.arl", 2 }, + { "EvilEnemyReckless.ar.00", 2 }, + { "EvilEnemyReckless.arl", 2 }, + { "EvilEnemySpooky.ar.00", 2 }, + { "EvilEnemySpooky.arl", 2 }, + { "EvilEnemyTitan.ar.00", 2 }, + { "EvilEnemyTitan.arl", 2 }, + { "EvilSonic.ar.00", 2 }, + { "EvilSonic.ar.01", 2 }, + { "EvilSonic.ar.02", 2 }, + { "EvilSonic.arl", 2 }, + { "ExStageTails1.ar.00", 2 }, + { "ExStageTails1.ar.01", 2 }, + { "ExStageTails1.ar.02", 2 }, + { "ExStageTails1.arl", 2 }, + { "ExStageTails2.ar.00", 2 }, + { "ExStageTails2.ar.01", 2 }, + { "ExStageTails2.arl", 2 }, + { "ExStageTails_Common.ar.00", 2 }, + { "ExStageTails_Common.ar.01", 2 }, + { "ExStageTails_Common.ar.02", 2 }, + { "ExStageTails_Common.ar.03", 2 }, + { "ExStageTails_Common.arl", 2 }, + { "Hint/BossGate.dds", 2 }, + { "Hint/BossKey_all.dds", 2 }, + { "Hint/BossKey_combine.dds", 2 }, + { "Hint/BossKey_moon.dds", 2 }, + { "Hint/BossKey_sun.dds", 2 }, + { "Hint/Camera_001D.dds", 2 }, + { "Hint/Changetime_001D.dds", 2 }, + { "Hint/CoolEdge_ACT1_001D.dds", 2 }, + { "Hint/CoolEdge_ACT1_002D.dds", 2 }, + { "Hint/CrayCastle_ACT1_001D.dds", 2 }, + { "Hint/CrayCastle_ACT1_001N.dds", 2 }, + { "Hint/CrayCastle_ACT1_003N.dds", 2 }, + { "Hint/DragonRoad_ACT1_001D.dds", 2 }, + { "Hint/HotDessert_ACT1_001D.dds", 2 }, + { "Hint/OrangeRoofs_ACT1_001D.dds", 2 }, + { "Hint/WhiteIsland_ACT1_002D.dds", 2 }, + { "Hint/WhiteIsland_ACT1_002N.dds", 2 }, + { "Hint/WhiteIsland_ACT1_003D.dds", 2 }, + { "Hint/WhiteIsland_ACT1_006D.dds", 2 }, + { "Hint/WhiteIsland_ACT1_007D.dds", 2 }, + { "Hint/WhiteIsland_ACT1_007N.dds", 2 }, + { "Hint/WhiteIsland_ACT1_008D.dds", 2 }, + { "Hint/WhiteIsland_ACT1_008N.dds", 2 }, + { "Hint/WhiteIsland_ACT1_009N.dds", 2 }, + { "Hint/WhiteIsland_ACT1_010D.dds", 2 }, + { "Hint/WhiteIsland_ACT1_010N.dds", 2 }, + { "Hint/WhiteIsland_ACT1_011N.dds", 2 }, + { "Hint/WhiteIsland_ACT1_012N.dds", 2 }, + { "Hint/WhiteIsland_ACT1_013D.dds", 2 }, + { "Hint/WhiteIsland_ACT1_015D.dds", 2 }, + { "Hint/WhiteIsland_ACT1_016D.dds", 2 }, + { "Hint/WhiteIsland_ACT1_016N.dds", 2 }, + { "Hint/WhiteIsland_ACT1_020N.dds", 2 }, + { "Hint/WhiteIsland_ACT2_001D.dds", 2 }, + { "Hint/WhiteIsland_ACT2_002D.dds", 2 }, + { "Hint/WhiteIsland_ACT2_003D.dds", 2 }, + { "Hint/WhiteIsland_ACT2_004D.dds", 2 }, + { "Hint/WhiteIsland_ACT2_005D.dds", 2 }, + { "Hint/guard_001N.dds", 2 }, + { "Inspire/chara/EggmanEVRoot.ar", 2 }, + { "Inspire/chara/EggmanEVRoot.arl", 2 }, + { "Inspire/chara/EvilEVRoot.ar", 2 }, + { "Inspire/chara/EvilEVRoot.arl", 2 }, + { "Inspire/chara/GhostWhipEVRoot.ar", 2 }, + { "Inspire/chara/GhostWhipEVRoot.arl", 2 }, + { "Inspire/chara/SonicEVRoot.ar", 2 }, + { "Inspire/chara/SonicEVRoot.arl", 2 }, + { "Inspire/chara/TailsEVRoot.ar", 2 }, + { "Inspire/chara/TailsEVRoot.arl", 2 }, + { "Inspire/chara/WhipEVRoot.ar", 2 }, + { "Inspire/chara/WhipEVRoot.arl", 2 }, + { "Inspire/chara/npc_professor_hi.ar", 2 }, + { "Inspire/chara/npc_professor_hi.arl", 2 }, + { "Inspire/scene/evrt_m0_06.ar", 2 }, + { "Inspire/scene/evrt_m0_06.arl", 2 }, + { "Inspire/scene/evrt_m1_01.ar", 2 }, + { "Inspire/scene/evrt_m1_01.arl", 2 }, + { "Inspire/scene/evrt_m1_02.ar", 2 }, + { "Inspire/scene/evrt_m1_02.arl", 2 }, + { "Inspire/scene/evrt_m1_03_1.ar", 2 }, + { "Inspire/scene/evrt_m1_03_1.arl", 2 }, + { "Inspire/scene/evrt_m1_03_2.ar", 2 }, + { "Inspire/scene/evrt_m1_03_2.arl", 2 }, + { "Inspire/scene/evrt_m2_01.ar", 2 }, + { "Inspire/scene/evrt_m2_01.arl", 2 }, + { "Inspire/scene/evrt_m2_02.ar", 2 }, + { "Inspire/scene/evrt_m2_02.arl", 2 }, + { "Inspire/scene/evrt_m2_03.ar", 2 }, + { "Inspire/scene/evrt_m2_03.arl", 2 }, + { "Inspire/scene/evrt_m3_01.ar", 2 }, + { "Inspire/scene/evrt_m3_01.arl", 2 }, + { "Inspire/scene/evrt_m3_02.ar", 2 }, + { "Inspire/scene/evrt_m3_02.arl", 2 }, + { "Inspire/scene/evrt_m3_03.ar", 2 }, + { "Inspire/scene/evrt_m3_03.arl", 2 }, + { "Inspire/scene/evrt_m3_05.ar", 2 }, + { "Inspire/scene/evrt_m3_05.arl", 2 }, + { "Inspire/scene/evrt_m4_01.ar", 2 }, + { "Inspire/scene/evrt_m4_01.arl", 2 }, + { "Inspire/scene/evrt_m5_01.ar", 2 }, + { "Inspire/scene/evrt_m5_01.arl", 2 }, + { "Inspire/scene/evrt_m5_02.ar", 2 }, + { "Inspire/scene/evrt_m5_02.arl", 2 }, + { "Inspire/scene/evrt_m6_01.ar", 2 }, + { "Inspire/scene/evrt_m6_01.arl", 2 }, + { "Inspire/scene/evrt_m6_02.ar", 2 }, + { "Inspire/scene/evrt_m6_02.arl", 2 }, + { "Inspire/scene/evrt_m6_03.ar", 2 }, + { "Inspire/scene/evrt_m6_03.arl", 2 }, + { "Inspire/scene/evrt_m7_01.ar", 2 }, + { "Inspire/scene/evrt_m7_01.arl", 2 }, + { "Inspire/scene/evrt_m7_02.ar", 2 }, + { "Inspire/scene/evrt_m7_02.arl", 2 }, + { "Inspire/scene/evrt_m7_04.ar", 2 }, + { "Inspire/scene/evrt_m7_04.arl", 2 }, + { "Inspire/scene/evrt_m8_01.ar", 2 }, + { "Inspire/scene/evrt_m8_01.arl", 2 }, + { "Inspire/scene/evrt_m8_02.ar", 2 }, + { "Inspire/scene/evrt_m8_02.arl", 2 }, + { "Inspire/scene/evrt_m8_03.ar", 2 }, + { "Inspire/scene/evrt_m8_03.arl", 2 }, + { "Inspire/scene/evrt_m8_06_2.ar", 2 }, + { "Inspire/scene/evrt_m8_06_2.arl", 2 }, + { "Inspire/scene/evrt_m8_07.ar", 2 }, + { "Inspire/scene/evrt_m8_07.arl", 2 }, + { "Inspire/scene/evrt_m8_09.ar", 2 }, + { "Inspire/scene/evrt_m8_09.arl", 2 }, + { "Inspire/scene/evrt_m8_11_1.ar", 2 }, + { "Inspire/scene/evrt_m8_11_1.arl", 2 }, + { "Inspire/scene/evrt_m8_11_3.ar", 2 }, + { "Inspire/scene/evrt_m8_11_3.arl", 2 }, + { "Inspire/scene/evrt_m8_13.ar", 2 }, + { "Inspire/scene/evrt_m8_13.arl", 2 }, + { "Inspire/scene/evrt_m8_14.ar", 2 }, + { "Inspire/scene/evrt_m8_14.arl", 2 }, + { "Inspire/scene/evrt_m8_15.ar", 2 }, + { "Inspire/scene/evrt_m8_15.arl", 2 }, + { "Inspire/scene/evrt_m8_16.ar", 2 }, + { "Inspire/scene/evrt_m8_16.arl", 2 }, + { "Inspire/scene/evrt_s1_03.ar", 2 }, + { "Inspire/scene/evrt_s1_03.arl", 2 }, + { "Inspire/scene/evrt_s1_04.ar", 2 }, + { "Inspire/scene/evrt_s1_04.arl", 2 }, + { "Inspire/scene/evrt_s1_05.ar", 2 }, + { "Inspire/scene/evrt_s1_05.arl", 2 }, + { "Inspire/scene/evrt_s1_06.ar", 2 }, + { "Inspire/scene/evrt_s1_06.arl", 2 }, + { "Inspire/scene/evrt_s2_01.ar", 2 }, + { "Inspire/scene/evrt_s2_01.arl", 2 }, + { "Inspire/scene/evrt_s2_03.ar", 2 }, + { "Inspire/scene/evrt_s2_03.arl", 2 }, + { "Inspire/scene/evrt_s2_04.ar", 2 }, + { "Inspire/scene/evrt_s2_04.arl", 2 }, + { "Inspire/scene/evrt_s3_03.ar", 2 }, + { "Inspire/scene/evrt_s3_03.arl", 2 }, + { "Inspire/scene/evrt_s3_04.ar", 2 }, + { "Inspire/scene/evrt_s3_04.arl", 2 }, + { "Inspire/scene/evrt_t0_01.ar", 2 }, + { "Inspire/scene/evrt_t0_01.arl", 2 }, + { "Inspire/scene/evrt_t0_02.ar", 2 }, + { "Inspire/scene/evrt_t0_02.arl", 2 }, + { "Inspire/scene/evrt_t0_03.ar", 2 }, + { "Inspire/scene/evrt_t0_03.arl", 2 }, + { "Inspire/scene/evrt_t0_04.ar", 2 }, + { "Inspire/scene/evrt_t0_04.arl", 2 }, + { "Inspire/subtitle/English/evrt_m0_01_05.ar", 2 }, + { "Inspire/subtitle/English/evrt_m0_01_05.arl", 2 }, + { "Inspire/subtitle/English/evrt_m0_06.ar", 2 }, + { "Inspire/subtitle/English/evrt_m0_06.arl", 2 }, + { "Inspire/subtitle/English/evrt_m1_01.ar", 2 }, + { "Inspire/subtitle/English/evrt_m1_01.arl", 2 }, + { "Inspire/subtitle/English/evrt_m1_02.ar", 2 }, + { "Inspire/subtitle/English/evrt_m1_02.arl", 2 }, + { "Inspire/subtitle/English/evrt_m1_03_1.ar", 2 }, + { "Inspire/subtitle/English/evrt_m1_03_1.arl", 2 }, + { "Inspire/subtitle/English/evrt_m1_03_2.ar", 2 }, + { "Inspire/subtitle/English/evrt_m1_03_2.arl", 2 }, + { "Inspire/subtitle/English/evrt_m2_01.ar", 2 }, + { "Inspire/subtitle/English/evrt_m2_01.arl", 2 }, + { "Inspire/subtitle/English/evrt_m2_02.ar", 2 }, + { "Inspire/subtitle/English/evrt_m2_02.arl", 2 }, + { "Inspire/subtitle/English/evrt_m2_03.ar", 2 }, + { "Inspire/subtitle/English/evrt_m2_03.arl", 2 }, + { "Inspire/subtitle/English/evrt_m3_01.ar", 2 }, + { "Inspire/subtitle/English/evrt_m3_01.arl", 2 }, + { "Inspire/subtitle/English/evrt_m3_02.ar", 2 }, + { "Inspire/subtitle/English/evrt_m3_02.arl", 2 }, + { "Inspire/subtitle/English/evrt_m3_03.ar", 2 }, + { "Inspire/subtitle/English/evrt_m3_03.arl", 2 }, + { "Inspire/subtitle/English/evrt_m3_05.ar", 2 }, + { "Inspire/subtitle/English/evrt_m3_05.arl", 2 }, + { "Inspire/subtitle/English/evrt_m4_01.ar", 2 }, + { "Inspire/subtitle/English/evrt_m4_01.arl", 2 }, + { "Inspire/subtitle/English/evrt_m5_01.ar", 2 }, + { "Inspire/subtitle/English/evrt_m5_01.arl", 2 }, + { "Inspire/subtitle/English/evrt_m5_02.ar", 2 }, + { "Inspire/subtitle/English/evrt_m5_02.arl", 2 }, + { "Inspire/subtitle/English/evrt_m6_01.ar", 2 }, + { "Inspire/subtitle/English/evrt_m6_01.arl", 2 }, + { "Inspire/subtitle/English/evrt_m6_02.ar", 2 }, + { "Inspire/subtitle/English/evrt_m6_02.arl", 2 }, + { "Inspire/subtitle/English/evrt_m6_03.ar", 2 }, + { "Inspire/subtitle/English/evrt_m6_03.arl", 2 }, + { "Inspire/subtitle/English/evrt_m7_01.ar", 2 }, + { "Inspire/subtitle/English/evrt_m7_01.arl", 2 }, + { "Inspire/subtitle/English/evrt_m7_02.ar", 2 }, + { "Inspire/subtitle/English/evrt_m7_02.arl", 2 }, + { "Inspire/subtitle/English/evrt_m7_04.ar", 2 }, + { "Inspire/subtitle/English/evrt_m7_04.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_01.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_01.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_02.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_02.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_03.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_03.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_04.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_04.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_05.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_05.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_06_1.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_06_1.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_06_2.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_06_2.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_07.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_07.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_08.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_08.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_09.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_09.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_10.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_10.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_11_1.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_11_1.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_11_3.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_11_3.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_12.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_12.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_13.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_13.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_14.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_14.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_15.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_15.arl", 2 }, + { "Inspire/subtitle/English/evrt_m8_16.ar", 2 }, + { "Inspire/subtitle/English/evrt_m8_16.arl", 2 }, + { "Inspire/subtitle/English/evrt_s1_03.ar", 2 }, + { "Inspire/subtitle/English/evrt_s1_03.arl", 2 }, + { "Inspire/subtitle/English/evrt_s1_04.ar", 2 }, + { "Inspire/subtitle/English/evrt_s1_04.arl", 2 }, + { "Inspire/subtitle/English/evrt_s1_05.ar", 2 }, + { "Inspire/subtitle/English/evrt_s1_05.arl", 2 }, + { "Inspire/subtitle/English/evrt_s1_06.ar", 2 }, + { "Inspire/subtitle/English/evrt_s1_06.arl", 2 }, + { "Inspire/subtitle/English/evrt_s2_01.ar", 2 }, + { "Inspire/subtitle/English/evrt_s2_01.arl", 2 }, + { "Inspire/subtitle/English/evrt_s2_03.ar", 2 }, + { "Inspire/subtitle/English/evrt_s2_03.arl", 2 }, + { "Inspire/subtitle/English/evrt_s2_04.ar", 2 }, + { "Inspire/subtitle/English/evrt_s2_04.arl", 2 }, + { "Inspire/subtitle/English/evrt_s3_03.ar", 2 }, + { "Inspire/subtitle/English/evrt_s3_03.arl", 2 }, + { "Inspire/subtitle/English/evrt_s3_04.ar", 2 }, + { "Inspire/subtitle/English/evrt_s3_04.arl", 2 }, + { "Inspire/subtitle/English/evrt_t0_01.ar", 2 }, + { "Inspire/subtitle/English/evrt_t0_01.arl", 2 }, + { "Inspire/subtitle/English/evrt_t0_02.ar", 2 }, + { "Inspire/subtitle/English/evrt_t0_02.arl", 2 }, + { "Inspire/subtitle/English/evrt_t0_03.ar", 2 }, + { "Inspire/subtitle/English/evrt_t0_03.arl", 2 }, + { "Inspire/subtitle/English/evrt_t0_04.ar", 2 }, + { "Inspire/subtitle/English/evrt_t0_04.arl", 2 }, + { "Inspire/subtitle/French/evrt_m0_01_05.ar", 2 }, + { "Inspire/subtitle/French/evrt_m0_01_05.arl", 2 }, + { "Inspire/subtitle/French/evrt_m0_06.ar", 2 }, + { "Inspire/subtitle/French/evrt_m0_06.arl", 2 }, + { "Inspire/subtitle/French/evrt_m1_01.ar", 2 }, + { "Inspire/subtitle/French/evrt_m1_01.arl", 2 }, + { "Inspire/subtitle/French/evrt_m1_02.ar", 2 }, + { "Inspire/subtitle/French/evrt_m1_02.arl", 2 }, + { "Inspire/subtitle/French/evrt_m1_03_1.ar", 2 }, + { "Inspire/subtitle/French/evrt_m1_03_1.arl", 2 }, + { "Inspire/subtitle/French/evrt_m1_03_2.ar", 2 }, + { "Inspire/subtitle/French/evrt_m1_03_2.arl", 2 }, + { "Inspire/subtitle/French/evrt_m2_01.ar", 2 }, + { "Inspire/subtitle/French/evrt_m2_01.arl", 2 }, + { "Inspire/subtitle/French/evrt_m2_02.ar", 2 }, + { "Inspire/subtitle/French/evrt_m2_02.arl", 2 }, + { "Inspire/subtitle/French/evrt_m2_03.ar", 2 }, + { "Inspire/subtitle/French/evrt_m2_03.arl", 2 }, + { "Inspire/subtitle/French/evrt_m3_01.ar", 2 }, + { "Inspire/subtitle/French/evrt_m3_01.arl", 2 }, + { "Inspire/subtitle/French/evrt_m3_02.ar", 2 }, + { "Inspire/subtitle/French/evrt_m3_02.arl", 2 }, + { "Inspire/subtitle/French/evrt_m3_03.ar", 2 }, + { "Inspire/subtitle/French/evrt_m3_03.arl", 2 }, + { "Inspire/subtitle/French/evrt_m3_05.ar", 2 }, + { "Inspire/subtitle/French/evrt_m3_05.arl", 2 }, + { "Inspire/subtitle/French/evrt_m4_01.ar", 2 }, + { "Inspire/subtitle/French/evrt_m4_01.arl", 2 }, + { "Inspire/subtitle/French/evrt_m5_01.ar", 2 }, + { "Inspire/subtitle/French/evrt_m5_01.arl", 2 }, + { "Inspire/subtitle/French/evrt_m5_02.ar", 2 }, + { "Inspire/subtitle/French/evrt_m5_02.arl", 2 }, + { "Inspire/subtitle/French/evrt_m6_01.ar", 2 }, + { "Inspire/subtitle/French/evrt_m6_01.arl", 2 }, + { "Inspire/subtitle/French/evrt_m6_02.ar", 2 }, + { "Inspire/subtitle/French/evrt_m6_02.arl", 2 }, + { "Inspire/subtitle/French/evrt_m6_03.ar", 2 }, + { "Inspire/subtitle/French/evrt_m6_03.arl", 2 }, + { "Inspire/subtitle/French/evrt_m7_01.ar", 2 }, + { "Inspire/subtitle/French/evrt_m7_01.arl", 2 }, + { "Inspire/subtitle/French/evrt_m7_02.ar", 2 }, + { "Inspire/subtitle/French/evrt_m7_02.arl", 2 }, + { "Inspire/subtitle/French/evrt_m7_04.ar", 2 }, + { "Inspire/subtitle/French/evrt_m7_04.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_01.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_01.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_02.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_02.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_03.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_03.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_04.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_04.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_05.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_05.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_06_1.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_06_1.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_06_2.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_06_2.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_07.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_07.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_08.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_08.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_09.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_09.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_10.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_10.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_11_1.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_11_1.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_11_3.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_11_3.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_12.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_12.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_13.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_13.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_14.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_14.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_15.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_15.arl", 2 }, + { "Inspire/subtitle/French/evrt_m8_16.ar", 2 }, + { "Inspire/subtitle/French/evrt_m8_16.arl", 2 }, + { "Inspire/subtitle/French/evrt_s1_03.ar", 2 }, + { "Inspire/subtitle/French/evrt_s1_03.arl", 2 }, + { "Inspire/subtitle/French/evrt_s1_04.ar", 2 }, + { "Inspire/subtitle/French/evrt_s1_04.arl", 2 }, + { "Inspire/subtitle/French/evrt_s1_05.ar", 2 }, + { "Inspire/subtitle/French/evrt_s1_05.arl", 2 }, + { "Inspire/subtitle/French/evrt_s1_06.ar", 2 }, + { "Inspire/subtitle/French/evrt_s1_06.arl", 2 }, + { "Inspire/subtitle/French/evrt_s2_01.ar", 2 }, + { "Inspire/subtitle/French/evrt_s2_01.arl", 2 }, + { "Inspire/subtitle/French/evrt_s2_03.ar", 2 }, + { "Inspire/subtitle/French/evrt_s2_03.arl", 2 }, + { "Inspire/subtitle/French/evrt_s2_04.ar", 2 }, + { "Inspire/subtitle/French/evrt_s2_04.arl", 2 }, + { "Inspire/subtitle/French/evrt_s3_03.ar", 2 }, + { "Inspire/subtitle/French/evrt_s3_03.arl", 2 }, + { "Inspire/subtitle/French/evrt_s3_04.ar", 2 }, + { "Inspire/subtitle/French/evrt_s3_04.arl", 2 }, + { "Inspire/subtitle/French/evrt_t0_01.ar", 2 }, + { "Inspire/subtitle/French/evrt_t0_01.arl", 2 }, + { "Inspire/subtitle/French/evrt_t0_02.ar", 2 }, + { "Inspire/subtitle/French/evrt_t0_02.arl", 2 }, + { "Inspire/subtitle/French/evrt_t0_03.ar", 2 }, + { "Inspire/subtitle/French/evrt_t0_03.arl", 2 }, + { "Inspire/subtitle/French/evrt_t0_04.ar", 2 }, + { "Inspire/subtitle/French/evrt_t0_04.arl", 2 }, + { "Inspire/subtitle/German/evrt_m0_01_05.ar", 2 }, + { "Inspire/subtitle/German/evrt_m0_01_05.arl", 2 }, + { "Inspire/subtitle/German/evrt_m0_06.ar", 2 }, + { "Inspire/subtitle/German/evrt_m0_06.arl", 2 }, + { "Inspire/subtitle/German/evrt_m1_01.ar", 2 }, + { "Inspire/subtitle/German/evrt_m1_01.arl", 2 }, + { "Inspire/subtitle/German/evrt_m1_02.ar", 2 }, + { "Inspire/subtitle/German/evrt_m1_02.arl", 2 }, + { "Inspire/subtitle/German/evrt_m1_03_1.ar", 2 }, + { "Inspire/subtitle/German/evrt_m1_03_1.arl", 2 }, + { "Inspire/subtitle/German/evrt_m1_03_2.ar", 2 }, + { "Inspire/subtitle/German/evrt_m1_03_2.arl", 2 }, + { "Inspire/subtitle/German/evrt_m2_01.ar", 2 }, + { "Inspire/subtitle/German/evrt_m2_01.arl", 2 }, + { "Inspire/subtitle/German/evrt_m2_02.ar", 2 }, + { "Inspire/subtitle/German/evrt_m2_02.arl", 2 }, + { "Inspire/subtitle/German/evrt_m2_03.ar", 2 }, + { "Inspire/subtitle/German/evrt_m2_03.arl", 2 }, + { "Inspire/subtitle/German/evrt_m3_01.ar", 2 }, + { "Inspire/subtitle/German/evrt_m3_01.arl", 2 }, + { "Inspire/subtitle/German/evrt_m3_02.ar", 2 }, + { "Inspire/subtitle/German/evrt_m3_02.arl", 2 }, + { "Inspire/subtitle/German/evrt_m3_03.ar", 2 }, + { "Inspire/subtitle/German/evrt_m3_03.arl", 2 }, + { "Inspire/subtitle/German/evrt_m3_05.ar", 2 }, + { "Inspire/subtitle/German/evrt_m3_05.arl", 2 }, + { "Inspire/subtitle/German/evrt_m4_01.ar", 2 }, + { "Inspire/subtitle/German/evrt_m4_01.arl", 2 }, + { "Inspire/subtitle/German/evrt_m5_01.ar", 2 }, + { "Inspire/subtitle/German/evrt_m5_01.arl", 2 }, + { "Inspire/subtitle/German/evrt_m5_02.ar", 2 }, + { "Inspire/subtitle/German/evrt_m5_02.arl", 2 }, + { "Inspire/subtitle/German/evrt_m6_01.ar", 2 }, + { "Inspire/subtitle/German/evrt_m6_01.arl", 2 }, + { "Inspire/subtitle/German/evrt_m6_02.ar", 2 }, + { "Inspire/subtitle/German/evrt_m6_02.arl", 2 }, + { "Inspire/subtitle/German/evrt_m6_03.ar", 2 }, + { "Inspire/subtitle/German/evrt_m6_03.arl", 2 }, + { "Inspire/subtitle/German/evrt_m7_01.ar", 2 }, + { "Inspire/subtitle/German/evrt_m7_01.arl", 2 }, + { "Inspire/subtitle/German/evrt_m7_02.ar", 2 }, + { "Inspire/subtitle/German/evrt_m7_02.arl", 2 }, + { "Inspire/subtitle/German/evrt_m7_04.ar", 2 }, + { "Inspire/subtitle/German/evrt_m7_04.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_01.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_01.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_02.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_02.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_03.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_03.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_04.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_04.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_05.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_05.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_06_1.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_06_1.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_06_2.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_06_2.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_07.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_07.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_08.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_08.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_09.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_09.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_10.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_10.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_11_1.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_11_1.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_11_3.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_11_3.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_12.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_12.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_13.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_13.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_14.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_14.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_15.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_15.arl", 2 }, + { "Inspire/subtitle/German/evrt_m8_16.ar", 2 }, + { "Inspire/subtitle/German/evrt_m8_16.arl", 2 }, + { "Inspire/subtitle/German/evrt_s1_03.ar", 2 }, + { "Inspire/subtitle/German/evrt_s1_03.arl", 2 }, + { "Inspire/subtitle/German/evrt_s1_04.ar", 2 }, + { "Inspire/subtitle/German/evrt_s1_04.arl", 2 }, + { "Inspire/subtitle/German/evrt_s1_05.ar", 2 }, + { "Inspire/subtitle/German/evrt_s1_05.arl", 2 }, + { "Inspire/subtitle/German/evrt_s1_06.ar", 2 }, + { "Inspire/subtitle/German/evrt_s1_06.arl", 2 }, + { "Inspire/subtitle/German/evrt_s2_01.ar", 2 }, + { "Inspire/subtitle/German/evrt_s2_01.arl", 2 }, + { "Inspire/subtitle/German/evrt_s2_03.ar", 2 }, + { "Inspire/subtitle/German/evrt_s2_03.arl", 2 }, + { "Inspire/subtitle/German/evrt_s2_04.ar", 2 }, + { "Inspire/subtitle/German/evrt_s2_04.arl", 2 }, + { "Inspire/subtitle/German/evrt_s3_03.ar", 2 }, + { "Inspire/subtitle/German/evrt_s3_03.arl", 2 }, + { "Inspire/subtitle/German/evrt_s3_04.ar", 2 }, + { "Inspire/subtitle/German/evrt_s3_04.arl", 2 }, + { "Inspire/subtitle/German/evrt_t0_01.ar", 2 }, + { "Inspire/subtitle/German/evrt_t0_01.arl", 2 }, + { "Inspire/subtitle/German/evrt_t0_02.ar", 2 }, + { "Inspire/subtitle/German/evrt_t0_02.arl", 2 }, + { "Inspire/subtitle/German/evrt_t0_03.ar", 2 }, + { "Inspire/subtitle/German/evrt_t0_03.arl", 2 }, + { "Inspire/subtitle/German/evrt_t0_04.ar", 2 }, + { "Inspire/subtitle/German/evrt_t0_04.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m0_01_05.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m0_01_05.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m0_06.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m0_06.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m1_01.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m1_01.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m1_02.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m1_02.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m1_03_1.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m1_03_1.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m1_03_2.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m1_03_2.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m2_01.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m2_01.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m2_02.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m2_02.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m2_03.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m2_03.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m3_01.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m3_01.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m3_02.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m3_02.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m3_03.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m3_03.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m3_05.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m3_05.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m4_01.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m4_01.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m5_01.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m5_01.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m5_02.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m5_02.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m6_01.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m6_01.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m6_02.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m6_02.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m6_03.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m6_03.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m7_01.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m7_01.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m7_02.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m7_02.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m7_04.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m7_04.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_01.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_01.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_02.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_02.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_03.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_03.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_04.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_04.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_05.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_05.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_06_1.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_06_1.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_06_2.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_06_2.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_07.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_07.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_08.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_08.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_09.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_09.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_10.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_10.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_11_1.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_11_1.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_11_3.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_11_3.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_12.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_12.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_13.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_13.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_14.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_14.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_15.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_15.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_16.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_m8_16.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_s1_03.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_s1_03.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_s1_04.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_s1_04.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_s1_05.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_s1_05.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_s1_06.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_s1_06.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_s2_01.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_s2_01.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_s2_03.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_s2_03.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_s2_04.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_s2_04.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_s3_03.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_s3_03.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_s3_04.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_s3_04.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_t0_01.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_t0_01.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_t0_02.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_t0_02.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_t0_03.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_t0_03.arl", 2 }, + { "Inspire/subtitle/Italian/evrt_t0_04.ar", 2 }, + { "Inspire/subtitle/Italian/evrt_t0_04.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m0_01_05.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m0_01_05.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m0_06.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m0_06.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m1_01.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m1_01.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m1_02.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m1_02.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m1_03_1.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m1_03_1.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m1_03_2.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m1_03_2.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m2_01.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m2_01.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m2_02.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m2_02.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m2_03.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m2_03.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m3_01.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m3_01.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m3_02.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m3_02.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m3_03.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m3_03.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m3_05.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m3_05.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m4_01.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m4_01.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m5_01.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m5_01.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m5_02.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m5_02.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m6_01.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m6_01.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m6_02.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m6_02.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m6_03.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m6_03.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m7_01.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m7_01.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m7_02.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m7_02.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m7_04.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m7_04.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_01.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_01.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_02.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_02.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_03.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_03.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_04.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_04.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_05.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_05.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_06_1.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_06_1.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_06_2.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_06_2.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_07.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_07.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_08.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_08.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_09.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_09.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_10.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_10.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_11_1.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_11_1.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_11_3.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_11_3.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_12.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_12.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_13.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_13.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_14.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_14.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_15.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_15.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_16.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_m8_16.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_s1_03.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_s1_03.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_s1_04.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_s1_04.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_s1_05.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_s1_05.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_s1_06.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_s1_06.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_s2_01.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_s2_01.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_s2_03.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_s2_03.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_s2_04.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_s2_04.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_s3_03.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_s3_03.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_s3_04.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_s3_04.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_t0_01.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_t0_01.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_t0_02.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_t0_02.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_t0_03.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_t0_03.arl", 2 }, + { "Inspire/subtitle/Japanese/evrt_t0_04.ar", 2 }, + { "Inspire/subtitle/Japanese/evrt_t0_04.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m0_01_05.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m0_01_05.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m0_06.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m0_06.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m1_01.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m1_01.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m1_02.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m1_02.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m1_03_1.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m1_03_1.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m1_03_2.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m1_03_2.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m2_01.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m2_01.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m2_02.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m2_02.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m2_03.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m2_03.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m3_01.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m3_01.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m3_02.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m3_02.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m3_03.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m3_03.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m3_05.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m3_05.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m4_01.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m4_01.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m5_01.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m5_01.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m5_02.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m5_02.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m6_01.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m6_01.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m6_02.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m6_02.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m6_03.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m6_03.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m7_01.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m7_01.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m7_02.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m7_02.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m7_04.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m7_04.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_01.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_01.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_02.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_02.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_03.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_03.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_04.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_04.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_05.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_05.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_06_1.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_06_1.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_06_2.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_06_2.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_07.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_07.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_08.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_08.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_09.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_09.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_10.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_10.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_11_1.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_11_1.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_11_3.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_11_3.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_12.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_12.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_13.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_13.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_14.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_14.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_15.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_15.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_16.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_m8_16.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_s1_03.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_s1_03.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_s1_04.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_s1_04.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_s1_05.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_s1_05.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_s1_06.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_s1_06.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_s2_01.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_s2_01.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_s2_03.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_s2_03.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_s2_04.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_s2_04.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_s3_03.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_s3_03.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_s3_04.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_s3_04.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_t0_01.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_t0_01.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_t0_02.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_t0_02.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_t0_03.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_t0_03.arl", 2 }, + { "Inspire/subtitle/Spanish/evrt_t0_04.ar", 2 }, + { "Inspire/subtitle/Spanish/evrt_t0_04.arl", 2 }, + { "Item/item_apple.dds", 2 }, + { "Item/item_audio.dds", 2 }, + { "Item/item_balloon.dds", 2 }, + { "Item/item_banana.dds", 2 }, + { "Item/item_bean.dds", 2 }, + { "Item/item_biscuit.dds", 2 }, + { "Item/item_bookshelf.dds", 2 }, + { "Item/item_bouquetA.dds", 2 }, + { "Item/item_bouquetB.dds", 2 }, + { "Item/item_bouquetC.dds", 2 }, + { "Item/item_bread.dds", 2 }, + { "Item/item_cake.dds", 2 }, + { "Item/item_cameo.dds", 2 }, + { "Item/item_can.dds", 2 }, + { "Item/item_candy.dds", 2 }, + { "Item/item_carpet.dds", 2 }, + { "Item/item_chaobitan.dds", 2 }, + { "Item/item_char.dds", 2 }, + { "Item/item_charm_PetraCapital.dds", 2 }, + { "Item/item_charm_SouthEastAsia.dds", 2 }, + { "Item/item_cheese.dds", 2 }, + { "Item/item_chicken.dds", 2 }, + { "Item/item_chilidog.dds", 2 }, + { "Item/item_chinesenoodle.dds", 2 }, + { "Item/item_chochin.dds", 2 }, + { "Item/item_chocolate.dds", 2 }, + { "Item/item_coffee.dds", 2 }, + { "Item/item_computer.dds", 2 }, + { "Item/item_countyplate_Africa.dds", 2 }, + { "Item/item_countyplate_China.dds", 2 }, + { "Item/item_countyplate_EggManBase.dds", 2 }, + { "Item/item_countyplate_EuropeanCity.dds", 2 }, + { "Item/item_countyplate_Mykonos.dds", 2 }, + { "Item/item_countyplate_NYCity.dds", 2 }, + { "Item/item_countyplate_PetraCapital.dds", 2 }, + { "Item/item_countyplate_Snow.dds", 2 }, + { "Item/item_countyplate_SouthEastAsia.dds", 2 }, + { "Item/item_crystal.dds", 2 }, + { "Item/item_curry.dds", 2 }, + { "Item/item_daunuts.dds", 2 }, + { "Item/item_doll_snow.dds", 2 }, + { "Item/item_doran.dds", 2 }, + { "Item/item_eggcandy.dds", 2 }, + { "Item/item_eggdog.dds", 2 }, + { "Item/item_egglunch.dds", 2 }, + { "Item/item_eggman.dds", 2 }, + { "Item/item_fish.dds", 2 }, + { "Item/item_fruit.dds", 2 }, + { "Item/item_glass.dds", 2 }, + { "Item/item_goggle.dds", 2 }, + { "Item/item_gramophone.dds", 2 }, + { "Item/item_grape.dds", 2 }, + { "Item/item_grilfish.dds", 2 }, + { "Item/item_hamburger.dds", 2 }, + { "Item/item_hammock.dds", 2 }, + { "Item/item_ice.dds", 2 }, + { "Item/item_icecream.dds", 2 }, + { "Item/item_illustratedbook.dds", 2 }, + { "Item/item_jelly.dds", 2 }, + { "Item/item_juce.dds", 2 }, + { "Item/item_key_EU_day.dds", 2 }, + { "Item/item_key_EU_night.dds", 2 }, + { "Item/item_key_beach_day.dds", 2 }, + { "Item/item_key_beach_night.dds", 2 }, + { "Item/item_key_petra_day.dds", 2 }, + { "Item/item_key_petra_night.dds", 2 }, + { "Item/item_key_snow_day.dds", 2 }, + { "Item/item_key_snow_night.dds", 2 }, + { "Item/item_khoro.dds", 2 }, + { "Item/item_lace.dds", 2 }, + { "Item/item_lantern.dds", 2 }, + { "Item/item_lemon.dds", 2 }, + { "Item/item_lunch.dds", 2 }, + { "Item/item_magazine.dds", 2 }, + { "Item/item_mask.dds", 2 }, + { "Item/item_mask_EuropeanCity.dds", 2 }, + { "Item/item_meat.dds", 2 }, + { "Item/item_medicinebottle.dds", 2 }, + { "Item/item_mochi.dds", 2 }, + { "Item/item_momoman.dds", 2 }, + { "Item/item_nats.dds", 2 }, + { "Item/item_nikuman.dds", 2 }, + { "Item/item_oil.dds", 2 }, + { "Item/item_oldnecklace.dds", 2 }, + { "Item/item_orange.dds", 2 }, + { "Item/item_pasta.dds", 2 }, + { "Item/item_peach.dds", 2 }, + { "Item/item_picture.dds", 2 }, + { "Item/item_pingameet.dds", 2 }, + { "Item/item_pitchinuts.dds", 2 }, + { "Item/item_pizza.dds", 2 }, + { "Item/item_plate.dds", 2 }, + { "Item/item_popcake.dds", 2 }, + { "Item/item_popcorn.dds", 2 }, + { "Item/item_popuri.dds", 2 }, + { "Item/item_potate.dds", 2 }, + { "Item/item_pots.dds", 2 }, + { "Item/item_presentboxA.dds", 2 }, + { "Item/item_presentboxB.dds", 2 }, + { "Item/item_presentboxC.dds", 2 }, + { "Item/item_puku.dds", 2 }, + { "Item/item_puppet.dds", 2 }, + { "Item/item_record.dds", 2 }, + { "Item/item_ringA.dds", 2 }, + { "Item/item_salmon.dds", 2 }, + { "Item/item_sand.dds", 2 }, + { "Item/item_sandwich_01.dds", 2 }, + { "Item/item_sandwich_02.dds", 2 }, + { "Item/item_sandwich_03.dds", 2 }, + { "Item/item_shellfish.dds", 2 }, + { "Item/item_shimauma_doll.dds", 2 }, + { "Item/item_shishimil.dds", 2 }, + { "Item/item_shishkeba.dds", 2 }, + { "Item/item_shoes_ab.dds", 2 }, + { "Item/item_shoes_ld.dds", 2 }, + { "Item/item_shoes_sp.dds", 2 }, + { "Item/item_shoes_st.dds", 2 }, + { "Item/item_sled.dds", 2 }, + { "Item/item_special_choco.dds", 2 }, + { "Item/item_statue_SouthEastAsia.dds", 2 }, + { "Item/item_statue_maria.dds", 2 }, + { "Item/item_steak.dds", 2 }, + { "Item/item_supple.dds", 2 }, + { "Item/item_tapestry_Africa.dds", 2 }, + { "Item/item_tapestry_China.dds", 2 }, + { "Item/item_tapestry_EggManBase.dds", 2 }, + { "Item/item_tapestry_EuropeanCity.dds", 2 }, + { "Item/item_tapestry_Mykonos.dds", 2 }, + { "Item/item_tapestry_NYCtiy.dds", 2 }, + { "Item/item_tapestry_PetraCapital.dds", 2 }, + { "Item/item_tapestry_Snow.dds", 2 }, + { "Item/item_tapestry_SouthEastAsia.dds", 2 }, + { "Item/item_teabottleA.dds", 2 }, + { "Item/item_teabottleB.dds", 2 }, + { "Item/item_teabottleC.dds", 2 }, + { "Item/item_teabottleD.dds", 2 }, + { "Item/item_teabottleE.dds", 2 }, + { "Item/item_teabottleF.dds", 2 }, + { "Item/item_teabottleG.dds", 2 }, + { "Item/item_television.dds", 2 }, + { "Item/item_tomato.dds", 2 }, + { "Item/item_topijuice.dds", 2 }, + { "Item/item_tsubo.dds", 2 }, + { "Item/item_tsukaso.dds", 2 }, + { "Item/item_videotape.dds", 2 }, + { "Item/item_whale.dds", 2 }, + { "Languages/English/ActionCommon.ar.00", 2 }, + { "Languages/English/ActionCommon.arl", 2 }, + { "Languages/English/BossCommon.ar.00", 2 }, + { "Languages/English/BossCommon.arl", 2 }, + { "Languages/English/EvilActionCommon.ar.00", 2 }, + { "Languages/English/EvilActionCommon.arl", 2 }, + { "Languages/English/EvilSonic.ar.00", 2 }, + { "Languages/English/EvilSonic.arl", 2 }, + { "Languages/English/ExStageTails_Common.ar.00", 2 }, + { "Languages/English/ExStageTails_Common.arl", 2 }, + { "Languages/English/Loading.ar.00", 2 }, + { "Languages/English/Loading.arl", 2 }, + { "Languages/English/Sonic.ar.00", 2 }, + { "Languages/English/Sonic.arl", 2 }, + { "Languages/English/SonicActionCommon.ar.00", 2 }, + { "Languages/English/SonicActionCommon.arl", 2 }, + { "Languages/English/SuperSonic.ar.00", 2 }, + { "Languages/English/SuperSonic.arl", 2 }, + { "Languages/English/SystemCommonCore.ar.00", 2 }, + { "Languages/English/SystemCommonCore.arl", 2 }, + { "Languages/English/Title.ar.00", 2 }, + { "Languages/English/Title.arl", 2 }, + { "Languages/English/Town_Africa_Common.ar.00", 2 }, + { "Languages/English/Town_Africa_Common.arl", 2 }, + { "Languages/English/Town_China_Common.ar.00", 2 }, + { "Languages/English/Town_China_Common.arl", 2 }, + { "Languages/English/Town_Common.ar.00", 2 }, + { "Languages/English/Town_Common.arl", 2 }, + { "Languages/English/Town_EULabo_Common.ar.00", 2 }, + { "Languages/English/Town_EULabo_Common.arl", 2 }, + { "Languages/English/Town_EggManBase_Common.ar.00", 2 }, + { "Languages/English/Town_EggManBase_Common.arl", 2 }, + { "Languages/English/Town_EuropeanCity_Common.ar.00", 4 }, + { "Languages/English/Town_EuropeanCity_Common.arl", 4 }, + { "Languages/English/Town_Labo_Common.ar.00", 2 }, + { "Languages/English/Town_Labo_Common.arl", 2 }, + { "Languages/English/Town_Mykonos_Common.ar.00", 4 }, + { "Languages/English/Town_Mykonos_Common.arl", 4 }, + { "Languages/English/Town_NYCity_Common.ar.00", 4 }, + { "Languages/English/Town_NYCity_Common.arl", 4 }, + { "Languages/English/Town_PetraCapital_Common.ar.00", 2 }, + { "Languages/English/Town_PetraCapital_Common.arl", 2 }, + { "Languages/English/Town_PetraLabo_Common.ar.00", 2 }, + { "Languages/English/Town_PetraLabo_Common.arl", 2 }, + { "Languages/English/Town_Snow_Common.ar.00", 2 }, + { "Languages/English/Town_Snow_Common.arl", 2 }, + { "Languages/English/Town_SouthEastAsia_Common.ar.00", 4 }, + { "Languages/English/Town_SouthEastAsia_Common.arl", 4 }, + { "Languages/English/WorldMap.ar.00", 2 }, + { "Languages/English/WorldMap.arl", 2 }, + { "Languages/French/ActionCommon.ar.00", 2 }, + { "Languages/French/ActionCommon.arl", 2 }, + { "Languages/French/BossCommon.ar.00", 2 }, + { "Languages/French/BossCommon.arl", 2 }, + { "Languages/French/EvilActionCommon.ar.00", 2 }, + { "Languages/French/EvilActionCommon.arl", 2 }, + { "Languages/French/EvilSonic.ar.00", 2 }, + { "Languages/French/EvilSonic.arl", 2 }, + { "Languages/French/ExStageTails_Common.ar.00", 2 }, + { "Languages/French/ExStageTails_Common.arl", 2 }, + { "Languages/French/Loading.ar.00", 2 }, + { "Languages/French/Loading.arl", 2 }, + { "Languages/French/Sonic.ar.00", 2 }, + { "Languages/French/Sonic.arl", 2 }, + { "Languages/French/SonicActionCommon.ar.00", 2 }, + { "Languages/French/SonicActionCommon.arl", 2 }, + { "Languages/French/SuperSonic.ar.00", 2 }, + { "Languages/French/SuperSonic.arl", 2 }, + { "Languages/French/SystemCommonCore.ar.00", 2 }, + { "Languages/French/SystemCommonCore.arl", 2 }, + { "Languages/French/Title.ar.00", 2 }, + { "Languages/French/Title.arl", 2 }, + { "Languages/French/Town_Africa_Common.ar.00", 2 }, + { "Languages/French/Town_Africa_Common.arl", 2 }, + { "Languages/French/Town_China_Common.ar.00", 2 }, + { "Languages/French/Town_China_Common.arl", 2 }, + { "Languages/French/Town_Common.ar.00", 2 }, + { "Languages/French/Town_Common.arl", 2 }, + { "Languages/French/Town_EULabo_Common.ar.00", 2 }, + { "Languages/French/Town_EULabo_Common.arl", 2 }, + { "Languages/French/Town_EggManBase_Common.ar.00", 2 }, + { "Languages/French/Town_EggManBase_Common.arl", 2 }, + { "Languages/French/Town_EuropeanCity_Common.ar.00", 2 }, + { "Languages/French/Town_EuropeanCity_Common.arl", 2 }, + { "Languages/French/Town_Labo_Common.ar.00", 2 }, + { "Languages/French/Town_Labo_Common.arl", 2 }, + { "Languages/French/Town_Mykonos_Common.ar.00", 2 }, + { "Languages/French/Town_Mykonos_Common.arl", 2 }, + { "Languages/French/Town_NYCity_Common.ar.00", 2 }, + { "Languages/French/Town_NYCity_Common.arl", 2 }, + { "Languages/French/Town_PetraCapital_Common.ar.00", 2 }, + { "Languages/French/Town_PetraCapital_Common.arl", 2 }, + { "Languages/French/Town_PetraLabo_Common.ar.00", 2 }, + { "Languages/French/Town_PetraLabo_Common.arl", 2 }, + { "Languages/French/Town_Snow_Common.ar.00", 2 }, + { "Languages/French/Town_Snow_Common.arl", 2 }, + { "Languages/French/Town_SouthEastAsia_Common.ar.00", 2 }, + { "Languages/French/Town_SouthEastAsia_Common.arl", 2 }, + { "Languages/French/WorldMap.ar.00", 2 }, + { "Languages/French/WorldMap.arl", 2 }, + { "Languages/German/ActionCommon.ar.00", 2 }, + { "Languages/German/ActionCommon.arl", 2 }, + { "Languages/German/BossCommon.ar.00", 2 }, + { "Languages/German/BossCommon.arl", 2 }, + { "Languages/German/EvilActionCommon.ar.00", 2 }, + { "Languages/German/EvilActionCommon.arl", 2 }, + { "Languages/German/EvilSonic.ar.00", 2 }, + { "Languages/German/EvilSonic.arl", 2 }, + { "Languages/German/ExStageTails_Common.ar.00", 2 }, + { "Languages/German/ExStageTails_Common.arl", 2 }, + { "Languages/German/Loading.ar.00", 2 }, + { "Languages/German/Loading.arl", 2 }, + { "Languages/German/Sonic.ar.00", 2 }, + { "Languages/German/Sonic.arl", 2 }, + { "Languages/German/SonicActionCommon.ar.00", 2 }, + { "Languages/German/SonicActionCommon.arl", 2 }, + { "Languages/German/SuperSonic.ar.00", 2 }, + { "Languages/German/SuperSonic.arl", 2 }, + { "Languages/German/SystemCommonCore.ar.00", 2 }, + { "Languages/German/SystemCommonCore.arl", 2 }, + { "Languages/German/Title.ar.00", 2 }, + { "Languages/German/Title.arl", 2 }, + { "Languages/German/Town_Africa_Common.ar.00", 2 }, + { "Languages/German/Town_Africa_Common.arl", 2 }, + { "Languages/German/Town_China_Common.ar.00", 2 }, + { "Languages/German/Town_China_Common.arl", 2 }, + { "Languages/German/Town_Common.ar.00", 2 }, + { "Languages/German/Town_Common.arl", 2 }, + { "Languages/German/Town_EULabo_Common.ar.00", 2 }, + { "Languages/German/Town_EULabo_Common.arl", 2 }, + { "Languages/German/Town_EggManBase_Common.ar.00", 2 }, + { "Languages/German/Town_EggManBase_Common.arl", 2 }, + { "Languages/German/Town_EuropeanCity_Common.ar.00", 2 }, + { "Languages/German/Town_EuropeanCity_Common.arl", 2 }, + { "Languages/German/Town_Labo_Common.ar.00", 2 }, + { "Languages/German/Town_Labo_Common.arl", 2 }, + { "Languages/German/Town_Mykonos_Common.ar.00", 2 }, + { "Languages/German/Town_Mykonos_Common.arl", 2 }, + { "Languages/German/Town_NYCity_Common.ar.00", 2 }, + { "Languages/German/Town_NYCity_Common.arl", 2 }, + { "Languages/German/Town_PetraCapital_Common.ar.00", 2 }, + { "Languages/German/Town_PetraCapital_Common.arl", 2 }, + { "Languages/German/Town_PetraLabo_Common.ar.00", 2 }, + { "Languages/German/Town_PetraLabo_Common.arl", 2 }, + { "Languages/German/Town_Snow_Common.ar.00", 2 }, + { "Languages/German/Town_Snow_Common.arl", 2 }, + { "Languages/German/Town_SouthEastAsia_Common.ar.00", 2 }, + { "Languages/German/Town_SouthEastAsia_Common.arl", 2 }, + { "Languages/German/WorldMap.ar.00", 2 }, + { "Languages/German/WorldMap.arl", 2 }, + { "Languages/Italian/ActionCommon.ar.00", 2 }, + { "Languages/Italian/ActionCommon.arl", 2 }, + { "Languages/Italian/BossCommon.ar.00", 2 }, + { "Languages/Italian/BossCommon.arl", 2 }, + { "Languages/Italian/EvilActionCommon.ar.00", 2 }, + { "Languages/Italian/EvilActionCommon.arl", 2 }, + { "Languages/Italian/EvilSonic.ar.00", 2 }, + { "Languages/Italian/EvilSonic.arl", 2 }, + { "Languages/Italian/ExStageTails_Common.ar.00", 2 }, + { "Languages/Italian/ExStageTails_Common.arl", 2 }, + { "Languages/Italian/Loading.ar.00", 2 }, + { "Languages/Italian/Loading.arl", 2 }, + { "Languages/Italian/Sonic.ar.00", 2 }, + { "Languages/Italian/Sonic.arl", 2 }, + { "Languages/Italian/SonicActionCommon.ar.00", 2 }, + { "Languages/Italian/SonicActionCommon.arl", 2 }, + { "Languages/Italian/SuperSonic.ar.00", 2 }, + { "Languages/Italian/SuperSonic.arl", 2 }, + { "Languages/Italian/SystemCommonCore.ar.00", 2 }, + { "Languages/Italian/SystemCommonCore.arl", 2 }, + { "Languages/Italian/Title.ar.00", 2 }, + { "Languages/Italian/Title.arl", 2 }, + { "Languages/Italian/Town_Africa_Common.ar.00", 2 }, + { "Languages/Italian/Town_Africa_Common.arl", 2 }, + { "Languages/Italian/Town_China_Common.ar.00", 2 }, + { "Languages/Italian/Town_China_Common.arl", 2 }, + { "Languages/Italian/Town_Common.ar.00", 2 }, + { "Languages/Italian/Town_Common.arl", 2 }, + { "Languages/Italian/Town_EULabo_Common.ar.00", 2 }, + { "Languages/Italian/Town_EULabo_Common.arl", 2 }, + { "Languages/Italian/Town_EggManBase_Common.ar.00", 2 }, + { "Languages/Italian/Town_EggManBase_Common.arl", 2 }, + { "Languages/Italian/Town_EuropeanCity_Common.ar.00", 2 }, + { "Languages/Italian/Town_EuropeanCity_Common.arl", 2 }, + { "Languages/Italian/Town_Labo_Common.ar.00", 2 }, + { "Languages/Italian/Town_Labo_Common.arl", 2 }, + { "Languages/Italian/Town_Mykonos_Common.ar.00", 2 }, + { "Languages/Italian/Town_Mykonos_Common.arl", 2 }, + { "Languages/Italian/Town_NYCity_Common.ar.00", 2 }, + { "Languages/Italian/Town_NYCity_Common.arl", 2 }, + { "Languages/Italian/Town_PetraCapital_Common.ar.00", 2 }, + { "Languages/Italian/Town_PetraCapital_Common.arl", 2 }, + { "Languages/Italian/Town_PetraLabo_Common.ar.00", 2 }, + { "Languages/Italian/Town_PetraLabo_Common.arl", 2 }, + { "Languages/Italian/Town_Snow_Common.ar.00", 2 }, + { "Languages/Italian/Town_Snow_Common.arl", 2 }, + { "Languages/Italian/Town_SouthEastAsia_Common.ar.00", 2 }, + { "Languages/Italian/Town_SouthEastAsia_Common.arl", 2 }, + { "Languages/Italian/WorldMap.ar.00", 2 }, + { "Languages/Italian/WorldMap.arl", 2 }, + { "Languages/Japanese/ActionCommon.ar.00", 2 }, + { "Languages/Japanese/ActionCommon.arl", 2 }, + { "Languages/Japanese/BossCommon.ar.00", 2 }, + { "Languages/Japanese/BossCommon.arl", 2 }, + { "Languages/Japanese/EvilActionCommon.ar.00", 2 }, + { "Languages/Japanese/EvilActionCommon.arl", 2 }, + { "Languages/Japanese/EvilSonic.ar.00", 2 }, + { "Languages/Japanese/EvilSonic.arl", 2 }, + { "Languages/Japanese/ExStageTails_Common.ar.00", 2 }, + { "Languages/Japanese/ExStageTails_Common.arl", 2 }, + { "Languages/Japanese/Loading.ar.00", 2 }, + { "Languages/Japanese/Loading.arl", 2 }, + { "Languages/Japanese/Sonic.ar.00", 2 }, + { "Languages/Japanese/Sonic.arl", 2 }, + { "Languages/Japanese/SonicActionCommon.ar.00", 2 }, + { "Languages/Japanese/SonicActionCommon.arl", 2 }, + { "Languages/Japanese/SuperSonic.ar.00", 2 }, + { "Languages/Japanese/SuperSonic.arl", 2 }, + { "Languages/Japanese/SystemCommonCore.ar.00", 2 }, + { "Languages/Japanese/SystemCommonCore.arl", 2 }, + { "Languages/Japanese/Title.ar.00", 2 }, + { "Languages/Japanese/Title.arl", 2 }, + { "Languages/Japanese/Town_Africa_Common.ar.00", 2 }, + { "Languages/Japanese/Town_Africa_Common.arl", 2 }, + { "Languages/Japanese/Town_China_Common.ar.00", 2 }, + { "Languages/Japanese/Town_China_Common.arl", 2 }, + { "Languages/Japanese/Town_Common.ar.00", 2 }, + { "Languages/Japanese/Town_Common.arl", 2 }, + { "Languages/Japanese/Town_EULabo_Common.ar.00", 2 }, + { "Languages/Japanese/Town_EULabo_Common.arl", 2 }, + { "Languages/Japanese/Town_EggManBase_Common.ar.00", 2 }, + { "Languages/Japanese/Town_EggManBase_Common.arl", 2 }, + { "Languages/Japanese/Town_EuropeanCity_Common.ar.00", 2 }, + { "Languages/Japanese/Town_EuropeanCity_Common.arl", 2 }, + { "Languages/Japanese/Town_Labo_Common.ar.00", 2 }, + { "Languages/Japanese/Town_Labo_Common.arl", 2 }, + { "Languages/Japanese/Town_Mykonos_Common.ar.00", 2 }, + { "Languages/Japanese/Town_Mykonos_Common.arl", 2 }, + { "Languages/Japanese/Town_NYCity_Common.ar.00", 2 }, + { "Languages/Japanese/Town_NYCity_Common.arl", 2 }, + { "Languages/Japanese/Town_PetraCapital_Common.ar.00", 2 }, + { "Languages/Japanese/Town_PetraCapital_Common.arl", 2 }, + { "Languages/Japanese/Town_PetraLabo_Common.ar.00", 2 }, + { "Languages/Japanese/Town_PetraLabo_Common.arl", 2 }, + { "Languages/Japanese/Town_Snow_Common.ar.00", 2 }, + { "Languages/Japanese/Town_Snow_Common.arl", 2 }, + { "Languages/Japanese/Town_SouthEastAsia_Common.ar.00", 2 }, + { "Languages/Japanese/Town_SouthEastAsia_Common.arl", 2 }, + { "Languages/Japanese/WorldMap.ar.00", 2 }, + { "Languages/Japanese/WorldMap.arl", 2 }, + { "Languages/Spanish/ActionCommon.ar.00", 2 }, + { "Languages/Spanish/ActionCommon.arl", 2 }, + { "Languages/Spanish/BossCommon.ar.00", 2 }, + { "Languages/Spanish/BossCommon.arl", 2 }, + { "Languages/Spanish/EvilActionCommon.ar.00", 2 }, + { "Languages/Spanish/EvilActionCommon.arl", 2 }, + { "Languages/Spanish/EvilSonic.ar.00", 2 }, + { "Languages/Spanish/EvilSonic.arl", 2 }, + { "Languages/Spanish/ExStageTails_Common.ar.00", 2 }, + { "Languages/Spanish/ExStageTails_Common.arl", 2 }, + { "Languages/Spanish/Loading.ar.00", 2 }, + { "Languages/Spanish/Loading.arl", 2 }, + { "Languages/Spanish/Sonic.ar.00", 2 }, + { "Languages/Spanish/Sonic.arl", 2 }, + { "Languages/Spanish/SonicActionCommon.ar.00", 2 }, + { "Languages/Spanish/SonicActionCommon.arl", 2 }, + { "Languages/Spanish/SuperSonic.ar.00", 2 }, + { "Languages/Spanish/SuperSonic.arl", 2 }, + { "Languages/Spanish/SystemCommonCore.ar.00", 2 }, + { "Languages/Spanish/SystemCommonCore.arl", 2 }, + { "Languages/Spanish/Title.ar.00", 2 }, + { "Languages/Spanish/Title.arl", 2 }, + { "Languages/Spanish/Town_Africa_Common.ar.00", 2 }, + { "Languages/Spanish/Town_Africa_Common.arl", 2 }, + { "Languages/Spanish/Town_China_Common.ar.00", 2 }, + { "Languages/Spanish/Town_China_Common.arl", 2 }, + { "Languages/Spanish/Town_Common.ar.00", 2 }, + { "Languages/Spanish/Town_Common.arl", 2 }, + { "Languages/Spanish/Town_EULabo_Common.ar.00", 2 }, + { "Languages/Spanish/Town_EULabo_Common.arl", 2 }, + { "Languages/Spanish/Town_EggManBase_Common.ar.00", 2 }, + { "Languages/Spanish/Town_EggManBase_Common.arl", 2 }, + { "Languages/Spanish/Town_EuropeanCity_Common.ar.00", 2 }, + { "Languages/Spanish/Town_EuropeanCity_Common.arl", 2 }, + { "Languages/Spanish/Town_Labo_Common.ar.00", 2 }, + { "Languages/Spanish/Town_Labo_Common.arl", 2 }, + { "Languages/Spanish/Town_Mykonos_Common.ar.00", 2 }, + { "Languages/Spanish/Town_Mykonos_Common.arl", 2 }, + { "Languages/Spanish/Town_NYCity_Common.ar.00", 2 }, + { "Languages/Spanish/Town_NYCity_Common.arl", 2 }, + { "Languages/Spanish/Town_PetraCapital_Common.ar.00", 2 }, + { "Languages/Spanish/Town_PetraCapital_Common.arl", 2 }, + { "Languages/Spanish/Town_PetraLabo_Common.ar.00", 2 }, + { "Languages/Spanish/Town_PetraLabo_Common.arl", 2 }, + { "Languages/Spanish/Town_Snow_Common.ar.00", 2 }, + { "Languages/Spanish/Town_Snow_Common.arl", 2 }, + { "Languages/Spanish/Town_SouthEastAsia_Common.ar.00", 2 }, + { "Languages/Spanish/Town_SouthEastAsia_Common.arl", 2 }, + { "Languages/Spanish/WorldMap.ar.00", 2 }, + { "Languages/Spanish/WorldMap.arl", 2 }, + { "Loading.ar.00", 2 }, + { "Loading.arl", 2 }, + { "Loading/EvilStage.dds", 2 }, + { "Loading/OPmovie_titlelogo_EN.dds", 2 }, + { "Loading/OPmovie_titlelogo_JP.dds", 2 }, + { "Loading/SonicStage.dds", 2 }, + { "Loading/TownSample.dds", 2 }, + { "Loading/logo_havok.dds", 2 }, + { "Loading/logo_sonicteam.dds", 2 }, + { "Loading/logos_en.dds", 2 }, + { "Loading/logos_jp.dds", 2 }, + { "Loading/mat_load_town_EU.dds", 2 }, + { "Loading/mat_load_town_NY.dds", 2 }, + { "Loading/mat_load_town_africa.dds", 2 }, + { "Loading/mat_load_town_beach.dds", 2 }, + { "Loading/mat_load_town_china.dds", 2 }, + { "Loading/mat_load_town_eggman.dds", 2 }, + { "Loading/mat_load_town_mykonos.dds", 2 }, + { "Loading/mat_load_town_petra.dds", 2 }, + { "Loading/mat_load_town_snow.dds", 2 }, + { "Loading/mat_loadinfo_bg_af_d.dds", 2 }, + { "Loading/mat_loadinfo_bg_af_n.dds", 2 }, + { "Loading/mat_loadinfo_bg_be_d.dds", 2 }, + { "Loading/mat_loadinfo_bg_be_n.dds", 2 }, + { "Loading/mat_loadinfo_bg_ch_d.dds", 2 }, + { "Loading/mat_loadinfo_bg_ch_n.dds", 2 }, + { "Loading/mat_loadinfo_bg_eg.dds", 2 }, + { "Loading/mat_loadinfo_bg_eu_d.dds", 2 }, + { "Loading/mat_loadinfo_bg_eu_n.dds", 2 }, + { "Loading/mat_loadinfo_bg_ex_1_360.dds", 2 }, + { "Loading/mat_loadinfo_bg_ex_2_360.dds", 2 }, + { "Loading/mat_loadinfo_bg_lb.dds", 2 }, + { "Loading/mat_loadinfo_bg_my_d.dds", 2 }, + { "Loading/mat_loadinfo_bg_my_n.dds", 2 }, + { "Loading/mat_loadinfo_bg_ny_d.dds", 2 }, + { "Loading/mat_loadinfo_bg_ny_n.dds", 2 }, + { "Loading/mat_loadinfo_bg_pe_d.dds", 2 }, + { "Loading/mat_loadinfo_bg_pe_n.dds", 2 }, + { "Loading/mat_loadinfo_bg_sn_d.dds", 2 }, + { "Loading/mat_loadinfo_bg_sn_n.dds", 2 }, + { "Loading/mat_loadinfo_robo_1.dds", 2 }, + { "Loading/mat_loadinfo_robo_2.dds", 2 }, + { "Loading/mat_loadinfo_robo_3.dds", 2 }, + { "Loading/mat_loadinfo_sonic_1.dds", 2 }, + { "Loading/mat_loadinfo_sonic_2.dds", 2 }, + { "Loading/mat_loadinfo_sonic_3.dds", 2 }, + { "Loading/mat_loadinfo_sonic_4.dds", 2 }, + { "Loading/mat_loadinfo_sonic_5.dds", 2 }, + { "Loading/mat_loadinfo_sonic_6.dds", 2 }, + { "Loading/mat_loadinfo_sonic_7.dds", 2 }, + { "Loading/mat_loadinfo_supersonic.dds", 2 }, + { "Loading/mat_loadinfo_werehog_1.dds", 2 }, + { "Loading/mat_loadinfo_werehog_2.dds", 2 }, + { "Loading/mat_loadinfo_werehog_3.dds", 2 }, + { "Loading/mat_loadinfo_werehog_4.dds", 2 }, + { "Loading/mat_loadinfo_werehog_5.dds", 2 }, + { "Loading/mat_loadinfo_werehog_6.dds", 2 }, + { "Loading/mat_loadinfo_werehog_7.dds", 2 }, + { "Loading/mat_loadinfo_werehog_8.dds", 2 }, + { "Loading/mat_loadinfo_werehog_9.dds", 2 }, + { "MainMenu.ar.00", 2 }, + { "MainMenu.arl", 2 }, + { "Packed/ActD_Africa/Stage.pfd", 1 }, + { "Packed/ActD_Beach/Stage.pfd", 1 }, + { "Packed/ActD_China/Stage.pfd", 1 }, + { "Packed/ActD_EU/Stage.pfd", 1 }, + { "Packed/ActD_MykonosAct1/Stage.pfd", 1 }, + { "Packed/ActD_MykonosAct2/Stage.pfd", 1 }, + { "Packed/ActD_NY/Stage.pfd", 1 }, + { "Packed/ActD_Petra/Stage.pfd", 1 }, + { "Packed/ActD_Snow/Stage.pfd", 1 }, + { "Packed/ActD_SubAfrica_01/Stage.pfd", 1 }, + { "Packed/ActD_SubAfrica_03/Stage.pfd", 1 }, + { "Packed/ActD_SubBeach_02/Stage.pfd", 1 }, + { "Packed/ActD_SubBeach_04/Stage.pfd", 1 }, + { "Packed/ActD_SubChina_03/Stage.pfd", 1 }, + { "Packed/ActD_SubChina_04/Stage.pfd", 1 }, + { "Packed/ActD_SubEU_01/Stage.pfd", 1 }, + { "Packed/ActD_SubEU_02/Stage.pfd", 1 }, + { "Packed/ActD_SubMykonos_01/Stage.pfd", 1 }, + { "Packed/ActD_SubNY_01/Stage.pfd", 1 }, + { "Packed/ActD_SubPetra_03/Stage.pfd", 1 }, + { "Packed/ActD_SubSnow_01/Stage.pfd", 1 }, + { "Packed/ActN_AfricaEvil/Stage.pfd", 1 }, + { "Packed/ActN_BeachEvil/Stage.pfd", 1 }, + { "Packed/ActN_ChinaEvil/Stage.pfd", 1 }, + { "Packed/ActN_EUEvil/Stage.pfd", 1 }, + { "Packed/ActN_MykonosEvil/Stage.pfd", 1 }, + { "Packed/ActN_NYEvil/Stage.pfd", 1 }, + { "Packed/ActN_PetraEvil/Stage.pfd", 1 }, + { "Packed/ActN_SnowEvil/Stage.pfd", 1 }, + { "Packed/ActN_SubAfrica_01/Stage.pfd", 1 }, + { "Packed/ActN_SubBeach_01/Stage.pfd", 1 }, + { "Packed/ActN_SubChina_01/Stage.pfd", 1 }, + { "Packed/ActN_SubMykonos_01/Stage.pfd", 1 }, + { "Packed/Act_EggmanLand/Stage.pfd", 1 }, + { "Packed/BossDarkGaia1_1Air/Stage.pfd", 1 }, + { "Packed/BossDarkGaia1_1Run/Stage.pfd", 1 }, + { "Packed/BossDarkGaia1_2Run/Stage.pfd", 1 }, + { "Packed/BossDarkGaia1_3Run/Stage.pfd", 1 }, + { "Packed/BossDarkGaiaMoray/Stage.pfd", 1 }, + { "Packed/BossEggBeetle/Stage.pfd", 1 }, + { "Packed/BossEggDragoon/Stage.pfd", 1 }, + { "Packed/BossEggLancer/Stage.pfd", 1 }, + { "Packed/BossEggRayBird/Stage.pfd", 1 }, + { "Packed/BossFinalDarkGaia/Stage.pfd", 1 }, + { "Packed/BossPetra/Stage.pfd", 1 }, + { "Packed/BossPhoenix/Stage.pfd", 1 }, + { "Packed/Event_M2_01_professor_room_new/Stage.pfd", 1 }, + { "Packed/Event_M4_01_egb_hideout/Stage.pfd", 1 }, + { "Packed/Event_M6_01_temple/Stage.pfd", 1 }, + { "Packed/Event_M8_02_egbHall/Stage.pfd", 1 }, + { "Packed/Event_M8_03/Stage.pfd", 1 }, + { "Packed/Event_M8_16_myk/Stage.pfd", 1 }, + { "Packed/Event_afr_hideout/Stage.pfd", 1 }, + { "Packed/Event_egb_hidout_exterior/Stage.pfd", 1 }, + { "Packed/Event_temple/Stage.pfd", 1 }, + { "Packed/ExStageTails1/Stage.pfd", 1 }, + { "Packed/ExStageTails2/Stage.pfd", 1 }, + { "Packed/Town_Africa/Stage.pfd", 1 }, + { "Packed/Town_AfricaETF/Stage.pfd", 1 }, + { "Packed/Town_AfricaETF_Night/Stage.pfd", 1 }, + { "Packed/Town_Africa_Night/Stage.pfd", 1 }, + { "Packed/Town_China/Stage.pfd", 1 }, + { "Packed/Town_ChinaETF/Stage.pfd", 1 }, + { "Packed/Town_ChinaETF_Night/Stage.pfd", 1 }, + { "Packed/Town_China_Night/Stage.pfd", 1 }, + { "Packed/Town_EULabo/Stage.pfd", 1 }, + { "Packed/Town_EULabo_Night/Stage.pfd", 1 }, + { "Packed/Town_EggManBase/Stage.pfd", 1 }, + { "Packed/Town_EuropeanCity/Stage.pfd", 1 }, + { "Packed/Town_EuropeanCityETF/Stage.pfd", 1 }, + { "Packed/Town_EuropeanCityETF_Night/Stage.pfd", 1 }, + { "Packed/Town_EuropeanCity_Night/Stage.pfd", 1 }, + { "Packed/Town_Mykonos/Stage.pfd", 1 }, + { "Packed/Town_MykonosETF/Stage.pfd", 1 }, + { "Packed/Town_MykonosETF_Night/Stage.pfd", 1 }, + { "Packed/Town_Mykonos_Night/Stage.pfd", 1 }, + { "Packed/Town_NYCity/Stage.pfd", 1 }, + { "Packed/Town_NYCityETF/Stage.pfd", 1 }, + { "Packed/Town_NYCityETF_Night/Stage.pfd", 1 }, + { "Packed/Town_NYCity_Night/Stage.pfd", 1 }, + { "Packed/Town_PetraCapital/Stage.pfd", 1 }, + { "Packed/Town_PetraCapitalETF/Stage.pfd", 1 }, + { "Packed/Town_PetraCapitalETF_Night/Stage.pfd", 1 }, + { "Packed/Town_PetraCapital_Night/Stage.pfd", 1 }, + { "Packed/Town_PetraLabo/Stage.pfd", 1 }, + { "Packed/Town_PetraLabo_Night/Stage.pfd", 1 }, + { "Packed/Town_Snow/Stage.pfd", 1 }, + { "Packed/Town_SnowETF/Stage.pfd", 1 }, + { "Packed/Town_SnowETF_Night/Stage.pfd", 1 }, + { "Packed/Town_Snow_Night/Stage.pfd", 1 }, + { "Packed/Town_SouthEastAsia/Stage.pfd", 1 }, + { "Packed/Town_SouthEastAsiaETF/Stage.pfd", 1 }, + { "Packed/Town_SouthEastAsiaETF_Night/Stage.pfd", 1 }, + { "Packed/Town_SouthEastAsia_Night/Stage.pfd", 1 }, + { "Sonic.ar.00", 2 }, + { "Sonic.ar.01", 2 }, + { "Sonic.arl", 2 }, + { "SonicActionCommon.ar.00", 2 }, + { "SonicActionCommon.arl", 2 }, + { "SonicActionCommonGeneral.ar.00", 2 }, + { "SonicActionCommonGeneral.arl", 2 }, + { "SonicActionCommon_Africa.ar.00", 2 }, + { "SonicActionCommon_Africa.arl", 2 }, + { "SonicActionCommon_Beach.ar.00", 2 }, + { "SonicActionCommon_Beach.ar.01", 2 }, + { "SonicActionCommon_Beach.arl", 2 }, + { "SonicActionCommon_China.ar.00", 2 }, + { "SonicActionCommon_China.ar.01", 2 }, + { "SonicActionCommon_China.arl", 2 }, + { "SonicActionCommon_EU.ar.00", 2 }, + { "SonicActionCommon_EU.ar.01", 2 }, + { "SonicActionCommon_EU.arl", 2 }, + { "SonicActionCommon_EggmanLand.ar.00", 2 }, + { "SonicActionCommon_EggmanLand.ar.01", 2 }, + { "SonicActionCommon_EggmanLand.arl", 2 }, + { "SonicActionCommon_Mykonos.ar.00", 2 }, + { "SonicActionCommon_Mykonos.arl", 2 }, + { "SonicActionCommon_NY.ar.00", 2 }, + { "SonicActionCommon_NY.ar.01", 2 }, + { "SonicActionCommon_NY.arl", 2 }, + { "SonicActionCommon_Petra.ar.00", 2 }, + { "SonicActionCommon_Petra.arl", 2 }, + { "SonicActionCommon_Snow.ar.00", 2 }, + { "SonicActionCommon_Snow.ar.01", 2 }, + { "SonicActionCommon_Snow.arl", 2 }, + { "SonicCommon.ar.00", 2 }, + { "SonicCommon.arl", 2 }, + { "SonicCommonGeneral.ar.00", 2 }, + { "SonicCommonGeneral.arl", 2 }, + { "SonicEnemyEAirCannon.ar.00", 2 }, + { "SonicEnemyEAirCannon.arl", 2 }, + { "SonicEnemyEAirChaser.ar.00", 2 }, + { "SonicEnemyEAirChaser.arl", 2 }, + { "SonicEnemyEBigChaser.ar.00", 2 }, + { "SonicEnemyEBigChaser.arl", 2 }, + { "SonicEnemyEElement.ar.00", 2 }, + { "SonicEnemyEElement.arl", 2 }, + { "SonicEnemyEFighterG.ar.00", 2 }, + { "SonicEnemyEFighterG.arl", 2 }, + { "SonicEnemyEFighterK.ar.00", 2 }, + { "SonicEnemyEFighterK.arl", 2 }, + { "SonicEnemyEFighterN.ar.00", 2 }, + { "SonicEnemyEFighterN.arl", 2 }, + { "SonicEnemyEFighterS.ar.00", 2 }, + { "SonicEnemyEFighterS.arl", 2 }, + { "SonicEnemyEFighterT.ar.00", 2 }, + { "SonicEnemyEFighterT.arl", 2 }, + { "SonicEnemyEMoleCannon.ar.00", 2 }, + { "SonicEnemyEMoleCannon.arl", 2 }, + { "SonicEnemyEShackle.ar.00", 2 }, + { "SonicEnemyEShackle.arl", 2 }, + { "SonicEnemyEShooter.ar.00", 2 }, + { "SonicEnemyEShooter.arl", 2 }, + { "SonicEnemyESpinner.ar.00", 2 }, + { "SonicEnemyESpinner.arl", 2 }, + { "SonicEnemyEThunderBall.ar.00", 2 }, + { "SonicEnemyEThunderBall.arl", 2 }, + { "Sound/Inspire/ev_m0_06_EN.cpk", 1 }, + { "Sound/Inspire/ev_m0_06_EN.csb", 1 }, + { "Sound/Inspire/ev_m0_06_JP.cpk", 1 }, + { "Sound/Inspire/ev_m0_06_JP.csb", 1 }, + { "Sound/Inspire/ev_m1_01_EN.cpk", 1 }, + { "Sound/Inspire/ev_m1_01_EN.csb", 1 }, + { "Sound/Inspire/ev_m1_01_JP.cpk", 1 }, + { "Sound/Inspire/ev_m1_01_JP.csb", 1 }, + { "Sound/Inspire/ev_m1_02_EN.cpk", 1 }, + { "Sound/Inspire/ev_m1_02_EN.csb", 1 }, + { "Sound/Inspire/ev_m1_02_JP.cpk", 1 }, + { "Sound/Inspire/ev_m1_02_JP.csb", 1 }, + { "Sound/Inspire/ev_m1_03_1_EN.cpk", 1 }, + { "Sound/Inspire/ev_m1_03_1_EN.csb", 1 }, + { "Sound/Inspire/ev_m1_03_2_EN.cpk", 1 }, + { "Sound/Inspire/ev_m1_03_2_EN.csb", 1 }, + { "Sound/Inspire/ev_m1_03_2_JP.cpk", 1 }, + { "Sound/Inspire/ev_m1_03_2_JP.csb", 1 }, + { "Sound/Inspire/ev_m1_03_JP.cpk", 1 }, + { "Sound/Inspire/ev_m1_03_JP.csb", 1 }, + { "Sound/Inspire/ev_m2_01_EN.cpk", 1 }, + { "Sound/Inspire/ev_m2_01_EN.csb", 1 }, + { "Sound/Inspire/ev_m2_01_JP.cpk", 1 }, + { "Sound/Inspire/ev_m2_01_JP.csb", 1 }, + { "Sound/Inspire/ev_m2_02_EN.cpk", 1 }, + { "Sound/Inspire/ev_m2_02_EN.csb", 1 }, + { "Sound/Inspire/ev_m2_02_JP.cpk", 1 }, + { "Sound/Inspire/ev_m2_02_JP.csb", 1 }, + { "Sound/Inspire/ev_m2_03_EN.cpk", 1 }, + { "Sound/Inspire/ev_m2_03_EN.csb", 1 }, + { "Sound/Inspire/ev_m2_03_JP.cpk", 1 }, + { "Sound/Inspire/ev_m2_03_JP.csb", 1 }, + { "Sound/Inspire/ev_m3_01_EN.cpk", 1 }, + { "Sound/Inspire/ev_m3_01_EN.csb", 1 }, + { "Sound/Inspire/ev_m3_01_JP.cpk", 1 }, + { "Sound/Inspire/ev_m3_01_JP.csb", 1 }, + { "Sound/Inspire/ev_m3_02_EN.cpk", 1 }, + { "Sound/Inspire/ev_m3_02_EN.csb", 1 }, + { "Sound/Inspire/ev_m3_02_JP.cpk", 1 }, + { "Sound/Inspire/ev_m3_02_JP.csb", 1 }, + { "Sound/Inspire/ev_m3_03_EN.cpk", 1 }, + { "Sound/Inspire/ev_m3_03_EN.csb", 1 }, + { "Sound/Inspire/ev_m3_03_JP.cpk", 1 }, + { "Sound/Inspire/ev_m3_03_JP.csb", 1 }, + { "Sound/Inspire/ev_m3_05_EN.cpk", 1 }, + { "Sound/Inspire/ev_m3_05_EN.csb", 1 }, + { "Sound/Inspire/ev_m3_05_JP.cpk", 1 }, + { "Sound/Inspire/ev_m3_05_JP.csb", 1 }, + { "Sound/Inspire/ev_m4_01_EN.cpk", 1 }, + { "Sound/Inspire/ev_m4_01_EN.csb", 1 }, + { "Sound/Inspire/ev_m4_01_JP.cpk", 1 }, + { "Sound/Inspire/ev_m4_01_JP.csb", 1 }, + { "Sound/Inspire/ev_m5_02_EN.cpk", 1 }, + { "Sound/Inspire/ev_m5_02_EN.csb", 1 }, + { "Sound/Inspire/ev_m5_02_JP.cpk", 1 }, + { "Sound/Inspire/ev_m5_02_JP.csb", 1 }, + { "Sound/Inspire/ev_m6_01_EN.cpk", 1 }, + { "Sound/Inspire/ev_m6_01_EN.csb", 1 }, + { "Sound/Inspire/ev_m6_01_JP.cpk", 1 }, + { "Sound/Inspire/ev_m6_01_JP.csb", 1 }, + { "Sound/Inspire/ev_m6_02_EN.cpk", 1 }, + { "Sound/Inspire/ev_m6_02_EN.csb", 1 }, + { "Sound/Inspire/ev_m6_02_JP.cpk", 1 }, + { "Sound/Inspire/ev_m6_02_JP.csb", 1 }, + { "Sound/Inspire/ev_m6_03_EN.cpk", 1 }, + { "Sound/Inspire/ev_m6_03_EN.csb", 1 }, + { "Sound/Inspire/ev_m6_03_JP.cpk", 1 }, + { "Sound/Inspire/ev_m6_03_JP.csb", 1 }, + { "Sound/Inspire/ev_m7_01_EN.cpk", 1 }, + { "Sound/Inspire/ev_m7_01_EN.csb", 1 }, + { "Sound/Inspire/ev_m7_01_JP.cpk", 1 }, + { "Sound/Inspire/ev_m7_01_JP.csb", 1 }, + { "Sound/Inspire/ev_m7_02_EN.cpk", 1 }, + { "Sound/Inspire/ev_m7_02_EN.csb", 1 }, + { "Sound/Inspire/ev_m7_02_JP.cpk", 1 }, + { "Sound/Inspire/ev_m7_02_JP.csb", 1 }, + { "Sound/Inspire/ev_m7_04_EN.cpk", 1 }, + { "Sound/Inspire/ev_m7_04_EN.csb", 1 }, + { "Sound/Inspire/ev_m7_04_JP.cpk", 1 }, + { "Sound/Inspire/ev_m7_04_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_01_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_01_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_01_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_01_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_02_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_02_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_02_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_02_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_03_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_03_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_03_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_03_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_06_02_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_06_02_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_06_2_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_06_2_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_07_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_07_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_07_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_07_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_08_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_08_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_08_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_08_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_09_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_09_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_09_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_09_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_11_3_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_11_3_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_11_3_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_11_3_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_12_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_12_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_12_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_12_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_13_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_13_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_13_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_13_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_14_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_14_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_14_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_14_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_15_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_15_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_15_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_15_JP.csb", 1 }, + { "Sound/Inspire/ev_m8_16_EN.cpk", 1 }, + { "Sound/Inspire/ev_m8_16_EN.csb", 1 }, + { "Sound/Inspire/ev_m8_16_JP.cpk", 1 }, + { "Sound/Inspire/ev_m8_16_JP.csb", 1 }, + { "Sound/Inspire/ev_s1_03_EN.cpk", 1 }, + { "Sound/Inspire/ev_s1_03_EN.csb", 1 }, + { "Sound/Inspire/ev_s1_03_JP.cpk", 1 }, + { "Sound/Inspire/ev_s1_03_JP.csb", 1 }, + { "Sound/Inspire/ev_s1_04_EN.cpk", 1 }, + { "Sound/Inspire/ev_s1_04_EN.csb", 1 }, + { "Sound/Inspire/ev_s1_04_JP.cpk", 1 }, + { "Sound/Inspire/ev_s1_04_JP.csb", 1 }, + { "Sound/Inspire/ev_s1_05_EN.cpk", 1 }, + { "Sound/Inspire/ev_s1_05_EN.csb", 1 }, + { "Sound/Inspire/ev_s1_05_JP.cpk", 1 }, + { "Sound/Inspire/ev_s1_05_JP.csb", 1 }, + { "Sound/Inspire/ev_s1_06_EN.cpk", 1 }, + { "Sound/Inspire/ev_s1_06_EN.csb", 1 }, + { "Sound/Inspire/ev_s1_06_JP.cpk", 1 }, + { "Sound/Inspire/ev_s1_06_JP.csb", 1 }, + { "Sound/Inspire/ev_s2_01_EN.cpk", 1 }, + { "Sound/Inspire/ev_s2_01_EN.csb", 1 }, + { "Sound/Inspire/ev_s2_01_JP.cpk", 1 }, + { "Sound/Inspire/ev_s2_01_JP.csb", 1 }, + { "Sound/Inspire/ev_s2_03_EN.cpk", 1 }, + { "Sound/Inspire/ev_s2_03_EN.csb", 1 }, + { "Sound/Inspire/ev_s2_03_JP.cpk", 1 }, + { "Sound/Inspire/ev_s2_03_JP.csb", 1 }, + { "Sound/Inspire/ev_s2_04_EN.cpk", 1 }, + { "Sound/Inspire/ev_s2_04_EN.csb", 1 }, + { "Sound/Inspire/ev_s2_04_JP.cpk", 1 }, + { "Sound/Inspire/ev_s2_04_JP.csb", 1 }, + { "Sound/Inspire/ev_s3_03_EN.cpk", 1 }, + { "Sound/Inspire/ev_s3_03_EN.csb", 1 }, + { "Sound/Inspire/ev_s3_03_JP.cpk", 1 }, + { "Sound/Inspire/ev_s3_03_JP.csb", 1 }, + { "Sound/Inspire/ev_s3_04_EN.cpk", 1 }, + { "Sound/Inspire/ev_s3_04_EN.csb", 1 }, + { "Sound/Inspire/ev_s3_04_JP.cpk", 1 }, + { "Sound/Inspire/ev_s3_04_JP.csb", 1 }, + { "Sound/Inspire/ev_t0_01_EN.cpk", 1 }, + { "Sound/Inspire/ev_t0_01_EN.csb", 1 }, + { "Sound/Inspire/ev_t0_01_JP.cpk", 1 }, + { "Sound/Inspire/ev_t0_01_JP.csb", 1 }, + { "Sound/Inspire/ev_t0_02_EN.cpk", 1 }, + { "Sound/Inspire/ev_t0_02_EN.csb", 1 }, + { "Sound/Inspire/ev_t0_02_JP.cpk", 1 }, + { "Sound/Inspire/ev_t0_02_JP.csb", 1 }, + { "Sound/Inspire/ev_t0_03_EN.cpk", 1 }, + { "Sound/Inspire/ev_t0_03_EN.csb", 1 }, + { "Sound/Inspire/ev_t0_03_JP.cpk", 1 }, + { "Sound/Inspire/ev_t0_03_JP.csb", 1 }, + { "Sound/Inspire/ev_t0_04_EN.cpk", 1 }, + { "Sound/Inspire/ev_t0_04_EN.csb", 1 }, + { "Sound/Inspire/ev_t0_04_JP.cpk", 1 }, + { "Sound/Inspire/ev_t0_04_JP.csb", 1 }, + { "Sound/Inspire/m0_06_bgm.cpk", 1 }, + { "Sound/Inspire/m0_06_bgm.csb", 1 }, + { "Sound/Inspire/m1_01_bgm.cpk", 1 }, + { "Sound/Inspire/m1_01_bgm.csb", 1 }, + { "Sound/Inspire/m1_02_bgm.cpk", 1 }, + { "Sound/Inspire/m1_02_bgm.csb", 1 }, + { "Sound/Inspire/m1_03_1_bgm.cpk", 1 }, + { "Sound/Inspire/m1_03_1_bgm.csb", 1 }, + { "Sound/Inspire/m1_03_2_bgm.cpk", 1 }, + { "Sound/Inspire/m1_03_2_bgm.csb", 1 }, + { "Sound/Inspire/m2_02_bgm.cpk", 1 }, + { "Sound/Inspire/m2_02_bgm.csb", 1 }, + { "Sound/Inspire/m2_03_bgm.cpk", 1 }, + { "Sound/Inspire/m2_03_bgm.csb", 1 }, + { "Sound/Inspire/m3_01_bgm.cpk", 1 }, + { "Sound/Inspire/m3_01_bgm.csb", 1 }, + { "Sound/Inspire/m3_02_bgm.cpk", 1 }, + { "Sound/Inspire/m3_02_bgm.csb", 1 }, + { "Sound/Inspire/m3_03_bgm.cpk", 1 }, + { "Sound/Inspire/m3_03_bgm.csb", 1 }, + { "Sound/Inspire/m3_05_bgm.cpk", 1 }, + { "Sound/Inspire/m3_05_bgm.csb", 1 }, + { "Sound/Inspire/m4_01_bgm.cpk", 1 }, + { "Sound/Inspire/m4_01_bgm.csb", 1 }, + { "Sound/Inspire/m5_01_bgm.cpk", 1 }, + { "Sound/Inspire/m5_01_bgm.csb", 1 }, + { "Sound/Inspire/m5_02_bgm.cpk", 1 }, + { "Sound/Inspire/m5_02_bgm.csb", 1 }, + { "Sound/Inspire/m6_01_bgm.cpk", 1 }, + { "Sound/Inspire/m6_01_bgm.csb", 1 }, + { "Sound/Inspire/m6_02_bgm.cpk", 1 }, + { "Sound/Inspire/m6_02_bgm.csb", 1 }, + { "Sound/Inspire/m6_03_bgm.cpk", 1 }, + { "Sound/Inspire/m6_03_bgm.csb", 1 }, + { "Sound/Inspire/m7_01_bgm.cpk", 1 }, + { "Sound/Inspire/m7_01_bgm.csb", 1 }, + { "Sound/Inspire/m7_02_bgm.cpk", 1 }, + { "Sound/Inspire/m7_02_bgm.csb", 1 }, + { "Sound/Inspire/m7_04_bgm.cpk", 1 }, + { "Sound/Inspire/m7_04_bgm.csb", 1 }, + { "Sound/Inspire/m8_02_bgm.cpk", 1 }, + { "Sound/Inspire/m8_02_bgm.csb", 1 }, + { "Sound/Inspire/m8_03_bgm.cpk", 1 }, + { "Sound/Inspire/m8_03_bgm.csb", 1 }, + { "Sound/Inspire/m8_06_2_bgm.cpk", 1 }, + { "Sound/Inspire/m8_06_2_bgm.csb", 1 }, + { "Sound/Inspire/m8_08_bgm.cpk", 1 }, + { "Sound/Inspire/m8_08_bgm.csb", 1 }, + { "Sound/Inspire/m8_09_bgm.cpk", 1 }, + { "Sound/Inspire/m8_09_bgm.csb", 1 }, + { "Sound/Inspire/m8_11_3_bgm.cpk", 1 }, + { "Sound/Inspire/m8_11_3_bgm.csb", 1 }, + { "Sound/Inspire/m8_12_bgm.cpk", 1 }, + { "Sound/Inspire/m8_12_bgm.csb", 1 }, + { "Sound/Inspire/m8_14_bgm.cpk", 1 }, + { "Sound/Inspire/m8_14_bgm.csb", 1 }, + { "Sound/Inspire/m8_15_bgm.cpk", 1 }, + { "Sound/Inspire/m8_15_bgm.csb", 1 }, + { "Sound/Inspire/m8_16_bgm.cpk", 1 }, + { "Sound/Inspire/m8_16_bgm.csb", 1 }, + { "Sound/Inspire/s1_05_bgm.cpk", 1 }, + { "Sound/Inspire/s1_05_bgm.csb", 1 }, + { "Sound/Inspire/s1_06_bgm.cpk", 1 }, + { "Sound/Inspire/s1_06_bgm.csb", 1 }, + { "Sound/Inspire/s2_03_bgm.cpk", 1 }, + { "Sound/Inspire/s2_03_bgm.csb", 1 }, + { "Sound/Inspire/s2_04_bgm.cpk", 1 }, + { "Sound/Inspire/s2_04_bgm.csb", 1 }, + { "Sound/Inspire/s3_04_bgm.cpk", 1 }, + { "Sound/Inspire/s3_04_bgm.csb", 1 }, + { "Sound/Inspire/t0_01_bgm.cpk", 1 }, + { "Sound/Inspire/t0_01_bgm.csb", 1 }, + { "Sound/Inspire/t0_02_bgm.cpk", 1 }, + { "Sound/Inspire/t0_02_bgm.csb", 1 }, + { "Sound/Inspire/t0_04_bgm.cpk", 1 }, + { "Sound/Inspire/t0_04_bgm.csb", 1 }, + { "Sound/bgm_boss_day.csb", 1 }, + { "Sound/bgm_boss_last1_air.csb", 1 }, + { "Sound/bgm_boss_last1_run.csb", 1 }, + { "Sound/bgm_boss_last2.csb", 1 }, + { "Sound/bgm_boss_night.csb", 1 }, + { "Sound/bgm_boss_night_egg.csb", 1 }, + { "Sound/bgm_jingle_bossclear.cpk", 1 }, + { "Sound/bgm_jingle_bossclear.csb", 1 }, + { "Sound/bgm_jingle_stgclear.cpk", 1 }, + { "Sound/bgm_jingle_stgclear.csb", 1 }, + { "Sound/bgm_planet_restored.cpk", 1 }, + { "Sound/bgm_planet_restored.csb", 1 }, + { "Sound/bgm_stg_afr.csb", 1 }, + { "Sound/bgm_stg_chn.csb", 1 }, + { "Sound/bgm_stg_e_afr.csb", 1 }, + { "Sound/bgm_stg_e_afr_jingle.csb", 1 }, + { "Sound/bgm_stg_e_btl.cpk", 1 }, + { "Sound/bgm_stg_e_btl.csb", 1 }, + { "Sound/bgm_stg_e_btl_boss.cpk", 1 }, + { "Sound/bgm_stg_e_btl_boss.csb", 1 }, + { "Sound/bgm_stg_e_chn.csb", 1 }, + { "Sound/bgm_stg_e_chn_jingle.csb", 1 }, + { "Sound/bgm_stg_e_egb.csb", 1 }, + { "Sound/bgm_stg_e_euc.csb", 1 }, + { "Sound/bgm_stg_e_euc_jingle.csb", 1 }, + { "Sound/bgm_stg_e_myk.csb", 1 }, + { "Sound/bgm_stg_e_myk_jingle.csb", 1 }, + { "Sound/bgm_stg_e_nyc.csb", 1 }, + { "Sound/bgm_stg_e_nyc_jingle.csb", 1 }, + { "Sound/bgm_stg_e_ptr.csb", 1 }, + { "Sound/bgm_stg_e_ptr_jingle.csb", 1 }, + { "Sound/bgm_stg_e_sea.csb", 1 }, + { "Sound/bgm_stg_e_sea_jingle.csb", 1 }, + { "Sound/bgm_stg_e_snw.csb", 1 }, + { "Sound/bgm_stg_e_snw_jingle.csb", 1 }, + { "Sound/bgm_stg_egb.csb", 1 }, + { "Sound/bgm_stg_euc.csb", 1 }, + { "Sound/bgm_stg_myk.csb", 1 }, + { "Sound/bgm_stg_myk_act1.csb", 1 }, + { "Sound/bgm_stg_nyc.csb", 1 }, + { "Sound/bgm_stg_ptr.csb", 1 }, + { "Sound/bgm_stg_sea.csb", 1 }, + { "Sound/bgm_stg_snw.csb", 1 }, + { "Sound/bgm_stg_tls1.csb", 1 }, + { "Sound/bgm_stg_tls2.csb", 1 }, + { "Sound/bgm_sys_ending.cpk", 1 }, + { "Sound/bgm_sys_ending.csb", 1 }, + { "Sound/bgm_sys_media.csb", 1 }, + { "Sound/bgm_sys_mediaroom.csb", 1 }, + { "Sound/bgm_sys_menu.csb", 1 }, + { "Sound/bgm_sys_opmovie1.cpk", 1 }, + { "Sound/bgm_sys_opmovie1.csb", 1 }, + { "Sound/bgm_sys_opmovie2.cpk", 1 }, + { "Sound/bgm_sys_opmovie2.csb", 1 }, + { "Sound/bgm_sys_result.cpk", 1 }, + { "Sound/bgm_sys_result.csb", 1 }, + { "Sound/bgm_sys_result_ng.cpk", 1 }, + { "Sound/bgm_sys_result_ng.csb", 1 }, + { "Sound/bgm_sys_title.csb", 1 }, + { "Sound/bgm_sys_vocal.cpk", 1 }, + { "Sound/bgm_sys_vocal.csb", 1 }, + { "Sound/bgm_sys_world.cpk", 1 }, + { "Sound/bgm_sys_world.csb", 1 }, + { "Sound/bgm_sys_worldmap.csb", 1 }, + { "Sound/bgm_twn_afr_day.csb", 1 }, + { "Sound/bgm_twn_afr_night.csb", 1 }, + { "Sound/bgm_twn_chn_day.csb", 1 }, + { "Sound/bgm_twn_chn_night.csb", 1 }, + { "Sound/bgm_twn_egb.csb", 1 }, + { "Sound/bgm_twn_euc_day.csb", 1 }, + { "Sound/bgm_twn_euc_night.csb", 1 }, + { "Sound/bgm_twn_myk_day.csb", 1 }, + { "Sound/bgm_twn_myk_night.csb", 1 }, + { "Sound/bgm_twn_nyc_day.csb", 1 }, + { "Sound/bgm_twn_nyc_night.csb", 1 }, + { "Sound/bgm_twn_ptr_day.csb", 1 }, + { "Sound/bgm_twn_ptr_night.csb", 1 }, + { "Sound/bgm_twn_sea_day.csb", 1 }, + { "Sound/bgm_twn_sea_night.csb", 1 }, + { "Sound/bgm_twn_snw_day.csb", 1 }, + { "Sound/bgm_twn_snw_night.csb", 1 }, + { "Sound/vs_boss_chip_e.cpk", 1 }, + { "Sound/vs_boss_chip_e.csb", 1 }, + { "Sound/vs_boss_chip_j.cpk", 1 }, + { "Sound/vs_boss_chip_j.csb", 1 }, + { "Sound/vs_boss_eggman_robo_e.cpk", 1 }, + { "Sound/vs_boss_eggman_robo_e.csb", 1 }, + { "Sound/vs_boss_eggman_robo_j.cpk", 1 }, + { "Sound/vs_boss_eggman_robo_j.csb", 1 }, + { "Sound/vs_boss_evil_e.cpk", 1 }, + { "Sound/vs_boss_evil_e.csb", 1 }, + { "Sound/vs_boss_evil_j.cpk", 1 }, + { "Sound/vs_boss_evil_j.csb", 1 }, + { "Sound/vs_boss_sonic_e.cpk", 1 }, + { "Sound/vs_boss_sonic_e.csb", 1 }, + { "Sound/vs_boss_sonic_j.cpk", 1 }, + { "Sound/vs_boss_sonic_j.csb", 1 }, + { "Sound/vs_result_evil_e.cpk", 1 }, + { "Sound/vs_result_evil_e.csb", 1 }, + { "Sound/vs_result_evil_j.cpk", 1 }, + { "Sound/vs_result_evil_j.csb", 1 }, + { "Sound/vs_result_sonic_e.cpk", 1 }, + { "Sound/vs_result_sonic_e.csb", 1 }, + { "Sound/vs_result_sonic_j.cpk", 1 }, + { "Sound/vs_result_sonic_j.csb", 1 }, + { "StaffRoll.ar.00", 2 }, + { "StaffRoll.arl", 2 }, + { "SuperSonic.ar.00", 2 }, + { "SuperSonic.arl", 2 }, + { "SystemCommon.ar.00", 2 }, + { "SystemCommon.arl", 2 }, + { "SystemCommonCore.ar.00", 2 }, + { "SystemCommonCore.arl", 2 }, + { "Title.ar.00", 2 }, + { "Title.arl", 2 }, + { "TitleE3.ar.00", 2 }, + { "TitleE3.arl", 2 }, + { "TitleModel.ar.00", 2 }, + { "TitleModel.ar.01", 2 }, + { "TitleModel.ar.02", 2 }, + { "TitleModel.arl", 2 }, + { "Town_Africa.ar.00", 2 }, + { "Town_Africa.arl", 2 }, + { "Town_AfricaETF.ar.00", 2 }, + { "Town_AfricaETF.arl", 2 }, + { "Town_AfricaETF_Common.ar.00", 2 }, + { "Town_AfricaETF_Common.arl", 2 }, + { "Town_AfricaETF_Night.ar.00", 2 }, + { "Town_AfricaETF_Night.arl", 2 }, + { "Town_Africa_Common.ar.00", 2 }, + { "Town_Africa_Common.ar.01", 2 }, + { "Town_Africa_Common.arl", 2 }, + { "Town_Africa_Dispel.ar.00", 2 }, + { "Town_Africa_Dispel.arl", 2 }, + { "Town_Africa_Night.ar.00", 2 }, + { "Town_Africa_Night.arl", 2 }, + { "Town_China.ar.00", 2 }, + { "Town_China.arl", 2 }, + { "Town_ChinaETF.ar.00", 2 }, + { "Town_ChinaETF.arl", 2 }, + { "Town_ChinaETF_Common.ar.00", 2 }, + { "Town_ChinaETF_Common.ar.01", 2 }, + { "Town_ChinaETF_Common.ar.02", 2 }, + { "Town_ChinaETF_Common.arl", 2 }, + { "Town_ChinaETF_Night.ar.00", 2 }, + { "Town_ChinaETF_Night.arl", 2 }, + { "Town_China_Common.ar.00", 2 }, + { "Town_China_Common.ar.01", 2 }, + { "Town_China_Common.ar.02", 2 }, + { "Town_China_Common.arl", 2 }, + { "Town_China_Dispel.ar.00", 2 }, + { "Town_China_Dispel.arl", 2 }, + { "Town_China_Night.ar.00", 2 }, + { "Town_China_Night.arl", 2 }, + { "Town_Common.ar.00", 2 }, + { "Town_Common.ar.01", 2 }, + { "Town_Common.arl", 2 }, + { "Town_EULabo.ar.00", 2 }, + { "Town_EULabo.arl", 2 }, + { "Town_EULabo_Common.ar.00", 2 }, + { "Town_EULabo_Common.ar.01", 2 }, + { "Town_EULabo_Common.arl", 2 }, + { "Town_EULabo_Night.ar.00", 2 }, + { "Town_EULabo_Night.arl", 2 }, + { "Town_EggManBase.ar.00", 2 }, + { "Town_EggManBase.ar.01", 2 }, + { "Town_EggManBase.arl", 2 }, + { "Town_EggManBase_Common.ar.00", 2 }, + { "Town_EggManBase_Common.ar.01", 2 }, + { "Town_EggManBase_Common.arl", 2 }, + { "Town_EuropeanCity.ar.00", 2 }, + { "Town_EuropeanCity.arl", 2 }, + { "Town_EuropeanCityETF.ar.00", 2 }, + { "Town_EuropeanCityETF.ar.01", 2 }, + { "Town_EuropeanCityETF.arl", 2 }, + { "Town_EuropeanCityETF_Common.ar.00", 2 }, + { "Town_EuropeanCityETF_Common.ar.01", 2 }, + { "Town_EuropeanCityETF_Common.ar.02", 2 }, + { "Town_EuropeanCityETF_Common.arl", 2 }, + { "Town_EuropeanCityETF_Night.ar.00", 2 }, + { "Town_EuropeanCityETF_Night.arl", 2 }, + { "Town_EuropeanCity_Common.ar.00", 4 }, + { "Town_EuropeanCity_Common.ar.01", 2 }, + { "Town_EuropeanCity_Common.ar.02", 2 }, + { "Town_EuropeanCity_Common.ar.03", 2 }, + { "Town_EuropeanCity_Common.arl", 2 }, + { "Town_EuropeanCity_Dispel.ar.00", 2 }, + { "Town_EuropeanCity_Dispel.arl", 2 }, + { "Town_EuropeanCity_Night.ar.00", 2 }, + { "Town_EuropeanCity_Night.arl", 2 }, + { "Town_Labo_Common.ar.00", 2 }, + { "Town_Labo_Common.ar.01", 2 }, + { "Town_Labo_Common.ar.02", 2 }, + { "Town_Labo_Common.ar.03", 2 }, + { "Town_Labo_Common.ar.04", 2 }, + { "Town_Labo_Common.arl", 2 }, + { "Town_Mykonos.ar.00", 2 }, + { "Town_Mykonos.arl", 2 }, + { "Town_MykonosETF.ar.00", 2 }, + { "Town_MykonosETF.arl", 2 }, + { "Town_MykonosETF_Common.ar.00", 2 }, + { "Town_MykonosETF_Common.ar.01", 2 }, + { "Town_MykonosETF_Common.arl", 2 }, + { "Town_MykonosETF_Night.ar.00", 2 }, + { "Town_MykonosETF_Night.arl", 2 }, + { "Town_Mykonos_Common.ar.00", 4 }, + { "Town_Mykonos_Common.ar.01", 2 }, + { "Town_Mykonos_Common.ar.02", 2 }, + { "Town_Mykonos_Common.arl", 2 }, + { "Town_Mykonos_Dispel.ar.00", 2 }, + { "Town_Mykonos_Dispel.arl", 2 }, + { "Town_Mykonos_Night.ar.00", 2 }, + { "Town_Mykonos_Night.arl", 2 }, + { "Town_NYCity.ar.00", 2 }, + { "Town_NYCity.arl", 2 }, + { "Town_NYCityETF.ar.00", 2 }, + { "Town_NYCityETF.arl", 2 }, + { "Town_NYCityETF_Common.ar.00", 2 }, + { "Town_NYCityETF_Common.ar.01", 2 }, + { "Town_NYCityETF_Common.ar.02", 2 }, + { "Town_NYCityETF_Common.arl", 2 }, + { "Town_NYCityETF_Night.ar.00", 2 }, + { "Town_NYCityETF_Night.arl", 2 }, + { "Town_NYCity_Common.ar.00", 4 }, + { "Town_NYCity_Common.ar.01", 2 }, + { "Town_NYCity_Common.arl", 2 }, + { "Town_NYCity_Dispel.ar.00", 2 }, + { "Town_NYCity_Dispel.arl", 2 }, + { "Town_NYCity_Night.ar.00", 2 }, + { "Town_NYCity_Night.arl", 2 }, + { "Town_PetraCapital.ar.00", 2 }, + { "Town_PetraCapital.arl", 2 }, + { "Town_PetraCapitalETF.ar.00", 2 }, + { "Town_PetraCapitalETF.arl", 2 }, + { "Town_PetraCapitalETF_Common.ar.00", 2 }, + { "Town_PetraCapitalETF_Common.arl", 2 }, + { "Town_PetraCapitalETF_Night.ar.00", 2 }, + { "Town_PetraCapitalETF_Night.arl", 2 }, + { "Town_PetraCapital_Common.ar.00", 2 }, + { "Town_PetraCapital_Common.ar.01", 2 }, + { "Town_PetraCapital_Common.ar.02", 2 }, + { "Town_PetraCapital_Common.arl", 2 }, + { "Town_PetraCapital_Dispel.ar.00", 2 }, + { "Town_PetraCapital_Dispel.arl", 2 }, + { "Town_PetraCapital_Night.ar.00", 2 }, + { "Town_PetraCapital_Night.arl", 2 }, + { "Town_PetraLabo.ar.00", 2 }, + { "Town_PetraLabo.arl", 2 }, + { "Town_PetraLabo_Common.ar.00", 2 }, + { "Town_PetraLabo_Common.ar.01", 2 }, + { "Town_PetraLabo_Common.arl", 2 }, + { "Town_PetraLabo_Night.ar.00", 2 }, + { "Town_PetraLabo_Night.arl", 2 }, + { "Town_Snow.ar.00", 2 }, + { "Town_Snow.arl", 2 }, + { "Town_SnowETF.ar.00", 2 }, + { "Town_SnowETF.arl", 2 }, + { "Town_SnowETF_Common.ar.00", 2 }, + { "Town_SnowETF_Common.arl", 2 }, + { "Town_SnowETF_Night.ar.00", 2 }, + { "Town_SnowETF_Night.arl", 2 }, + { "Town_Snow_Common.ar.00", 2 }, + { "Town_Snow_Common.ar.01", 2 }, + { "Town_Snow_Common.arl", 2 }, + { "Town_Snow_Dispel.ar.00", 2 }, + { "Town_Snow_Dispel.arl", 2 }, + { "Town_Snow_Night.ar.00", 2 }, + { "Town_Snow_Night.arl", 2 }, + { "Town_SouthEastAsia.ar.00", 2 }, + { "Town_SouthEastAsia.arl", 2 }, + { "Town_SouthEastAsiaETF.ar.00", 2 }, + { "Town_SouthEastAsiaETF.arl", 2 }, + { "Town_SouthEastAsiaETF_Common.ar.00", 2 }, + { "Town_SouthEastAsiaETF_Common.ar.01", 2 }, + { "Town_SouthEastAsiaETF_Common.ar.02", 2 }, + { "Town_SouthEastAsiaETF_Common.arl", 2 }, + { "Town_SouthEastAsiaETF_Night.ar.00", 2 }, + { "Town_SouthEastAsiaETF_Night.arl", 2 }, + { "Town_SouthEastAsia_Common.ar.00", 4 }, + { "Town_SouthEastAsia_Common.ar.01", 2 }, + { "Town_SouthEastAsia_Common.arl", 2 }, + { "Town_SouthEastAsia_Dispel.ar.00", 2 }, + { "Town_SouthEastAsia_Dispel.arl", 2 }, + { "Town_SouthEastAsia_Night.ar.00", 2 }, + { "Town_SouthEastAsia_Night.arl", 2 }, + { "WorldMap.ar.00", 2 }, + { "WorldMap.arl", 2 }, + { "default.xex", 3 }, + { "movie/CHN.sfd", 1 }, + { "movie/HedgehogEngine_logo.sfd", 1 }, + { "movie/Inspire/ex00_movie.sfd", 1 }, + { "movie/Inspire/ex01_movie.sfd", 1 }, + { "movie/Inspire/m2_02_monitor_roop.sfd", 1 }, + { "movie/Inspire/m3_05_monitor_1shot.sfd", 1 }, + { "movie/Inspire/m3_05_movie.sfd", 1 }, + { "movie/Inspire/m4_01_monitor_1shot.sfd", 1 }, + { "movie/Inspire/m4_01_monitor_roop.sfd", 1 }, + { "movie/Inspire/m4_01_movie01.sfd", 1 }, + { "movie/Inspire/m4_01_movie02.sfd", 1 }, + { "movie/Inspire/m5_02_monitor_1shot_a.sfd", 1 }, + { "movie/Inspire/m5_02_monitor_1shot_b.sfd", 1 }, + { "movie/Inspire/m5_02_monitor_1shot_c.sfd", 1 }, + { "movie/Inspire/m8_01_monitor_1shot.sfd", 1 }, + { "movie/Inspire/m8_01_movie.sfd", 1 }, + { "movie/SEA.sfd", 1 }, + { "movie/SNW_gooON.sfd", 1 }, + { "movie/evmo_m0_01_05_OPN_cs.sfd", 1 }, + { "movie/evmo_m3_04_CTF_hd.sfd", 1 }, + { "movie/evmo_m7_03_CTL_hd.sfd", 1 }, + { "movie/evmo_m8_04_DGA_hd.sfd", 1 }, + { "movie/evmo_m8_05_TGS_hd.sfd", 1 }, + { "movie/evmo_m8_06_1_TGU_hd.sfd", 1 }, + { "movie/evmo_m8_10_DGB_hd.sfd", 1 }, + { "movie/evmo_m8_11_2_DGV_hd.sfd", 1 }, + { "movie/evmo_title_loop.sfd", 1 }, + { "movie/evmo_title_loop_jp.sfd", 1 }, + { "movie/evmo_transform0_s2e_00.sfd", 1 }, + { "movie/evmo_transform0_s2e_01.sfd", 1 }, + { "movie/evmo_transform1_e2s_00.sfd", 1 }, + { "movie/evmo_transform1_e2s_01.sfd", 1 }, + { "movie/evrt_m8_08.sfd", 1 }, + { "movie/evrt_m8_12.sfd", 1 }, + { "movie/sega_logo_jp.sfd", 1 }, + { "movie/sega_logo_us.sfd", 1 }, + { "reddog/button_close_1.dds", 2 }, + { "reddog/button_close_2.dds", 2 }, + { "reddog/button_minimum_1.dds", 2 }, + { "reddog/button_minimum_2.dds", 2 }, + { "reddog/button_pin_1.dds", 2 }, + { "reddog/button_pin_2.dds", 2 }, + { "reddog/checkbox_1.dds", 2 }, + { "reddog/checkbox_2.dds", 2 }, + { "reddog/common_arrow_1.dds", 2 }, + { "reddog/common_arrow_2.dds", 2 }, + { "reddog/common_button_1.dds", 2 }, + { "reddog/common_button_2.dds", 2 }, + { "reddog/common_frame.dds", 2 }, + { "reddog/common_frame_bold.dds", 2 }, + { "reddog/common_frame_bold_t.dds", 2 }, + { "reddog/common_frame_t.dds", 2 }, + { "reddog/common_icon.dds", 2 }, + { "reddog/mouse_cursor.dds", 2 }, + { "reddog/mouse_cursor_h.dds", 2 }, + { "reddog/mouse_cursor_slant_l.dds", 2 }, + { "reddog/mouse_cursor_v.dds", 2 }, + { "reddog/scroll_bar_lr.dds", 2 }, + { "reddog/scroll_bar_ud.dds", 2 }, + { "reddog/scroll_button_lr.dds", 2 }, + { "reddog/scroll_button_ud.dds", 2 }, + { "reddog/scroll_lane_lr.dds", 2 }, + { "reddog/scroll_lane_ud.dds", 2 }, + { "reddog/sonic_icon.dds", 2 }, + { "reddog/title_bar.dds", 2 }, + { "reddog/window_frame.dds", 2 }, + { "reddog/window_frame_t.dds", 2 }, + { "shader.ar", 2 }, + { "shader.arl", 2 }, + { "voices/English/EvilSonic.ar.00", 2 }, + { "voices/English/EvilSonic.arl", 2 }, + { "voices/English/ExStageTails_Common.ar.00", 2 }, + { "voices/English/ExStageTails_Common.arl", 2 }, + { "voices/English/Sonic.ar.00", 2 }, + { "voices/English/Sonic.arl", 2 }, + { "voices/English/SystemCommon.ar.00", 2 }, + { "voices/English/SystemCommon.arl", 2 }, + { "voices/English/Town_Common.ar.00", 2 }, + { "voices/English/Town_Common.arl", 2 }, + { "voices/Japanese/EvilSonic.ar.00", 2 }, + { "voices/Japanese/EvilSonic.arl", 2 }, + { "voices/Japanese/ExStageTails_Common.ar.00", 2 }, + { "voices/Japanese/ExStageTails_Common.arl", 2 }, + { "voices/Japanese/Sonic.ar.00", 2 }, + { "voices/Japanese/Sonic.arl", 2 }, + { "voices/Japanese/SystemCommon.ar.00", 2 }, + { "voices/Japanese/SystemCommon.arl", 2 }, + { "voices/Japanese/Town_Common.ar.00", 2 }, + { "voices/Japanese/Town_Common.arl", 2 }, + { "xarialuni.ttf", 1 }, +}; + +const size_t GameFilesSize = std::size(GameFiles); diff --git a/UnleashedRecomp/install/hashes/game.h b/UnleashedRecomp/install/hashes/game.h new file mode 100644 index 00000000..e2ac698d --- /dev/null +++ b/UnleashedRecomp/install/hashes/game.h @@ -0,0 +1,10 @@ +// File automatically generated by fshasher + +#pragma once + +#include + +extern const uint64_t GameHashes[]; +extern const std::pair GameFiles[]; +extern const size_t GameFilesSize; + diff --git a/UnleashedRecomp/install/hashes/holoska.cpp b/UnleashedRecomp/install/hashes/holoska.cpp new file mode 100644 index 00000000..12ca75dd --- /dev/null +++ b/UnleashedRecomp/install/hashes/holoska.cpp @@ -0,0 +1,198 @@ +// File automatically generated by fshasher + +#include + +extern const uint64_t HoloskaHashes[]; +extern const std::pair HoloskaFiles[]; +extern const size_t HoloskaFilesSize; + +const uint64_t HoloskaHashes[] = { + 2675323900039702065ULL, + 4277145918507575318ULL, + 37003434483691695ULL, + 173772618141122105ULL, + 10014684039097108933ULL, + 12951885659934974458ULL, + 5420475312037398025ULL, + 8990457325890346487ULL, + 5828311441007099177ULL, + 15895929894456691275ULL, + 10944334660972947767ULL, + 12306207387774270676ULL, + 1133020226384470961ULL, + 10978642704870093657ULL, + 6571493200930941260ULL, + 12775456849440773110ULL, + 10993350723710351594ULL, + 18266525158058610108ULL, + 5224405159313498915ULL, + 7030149124581670257ULL, + 743509372682842317ULL, + 6268515345337947410ULL, + 621840898472918401ULL, + 7793408857629121219ULL, + 3628810224077277661ULL, + 4735419277840395906ULL, + 6298408288867498004ULL, + 9672923561522739380ULL, + 8577458973002786949ULL, + 8580672557326042084ULL, + 905264783309208510ULL, + 5442721461459141559ULL, + 5665558615477908883ULL, + 9138114750084480028ULL, + 10560390528404575839ULL, + 13571388347857105531ULL, + 759267540240315808ULL, + 1395028858241468056ULL, + 4101501475292075848ULL, + 13453093997934088664ULL, + 16436427612349862673ULL, + 16475130472640188313ULL, + 1009427446083976444ULL, + 6227277608980222296ULL, + 13005423191223021574ULL, + 7227050263030209202ULL, + 9777930758670277699ULL, + 877007860174867856ULL, + 18238103507153996510ULL, + 17930956651100144422ULL, + 9455059678942766083ULL, + 11513193284629003124ULL, + 14582773429927700438ULL, + 7832492987792635365ULL, + 14922683551437897222ULL, + 2218036959448726520ULL, + 5915675802417501794ULL, + 4734985573199693091ULL, + 13894625369955491525ULL, + 10164406532505859673ULL, + 11738098787596070522ULL, + 2506038633852497536ULL, + 3066872557705014675ULL, + 13577051447279183181ULL, + 15995491349078614893ULL, + 7170529702240695373ULL, + 9610481190777925774ULL, + 9843976124448789757ULL, + 15999881082141829716ULL, + 1705967380110975175ULL, + 1945492401042462005ULL, + 12826054609787136918ULL, + 14947608392493777252ULL, + 8454834516025688631ULL, + 16412196874867098033ULL, + 1302335439956347422ULL, + 5904634235948759380ULL, + 837467602803878420ULL, + 11838669303496931932ULL, + 1026342585625625691ULL, + 17104669198514697031ULL, + 6226633771929098644ULL, + 11434391196365401368ULL, + 1825358492785453273ULL, + 10935112159483090915ULL, + 10368247242044046510ULL, + 5360854891214543592ULL, + 9184741739495532010ULL, + 1210820029035423219ULL, + 3779694736357686174ULL, + 11026144482164398929ULL, + 17624209453030784775ULL, + 1268371966612623612ULL, + 17620869642251638393ULL, + 7500432003580343090ULL, + 8925351885022805937ULL, + 4545712040089568182ULL, + 16087391183543862251ULL, + 7153771647341077160ULL, + 15835374550237816233ULL, + 10806012310881440072ULL, + 14061367079592692873ULL, + 16856865969950237558ULL, + 16918398385542560356ULL, + 7838032685469261389ULL, + 14087988214801845031ULL, + 287254560976480823ULL, + 4291829565728637795ULL, + 1833361518702399357ULL, + 9945701995133200218ULL, + 12195458283103638803ULL, + 18193324349862755987ULL, + 3992878524104250195ULL, + 9683778847586532057ULL, + 640455243454193529ULL, + 9845312495153161302ULL, +}; + +const std::pair HoloskaFiles[] = { + { "#ActD_SubSnow_02.ar.00", 2 }, + { "#ActD_SubSnow_02.arl", 2 }, + { "#ActD_SubSnow_03.ar.00", 2 }, + { "#ActD_SubSnow_03.arl", 2 }, + { "#ActD_SubSnow_04.ar.00", 2 }, + { "#ActD_SubSnow_04.arl", 2 }, + { "#ActD_SubSnow_05.ar.00", 2 }, + { "#ActD_SubSnow_05.arl", 2 }, + { "#ActN_SubSnow_01.ar.00", 2 }, + { "#ActN_SubSnow_01.arl", 2 }, + { "#ActN_SubSnow_02.ar.00", 2 }, + { "#ActN_SubSnow_02.arl", 2 }, + { "#Application.ar.00", 2 }, + { "#Application.arl", 2 }, + { "ActD_SubSnow_02.ar.00", 2 }, + { "ActD_SubSnow_02.arl", 2 }, + { "ActD_SubSnow_03.ar.00", 2 }, + { "ActD_SubSnow_03.arl", 2 }, + { "ActN_SubSnow_01.ar.00", 2 }, + { "ActN_SubSnow_01.arl", 2 }, + { "ActN_SubSnow_02.ar.00", 2 }, + { "ActN_SubSnow_02.arl", 2 }, + { "Additional/ActD_Snow/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubSnow_01/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubSnow_02/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubSnow_03/Stage-Add.pfd", 1 }, + { "Additional/ActN_SnowEvil/Stage-Add.pfd", 1 }, + { "Additional/ActN_SubSnow_01/Stage-Add.pfd", 1 }, + { "Additional/ActN_SubSnow_02/Stage-Add.pfd", 1 }, + { "Additional/BossDarkGaiaMoray/Stage-Add.pfd", 1 }, + { "Additional/Town_Snow/Stage-Add.pfd", 1 }, + { "Additional/Town_SnowETF/Stage-Add.pfd", 1 }, + { "Additional/Town_SnowETF_Night/Stage-Add.pfd", 1 }, + { "Additional/Town_Snow_Night/Stage-Add.pfd", 1 }, + { "DLC.xml", 1 }, + { "Languages/English/WorldMap.ar.00", 2 }, + { "Languages/English/WorldMap.arl", 2 }, + { "Languages/French/WorldMap.ar.00", 2 }, + { "Languages/French/WorldMap.arl", 2 }, + { "Languages/German/WorldMap.ar.00", 2 }, + { "Languages/German/WorldMap.arl", 2 }, + { "Languages/Italian/WorldMap.ar.00", 2 }, + { "Languages/Italian/WorldMap.arl", 2 }, + { "Languages/Japanese/WorldMap.ar.00", 2 }, + { "Languages/Japanese/WorldMap.arl", 2 }, + { "Languages/Spanish/WorldMap.ar.00", 2 }, + { "Languages/Spanish/WorldMap.arl", 2 }, + { "Packed/ActD_SubSnow_02/Stage.pfd", 1 }, + { "Packed/ActD_SubSnow_03/Stage.pfd", 1 }, + { "Packed/ActN_SubSnow_01/Stage.pfd", 1 }, + { "Packed/ActN_SubSnow_02/Stage.pfd", 1 }, + { "Snow.dmy", 1 }, + { "WorldMap.ar.00", 2 }, + { "WorldMap.arl", 2 }, + { "work/ActD_Snow/Terrain.prm.xml", 2 }, + { "work/ActD_SubSnow_01/Terrain.prm.xml", 2 }, + { "work/ActN_SnowEvil/Terrain.prm.xml", 2 }, + { "work/SystemCommon/SR_EnterSnowDayActionSub02.seq.xml", 2 }, + { "work/SystemCommon/SR_EnterSnowDayActionSub03.seq.xml", 2 }, + { "work/SystemCommon/SR_EnterSnowDayActionSub04.seq.xml", 2 }, + { "work/SystemCommon/SR_EnterSnowDayActionSub05.seq.xml", 2 }, + { "work/SystemCommon/SR_EnterSnowNightActionSub01.seq.xml", 2 }, + { "work/SystemCommon/SR_EnterSnowNightActionSub02.seq.xml", 2 }, + { "work/Town_Snow/Terrain.prm.xml", 2 }, + { "work/Town_SnowETF/Terrain.prm.xml", 2 }, + { "work/Town_SnowETF_Night/Terrain.prm.xml", 2 }, + { "work/Town_Snow_Night/Terrain.prm.xml", 2 }, +}; + +const size_t HoloskaFilesSize = std::size(HoloskaFiles); diff --git a/UnleashedRecomp/install/hashes/holoska.h b/UnleashedRecomp/install/hashes/holoska.h new file mode 100644 index 00000000..1d61232b --- /dev/null +++ b/UnleashedRecomp/install/hashes/holoska.h @@ -0,0 +1,10 @@ +// File automatically generated by fshasher + +#pragma once + +#include + +extern const uint64_t HoloskaHashes[]; +extern const std::pair HoloskaFiles[]; +extern const size_t HoloskaFilesSize; + diff --git a/UnleashedRecomp/install/hashes/mazuri.cpp b/UnleashedRecomp/install/hashes/mazuri.cpp new file mode 100644 index 00000000..ad80de61 --- /dev/null +++ b/UnleashedRecomp/install/hashes/mazuri.cpp @@ -0,0 +1,207 @@ +// File automatically generated by fshasher + +#include + +extern const uint64_t MazuriHashes[]; +extern const std::pair MazuriFiles[]; +extern const size_t MazuriFilesSize; + +const uint64_t MazuriHashes[] = { + 8310122492208490409ULL, + 14334946716403322379ULL, + 6359932846637962320ULL, + 15564392554394963521ULL, + 4145580004644844748ULL, + 5886649247807377109ULL, + 8972853618768766550ULL, + 16274784949553698740ULL, + 7644922894813285241ULL, + 16792340405196435317ULL, + 7219363224850733712ULL, + 14783821508665540659ULL, + 90578118658326728ULL, + 322485799435034401ULL, + 11426516458306753692ULL, + 16875540838976300804ULL, + 691543308196576824ULL, + 12748185913217986160ULL, + 181497269294558465ULL, + 13384184373605717208ULL, + 9680733245723597610ULL, + 11319512019915225753ULL, + 5156260857743175296ULL, + 17024263853193085482ULL, + 9161916068418754052ULL, + 15099371411684664534ULL, + 8811039586506246550ULL, + 13344975442165302144ULL, + 11616101478448229001ULL, + 16890442647900693500ULL, + 10613805266180977971ULL, + 12232891231073729485ULL, + 5827659615582798219ULL, + 10044950643067304005ULL, + 10405571379268351804ULL, + 17852400551605150551ULL, + 8485124434733981977ULL, + 12177189339342254810ULL, + 6914067631133882133ULL, + 8516330542230824299ULL, + 5227234300746783898ULL, + 11316739451124421549ULL, + 4006017088443300321ULL, + 8144466479720785800ULL, + 14807147190400377590ULL, + 17032461497328235598ULL, + 3485364854384528759ULL, + 12314750532364104301ULL, + 18171772732457610158ULL, + 15511223977167516261ULL, + 3733997387449100578ULL, + 3127614471276641962ULL, + 16473237911443301576ULL, + 8519032476298984207ULL, + 1282659255712538566ULL, + 9032400057270978659ULL, + 1438891209736948095ULL, + 9445272093697834862ULL, + 17042589027198683899ULL, + 17834939632591927531ULL, + 17963312833258248676ULL, + 11212796985379953935ULL, + 8520618928746918706ULL, + 12620044629892189723ULL, + 17231920840550500769ULL, + 14751571373966723331ULL, + 15192962011256471386ULL, + 5641128099468064081ULL, + 15353897587627765076ULL, + 9694642992346267925ULL, + 12849306083654146943ULL, + 12611788236218891748ULL, + 13815021343500055451ULL, + 17210166018872705038ULL, + 17856279508890497700ULL, + 15236163838001295487ULL, + 15463039469068597027ULL, + 3188082504873605346ULL, + 10762266561438768212ULL, + 842630621715284677ULL, + 1961824913476492580ULL, + 5152443868555296771ULL, + 10324715709102329399ULL, + 1763695362403970051ULL, + 3584532033227831137ULL, + 5851561062160893814ULL, + 10927370304760079285ULL, + 13011799481510971519ULL, + 17677776816961090167ULL, + 13923999678594617040ULL, + 5360854891214543592ULL, + 9184741739495532010ULL, + 1210820029035423219ULL, + 3779694736357686174ULL, + 45507338756965322ULL, + 17034560519917147503ULL, + 615638415508415245ULL, + 12821211946029354361ULL, + 173839052608557733ULL, + 6298694170641867436ULL, + 12773486509288875531ULL, + 12866025506444541977ULL, + 3427216651702511068ULL, + 8503894857294129869ULL, + 8658756214229842885ULL, + 12517977842558558441ULL, + 8772357560481233720ULL, + 9298201679300251287ULL, + 1413776131937655221ULL, + 16241630498833235183ULL, + 3107620193063708762ULL, + 18350383620420541255ULL, + 108006630585092978ULL, + 171415973667919914ULL, + 1817978790908311521ULL, + 7165219417836909758ULL, + 5462363977947174456ULL, + 8840489652156575872ULL, + 10345266752933627695ULL, + 15321193045322335042ULL, + 471637519459967124ULL, + 6817966383869009387ULL, +}; + +const std::pair MazuriFiles[] = { + { "#ActD_SubAfrica_02.ar.00", 2 }, + { "#ActD_SubAfrica_02.arl", 2 }, + { "#ActD_SubAfrica_04.ar.00", 2 }, + { "#ActD_SubAfrica_04.arl", 2 }, + { "#ActD_SubAfrica_05.ar.00", 2 }, + { "#ActD_SubAfrica_05.arl", 2 }, + { "#ActD_SubAfrica_06.ar.00", 2 }, + { "#ActD_SubAfrica_06.arl", 2 }, + { "#ActN_SubAfrica_02.ar.00", 2 }, + { "#ActN_SubAfrica_02.arl", 2 }, + { "#ActN_SubAfrica_03.ar.00", 2 }, + { "#ActN_SubAfrica_03.arl", 2 }, + { "#Application.ar.00", 2 }, + { "#Application.arl", 2 }, + { "ActD_SubAfrica_02.ar.00", 2 }, + { "ActD_SubAfrica_02.ar.01", 2 }, + { "ActD_SubAfrica_02.arl", 2 }, + { "ActD_SubAfrica_06.ar.00", 2 }, + { "ActD_SubAfrica_06.arl", 2 }, + { "ActN_SubAfrica_02.ar.00", 2 }, + { "ActN_SubAfrica_02.arl", 2 }, + { "ActN_SubAfrica_03.ar.00", 2 }, + { "ActN_SubAfrica_03.ar.01", 2 }, + { "ActN_SubAfrica_03.arl", 2 }, + { "Additional/ActD_Africa/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubAfrica_01/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubAfrica_02/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubAfrica_03/Stage-Add.pfd", 1 }, + { "Additional/ActN_AfricaEvil/Stage-Add.pfd", 1 }, + { "Additional/ActN_SubAfrica_01/Stage-Add.pfd", 1 }, + { "Additional/ActN_SubAfrica_02/Stage-Add.pfd", 1 }, + { "Additional/ActN_SubAfrica_03/Stage-Add.pfd", 1 }, + { "Additional/BossEggBeetle/Stage-Add.pfd", 1 }, + { "Additional/Event_afr_hideout/Stage-Add.pfd", 1 }, + { "Additional/Town_Africa/Stage-Add.pfd", 1 }, + { "Additional/Town_AfricaETF/Stage-Add.pfd", 1 }, + { "Additional/Town_AfricaETF_Night/Stage-Add.pfd", 1 }, + { "Additional/Town_Africa_Night/Stage-Add.pfd", 1 }, + { "DLC.xml", 1 }, + { "Languages/English/WorldMap.ar.00", 2 }, + { "Languages/English/WorldMap.arl", 2 }, + { "Languages/French/WorldMap.ar.00", 2 }, + { "Languages/French/WorldMap.arl", 2 }, + { "Languages/German/WorldMap.ar.00", 2 }, + { "Languages/German/WorldMap.arl", 2 }, + { "Languages/Italian/WorldMap.ar.00", 2 }, + { "Languages/Italian/WorldMap.arl", 2 }, + { "Languages/Japanese/WorldMap.ar.00", 2 }, + { "Languages/Japanese/WorldMap.arl", 2 }, + { "Languages/Spanish/WorldMap.ar.00", 2 }, + { "Languages/Spanish/WorldMap.arl", 2 }, + { "Packed/ActD_SubAfrica_02/Stage.pfd", 1 }, + { "Packed/ActN_SubAfrica_02/Stage.pfd", 1 }, + { "Packed/ActN_SubAfrica_03/Stage.pfd", 1 }, + { "WorldMap.ar.00", 2 }, + { "WorldMap.arl", 2 }, + { "work/ActD_Africa/Terrain.prm.xml", 2 }, + { "work/ActD_SubAfrica_01/Terrain.prm.xml", 2 }, + { "work/ActD_SubAfrica_02/Terrain.prm.xml", 2 }, + { "work/ActD_SubAfrica_03/Terrain.prm.xml", 2 }, + { "work/ActN_AfricaEvil/Terrain.prm.xml", 2 }, + { "work/ActN_SubAfrica_01/Terrain.prm.xml", 2 }, + { "work/ActN_SubAfrica_02/Terrain.prm.xml", 2 }, + { "work/ActN_SubAfrica_03/Terrain.prm.xml", 2 }, + { "work/BossEggBeetle/Terrain.prm.xml", 2 }, + { "work/Event_afr_hideout/Terrain.prm.xml", 2 }, + { "work/Town_Africa/Terrain.prm.xml", 2 }, + { "work/Town_AfricaETF/Terrain.prm.xml", 2 }, + { "work/Town_AfricaETF_Night/Terrain.prm.xml", 2 }, + { "work/Town_Africa_Night/Terrain.prm.xml", 2 }, +}; + +const size_t MazuriFilesSize = std::size(MazuriFiles); diff --git a/UnleashedRecomp/install/hashes/mazuri.h b/UnleashedRecomp/install/hashes/mazuri.h new file mode 100644 index 00000000..a3afdb89 --- /dev/null +++ b/UnleashedRecomp/install/hashes/mazuri.h @@ -0,0 +1,10 @@ +// File automatically generated by fshasher + +#pragma once + +#include + +extern const uint64_t MazuriHashes[]; +extern const std::pair MazuriFiles[]; +extern const size_t MazuriFilesSize; + diff --git a/UnleashedRecomp/install/hashes/spagonia.cpp b/UnleashedRecomp/install/hashes/spagonia.cpp new file mode 100644 index 00000000..12d68112 --- /dev/null +++ b/UnleashedRecomp/install/hashes/spagonia.cpp @@ -0,0 +1,207 @@ +// File automatically generated by fshasher + +#include + +extern const uint64_t SpagoniaHashes[]; +extern const std::pair SpagoniaFiles[]; +extern const size_t SpagoniaFilesSize; + +const uint64_t SpagoniaHashes[] = { + 14867694217129324738ULL, + 17100842773888706873ULL, + 9752656502718674446ULL, + 15671159208413511075ULL, + 1812603898025740639ULL, + 12613450881360770457ULL, + 1154935869782185816ULL, + 8219769246658808506ULL, + 9695895323794780829ULL, + 15823038424497033867ULL, + 5817217669193198611ULL, + 6497441520538379134ULL, + 10139383215379183246ULL, + 13620914181664931155ULL, + 4668974212184368466ULL, + 10500741838109391509ULL, + 647311874653915105ULL, + 7661921675863949967ULL, + 323394983647000743ULL, + 797187618373021610ULL, + 353294754399582215ULL, + 16740492856758014010ULL, + 1952614254672843308ULL, + 2667940006400122486ULL, + 12564343012022085590ULL, + 16154216407056286457ULL, + 6298408288867498004ULL, + 9672923561522739380ULL, + 14834906762895569303ULL, + 16854111345280229225ULL, + 4837640393588267349ULL, + 16098597153130008996ULL, + 12600320757740560262ULL, + 12939475623775993690ULL, + 10477103196696189363ULL, + 12732657904265336737ULL, + 13095277609263620069ULL, + 16750231076154973610ULL, + 2022042165098050912ULL, + 17839881966578661233ULL, + 5534774080348504073ULL, + 14030101124033407301ULL, + 6718729617636463209ULL, + 12440200088588141894ULL, + 6369118057772660528ULL, + 7315135301096821941ULL, + 7602114569538282692ULL, + 11336647640667052949ULL, + 10152111535756487098ULL, + 5265464758157500744ULL, + 5234945774616460434ULL, + 10795075404967515916ULL, + 13538969501315954190ULL, + 17102608468773106653ULL, + 14121317735511216399ULL, + 5157803794135169420ULL, + 7199840892697349122ULL, + 1225096793739555247ULL, + 9128945470099535129ULL, + 4734985573199693091ULL, + 13894625369955491525ULL, + 10164406532505859673ULL, + 11738098787596070522ULL, + 2506038633852497536ULL, + 3066872557705014675ULL, + 13577051447279183181ULL, + 15995491349078614893ULL, + 7170529702240695373ULL, + 9610481190777925774ULL, + 9843976124448789757ULL, + 15999881082141829716ULL, + 1705967380110975175ULL, + 1945492401042462005ULL, + 12826054609787136918ULL, + 14947608392493777252ULL, + 8454834516025688631ULL, + 16412196874867098033ULL, + 1302335439956347422ULL, + 5904634235948759380ULL, + 837467602803878420ULL, + 11838669303496931932ULL, + 1026342585625625691ULL, + 17104669198514697031ULL, + 3709548792784456596ULL, + 16703932146892522057ULL, + 3247313303103704726ULL, + 5360854891214543592ULL, + 9184741739495532010ULL, + 1210820029035423219ULL, + 3779694736357686174ULL, + 1269303531989512502ULL, + 15044160000628794537ULL, + 8716580408330791802ULL, + 16789543858655671716ULL, + 2003346667352944922ULL, + 15313758642971562051ULL, + 2739790431130553532ULL, + 6783670011455890702ULL, + 697852188952975609ULL, + 17185281492289182605ULL, + 5699074391444795502ULL, + 6148412876775458906ULL, + 2511824900179921974ULL, + 9520550565124263974ULL, + 1879590205302053732ULL, + 16445653421013634259ULL, + 163664281434034891ULL, + 14992345757081400517ULL, + 3472557166861866135ULL, + 7070790832398904932ULL, + 14233035291283305411ULL, + 17367771094700951804ULL, + 14233035291283305411ULL, + 17367771094700951804ULL, + 4805103552407476622ULL, + 10627247764815196413ULL, + 4664450768495384140ULL, + 11104978684669875710ULL, + 4664450768495384140ULL, + 11104978684669875710ULL, + 16106838734002406075ULL, + 16965457262918815126ULL, +}; + +const std::pair SpagoniaFiles[] = { + { "#ActD_SubEU_03.ar.00", 2 }, + { "#ActD_SubEU_03.arl", 2 }, + { "#ActD_SubEU_04.ar.00", 2 }, + { "#ActD_SubEU_04.arl", 2 }, + { "#ActD_SubEU_05.ar.00", 2 }, + { "#ActD_SubEU_05.arl", 2 }, + { "#ActD_SubEU_06.ar.00", 2 }, + { "#ActD_SubEU_06.arl", 2 }, + { "#ActN_SubEU_01.ar.00", 2 }, + { "#ActN_SubEU_01.arl", 2 }, + { "#ActN_SubEU_02.ar.00", 2 }, + { "#ActN_SubEU_02.arl", 2 }, + { "#Application.ar.00", 2 }, + { "#Application.arl", 2 }, + { "ActD_SubEU_03.ar.00", 2 }, + { "ActD_SubEU_03.ar.01", 2 }, + { "ActD_SubEU_03.arl", 2 }, + { "ActD_SubEU_04.ar.00", 2 }, + { "ActD_SubEU_04.ar.01", 2 }, + { "ActD_SubEU_04.arl", 2 }, + { "ActN_SubEU_01.ar.00", 2 }, + { "ActN_SubEU_01.arl", 2 }, + { "Additional/ActD_EU/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubEU_01/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubEU_02/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubEU_03/Stage-Add.pfd", 1 }, + { "Additional/ActD_SubEU_04/Stage-Add.pfd", 1 }, + { "Additional/ActN_EUEvil/Stage-Add.pfd", 1 }, + { "Additional/ActN_SubEU_01/Stage-Add.pfd", 1 }, + { "Additional/Event_M2_01_professor_room_new/Stage-Add.pfd", 1 }, + { "Additional/Town_EULabo/Stage-Add.pfd", 1 }, + { "Additional/Town_EULabo_Night/Stage-Add.pfd", 1 }, + { "Additional/Town_EuropeanCity/Stage-Add.pfd", 1 }, + { "Additional/Town_EuropeanCityETF/Stage-Add.pfd", 1 }, + { "Additional/Town_EuropeanCityETF_Night/Stage-Add.pfd", 1 }, + { "Additional/Town_EuropeanCity_Night/Stage-Add.pfd", 1 }, + { "DLC.xml", 1 }, + { "Languages/English/WorldMap.ar.00", 2 }, + { "Languages/English/WorldMap.arl", 2 }, + { "Languages/French/WorldMap.ar.00", 2 }, + { "Languages/French/WorldMap.arl", 2 }, + { "Languages/German/WorldMap.ar.00", 2 }, + { "Languages/German/WorldMap.arl", 2 }, + { "Languages/Italian/WorldMap.ar.00", 2 }, + { "Languages/Italian/WorldMap.arl", 2 }, + { "Languages/Japanese/WorldMap.ar.00", 2 }, + { "Languages/Japanese/WorldMap.arl", 2 }, + { "Languages/Spanish/WorldMap.ar.00", 2 }, + { "Languages/Spanish/WorldMap.arl", 2 }, + { "Packed/ActD_SubEU_03/Stage.pfd", 1 }, + { "Packed/ActD_SubEU_04/Stage.pfd", 1 }, + { "Packed/ActN_SubEU_01/Stage.pfd", 1 }, + { "WorldMap.ar.00", 2 }, + { "WorldMap.arl", 2 }, + { "work/ActD_EU/Terrain.prm.xml", 2 }, + { "work/ActD_SubEU_01/Terrain.prm.xml", 2 }, + { "work/ActD_SubEU_02/Terrain.prm.xml", 2 }, + { "work/ActN_EUEvil/Terrain.prm.xml", 2 }, + { "work/BossEggRayBird/Terrain.prm.xml", 2 }, + { "work/Event_M2_01_professor_room_new/Terrain.prm.xml", 2 }, + { "work/SystemCommon/SR_EnterEUDayActionSub03.seq.xml", 2 }, + { "work/SystemCommon/SR_EnterEUDayActionSub04.seq.xml", 2 }, + { "work/SystemCommon/SR_EnterEUDayActionSub05.seq.xml", 2 }, + { "work/SystemCommon/SR_EnterEUNightActionSub02.seq.xml", 2 }, + { "work/Town_EULabo/Terrain.prm.xml", 2 }, + { "work/Town_EULabo_Night/Terrain.prm.xml", 2 }, + { "work/Town_EuropeanCity/Terrain.prm.xml", 2 }, + { "work/Town_EuropeanCityETF/Terrain.prm.xml", 2 }, + { "work/Town_EuropeanCityETF_Night/Terrain.prm.xml", 2 }, + { "work/Town_EuropeanCity_Night/Terrain.prm.xml", 2 }, +}; + +const size_t SpagoniaFilesSize = std::size(SpagoniaFiles); diff --git a/UnleashedRecomp/install/hashes/spagonia.h b/UnleashedRecomp/install/hashes/spagonia.h new file mode 100644 index 00000000..7db2f8bf --- /dev/null +++ b/UnleashedRecomp/install/hashes/spagonia.h @@ -0,0 +1,10 @@ +// File automatically generated by fshasher + +#pragma once + +#include + +extern const uint64_t SpagoniaHashes[]; +extern const std::pair SpagoniaFiles[]; +extern const size_t SpagoniaFilesSize; + diff --git a/UnleashedRecomp/install/hashes/update.cpp b/UnleashedRecomp/install/hashes/update.cpp new file mode 100644 index 00000000..8239355e --- /dev/null +++ b/UnleashedRecomp/install/hashes/update.cpp @@ -0,0 +1,89 @@ +// File automatically generated by fshasher + +#include + +extern const uint64_t UpdateHashes[]; +extern const std::pair UpdateFiles[]; +extern const size_t UpdateFilesSize; + +const uint64_t UpdateHashes[] = { + 6914273463875662709ULL, + 15542186142639918255ULL, + 17773094197787397017ULL, + 5694064368761413534ULL, + 10660633045276223515ULL, + 6259845327508088719ULL, + 12140399948272279979ULL, + 7418638713822288133ULL, + 14117267789244251538ULL, + 15188168166630393460ULL, + 3161308809281010162ULL, + 5322614488283725236ULL, + 4606314145682200491ULL, + 11955725616840921688ULL, + 11797277641169528627ULL, + 16412181293791116322ULL, + 11038823378333165548ULL, + 5479982606338303627ULL, + 868771203788675788ULL, + 17001824000099573976ULL, + 9159616851251538481ULL, + 15568568481517853886ULL, + 10521442355407577670ULL, + 9513615512117450320ULL, + 4920031480332452542ULL, + 17152633532642839320ULL, + 1430448682009298272ULL, + 2819842435698853770ULL, + 1430448682009298272ULL, + 2819842435698853770ULL, + 13038055622504309783ULL, + 1430448682009298272ULL, + 2819842435698853770ULL, + 3623875508130760747ULL, + 1400141374194792546ULL, + 3560111161029067800ULL, + 2610060740632518377ULL, + 2610060740632518377ULL, +}; + +const std::pair UpdateFiles[] = { + { "default.xexp", 3 }, + { "work/ActD_MykonosAct1/Base.set.xml", 1 }, + { "work/ActD_NY/Mission_NYCity_S20_10.set.xml", 1 }, + { "work/ActD_SubEU_01/Set2.set.xml", 1 }, + { "work/ActD_SubNY_01/Set.set.xml", 1 }, + { "work/ActD_SubNY_01/Stage.stg.xml", 1 }, + { "work/ActD_SubNY_01/ny_sub_path.path.xml", 1 }, + { "work/ActD_SubSnow_01/Sub_Layer1_Set.set.xml", 1 }, + { "work/ActD_SubSnow_01/Sub_Layer2_Set.set.xml", 1 }, + { "work/ActD_SubSnow_01/Sub_Layer3_Set.set.xml", 1 }, + { "work/ActN_BeachEvil/evl_sea_obj_st_waterCircle.model", 1 }, + { "work/ActN_BeachEvil/sea_water_circle.material", 1 }, + { "work/ActN_ChinaEvil/area06_enemyset.set.xml", 1 }, + { "work/ActN_ChinaEvil/area07_enemyset.set.xml", 1 }, + { "work/ActN_ChinaEvil/system.set.xml", 1 }, + { "work/ActN_EUEvil/area16_gimmickset.set.xml", 1 }, + { "work/ActN_EUEvil/area18_gimmickset.set.xml", 1 }, + { "work/ActN_EUEvil/system.set.xml", 1 }, + { "work/ActN_PetraEvil/system.set.xml", 1 }, + { "work/ActN_SubChina_01/area01_enemyset.set.xml", 1 }, + { "work/ActN_SubChina_01/area01_gimmickset.set.xml", 1 }, + { "work/Act_EggmanLand/BaseEvil.set.xml", 1 }, + { "work/Act_EggmanLand/system.set.xml", 1 }, + { "work/Application/SR_AdjustTownState.seq.xml", 1 }, + { "work/CmnTown_Mykonos/myk_obj_soc_paperboxABC.dds", 1 }, + { "work/CmnTown_Snow/snw_obj_snowman04_dif.dds", 1 }, + { "work/EvilActionCommon_Mykonos/myk_obj_soc_paperboxABC.dds", 1 }, + { "work/EvilActionCommon_Snow/snw_obj_snowman04_dif.dds", 1 }, + { "work/Inspire/scene/evrt_m5_02/evrt_m5_02.inspire_resource.xml", 1 }, + { "work/SonicActionCommon_Mykonos/myk_obj_soc_paperboxABC.dds", 1 }, + { "work/SonicActionCommon_Snow/snw_obj_snowman04_dif.dds", 1 }, + { "work/Title/mat_mainmenu_common_001.dds", 1 }, + { "work/Town_EuropeanCity_Dispel/Mission_EuropeanCity_S30_10.set.xml", 1 }, + { "work/Town_NYCity_Dispel/Mission_MoveMission_S20_10.set.xml", 1 }, + { "work/Town_SouthEastAsiaETF/CommonOBJ.set.xml", 1 }, + { "work/Town_SouthEastAsiaETF_Night/CommonOBJ.set.xml", 1 }, +}; + +const size_t UpdateFilesSize = std::size(UpdateFiles); diff --git a/UnleashedRecomp/install/hashes/update.h b/UnleashedRecomp/install/hashes/update.h new file mode 100644 index 00000000..b5ea7a72 --- /dev/null +++ b/UnleashedRecomp/install/hashes/update.h @@ -0,0 +1,10 @@ +// File automatically generated by fshasher + +#pragma once + +#include + +extern const uint64_t UpdateHashes[]; +extern const std::pair UpdateFiles[]; +extern const size_t UpdateFilesSize; + diff --git a/UnleashedRecomp/install/installer.cpp b/UnleashedRecomp/install/installer.cpp new file mode 100644 index 00000000..0058b2e0 --- /dev/null +++ b/UnleashedRecomp/install/installer.cpp @@ -0,0 +1,492 @@ +#include "installer.h" + +#include + +#include "directory_file_system.h" +#include "iso_file_system.h" +#include "xcontent_file_system.h" + +#include "hashes/apotos_shamar.h" +#include "hashes/chunnan.h" +#include "hashes/empire_city_adabat.h" +#include "hashes/game.h" +#include "hashes/holoska.h" +#include "hashes/mazuri.h" +#include "hashes/spagonia.h" +#include "hashes/update.h" + +static const std::string GameDirectory = "game"; +static const std::string DLCDirectory = "dlc"; +static const std::string ApotosShamarDirectory = DLCDirectory + "/Apotos & Shamar Adventure Pack"; +static const std::string ChunnanDirectory = DLCDirectory + "/Chunnan Adventure Pack"; +static const std::string EmpireCityAdabatDirectory = DLCDirectory + "/Empire City & Adabat Adventure Pack"; +static const std::string HoloskaDirectory = DLCDirectory + "/Holoska Adventure Pack"; +static const std::string MazuriDirectory = DLCDirectory + "/Mazuri Adventure Pack"; +static const std::string SpagoniaDirectory = DLCDirectory + "/Spagonia Adventure Pack"; +static const std::string UpdateDirectory = "update"; +static const std::string GameExecutableFile = "default.xex"; +static const std::string DLCValidationFile = "DLC.xml"; +static const std::string UpdateExecutablePatchFile = "default.xexp"; +static const std::string ISOExtension = ".iso"; +static const std::string OldExtension = ".old"; +static const std::string TempExtension = ".tmp"; + +static std::string fromU8(const std::u8string &str) +{ + return std::string(str.begin(), str.end()); +} + +static std::string fromPath(const std::filesystem::path &path) +{ + return fromU8(path.u8string()); +} + +static std::string toLower(std::string str) { + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { return std::tolower(c); }); + return str; +}; + +static std::unique_ptr createFileSystemFromPath(const std::filesystem::path &path) +{ + if (XContentFileSystem::check(path)) + { + return XContentFileSystem::create(path); + } + else if (toLower(path.extension().string()) == ISOExtension) + { + return ISOFileSystem::create(path); + } + else if (std::filesystem::is_directory(path)) + { + return DirectoryFileSystem::create(path); + } + else + { + return nullptr; + } +} + +static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, bool skipHashChecks, std::vector &fileData, Journal &journal, const std::function &progressCallback) { + const std::string filename(pair.first); + const uint32_t hashCount = pair.second; + if (!sourceVfs.exists(filename)) + { + journal.lastResult = Journal::Result::FileMissing; + journal.lastErrorMessage = std::format("File {} does not exist in the file system.", filename); + return false; + } + + if (!sourceVfs.load(filename, fileData)) + { + journal.lastResult = Journal::Result::FileReadFailed; + journal.lastErrorMessage = std::format("Failed to read file {} from the file system.", filename); + return false; + } + + if (!skipHashChecks) + { + uint64_t fileHash = XXH3_64bits(fileData.data(), fileData.size()); + bool fileHashFound = false; + for (uint32_t i = 0; i < hashCount && !fileHashFound; i++) + { + fileHashFound = fileHash == fileHashes[i]; + } + + if (!fileHashFound) + { + journal.lastResult = Journal::Result::FileHashFailed; + journal.lastErrorMessage = std::format("File {} from the file system did not match any of the known hashes.", filename); + return false; + } + } + + std::filesystem::path targetPath = targetDirectory / std::filesystem::path(std::u8string_view((const char8_t *)(pair.first))); + std::filesystem::path parentPath = targetPath.parent_path(); + if (!std::filesystem::exists(parentPath)) + { + std::filesystem::create_directories(parentPath); + } + + while (!parentPath.empty()) { + journal.createdDirectories.insert(parentPath); + + if (parentPath != targetDirectory) { + parentPath = parentPath.parent_path(); + } + else { + parentPath = std::filesystem::path(); + } + } + + std::ofstream outStream(targetPath, std::ios::binary); + if (!outStream.is_open()) + { + journal.lastResult = Journal::Result::FileCreationFailed; + journal.lastErrorMessage = std::format("Failed to create file at {}.", targetPath.string()); + return false; + } + + journal.createdFiles.push_back(targetPath); + + outStream.write((const char *)(fileData.data()), fileData.size()); + if (outStream.bad()) + { + journal.lastResult = Journal::Result::FileWriteFailed; + journal.lastErrorMessage = std::format("Failed to create file at {}.", targetPath.string()); + return false; + } + + progressCallback(++journal.progressCounter); + + return true; +} + +static DLC detectDLC(const std::filesystem::path &sourcePath, VirtualFileSystem &sourceVfs, Journal &journal) +{ + std::vector dlcXmlBytes; + if (!sourceVfs.load(DLCValidationFile, dlcXmlBytes)) + { + journal.lastResult = Journal::Result::FileMissing; + journal.lastErrorMessage = std::format("File {} does not exist in the file system.", DLCValidationFile); + return DLC::Unknown; + } + + const char TypeStartString[] = ""; + const char TypeEndString[] = ""; + size_t dlcByteCount = dlcXmlBytes.size(); + dlcXmlBytes.resize(dlcByteCount + 1); + dlcXmlBytes[dlcByteCount] = '\0'; + const char *typeStartLocation = strstr((const char *)(dlcXmlBytes.data()), TypeStartString); + const char *typeEndLocation = typeStartLocation != nullptr ? strstr(typeStartLocation, TypeEndString) : nullptr; + if (typeStartLocation == nullptr || typeEndLocation == nullptr) + { + journal.lastResult = Journal::Result::DLCParsingFailed; + journal.lastErrorMessage = "Failed to find DLC type for " + sourcePath.string() + "."; + return DLC::Unknown; + } + + const char *typeNumberLocation = typeStartLocation + strlen(TypeStartString); + size_t typeNumberCount = typeEndLocation - typeNumberLocation; + if (typeNumberCount != 1) + { + journal.lastResult = Journal::Result::UnknownDLCType; + journal.lastErrorMessage = "DLC type for " + sourcePath.string() + " is unknown."; + return DLC::Unknown; + } + + switch (*typeNumberLocation) + { + case '1': + return DLC::Spagonia; + case '2': + return DLC::Chunnan; + case '3': + return DLC::Mazuri; + case '4': + return DLC::Holoska; + case '5': + return DLC::ApotosShamar; + case '7': + return DLC::EmpireCityAdabat; + default: + journal.lastResult = Journal::Result::UnknownDLCType; + journal.lastErrorMessage = "DLC type for " + sourcePath.string() + " is unknown."; + return DLC::Unknown; + } +} + +bool Installer::checkGameInstall(const std::filesystem::path &baseDirectory) +{ + return std::filesystem::exists(baseDirectory / GameDirectory / GameExecutableFile); +} + +bool Installer::copyFiles(std::span filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function &progressCallback) +{ + if (!std::filesystem::exists(targetDirectory) && !std::filesystem::create_directories(targetDirectory)) + { + journal.lastResult = Journal::Result::DirectoryCreationFailed; + journal.lastErrorMessage = "Unable to create directory at " + fromPath(targetDirectory); + return false; + } + + FilePair validationPair = {}; + uint32_t validationHashIndex = 0; + uint32_t hashIndex = 0; + uint32_t hashCount = 0; + std::vector fileData; + for (FilePair pair : filePairs) + { + hashIndex = hashCount; + hashCount += pair.second; + + if (validationFile.compare(pair.first) == 0) + { + validationPair = pair; + validationHashIndex = hashIndex; + continue; + } + + if (!copyFile(pair, &fileHashes[hashIndex], sourceVfs, targetDirectory, skipHashChecks, fileData, journal, progressCallback)) + { + return false; + } + } + + // Validation file is copied last after all other files have been copied. + if (validationPair.first != nullptr) + { + if (!copyFile(validationPair, &fileHashes[validationHashIndex], sourceVfs, targetDirectory, skipHashChecks, fileData, journal, progressCallback)) + { + return false; + } + } + else + { + journal.lastResult = Journal::Result::ValidationFileMissing; + journal.lastErrorMessage = std::format("Unable to find validation file {} in file system.", validationFile); + return false; + } + + return true; +} + +bool Installer::parseContent(const std::filesystem::path &sourcePath, std::unique_ptr &targetVfs, Journal &journal) +{ + targetVfs = createFileSystemFromPath(sourcePath); + if (targetVfs != nullptr) + { + return true; + } + else + { + journal.lastResult = Journal::Result::VirtualFileSystemFailed; + journal.lastErrorMessage = "Unable to open file system at " + fromPath(sourcePath); + return false; + } +} + +bool Installer::install(const Input &input, const std::filesystem::path &targetDirectory, Journal &journal, const std::function &progressCallback) +{ + // Parse the contents of the base game. + std::unique_ptr gameSource; + if (!input.gameSource.empty()) + { + if (!parseContent(input.gameSource, gameSource, journal)) + { + return false; + } + + journal.progressTotal += GameFilesSize; + } + + // Parse the contents of Update. + std::unique_ptr updateSource; + if (!input.updateSource.empty()) + { + if (!parseContent(input.updateSource, updateSource, journal)) + { + return false; + } + + journal.progressTotal += UpdateFilesSize; + } + + // Parse the contents of the DLC Packs. + struct DLCSource { + std::unique_ptr sourceVfs; + std::span filePairs; + const uint64_t *fileHashes = nullptr; + std::string targetSubDirectory; + }; + + std::vector dlcSources; + for (const auto &path : input.dlcSources) + { + dlcSources.emplace_back(); + DLCSource &dlcSource = dlcSources.back(); + if (!parseContent(path, dlcSource.sourceVfs, journal)) + { + return false; + } + + DLC dlc = detectDLC(path, *dlcSource.sourceVfs, journal); + switch (dlc) + { + case DLC::Spagonia: + dlcSource.filePairs = { SpagoniaFiles, SpagoniaFilesSize }; + dlcSource.fileHashes = SpagoniaHashes; + dlcSource.targetSubDirectory = SpagoniaDirectory; + break; + case DLC::Chunnan: + dlcSource.filePairs = { ChunnanFiles, ChunnanFilesSize }; + dlcSource.fileHashes = ChunnanHashes; + dlcSource.targetSubDirectory = ChunnanDirectory; + break; + case DLC::Mazuri: + dlcSource.filePairs = { MazuriFiles, MazuriFilesSize }; + dlcSource.fileHashes = MazuriHashes; + dlcSource.targetSubDirectory = MazuriDirectory; + break; + case DLC::Holoska: + dlcSource.filePairs = { HoloskaFiles, HoloskaFilesSize }; + dlcSource.fileHashes = HoloskaHashes; + dlcSource.targetSubDirectory = HoloskaDirectory; + break; + case DLC::ApotosShamar: + dlcSource.filePairs = { ApotosShamarFiles, ApotosShamarFilesSize }; + dlcSource.fileHashes = ApotosShamarHashes; + dlcSource.targetSubDirectory = ApotosShamarDirectory; + break; + case DLC::EmpireCityAdabat: + dlcSource.filePairs = { EmpireCityAdabatFiles, EmpireCityAdabatFilesSize }; + dlcSource.fileHashes = EmpireCityAdabatHashes; + dlcSource.targetSubDirectory = EmpireCityAdabatDirectory; + break; + default: + return false; + } + + journal.progressTotal += dlcSource.filePairs.size(); + } + + // Install the base game. + if (!copyFiles({ GameFiles, GameFilesSize }, GameHashes, *gameSource, targetDirectory / GameDirectory, GameExecutableFile, input.skipHashChecks, journal, progressCallback)) + { + return false; + } + + // Install the update. + if (!copyFiles({ UpdateFiles, UpdateFilesSize }, UpdateHashes, *updateSource, targetDirectory / UpdateDirectory, UpdateExecutablePatchFile, input.skipHashChecks, journal, progressCallback)) + { + return false; + } + + // Patch the executable with the update's file. + std::filesystem::path baseXexPath = targetDirectory / GameDirectory / GameExecutableFile; + std::filesystem::path patchPath = targetDirectory / UpdateDirectory / UpdateExecutablePatchFile; + std::filesystem::path patchedXexPath = targetDirectory / GameDirectory / (GameExecutableFile + TempExtension); + XexPatcher::Result patcherResult = XexPatcher::apply(baseXexPath, patchPath, patchedXexPath); + if (patcherResult != XexPatcher::Result::Success) + { + journal.lastResult = Journal::Result::PatchProcessFailed; + journal.lastPatcherResult = patcherResult; + journal.lastErrorMessage = "Patch process failed."; + return false; + } + + // Replace the executable by renaming and deleting in a safe way. + std::error_code ec; + std::filesystem::path oldXexPath = targetDirectory / GameDirectory / (GameExecutableFile + OldExtension); + std::filesystem::rename(baseXexPath, oldXexPath, ec); + if (ec) + { + journal.lastResult = Journal::Result::PatchReplacementFailed; + journal.lastErrorMessage = "Failed to rename executable."; + return false; + } + + std::filesystem::rename(patchedXexPath, baseXexPath, ec); + if (ec) + { + std::filesystem::rename(oldXexPath, baseXexPath, ec); + journal.lastResult = Journal::Result::PatchReplacementFailed; + journal.lastErrorMessage = "Failed to rename executable."; + return false; + } + + std::filesystem::remove(oldXexPath); + + // Install the DLC. + if (!dlcSources.empty()) + { + journal.createdDirectories.insert(targetDirectory / DLCDirectory); + } + + for (const DLCSource &dlcSource : dlcSources) + { + if (!copyFiles(dlcSource.filePairs, dlcSource.fileHashes, *dlcSource.sourceVfs, targetDirectory / dlcSource.targetSubDirectory, DLCValidationFile, input.skipHashChecks, journal, progressCallback)) + { + return false; + } + } + + return true; +} + +void Installer::rollback(Journal &journal) +{ + std::error_code ec; + for (const auto &path : journal.createdFiles) + { + std::filesystem::remove(path, ec); + } + + for (auto it = journal.createdDirectories.rbegin(); it != journal.createdDirectories.rend(); it++) + { + std::filesystem::remove(*it, ec); + } +} + +bool Installer::parseGame(const std::filesystem::path &sourcePath) +{ + std::unique_ptr sourceVfs = createFileSystemFromPath(sourcePath); + if (sourceVfs == nullptr) + { + return false; + } + + return sourceVfs->exists(GameExecutableFile); +} + +bool Installer::parseUpdate(const std::filesystem::path &sourcePath) +{ + std::unique_ptr sourceVfs = createFileSystemFromPath(sourcePath); + if (sourceVfs == nullptr) + { + return false; + } + + return sourceVfs->exists(UpdateExecutablePatchFile); +} + +DLC Installer::parseDLC(const std::filesystem::path &sourcePath) +{ + Journal journal; + std::unique_ptr sourceVfs = createFileSystemFromPath(sourcePath); + if (sourceVfs == nullptr) + { + return DLC::Unknown; + } + + return detectDLC(sourcePath, *sourceVfs, journal); +} + +XexPatcher::Result Installer::checkGameUpdateCompatibility(const std::filesystem::path &gameSourcePath, const std::filesystem::path &updateSourcePath) +{ + std::unique_ptr gameSourceVfs = createFileSystemFromPath(gameSourcePath); + if (gameSourceVfs == nullptr) + { + return XexPatcher::Result::FileOpenFailed; + } + + std::unique_ptr updateSourceVfs = createFileSystemFromPath(updateSourcePath); + if (updateSourceVfs == nullptr) + { + return XexPatcher::Result::FileOpenFailed; + } + + std::vector xexBytes; + std::vector patchBytes; + if (!gameSourceVfs->load(GameExecutableFile, xexBytes)) + { + return XexPatcher::Result::FileOpenFailed; + } + + if (!updateSourceVfs->load(UpdateExecutablePatchFile, patchBytes)) + { + return XexPatcher::Result::FileOpenFailed; + } + + std::vector patchedBytes; + return XexPatcher::apply(xexBytes, patchBytes, patchedBytes, true); +} diff --git a/UnleashedRecomp/install/installer.h b/UnleashedRecomp/install/installer.h new file mode 100644 index 00000000..43006146 --- /dev/null +++ b/UnleashedRecomp/install/installer.h @@ -0,0 +1,76 @@ +#pragma once + +#include +#include + +#include "virtual_file_system.h" +#include "xex_patcher.h" + +enum class DLC { + Unknown, + Spagonia, + Chunnan, + Mazuri, + Holoska, + ApotosShamar, + EmpireCityAdabat +}; + +struct Journal +{ + enum class Result + { + Success, + VirtualFileSystemFailed, + DirectoryCreationFailed, + FileMissing, + FileReadFailed, + FileHashFailed, + FileCreationFailed, + FileWriteFailed, + ValidationFileMissing, + DLCParsingFailed, + PatchProcessFailed, + PatchReplacementFailed, + UnknownDLCType + }; + + uint32_t progressCounter = 0; + uint32_t progressTotal = 0; + std::list createdFiles; + std::set createdDirectories; + Result lastResult = Result::Success; + XexPatcher::Result lastPatcherResult = XexPatcher::Result::Success; + std::string lastErrorMessage; +}; + +using FilePair = std::pair; + +struct Installer +{ + struct Input + { + std::filesystem::path gameSource; + std::filesystem::path updateSource; + std::list dlcSources; + bool skipHashChecks = false; + }; + + static bool checkGameInstall(const std::filesystem::path &baseDirectory); + static bool copyFiles(std::span filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function &progressCallback); + static bool parseContent(const std::filesystem::path &sourcePath, std::unique_ptr &targetVfs, Journal &journal); + static bool install(const Input &input, const std::filesystem::path &targetDirectory, Journal &journal, const std::function &progressCallback); + static void rollback(Journal &journal); + + // Convenience method for checking if the specified file contains the game. This should be used when the user selects the file. + static bool parseGame(const std::filesystem::path &sourcePath); + + // Convenience method for checking if the specified file contains the update. This should be used when the user selects the file. + static bool parseUpdate(const std::filesystem::path &sourcePath); + + // Convenience method for the installer to check which DLC the file that was specified corresponds to. This should be used when the user selects the file. + static DLC parseDLC(const std::filesystem::path &sourcePath); + + // Convenience method for checking if a game and an update are compatible. This should be used when the user presses next during installation. + static XexPatcher::Result checkGameUpdateCompatibility(const std::filesystem::path &gameSourcePath, const std::filesystem::path &updateSourcePath); +}; diff --git a/UnleashedRecomp/install/iso_file_system.cpp b/UnleashedRecomp/install/iso_file_system.cpp new file mode 100644 index 00000000..0348bbe6 --- /dev/null +++ b/UnleashedRecomp/install/iso_file_system.cpp @@ -0,0 +1,191 @@ +// Referenced from: https://github.com/xenia-canary/xenia-canary/blob/canary_experimental/src/xenia/vfs/devices/disc_image_device.cc + +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2023 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "iso_file_system.h" + +#include + +ISOFileSystem::ISOFileSystem(const std::filesystem::path &isoPath) +{ + mappedFile.open(isoPath); + if (!mappedFile.isOpen()) + { + return; + } + + // Find root sector. + const uint8_t *mappedFileData = mappedFile.data(); + uint32_t gameOffset = 0; + const size_t XeSectorSize = 2048; + static const size_t PossibleOffsets[] = { 0x00000000, 0x0000FB20, 0x00020600, 0x02080000, 0x0FD90000, }; + bool magicFound = false; + const char RefMagic[] = "MICROSOFT*XBOX*MEDIA"; + for (size_t i = 0; i < std::size(PossibleOffsets); i++) + { + size_t fileOffset = PossibleOffsets[i] + (32 * XeSectorSize); + if ((fileOffset + strlen(RefMagic)) > mappedFile.size()) + { + continue; + } + + if (std::memcmp(&mappedFileData[fileOffset], RefMagic, strlen(RefMagic)) == 0) + { + gameOffset = PossibleOffsets[i]; + magicFound = true; + } + } + + size_t rootInfoOffset = gameOffset + (32 * XeSectorSize) + 20; + if (!magicFound || (rootInfoOffset + 8) > mappedFile.size()) + { + mappedFile.close(); + return; + } + + // Parse root information. + uint32_t rootSector = *(uint32_t *)(&mappedFileData[rootInfoOffset + 0]); + uint32_t rootSize = *(uint32_t *)(&mappedFileData[rootInfoOffset + 4]); + size_t rootOffset = gameOffset + (rootSector * XeSectorSize); + const uint32_t MinRootSize = 13; + const uint32_t MaxRootSize = 32 * 1024 * 1024; + if ((rootSize < MinRootSize) || (rootSize > MaxRootSize)) + { + mappedFile.close(); + return; + } + + struct IterationStep + { + std::string fileNameBase; + size_t nodeOffset = 0; + size_t entryOffset = 0; + + IterationStep() = default; + IterationStep(std::string fileNameBase, size_t nodeOffset, size_t entryOffset) : fileNameBase(fileNameBase), nodeOffset(nodeOffset), entryOffset(entryOffset) { } + }; + + std::stack iterationStack; + iterationStack.emplace("", rootOffset, 0); + + IterationStep step; + uint16_t nodeL, nodeR; + uint32_t sector, length; + uint8_t attributes, nameLength; + char fileName[256]; + const uint8_t FileAttributeDirectory = 0x10; + while (!iterationStack.empty()) + { + step = iterationStack.top(); + iterationStack.pop(); + + size_t infoOffset = step.nodeOffset + step.entryOffset; + if ((infoOffset + 14) > mappedFile.size()) + { + mappedFile.close(); + return; + } + + nodeL = *(uint16_t *)(&mappedFileData[infoOffset + 0]); + nodeR = *(uint16_t *)(&mappedFileData[infoOffset + 2]); + sector = *(uint32_t *)(&mappedFileData[infoOffset + 4]); + length = *(uint32_t *)(&mappedFileData[infoOffset + 8]); + attributes = *(uint8_t *)(&mappedFileData[infoOffset + 12]); + nameLength = *(uint8_t *)(&mappedFileData[infoOffset + 13]); + + size_t nameOffset = infoOffset + 14; + if ((nameOffset + nameLength) > mappedFile.size()) + { + mappedFile.close(); + return; + } + + memcpy(fileName, &mappedFileData[nameOffset], nameLength); + fileName[nameLength] = '\0'; + + if (nodeL) + { + iterationStack.emplace(step.fileNameBase, step.nodeOffset, nodeL * 4); + } + + if (nodeR) + { + iterationStack.emplace(step.fileNameBase, step.nodeOffset, nodeR * 4); + } + + std::string fileNameUTF8 = step.fileNameBase + fileName; + if (attributes & FileAttributeDirectory) + { + if (length > 0) + { + iterationStack.emplace(fileNameUTF8 + "/", gameOffset + sector * XeSectorSize, 0); + } + } + else + { + fileMap[fileNameUTF8] = { gameOffset + sector * XeSectorSize, length}; + } + } +} + +bool ISOFileSystem::load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const +{ + auto it = fileMap.find(path); + if (it != fileMap.end()) + { + if (fileDataMaxByteCount < std::get<1>(it->second)) + { + return false; + } + + const uint8_t *mappedFileData = mappedFile.data(); + memcpy(fileData, &mappedFileData[std::get<0>(it->second)], std::get<1>(it->second)); + return true; + } + else + { + return false; + } +} + +size_t ISOFileSystem::getSize(const std::string &path) const +{ + auto it = fileMap.find(path); + if (it != fileMap.end()) + { + return std::get<1>(it->second); + } + else + { + return 0; + } +} + +bool ISOFileSystem::exists(const std::string &path) const +{ + return fileMap.find(path) != fileMap.end(); +} + +bool ISOFileSystem::empty() const +{ + return !mappedFile.isOpen(); +} + +std::unique_ptr ISOFileSystem::create(const std::filesystem::path &isoPath) { + std::unique_ptr isoFs = std::make_unique(isoPath); + if (!isoFs->empty()) + { + return isoFs; + } + else + { + return nullptr; + } +} diff --git a/UnleashedRecomp/install/iso_file_system.h b/UnleashedRecomp/install/iso_file_system.h new file mode 100644 index 00000000..b7bac458 --- /dev/null +++ b/UnleashedRecomp/install/iso_file_system.h @@ -0,0 +1,33 @@ +// Referenced from: https://github.com/xenia-canary/xenia-canary/blob/canary_experimental/src/xenia/vfs/devices/disc_image_device.cc + +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2023 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#pragma once + +#include +#include + +#include "virtual_file_system.h" + +#include "memory_mapped_file.h" + +struct ISOFileSystem : VirtualFileSystem +{ + MemoryMappedFile mappedFile; + std::map> fileMap; + + ISOFileSystem(const std::filesystem::path &isoPath); + bool load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const override; + size_t getSize(const std::string &path) const override; + bool exists(const std::string &path) const override; + bool empty() const; + + static std::unique_ptr create(const std::filesystem::path &isoPath); +}; diff --git a/UnleashedRecomp/install/memory_mapped_file.cpp b/UnleashedRecomp/install/memory_mapped_file.cpp new file mode 100644 index 00000000..b96ea543 --- /dev/null +++ b/UnleashedRecomp/install/memory_mapped_file.cpp @@ -0,0 +1,169 @@ +#include "memory_mapped_file.h" + +#if !defined(_WIN32) +# include +# include +# include +# include +#endif + +MemoryMappedFile::MemoryMappedFile() +{ + // Default constructor. +} + +MemoryMappedFile::MemoryMappedFile(const std::filesystem::path &path) +{ + open(path); +} + +MemoryMappedFile::~MemoryMappedFile() +{ + close(); +} + +MemoryMappedFile::MemoryMappedFile(MemoryMappedFile &&other) +{ +#if defined(_WIN32) + fileHandle = other.fileHandle; + fileMappingHandle = other.fileMappingHandle; + fileView = other.fileView; + fileSize = other.fileSize; + + other.fileHandle = nullptr; + other.fileMappingHandle = nullptr; + other.fileView = nullptr; + other.fileSize.QuadPart = 0; +#else + fileHandle = other.fileHandle; + fileView = other.fileView; + fileSize = other.fileSize; + + other.fileHandle = -1; + other.fileView = MAP_FAILED; + other.fileSize = 0; +#endif +} + +bool MemoryMappedFile::open(const std::filesystem::path &path) +{ +#if defined(_WIN32) + fileHandle = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (fileHandle == INVALID_HANDLE_VALUE) + { + fprintf(stderr, "CreateFileW failed with error %lu.\n", GetLastError()); + fileHandle = nullptr; + return false; + } + + if (!GetFileSizeEx(fileHandle, &fileSize)) + { + fprintf(stderr, "GetFileSizeEx failed with error %lu.\n", GetLastError()); + CloseHandle(fileHandle); + fileHandle = nullptr; + return false; + } + + fileMappingHandle = CreateFileMappingW(fileHandle, nullptr, PAGE_READONLY, 0, 0, nullptr); + if (fileMappingHandle == nullptr) + { + fprintf(stderr, "CreateFileMappingW failed with error %lu.\n", GetLastError()); + CloseHandle(fileHandle); + fileHandle = nullptr; + return false; + } + + fileView = MapViewOfFile(fileMappingHandle, FILE_MAP_READ, 0, 0, 0); + if (fileView == nullptr) + { + fprintf(stderr, "MapViewOfFile failed with error %lu.\n", GetLastError()); + CloseHandle(fileMappingHandle); + CloseHandle(fileHandle); + fileMappingHandle = nullptr; + fileHandle = nullptr; + return false; + } + + return true; +#else + fileHandle = ::open(path.c_str(), O_RDONLY); + if (fileHandle == -1) + { + fprintf(stderr, "open for %s failed with error %s.\n", path.c_str(), strerror(errno)); + return false; + } + + fileSize = lseek(fileHandle, 0, SEEK_END); + if (fileSize == (off_t)(-1)) + { + fprintf(stderr, "lseek failed with error %s.\n", strerror(errno)); + close(fileHandle); + fileHandle = -1; + return false; + } + + fileView = mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fileHandle, 0); + if (fileView == MAP_FAILED) + { + fprintf(stderr, "mmap failed with error %s.\n", strerror(errno)); + close(fileHandle); + fileHandle = -1; + return false; + } + + return true; +#endif +} + +void MemoryMappedFile::close() +{ +#if defined(_WIN32) + if (fileView != nullptr) + { + UnmapViewOfFile(fileView); + } + + if (fileMappingHandle != nullptr) + { + CloseHandle(fileMappingHandle); + } + + if (fileHandle != nullptr) + { + CloseHandle(fileHandle); + } +#else + if (fileView != MAP_FAILED) + { + munmap(fileView, fileSize); + } + + if (fileHandle != -1) + { + close(fileHandle); + } +#endif +} + +bool MemoryMappedFile::isOpen() const +{ +#if defined(_WIN32) + return (fileView != nullptr); +#else + return (fileView != MAP_FAILED); +#endif +} + +uint8_t *MemoryMappedFile::data() const +{ + return reinterpret_cast(fileView); +} + +size_t MemoryMappedFile::size() const +{ +#if defined(_WIN32) + return fileSize.QuadPart; +#else + return static_cast(fileSize); +#endif +} diff --git a/UnleashedRecomp/install/memory_mapped_file.h b/UnleashedRecomp/install/memory_mapped_file.h new file mode 100644 index 00000000..a3de88b2 --- /dev/null +++ b/UnleashedRecomp/install/memory_mapped_file.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#if defined(_WIN32) +# include +#else +# include +#endif + +struct MemoryMappedFile { +#if defined(_WIN32) + HANDLE fileHandle = nullptr; + HANDLE fileMappingHandle = nullptr; + LPVOID fileView = nullptr; + LARGE_INTEGER fileSize = {}; +#else + int fileHandle = -1; + void *fileView = MAP_FAILED; + off_t fileSize = 0; +#endif + + MemoryMappedFile(); + MemoryMappedFile(const std::filesystem::path &path); + MemoryMappedFile(MemoryMappedFile &&other); + ~MemoryMappedFile(); + bool open(const std::filesystem::path &path); + void close(); + bool isOpen() const; + uint8_t *data() const; + size_t size() const; +}; diff --git a/UnleashedRecomp/install/virtual_file_system.h b/UnleashedRecomp/install/virtual_file_system.h new file mode 100644 index 00000000..3b926085 --- /dev/null +++ b/UnleashedRecomp/install/virtual_file_system.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +struct VirtualFileSystem { + virtual ~VirtualFileSystem() { }; + virtual bool load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const = 0; + virtual size_t getSize(const std::string &path) const = 0; + virtual bool exists(const std::string &path) const = 0; + + // Concrete implementation shortcut. + bool load(const std::string &path, std::vector &fileData) + { + size_t fileDataSize = getSize(path); + if (fileDataSize == 0) + { + return false; + } + + fileData.resize(fileDataSize); + return load(path, fileData.data(), fileDataSize); + } +}; diff --git a/UnleashedRecomp/install/xcontent_file_system.cpp b/UnleashedRecomp/install/xcontent_file_system.cpp new file mode 100644 index 00000000..c3178262 --- /dev/null +++ b/UnleashedRecomp/install/xcontent_file_system.cpp @@ -0,0 +1,641 @@ +// Referenced from: https://github.com/xenia-canary/xenia-canary/blob/canary_experimental/src/xenia/vfs/devices/xcontent_container_device.cc + +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2023 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + + +#include "xcontent_file_system.h" + +#include +#include +#include + +enum class XContentPackageType +{ + CON = 0x434F4E20, + PIRS = 0x50495253, + LIVE = 0x4C495645, +}; + +struct XContentLicense +{ + be licenseId; + be licenseBits; + be licenseFlags; +}; + +#pragma pack(push, 1) +struct XContentHeader +{ + be magic; + uint8_t signature[0x228]; + XContentLicense licenses[0x10]; + uint8_t contentId[0x14]; + be headerSize; +}; +static_assert(sizeof(XContentHeader) == 0x344); + +struct StfsVolumeDescriptor +{ + uint8_t descriptorLength; + uint8_t version; + + union + { + uint8_t asByte; + struct + { + uint8_t readOnlyFormat : 1; + uint8_t rootActiveIndex : 1; + uint8_t directoryOverallocated : 1; + uint8_t directoryIndexBoundsValid : 1; + } bits; + } flags; + + uint16_t fileTableBlockCount; + uint8_t fileTableBlockNumberRaw[3]; + uint8_t topHashTableHash[0x14]; + be totalBlockCount; + be freeBlockCount; +}; +static_assert(sizeof(StfsVolumeDescriptor) == 0x24); + +struct StfsDirectoryEntry { + char name[40]; + + struct + { + uint8_t nameLength : 6; + uint8_t contiguous : 1; + uint8_t directory : 1; + } flags; + + uint8_t validDataBlocksRaw[3]; + uint8_t allocatedDataBlocksRaw[3]; + uint8_t startBlockNumberRaw[3]; + be directoryIndex; + be length; + be createDate; + be createTime; + be modifiedDate; + be modifiedTime; +}; +static_assert(sizeof(StfsDirectoryEntry) == 0x40); + +struct StfsDirectoryBlock { + StfsDirectoryEntry entries[0x40]; +}; +static_assert(sizeof(StfsDirectoryBlock) == 0x1000); + +struct StfsHashEntry { + uint8_t sha1[0x14]; + be infoRaw; +}; +static_assert(sizeof(StfsHashEntry) == 0x18); + +struct StfsHashTable { + StfsHashEntry entries[170]; + be numBlocks; + uint8_t padding[12]; +}; +static_assert(sizeof(StfsHashTable) == 0x1000); + +struct SvodDeviceDescriptor { + uint8_t descriptorLength; + uint8_t blockCacheElementCount; + uint8_t workerThreadProcessor; + uint8_t workerThreadPriority; + uint8_t firstFragmentHashEntry[0x14]; + union { + uint8_t asByte; + struct { + uint8_t mustBeZeroForFutureUsage : 6; + uint8_t enhancedGdfLayout : 1; + uint8_t zeroForDownlevelClients : 1; + } bits; + } features; + uint8_t numDataBlocksRaw[3]; + uint8_t startDataBlockRaw[3]; + uint8_t reserved[5]; +}; +static_assert(sizeof(SvodDeviceDescriptor) == 0x24); + +struct SvodDirectoryEntry { + uint16_t nodeL; + uint16_t nodeR; + uint32_t dataBlock; + uint32_t length; + uint8_t attributes; + uint8_t nameLength; +}; +static_assert(sizeof(SvodDirectoryEntry) == 0xE); + +struct XContentMetadata +{ + be contentType; + be metadataVersion; + be contentSize; + uint8_t executionInfo[24]; + uint8_t consoleId[5]; + be profileId; + + union { + StfsVolumeDescriptor stfsVolumeDescriptor; + SvodDeviceDescriptor svodDeviceDescriptor; + }; + + be dataFileCount; + be dataFileSize; + be volumeType; + be onlineCreator; + be category; +}; +static_assert(sizeof(XContentMetadata) == 0x75); + +#pragma pack(pop) + +struct XContentContainerHeader +{ + XContentHeader contentHeader; + XContentMetadata contentMetadata; +}; + +const uint32_t StfsBlockSize = 0x1000; +const uint32_t StfsBlocksHashLevelAmount = 3; +const uint32_t StfsBlocksPerHashLevel[StfsBlocksHashLevelAmount] = { 170, 28900, 4913000 }; +const uint32_t StfsEndOfChain = 0xFFFFFF; +const uint32_t StfsEntriesPerDirectoryBlock = StfsBlockSize / sizeof(StfsDirectoryEntry); + +uint32_t parseUint24(const uint8_t *bytes) { + return bytes[0] | (bytes[1] << 8U) | (bytes[2] << 16U); +} + +size_t blockIndexToOffset(uint64_t baseOffset, uint64_t blockIndex) +{ + uint64_t block = blockIndex; + for (uint32_t i = 0; i < StfsBlocksHashLevelAmount; i++) + { + uint32_t levelBase = StfsBlocksPerHashLevel[i]; + block += ((blockIndex + levelBase) / levelBase); + if (blockIndex < levelBase) + { + break; + } + } + + return baseOffset + (block << 12); +} + +uint32_t blockIndexToHashBlockNumber(uint32_t blockIndex) { + if (blockIndex < StfsBlocksPerHashLevel[0]) + { + return 0; + } + + uint32_t block = (blockIndex / StfsBlocksPerHashLevel[0]) * (StfsBlocksPerHashLevel[0] + 1); + block += ((blockIndex / StfsBlocksPerHashLevel[1]) + 1); + if (blockIndex < StfsBlocksPerHashLevel[1]) + { + return block; + } + + return block + 1; +} + +size_t blockIndexToHashBlockOffset(uint64_t baseOffset, uint32_t blockIndex) +{ + size_t blockNumber = blockIndexToHashBlockNumber(blockIndex); + return baseOffset + (blockNumber << 12); +} + +const StfsHashEntry *hashEntryFromBlockIndex(const uint8_t *fileData, uint64_t baseOffset, uint64_t blockIndex) +{ + size_t hashOffset = blockIndexToHashBlockOffset(baseOffset, blockIndex); + const StfsHashTable *hashTable = (const StfsHashTable *)(&fileData[hashOffset]); + return &hashTable->entries[blockIndex % StfsBlocksPerHashLevel[0]]; +} + +void blockToOffsetAndFile(SvodLayoutType svodLayoutType, size_t svodStartDataBlock, size_t svodBaseOffset, size_t block, size_t &outOffset, size_t &outFileIndex) +{ + const size_t BlockSize = 0x800; + const size_t HashBlockSize = 0x1000; + const size_t BlocksPerL0Hash = 0x198; + const size_t HashesPerL1Hash = 0xA1C4; + const size_t BlocksPerFile = 0x14388; + const size_t MaxFileSize = 0xA290000; + size_t trueBlock = block - (svodStartDataBlock * 2); + if (svodLayoutType == SvodLayoutType::EnhancedGDF) + { + trueBlock += 0x2; + } + + size_t fileBlock = trueBlock % BlocksPerFile; + outFileIndex = trueBlock / BlocksPerFile; + + size_t offset = 0; + size_t level0TableCount = (fileBlock / BlocksPerL0Hash) + 1; + offset += level0TableCount * HashBlockSize; + + size_t level1TableCount = (level0TableCount / HashesPerL1Hash) + 1; + offset += level1TableCount * HashBlockSize; + + if (svodLayoutType == SvodLayoutType::SingleFile) + { + offset += svodBaseOffset; + } + + outOffset = (fileBlock * BlockSize) + offset; + if (outOffset >= MaxFileSize) + { + outOffset = (outOffset % MaxFileSize) + 0x2000; + outFileIndex++; + } +} + +XContentFileSystem::XContentFileSystem(const std::filesystem::path &contentPath) +{ + mappedFiles.emplace_back(); + + MemoryMappedFile &rootMappedFile = mappedFiles.back(); + rootMappedFile.open(contentPath); + if (!rootMappedFile.isOpen()) + { + return; + } + + const uint8_t *rootMappedFileData = rootMappedFile.data(); + if (sizeof(XContentContainerHeader) > rootMappedFile.size()) + { + mappedFiles.clear(); + return; + } + + XContentContainerHeader contentContainerHeader = *(const XContentContainerHeader *)(rootMappedFileData); + XContentPackageType packageType = XContentPackageType(contentContainerHeader.contentHeader.magic.get()); + if (packageType != XContentPackageType::CON && packageType != XContentPackageType::LIVE && packageType != XContentPackageType::PIRS) + { + mappedFiles.clear(); + return; + } + + const XContentMetadata &metadata = contentContainerHeader.contentMetadata; + volumeType = XContentVolumeType(metadata.volumeType.get()); + if (volumeType == XContentVolumeType::STFS) + { + const StfsVolumeDescriptor &descriptor = metadata.stfsVolumeDescriptor; + if (descriptor.descriptorLength != sizeof(StfsVolumeDescriptor) || !descriptor.flags.bits.readOnlyFormat) + { + mappedFiles.clear(); + return; + } + + baseOffset = ((contentContainerHeader.contentHeader.headerSize + StfsBlockSize - 1) / StfsBlockSize) * StfsBlockSize; + + uint32_t entryCount = 0; + uint32_t tableBlockIndex = parseUint24(descriptor.fileTableBlockNumberRaw); + uint32_t tableBlockCount = descriptor.fileTableBlockCount; + std::map directoryNames; + for (uint32_t i = 0; i < tableBlockCount; i++) + { + size_t offset = blockIndexToOffset(baseOffset, tableBlockIndex); + if (offset + sizeof(StfsDirectoryBlock) > rootMappedFile.size()) + { + mappedFiles.clear(); + return; + } + + StfsDirectoryBlock *directoryBlock = (StfsDirectoryBlock *)(&rootMappedFileData[offset]); + for (uint32_t j = 0; j < StfsEntriesPerDirectoryBlock; j++) + { + const StfsDirectoryEntry &directoryEntry = directoryBlock->entries[j]; + if (directoryEntry.name[0] == '\0') + { + break; + } + + std::string fileNameBase = directoryNames[directoryEntry.directoryIndex]; + std::string fileName(directoryEntry.name, directoryEntry.flags.nameLength & 0x3F); + if (directoryEntry.flags.directory) + { + directoryNames[entryCount++] = fileNameBase + fileName + "/"; + continue; + } + + uint32_t fileBlockIndex = parseUint24(directoryEntry.startBlockNumberRaw); + uint32_t fileBlockCount = parseUint24(directoryEntry.allocatedDataBlocksRaw); + fileMap[fileNameBase + fileName] = { directoryEntry.length, fileBlockIndex, fileBlockCount }; + entryCount++; + } + + const StfsHashEntry *hashEntry = hashEntryFromBlockIndex(rootMappedFileData, baseOffset, tableBlockIndex); + tableBlockIndex = hashEntry->infoRaw & 0xFFFFFF; + if (tableBlockIndex == StfsEndOfChain) + { + break; + } + } + } + else if (volumeType == XContentVolumeType::SVOD) + { + mappedFiles.clear(); + + // Close the root file and open all the files inside the directory with the same name instead. + std::filesystem::path dataDirectory(contentPath.u8string() + u8".data"); + if (!std::filesystem::is_directory(dataDirectory)) + { + return; + } + + // Find all data files inside the directory. + std::set orderedPaths; + for (auto &entry : std::filesystem::directory_iterator(dataDirectory)) + { + if (!entry.is_regular_file()) + { + continue; + } + + orderedPaths.emplace(entry.path()); + } + + // Memory map all the files that were found. + for (auto &path : orderedPaths) + { + mappedFiles.emplace_back(); + if (!mappedFiles.back().open(path)) + { + mappedFiles.clear(); + return; + } + } + + if (mappedFiles.empty()) + { + return; + } + + // Determine the layout of the SVOD from the first file. + MemoryMappedFile &firstMappedFile = mappedFiles.front(); + const uint8_t *firstMappedFileData = firstMappedFile.data(); + const char *RefMagic = "MICROSOFT*XBOX*MEDIA"; + size_t RefXSFMagicOffset = 0x12000; + size_t SingleFileMagicOffset = 0xD000; + if (metadata.svodDeviceDescriptor.features.bits.enhancedGdfLayout) + { + size_t EGDFMagicOffset = 0x2000; + if (EGDFMagicOffset >= firstMappedFile.size() || std::memcmp(&firstMappedFileData[EGDFMagicOffset], RefMagic, strlen(RefMagic)) != 0) + { + mappedFiles.clear(); + return; + } + + svodBaseOffset = 0; + svodMagicOffset = EGDFMagicOffset; + svodLayoutType = SvodLayoutType::EnhancedGDF; + } + else if (RefXSFMagicOffset < firstMappedFile.size() && std::memcmp(&firstMappedFileData[RefXSFMagicOffset], RefMagic, strlen(RefMagic)) == 0) + { + const char *XSFMagic = "XSF"; + size_t XSFMagicOffset = 0x2000; + svodBaseOffset = 0x10000; + svodMagicOffset = 0x12000; + + if (std::memcmp(&firstMappedFileData[XSFMagicOffset], XSFMagic, strlen(XSFMagic)) == 0) + { + svodLayoutType = SvodLayoutType::XSF; + } + else + { + svodLayoutType = SvodLayoutType::Unknown; + } + } + else if (SingleFileMagicOffset < firstMappedFile.size() && std::memcmp(&firstMappedFileData[SingleFileMagicOffset], RefMagic, strlen(RefMagic)) == 0) + { + svodBaseOffset = 0xB000; + svodMagicOffset = 0xD000; + svodLayoutType = SvodLayoutType::SingleFile; + } + else { + mappedFiles.clear(); + return; + } + + svodStartDataBlock = parseUint24(metadata.svodDeviceDescriptor.startDataBlockRaw); + + struct IterationStep + { + std::string fileNameBase; + uint32_t blockIndex = 0; + uint32_t ordinalIndex = 0; + + IterationStep() = default; + IterationStep(std::string fileNameBase, uint32_t blockIndex, uint32_t ordinalIndex) : fileNameBase(fileNameBase), blockIndex(blockIndex), ordinalIndex(ordinalIndex) { } + }; + + std::stack iterationStack; + uint32_t rootBlock = *(uint32_t *)(&firstMappedFileData[svodMagicOffset + 0x14]); + iterationStack.emplace("", rootBlock, 0); + + IterationStep step; + size_t fileOffset, fileIndex; + char fileName[256]; + const uint8_t FileAttributeDirectory = 0x10; + while (!iterationStack.empty()) + { + step = iterationStack.top(); + iterationStack.pop(); + + size_t ordinalOffset = step.ordinalIndex * 0x4; + size_t blockOffset = ordinalOffset / 0x800; + size_t trueOrdinalOffset = ordinalOffset % 0x800; + blockToOffsetAndFile(svodLayoutType, svodStartDataBlock, svodBaseOffset, step.blockIndex + blockOffset, fileOffset, fileIndex); + fileOffset += trueOrdinalOffset; + if (fileIndex >= mappedFiles.size()) + { + mappedFiles.clear(); + return; + } + + const MemoryMappedFile &mappedFile = mappedFiles[fileIndex]; + if ((fileOffset + sizeof(SvodDirectoryEntry)) > mappedFile.size()) + { + mappedFiles.clear(); + return; + } + + const uint8_t *mappedFileData = mappedFile.data(); + const SvodDirectoryEntry *directoryEntry = (const SvodDirectoryEntry *)(&mappedFileData[fileOffset]); + size_t nameOffset = fileOffset + sizeof(SvodDirectoryEntry); + if ((nameOffset + directoryEntry->nameLength) > mappedFile.size()) + { + mappedFiles.clear(); + return; + } + + memcpy(fileName, &mappedFileData[nameOffset], directoryEntry->nameLength); + fileName[directoryEntry->nameLength] = '\0'; + + if (directoryEntry->nodeL) + { + iterationStack.emplace(step.fileNameBase, step.blockIndex, directoryEntry->nodeL); + } + + if (directoryEntry->nodeR) + { + iterationStack.emplace(step.fileNameBase, step.blockIndex, directoryEntry->nodeR); + } + + std::string fileNameUTF8 = step.fileNameBase + fileName; + if (directoryEntry->attributes & FileAttributeDirectory) + { + if (directoryEntry->length > 0) + { + iterationStack.emplace(fileNameUTF8 + "/", directoryEntry->dataBlock, 0); + } + } + else + { + fileMap[fileNameUTF8] = { directoryEntry->length, directoryEntry->dataBlock, 0 }; + } + } + } + else + { + mappedFiles.clear(); + } +} + +bool XContentFileSystem::load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const +{ + auto it = fileMap.find(path); + if (it != fileMap.end()) + { + if (fileDataMaxByteCount < it->second.size) + { + return false; + } + + if (volumeType == XContentVolumeType::STFS) + { + const MemoryMappedFile &rootMappedFile = mappedFiles.back(); + const uint8_t *rootMappedFileData = rootMappedFile.data(); + size_t fileDataOffset = 0; + size_t remainingSize = it->second.size; + uint32_t fileBlockIndex = it->second.blockIndex; + for (uint32_t i = 0; i < it->second.blockCount && fileBlockIndex != StfsEndOfChain; i++) + { + size_t blockSize = std::min(size_t(StfsBlockSize), remainingSize); + size_t blockOffset = blockIndexToOffset(baseOffset, fileBlockIndex); + if (blockOffset + blockSize > rootMappedFile.size()) + { + return false; + } + + memcpy(&fileData[fileDataOffset], &rootMappedFileData[blockOffset], blockSize); + + const StfsHashEntry *hashEntry = hashEntryFromBlockIndex(rootMappedFileData, baseOffset, fileBlockIndex); + fileBlockIndex = hashEntry->infoRaw & 0xFFFFFF; + fileDataOffset += blockSize; + remainingSize -= blockSize; + } + + return remainingSize == 0; + } + else if (volumeType == XContentVolumeType::SVOD) + { + size_t fileDataOffset = 0; + size_t remainingSize = it->second.size; + size_t currentBlock = it->second.blockIndex; + while (remainingSize > 0) + { + size_t blockFileOffset, blockFileIndex; + blockToOffsetAndFile(svodLayoutType, svodStartDataBlock, svodBaseOffset, currentBlock, blockFileOffset, blockFileIndex); + if (blockFileIndex >= mappedFiles.size()) + { + return false; + } + + const MemoryMappedFile &mappedFile = mappedFiles[blockFileIndex]; + const uint8_t *mappedFileData = mappedFile.data(); + size_t blockSize = std::min(size_t(0x800), remainingSize); + if (blockFileOffset + blockSize > mappedFile.size()) + { + return false; + } + + memcpy(&fileData[fileDataOffset], &mappedFileData[blockFileOffset], blockSize); + + fileDataOffset += blockSize; + remainingSize -= blockSize; + currentBlock++; + } + + return remainingSize == 0; + } + else + { + return false; + } + } + else + { + return false; + } +} + +size_t XContentFileSystem::getSize(const std::string &path) const +{ + auto it = fileMap.find(path); + if (it != fileMap.end()) + { + return it->second.size; + } + else + { + return 0; + } +} + +bool XContentFileSystem::exists(const std::string &path) const +{ + return fileMap.find(path) != fileMap.end(); +} + +bool XContentFileSystem::empty() const +{ + return mappedFiles.empty(); +} + +std::unique_ptr XContentFileSystem::create(const std::filesystem::path &contentPath) +{ + std::unique_ptr xContentFS = std::make_unique(contentPath); + if (!xContentFS->empty()) + { + return xContentFS; + } + else + { + return nullptr; + } +} + +bool XContentFileSystem::check(const std::filesystem::path &contentPath) +{ + std::ifstream contentStream(contentPath, std::ios::binary); + if (!contentStream.is_open()) + { + return false; + } + + uint32_t packageTypeUint = 0; + contentStream.read((char *)(&packageTypeUint), sizeof(uint32_t)); + packageTypeUint = std::byteswap(packageTypeUint); + XContentPackageType packageType = XContentPackageType(packageTypeUint); + return packageType == XContentPackageType::CON || packageType == XContentPackageType::LIVE || packageType == XContentPackageType::PIRS; +} diff --git a/UnleashedRecomp/install/xcontent_file_system.h b/UnleashedRecomp/install/xcontent_file_system.h new file mode 100644 index 00000000..4247cd56 --- /dev/null +++ b/UnleashedRecomp/install/xcontent_file_system.h @@ -0,0 +1,61 @@ +// Referenced from: https://github.com/xenia-canary/xenia-canary/blob/canary_experimental/src/xenia/vfs/devices/xcontent_container_device.cc + +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2023 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#pragma once + +#include +#include + +#include "virtual_file_system.h" + +#include "memory_mapped_file.h" + +enum class XContentVolumeType +{ + STFS = 0, + SVOD = 1, +}; + +enum class SvodLayoutType +{ + Unknown = 0x0, + EnhancedGDF = 0x1, + XSF = 0x2, + SingleFile = 0x4, +}; + +struct XContentFileSystem : VirtualFileSystem +{ + struct File + { + size_t size = 0; + uint32_t blockIndex = 0; + uint32_t blockCount = 0; + }; + + XContentVolumeType volumeType = XContentVolumeType::STFS; + SvodLayoutType svodLayoutType = SvodLayoutType::Unknown; + size_t svodStartDataBlock = 0; + size_t svodBaseOffset = 0; + size_t svodMagicOffset = 0; + std::vector mappedFiles; + uint64_t baseOffset = 0; + std::map fileMap; + + XContentFileSystem(const std::filesystem::path &contentPath); + bool load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const override; + size_t getSize(const std::string &path) const override; + bool exists(const std::string &path) const override; + bool empty() const; + + static std::unique_ptr create(const std::filesystem::path &contentPath); + static bool check(const std::filesystem::path &contentPath); +}; diff --git a/UnleashedRecomp/install/xex_patcher.cpp b/UnleashedRecomp/install/xex_patcher.cpp new file mode 100644 index 00000000..8d2ea1b6 --- /dev/null +++ b/UnleashedRecomp/install/xex_patcher.cpp @@ -0,0 +1,693 @@ +// Referenced from: https://github.com/xenia-canary/xenia-canary/blob/canary_experimental/src/xenia/cpu/xex_module.cc + +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2023 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xex_patcher.h" + +#include +#include + +#include +#include +#include +#include + +#include "memory_mapped_file.h" + +enum Xex2ModuleFlags +{ + XEX_MODULE_MODULE_PATCH = 0x10, + XEX_MODULE_PATCH_FULL = 0x20, + XEX_MODULE_PATCH_DELTA = 0x40, +}; + +enum Xex2HeaderKeys +{ + XEX_HEADER_FILE_FORMAT_INFO = 0x3FF, + XEX_HEADER_DELTA_PATCH_DESCRIPTOR = 0x5FF, +}; + +enum Xex2EncryptionType +{ + XEX_ENCRYPTION_NONE = 0, + XEX_ENCRYPTION_NORMAL = 1, +}; + +enum Xex2CompressionType +{ + XEX_COMPRESSION_NONE = 0, + XEX_COMPRESSION_BASIC = 1, + XEX_COMPRESSION_NORMAL = 2, + XEX_COMPRESSION_DELTA = 3, +}; + +enum Xex2SectionType +{ + XEX_SECTION_CODE = 1, + XEX_SECTION_DATA = 2, + XEX_SECTION_READONLY_DATA = 3, +}; + +struct Xex2OptHeader +{ + be key; + + union + { + be value; + be offset; + }; +}; + +struct Xex2Header +{ + be magic; + be moduleFlags; + be headerSize; + be reserved; + be securityOffset; + be headerCount; + Xex2OptHeader headers[1]; +}; + +struct Xex2PageDescriptor +{ + union + { + // Must be endian-swapped before reading the bitfield. + uint32_t beValue; + struct + { + uint32_t info : 4; + uint32_t pageCount : 28; + }; + }; + + char dataDigest[0x14]; +}; + +struct Xex2SecurityInfo +{ + be headerSize; + be imageSize; + char rsaSignature[0x100]; + be unknown; + be imageFlags; + be loadAddress; + char sectionDigest[0x14]; + be importTableCount; + char importTableDigest[0x14]; + char xgd2MediaId[0x10]; + char aesKey[0x10]; + be exportTable; + char headerDigest[0x14]; + be region; + be allowedMediaTypes; + be pageDescriptorCount; + Xex2PageDescriptor pageDescriptors[1]; +}; + +struct Xex2DeltaPatch +{ + be oldAddress; + be newAddress; + be uncompressedLength; + be compressedLength; + char patchData[1]; +}; + +struct Xex2OptDeltaPatchDescriptor +{ + be size; + be targetVersionValue; + be sourceVersionValue; + uint8_t digestSource[0x14]; + uint8_t imageKeySource[0x10]; + be sizeOfTargetHeaders; + be deltaHeadersSourceOffset; + be deltaHeadersSourceSize; + be deltaHeadersTargetOffset; + be deltaImageSourceOffset; + be deltaImageSourceSize; + be deltaImageTargetOffset; + Xex2DeltaPatch info; +}; + +struct Xex2FileBasicCompressionBlock +{ + be dataSize; + be zeroSize; +}; + +struct Xex2FileBasicCompressionInfo +{ + Xex2FileBasicCompressionBlock firstBlock; +}; + +struct Xex2CompressedBlockInfo +{ + be blockSize; + uint8_t blockHash[20]; +}; + +struct Xex2FileNormalCompressionInfo +{ + be windowSize; + Xex2CompressedBlockInfo firstBlock; +}; + +struct Xex2OptFileFormatInfo +{ + be infoSize; + be encryptionType; + be compressionType; + union + { + Xex2FileBasicCompressionInfo basic; + Xex2FileNormalCompressionInfo normal; + } compressionInfo; +}; + +static const void *getOptHeaderPtr(std::span moduleBytes, uint32_t headerKey) +{ + if ((headerKey & 0xFF) == 0) + { + assert(false && "Wrong type of method for this key. Expected return value is a number."); + return nullptr; + } + + const Xex2Header *xex2Header = (const Xex2Header *)(moduleBytes.data()); + for (uint32_t i = 0; i < xex2Header->headerCount; i++) + { + const Xex2OptHeader &optHeader = xex2Header->headers[i]; + if (optHeader.key == headerKey) + { + if ((headerKey & 0xFF) == 1) + { + return &optHeader.value; + } + else + { + return &moduleBytes.data()[optHeader.offset]; + } + } + } + + return nullptr; +} + +struct mspack_memory_file +{ + mspack_system sys; + void *buffer; + size_t bufferSize; + size_t offset; +}; + +static mspack_memory_file *mspack_memory_open(mspack_system *sys, void *buffer, size_t bufferSize) +{ + assert(bufferSize < INT_MAX); + + if (bufferSize >= INT_MAX) + { + return nullptr; + } + + mspack_memory_file *memoryFile = (mspack_memory_file *)(std::calloc(1, sizeof(mspack_memory_file))); + if (memoryFile == nullptr) + { + return memoryFile; + } + + memoryFile->buffer = buffer; + memoryFile->bufferSize = bufferSize; + memoryFile->offset = 0; + return memoryFile; +} + +static void mspack_memory_close(mspack_memory_file *file) +{ + std::free(file); +} + +static int mspack_memory_read(mspack_file *file, void *buffer, int chars) +{ + mspack_memory_file *memoryFile = (mspack_memory_file *)(file); + const size_t remaining = memoryFile->bufferSize - memoryFile->offset; + const size_t total = std::min(size_t(chars), remaining); + std::memcpy(buffer, (uint8_t *)(memoryFile->buffer) + memoryFile->offset, total); + memoryFile->offset += total; + return int(total); +} + +static int mspack_memory_write(mspack_file *file, void *buffer, int chars) +{ + mspack_memory_file *memoryFile = (mspack_memory_file *)(file); + const size_t remaining = memoryFile->bufferSize - memoryFile->offset; + const size_t total = std::min(size_t(chars), remaining); + std::memcpy((uint8_t *)(memoryFile->buffer) + memoryFile->offset, buffer, total); + memoryFile->offset += total; + return int(total); +} + +static void *mspack_memory_alloc(mspack_system *sys, size_t chars) +{ + return std::calloc(chars, 1); +} + +static void mspack_memory_free(void *ptr) +{ + std::free(ptr); +} + +static void mspack_memory_copy(void *src, void *dest, size_t chars) +{ + std::memcpy(dest, src, chars); +} + +static mspack_system *mspack_memory_sys_create() +{ + auto sys = (mspack_system *)(std::calloc(1, sizeof(mspack_system))); + if (!sys) + { + return nullptr; + } + + sys->read = mspack_memory_read; + sys->write = mspack_memory_write; + sys->alloc = mspack_memory_alloc; + sys->free = mspack_memory_free; + sys->copy = mspack_memory_copy; + return sys; +} + +static void mspack_memory_sys_destroy(struct mspack_system *sys) +{ + free(sys); +} + +#if defined(_WIN32) +inline bool bitScanForward(uint32_t v, uint32_t *outFirstSetIndex) +{ + return _BitScanForward((unsigned long *)(outFirstSetIndex), v) != 0; +} + +inline bool bitScanForward(uint64_t v, uint32_t *outFirstSetIndex) +{ + return _BitScanForward64((unsigned long *)(outFirstSetIndex), v) != 0; +} + +#else +inline bool bitScanForward(uint32_t v, uint32_t *outFirstSetIndex) +{ + int i = ffs(v); + *out_first_set_index = i - 1; + return i != 0; +} + +inline bool bitScanForward(uint64_t v, uint32_t *outFirstSetIndex) +{ + int i = __builtin_ffsll(v); + *out_first_set_index = i - 1; + return i != 0; +} +#endif + +static int lzxDecompress(const void *lzxData, size_t lzxLength, void *dst, size_t dstLength, uint32_t windowSize, void *windowData, size_t windowDataLength) +{ + int resultCode = 1; + uint32_t windowBits; + if (!bitScanForward(windowSize, &windowBits)) { + return resultCode; + } + + mspack_system *sys = mspack_memory_sys_create(); + mspack_memory_file *lzxSrc = mspack_memory_open(sys, (void *)(lzxData), lzxLength); + mspack_memory_file *lzxDst = mspack_memory_open(sys, dst, dstLength); + lzxd_stream *lzxd = lzxd_init(sys, (mspack_file *)(lzxSrc), (mspack_file *)(lzxDst), windowBits, 0, 0x8000, dstLength, 0); + if (lzxd != nullptr) { + if (windowData != nullptr) { + size_t paddingLength = windowSize - windowDataLength; + std::memset(&lzxd->window[0], 0, paddingLength); + std::memcpy(&lzxd->window[paddingLength], windowData, windowDataLength); + lzxd->ref_data_size = windowSize; + } + + resultCode = lzxd_decompress(lzxd, dstLength); + lzxd_free(lzxd); + } + + if (lzxSrc) { + mspack_memory_close(lzxSrc); + } + + if (lzxDst) { + mspack_memory_close(lzxDst); + } + + if (sys) { + mspack_memory_sys_destroy(sys); + } + + return resultCode; +} + +static int lzxDeltaApplyPatch(const Xex2DeltaPatch *deltaPatch, uint32_t patchLength, uint32_t windowSize, uint8_t *dstData) +{ + const void *patchEnd = (const uint8_t *)(deltaPatch) + patchLength; + const Xex2DeltaPatch *curPatch = deltaPatch; + while (patchEnd > curPatch) + { + int patchSize = -4; + if (curPatch->compressedLength == 0 && curPatch->uncompressedLength == 0 && curPatch->newAddress == 0 && curPatch->oldAddress == 0) + { + // End of patch. + break; + } + + switch (curPatch->compressedLength) + { + case 0: + // Set the data to zeroes. + std::memset(&dstData[curPatch->newAddress], 0, curPatch->uncompressedLength); + break; + case 1: + // Move the data. + std::memcpy(&dstData[curPatch->newAddress], &dstData[curPatch->oldAddress], curPatch->uncompressedLength); + break; + default: + // Decompress the data into the destination. + patchSize = curPatch->compressedLength - 4; + int result = lzxDecompress(curPatch->patchData, curPatch->compressedLength, &dstData[curPatch->newAddress], curPatch->uncompressedLength, windowSize, &dstData[curPatch->oldAddress], curPatch->uncompressedLength); + if (result != 0) + { + return result; + } + + break; + } + + curPatch++; + curPatch = (const Xex2DeltaPatch *)((const uint8_t *)(curPatch) + patchSize); + } + + return 0; +} + +XexPatcher::Result XexPatcher::apply(std::span xexBytes, std::span patchBytes, std::vector &outBytes, bool skipData) +{ + // Validate headers. + static const char Xex2Magic[] = "XEX2"; + const Xex2Header *xexHeader = (const Xex2Header *)(xexBytes.data()); + if (memcmp(xexBytes.data(), Xex2Magic, 4) != 0) + { + return Result::XexFileInvalid; + } + + const Xex2Header *patchHeader = (const Xex2Header *)(patchBytes.data()); + if (memcmp(patchBytes.data(), Xex2Magic, 4) != 0) + { + return Result::PatchFileInvalid; + } + + if ((patchHeader->moduleFlags & (XEX_MODULE_MODULE_PATCH | XEX_MODULE_PATCH_DELTA | XEX_MODULE_PATCH_FULL)) == 0) + { + return Result::PatchFileInvalid; + } + + // Validate patch. + const Xex2OptDeltaPatchDescriptor *patchDescriptor = (const Xex2OptDeltaPatchDescriptor *)(getOptHeaderPtr(patchBytes, XEX_HEADER_DELTA_PATCH_DESCRIPTOR)); + if (patchDescriptor == nullptr) + { + return Result::PatchFileInvalid; + } + + const Xex2OptFileFormatInfo *patchFileFormatInfo = (const Xex2OptFileFormatInfo *)(getOptHeaderPtr(patchBytes, XEX_HEADER_FILE_FORMAT_INFO)); + if (patchFileFormatInfo == nullptr) + { + return Result::PatchFileInvalid; + } + + if (patchFileFormatInfo->compressionType != XEX_COMPRESSION_DELTA) + { + return Result::PatchFileInvalid; + } + + if (patchDescriptor->deltaHeadersSourceOffset > xexHeader->headerSize) + { + return Result::PatchIncompatible; + } + + if (patchDescriptor->deltaHeadersSourceSize > (xexHeader->headerSize - patchDescriptor->deltaHeadersSourceOffset)) + { + return Result::PatchIncompatible; + } + + if (patchDescriptor->deltaHeadersTargetOffset > patchDescriptor->sizeOfTargetHeaders) + { + return Result::PatchIncompatible; + } + + uint32_t deltaTargetSize = patchDescriptor->sizeOfTargetHeaders - patchDescriptor->deltaHeadersTargetOffset; + if (patchDescriptor->deltaHeadersSourceSize > deltaTargetSize) + { + return Result::PatchIncompatible; + } + + // Apply patch. + uint32_t headerTargetSize = patchDescriptor->sizeOfTargetHeaders; + if (headerTargetSize == 0) + { + headerTargetSize = patchDescriptor->deltaHeadersTargetOffset + patchDescriptor->deltaHeadersSourceSize; + } + + // Create the bytes for the new XEX header. Copy over the existing data. + uint32_t newXexHeaderSize = std::max(headerTargetSize, xexHeader->headerSize.get()); + outBytes.resize(newXexHeaderSize); + memset(outBytes.data(), 0, newXexHeaderSize); + memcpy(outBytes.data(), xexBytes.data(), headerTargetSize); + + Xex2Header *newXexHeader = (Xex2Header *)(outBytes.data()); + if (patchDescriptor->deltaHeadersSourceOffset > 0) + { + memcpy(&outBytes[patchDescriptor->deltaHeadersTargetOffset], &outBytes[patchDescriptor->deltaHeadersSourceOffset], patchDescriptor->deltaHeadersSourceSize); + } + + int resultCode = lzxDeltaApplyPatch(&patchDescriptor->info, patchDescriptor->size, patchFileFormatInfo->compressionInfo.normal.windowSize, outBytes.data()); + if (resultCode != 0) + { + return Result::PatchFailed; + } + + // Make the header the specified size by the patch. + outBytes.resize(headerTargetSize); + newXexHeader = (Xex2Header *)(outBytes.data()); + + // Copy the rest of the data. + const Xex2SecurityInfo *newSecurityInfo = (const Xex2SecurityInfo *)(&outBytes[newXexHeader->securityOffset]); + outBytes.resize(outBytes.size() + newSecurityInfo->imageSize); + memset(&outBytes[headerTargetSize], 0, outBytes.size() - headerTargetSize); + memcpy(&outBytes[headerTargetSize], &xexBytes[xexHeader->headerSize], xexBytes.size() - xexHeader->headerSize); + newXexHeader = (Xex2Header *)(outBytes.data()); + newSecurityInfo = (const Xex2SecurityInfo *)(&outBytes[newXexHeader->securityOffset]); + + // Decrypt the keys and validate that the patch is compatible with the base file. + static const uint32_t KeySize = 16; + static const uint8_t Xex2RetailKey[16] = { 0x20, 0xB1, 0x85, 0xA5, 0x9D, 0x28, 0xFD, 0xC3, 0x40, 0x58, 0x3F, 0xBB, 0x08, 0x96, 0xBF, 0x91 }; + static const uint8_t AESBlankIV[AES_BLOCKLEN] = {}; + const Xex2SecurityInfo *originalSecurityInfo = (const Xex2SecurityInfo *)(&xexBytes[xexHeader->securityOffset]); + const Xex2SecurityInfo *patchSecurityInfo = (const Xex2SecurityInfo *)(&patchBytes[patchHeader->securityOffset]); + uint8_t decryptedOriginalKey[KeySize]; + uint8_t decryptedNewKey[KeySize]; + uint8_t decryptedPatchKey[KeySize]; + uint8_t decrpytedImageKeySource[KeySize]; + memcpy(decryptedOriginalKey, originalSecurityInfo->aesKey, KeySize); + memcpy(decryptedNewKey, newSecurityInfo->aesKey, KeySize); + memcpy(decryptedPatchKey, patchSecurityInfo->aesKey, KeySize); + memcpy(decrpytedImageKeySource, patchDescriptor->imageKeySource, KeySize); + + AES_ctx aesContext; + AES_init_ctx_iv(&aesContext, Xex2RetailKey, AESBlankIV); + AES_CBC_decrypt_buffer(&aesContext, decryptedOriginalKey, KeySize); + + AES_ctx_set_iv(&aesContext, AESBlankIV); + AES_CBC_decrypt_buffer(&aesContext, decryptedNewKey, KeySize); + + AES_init_ctx_iv(&aesContext, decryptedNewKey, AESBlankIV); + AES_CBC_decrypt_buffer(&aesContext, decryptedPatchKey, KeySize); + + AES_ctx_set_iv(&aesContext, AESBlankIV); + AES_CBC_decrypt_buffer(&aesContext, decrpytedImageKeySource, KeySize); + + // Validate the patch's key matches the one from the original XEX. + if (memcmp(decrpytedImageKeySource, decryptedOriginalKey, KeySize) != 0) + { + return Result::PatchIncompatible; + } + + // Don't process the rest of the patch. + if (skipData) + { + return Result::Success; + } + + // Decrypt base XEX if necessary. + const Xex2OptFileFormatInfo *fileFormatInfo = (const Xex2OptFileFormatInfo *)(getOptHeaderPtr(xexBytes, XEX_HEADER_FILE_FORMAT_INFO)); + if (fileFormatInfo == nullptr) + { + return Result::XexFileInvalid; + } + + if (fileFormatInfo->encryptionType == XEX_ENCRYPTION_NORMAL) + { + AES_init_ctx_iv(&aesContext, decryptedOriginalKey, AESBlankIV); + AES_CBC_decrypt_buffer(&aesContext, &outBytes[headerTargetSize], xexBytes.size() - xexHeader->headerSize); + } + else if (fileFormatInfo->encryptionType != XEX_ENCRYPTION_NONE) + { + return Result::XexFileInvalid; + } + + // Decompress base XEX if necessary. + if (fileFormatInfo->compressionType == XEX_COMPRESSION_BASIC) + { + const Xex2FileBasicCompressionBlock *blocks = &fileFormatInfo->compressionInfo.basic.firstBlock; + int32_t numBlocks = (fileFormatInfo->infoSize / sizeof(Xex2FileBasicCompressionBlock)) - 1; + int32_t baseCompressedSize = 0; + int32_t baseImageSize = 0; + for (int32_t i = 0; i < numBlocks; i++) { + baseCompressedSize += blocks[i].dataSize; + baseImageSize += blocks[i].dataSize + blocks[i].zeroSize; + } + + if (outBytes.size() < (headerTargetSize + baseImageSize)) + { + return Result::XexFileInvalid; + } + + // Reverse iteration allows to perform this decompression in place. + uint8_t *srcDataCursor = outBytes.data() + headerTargetSize + baseCompressedSize; + uint8_t *outDataCursor = outBytes.data() + headerTargetSize + baseImageSize; + for (int32_t i = numBlocks - 1; i >= 0; i--) + { + outDataCursor -= blocks[i].zeroSize; + memset(outDataCursor, 0, blocks[i].zeroSize); + outDataCursor -= blocks[i].dataSize; + srcDataCursor -= blocks[i].dataSize; + memmove(outDataCursor, srcDataCursor, blocks[i].dataSize); + } + } + else if (fileFormatInfo->compressionType == XEX_COMPRESSION_NORMAL || fileFormatInfo->compressionType == XEX_COMPRESSION_DELTA) + { + return Result::XexFileUnsupported; + } + else if (fileFormatInfo->compressionType != XEX_COMPRESSION_NONE) + { + return Result::XexFileInvalid; + } + + Xex2OptFileFormatInfo *newFileFormatInfo = (Xex2OptFileFormatInfo *)(getOptHeaderPtr(outBytes, XEX_HEADER_FILE_FORMAT_INFO)); + if (newFileFormatInfo == nullptr) + { + return Result::PatchFailed; + } + + // Update the header to indicate no encryption or compression is used. + newFileFormatInfo->encryptionType = XEX_ENCRYPTION_NONE; + newFileFormatInfo->compressionType = XEX_COMPRESSION_NONE; + + // Copy and decrypt patch data if necessary. + std::vector patchData; + patchData.resize(patchBytes.size() - patchHeader->headerSize); + memcpy(patchData.data(), &patchBytes[patchHeader->headerSize], patchData.size()); + + if (patchFileFormatInfo->encryptionType == XEX_ENCRYPTION_NORMAL) + { + AES_init_ctx_iv(&aesContext, decryptedPatchKey, AESBlankIV); + AES_CBC_decrypt_buffer(&aesContext, patchData.data(), patchData.size()); + } + else if (patchFileFormatInfo->encryptionType != XEX_ENCRYPTION_NONE) + { + return Result::PatchFileInvalid; + } + + const Xex2CompressedBlockInfo *currentBlock = &patchFileFormatInfo->compressionInfo.normal.firstBlock; + uint8_t *outExe = &outBytes[newXexHeader->headerSize]; + if (patchDescriptor->deltaImageSourceOffset > 0) + { + memcpy(&outExe[patchDescriptor->deltaImageTargetOffset], &outExe[patchDescriptor->deltaImageSourceOffset], patchDescriptor->deltaImageSourceSize); + } + + static const uint32_t DigestSize = 20; + uint8_t sha1Digest[DigestSize]; + sha1::SHA1 sha1Context; + uint8_t *patchDataCursor = patchData.data(); + while (currentBlock->blockSize > 0) + { + const Xex2CompressedBlockInfo *nextBlock = (const Xex2CompressedBlockInfo *)(patchDataCursor); + + // Hash and validate the block. + sha1Context.reset(); + sha1Context.processBytes(patchDataCursor, currentBlock->blockSize); + sha1Context.finalize(sha1Digest); + if (memcmp(sha1Digest, currentBlock->blockHash, DigestSize) != 0) + { + return Result::PatchFailed; + } + + patchDataCursor += 24; + + // Apply the block's patch data. + uint32_t blockDataSize = currentBlock->blockSize - 24; + if (lzxDeltaApplyPatch((const Xex2DeltaPatch *)(patchDataCursor), blockDataSize, patchFileFormatInfo->compressionInfo.normal.windowSize, outExe) != 0) + { + return Result::PatchFailed; + } + + patchDataCursor += blockDataSize; + currentBlock = nextBlock; + } + + return Result::Success; +} + +XexPatcher::Result XexPatcher::apply(const std::filesystem::path &baseXexPath, const std::filesystem::path &patchXexPath, const std::filesystem::path &newXexPath) +{ + MemoryMappedFile baseXexFile(baseXexPath); + MemoryMappedFile patchFile(patchXexPath); + if (!baseXexFile.isOpen() || !patchFile.isOpen()) + { + return Result::FileOpenFailed; + } + + std::vector newXexBytes; + Result result = apply({ baseXexFile.data(), baseXexFile.size() }, { patchFile.data(), patchFile.size() }, newXexBytes, false); + if (result != Result::Success) + { + return result; + } + + std::ofstream newXexFile(newXexPath, std::ios::binary); + if (!newXexFile.is_open()) + { + return Result::FileOpenFailed; + } + + newXexFile.write((const char *)(newXexBytes.data()), newXexBytes.size()); + newXexFile.close(); + + if (newXexFile.bad()) + { + std::filesystem::remove(newXexPath); + return Result::FileWriteFailed; + } + + return Result::Success; +} diff --git a/UnleashedRecomp/install/xex_patcher.h b/UnleashedRecomp/install/xex_patcher.h new file mode 100644 index 00000000..c86ed75c --- /dev/null +++ b/UnleashedRecomp/install/xex_patcher.h @@ -0,0 +1,35 @@ +// Referenced from: https://github.com/xenia-canary/xenia-canary/blob/canary_experimental/src/xenia/cpu/xex_module.cc + +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2023 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#pragma once + +#include +#include +#include +#include + +struct XexPatcher +{ + enum class Result { + Success, + FileOpenFailed, + FileWriteFailed, + XexFileUnsupported, + XexFileInvalid, + PatchFileInvalid, + PatchIncompatible, + PatchFailed, + PatchUnsupported + }; + + static Result apply(std::span xexBytes, std::span patchBytes, std::vector &outBytes, bool skipData); + static Result apply(const std::filesystem::path &baseXexPath, const std::filesystem::path &patchXexPath, const std::filesystem::path &newXexPath); +}; diff --git a/UnleashedRecomp/main.cpp b/UnleashedRecomp/main.cpp index 846ed8fe..7ac1e4f1 100644 --- a/UnleashedRecomp/main.cpp +++ b/UnleashedRecomp/main.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #define GAME_XEX_PATH "game:\\default.xex" @@ -96,13 +97,15 @@ uint32_t LdrLoadModule(const char* path) auto format = Xex2FindOptionalHeader(xex, XEX_HEADER_FILE_FORMAT_INFO); auto entry = *Xex2FindOptionalHeader(xex, XEX_HEADER_ENTRY_POINT); ByteSwap(entry); - assert(format->CompressionType >= 1); - if (format->CompressionType == 1) + auto srcData = (char *)xex + xex->SizeOfHeader; + auto destData = (char *)g_memory.Translate(security->ImageBase); + if (format->CompressionType == 0) + { + memcpy(destData, srcData, security->SizeOfImage); + } + else if (format->CompressionType == 1) { - auto srcData = (char*)xex + xex->SizeOfHeader; - auto destData = (char*)g_memory.Translate(security->ImageBase); - auto numBlocks = (format->SizeOfHeader / sizeof(XEX_BASIC_FILE_COMPRESSION_INFO)) - 1; auto blocks = reinterpret_cast(format + 1); @@ -117,6 +120,10 @@ uint32_t LdrLoadModule(const char* path) destData += blocks[i].SizeOfPadding; } } + else + { + assert(false && "Unknown compression type."); + } return entry; } diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index d0b89ccd..9f43e072 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(${SWA_THIRDPARTY_ROOT}/PowerRecomp) -add_subdirectory(${SWA_THIRDPARTY_ROOT}/ShaderRecomp) -add_subdirectory(${SWA_THIRDPARTY_ROOT}/o1heap) +add_subdirectory(${SWA_THIRDPARTY_ROOT}/ShaderRecomp) +add_subdirectory(${SWA_THIRDPARTY_ROOT}/o1heap) +add_subdirectory(${SWA_THIRDPARTY_ROOT}/fshasher) diff --git a/thirdparty/PowerRecomp b/thirdparty/PowerRecomp index 7dd4f91a..675b482e 160000 --- a/thirdparty/PowerRecomp +++ b/thirdparty/PowerRecomp @@ -1 +1 @@ -Subproject commit 7dd4f91ac635b001a56cc7a27af48f0436bbad3f +Subproject commit 675b482ec4852b873590fb999d24b426bade2b3a diff --git a/thirdparty/ShaderRecomp b/thirdparty/ShaderRecomp index f936ed22..30f59860 160000 --- a/thirdparty/ShaderRecomp +++ b/thirdparty/ShaderRecomp @@ -1 +1 @@ -Subproject commit f936ed2212d8291439003eb0c0d8edc0ecafd24d +Subproject commit 30f598604767602e3afce56b947e99dba2b51211 diff --git a/thirdparty/TinySHA1/TinySHA1.hpp b/thirdparty/TinySHA1/TinySHA1.hpp new file mode 100644 index 00000000..2493e88f --- /dev/null +++ b/thirdparty/TinySHA1/TinySHA1.hpp @@ -0,0 +1,223 @@ +/* + * + * TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based + * on the implementation in boost::uuid::details. + * + * SHA1 Wikipedia Page: http://en.wikipedia.org/wiki/SHA-1 + * + * Copyright (c) 2012-22 SAURAV MOHAPATRA + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Taken from https://github.com/mohaps/TinySHA1 + * Modified for use by Xenia + */ +#ifndef _TINY_SHA1_HPP_ +#define _TINY_SHA1_HPP_ + +#include +#include +#include +#include + +namespace sha1 { +class SHA1 { + public: + typedef uint32_t digest32_t[5]; + typedef uint8_t digest8_t[20]; + inline static uint32_t LeftRotate(uint32_t value, size_t count) { + return (value << count) ^ (value >> (32 - count)); + } + SHA1() { reset(); } + virtual ~SHA1() {} + SHA1(const SHA1& s) { *this = s; } + const SHA1& operator=(const SHA1& s) { + memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t)); + memcpy(m_block, s.m_block, 64); + m_blockByteIndex = s.m_blockByteIndex; + m_byteCount = s.m_byteCount; + + return *this; + } + + SHA1& init(const uint32_t digest[5], const uint8_t block[64], + uint32_t count) { + std::memcpy(m_digest, digest, 20); + std::memcpy(m_block, block, count % 64); + m_byteCount = count; + m_blockByteIndex = count % 64; + + return *this; + } + + const uint32_t* getDigest() const { return m_digest; } + const uint8_t* getBlock() const { return m_block; } + size_t getBlockByteIndex() const { return m_blockByteIndex; } + size_t getByteCount() const { return m_byteCount; } + + SHA1& reset() { + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + m_blockByteIndex = 0; + m_byteCount = 0; + return *this; + } + + SHA1& processByte(uint8_t octet) { + this->m_block[this->m_blockByteIndex++] = octet; + ++this->m_byteCount; + if (m_blockByteIndex == 64) { + this->m_blockByteIndex = 0; + processBlock(); + } + + return *this; + } + + SHA1& processBlock(const void* const start, const void* const end) { + const uint8_t* begin = static_cast(start); + const uint8_t* finish = static_cast(end); + while (begin != finish) { + processByte(*begin); + begin++; + } + return *this; + } + + SHA1& processBytes(const void* const data, size_t len) { + const uint8_t* block = static_cast(data); + processBlock(block, block + len); + return *this; + } + + const uint32_t* finalize(digest32_t digest) { + size_t bitCount = this->m_byteCount * 8; + processByte(0x80); + if (this->m_blockByteIndex > 56) { + while (m_blockByteIndex != 0) { + processByte(0); + } + while (m_blockByteIndex < 56) { + processByte(0); + } + } else { + while (m_blockByteIndex < 56) { + processByte(0); + } + } + processByte(0); + processByte(0); + processByte(0); + processByte(0); + processByte(static_cast((bitCount >> 24) & 0xFF)); + processByte(static_cast((bitCount >> 16) & 0xFF)); + processByte(static_cast((bitCount >> 8) & 0xFF)); + processByte(static_cast((bitCount)&0xFF)); + + memcpy(digest, m_digest, 5 * sizeof(uint32_t)); + return digest; + } + + const uint8_t* finalize(digest8_t digest) { + digest32_t d32; + finalize(d32); + size_t di = 0; + digest[di++] = ((d32[0] >> 24) & 0xFF); + digest[di++] = ((d32[0] >> 16) & 0xFF); + digest[di++] = ((d32[0] >> 8) & 0xFF); + digest[di++] = ((d32[0]) & 0xFF); + + digest[di++] = ((d32[1] >> 24) & 0xFF); + digest[di++] = ((d32[1] >> 16) & 0xFF); + digest[di++] = ((d32[1] >> 8) & 0xFF); + digest[di++] = ((d32[1]) & 0xFF); + + digest[di++] = ((d32[2] >> 24) & 0xFF); + digest[di++] = ((d32[2] >> 16) & 0xFF); + digest[di++] = ((d32[2] >> 8) & 0xFF); + digest[di++] = ((d32[2]) & 0xFF); + + digest[di++] = ((d32[3] >> 24) & 0xFF); + digest[di++] = ((d32[3] >> 16) & 0xFF); + digest[di++] = ((d32[3] >> 8) & 0xFF); + digest[di++] = ((d32[3]) & 0xFF); + + digest[di++] = ((d32[4] >> 24) & 0xFF); + digest[di++] = ((d32[4] >> 16) & 0xFF); + digest[di++] = ((d32[4] >> 8) & 0xFF); + digest[di++] = ((d32[4]) & 0xFF); + return digest; + } + + protected: + void processBlock() { + uint32_t w[80]; + for (size_t i = 0; i < 16; i++) { + w[i] = (m_block[i * 4 + 0] << 24); + w[i] |= (m_block[i * 4 + 1] << 16); + w[i] |= (m_block[i * 4 + 2] << 8); + w[i] |= (m_block[i * 4 + 3]); + } + for (size_t i = 16; i < 80; i++) { + w[i] = LeftRotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); + } + + uint32_t a = m_digest[0]; + uint32_t b = m_digest[1]; + uint32_t c = m_digest[2]; + uint32_t d = m_digest[3]; + uint32_t e = m_digest[4]; + + for (std::size_t i = 0; i < 80; ++i) { + uint32_t f = 0; + uint32_t k = 0; + + if (i < 20) { + f = (b & c) | (~b & d); + k = 0x5A827999; + } else if (i < 40) { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } else if (i < 60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } else { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = LeftRotate(b, 30); + b = a; + a = temp; + } + + m_digest[0] += a; + m_digest[1] += b; + m_digest[2] += c; + m_digest[3] += d; + m_digest[4] += e; + } + + private: + digest32_t m_digest; + uint8_t m_block[64]; + size_t m_blockByteIndex; + size_t m_byteCount; +}; +} +#endif diff --git a/thirdparty/fshasher/CMakeLists.txt b/thirdparty/fshasher/CMakeLists.txt new file mode 100644 index 00000000..86221f8b --- /dev/null +++ b/thirdparty/fshasher/CMakeLists.txt @@ -0,0 +1,7 @@ +project("fshasher") + +add_executable(fshasher "fshasher.cpp") + +find_package(xxhash CONFIG REQUIRED) + +target_link_libraries(fshasher PRIVATE xxHash::xxhash) diff --git a/thirdparty/fshasher/fshasher.cpp b/thirdparty/fshasher/fshasher.cpp new file mode 100644 index 00000000..e0d32171 --- /dev/null +++ b/thirdparty/fshasher/fshasher.cpp @@ -0,0 +1,203 @@ +// +// fshasher - CLI tool to generate a hash map from a file system. +// +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "plainargs.h" + +void showHelp() { + std::cout << "fshasher --directory --source --header
--variable " << std::endl; +} + +int process(const std::list &searchDirectories, std::ofstream &outputSourceStream, std::ofstream &outputHeaderStream, const std::string &variableName) { + auto writeExterns = [&](std::ofstream &outputStream) + { + outputStream << "extern const uint64_t " << variableName << "Hashes[];" << std::endl; + outputStream << "extern const std::pair " << variableName << "Files[];" << std::endl; + outputStream << "extern const size_t " << variableName << "FilesSize;" << std::endl << std::endl; + }; + + // Generate header. + outputHeaderStream << "// File automatically generated by fshasher" << std::endl << std::endl; + outputHeaderStream << "#pragma once" << std::endl << std::endl; + outputHeaderStream << "#include " << std::endl << std::endl; + writeExterns(outputHeaderStream); + + if (outputHeaderStream.bad()) + { + std::cerr << "Failed to write to output header." << std::endl; + return 1; + } + + outputSourceStream << "// File automatically generated by fshasher" << std::endl << std::endl; + outputSourceStream << "#include " << std::endl << std::endl; + writeExterns(outputSourceStream); + + std::map> fileHashSets; + char fileData[65536]; + XXH3_state_t xxh3; + for (const std::filesystem::path &searchDirectory : searchDirectories) + { + if (!std::filesystem::is_directory(searchDirectory)) + { + std::cerr << "Specified directory " << searchDirectory << " does not exist." << std::endl; + return 1; + } + + for (const std::filesystem::directory_entry &entry : std::filesystem::recursive_directory_iterator(searchDirectory)) + { + if (!entry.is_regular_file()) + { + continue; + } + + std::filesystem::path entryPath = entry.path(); + std::filesystem::path entryRelative = std::filesystem::relative(entryPath, searchDirectory); + std::ifstream entryStream(entryPath, std::ios::binary); + if (!entryStream.is_open()) + { + std::cerr << "Could not open " << entryPath << " for reading." << std::endl; + return 1; + } + + std::cout << "Reading " << entryRelative << "." << std::endl; + XXH3_64bits_reset(&xxh3); + while (!entryStream.eof() && !entryStream.bad()) + { + entryStream.read(fileData, sizeof(fileData)); + XXH3_64bits_update(&xxh3, fileData, entryStream.gcount()); + } + + if (entryStream.bad()) + { + std::cerr << "Could not read " << entryPath << " successfully." << std::endl; + return 1; + } + + std::u8string entryRelativeU8 = entryRelative.u8string(); + std::replace(entryRelativeU8.begin(), entryRelativeU8.end(), '\\', '/'); + fileHashSets[entryRelativeU8].insert(XXH3_64bits_digest(&xxh3)); + } + } + + outputSourceStream << "const uint64_t " << variableName << "Hashes[] = {" << std::endl; + + for (auto &it : fileHashSets) + { + for (uint64_t hash : it.second) + { + outputSourceStream << " " << hash << "ULL," << std::endl; + } + + if (outputSourceStream.bad()) + { + std::cerr << "Failed to write to output source." << std::endl; + return 1; + } + } + + outputSourceStream << "};" << std::endl << std::endl; + outputSourceStream << "const std::pair " << variableName << "Files[] = {" << std::endl; + + for (const auto &it : fileHashSets) + { + outputSourceStream << " { \"" << (const char *)(it.first.c_str()) << "\", " << it.second.size() << " }," << std::endl; + if (outputSourceStream.bad()) + { + std::cerr << "Failed to write to output source." << std::endl; + return 1; + } + } + + outputSourceStream << "};" << std::endl << std::endl; + outputSourceStream << "const size_t " << variableName << "FilesSize = std::size(" << variableName << "Files);" << std::endl; + + if (outputSourceStream.bad()) + { + std::cerr << "Failed to write to output source." << std::endl; + return 1; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + plainargs::Result argsResult = plainargs::parse(argc, argv); + std::vector directories = argsResult.getValues("directory", "d"); + std::string variable = argsResult.getValue("variable", "v"); + std::string source = argsResult.getValue("source", "s"); + std::string header = argsResult.getValue("header", "h"); + if (directories.empty() || variable.empty() || source.empty() || header.empty()) + { + showHelp(); + return 1; + } + + std::filesystem::path sourcePath(source); + std::ofstream sourceStream(sourcePath); + if (!sourceStream.is_open()) + { + std::cerr << "Could not open " << sourcePath << " for writing." << std::endl; + return 1; + } + + std::filesystem::path headerPath(header); + std::ofstream headerStream(headerPath); + if (!headerStream.is_open()) + { + std::cerr << "Could not open " << headerPath << " for writing." << std::endl; + return 1; + } + + std::list searchDirectories; + for (std::string &directory : directories) + { + searchDirectories.emplace_back(directory); + } + + int resultCode = process(searchDirectories, sourceStream, headerStream, variable); + sourceStream.close(); + headerStream.close(); + + if (resultCode != 0) + { + std::cerr << "Failed to generate " << sourcePath << "and" << headerPath << "." << std::endl; + std::filesystem::remove(sourcePath); + std::filesystem::remove(headerPath); + } + + return resultCode; +} diff --git a/thirdparty/fshasher/plainargs.h b/thirdparty/fshasher/plainargs.h new file mode 100644 index 00000000..18ee421a --- /dev/null +++ b/thirdparty/fshasher/plainargs.h @@ -0,0 +1,147 @@ +// +// plainargs - A very plain CLI arguments parsing header-only library. +// +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. +// +// In jurisdictions that recognize copyright laws, the author or authors +// of this software dedicate any and all copyright interest in the +// software to the public domain. We make this dedication for the benefit +// of the public at large and to the detriment of our heirs and +// successors. We intend this dedication to be an overt act of +// relinquishment in perpetuity of all present and future rights to this +// software under copyright law. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +#include +#include + +namespace plainargs { + class Result { + private: + struct Option { + uint32_t keyIndex; + uint32_t valueCount; + }; + + std::string directory; + std::vector arguments; + std::vector