From 051cc6d15f2ef7f30544acb43f98a39f5d5acc60 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Tue, 5 Apr 2022 19:22:21 -0400 Subject: [PATCH] Add WIP main.cpp / CStringTable.cpp --- Makefile | 2 +- asm/Kyoto_CWD/main.s | 32 +- include/gx_struct.h | 30 + src/Kyoto_CWD/CStringTable.cpp | 50 ++ src/Kyoto_CWD/main.cpp | 1158 ++++++++++++++++++++++++++++++++ 5 files changed, 1255 insertions(+), 17 deletions(-) create mode 100644 include/gx_struct.h create mode 100644 src/Kyoto_CWD/CStringTable.cpp create mode 100644 src/Kyoto_CWD/main.cpp diff --git a/Makefile b/Makefile index df29708a..62208eae 100644 --- a/Makefile +++ b/Makefile @@ -109,7 +109,7 @@ ifeq ($(VERBOSE),0) # this set of LDFLAGS generates no warnings. LDFLAGS := $(MAPGEN) -fp hard -nodefaults -w off endif -CFLAGS = -Cpp_exceptions off -enum int -inline auto -proc gekko -RTTI off -fp hard -fp_contract on -rostr -O4,p -use_lmw_stmw on -sdata 8 -sdata2 8 -nodefaults $(INCLUDES) +CFLAGS = -Cpp_exceptions off -enum int -inline auto -proc gekko -RTTI off -fp hard -fp_contract on -str pool -rostr -O4,p -use_lmw_stmw on -sdata 8 -sdata2 8 -nodefaults $(INCLUDES) ifeq ($(VERBOSE),0) # this set of ASFLAGS generates no warnings. diff --git a/asm/Kyoto_CWD/main.s b/asm/Kyoto_CWD/main.s index ac64f857..19d8d3e7 100644 --- a/asm/Kyoto_CWD/main.s +++ b/asm/Kyoto_CWD/main.s @@ -2749,7 +2749,7 @@ RsMain__5CMainFiPCPCc: /* 80004E24 00001D84 41 82 00 14 */ beq lbl_80004E38 /* 80004E28 00001D88 7F A4 EB 78 */ mr r4, r29 /* 80004E2C 00001D8C 38 BD 00 6D */ addi r5, r29, 0x6d -/* 80004E30 00001D90 48 00 2C 8D */ bl __ct__18CGameGlobalObjectsFP10COsContextP10CMemorySys +/* 80004E30 00001D90 48 00 2C 8D */ bl __ct__18CGameGlobalObjectsFR10COsContextR10CMemorySys /* 80004E34 00001D94 7C 60 1B 78 */ mr r0, r3 lbl_80004E38: /* 80004E38 00001D98 90 01 00 0C */ stw r0, 0xc(r1) @@ -3157,7 +3157,7 @@ lbl_80005414: /* 80005414 00002374 D0 3E 00 00 */ stfs f1, 0(r30) /* 80005418 00002378 38 61 00 18 */ addi r3, r1, 0x18 /* 8000541C 0000237C 38 9D 00 F0 */ addi r4, r29, 0xf0 -/* 80005420 00002380 48 00 08 25 */ bl "GetAverage__21TReservedAverageFv" +/* 80005420 00002380 48 00 08 25 */ bl "GetAverage__21TReservedAverageCFv" /* 80005424 00002384 C0 01 00 18 */ lfs f0, 0x18(r1) /* 80005428 00002388 38 80 00 00 */ li r4, 0 /* 8000542C 0000238C 83 41 00 08 */ lwz r26, 8(r1) @@ -3197,7 +3197,7 @@ lbl_8000547C: /* 800054AC 0000240C FC 20 F0 90 */ fmr f1, f30 /* 800054B0 00002410 7F A3 EB 78 */ mr r3, r29 /* 800054B4 00002414 38 84 00 28 */ addi r4, r4, 0x28 -/* 800054B8 00002418 48 00 0B 85 */ bl DrawDebugMetrics__5CMainFR10CStopwatchf +/* 800054B8 00002418 48 00 0B 85 */ bl DrawDebugMetrics__5CMainFdR10CStopwatch /* 800054BC 0000241C 83 41 00 08 */ lwz r26, 8(r1) /* 800054C0 00002420 48 37 FE E9 */ bl OSGetTime /* 800054C4 00002424 80 BA 00 2C */ lwz r5, 0x2c(r26) @@ -3283,7 +3283,7 @@ lbl_800055EC: /* 800055EC 0000254C D0 3F 00 00 */ stfs f1, 0(r31) /* 800055F0 00002550 38 61 00 10 */ addi r3, r1, 0x10 /* 800055F4 00002554 38 9D 01 04 */ addi r4, r29, 0x104 -/* 800055F8 00002558 48 00 06 4D */ bl "GetAverage__21TReservedAverageFv" +/* 800055F8 00002558 48 00 06 4D */ bl "GetAverage__21TReservedAverageCFv" /* 800055FC 0000255C FC 1E E8 2A */ fadd f0, f30, f29 /* 80005600 00002560 C8 42 80 10 */ lfd f2, lbl_805A9D30@sda21(r2) /* 80005604 00002564 C0 61 00 10 */ lfs f3, 0x10(r1) @@ -3411,11 +3411,11 @@ lbl_800057AC: /* 800057C4 00002724 48 00 26 A5 */ bl ShutdownSubsystems__5CMainFv /* 800057C8 00002728 38 61 00 0C */ addi r3, r1, 0xc /* 800057CC 0000272C 38 80 00 00 */ li r4, 0 -/* 800057D0 00002730 48 00 00 45 */ bl sub_80005814 +/* 800057D0 00002730 48 00 00 45 */ bl "__as__Q24rstl32single_ptr<18CGameGlobalObjects>FP18CGameGlobalObjects" /* 800057D4 00002734 48 33 F4 F1 */ bl Shutdown__12CARAMManagerFv /* 800057D8 00002738 38 61 00 0C */ addi r3, r1, 0xc /* 800057DC 0000273C 38 80 FF FF */ li r4, -1 -/* 800057E0 00002740 48 00 04 C5 */ bl sub_80005ca4 +/* 800057E0 00002740 48 00 04 C5 */ bl "__dt__Q24rstl32single_ptr<18CGameGlobalObjects>Fv" /* 800057E4 00002744 38 60 00 00 */ li r3, 0 /* 800057E8 00002748 E3 E1 01 48 */ psq_l f31, 328(r1), 0, qr0 /* 800057EC 0000274C CB E1 01 40 */ lfd f31, 0x140(r1) @@ -3429,8 +3429,8 @@ lbl_800057AC: /* 8000580C 0000276C 38 21 01 50 */ addi r1, r1, 0x150 /* 80005810 00002770 4E 80 00 20 */ blr -.global sub_80005814 -sub_80005814: +.global "__as__Q24rstl32single_ptr<18CGameGlobalObjects>FP18CGameGlobalObjects" +"__as__Q24rstl32single_ptr<18CGameGlobalObjects>FP18CGameGlobalObjects": /* 80005814 00002774 94 21 FF F0 */ stwu r1, -0x10(r1) /* 80005818 00002778 7C 08 02 A6 */ mflr r0 /* 8000581C 0000277C 90 01 00 14 */ stw r0, 0x14(r1) @@ -3741,8 +3741,8 @@ lbl_80005C20: /* 80005C3C 00002B9C 38 21 00 30 */ addi r1, r1, 0x30 /* 80005C40 00002BA0 4E 80 00 20 */ blr -.global "GetAverage__21TReservedAverageFv" -"GetAverage__21TReservedAverageFv": +.global "GetAverage__21TReservedAverageCFv" +"GetAverage__21TReservedAverageCFv": /* 80005C44 00002BA4 94 21 FF F0 */ stwu r1, -0x10(r1) /* 80005C48 00002BA8 7C 08 02 A6 */ mflr r0 /* 80005C4C 00002BAC 90 01 00 14 */ stw r0, 0x14(r1) @@ -3770,8 +3770,8 @@ lbl_80005C90: /* 80005C9C 00002BFC 38 21 00 10 */ addi r1, r1, 0x10 /* 80005CA0 00002C00 4E 80 00 20 */ blr -.global sub_80005ca4 -sub_80005ca4: +.global "__dt__Q24rstl32single_ptr<18CGameGlobalObjects>Fv" +"__dt__Q24rstl32single_ptr<18CGameGlobalObjects>Fv": /* 80005CA4 00002C04 94 21 FF F0 */ stwu r1, -0x10(r1) /* 80005CA8 00002C08 7C 08 02 A6 */ mflr r0 /* 80005CAC 00002C0C 90 01 00 14 */ stw r0, 0x14(r1) @@ -4023,8 +4023,8 @@ CheckTerminate__5CMainFv: /* 80006034 00002F94 38 60 00 00 */ li r3, 0 /* 80006038 00002F98 4E 80 00 20 */ blr -.global DrawDebugMetrics__5CMainFR10CStopwatchf -DrawDebugMetrics__5CMainFR10CStopwatchf: +.global DrawDebugMetrics__5CMainFdR10CStopwatch +DrawDebugMetrics__5CMainFdR10CStopwatch: /* 8000603C 00002F9C 4E 80 00 20 */ blr .global DoPredrawMetrics__5CMainFv @@ -5883,8 +5883,8 @@ lbl_80007A90: /* 80007AB4 00004A14 38 21 00 10 */ addi r1, r1, 0x10 /* 80007AB8 00004A18 4E 80 00 20 */ blr -.global __ct__18CGameGlobalObjectsFP10COsContextP10CMemorySys -__ct__18CGameGlobalObjectsFP10COsContextP10CMemorySys: +.global __ct__18CGameGlobalObjectsFR10COsContextR10CMemorySys +__ct__18CGameGlobalObjectsFR10COsContextR10CMemorySys: /* 80007ABC 00004A1C 94 21 FF E0 */ stwu r1, -0x20(r1) /* 80007AC0 00004A20 7C 08 02 A6 */ mflr r0 /* 80007AC4 00004A24 90 01 00 24 */ stw r0, 0x24(r1) diff --git a/include/gx_struct.h b/include/gx_struct.h new file mode 100644 index 00000000..8ea82eeb --- /dev/null +++ b/include/gx_struct.h @@ -0,0 +1,30 @@ +#ifndef __GX_STRUCT_H__ +#define __GX_STRUCT_H__ + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _GXRenderModeObj { + u32 viTVMode; + u16 fbWidth; + u16 efbHeight; + u16 xfbHeight; + u16 viXOrigin; + u16 viYOrigin; + u16 viWidth; + u16 viHeight; + u32 xfbMode; + u8 field_rendering; + u8 aa; + u8 sample_pattern[12][2]; + u8 vfilter[7]; +} GXRenderModeObj; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/Kyoto_CWD/CStringTable.cpp b/src/Kyoto_CWD/CStringTable.cpp new file mode 100644 index 00000000..547ce806 --- /dev/null +++ b/src/Kyoto_CWD/CStringTable.cpp @@ -0,0 +1,50 @@ +#define FourCC unsigned long + +static FourCC mCurrentLanguage = 'ENGL'; + +class CStringTable { + u32 x0_stringCount; + rstl::single_ptr x4_data; +public: + CStringTable(CInputStream& in); +}; + +template <> +inline s32 cinput_stream_helper(TType type, CInputStream& in) { return in.ReadLong(); } +template <> +inline u32 cinput_stream_helper(TType type, CInputStream& in) { return in.ReadLong(); } +template <> +inline unsigned long cinput_stream_helper(TType type, CInputStream& in) { return in.ReadLong(); } +template +inline rstl::pair cinput_stream_helper(TType > type, CInputStream& in) { + rstl::pair result; + result.first = in.Get(); + result.second = in.Get(); + return result; +} + +CStringTable::CStringTable(CInputStream& in) : x0_stringCount(0), x4_data(NULL) { + in.ReadLong(); + in.ReadLong(); + size_t langCount = in.Get(); + x0_stringCount = in.Get(); + rstl::vector > langOffsets(langCount); + for (size_t i = 0; i < langCount; ++i) { + langOffsets.push_back(in.Get >()); + } + + size_t offset = langOffsets.front().second; + for (size_t i = 0; i < langCount; ++i) { + if (langOffsets[i].first == mCurrentLanguage) { + offset = langOffsets[i].second; + break; + } + } + for (u32 i = 0; i < offset; ++i) { + in.ReadChar(); + } + + u32 dataLen = in.Get(); + x4_data = new u8[dataLen]; + in.ReadBytes(x4_data.get(), dataLen); +} diff --git a/src/Kyoto_CWD/main.cpp b/src/Kyoto_CWD/main.cpp new file mode 100644 index 00000000..430ff472 --- /dev/null +++ b/src/Kyoto_CWD/main.cpp @@ -0,0 +1,1158 @@ +#include "types.h" +#include "gx_struct.h" + +class CStreamAudioManager { +public: + static void Update(float dt); + static void StopAll(); +}; + +namespace CMemory { +void* Alloc(unsigned long sz); +void Free(const void* ptr); +} + +inline void operator delete(void* ptr) { + // if (ptr != nullptr) + CMemory::Free(ptr); +} + +void* operator new(unsigned long sz, const char*, const char*); +void* operator new[](unsigned long sz, const char*, const char*); +inline void* operator new(unsigned long sz) { + const char* fileAndLineNo = "??(??)"; + const char* type = nullptr; + return operator new(sz, fileAndLineNo, type); +} +inline void* operator new[](unsigned long sz) { + const char* fileAndLineNo = "??(??)"; + const char* type = nullptr; + return operator new[](sz, fileAndLineNo, type); +} +// placement new +inline void* operator new(unsigned long n, void* ptr) { return ptr; }; + +namespace rstl { +struct rmemory_allocator { +template +static void allocate(T*& out, size_t count) { + // out = static_cast(CMemory::Alloc(sizeof(T) * sz)); + out = new T[count]; +} +template +static void deallocate(T* ptr) { + if (ptr != nullptr) + // CMemory::Free(ptr); + delete ptr; +} +}; + +template +inline void construct(void* dest, const T& src) { + *static_cast(dest) = src; +} + +template +inline void destroy(T* in) { + in->~T(); +} + +template +inline void destroy(Iter begin, Iter end) { + Iter current = begin; + while (current != end) { + current.destroy(); + ++current; + } +} + +template +inline void uninitialized_copy(Iter begin, Iter end, T* in) { + Iter current = begin; + while (current != end) { + current = *in; + ++current; + } +} + +template +inline void uninitialized_copy_n(T* dest, size_t count, T* src) { + for (size_t i = 0; i < count; ++i) { + construct(dest, *src); + destroy(src); + ++dest; + ++src; + } +} + +template +class optional_object { + T x0_item; + bool x4_valid; + +public: + optional_object() : x4_valid(false) {} + optional_object(const T& item) : x0_item(item), x4_valid(true) {} + ~optional_object() { clear(); } + + T& data() { return x0_item; } + operator bool() const { return x4_valid; } + void clear() { + rstl::destroy(&x0_item); + x4_valid = false; + } +}; + +template +class const_pointer_iterator { +protected: + const T* current; +public: + const_pointer_iterator() : current(nullptr) {} + const_pointer_iterator(const T* begin) : current(begin) {} + void operator++() { ++current; } + void operator--() { --current; } + T* get_pointer() const { return const_cast(current); } + const T& operator*() const { return *get_pointer(); } + const T* operator->() const { return get_pointer(); } + bool CheckValid() const { return current != nullptr; } + bool operator==(const const_pointer_iterator& other) { return current == other.current; } + bool operator!=(const const_pointer_iterator& other) { return current != other.current; } + + friend const_pointer_iterator operator+(const const_pointer_iterator& x, int v) { + return const_pointer_iterator(x.current + v); + } + friend const_pointer_iterator operator-(const const_pointer_iterator& x, int v) { + return const_pointer_iterator(x.current - v); + } +}; +template +class pointer_iterator : public const_pointer_iterator { +public: + pointer_iterator() : const_pointer_iterator(nullptr) {} + pointer_iterator(T* begin) : const_pointer_iterator(begin) {} + void operator=(const T& other) { + if (CheckValid()) { + *get_pointer() = other; + } + } + T* get_pointer() const { return const_cast(current); } + // T* operator*() const { if (CheckValid()) return get_pointer(); else return nullptr; } + T* operator->() const { return get_pointer(); } + void destroy() const { + if (CheckValid()) { + rstl::destroy(get_pointer()); + } + } + + friend pointer_iterator operator+(const pointer_iterator& x, int v) { + return pointer_iterator(x.get_pointer() + v); + } + friend pointer_iterator operator-(const pointer_iterator& x, int v) { + return pointer_iterator(x.get_pointer() - v); + } +}; + +template +class vector { + int x0_unk; + size_t x4_count; + size_t x8_capacity; + T* xc_items; +public: + typedef pointer_iterator, Alloc> iterator; + typedef const_pointer_iterator, Alloc> const_iterator; + + inline iterator begin() { return iterator(xc_items); } + inline const_iterator begin() const { return const_iterator(xc_items); } + inline iterator end() { return iterator(xc_items + x4_count); } + inline const_iterator end() const { return const_iterator(xc_items + x4_count); } + inline vector() : x4_count(0), x8_capacity(0), xc_items(NULL) {} + inline vector(size_t count) : x4_count(0), x8_capacity(0), xc_items(0) { reserve(count); } + vector(const vector& other) { + x4_count = other.x4_count; + x8_capacity = other.x8_capacity; + if (x4_count == 0 && x8_capacity == 0) { + xc_items = NULL; + } else { + if (x8_capacity == 0) { + xc_items = NULL; + } else { + Alloc::allocate(xc_items, x8_capacity); + } + // what's going on here? + iterator iter; + const_iterator otherIter; + otherIter = other.begin(); + iter = begin(); + for (size_t i = 0; i < x4_count; ++i) { + iter = *otherIter; + ++iter; + ++otherIter; + } + } + } + ~vector() { + rstl::destroy(begin(), end()); + Alloc::deallocate(xc_items); + } + + void reserve(size_t size) { + if (x8_capacity >= size) return; + T* newData; + Alloc::allocate(newData, size); + uninitialized_copy_n(newData, x4_count, xc_items); + rstl::destroy(begin(), end()); + Alloc::deallocate(xc_items); + xc_items = newData; + x8_capacity = size; + } + void push_back(const T& in) { + if (x4_count >= x8_capacity) { + reserve(x8_capacity != 0 ? x8_capacity * 2 : 4); + } + iterator out = begin() + x4_count; + out = in; + ++x4_count; + } + + inline T* data() { return xc_items; } + inline const T* data() const { return xc_items; } + inline size_t size() const { return x4_count; } + inline size_t capacity() const { return x8_capacity; } + inline T& front() { return xc_items[0]; } + inline const T& front() const { return xc_items[0]; } + inline T& back() { return xc_items[x4_count - 1]; } + inline const T& back() const { return xc_items[x4_count - 1]; } + inline T& operator[](size_t idx) { return xc_items[idx]; } + inline const T& operator[](size_t idx) const { return xc_items[idx]; } +}; + +template +class reserved_vector { + size_t x0_count; + T x4_items[N]; + +public: + typedef pointer_iterator, void> iterator; + typedef const_pointer_iterator, void> const_iterator; + + inline iterator begin() { return iterator(x4_items); } + inline const_iterator begin() const { return const_iterator(x4_items); } + inline iterator end() { return iterator(x4_items + x0_count); } + inline const_iterator end() const { return const_iterator(x4_items + x0_count); } + + ~reserved_vector() { + for (u32 i = x0_count; i > 0; --i) { + ~T(x4_items[i]); + } + } + + void push_back(const T& in) { + if (x0_count < N) { + iterator out = begin() + x0_count; + out = in; + ++x0_count; + } + } + + inline T* data() { return x4_items; } + inline const T* data() const { return x4_items; } + inline size_t size() const { return x0_count; } + inline size_t capacity() const { return N; } + inline T& front() { return x4_items[0]; } + inline const T& front() const { return x4_items[0]; } + inline T& back() { return x4_items[x0_count - 1]; } + inline const T& back() const { return x4_items[x0_count - 1]; } + inline T& operator[](size_t idx) { return data()[idx]; } + inline const T& operator[](size_t idx) const { return data()[idx]; } +}; + +template +class CRefData { +public: + T* x0_ptr; + unsigned int x4_refCount; +}; + +template +class rc_ptr { + CRefData* x0_refData; +public: + ~rc_ptr(); + T* get() { return x0_refData->x0_ptr; } + T* operator->() { return get(); } +}; + +template +class pair { +public: + L first; + R second; + + inline pair() {} + inline pair(const L& first, const R& second) : first(first), second(second) {} +}; + +template +class single_ptr { + T* x0_ptr; +public: + single_ptr(T* ptr) : x0_ptr(ptr) {} + ~single_ptr() { delete x0_ptr; } + T* get() { return x0_ptr; } + T* operator->() { return x0_ptr; } + void operator=(T* ptr) { + delete x0_ptr; + x0_ptr = ptr; + } +}; + +template +struct char_traits {}; + +template , typename Alloc = rmemory_allocator> +class basic_string +{ + struct COWData + { + u32 x0_capacity; + u32 x4_refCount; + _CharTp* x8_data; + }; + + const _CharTp* x0_ptr; + COWData* x4_cow; + u32 x8_size; + u32 _pad; // Alloc? + + // void internal_allocate(int size) + // { + // x4_cow = reinterpret_cast(new u8[size * sizeof(_CharTp) + 8]); + // x0_ptr = x4_cow->x8_data; + // x4_cow->x0_capacity = u32(size); + // x4_cow->x4_refCount = 1; + // } + + void internal_dereference(); + // { + // if (x4_cow && --x4_cow->x4_refCount == 0) + // delete[] x4_cow; + // } + + static const _CharTp _EmptyString; + +public: + struct literal_t {}; + + basic_string() : x0_ptr(&_EmptyString), x4_cow(nullptr), x8_size(0) {} + + basic_string(literal_t, const _CharTp* data); + // { + // x0_ptr = data; + // x4_cow = nullptr; + + // const _CharTp* it = data; + // while (*it) + // ++it; + + // x8_size = u32((it - data) / sizeof(_CharTp)); + // } + + basic_string(const basic_string& str); + // { + // x0_ptr = str.x0_ptr; + // x4_cow = str.x4_cow; + // x8_size = str.x8_size; + // if (x4_cow) + // ++x4_cow->x4_refCount; + // } + + basic_string(const _CharTp* data, int size, const Alloc&); + // { + // if (size <= 0 && !data) + // { + // x0_ptr = &_EmptyString; + // x4_cow = nullptr; + // x8_size = 0; + // return; + // } + + // const _CharTp* it = data; + // u32 len = 0; + // while (*it) + // { + // if (size != -1 && len >= size) + // break; + // ++it; + // ++len; + // } + + // internal_allocate(len + 1); + // x8_size = len; + // for (int i = 0; i < len; ++i) + // x4_cow->x8_data[i] = data[i]; + // x4_cow->x8_data[len] = 0; + // } + + ~basic_string() + { + internal_dereference(); + } + + basic_string& operator=(const basic_string&); + basic_string operator+(const basic_string&); + + const char* data() const { return x0_ptr; } +}; + +// template <> +// const char basic_string::_EmptyString = 0; +// template <> +// const wchar_t basic_string::_EmptyString = 0; + +typedef basic_string wstring; +typedef basic_string string; + +wstring wstring_l(const wchar_t* data); +// { +// return wstring(wstring::literal_t(), data); +// } + +string string_l(const char* data); +// { +// return string(string::literal_t(), data); +// } + +} + +// wine tools/mwcc_compiler/2.6/mwcceppc.exe -Cpp_exceptions off -enum int -inline auto -proc gekko -RTTI off -fp hard -fp_contract on -str pool -rostr -O4,p -use_lmw_stmw on -sdata 8 -sdata2 8 -nodefaults -i include/ -c -o build/mp1.0/src/Kyoto_CWD/main.o src/Kyoto_CWD/main.cpp +// +template +class TOneStatic { +public: + void* operator new(unsigned long sz, const char*, const char*) { + ReferenceCount()++; + return GetAllocSpace(); + } + void* operator new(unsigned long sz) { return operator new(sz, "??(??)", nullptr); } +private: + static void* GetAllocSpace() { + static u8 sAllocSpace[sizeof(T)]; + return &sAllocSpace; + } + static u32& ReferenceCount() { + static u32 sReferenceCount = 0; + return sReferenceCount; + } +}; + +class COsContext { + int x0_right; + int x4_bottom; + int x8_left; + int xc_top; + int x10_format; + int x14_consoleType; + void* x18_arenaLo1; + void* x1c_arenaHi; + void* x20_arenaLo2; + void* x24_frameBuffer1; + void* x28_frameBuffer2; + int x2c_frameBufferSize; + GXRenderModeObj x30_renderMode; +}; + +class CMemorySys { + u8 x0_unk; +}; + +class CTweaks { + int x0_unk; +public: + void RegisterResourceTweaks(); + void RegisterTweaks(); +}; + +class CWorldState { + +}; +class CPlayerState { + // TODO +public: + void SetIsFusionEnabled(bool v); +}; +class CWorldTransManager; + +typedef int TEditorId; + +inline bool checkFlag(int flag, int pos) { + bool result = false; + result = flag >> pos & 1; + return result; +} + +class CSystemOptions { +public: + rstl::reserved_vector x0_; + rstl::reserved_vector x68_; + rstl::vector > xac_; + int xbc_; + int xc0_; + int xc4_; + int xc8_; + int xcc_; + u8 xd0_; + + CSystemOptions(); + CSystemOptions(const CSystemOptions&); + ~CSystemOptions(); + CSystemOptions& operator=(const CSystemOptions&); + + void SetHasFusion(bool v); + bool GetHasFusion() const { return checkFlag(xd0_, 3); } +}; + +class CInputStream; + +class CGameOptions { + rstl::reserved_vector x0_; + int x44_; // ESurroundModes + int x48_; + int x4c_; + int x50_; + int x54_; + int x58_; + int x5c_; + int x60_; + int x64_; + int x68_; + rstl::vector > x6c_; +public: + CGameOptions(); + CGameOptions(const CGameOptions&); + CGameOptions(CInputStream& in); + ~CGameOptions(); + CGameOptions& operator=(const CGameOptions&); + + void EnsureOptions(); +}; + +struct SHintState; + +class CHintOptions { +public: + rstl::vector x0_; + int x10_; + + void SetHintNextTime(); +}; + +template +struct TType {}; +template +inline T cinput_stream_helper(TType type, CInputStream& in); + +class CInputStream { +public: + CInputStream(size_t len); + CInputStream(const void* ptr, size_t len, bool owned); + virtual ~CInputStream(); + + s32 ReadLong(); + char ReadChar(); + void ReadBytes(void* in, unsigned long len); + u32 ReadBits(int len); + + template + inline T Get() { return cinput_stream_helper(TType(), *this); } + +private: + u32 x4_blockOffset; + u32 x8_blockLen; + u32 xc_len; + u8* x10_ptr; + bool x14_owned; + u32 x18_readPosition; + u32 x1c_bitWord; + u32 x20_bitOffset; +}; + +class CMemoryInStream : public CInputStream { +public: + enum EOwnerShip { + NotOwned, + Owned, + }; + + CMemoryInStream(const void* ptr, unsigned long len); + CMemoryInStream(const void* ptr, unsigned long len, EOwnerShip ownership); + virtual ~CMemoryInStream() {} +}; + +class CGameState { +public: + rstl::reserved_vector x0_; + int x84_mlvlId; + rstl::vector x88_worldStates; + rstl::rc_ptr x98_playerState; + rstl::rc_ptr x9c_transManager; + double xa0_playTime; + CSystemOptions xa8_systemOptions; + CGameOptions x17c_gameOptions; + CHintOptions x1f8_hintOptions; + int x20c_saveIdx; + long long x210_cardSerial; + rstl::vector x218_backupBuf; + int x228_flags; + + CGameState(); + CGameState(CInputStream& in, int saveIdx); + CGameState(const CGameState&); + ~CGameState(); + CGameState& operator=(const CGameState&); + + rstl::rc_ptr& PlayerState(); + + // void SetGameOptions(CGameOptions options) { + // x17c_gameOptions = options; + // x17c_gameOptions.EnsureOptions(); + // } +}; + +class CDvdFile { +public: + static bool FileExists(const char*); + +private: + u8 pad[0x28]; +}; + +class CPakFile : CDvdFile { +public: + bool IsWorldPak() const { return x28_26_worldPak; } + void EnsureWorldPakReady(); + +private: + bool x28_24_buildDepList : 1; + bool x28_25_aramFile : 1; + bool x28_26_worldPak : 1; + bool x28_27_stashedInARAM : 1; +}; + +class CResLoader { +public: + s32 GetPakCount(); + CPakFile& GetPakFile(s32 idx); + void AddPakFileAsync(rstl::string&, bool, bool); + void AsyncIdlePakLoading(); + bool AreAllPaksLoaded() const; + +private: + u8 pad[0x58]; +}; + +class CResFactory { +public: + virtual ~CResFactory(); + + void AsyncIdle(u32 time); + + CResLoader& GetResLoader() { return x4_resLoader; } + +private: + CResLoader x4_resLoader; +}; + +class CGameGlobalObjects : TOneStatic { +public: + CGameGlobalObjects(COsContext&, CMemorySys&); + ~CGameGlobalObjects(); + + void PostInitialize(COsContext&, CMemorySys&); + +// private: + u8 pad[0x134]; + rstl::single_ptr x134_gameState; + u8 pad2[0x24]; +}; + +class CIOWinManager { +public: + void Draw() const; + + inline bool IsEmpty() const { return x4_ == 0 && x0_ == 0; } + +private: + u32 x0_; + u32 x4_; + // rstl::list x8_; +}; + +extern "C" { +// os +typedef s64 OSTime; +OSTime OSGetTime(); +} + +class CStopwatch { +public: +class CSWData { +public: + void Initialize(); + s64 GetTimerFreq() const { return x0_timerFreq; } + s64 GetTimerFreqO1M() const { return x8_timerFreqO1M; } + f32 GetTimerPeriod() const { return x10_timerPeriod; } + s64 GetCPUCycles() const { return OSGetTime(); } + +private: + s64 x0_timerFreq; + s64 x8_timerFreqO1M; + f32 x10_timerPeriod; +}; + +private: +static CSWData mData; +static CStopwatch mGlobalTimer; + +s64 x0_startTime; + +public: + CStopwatch() : x0_startTime(mData.GetCPUCycles()) {} + // static inline void InitGlobalTimer() {} + // static inline CStopwatch& GetGlobalTimerObj() { return mGlobalTimer; } + inline void Reset() { + if (mData.GetTimerFreq() == 0) { + mData.Initialize(); + } + x0_startTime = mData.GetCPUCycles(); + } + inline float GetElapsedTime() const { + return (mData.GetCPUCycles() - x0_startTime) * mData.GetTimerPeriod(); + } + inline s64 GetElapsedMicros() const { + return (mData.GetCPUCycles() - x0_startTime) / mData.GetTimerFreqO1M(); + } +}; + +class CGameArchitectureSupport : TOneStatic { +public: + CGameArchitectureSupport(COsContext&); + ~CGameArchitectureSupport(); + + void PreloadAudio(); + bool UpdateTicks(); + void Update(); + + // TODO + inline CStopwatch& GetStopwatch1() { return x20_stopwatch1; } + inline CStopwatch& GetStopwatch2() { return x28_stopwatch2; } + inline CIOWinManager& GetIOWinManager() { return *(CIOWinManager*)(((u8*)this)+0x58); } + inline int& GetFramesDrawn() const { return *(int*)(((u8*)this)+0x78); } + +private: + u8 pad[0x20]; + CStopwatch x20_stopwatch1; + CStopwatch x28_stopwatch2; + u8 pad2[0xa0]; +}; + +class CSfxManager { +public: + static void Update(float dt); +}; + +template +class TReservedAverage : rstl::reserved_vector { +public: + TReservedAverage(const T& value) { + // resize(value, N); TODO + } + void AddValue(const T& value) { + push_back(value); + for (size_t i = size() - 1; i > 0; --i) { + operator[](i) = operator[](i - 1); + } + operator[](0) = value; + } + rstl::optional_object GetAverage() const; +}; + +class CMain { + COsContext x0_osContext; + u8 x6c_unk; + CMemorySys x6d_memorySys; + CTweaks x70_tweaks; + u8 pad[0x7c]; + TReservedAverage xf0_; + TReservedAverage x104_; + f32 x118_; + f32 x11c_; + f32 x120_; + f32 x124_; + CGameGlobalObjects* x128_gameGlobalObjects; + u32 x12c_flowState; // EFlowState + rstl::reserved_vector x130_frameTimes; + s32 x15c_frameTimeIdx; + bool x160_24_finished : 1; + bool x160_25_mfGameBuilt : 1; + bool x160_26_screenFading : 1; + bool x160_27_ : 1; + bool x160_28_manageCard : 1; + bool x160_29_ : 1; + bool x160_30_ : 1; + bool x160_31_cardBusy : 1; + bool x161_24_gameFrameDrawn : 1; + CGameArchitectureSupport* x164_; + +public: + void UpdateStreamedAudio(); + void RegisterResourceTweaks(); + void ResetGameState(); + void StreamNewGameState(CInputStream& in, int saveIdx); + void RefreshGameState(); + void AddWorldPaks(); + void EnsureWorldPaksReady(); + void AsyncIdle(u32 time); + int RsMain(int argc, char** argv); + void InitializeSubsystems(); + void FillInAssetIDs(); + void ShutdownSubsystems(); + void MemoryCardInitializePump(); + void DoPredrawMetrics(); + void DrawDebugMetrics(double dt, CStopwatch& stopWatch); + bool CheckTerminate(); + bool CheckReset(); +}; + +class CTweakGame { +public: + u32 x0_; + rstl::string x4_; +}; + +class CInGameTweakManager { +public: + bool ReadFromMemoryCard(const rstl::string&); +private: +}; + +// tweaks +extern CTweakGame* gpTweakGame; + +class CCubeRenderer { +public: + virtual void BeginScene(); + virtual void EndScene(); +}; + +extern "C" { +// PPCArch +void PPCSetFpIEEEMode(); +// os +typedef s64 OSTime; +OSTime OSGetTime(); +// OSCache +void LCEnable(); + +// ? +void srand(int); + +// something pad +void sub_8038645c(u32); +// something gx +void sub_8036ccfc(); +// part of CMain but lazy +void nullsub_2(CMain*); +} + +class CARAMToken { +public: + static void UpdateAllDMAs(); +}; + +class CARAMManager { +public: + static void Shutdown(); + static void CollectGarbage(); +}; + +class CGraphics { +public: + static void SetIsBeginSceneClearFb(bool); + static void BeginScene(); + static void EndScene(); +}; + +inline void rs_log_print(const char*, ...) {} + +namespace CBasics { + char* Stringize(const char* fmt, ...); +}; + +// sbss +CResFactory* gpResourceFactory; +void* gpSimplePool; +CCubeRenderer* gpRender; +void* gpCharacterFactoryBuilder; +void* gGuiSystem; +void* gpStringTable; +CMain* gpMain; +void* gpController; +CGameState* gpGameState; +void* gpMemoryCard; +CInGameTweakManager* gpTweakManager; +void* gpDefaultFont; +void* lbl_805A8C50; +void* lbl_805A8C54; +bool lbl_805A8C58; +u32 sARAMMemArray[2]; + +// sdata +bool lbl_805A6BC0; + +// 80003640 +void nullsub_1() {} + +// 80003644 +void InitMetroTRK() {} + +// 80003648 +int sub_80003648() { return 0; } + +// 80003650 +int sub_80003650() { return 0; } + +// 80003658 +void CMain::UpdateStreamedAudio() { + CStreamAudioManager::Update(1.f / 60.f); +} + +// 8000367C +void CMain::RegisterResourceTweaks() { + x70_tweaks.RegisterResourceTweaks(); +} + +// 800036A0 +void CMain::ResetGameState() { + CSystemOptions persistentOptions = gpGameState->xa8_systemOptions; + CGameOptions gameOptions = gpGameState->x17c_gameOptions; + x128_gameGlobalObjects->x134_gameState = nullptr; + gpGameState = nullptr; + x128_gameGlobalObjects->x134_gameState = new CGameState(); + gpGameState = x128_gameGlobalObjects->x134_gameState.get(); + gpGameState->xa8_systemOptions = persistentOptions; + gpGameState->x17c_gameOptions = gameOptions; + gpGameState->x17c_gameOptions.EnsureOptions(); + gpGameState->PlayerState()->SetIsFusionEnabled(gpGameState->xa8_systemOptions.GetHasFusion()); +} + +// 800044A4 +void CMain::StreamNewGameState(CInputStream& in, int saveIdx) { + bool hasFusion = gpGameState->xa8_systemOptions.GetHasFusion(); + x128_gameGlobalObjects->x134_gameState = nullptr; + gpGameState = nullptr; + x128_gameGlobalObjects->x134_gameState = new CGameState(in, saveIdx); + gpGameState = x128_gameGlobalObjects->x134_gameState.get(); + gpGameState->xa8_systemOptions.SetHasFusion(hasFusion); + gpGameState->PlayerState()->SetIsFusionEnabled(gpGameState->xa8_systemOptions.GetHasFusion()); + gpGameState->x1f8_hintOptions.SetHintNextTime(); +} + +// 80004590 +void CMain::RefreshGameState() { + CSystemOptions systemOptions = gpGameState->xa8_systemOptions; + int saveIdx = gpGameState->x20c_saveIdx; + long long cardSerial = gpGameState->x210_cardSerial; + rstl::vector backupBuf = gpGameState->x218_backupBuf; + CGameOptions gameOptions = gpGameState->x17c_gameOptions; + x128_gameGlobalObjects->x134_gameState = NULL; + gpGameState = NULL; + { + CMemoryInStream stream(backupBuf.data(), backupBuf.size(), CMemoryInStream::Owned); + x128_gameGlobalObjects->x134_gameState = new CGameState(stream, saveIdx); + } + gpGameState = x128_gameGlobalObjects->x134_gameState.get(); + gpGameState->xa8_systemOptions = systemOptions; + gpGameState->x17c_gameOptions = gameOptions; + gpGameState->x17c_gameOptions.EnsureOptions(); + gpGameState->x210_cardSerial = cardSerial; + gpGameState->PlayerState()->SetIsFusionEnabled(gpGameState->xa8_systemOptions.GetHasFusion()); +} + +// 8000487C +void CMain::EnsureWorldPaksReady(void) { + CResLoader& resLoader = gpResourceFactory->GetResLoader(); + for (s32 i = 0; i < resLoader.GetPakCount(); ++i) { + CPakFile& file = resLoader.GetPakFile(i); + if (file.IsWorldPak()) { + file.EnsureWorldPakReady(); + } + } +} + +// 80004AEC +void CMain::AddWorldPaks() { + rstl::rmemory_allocator allocator; + rstl::string basePath = gpTweakGame->x4_; + for (int i = 0; i < 9; ++i) { + rstl::string pak = basePath + (i == 0 ? rstl::string_l("") : rstl::string(CBasics::Stringize("%d", i), -1, allocator)); + if (CDvdFile::FileExists((pak + rstl::string_l(".pak")).data())) { + gpResourceFactory->GetResLoader().AddPakFileAsync(pak, false, true); + } + } +} + +// 80004CE8 +void CMain::AsyncIdle(u32 time) { + if (time < 500) { + u32 total = 0; + for (int i = 0; i < x130_frameTimes.capacity(); ++i) { + total += x130_frameTimes[i]; + } + if (total < 500 * x130_frameTimes.capacity()) { + time = 500; + } else { + time = 0; + } + } + if (time != 0) { + gpResourceFactory->AsyncIdle(time); + } + x130_frameTimes[x15c_frameTimeIdx] = time; + x15c_frameTimeIdx = x15c_frameTimeIdx + 1; + if (x15c_frameTimeIdx >= x130_frameTimes.capacity()) { + x15c_frameTimeIdx = 0; + } +} + +// 80004DC8 +int CMain::RsMain(int argc, char** argv) { + PPCSetFpIEEEMode(); + CStopwatch timer; + LCEnable(); + + rstl::single_ptr gameGlobalObjects(new CGameGlobalObjects(x0_osContext, x6d_memorySys)); + x128_gameGlobalObjects = gameGlobalObjects.get(); + + for (int i = 0; i < 4; ++i) { + xf0_.AddValue(0.3f); + x104_.AddValue(0.2f); + } + + x118_ = 0.3f; + x11c_ = 0.2f; + InitializeSubsystems(); + gameGlobalObjects->PostInitialize(x0_osContext, x6d_memorySys); + x70_tweaks.RegisterTweaks(); + AddWorldPaks(); + + { + rstl::string str; + bool bVar1; + if (gpTweakManager->ReadFromMemoryCard(rstl::string_l("AudioTweaks"))) { + str = rstl::string_l("Loaded audio tweaks from memory card\n"); + bVar1 = true; + } else { + str = rstl::string_l("FAILED to load audio tweaks from memory card\n"); + bVar1 = true; + } + + FillInAssetIDs(); + + rstl::single_ptr archSupport(new CGameArchitectureSupport(x0_osContext)); + x164_ = archSupport.get(); + archSupport->PreloadAudio(); + + srand(timer.GetElapsedMicros()); + + if (lbl_805A8C54 != nullptr) { + CMemoryInStream stream(lbl_805A8C54, 0x80); + stream.ReadBits(1); + gpGameState->x17c_gameOptions = CGameOptions(stream); + gpGameState->x17c_gameOptions.EnsureOptions(); + lbl_805A6BC0 = stream.ReadBits(1); + } + + #define dt 1.0/60.0 + while (!x160_24_finished) { + archSupport->GetStopwatch2().Reset(); + gpResourceFactory->GetResLoader().AsyncIdlePakLoading(); + if (gpMemoryCard == nullptr && gpResourceFactory->GetResLoader().AreAllPaksLoaded()) { + MemoryCardInitializePump(); + } + CARAMManager::CollectGarbage(); + CARAMToken::UpdateAllDMAs(); + if (!archSupport->UpdateTicks()) { + x160_24_finished = true; + } + f64 t1 = archSupport->GetStopwatch2().GetElapsedTime(); + xf0_.AddValue(t1 / dt); + x118_ = xf0_.GetAverage().data(); + archSupport->GetStopwatch2().Reset(); + DoPredrawMetrics(); + + if (bVar1) { + bVar1 = false; + // rs_log_print(str.data()); + } + if (!x160_26_screenFading) { + gpRender->BeginScene(); + archSupport->GetIOWinManager().Draw(); + DrawDebugMetrics(t1, archSupport->GetStopwatch2()); + + f64 t2 = archSupport->GetStopwatch2().GetElapsedTime(); + x104_.AddValue(t2 / dt); + x11c_ = x104_.GetAverage().data(); + + u32 idleMicros; + f64 idleTime = (dt - (t1 + t2)) - 0.00075; + if (idleTime > 0) idleMicros = idleTime * 1000000; + else idleMicros = 0; + AsyncIdle(idleMicros); + + gpRender->EndScene(); + + if (x161_24_gameFrameDrawn) { + ++archSupport->GetFramesDrawn(); + x161_24_gameFrameDrawn = false; + } + } else { + gpResourceFactory->AsyncIdle(1000000); + } + + archSupport->Update(); + CSfxManager::Update(dt); + UpdateStreamedAudio(); + + if (CheckTerminate()) break; + bool needsReset = false; + if (archSupport->GetIOWinManager().IsEmpty()) { + // rs_log_print + needsReset = true; + } else if (CheckReset()) { + needsReset = true; + } + if (needsReset) { + x12c_flowState = 5; // Default + CStreamAudioManager::StopAll(); + sub_8038645c(0xf0000000); + CGraphics::SetIsBeginSceneClearFb(true); + CGraphics::BeginScene(); + CGraphics::EndScene(); + sub_8036ccfc(); + + archSupport = nullptr; + CGameArchitectureSupport* tmp = new CGameArchitectureSupport(x0_osContext); + archSupport = tmp; + x164_ = archSupport.get(); + tmp->PreloadAudio(); + } + nullsub_2(this); + } + } + ShutdownSubsystems(); + gameGlobalObjects = nullptr; + CARAMManager::Shutdown(); + return 0; +} \ No newline at end of file