Merge branch 'main' into options-menu

# Conflicts:
#	UnleashedRecomp/CMakeLists.txt
#	UnleashedRecomp/api/CSD/Manager/csdmNode.h
#	UnleashedRecomp/api/CSD/Manager/csdmNode.inl
#	UnleashedRecomp/api/Hedgehog/Base/Type/detail/hhStringHolder.h
#	UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.h
#	UnleashedRecomp/api/Hedgehog/Database/System/hhDatabaseData.inl
#	UnleashedRecomp/api/SWA.h
#	UnleashedRecomp/api/SWA.inl
#	UnleashedRecomp/api/SWA/System/ApplicationDocument.h
#	UnleashedRecomp/api/boost/smart_ptr/shared_ptr.h
#	UnleashedRecomp/gpu/video.cpp
#	UnleashedRecomp/main.cpp
#	UnleashedRecomp/stdafx.h
#	UnleashedRecomp/ui/window.cpp
#	UnleashedRecompLib/config/SWA.toml
This commit is contained in:
Skyth 2024-11-30 20:03:54 +03:00
commit 3015111379
89 changed files with 16280 additions and 245 deletions

3
.gitmodules vendored
View file

@ -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

View file

@ -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(
@ -46,8 +47,8 @@ set(SWA_CPU_CXX_SOURCES
set(SWA_GPU_CXX_SOURCES
"gpu/video.cpp"
"gpu/imgui_snapshot.cpp"
"gpu/rhi/rt64_d3d12.cpp"
"gpu/rhi/rt64_vulkan.cpp"
"gpu/rhi/plume_d3d12.cpp"
"gpu/rhi/plume_vulkan.cpp"
)
set(SWA_APU_CXX_SOURCES
@ -82,6 +83,32 @@ 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_USER_CXX_SOURCES
"user/achievement_data.cpp"
"user/config.cpp"
@ -102,6 +129,9 @@ 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"
${SWA_USER_CXX_SOURCES}
)
@ -132,6 +162,8 @@ 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)
find_package(unofficial-tiny-aes-c CONFIG REQUIRED)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12)
add_custom_command(TARGET UnleashedRecomp POST_BUILD
@ -140,10 +172,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
@ -164,13 +199,18 @@ target_link_libraries(UnleashedRecomp PRIVATE
unofficial::concurrentqueue::concurrentqueue
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}
)
target_precompile_headers(UnleashedRecomp PUBLIC ${SWA_PRECOMPILED_HEADERS})
@ -208,3 +248,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"
)

View file

@ -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 <SWA.inl>
#include <CSD/Manager/csdmBase.h>
#include <CSD/Manager/csdmResourceBase.h>
#include <CSD/Manager/csdmNodeObserver.h>
#include <CSD/Manager/csdmSubjectBase.h>
#include <Hedgehog/Math/Vector2.h>
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 <CSD/Manager/csdmNode.inl>

View file

@ -17,11 +17,9 @@ namespace Chao::CSD
GuestToHostFunction<int>(0x830BF640, this, in_pText);
}
inline Hedgehog::Math::CVector2* CNode::GetPosition() const
inline void CNode::GetPosition(Hedgehog::Math::CVector2& out_rResult) const
{
guest_stack_var<Hedgehog::Math::CVector2> pos;
GuestToHostFunction<void>(0x830BF008, pos.get(), this);
return pos.get();
GuestToHostFunction<void>(0x830BF008, &out_rResult, this);
}
inline void CNode::SetPosition(float in_X, float in_Y)

View file

@ -0,0 +1,378 @@
#pragma once
#include <Hedgehog/Base/System/hhAllocator.h>
namespace hh
{
template<
class Key,
class T,
class Compare = std::less<Key>,
class Allocator = Hedgehog::Base::TAllocator<std::pair<const Key, T>>>
class map
{
protected:
enum EColor
{
eColor_Red,
eColor_Black
};
struct SNode
{
using allocator_type = typename std::allocator_traits<Allocator>::template rebind_alloc<SNode>;
xpointer<SNode> pLeft;
xpointer<SNode> pParent;
xpointer<SNode> pRight;
std::pair<const Key, T> Value;
uint8_t Color;
bool IsNil;
};
Compare m_Comp;
typename SNode::allocator_type m_Alloc;
xpointer<SNode> m_pHead;
be<uint32_t> 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<const Key, T>;
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<Allocator>::pointer;
using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
class iterator
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = std::pair<const Key, T>;
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<const Key, T>;
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<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_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<int, int>) == 0xC);
}

View file

@ -0,0 +1,255 @@
#pragma once
#include <Hedgehog/Base/System/hhAllocator.h>
namespace hh
{
template<typename T, typename Allocator = Hedgehog::Base::TAllocator<T>>
class vector
{
protected:
Allocator m_Alloc;
xpointer<T> m_pFirst;
xpointer<T> m_pLast;
xpointer<T> 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<Allocator>::pointer;
using const_pointer = typename std::allocator_traits<Allocator>::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<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_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<int>, 0x10);
}

View file

@ -0,0 +1,27 @@
#pragma once
#include <SWA.inl>
namespace Hedgehog::Base
{
class CSharedString;
class CStringSymbol
{
public:
be<uint32_t> 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 <Hedgehog/Base/System/hhSymbol.inl>

View file

@ -0,0 +1,31 @@
namespace Hedgehog::Base
{
inline CStringSymbol::CStringSymbol()
{
}
inline CStringSymbol::CStringSymbol(const char* in_pName)
{
GuestToHostFunction<void>(sub_82E014D8, this, in_pName);
}
inline CStringSymbol::CStringSymbol(const CSharedString& in_rName)
{
GuestToHostFunction<void>(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;
}
}

View file

@ -1,6 +1,6 @@
#pragma once
#include "SWA.inl"
#include <SWA.inl>
namespace Hedgehog::Base
{
@ -41,4 +41,4 @@ namespace Hedgehog::Base
};
}
#include "Hedgehog/Base/Type/detail/hhStringHolder.inl"
#include <Hedgehog/Base/Type/detail/hhStringHolder.inl>

View file

@ -212,11 +212,6 @@ namespace Hedgehog::Base
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);

View file

@ -1,6 +1,7 @@
#pragma once
#include "Hedgehog/Base/hhObject.h"
#include <Hedgehog/Base/hhObject.h>
#include <Hedgehog/Base/Type/hhSharedString.h>
namespace Hedgehog::Database
{

View file

@ -7,7 +7,7 @@ namespace Hedgehog::Database
inline bool CDatabaseData::CheckMadeAll()
{
return true;
return GuestToHostFunction<bool>(m_pVftable->m_fpCheckMadeAll, this);
}
inline bool CDatabaseData::IsMadeOne() const

View file

@ -0,0 +1,19 @@
#pragma once
#include <SWA.inl>
namespace Hedgehog::Mirage
{
class CRenderingInfrastructure;
class CVertexDeclarationPtr
{
public:
xpointer<void> m_pD3DVertexDeclaration;
xpointer<CRenderingInfrastructure> m_pRenderingInfrastructure;
};
SWA_ASSERT_OFFSETOF(CVertexDeclarationPtr, m_pD3DVertexDeclaration, 0x0);
SWA_ASSERT_OFFSETOF(CVertexDeclarationPtr, m_pRenderingInfrastructure, 0x4);
SWA_ASSERT_SIZEOF(CVertexDeclarationPtr, 0x8);
}

View file

@ -0,0 +1,39 @@
#pragma once
#include <boost/smart_ptr/shared_ptr.h>
#include <Hedgehog/Base/Container/hhVector.h>
#include <Hedgehog/Database/System/hhDatabaseData.h>
namespace Hedgehog::Mirage
{
class CMaterialData;
class CTexsetData;
class CShaderListData;
class CParameterFloat4Element;
class CParameterInt4Element;
class CParameterBoolElement;
class CMaterialData : public Database::CDatabaseData
{
public:
boost::shared_ptr<CShaderListData> m_spShaderListData;
boost::shared_ptr<CTexsetData> m_spTexsetData;
hh::vector<boost::shared_ptr<CParameterFloat4Element>> m_Float4Params;
hh::vector<boost::shared_ptr<CParameterInt4Element>> m_Int4Params;
hh::vector<boost::shared_ptr<CParameterBoolElement>> 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);
}

View file

@ -0,0 +1,43 @@
#pragma once
#include <boost/smart_ptr/shared_ptr.h>
#include <Hedgehog/Base/Type/hhSharedString.h>
#include <Hedgehog/Database/System/hhDatabaseData.h>
#include <Hedgehog/MirageCore/Misc/hhVertexDeclarationPtr.h>
namespace Hedgehog::Mirage
{
class CMaterialData;
class CMeshData : public Database::CDatabaseData
{
public:
be<uint32_t> m_IndexNum;
be<uint32_t> m_VertexNum;
be<uint32_t> m_VertexSize;
be<uint32_t> m_NodeNum;
xpointer<uint8_t> m_pNodeIndices;
be<uint32_t> m_VertexOffset;
be<uint32_t> m_IndexOffset;
xpointer<void> m_pD3DIndexBuffer;
xpointer<void> m_pD3DVertexBuffer;
CVertexDeclarationPtr m_VertexDeclarationPtr;
SWA_INSERT_PADDING(0x4);
boost::shared_ptr<CMaterialData> 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);
}

View file

@ -0,0 +1,46 @@
#pragma once
#include <Hedgehog/Base/Container/hhVector.h>
#include <Hedgehog/Database/System/hhDatabaseData.h>
namespace Hedgehog::Mirage
{
class CNodeGroupModelData;
class CMeshData;
class CModelNodeData;
class CMatrixData;
class CAabbData;
class CSphereData;
class CMorphModelData;
class CModelData : public Database::CDatabaseData
{
public:
be<uint32_t> m_NodeGroupModelNum;
hh::vector<boost::shared_ptr<CNodeGroupModelData>> m_NodeGroupModels;
hh::vector<boost::shared_ptr<CMeshData>> m_OpaqueMeshes;
hh::vector<boost::shared_ptr<CMeshData>> m_TransparentMeshes;
hh::vector<boost::shared_ptr<CMeshData>> m_PunchThroughMeshes;
be<uint32_t> m_NodeNum;
boost::shared_ptr<uint8_t[]> m_spNodeParentIndices;
boost::shared_ptr<CModelNodeData[]> m_spNodes;
boost::shared_ptr<CMatrixData[]> m_spNodeMatrices;
boost::shared_ptr<CAabbData> m_spAabb;
boost::shared_ptr<CSphereData> m_spSphere;
hh::vector<boost::shared_ptr<CMorphModelData>> 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);
}

View file

@ -0,0 +1,30 @@
#pragma once
#include <Hedgehog/Base/Container/hhVector.h>
#include <Hedgehog/Database/System/hhDatabaseData.h>
namespace Hedgehog::Mirage
{
class CMeshData;
class CNodeGroupModelData : public Database::CDatabaseData
{
public:
hh::vector<boost::shared_ptr<CMeshData>> m_OpaqueMeshes;
hh::vector<boost::shared_ptr<CMeshData>> m_TransparentMeshes;
hh::vector<boost::shared_ptr<CMeshData>> m_PunchThroughMeshes;
be<uint32_t> m_SpecialMeshGroupNum;
boost::shared_ptr<be<uint32_t>> m_SpecialMeshGroupModes;
hh::vector<hh::vector<boost::shared_ptr<CMeshData>>> 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);
}

View file

@ -0,0 +1,30 @@
#pragma once
#include <boost/smart_ptr/shared_ptr.h>
#include <Hedgehog/Database/System/hhDatabaseData.h>
namespace Hedgehog::Base
{
class CCriticalSectionD3D9;
}
namespace Hedgehog::Mirage
{
class CRenderingInfrastructure;
class CPixelShaderCodeData : public Database::CDatabaseData
{
public:
xpointer<void> m_pD3DPixelShader;
xpointer<uint8_t> m_spFunction;
boost::shared_ptr<Base::CCriticalSectionD3D9> m_spCriticalSection;
xpointer<CRenderingInfrastructure> 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);
}

View file

@ -0,0 +1,22 @@
#pragma once
#include <Hedgehog/Base/Container/hhVector.h>
#include <Hedgehog/Database/System/hhDatabaseData.h>
namespace Hedgehog::Mirage
{
class CPixelShaderCodeData;
class CPixelShaderParameterData;
class CPixelShaderData : public Hedgehog::Database::CDatabaseData
{
public:
boost::shared_ptr<CPixelShaderCodeData> m_spCode;
SWA_INSERT_PADDING(0x4);
hh::vector<boost::shared_ptr<CPixelShaderParameterData>> m_ParameterList;
};
SWA_ASSERT_OFFSETOF(CPixelShaderData, m_spCode, 0xC);
SWA_ASSERT_OFFSETOF(CPixelShaderData, m_ParameterList, 0x18);
SWA_ASSERT_SIZEOF(CPixelShaderData, 0x28);
}

View file

@ -0,0 +1,46 @@
#pragma once
#include <boost/smart_ptr/shared_ptr.h>
#include <Hedgehog/Base/Container/hhMap.h>
#include <Hedgehog/Base/System/hhSymbol.h>
#include <Hedgehog/Database/System/hhDatabaseData.h>
namespace Hedgehog::Mirage
{
class CVertexShaderData;
class CPixelShaderData;
class CVertexShaderPermutationData
{
public:
hh::map<be<uint32_t>, boost::shared_ptr<CVertexShaderData>> m_VertexShaders;
be<uint32_t> 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<Base::CStringSymbol, boost::shared_ptr<CVertexShaderPermutationData>> m_VertexShaderPermutations;
hh::map<be<uint32_t>, boost::shared_ptr<CPixelShaderData>> m_PixelShaders;
be<uint32_t> 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<Base::CStringSymbol, CPixelShaderPermutationData> m_PixelShaderPermutations;
};
SWA_ASSERT_OFFSETOF(CShaderListData, m_PixelShaderPermutations, 0xC);
SWA_ASSERT_SIZEOF(CShaderListData, 0x18);
}

View file

@ -0,0 +1,29 @@
#pragma once
#include <Hedgehog/Base/Container/hhVector.h>
#include <Hedgehog/Database/System/hhDatabaseData.h>
namespace Hedgehog::Mirage
{
class CSphereData;
class CNodeGroupModelData;
class CMeshData;
class CTerrainModelData : public Database::CDatabaseData
{
public:
SWA_INSERT_PADDING(0x4);
hh::vector<boost::shared_ptr<CNodeGroupModelData>> m_NodeGroupModels;
hh::vector<boost::shared_ptr<CMeshData>> m_OpaqueMeshes;
hh::vector<boost::shared_ptr<CMeshData>> m_TransparentMeshes;
hh::vector<boost::shared_ptr<CMeshData>> m_PunchThroughMeshes;
boost::shared_ptr<CSphereData> 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);
}

View file

@ -0,0 +1,24 @@
#pragma once
#include <boost/smart_ptr/shared_ptr.h>
#include <Hedgehog/Base/Container/hhVector.h>
#include <Hedgehog/Database/System/hhDatabaseData.h>
namespace Hedgehog::Mirage
{
class CTextureData;
class CTexsetData : public Database::CDatabaseData
{
public:
hh::vector<boost::shared_ptr<CTextureData>> m_TextureList;
hh::vector<Base::CSharedString> 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);
}

View file

@ -0,0 +1,17 @@
#pragma once
#include <Hedgehog/Database/System/hhDatabaseData.h>
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);
}

View file

@ -0,0 +1,30 @@
#pragma once
#include <boost/smart_ptr/shared_ptr.h>
#include <Hedgehog/Database/System/hhDatabaseData.h>
namespace Hedgehog::Base
{
class CCriticalSectionD3D9;
}
namespace Hedgehog::Mirage
{
class CRenderingInfrastructure;
class CVertexShaderCodeData : public Database::CDatabaseData
{
public:
xpointer<void> m_pD3DVertexShader;
xpointer<uint8_t> m_spFunction;
boost::shared_ptr<Base::CCriticalSectionD3D9> m_spCriticalSection;
xpointer<CRenderingInfrastructure> 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);
}

View file

@ -0,0 +1,22 @@
#pragma once
#include <Hedgehog/Base/Container/hhVector.h>
#include <Hedgehog/Database/System/hhDatabaseData.h>
namespace Hedgehog::Mirage
{
class CVertexShaderCodeData;
class CVertexShaderParameterData;
class CVertexShaderData : public Hedgehog::Database::CDatabaseData
{
public:
boost::shared_ptr<CVertexShaderCodeData> m_spCode;
SWA_INSERT_PADDING(0x4);
hh::vector<boost::shared_ptr<CVertexShaderParameterData>> m_ParameterList;
};
SWA_ASSERT_OFFSETOF(CVertexShaderData, m_spCode, 0xC);
SWA_ASSERT_OFFSETOF(CVertexShaderData, m_ParameterList, 0x18);
SWA_ASSERT_SIZEOF(CVertexShaderData, 0x28);
}

View file

@ -0,0 +1,41 @@
#pragma once
#include <boost/smart_ptr/shared_ptr.h>
#include <Hedgehog/Base/Container/hhVector.h>
#include <Hedgehog/Database/System/hhDatabaseData.h>
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<boost::anonymous_shared_ptr> m_spFieldC;
boost::shared_ptr<Hedgehog::Mirage::CShaderListData> m_spDefaultShaderListData; // BillboardParticle_d[v]
boost::shared_ptr<Hedgehog::Mirage::CShaderListData> m_spShaderListData;
bool m_Field2C;
be<uint32_t> m_BlendMode;
be<uint32_t> m_AddressMode;
Hedgehog::Base::CSharedString m_MaterialName;
Hedgehog::Base::CSharedString m_TextureName;
Hedgehog::Base::CSharedString m_DeflectionTextureName;
Hedgehog::Base::CSharedString m_ShaderName;
be<float> m_Field48;
be<float> m_Field4C;
};
SWA_ASSERT_SIZEOF(CParticleMaterial, 0x50);
}

View file

@ -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,13 +15,46 @@
#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"
#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/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"
#include "Hedgehog/Universe/Engine/hhUpdateUnit.h"
#include "Hedgehog/Universe/Thread/hhParallelJob.h"
#include "SWA/Achievement/AchievementManager.h"
#include "SWA/Camera/Camera.h"
#include "SWA/Achievement/AchievementTest.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"
@ -45,26 +62,29 @@
#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"

View file

@ -4,11 +4,17 @@
#include <cpu/guest_stack_var.h>
#include <kernel/function.h>
#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_assert(offsetof(type, field) == offset)
#define SWA_ASSERT_SIZEOF(type, size) \
static_assert(sizeof(type) == size)
#define SWA_VIRTUAL_FUNCTION(returnType, virtualIndex, ...) \
GuestToHostFunction<returnType>(*(be<uint32_t>*)(g_memory.Translate(*(be<uint32_t>*)(this) + (4 * virtualIndex))), __VA_ARGS__)

View file

@ -69,7 +69,12 @@ namespace boost
uint32_t use_count() const
{
return use_count_;
return std::byteswap(static_cast<uint32_t const volatile &>(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<T> 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<void>;

View file

@ -0,0 +1,65 @@
{ reinterpret_cast<GuestShader*>(0x135289E4F64C6EEA),reinterpret_cast<GuestShader*>(0x6B812461EA74928D),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x135289E4F64C6EEA),reinterpret_cast<GuestShader*>(0x7C6A695E4296FA3B),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x135289E4F64C6EEA),reinterpret_cast<GuestShader*>(0xC20BFEE4B086F5EF),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x1D29E1386144A506),reinterpret_cast<GuestShader*>(0x22CDDA5C6346A97),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x36DB3B40FA419EF6),reinterpret_cast<GuestShader*>(0x3BF885B6A8263F78),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x36DB3B40FA419EF6),reinterpret_cast<GuestShader*>(0x3BF885B6A8263F78),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x681C97662BFE9150),reinterpret_cast<GuestShader*>(0xDC635C4E7013864E),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x681E682667303C76),reinterpret_cast<GuestShader*>(0x38771885AC644B5),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x681E682667303C76),reinterpret_cast<GuestShader*>(0x604349CBF72CCF8C),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x132D2F2079D74CB3),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x198E2B57B47DAF53),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x3016DA5F348C87A7),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x3016DA5F348C87A7),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x3016DA5F348C87A7),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x4294510C775F4EE8),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x48BE63A8F5F1C78A),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x50700665A5F55DFE),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x605C1E349CC4CAAB),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x65325B9C7DA3DB04),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x67064E6EA39B439E),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x7D9F06B0E048B75D),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x891B8684FB17752B),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0x9FA5AACB5B14A226),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0xC47F2F91BA2A5D86),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x6DE86503F8AA38E2),reinterpret_cast<GuestShader*>(0xFB79F59782376846),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x720D6E5EDA78433B),reinterpret_cast<GuestShader*>(0x96EACBACDE1AAFAA),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x7C34DB46DEEFB0C2),reinterpret_cast<GuestShader*>(0xDBD8B29544AC9277),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x7CC3A0B01523741B),reinterpret_cast<GuestShader*>(0x315BB80DAE685834),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x86FE3502D5EC24AA),reinterpret_cast<GuestShader*>(0x68FCC0B90EBC457B),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x86FE3502D5EC24AA),reinterpret_cast<GuestShader*>(0x94A71CC9B94E3101),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x88F67387B88F932F),reinterpret_cast<GuestShader*>(0x49101E452DF2FE98),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x8A459F1CE0E957D3),reinterpret_cast<GuestShader*>(0x5D7ACAE543747185),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x8E4BB23465BD909E),reinterpret_cast<GuestShader*>(0x0),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x8E4BB23465BD909E),reinterpret_cast<GuestShader*>(0x0),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x965929BAA69F0AE),reinterpret_cast<GuestShader*>(0x66578F29004F8FD0),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x965929BAA69F0AE),reinterpret_cast<GuestShader*>(0x6B9732B4CD7E7740),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x965929BAA69F0AE),reinterpret_cast<GuestShader*>(0x6C50210CBDA8A23A),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x965929BAA69F0AE),reinterpret_cast<GuestShader*>(0x6C50210CBDA8A23A),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x965929BAA69F0AE),reinterpret_cast<GuestShader*>(0x6C50210CBDA8A23A),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x965929BAA69F0AE),reinterpret_cast<GuestShader*>(0x6C50210CBDA8A23A),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x965929BAA69F0AE),reinterpret_cast<GuestShader*>(0x6C50210CBDA8A23A),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x965929BAA69F0AE),reinterpret_cast<GuestShader*>(0x6C50210CBDA8A23A),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x965929BAA69F0AE),reinterpret_cast<GuestShader*>(0x92940FDD115733E1),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x965929BAA69F0AE),reinterpret_cast<GuestShader*>(0xA305C47ED9FB58CF),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x965929BAA69F0AE),reinterpret_cast<GuestShader*>(0xD44C189D5067922E),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0x965929BAA69F0AE),reinterpret_cast<GuestShader*>(0xD736237D80908063),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xA3CD49F172D99214),reinterpret_cast<GuestShader*>(0xD5EA32DB758EF0B8),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xA3FD368C62079765),reinterpret_cast<GuestShader*>(0xE8E3FF65F2356201),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xA3FD368C62079765),reinterpret_cast<GuestShader*>(0xE8E3FF65F2356201),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xA4CF0215A03D9571),reinterpret_cast<GuestShader*>(0xA3A659F1590CC180),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xB1086A4947A797DE),reinterpret_cast<GuestShader*>(0x996F5A774A646D92),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xB1086A4947A797DE),reinterpret_cast<GuestShader*>(0x996F5A774A646D92),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xB1086A4947A797DE),reinterpret_cast<GuestShader*>(0x996F5A774A646D92),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xB1EA909C660122A7),reinterpret_cast<GuestShader*>(0xC96708D6F26CC6D9),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xB4CAFC034A37C8A8),reinterpret_cast<GuestShader*>(0x31173204A896098A),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xB4CAFC034A37C8A8),reinterpret_cast<GuestShader*>(0x31173204A896098A),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xB4CAFC034A37C8A8),reinterpret_cast<GuestShader*>(0x31173204A896098A),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xBBD01C46D72EDC37),reinterpret_cast<GuestShader*>(0x4E1399E5E0E40511),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xBDA992649419F2DD),reinterpret_cast<GuestShader*>(0x5A4CFA9D29441E0),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xBDA992649419F2DD),reinterpret_cast<GuestShader*>(0x5A4CFA9D29441E0),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xCF28F33974EC44F6),reinterpret_cast<GuestShader*>(0xD5EA32DB758EF0B8),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xD6EA5D49CB1F965C),reinterpret_cast<GuestShader*>(0x2FE1A3913EF3EE8A),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xD6EA5D49CB1F965C),reinterpret_cast<GuestShader*>(0x53EF4B071D1B59D3),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xD738D79626374EBE),reinterpret_cast<GuestShader*>(0xAAE40F54746EB116),reinterpret_cast<GuestVertexDeclaration*>(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<GuestShader*>(0xFF5A2C4C81AA6FDF),reinterpret_cast<GuestShader*>(0xE105CB09EA634E60),reinterpret_cast<GuestVertexDeclaration*>(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 },

View file

@ -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,

View file

@ -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,};

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 renderbag and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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 OR COPYRIGHT HOLDERS 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.

View file

@ -1,8 +1,11 @@
//
// RT64
// plume
//
// Copyright (c) 2024 renderbag and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file for details.
//
#include "rt64_d3d12.h"
#include "plume_d3d12.h"
#include <unordered_set>
@ -34,7 +37,7 @@ extern "C" {
__declspec(dllexport) extern const char* D3D12SDKPath = ".\\D3D12\\";
}
namespace RT64 {
namespace plume {
static const uint32_t ShaderDescriptorHeapSize = 65536;
static const uint32_t SamplerDescriptorHeapSize = 1024;
static const uint32_t TargetDescriptorHeapSize = 16384;
@ -2672,6 +2675,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 +2798,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 +3022,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.");

View file

@ -1,10 +1,13 @@
//
// RT64
// plume
//
// Copyright (c) 2024 renderbag and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file for details.
//
#pragma once
#include "rt64_render_interface.h"
#include "plume_render_interface.h"
#include <map>
#include <mutex>
@ -15,7 +18,7 @@
#include "D3D12MemAlloc.h"
namespace RT64 {
namespace plume {
struct D3D12Buffer;
struct D3D12CommandQueue;
struct D3D12Device;
@ -355,6 +358,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 +369,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 +382,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;
};

View file

@ -1,14 +1,17 @@
//
// RT64
// plume
//
// Copyright (c) 2024 renderbag and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file for details.
//
#pragma once
#include <climits>
#include "rt64_render_interface_types.h"
#include "plume_render_interface_types.h"
namespace RT64 {
namespace plume {
// Interfaces.
struct RenderBufferFormattedView {
@ -53,6 +56,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;
};
@ -242,4 +246,4 @@ namespace RT64 {
extern void TestShutdown();
};
#include "rt64_render_interface_builders.h"
#include "plume_render_interface_builders.h"

View file

@ -1,12 +1,15 @@
//
// RT64
// plume
//
// Copyright (c) 2024 renderbag and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file for details.
//
#pragma once
#include <unordered_set>
namespace RT64 {
namespace plume {
struct RenderDescriptorSetBuilder {
std::list<std::vector<const RenderSampler *>> samplerPointerVectorList;
std::vector<RenderDescriptorRange> descriptorRanges;

View file

@ -1,5 +1,8 @@
//
// RT64
// plume
//
// Copyright (c) 2024 renderbag and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file for details.
//
#pragma once
@ -26,7 +29,7 @@
typedef struct _NSWindow NSWindow;
#endif
namespace RT64 {
namespace plume {
#if defined(_WIN64)
// Native HWND handle to the target window.
typedef HWND RenderWindow;

View file

@ -1,11 +1,14 @@
//
// RT64
// plume
//
// Copyright (c) 2024 renderbag and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file for details.
//
#define VMA_IMPLEMENTATION
#define VOLK_IMPLEMENTATION
#include "rt64_vulkan.h"
#include "plume_vulkan.h"
#include <algorithm>
#include <cmath>
@ -13,7 +16,7 @@
#include <unordered_map>
#if DLSS_ENABLED
# include "render/rt64_dlss.h"
# include "render/plume_dlss.h"
#endif
#ifndef NDEBUG
@ -24,7 +27,7 @@
// TODO:
// - Fix resource pools.
namespace RT64 {
namespace plume {
// Backend constants.
// Required buffer alignment for acceleration structures.
@ -1316,6 +1319,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 +1559,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 +1763,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.");
@ -4051,9 +4066,9 @@ namespace RT64 {
}
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "RT64";
appInfo.pApplicationName = "plume";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "RT64";
appInfo.pEngineName = "plume";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_2;

View file

@ -1,10 +1,13 @@
//
// RT64
// plume
//
// Copyright (c) 2024 renderbag and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file for details.
//
#pragma once
#include "rt64_render_interface.h"
#include "plume_render_interface.h"
#include <mutex>
#include <set>
@ -23,7 +26,7 @@
#include "vk_mem_alloc.h"
namespace RT64 {
namespace plume {
struct VulkanCommandQueue;
struct VulkanDevice;
struct VulkanInterface;
@ -158,6 +161,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 +171,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 +184,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;
};

View file

@ -1,4 +1,4 @@
#include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.hlsli"
#include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.h"
#ifdef __spirv__

View file

@ -1,6 +1,6 @@
#pragma once
#include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.hlsli"
#include "../../../thirdparty/ShaderRecomp/ShaderRecomp/shader_common.h"
#ifdef __spirv__

View file

@ -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;
}

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,14 @@
#pragma once
#include "rhi/rt64_render_interface.h"
//#define ASYNC_PSO_DEBUG
#define PSO_CACHING
#include "rhi/plume_render_interface.h"
#define D3DCLEAR_TARGET 0x1
#define D3DCLEAR_ZBUFFER 0x10
using namespace RT64;
using namespace plume;
struct GuestSamplerState
{
@ -78,6 +81,19 @@ struct GuestResource
incrementedValue = std::byteswap(std::byteswap(originalValue) + 1);
} while (InterlockedCompareExchange(reinterpret_cast<LONG*>(&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<LONG*>(&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<RenderInputElement[]> inputElements;
std::unique_ptr<GuestVertexElement[]> 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<RenderShader> shader;
struct ShaderCacheEntry* shaderCacheEntry = nullptr;
ankerl::unordered_dense::map<uint32_t, std::unique_ptr<RenderShader>> linkedShaders;
std::vector<ComPtr<IDxcBlob>> shaderBlobs;
ComPtr<IDxcBlobEncoding> libraryBlob;
#ifdef ASYNC_PSO_DEBUG
const char* name = "<unknown>";
#endif
};
struct GuestViewport

View file

@ -0,0 +1,65 @@
#pragma once
#include <filesystem>
#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<VirtualFileSystem> create(const std::filesystem::path &directoryPath)
{
if (std::filesystem::exists(directoryPath))
{
return std::make_unique<DirectoryFileSystem>(directoryPath);
}
else
{
return nullptr;
}
}
};

View file

@ -0,0 +1,297 @@
// File automatically generated by fshasher
#include <utility>
extern const uint64_t ApotosShamarHashes[];
extern const std::pair<const char *, uint32_t> 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<const char *, uint32_t> 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);

View file

@ -0,0 +1,10 @@
// File automatically generated by fshasher
#pragma once
#include <utility>
extern const uint64_t ApotosShamarHashes[];
extern const std::pair<const char *, uint32_t> ApotosShamarFiles[];
extern const size_t ApotosShamarFilesSize;

View file

@ -0,0 +1,211 @@
// File automatically generated by fshasher
#include <utility>
extern const uint64_t ChunnanHashes[];
extern const std::pair<const char *, uint32_t> 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<const char *, uint32_t> 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);

View file

@ -0,0 +1,10 @@
// File automatically generated by fshasher
#pragma once
#include <utility>
extern const uint64_t ChunnanHashes[];
extern const std::pair<const char *, uint32_t> ChunnanFiles[];
extern const size_t ChunnanFilesSize;

View file

@ -0,0 +1,301 @@
// File automatically generated by fshasher
#include <utility>
extern const uint64_t EmpireCityAdabatHashes[];
extern const std::pair<const char *, uint32_t> 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<const char *, uint32_t> 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);

View file

@ -0,0 +1,10 @@
// File automatically generated by fshasher
#pragma once
#include <utility>
extern const uint64_t EmpireCityAdabatHashes[];
extern const std::pair<const char *, uint32_t> EmpireCityAdabatFiles[];
extern const size_t EmpireCityAdabatFilesSize;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,10 @@
// File automatically generated by fshasher
#pragma once
#include <utility>
extern const uint64_t GameHashes[];
extern const std::pair<const char *, uint32_t> GameFiles[];
extern const size_t GameFilesSize;

View file

@ -0,0 +1,198 @@
// File automatically generated by fshasher
#include <utility>
extern const uint64_t HoloskaHashes[];
extern const std::pair<const char *, uint32_t> 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<const char *, uint32_t> 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);

View file

@ -0,0 +1,10 @@
// File automatically generated by fshasher
#pragma once
#include <utility>
extern const uint64_t HoloskaHashes[];
extern const std::pair<const char *, uint32_t> HoloskaFiles[];
extern const size_t HoloskaFilesSize;

View file

@ -0,0 +1,207 @@
// File automatically generated by fshasher
#include <utility>
extern const uint64_t MazuriHashes[];
extern const std::pair<const char *, uint32_t> 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<const char *, uint32_t> 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);

View file

@ -0,0 +1,10 @@
// File automatically generated by fshasher
#pragma once
#include <utility>
extern const uint64_t MazuriHashes[];
extern const std::pair<const char *, uint32_t> MazuriFiles[];
extern const size_t MazuriFilesSize;

View file

@ -0,0 +1,207 @@
// File automatically generated by fshasher
#include <utility>
extern const uint64_t SpagoniaHashes[];
extern const std::pair<const char *, uint32_t> 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<const char *, uint32_t> 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);

View file

@ -0,0 +1,10 @@
// File automatically generated by fshasher
#pragma once
#include <utility>
extern const uint64_t SpagoniaHashes[];
extern const std::pair<const char *, uint32_t> SpagoniaFiles[];
extern const size_t SpagoniaFilesSize;

View file

@ -0,0 +1,89 @@
// File automatically generated by fshasher
#include <utility>
extern const uint64_t UpdateHashes[];
extern const std::pair<const char *, uint32_t> 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<const char *, uint32_t> 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);

View file

@ -0,0 +1,10 @@
// File automatically generated by fshasher
#pragma once
#include <utility>
extern const uint64_t UpdateHashes[];
extern const std::pair<const char *, uint32_t> UpdateFiles[];
extern const size_t UpdateFilesSize;

View file

@ -0,0 +1,492 @@
#include "installer.h"
#include <xxh3.h>
#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<VirtualFileSystem> 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<uint8_t> &fileData, Journal &journal, const std::function<void(uint32_t)> &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<uint8_t> 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[] = "<Type>";
const char TypeEndString[] = "</Type>";
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<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function<void(uint32_t)> &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<uint8_t> 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<VirtualFileSystem> &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<void(uint32_t)> &progressCallback)
{
// Parse the contents of the base game.
std::unique_ptr<VirtualFileSystem> gameSource;
if (!input.gameSource.empty())
{
if (!parseContent(input.gameSource, gameSource, journal))
{
return false;
}
journal.progressTotal += GameFilesSize;
}
// Parse the contents of Update.
std::unique_ptr<VirtualFileSystem> 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<VirtualFileSystem> sourceVfs;
std::span<const FilePair> filePairs;
const uint64_t *fileHashes = nullptr;
std::string targetSubDirectory;
};
std::vector<DLCSource> 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<VirtualFileSystem> sourceVfs = createFileSystemFromPath(sourcePath);
if (sourceVfs == nullptr)
{
return false;
}
return sourceVfs->exists(GameExecutableFile);
}
bool Installer::parseUpdate(const std::filesystem::path &sourcePath)
{
std::unique_ptr<VirtualFileSystem> 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<VirtualFileSystem> 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<VirtualFileSystem> gameSourceVfs = createFileSystemFromPath(gameSourcePath);
if (gameSourceVfs == nullptr)
{
return XexPatcher::Result::FileOpenFailed;
}
std::unique_ptr<VirtualFileSystem> updateSourceVfs = createFileSystemFromPath(updateSourcePath);
if (updateSourceVfs == nullptr)
{
return XexPatcher::Result::FileOpenFailed;
}
std::vector<uint8_t> xexBytes;
std::vector<uint8_t> patchBytes;
if (!gameSourceVfs->load(GameExecutableFile, xexBytes))
{
return XexPatcher::Result::FileOpenFailed;
}
if (!updateSourceVfs->load(UpdateExecutablePatchFile, patchBytes))
{
return XexPatcher::Result::FileOpenFailed;
}
std::vector<uint8_t> patchedBytes;
return XexPatcher::apply(xexBytes, patchBytes, patchedBytes, true);
}

View file

@ -0,0 +1,76 @@
#pragma once
#include <span>
#include <set>
#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<std::filesystem::path> createdFiles;
std::set<std::filesystem::path> createdDirectories;
Result lastResult = Result::Success;
XexPatcher::Result lastPatcherResult = XexPatcher::Result::Success;
std::string lastErrorMessage;
};
using FilePair = std::pair<const char *, uint32_t>;
struct Installer
{
struct Input
{
std::filesystem::path gameSource;
std::filesystem::path updateSource;
std::list<std::filesystem::path> dlcSources;
bool skipHashChecks = false;
};
static bool checkGameInstall(const std::filesystem::path &baseDirectory);
static bool copyFiles(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function<void(uint32_t)> &progressCallback);
static bool parseContent(const std::filesystem::path &sourcePath, std::unique_ptr<VirtualFileSystem> &targetVfs, Journal &journal);
static bool install(const Input &input, const std::filesystem::path &targetDirectory, Journal &journal, const std::function<void(uint32_t)> &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);
};

View file

@ -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 <stack>
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<IterationStep> 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> ISOFileSystem::create(const std::filesystem::path &isoPath) {
std::unique_ptr<ISOFileSystem> isoFs = std::make_unique<ISOFileSystem>(isoPath);
if (!isoFs->empty())
{
return isoFs;
}
else
{
return nullptr;
}
}

View file

@ -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 <filesystem>
#include <map>
#include "virtual_file_system.h"
#include "memory_mapped_file.h"
struct ISOFileSystem : VirtualFileSystem
{
MemoryMappedFile mappedFile;
std::map<std::string, std::tuple<size_t, size_t>> 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<ISOFileSystem> create(const std::filesystem::path &isoPath);
};

View file

@ -0,0 +1,169 @@
#include "memory_mapped_file.h"
#if !defined(_WIN32)
# include <cstring>
# include <cstdio>
# include <fcntl.h>
# include <unistd.h>
#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<uint8_t *>(fileView);
}
size_t MemoryMappedFile::size() const
{
#if defined(_WIN32)
return fileSize.QuadPart;
#else
return static_cast<size_t>(fileSize);
#endif
}

View file

@ -0,0 +1,32 @@
#pragma once
#include <filesystem>
#if defined(_WIN32)
# include <Windows.h>
#else
# include <sys/mman.h>
#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;
};

View file

@ -0,0 +1,24 @@
#pragma once
#include <algorithm>
#include <memory>
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<uint8_t> &fileData)
{
size_t fileDataSize = getSize(path);
if (fileDataSize == 0)
{
return false;
}
fileData.resize(fileDataSize);
return load(path, fileData.data(), fileDataSize);
}
};

View file

@ -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 <bit>
#include <set>
#include <stack>
enum class XContentPackageType
{
CON = 0x434F4E20,
PIRS = 0x50495253,
LIVE = 0x4C495645,
};
struct XContentLicense
{
be<uint64_t> licenseId;
be<uint32_t> licenseBits;
be<uint32_t> licenseFlags;
};
#pragma pack(push, 1)
struct XContentHeader
{
be<uint32_t> magic;
uint8_t signature[0x228];
XContentLicense licenses[0x10];
uint8_t contentId[0x14];
be<uint32_t> 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<uint32_t> totalBlockCount;
be<uint32_t> 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<uint16_t> directoryIndex;
be<uint32_t> length;
be<uint16_t> createDate;
be<uint16_t> createTime;
be<uint16_t> modifiedDate;
be<uint16_t> modifiedTime;
};
static_assert(sizeof(StfsDirectoryEntry) == 0x40);
struct StfsDirectoryBlock {
StfsDirectoryEntry entries[0x40];
};
static_assert(sizeof(StfsDirectoryBlock) == 0x1000);
struct StfsHashEntry {
uint8_t sha1[0x14];
be<uint32_t> infoRaw;
};
static_assert(sizeof(StfsHashEntry) == 0x18);
struct StfsHashTable {
StfsHashEntry entries[170];
be<uint32_t> 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<uint32_t> contentType;
be<uint32_t> metadataVersion;
be<uint64_t> contentSize;
uint8_t executionInfo[24];
uint8_t consoleId[5];
be<uint64_t> profileId;
union {
StfsVolumeDescriptor stfsVolumeDescriptor;
SvodDeviceDescriptor svodDeviceDescriptor;
};
be<uint32_t> dataFileCount;
be<uint64_t> dataFileSize;
be<uint32_t> volumeType;
be<uint64_t> onlineCreator;
be<uint32_t> 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<uint32_t, std::string> 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<std::filesystem::path> 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<IterationStep> 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> XContentFileSystem::create(const std::filesystem::path &contentPath)
{
std::unique_ptr<XContentFileSystem> xContentFS = std::make_unique<XContentFileSystem>(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;
}

View file

@ -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 <filesystem>
#include <map>
#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<MemoryMappedFile> mappedFiles;
uint64_t baseOffset = 0;
std::map<std::string, File> 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<XContentFileSystem> create(const std::filesystem::path &contentPath);
static bool check(const std::filesystem::path &contentPath);
};

View file

@ -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 <bit>
#include <cassert>
#include <aes.hpp>
#include <lzx.h>
#include <mspack.h>
#include <TinySHA1.hpp>
#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<uint32_t> key;
union
{
be<uint32_t> value;
be<uint32_t> offset;
};
};
struct Xex2Header
{
be<uint32_t> magic;
be<uint32_t> moduleFlags;
be<uint32_t> headerSize;
be<uint32_t> reserved;
be<uint32_t> securityOffset;
be<uint32_t> 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<uint32_t> headerSize;
be<uint32_t> imageSize;
char rsaSignature[0x100];
be<uint32_t> unknown;
be<uint32_t> imageFlags;
be<uint32_t> loadAddress;
char sectionDigest[0x14];
be<uint32_t> importTableCount;
char importTableDigest[0x14];
char xgd2MediaId[0x10];
char aesKey[0x10];
be<uint32_t> exportTable;
char headerDigest[0x14];
be<uint32_t> region;
be<uint32_t> allowedMediaTypes;
be<uint32_t> pageDescriptorCount;
Xex2PageDescriptor pageDescriptors[1];
};
struct Xex2DeltaPatch
{
be<uint32_t> oldAddress;
be<uint32_t> newAddress;
be<uint16_t> uncompressedLength;
be<uint16_t> compressedLength;
char patchData[1];
};
struct Xex2OptDeltaPatchDescriptor
{
be<uint32_t> size;
be<uint32_t> targetVersionValue;
be<uint32_t> sourceVersionValue;
uint8_t digestSource[0x14];
uint8_t imageKeySource[0x10];
be<uint32_t> sizeOfTargetHeaders;
be<uint32_t> deltaHeadersSourceOffset;
be<uint32_t> deltaHeadersSourceSize;
be<uint32_t> deltaHeadersTargetOffset;
be<uint32_t> deltaImageSourceOffset;
be<uint32_t> deltaImageSourceSize;
be<uint32_t> deltaImageTargetOffset;
Xex2DeltaPatch info;
};
struct Xex2FileBasicCompressionBlock
{
be<uint32_t> dataSize;
be<uint32_t> zeroSize;
};
struct Xex2FileBasicCompressionInfo
{
Xex2FileBasicCompressionBlock firstBlock;
};
struct Xex2CompressedBlockInfo
{
be<uint32_t> blockSize;
uint8_t blockHash[20];
};
struct Xex2FileNormalCompressionInfo
{
be<uint32_t> windowSize;
Xex2CompressedBlockInfo firstBlock;
};
struct Xex2OptFileFormatInfo
{
be<uint32_t> infoSize;
be<uint16_t> encryptionType;
be<uint16_t> compressionType;
union
{
Xex2FileBasicCompressionInfo basic;
Xex2FileNormalCompressionInfo normal;
} compressionInfo;
};
static const void *getOptHeaderPtr(std::span<const uint8_t> 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<const uint8_t> xexBytes, std::span<const uint8_t> patchBytes, std::vector<uint8_t> &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<uint8_t> 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<uint8_t> 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;
}

View file

@ -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 <cstdint>
#include <filesystem>
#include <span>
#include <vector>
struct XexPatcher
{
enum class Result {
Success,
FileOpenFailed,
FileWriteFailed,
XexFileUnsupported,
XexFileInvalid,
PatchFileInvalid,
PatchIncompatible,
PatchFailed,
PatchUnsupported
};
static Result apply(std::span<const uint8_t> xexBytes, std::span<const uint8_t> patchBytes, std::vector<uint8_t> &outBytes, bool skipData);
static Result apply(const std::filesystem::path &baseXexPath, const std::filesystem::path &patchXexPath, const std::filesystem::path &newXexPath);
};

View file

@ -101,13 +101,15 @@ uint32_t LdrLoadModule(const char* path)
auto format = Xex2FindOptionalHeader<XEX_FILE_FORMAT_INFO>(xex, XEX_HEADER_FILE_FORMAT_INFO);
auto entry = *Xex2FindOptionalHeader<uint32_t>(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<const XEX_BASIC_FILE_COMPRESSION_INFO*>(format + 1);
@ -122,6 +124,10 @@ uint32_t LdrLoadModule(const char* path)
destData += blocks[i].SizeOfPadding;
}
}
else
{
assert(false && "Unknown compression type.");
}
auto res = Xex2FindOptionalHeader<XEX_RESOURCE_INFO>(xex, XEX_HEADER_RESOURCE_INFO);

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="be&lt;*&gt;">
<DisplayString>{get()}</DisplayString>
<Expand>
<Item Name="Value">get()</Item>
</Expand>
</Type>
<Type Name="xpointer&lt;*&gt;">
<DisplayString>{get()}</DisplayString>
<Expand>
<Item Name="Value">get()</Item>
</Expand>
</Type>
<Type Name="boost::shared_ptr&lt;*&gt;">
<DisplayString>{get()}</DisplayString>
<Expand>
<Item Name="Value">get()</Item>
</Expand>
</Type>
</AutoVisualizer>

View file

@ -10,8 +10,8 @@
#include <winrt/Windows.Media.Control.h>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Media::Control;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Media::Control;
GlobalSystemMediaTransportControlsSessionManager m_sessionManager = nullptr;

View file

@ -3,6 +3,7 @@
#define NOMINMAX
#include <windows.h>
#include <dxcapi.h>
#include <ShlObj_core.h>
#include <algorithm>
#include <mutex>
@ -27,6 +28,12 @@
#include <imgui_internal.h>
#include <imgui_impl_sdl2.h>
#include <o1heap.h>
#include <cstddef>
#include <wrl/client.h>
#include <smolv.h>
#include <print>
using Microsoft::WRL::ComPtr;
#include "framework.h"
#include "mutex.h"

View file

@ -11,6 +11,9 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
if (ImGui::GetIO().BackendPlatformUserData != nullptr)
ImGui_ImplSDL2_ProcessEvent(event);
for (auto listener : GetEventListeners())
listener->OnSDLEvent(event);
switch (event->type)
{
case SDL_QUIT:
@ -131,9 +134,6 @@ int Window_OnSDLEvent(void*, SDL_Event* event)
}
}
for (auto listener : GetEventListeners())
listener->OnSDLEvent(event);
return 0;
}

View file

@ -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\"

View file

@ -424,6 +424,31 @@ 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"]
# World Map Pause Menu
[[midasm_hook]]
name = "CHudPauseAddOptionsItemMidAsmHook"

View file

@ -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[];

View file

@ -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)

@ -1 +1 @@
Subproject commit 30f598604767602e3afce56b947e99dba2b51211
Subproject commit f936ed2212d8291439003eb0c0d8edc0ecafd24d

223
thirdparty/TinySHA1/TinySHA1.hpp vendored Normal file
View file

@ -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 <mohaps@gmail.com>
*
* 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 <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdint.h>
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<const uint8_t*>(start);
const uint8_t* finish = static_cast<const uint8_t*>(end);
while (begin != finish) {
processByte(*begin);
begin++;
}
return *this;
}
SHA1& processBytes(const void* const data, size_t len) {
const uint8_t* block = static_cast<const uint8_t*>(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<unsigned char>((bitCount >> 24) & 0xFF));
processByte(static_cast<unsigned char>((bitCount >> 16) & 0xFF));
processByte(static_cast<unsigned char>((bitCount >> 8) & 0xFF));
processByte(static_cast<unsigned char>((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

7
thirdparty/fshasher/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,7 @@
project("fshasher")
add_executable(fshasher "fshasher.cpp")
find_package(xxhash CONFIG REQUIRED)
target_link_libraries(fshasher PRIVATE xxHash::xxhash)

203
thirdparty/fshasher/fshasher.cpp vendored Normal file
View file

@ -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 <cstdio>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <list>
#include <map>
#include <set>
#include <xxh3.h>
#include "plainargs.h"
void showHelp() {
std::cout << "fshasher --directory <directory1 directory2 ...> --source <source file> --header <header file> --variable <variable name>" << std::endl;
}
int process(const std::list<std::filesystem::path> &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<const char *, uint32_t> " << 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 <utility>" << 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 <utility>" << std::endl << std::endl;
writeExterns(outputSourceStream);
std::map<std::u8string, std::set<uint64_t>> 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<const char *, uint32_t> " << 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<std::string> 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<std::filesystem::path> 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;
}

147
thirdparty/fshasher/plainargs.h vendored Normal file
View file

@ -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 <string>
#include <unordered_map>
namespace plainargs {
class Result {
private:
struct Option {
uint32_t keyIndex;
uint32_t valueCount;
};
std::string directory;
std::vector<std::string> arguments;
std::vector<Option> options;
std::unordered_map<std::string, uint32_t> shortKeyMap;
std::unordered_map<std::string, uint32_t> longKeyMap;
public:
// Arguments are the same as main().
Result(int argc, char *argv[]) {
if (argc < 1) {
return;
}
directory = argv[0];
arguments.resize(size_t(argc - 1));
for (uint32_t i = 1; i < uint32_t(argc); i++) {
std::string &argument = arguments[i - 1];
argument = std::string(argv[i]);
if (!argument.empty()) {
bool shortKey = (argument.size() > 1) && (argument[0] == '-');
bool longKey = (argument.size() > 2) && (argument[0] == '-') && (argument[1] == '-');
if (longKey) {
longKeyMap[argument.substr(2)] = uint32_t(options.size());
options.emplace_back(Option{ i - 1, 0 });
}
else if (shortKey) {
shortKeyMap[argument.substr(1)] = uint32_t(options.size());
options.emplace_back(Option{ i - 1, 0 });
}
else if (!options.empty()) {
options.back().valueCount++;
}
}
}
}
// Return all the values associated to the long key or the short key in order.
std::vector<std::string> getValues(const std::string &longKey, const std::string &shortKey = "", uint32_t maxValues = 0) const {
std::vector<std::string> values;
auto optionIt = options.end();
if (!longKey.empty()) {
auto it = longKeyMap.find(longKey);
if (it != longKeyMap.end()) {
optionIt = options.begin() + it->second;
}
}
if ((optionIt == options.end()) && !shortKey.empty()) {
auto it = shortKeyMap.find(shortKey);
if (it != shortKeyMap.end()) {
optionIt = options.begin() + it->second;
}
}
if (optionIt != options.end()) {
uint32_t valueCount = optionIt->valueCount;
if ((maxValues > 0) && (valueCount > maxValues)) {
valueCount = maxValues;
}
values.resize(valueCount);
for (uint32_t i = 0; i < valueCount; i++) {
values[i] = arguments[optionIt->keyIndex + i + 1];
}
}
return values;
}
std::string getValue(const std::string &longKey, const std::string &shortKey = "") const {
std::vector<std::string> values = getValues(longKey, shortKey, 1);
return !values.empty() ? values.front() : std::string();
}
// Return whether an option with the long key or short key was specified.
bool hasOption(const std::string &longKey, const std::string &shortKey = "") const {
if (!longKey.empty() && (longKeyMap.find(longKey) != longKeyMap.end())) {
return true;
}
else if (!shortKey.empty() && (shortKeyMap.find(shortKey) != shortKeyMap.end())) {
return true;
}
else {
return false;
}
}
// Corresponds to argv[0].
const std::string &getDirectory() const {
return directory;
}
// No bounds checking, must be a valid index.
const std::string getArgument(uint32_t index) const {
return arguments[index];
}
// Will be one less than argc.
uint32_t getArgumentCount() const {
return arguments.size();
}
};
// Parse and return the arguments in a structure that can be queried easily. Does not perform any validation of the arguments.
Result parse(int argc, char *argv[]) {
return Result(argc, argv);
}
};

1
thirdparty/libmspack vendored Submodule

@ -0,0 +1 @@
Subproject commit 305907723a4e7ab2018e58040059ffb5e77db837

View file

@ -16,9 +16,11 @@
"zstd",
"stb",
"concurrentqueue",
"tiny-aes-c",
{
"name": "imgui",
"features": [ "sdl2-binding" ]
}
},
"magic-enum"
]
}