Compare commits

..

34 Commits

Author SHA1 Message Date
madeline 1520205403 Merge branch 'main' of https://github.com/TakaRikka/dusk into vmem 2026-04-28 02:52:17 -07:00
madeline d2d7459d05 more granular heap grows 2026-04-28 02:49:24 -07:00
madeline c71272af05 virtual memory and actor spawner 2026-04-28 02:25:18 -07:00
TakaRikka 30b7087f30 add option for only fishing once for sera's cat 2026-04-27 22:04:42 -07:00
Luke Street 0c1372f986 Revert "Kinda crappy initial controller support"
This reverts commit 23a91a37be.
2026-04-27 21:55:57 -06:00
TakaRikka a4777045fe Merge pull request #578 from TwilitRealm/fix/fix-disable-hud
Fix bugs with Disable Main HUD
2026-04-27 15:29:02 -07:00
TakaRikka bbe8ea6aa6 Merge pull request #577 from TwilitRealm/better-freecam-code
Better Freecam code + Allow Freecam in Target mode
2026-04-27 15:28:39 -07:00
MelonSpeedruns d662db69f0 Fix bugs with Disable Main HUD 2026-04-27 17:04:42 -04:00
MelonSpeedruns 9b259143be Better Freecam code + Allow Freecam in Target mode 2026-04-27 12:05:26 -04:00
Irastris 5f33489465 Register interp callback for d_a_obj_lv8Lift 2026-04-27 01:04:45 -04:00
Luke Street 23a91a37be Kinda crappy initial controller support 2026-04-26 21:01:41 -06:00
TakaRikka a886f8a2df Merge pull request #568 from TwilitRealm/fix/d_a_obj_balloon
d_a_balloon score and interp fixes
2026-04-26 17:00:30 -07:00
TakaRikka 6df7b1e9cd Merge pull request #357 from TwilitRealm/speedrun-timer
speedrun timer
2026-04-26 16:59:47 -07:00
TakaRikka 206c02b527 fix igt timer 2026-04-26 16:51:10 -07:00
Pheenoh a05d1a9ee6 d_a_balloon score and interp fixes 2026-04-26 17:05:46 -06:00
Howard Luck ed0df01b8d Merge pull request #565 from TwilitRealm/fix/clib_offsetpos
cLib_offsetPos param aliasing fix
2026-04-26 16:09:26 -06:00
Pheenoh 0f9d563a3e cLib_offsetPos param aliasing fix 2026-04-26 15:59:45 -06:00
TakaRikka f3fb65495e Merge pull request #561 from TwilitRealm/fix/pal_lang
Only show language selection if PAL disc
2026-04-26 14:50:14 -07:00
TakaRikka 196f33005e Merge pull request #560 from TwilitRealm/fix/imgui-and-camera-x
ImGui Button name change + Fix Freecam Invert X Axis option
2026-04-26 14:49:40 -07:00
Luke Street 90c0bdded0 Use GXDestroyCopyTex on map destroy
Resolves #469
2026-04-26 14:02:28 -06:00
Pheenoh f856f871bb Only show languages if PAL disc 2026-04-26 13:58:38 -06:00
Jasper St. Pierre e75ea18ef0 map deco perf 2026-04-26 11:52:20 -07:00
Jasper St. Pierre 50e2d9d1a7 grass draw fix
closes #534
2026-04-26 11:18:25 -07:00
Jasper St. Pierre 5c84978c3c evil perf fix
closes #552
2026-04-26 10:44:52 -07:00
MelonSpeedruns 3859f39729 Fix camera radius to be smoother 2026-04-26 10:25:10 -04:00
MelonSpeedruns 3498ded9d9 ImGui Button name change + Fix Freecam Invert X Axis option 2026-04-26 10:18:47 -04:00
Phillip Stephens 8784958c40 Quick PAD rumble fixes, add button to test rumble configuration 2026-04-25 22:51:39 -07:00
Phillip Stephens c1231885fe Add rumble intensity sliders to input configurator (#558) 2026-04-25 23:17:17 -06:00
TakaRikka 6cf94b4491 remove unneeded file 2026-04-25 21:18:51 -07:00
TakaRikka 30aa2dd527 Merge branch 'main' of github.com:TwilitRealm/dusk into speedrun-timer 2026-04-25 21:16:27 -07:00
TakaRikka 8e121a7e51 update timer impl 2026-04-25 21:12:51 -07:00
TakaRikka 17949e526b Merge branch 'main' of github.com:TwilitRealm/dusk into speedrun-timer 2026-04-25 06:05:50 -07:00
TakaRikka 0d76b90144 Merge branch 'main' of https://github.com/TakaRikka/dusk into speedrun-timer 2026-04-14 04:10:28 -07:00
madeline a6690c2052 speedrun timer 2026-04-12 23:22:25 -07:00
56 changed files with 1413 additions and 152 deletions
+4
View File
@@ -306,6 +306,10 @@ if (DUSK_ENABLE_SENTRY_NATIVE)
list(APPEND GAME_COMPILE_DEFS DUSK_ENABLE_SENTRY_NATIVE=1 SENTRY_BUILD_STATIC=1) list(APPEND GAME_COMPILE_DEFS DUSK_ENABLE_SENTRY_NATIVE=1 SENTRY_BUILD_STATIC=1)
endif () endif ()
if (WIN32)
list(APPEND GAME_LIBS Ws2_32)
endif ()
if (DUSK_MOVIE_SUPPORT) if (DUSK_MOVIE_SUPPORT)
if (TARGET libjpeg-turbo::turbojpeg-static) if (TARGET libjpeg-turbo::turbojpeg-static)
list(APPEND GAME_LIBS libjpeg-turbo::turbojpeg-static) list(APPEND GAME_LIBS libjpeg-turbo::turbojpeg-static)
+1 -1
+3
View File
@@ -1453,6 +1453,7 @@ set(DUSK_FILES
src/dusk/imgui/ImGuiProcessOverlay.cpp src/dusk/imgui/ImGuiProcessOverlay.cpp
src/dusk/imgui/ImGuiCameraOverlay.cpp src/dusk/imgui/ImGuiCameraOverlay.cpp
src/dusk/imgui/ImGuiHeapOverlay.cpp src/dusk/imgui/ImGuiHeapOverlay.cpp
src/dusk/imgui/ImGuiActorSpawner.cpp
src/dusk/imgui/ImGuiDebugPad.cpp src/dusk/imgui/ImGuiDebugPad.cpp
src/dusk/imgui/ImGuiControllerOverlay.cpp src/dusk/imgui/ImGuiControllerOverlay.cpp
src/dusk/imgui/ImGuiStubLog.cpp src/dusk/imgui/ImGuiStubLog.cpp
@@ -1464,7 +1465,9 @@ set(DUSK_FILES
src/dusk/imgui/ImGuiAchievements.cpp src/dusk/imgui/ImGuiAchievements.cpp
src/dusk/achievements.cpp src/dusk/achievements.cpp
src/dusk/iso_validate.cpp src/dusk/iso_validate.cpp
src/dusk/livesplit.cpp
src/dusk/offset_ptr.cpp src/dusk/offset_ptr.cpp
src/dusk/vmem.cpp
src/dusk/OSContext.cpp src/dusk/OSContext.cpp
src/dusk/OSThread.cpp src/dusk/OSThread.cpp
src/dusk/OSMutex.cpp src/dusk/OSMutex.cpp
+3
View File
@@ -58,6 +58,9 @@ public:
void setNextPoint(); void setNextPoint();
int Draw(); int Draw();
int Delete(); int Delete();
#if TARGET_PC
friend void daL8Lift_interp_callback(bool isSimFrame, void* pUserWork);
#endif
u8 getPthID() { return fopAcM_GetParamBit(this, 0, 8); } u8 getPthID() { return fopAcM_GetParamBit(this, 0, 8); }
u8 getMoveSpeed() { return fopAcM_GetParamBit(this, 8, 4); } u8 getMoveSpeed() { return fopAcM_GetParamBit(this, 8, 4); }
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include <cstdint>
namespace dusk::speedrun {
void onGameFrame();
uint64_t getFrameCount();
void start();
void reset();
void connectLiveSplit(const char* host = "127.0.0.1", int port = 16834);
void disconnectLiveSplit();
bool consumeConnectedEvent();
bool consumeDisconnectedEvent();
void updateLiveSplit();
void shutdown();
}
-10
View File
@@ -1,10 +0,0 @@
#ifndef DUSK_MEMORY_H
#define DUSK_MEMORY_H
#if TARGET_PC
#define HEAP_SIZE(original, dusk) (dusk)
#else
#define HEAP_SIZE(original, dusk) (original)
#endif
#endif
+6
View File
@@ -76,6 +76,7 @@ struct UserSettings {
ConfigVar<bool> fastClimbing; ConfigVar<bool> fastClimbing;
ConfigVar<bool> noMissClimbing; ConfigVar<bool> noMissClimbing;
ConfigVar<bool> fastTears; ConfigVar<bool> fastTears;
ConfigVar<bool> no2ndFishForCat;
ConfigVar<bool> instantSaves; ConfigVar<bool> instantSaves;
ConfigVar<bool> instantText; ConfigVar<bool> instantText;
ConfigVar<bool> sunsSong; ConfigVar<bool> sunsSong;
@@ -96,6 +97,7 @@ struct UserSettings {
ConfigVar<int> internalResolutionScale; ConfigVar<int> internalResolutionScale;
ConfigVar<int> shadowResolutionMultiplier; ConfigVar<int> shadowResolutionMultiplier;
ConfigVar<bool> enableDepthOfField; ConfigVar<bool> enableDepthOfField;
ConfigVar<bool> enableMapBackground;
// Audio // Audio
ConfigVar<bool> noLowHpSound; ConfigVar<bool> noLowHpSound;
@@ -137,6 +139,10 @@ struct UserSettings {
// Controls // Controls
ConfigVar<bool> enableTurboKeybind; ConfigVar<bool> enableTurboKeybind;
// Tools
ConfigVar<bool> speedrunMode;
ConfigVar<bool> liveSplitEnabled;
} game; } game;
struct { struct {
+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include <stddef.h>
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
namespace dusk {
#endif
// Reserve a contiguous virtual address range without committing physical pages
void* vmem_reserve(size_t size);
// Commit physical backing for pages in a previously reserved range, ptr and size should be page-aligned
bool vmem_commit(void* ptr, size_t size);
// Decommit physical pages in a reserved range, releasing RAM without releasing address space
void vmem_decommit(void* ptr, size_t size);
// Release an entire virtual reservation obtained from vmem_reserve
void vmem_release(void* ptr, size_t size);
// Returns the OS page size
size_t vmem_page_size();
// Shared vmem arena
// All JKR heap vmem reservations are sub-allocated from a single large reservation,
// keeping the total entry count at 1 regardless of how many heaps exist
// Must be called once before any JKR heap is created
void vmem_arena_init();
// Allocate a slot of size bytes (page-aligned) from the arena
void* vmem_arena_alloc(size_t size);
// Return a slot to the arena and decommit its physical pages
void vmem_arena_free(void* ptr, size_t size);
#ifdef __cplusplus
} // namespace dusk
// Total virtual address space reserved for the shared JKR heap arena
inline constexpr size_t JKR_VMEM_ARENA_SIZE = 128ULL * 1024 * 1024 * 1024; // 128 GB
// Virtual address space reserved per JKR heap (one slot in the shared arena)
inline constexpr size_t JKR_HEAP_VIRTUAL_RESERVE = 64ULL * 1024 * 1024; // 64 MB
// Minimum growth increment when a JKR heap expands into reserved but uncommitted pages
inline constexpr size_t JKR_HEAP_GROW_CHUNK = 4ULL * 1024 * 1024; // 4 MB
// Maximum number of free slots the arena can track (= total slots in the arena)
inline constexpr size_t JKR_VMEM_MAX_FREE_SLOTS = JKR_VMEM_ARENA_SIZE / JKR_HEAP_VIRTUAL_RESERVE;
#endif
@@ -127,6 +127,13 @@ public:
[[nodiscard]] const CMemBlock* getFreeHead() const { return mHeadFreeList; } [[nodiscard]] const CMemBlock* getFreeHead() const { return mHeadFreeList; }
[[nodiscard]] CMemBlock* getUsedHead() { return mHeadUsedList; } [[nodiscard]] CMemBlock* getUsedHead() { return mHeadUsedList; }
[[nodiscard]] const CMemBlock* getUsedHead() const { return mHeadUsedList; } [[nodiscard]] const CMemBlock* getUsedHead() const { return mHeadUsedList; }
void* mVmemBase; // base of VM reservation
size_t mVmemCapacity; // total reserved bytes
size_t mVmemCommitted; // page-aligned committed bytes so far
// Commit more pages and splice them into the free list
bool growHeap(u32 needed);
#endif #endif
}; };
@@ -61,6 +61,15 @@ public:
static JKRSolidHeap* create(u32, JKRHeap*, bool); static JKRSolidHeap* create(u32, JKRHeap*, bool);
static void* getState_(TState* state) { return getState_buf_(state); } static void* getState_(TState* state) { return getState_buf_(state); }
#if TARGET_PC
void* mVmemBase; // base of VM reservation
size_t mVmemCapacity; // total reserved bytes
size_t mVmemCommitted; // page-aligned committed bytes so far
// Commit more pages and extend the free region
bool growHeap(u32 needed);
#endif
}; };
inline JKRSolidHeap* JKRCreateSolidHeap(u32 param_0, JKRHeap* heap, bool param_2) { inline JKRSolidHeap* JKRCreateSolidHeap(u32 param_0, JKRHeap* heap, bool param_2) {
+121 -6
View File
@@ -10,6 +10,11 @@
#include "JSystem/JUtility/JUTConsole.h" #include "JSystem/JUtility/JUTConsole.h"
#include "JSystem/JUtility/JUTException.h" #include "JSystem/JUtility/JUTException.h"
#include <cstdlib> #include <cstdlib>
#if TARGET_PC
#include "dusk/vmem.h"
#include <algorithm>
#include "dusk/logging.h"
#endif
JKRExpHeap* JKRExpHeap::createRoot(int maxHeaps, bool errorFlag) { JKRExpHeap* JKRExpHeap::createRoot(int maxHeaps, bool errorFlag) {
JKRExpHeap* heap = NULL; JKRExpHeap* heap = NULL;
@@ -71,21 +76,49 @@ JKRExpHeap* JKRExpHeap::create(u32 size, JKRHeap* parent, bool errorFlag) {
u32 alignedSize = ALIGN_PREV(size, 0x10); u32 alignedSize = ALIGN_PREV(size, 0x10);
if (alignedSize < expHeapSize + blockSize) if (alignedSize < expHeapSize + blockSize) {
return NULL; return NULL;
}
u8* memory = (u8*)JKRAllocFromHeap(parent, alignedSize, 0x10); #if TARGET_PC
u8* dataPtr = (memory + expHeapSize); u8* vmemBase = (u8*)dusk::vmem_arena_alloc(JKR_HEAP_VIRTUAL_RESERVE);
if (!vmemBase) {
return NULL;
}
const size_t pageSize = dusk::vmem_page_size();
size_t commitSize = ALIGN_NEXT((size_t)alignedSize, pageSize);
if (!dusk::vmem_commit(vmemBase, commitSize)) {
dusk::vmem_arena_free(vmemBase, JKR_HEAP_VIRTUAL_RESERVE);
return NULL;
}
u8* memory = vmemBase;
u8* dataPtr = memory + expHeapSize;
newHeap = JKR_NEW_ARGS(memory) JKRExpHeap(dataPtr, alignedSize - expHeapSize, parent, errorFlag);
if (newHeap == NULL) {
dusk::vmem_arena_free(vmemBase, JKR_HEAP_VIRTUAL_RESERVE);
return NULL;
}
newHeap->mVmemBase = vmemBase;
newHeap->mVmemCapacity = JKR_HEAP_VIRTUAL_RESERVE;
newHeap->mVmemCommitted = commitSize;
#else
u8* memory = (u8*)JKRAllocFromHeap(parent, alignedSize, 0x10);
u8* dataPtr = memory + expHeapSize;
if (!memory) { if (!memory) {
return NULL; return NULL;
} }
newHeap = JKR_NEW_ARGS (memory) JKRExpHeap(dataPtr, alignedSize - expHeapSize, parent, errorFlag); newHeap = JKR_NEW_ARGS(memory) JKRExpHeap(dataPtr, alignedSize - expHeapSize, parent, errorFlag);
if (newHeap == NULL) { if (newHeap == NULL) {
JKRFree(memory); JKRFree(memory);
return NULL; return NULL;
} }
#endif
#if DEBUG #if DEBUG
if (newHeap) { if (newHeap) {
u8* local_30 = dataPtr + sizeof(CMemBlock); u8* local_30 = dataPtr + sizeof(CMemBlock);
@@ -102,9 +135,16 @@ JKRExpHeap* JKRExpHeap::create(u32 size, JKRHeap* parent, bool errorFlag) {
JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* parent, bool errorFlag) { JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* parent, bool errorFlag) {
JKRHeap* parent2; JKRHeap* parent2;
if (parent == NULL) { if (parent == NULL) {
#if TARGET_PC
// VM-backed heaps live outside the root heap's address range, so find() fails
// findAllHeap() searches the full tree
parent2 = getRootHeap()->findAllHeap(ptr);
#else
parent2 = getRootHeap()->find(ptr); parent2 = getRootHeap()->find(ptr);
if (!parent2) #endif
if (!parent2) {
return NULL; return NULL;
}
} else { } else {
parent2 = parent; parent2 = parent;
} }
@@ -136,6 +176,15 @@ JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* parent, bool errorF
} }
void JKRExpHeap::do_destroy() { void JKRExpHeap::do_destroy() {
#if TARGET_PC
if (mVmemBase) {
void* vmemBase = mVmemBase;
size_t vmemCapacity = mVmemCapacity;
this->~JKRExpHeap();
dusk::vmem_arena_free(vmemBase, vmemCapacity);
return;
}
#endif
if (!field_0x6e) { if (!field_0x6e) {
JKRHeap* heap = getParent(); JKRHeap* heap = getParent();
if (heap) { if (heap) {
@@ -163,6 +212,11 @@ JKRExpHeap::JKRExpHeap(void* data, u32 size, JKRHeap* parent, bool errorFlag)
mHeadFreeList->initiate(NULL, NULL, size - sizeof(CMemBlock), 0, 0); mHeadFreeList->initiate(NULL, NULL, size - sizeof(CMemBlock), 0, 0);
mHeadUsedList = NULL; mHeadUsedList = NULL;
mTailUsedList = NULL; mTailUsedList = NULL;
#if TARGET_PC
mVmemBase = nullptr;
mVmemCapacity = 0;
mVmemCommitted = 0;
#endif
} }
JKRExpHeap::~JKRExpHeap() { JKRExpHeap::~JKRExpHeap() {
@@ -214,6 +268,24 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
#endif #endif
#if TARGET_PC #if TARGET_PC
if (!ptr && mVmemBase) {
// Heap is full, commit the next chunk of reserved VM and retry
if (growHeap(size)) {
if (alignment >= 0) {
if (alignment <= 4) {
ptr = allocFromHead(size);
} else {
ptr = allocFromHead(size, alignment);
}
} else {
if (-alignment <= 4) {
ptr = allocFromTail(size);
} else {
ptr = allocFromTail(size, -alignment);
}
}
}
}
if (!ptr) { if (!ptr) {
// Allocation failed. // Allocation failed.
OSReport_Error( OSReport_Error(
@@ -491,6 +563,49 @@ static void dummy() {
OS_REPORT("newSize > 0"); OS_REPORT("newSize > 0");
} }
#if TARGET_PC
bool JKRExpHeap::growHeap(u32 needed) {
// Determine how much to commit
// Always grow by at least JKR_HEAP_GROW_CHUNK
const size_t pageSize = dusk::vmem_page_size();
size_t wantBytes = (size_t)needed + sizeof(CMemBlock);
size_t growAmount = std::max(wantBytes, JKR_HEAP_GROW_CHUNK);
growAmount = ALIGN_NEXT(growAmount, pageSize);
size_t remaining = mVmemCapacity - mVmemCommitted;
if (growAmount > remaining) {
// Clamp to whatever reservation is left
growAmount = ALIGN_PREV(remaining, pageSize);
if (growAmount < wantBytes) {
return false;
}
}
void* commitBase = (u8*)mVmemBase + mVmemCommitted;
if (!dusk::vmem_commit(commitBase, growAmount)) {
return false;
}
// Splice the new committed region into the free list as a single block at mEnd
CMemBlock* newBlock = (CMemBlock*)mEnd;
newBlock->size = (u32)(growAmount - sizeof(CMemBlock));
newBlock->mFlags = 0;
mEnd = (u8*)mEnd + growAmount;
mSize += (u32)growAmount;
mVmemCommitted += growAmount;
recycleFreeBlock(newBlock);
DuskLog.debug("[JKRExpHeap] '{}' grew by {} MB (committed: {} MB / reserved: {} MB)\n",
getName(),
growAmount / (1024 * 1024),
mVmemCommitted / (1024 * 1024),
mVmemCapacity / (1024 * 1024));
return true;
}
#endif
void JKRExpHeap::do_freeAll() { void JKRExpHeap::do_freeAll() {
lock(); lock();
JKRHeap::callAllDisposer(); JKRHeap::callAllDisposer();
+115 -3
View File
@@ -1,4 +1,4 @@
#include "JSystem/JSystem.h" // IWYU pragma: keep #include "JSystem/JSystem.h" // IWYU pragma: keep
#include "JSystem/JKernel/JKRSolidHeap.h" #include "JSystem/JKernel/JKRSolidHeap.h"
#include "JSystem/JGadget/binary.h" #include "JSystem/JGadget/binary.h"
@@ -7,6 +7,11 @@
#include "global.h" #include "global.h"
#include <stdint.h> #include <stdint.h>
#include <cstdlib> #include <cstdlib>
#if TARGET_PC
#include "dusk/vmem.h"
#include <algorithm>
#include "dusk/logging.h"
#endif
JKRSolidHeap* JKRSolidHeap::create(u32 size, JKRHeap* heap, bool useErrorHandler) { JKRSolidHeap* JKRSolidHeap::create(u32 size, JKRHeap* heap, bool useErrorHandler) {
if (!heap) { if (!heap) {
@@ -19,18 +24,56 @@ JKRSolidHeap* JKRSolidHeap::create(u32 size, JKRHeap* heap, bool useErrorHandler
} }
u32 alignedSize = ALIGN_PREV(size, 0x10); u32 alignedSize = ALIGN_PREV(size, 0x10);
if (alignedSize < solidHeapSize) if (alignedSize < solidHeapSize) {
return NULL; return NULL;
}
#if TARGET_PC
u8* vmemBase = (u8*)dusk::vmem_arena_alloc(JKR_HEAP_VIRTUAL_RESERVE);
if (!vmemBase) {
return NULL;
}
const size_t pageSize = dusk::vmem_page_size();
size_t commitSize = ALIGN_NEXT((size_t)alignedSize, pageSize);
if (!dusk::vmem_commit(vmemBase, commitSize)) {
dusk::vmem_arena_free(vmemBase, JKR_HEAP_VIRTUAL_RESERVE);
return NULL;
}
u8* mem = vmemBase;
void* dataPtr = mem + solidHeapSize;
JKRSolidHeap* newHeap = JKR_NEW_ARGS(mem) JKRSolidHeap(dataPtr, alignedSize - solidHeapSize, heap, useErrorHandler);
if (newHeap == NULL) {
dusk::vmem_arena_free(vmemBase, JKR_HEAP_VIRTUAL_RESERVE);
return NULL;
}
newHeap->mVmemBase = vmemBase;
newHeap->mVmemCapacity = JKR_HEAP_VIRTUAL_RESERVE;
newHeap->mVmemCommitted = commitSize;
return newHeap;
#else
u8* mem = (u8*)JKRAllocFromHeap(heap, alignedSize, 0x10); u8* mem = (u8*)JKRAllocFromHeap(heap, alignedSize, 0x10);
void* dataPtr = mem + solidHeapSize; void* dataPtr = mem + solidHeapSize;
if (!mem) if (!mem) {
return NULL; return NULL;
}
return JKR_NEW_ARGS (mem) JKRSolidHeap(dataPtr, alignedSize - solidHeapSize, heap, useErrorHandler); return JKR_NEW_ARGS (mem) JKRSolidHeap(dataPtr, alignedSize - solidHeapSize, heap, useErrorHandler);
#endif
} }
void JKRSolidHeap::do_destroy(void) { void JKRSolidHeap::do_destroy(void) {
#if TARGET_PC
if (mVmemBase) {
void* vmemBase = mVmemBase;
size_t vmemCapacity = mVmemCapacity;
this->~JKRSolidHeap();
dusk::vmem_arena_free(vmemBase, vmemCapacity);
return;
}
#endif
JKRHeap* parent = getParent(); JKRHeap* parent = getParent();
if (parent) { if (parent) {
this->~JKRSolidHeap(); this->~JKRSolidHeap();
@@ -44,6 +87,11 @@ JKRSolidHeap::JKRSolidHeap(void* start, u32 size, JKRHeap* parent, bool useError
mSolidHead = (u8*)mStart; mSolidHead = (u8*)mStart;
mSolidTail = (u8*)mEnd; mSolidTail = (u8*)mEnd;
field_0x78 = NULL; field_0x78 = NULL;
#if TARGET_PC
mVmemBase = nullptr;
mVmemCapacity = 0;
mVmemCommitted = 0;
#endif
#if DEBUG #if DEBUG
if (mDebugFill) { if (mDebugFill) {
JKRFillMemory(mStart, mSize, JKRValue_DEBUGFILL_NOTUSE); JKRFillMemory(mStart, mSize, JKRValue_DEBUGFILL_NOTUSE);
@@ -59,6 +107,15 @@ s32 JKRSolidHeap::adjustSize(void) {
int r25 = 0; int r25 = 0;
JKRHeap* parent = getParent(); JKRHeap* parent = getParent();
if (parent) { if (parent) {
#if TARGET_PC
if (mVmemBase) {
// VM-backed heap, can't resize in parent, but this is not a failure
// Return what the trimmed size would have been so the caller doesn't log an error
u32 thisSize = (uintptr_t)mStart - (uintptr_t)this;
u32 newSize = ALIGN_NEXT(mSolidHead - mStart, 0x20);
return (s32)(thisSize + newSize);
}
#endif
lock(); lock();
u32 thisSize = (uintptr_t)mStart - (uintptr_t)this; u32 thisSize = (uintptr_t)mStart - (uintptr_t)this;
u32 newSize = ALIGN_NEXT(mSolidHead - mStart, 0x20); u32 newSize = ALIGN_NEXT(mSolidHead - mStart, 0x20);
@@ -110,6 +167,11 @@ void* JKRSolidHeap::allocFromHead(u32 size, int alignment) {
void* ptr = NULL; void* ptr = NULL;
uintptr_t alignedStart = (alignment - 1 + (uintptr_t)mSolidHead) & ~(alignment - 1); uintptr_t alignedStart = (alignment - 1 + (uintptr_t)mSolidHead) & ~(alignment - 1);
u32 totalSize = size + (alignedStart - (uintptr_t)mSolidHead); u32 totalSize = size + (alignedStart - (uintptr_t)mSolidHead);
#if TARGET_PC
if (totalSize > mFreeSize && mVmemBase) {
growHeap(totalSize);
}
#endif
if (totalSize <= mFreeSize) { if (totalSize <= mFreeSize) {
#if DEBUG #if DEBUG
if (mCheckMemoryFilled) { if (mCheckMemoryFilled) {
@@ -137,6 +199,15 @@ void* JKRSolidHeap::allocFromTail(u32 size, int alignment) {
void* ptr = NULL; void* ptr = NULL;
uintptr_t alignedStart = ALIGN_PREV((uintptr_t)mSolidTail - size, alignment); uintptr_t alignedStart = ALIGN_PREV((uintptr_t)mSolidTail - size, alignment);
u32 totalSize = (uintptr_t)mSolidTail - (uintptr_t)alignedStart; u32 totalSize = (uintptr_t)mSolidTail - (uintptr_t)alignedStart;
#if TARGET_PC
if (totalSize > mFreeSize && mVmemBase) {
if (growHeap(totalSize)) {
// mSolidTail moved to new mEnd; recompute from the new tail position
alignedStart = ALIGN_PREV((uintptr_t)mSolidTail - size, alignment);
totalSize = (uintptr_t)mSolidTail - (uintptr_t)alignedStart;
}
}
#endif
if (totalSize <= mFreeSize) { if (totalSize <= mFreeSize) {
ptr = (void*)alignedStart; ptr = (void*)alignedStart;
mSolidTail -= totalSize; mSolidTail -= totalSize;
@@ -158,6 +229,47 @@ void* JKRSolidHeap::allocFromTail(u32 size, int alignment) {
return ptr; return ptr;
} }
#if TARGET_PC
bool JKRSolidHeap::growHeap(u32 needed) {
// Growth is only safe when no tail allocations exist yet
if (mSolidTail != mEnd) {
return false;
}
const size_t pageSize = dusk::vmem_page_size();
size_t wantBytes = (size_t)needed;
size_t growAmount = std::max(wantBytes, JKR_HEAP_GROW_CHUNK);
growAmount = ALIGN_NEXT(growAmount, pageSize);
size_t remaining = mVmemCapacity - mVmemCommitted;
if (growAmount > remaining) {
growAmount = ALIGN_PREV(remaining, pageSize);
if (growAmount < wantBytes) {
return false;
}
}
void* commitBase = (u8*)mVmemBase + mVmemCommitted;
if (!dusk::vmem_commit(commitBase, growAmount)) {
return false;
}
// Extend the heap end and the tail pointer
mEnd = (u8*)mEnd + growAmount;
mSolidTail = mEnd;
mFreeSize += (u32)growAmount;
mSize += (u32)growAmount;
mVmemCommitted += growAmount;
DuskLog.debug("[JKRSolidHeap] '{}' grew by {} MB (committed: {} MB / reserved: {} MB)\n",
getName(),
growAmount / (1024 * 1024),
mVmemCommitted / (1024 * 1024),
mVmemCapacity / (1024 * 1024));
return true;
}
#endif
void JKRSolidHeap::do_free(void* ptr) { void JKRSolidHeap::do_free(void* ptr) {
JUTWarningConsole_f("free: cannot free memory block (%08x)\n", ptr); JUTWarningConsole_f("free: cannot free memory block (%08x)\n", ptr);
} }
+11
View File
@@ -468,9 +468,20 @@ s16 cLib_targetAngleX(cXyz const* lhs, cXyz const* rhs) {
void cLib_offsetPos(cXyz* pdest, cXyz const* psrc, s16 angle, cXyz const* vec) { void cLib_offsetPos(cXyz* pdest, cXyz const* psrc, s16 angle, cXyz const* vec) {
f32 cos = cM_scos(angle); f32 cos = cM_scos(angle);
f32 sin = cM_ssin(angle); f32 sin = cM_ssin(angle);
// MWCC loads vec members into registers before writing to pdest; other compilers may not,
// which corrupts results when pdest and vec alias the same memory.
#if !__MWERKS__
f32 vx = vec->x;
f32 vy = vec->y;
f32 vz = vec->z;
pdest->x = psrc->x + (vx * cos + vz * sin);
pdest->y = psrc->y + vy;
pdest->z = psrc->z + (vz * cos - vx * sin);
#else
pdest->x = psrc->x + (vec->x * cos + vec->z * sin); pdest->x = psrc->x + (vec->x * cos + vec->z * sin);
pdest->y = psrc->y + vec->y; pdest->y = psrc->y + vec->y;
pdest->z = psrc->z + (vec->z * cos - vec->x * sin); pdest->z = psrc->z + (vec->z * cos - vec->x * sin);
#endif
} }
/** /**
+10
View File
@@ -23,6 +23,7 @@
#include "d/actor/d_a_npc_tkc.h" #include "d/actor/d_a_npc_tkc.h"
#include <cstring> #include <cstring>
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/settings.h" #include "dusk/settings.h"
BOOL daAlink_c::checkEventRun() const { BOOL daAlink_c::checkEventRun() const {
@@ -4005,6 +4006,15 @@ int daAlink_c::procGanonFinishInit() {
field_0x37c8 = current.pos; field_0x37c8 = current.pos;
onEndResetFlg1(ERFLG1_SHIELD_BACKBONE); onEndResetFlg1(ERFLG1_SHIELD_BACKBONE);
#if TARGET_PC
if (dusk::getSettings().game.speedrunMode) {
if (dusk::m_speedrunInfo.m_isRunStarted) {
dusk::m_speedrunInfo.stopRun();
}
}
#endif
return 1; return 1;
} }
+14 -3
View File
@@ -6,6 +6,7 @@
#include "d/dolzel_rel.h" // IWYU pragma: keep #include "d/dolzel_rel.h" // IWYU pragma: keep
#include "d/actor/d_a_balloon_2D.h" #include "d/actor/d_a_balloon_2D.h"
#include "dusk/frame_interpolation.h"
#include "JSystem/J2DGraph/J2DGrafContext.h" #include "JSystem/J2DGraph/J2DGrafContext.h"
#include "JSystem/J2DGraph/J2DScreen.h" #include "JSystem/J2DGraph/J2DScreen.h"
#include "JSystem/J2DGraph/J2DTextBox.h" #include "JSystem/J2DGraph/J2DTextBox.h"
@@ -438,7 +439,12 @@ void daBalloon2D_c::setComboAlpha() {
void daBalloon2D_c::drawAddScore() { void daBalloon2D_c::drawAddScore() {
for (s32 i = 19; i >= 0; i--) { for (s32 i = 19; i >= 0; i--) {
if (field_0x5f8[i].field_0xe != 0) { if (field_0x5f8[i].field_0xe != 0) {
field_0x5f8[i].field_0xe--; #ifdef TARGET_PC
if (dusk::frame_interp::get_ui_tick_pending())
#endif
{
field_0x5f8[i].field_0xe--;
}
s32 score3; s32 score3;
s32 score2; s32 score2;
s32 score = field_0x5f8[i].field_0xc; s32 score = field_0x5f8[i].field_0xc;
@@ -446,8 +452,13 @@ void daBalloon2D_c::drawAddScore() {
u8 local_88 = 0xff; u8 local_88 = 0xff;
f32 dVar11 = 30.0f; f32 dVar11 = 30.0f;
f32 dVar9 = 30.0f; f32 dVar9 = 30.0f;
field_0x5f8[i].field_0x0.x += cM_ssin(temp0) * 0.3f; #ifdef TARGET_PC
field_0x5f8[i].field_0x0.y -= 1.0f; if (dusk::frame_interp::get_ui_tick_pending())
#endif
{
field_0x5f8[i].field_0x0.x += cM_ssin(temp0) * 0.3f;
field_0x5f8[i].field_0x0.y -= 1.0f;
}
if (field_0x5f8[i].field_0xe < 10) { if (field_0x5f8[i].field_0xe < 10) {
f32 fVar5 = field_0x5f8[i].field_0xe / 10.0f; f32 fVar5 = field_0x5f8[i].field_0xe / 10.0f;
local_88 = fVar5 * 255.0f; local_88 = fVar5 * 255.0f;
+1 -3
View File
@@ -14,8 +14,6 @@
#include "JSystem/J2DGraph/J2DAnmLoader.h" #include "JSystem/J2DGraph/J2DAnmLoader.h"
#include <cstring> #include <cstring>
#include "dusk/memory.h"
class daCoach2D_HIO_c : public mDoHIO_entry_c { class daCoach2D_HIO_c : public mDoHIO_entry_c {
public: public:
struct Param { struct Param {
@@ -155,7 +153,7 @@ int daCoach2D_c::createHeap() {
int daCoach2D_c::create() { int daCoach2D_c::create() {
int phase_state = dComIfG_resLoad(this, l_arcName); int phase_state = dComIfG_resLoad(this, l_arcName);
if (phase_state == cPhs_COMPLEATE_e) { if (phase_state == cPhs_COMPLEATE_e) {
if (!fopAcM_entrySolidHeap(this, daCoach2D_createHeap, HEAP_SIZE(0x5050, 0x6000))) { if (!fopAcM_entrySolidHeap(this, daCoach2D_createHeap, 0x5050)) {
return cPhs_ERROR_e; return cPhs_ERROR_e;
} }
+2 -3
View File
@@ -956,7 +956,7 @@ static void npc_ne_tame(npc_ne_class* i_this) {
i_this->mpMorf->setPlaySpeed(i_this->mAnmSpeed); i_this->mpMorf->setPlaySpeed(i_this->mAnmSpeed);
/* dSv_event_flag_c::F_0470 - Fishing Pond - Reserved for fishing */ /* dSv_event_flag_c::F_0470 - Fishing Pond - Reserved for fishing */
if (dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[470])) { if (IF_DUSK(dusk::getSettings().game.no2ndFishForCat) || dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[470])) {
if (fpcEx_Search(s_fish_sub, _this) != NULL) { if (fpcEx_Search(s_fish_sub, _this) != NULL) {
i_this->mAction = npc_ne_class::ACT_HOME; i_this->mAction = npc_ne_class::ACT_HOME;
i_this->mMode = 10; i_this->mMode = 10;
@@ -2948,8 +2948,7 @@ static int daNpc_Ne_Execute(npc_ne_class* i_this) {
if (i_this->mWantsFish && (i_this->mCounter & 0xf) == 0) { if (i_this->mWantsFish && (i_this->mCounter & 0xf) == 0) {
/* dSv_event_flag_c::F_0470 - Fishing Pond - Reserved for fishing */ /* dSv_event_flag_c::F_0470 - Fishing Pond - Reserved for fishing */
if (dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[470]) if ((IF_DUSK(dusk::getSettings().game.no2ndFishForCat) || dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[470])) && i_this->mDistToTarget < 1500.0f) {
&& i_this->mDistToTarget < 1500.0f) {
if (fopAcM_SearchByName(fpcNm_MG_ROD_e) != NULL) { if (fopAcM_SearchByName(fpcNm_MG_ROD_e) != NULL) {
i_this->mNoFollow = false; i_this->mNoFollow = false;
} else { } else {
+7
View File
@@ -205,6 +205,13 @@ int daObj_Balloon_c::_delete() {
Z2GetAudioMgr()->seStop(Z2SE_OBJ_WATERMILL_ROUND, 0); Z2GetAudioMgr()->seStop(Z2SE_OBJ_WATERMILL_ROUND, 0);
if (mHIOInit) { if (mHIOInit) {
hio_set = false; hio_set = false;
#ifdef TARGET_PC
// !@bug d_a_obj_balloon.rel unload used to zero these file-statics; with static linking they dangle across scenes.
m_combo_type = 0xFFFFFFFF;
m_combo_count = 0;
m_combo_next_score = 0;
m_balloon_score = 0;
#endif
} }
return 1; return 1;
} }
+41
View File
@@ -10,6 +10,10 @@
#include "d/d_path.h" #include "d/d_path.h"
#include "d/d_bg_w.h" #include "d/d_bg_w.h"
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#endif
daL8Lift_HIO_c::daL8Lift_HIO_c() { daL8Lift_HIO_c::daL8Lift_HIO_c() {
mStopDisappearTime = 30; mStopDisappearTime = 30;
mStartMoveTime = 60; mStartMoveTime = 60;
@@ -380,7 +384,44 @@ void daL8Lift_c::setNextPoint() {
mCurrentPoint = next_point; mCurrentPoint = next_point;
} }
#if TARGET_PC
void daL8Lift_interp_callback(bool isSimFrame, void* pUserWork) {
daL8Lift_c* lift = static_cast<daL8Lift_c*>(pUserWork);
if (lift == NULL || lift->mpModel == NULL) {
return;
}
g_env_light.settingTevStruct(0x10, &lift->current.pos, &lift->tevStr);
g_env_light.setLightTevColorType_MAJI(lift->mpModel, &lift->tevStr);
J3DModelData* modelData = lift->mpModel->getModelData();
J3DMaterial* materialp = modelData->getMaterialNodePointer(0);
if (materialp->getTexGenBlock()->getTexMtx(1) != NULL) {
J3DTexMtxInfo* mtx_info = &materialp->getTexGenBlock()->getTexMtx(1)->getTexMtxInfo();
if (mtx_info != NULL) {
Mtx m;
C_MTXLightOrtho(m, 100.0f, -100.0f, -100.0f, 100.0f, 1.0f, 1.0f, 0.0f, 0.0f);
mDoMtx_stack_c::XrotS(0x4000);
mDoMtx_stack_c::transM(-lift->current.pos.x, -lift->current.pos.y, -lift->current.pos.z);
cMtx_concat(m, mDoMtx_stack_c::get(), mtx_info->mEffectMtx);
}
}
lift->mBtk.entry(modelData);
J3DGXColor* color = materialp->getTevKColor(1);
color->r = l_HIO.mColorR;
color->g = l_HIO.mColorG;
color->b = l_HIO.mColorB;
}
#endif
int daL8Lift_c::Draw() { int daL8Lift_c::Draw() {
#if TARGET_PC
dusk::frame_interp::add_interpolation_callback(&daL8Lift_interp_callback, this);
#endif
g_env_light.settingTevStruct(16, &current.pos, &tevStr); g_env_light.settingTevStruct(16, &current.pos, &tevStr);
g_env_light.setLightTevColorType_MAJI(mpModel, &tevStr); g_env_light.setLightTevColorType_MAJI(mpModel, &tevStr);
J3DModelData* modelData = mpModel->getModelData(); J3DModelData* modelData = mpModel->getModelData();
+2 -12
View File
@@ -7,13 +7,8 @@
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
#if TARGET_PC
const u16 l_J_Ohana00_64TEX__width = 64;
const u16 l_J_Ohana00_64TEX__height = 64;
#else
const u16 l_J_Ohana00_64TEX__width = 63; const u16 l_J_Ohana00_64TEX__width = 63;
const u16 l_J_Ohana00_64TEX__height = 63; const u16 l_J_Ohana00_64TEX__height = 63;
#endif
#if TARGET_PC #if TARGET_PC
#include "dusk/dvd_asset.hpp" #include "dusk/dvd_asset.hpp"
@@ -136,13 +131,8 @@ l_matDL__d_a_grass(l_J_Ohana00_64TEX)
l_matLight4DL(l_J_Ohana00_64TEX) l_matLight4DL(l_J_Ohana00_64TEX)
#endif #endif
#if TARGET_PC
const u16 l_J_Ohana01_64128_0419TEX__width = 64;
const u16 l_J_Ohana01_64128_0419TEX__height = 128;
#else
const u16 l_J_Ohana01_64128_0419TEX__width = 63; const u16 l_J_Ohana01_64128_0419TEX__width = 63;
const u16 l_J_Ohana01_64128_0419TEX__height = 127; const u16 l_J_Ohana01_64128_0419TEX__height = 127;
#endif
#if TARGET_PC #if TARGET_PC
using GameVersion = dusk::version::GameVersion; using GameVersion = dusk::version::GameVersion;
@@ -592,11 +582,11 @@ dFlower_packet_c::dFlower_packet_c() {
#if TARGET_PC #if TARGET_PC
GXInitTexObj(&mTexObj_l_J_Ohana00_64TEX, l_J_Ohana00_64TEX, GXInitTexObj(&mTexObj_l_J_Ohana00_64TEX, l_J_Ohana00_64TEX,
l_J_Ohana00_64TEX__width, l_J_Ohana00_64TEX__height, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE l_J_Ohana00_64TEX__width + 1, l_J_Ohana00_64TEX__height + 1, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE
); );
GXInitTexObj(&mTexObj_l_J_Ohana01_64128_0419TEX, l_J_Ohana01_64128_0419TEX, GXInitTexObj(&mTexObj_l_J_Ohana01_64128_0419TEX, l_J_Ohana01_64128_0419TEX,
l_J_Ohana01_64128_0419TEX__width, l_J_Ohana01_64128_0419TEX__height, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE l_J_Ohana01_64128_0419TEX__width + 1, l_J_Ohana01_64128_0419TEX__height + 1, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE
); );
#endif #endif
+6 -8
View File
@@ -494,11 +494,11 @@ dGrass_packet_c::dGrass_packet_c() {
#if TARGET_PC #if TARGET_PC
GXInitTexObj(&mTexObj_l_M_kusa05_RGBATEX, l_M_kusa05_RGBATEX, GXInitTexObj(&mTexObj_l_M_kusa05_RGBATEX, l_M_kusa05_RGBATEX,
l_M_kusa05_RGBATEX__width, l_M_kusa05_RGBATEX__height, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE l_M_kusa05_RGBATEX__width + 1, l_M_kusa05_RGBATEX__height + 1, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE
); );
GXInitTexObj(&mTexObj_l_M_Hijiki00TEX, l_M_Hijiki00TEX, GXInitTexObj(&mTexObj_l_M_Hijiki00TEX, l_M_Hijiki00TEX,
l_M_Hijiki00TEX__width, l_M_Hijiki00TEX__height, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE l_M_Hijiki00TEX__width + 1, l_M_Hijiki00TEX__height + 1, GX_TF_RGB5A3, GX_REPEAT, GX_CLAMP, GX_FALSE
); );
#endif #endif
@@ -646,18 +646,14 @@ void dGrass_packet_c::draw() {
} }
if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) { if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) {
#if TARGET_PC IF_DUSK(GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0));
GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0);
#endif
if (sp48 <= 3) { if (sp48 <= 3) {
GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size); GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size);
} else { } else {
GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size); GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size);
} }
} else { } else {
#if TARGET_PC IF_DUSK(GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0));
GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0);
#endif
GXCallDisplayList(l_Tengusa_matDL, 0xA0); GXCallDisplayList(l_Tengusa_matDL, 0xA0);
} }
@@ -683,12 +679,14 @@ void dGrass_packet_c::draw() {
while (var_r29 != NULL) { while (var_r29 != NULL) {
if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) { if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) {
IF_DUSK(GXLoadTexObj(&mTexObj_l_M_kusa05_RGBATEX, GX_TEXMAP0));
if (sp48 <= 2) { if (sp48 <= 2) {
GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size); GXCallDisplayList(mp_kusa9q_14_DL, m_kusa9q_DL_14_size);
} else { } else {
GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size); GXCallDisplayList(mp_kusa9q_DL, m_kusa9q_DL_size);
} }
} else { } else {
IF_DUSK(GXLoadTexObj(&mTexObj_l_M_Hijiki00TEX, GX_TEXMAP0));
GXCallDisplayList(l_Tengusa_matDL, 0xA0); GXCallDisplayList(l_Tengusa_matDL, 0xA0);
} }
+13
View File
@@ -9,6 +9,8 @@
#include "JSystem/J2DGraph/J2DScreen.h" #include "JSystem/J2DGraph/J2DScreen.h"
#include "JSystem/J2DGraph/J2DTextBox.h" #include "JSystem/J2DGraph/J2DTextBox.h"
#include "d/d_msg_string.h" #include "d/d_msg_string.h"
#include "dusk/livesplit.h"
#include "dusk/imgui/ImGuiConsole.hpp"
#include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_controller_pad.h"
dBrightCheck_c::dBrightCheck_c(JKRArchive* i_archive) { dBrightCheck_c::dBrightCheck_c(JKRArchive* i_archive) {
@@ -138,6 +140,17 @@ void dBrightCheck_c::modeWait() {}
void dBrightCheck_c::modeMove() { void dBrightCheck_c::modeMove() {
if (mDoCPd_c::getTrigA(PAD_1) || mDoCPd_c::getTrigStart(PAD_1)) { if (mDoCPd_c::getTrigA(PAD_1) || mDoCPd_c::getTrigStart(PAD_1)) {
mDoAud_seStart(Z2SE_ENTER_GAME, NULL, 0, 0); mDoAud_seStart(Z2SE_ENTER_GAME, NULL, 0, 0);
#ifdef TARGET_PC
dusk::speedrun::start();
if (dusk::getSettings().game.speedrunMode && !dusk::getSettings().game.hideTvSettingsScreen) {
// start a new run if a run isn't already in progress
if (!dusk::m_speedrunInfo.m_isRunStarted) {
dusk::ImGuiMenuGame::resetForSpeedrunMode();
dusk::m_speedrunInfo.startRun();
}
}
#endif
mCompleteCheck = true; mCompleteCheck = true;
mMode = MODE_WAIT_e; mMode = MODE_WAIT_e;
} }
+36 -24
View File
@@ -794,16 +794,15 @@ void dCamera_c::updatePad() {
if (mTriggerLeftLast > mCamSetup.ManualEndVal()) { if (mTriggerLeftLast > mCamSetup.ManualEndVal()) {
if (mLockLActive == 0) { if (mLockLActive == 0) {
#if TARGET_PC
mCamParam.mManualMode = 0;
#endif
mLockLJustActivated = 1; mLockLJustActivated = 1;
} else { } else {
mLockLJustActivated = 0; mLockLJustActivated = 0;
} }
mLockLActive = 1; mLockLActive = 1;
#if TARGET_PC
mCamParam.mManualMode = 0;
#endif
} else { } else {
mLockLJustActivated = 0; mLockLJustActivated = 0;
mLockLActive = 0; mLockLActive = 0;
@@ -1178,12 +1177,6 @@ bool dCamera_c::Run() {
} else { } else {
sp0F = (this->*engine_tbl[mCamParam.Algorythmn(mCamStyle)])(mCamStyle); sp0F = (this->*engine_tbl[mCamParam.Algorythmn(mCamStyle)])(mCamStyle);
#if TARGET_PC
if (mCamParam.Algorythmn(mCamStyle) != 1) {
mCamParam.mManualMode = 0;
}
#endif
field_0x170++; field_0x170++;
field_0x160++; field_0x160++;
mCurCamStyleTimer++; mCurCamStyleTimer++;
@@ -3527,6 +3520,12 @@ void dCamera_c::checkGroundInfo() {
} }
bool dCamera_c::chaseCamera(s32 param_0) { bool dCamera_c::chaseCamera(s32 param_0) {
#if TARGET_PC
if (freeCamera()) {
return 1;
}
#endif
static f32 JumpCushion = 0.9f; static f32 JumpCushion = 0.9f;
f32 charge_latitude = mCamSetup.ChargeLatitude(); f32 charge_latitude = mCamSetup.ChargeLatitude();
int charge_timer = mCamSetup.ChargeTimer(); int charge_timer = mCamSetup.ChargeTimer();
@@ -4631,10 +4630,6 @@ bool dCamera_c::chaseCamera(s32 param_0) {
sp110 = mViewCache.mDirection.R(); sp110 = mViewCache.mDirection.R();
mViewCache.mDirection.R(mViewCache.mDirection.R() + (fVar55 - mViewCache.mDirection.R()) * chase->field_0x74); mViewCache.mDirection.R(mViewCache.mDirection.R() + (fVar55 - mViewCache.mDirection.R()) * chase->field_0x74);
#if TARGET_PC
freeCamera();
#endif
chase->field_0x64 = mViewCache.mCenter + mViewCache.mDirection.Xyz(); chase->field_0x64 = mViewCache.mCenter + mViewCache.mDirection.Xyz();
mViewCache.mEye = chase->field_0x64; mViewCache.mEye = chase->field_0x64;
@@ -7482,6 +7477,9 @@ bool dCamera_c::freeCamera() {
return false; return false;
} }
mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree();
mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree();
cXyz camMovement = {mPadInfo.mCStick.mLastPosX, mPadInfo.mCStick.mLastPosY, 0.0f}; cXyz camMovement = {mPadInfo.mCStick.mLastPosX, mPadInfo.mCStick.mLastPosY, 0.0f};
f32 magnitude = sqrt(mPadInfo.mCStick.mLastPosX * mPadInfo.mCStick.mLastPosX + mPadInfo.mCStick.mLastPosY * mPadInfo.mCStick.mLastPosY); f32 magnitude = sqrt(mPadInfo.mCStick.mLastPosX * mPadInfo.mCStick.mLastPosX + mPadInfo.mCStick.mLastPosY * mPadInfo.mCStick.mLastPosY);
@@ -7493,20 +7491,34 @@ bool dCamera_c::freeCamera() {
} }
camMovement = camMovement.normalize(); camMovement = camMovement.normalize();
camMovement.x *= (dusk::getSettings().game.invertCameraXAxis ? 1.0f : -1.0f) * dusk::getSettings().game.freeCameraSensitivity * 4.0f; camMovement.y *= dusk::getSettings().game.invertCameraYAxis ? 1.0f : -1.0f;
camMovement.y *= (dusk::getSettings().game.invertCameraYAxis ? 1.0f : -1.0f) * dusk::getSettings().game.freeCameraSensitivity * 4.0f; mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity * 4.0f;
mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity; mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity * 4.0f;
mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity;
} }
if (mCamParam.mManualMode) { if (!mCamParam.mManualMode) {
mCamParam.freeYAngle = std::clamp(mCamParam.freeYAngle, -35.0f, 60.0f); return false;
mViewCache.mDirection.mAzimuth = cSAngle(mCamParam.freeXAngle);
mViewCache.mDirection.mInclination = cSAngle(mCamParam.freeYAngle);
mViewCache.mDirection.mRadius = std::clamp(mCamParam.freeYAngle * 15.0f, 300.0f, 10000.0f);
} }
return mCamParam.mManualMode; f32 minYAngle = -10.0f;
f32 maxAngle = 50.0f;
mCamParam.freeYAngle = std::clamp(mCamParam.freeYAngle, minYAngle, maxAngle);
mViewCache.mDirection.mAzimuth = cSAngle(mCamParam.freeXAngle);
mViewCache.mDirection.mInclination = cSAngle(mCamParam.freeYAngle);
f32 currentLerp = (mCamParam.freeYAngle - minYAngle) / (maxAngle - minYAngle);
mViewCache.mDirection.mRadius = std::lerp(200.0f, 1000.0f, currentLerp);
cXyz finalCenter = mpPlayerActor->current.pos;
finalCenter.y += mIsWolf ? 90.0f : 100.0f;
mViewCache.mCenter = finalCenter;
cXyz finalEye = finalCenter + mViewCache.mDirection.Xyz();
mViewCache.mEye = finalEye;
mViewCache.mFovy = 60.0f;
return true;
} }
#endif #endif
+7
View File
@@ -78,7 +78,14 @@ void dEyeHL_mng_c::remove(dEyeHL_c* i_obj) {
next = m_obj; next = m_obj;
} }
#if TARGET_PC
// Skip the write if the heap owning m_timg was already destroyed
if (JKRHeap::findFromRoot(i_obj->m_timg) != nullptr) {
i_obj->m_timg->LODBias = i_obj->m_lodBias;
}
#else
i_obj->m_timg->LODBias = i_obj->m_lodBias; i_obj->m_timg->LODBias = i_obj->m_lodBias;
#endif
i_obj->m_timg = NULL; i_obj->m_timg = NULL;
i_obj->m_pre = NULL; i_obj->m_pre = NULL;
i_obj->m_next = NULL; i_obj->m_next = NULL;
+1 -2
View File
@@ -6,7 +6,6 @@
#include "d/dolzel.h" // IWYU pragma: keep #include "d/dolzel.h" // IWYU pragma: keep
#include "d/d_k_wmark.h" #include "d/d_k_wmark.h"
#include "dusk/memory.h"
#include "JSystem/J3DGraphBase/J3DMaterial.h" #include "JSystem/J3DGraphBase/J3DMaterial.h"
#include "SSystem/SComponent/c_math.h" #include "SSystem/SComponent/c_math.h"
#include "d/actor/d_a_player.h" #include "d/actor/d_a_player.h"
@@ -34,7 +33,7 @@ int dkWmark_c::create() {
mColorType = this->parameters; mColorType = this->parameters;
} }
mpHeap = mDoExt_createSolidHeapFromGameToCurrent(HEAP_SIZE(0x880, 0x1100), 0x20); mpHeap = mDoExt_createSolidHeapFromGameToCurrent(0x880, 0x20);
if (mpHeap != NULL) { if (mpHeap != NULL) {
JKRHEAP_NAME(mpHeap, "dkWmark_c::mpHeap"); JKRHEAP_NAME(mpHeap, "dkWmark_c::mpHeap");
J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes("Alink", 0x23); J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes("Alink", 0x23);
+1 -2
View File
@@ -1,7 +1,6 @@
#include "d/dolzel.h" // IWYU pragma: keep #include "d/dolzel.h" // IWYU pragma: keep
#include "d/d_kankyo.h" #include "d/d_kankyo.h"
#include "dusk/memory.h"
#ifdef __REVOLUTION_SDK__ #ifdef __REVOLUTION_SDK__
#include <revolution.h> #include <revolution.h>
#else #else
@@ -1186,7 +1185,7 @@ static void undwater_init() {
J3DModelData* modelData2 = (J3DModelData*)dComIfG_getObjectRes("Always", 0x1D); J3DModelData* modelData2 = (J3DModelData*)dComIfG_getObjectRes("Always", 0x1D);
JUT_ASSERT(1867, modelData2 != NULL); JUT_ASSERT(1867, modelData2 != NULL);
g_env_light.undwater_ef_heap = mDoExt_createSolidHeapFromGameToCurrent(HEAP_SIZE(0x600, 0xC00), 0x20); g_env_light.undwater_ef_heap = mDoExt_createSolidHeapFromGameToCurrent(0x600, 0x20);
JKRHEAP_NAME(g_env_light.undwater_ef_heap, "g_env_light.undwater_ef_heap"); JKRHEAP_NAME(g_env_light.undwater_ef_heap, "g_env_light.undwater_ef_heap");
if (g_env_light.undwater_ef_heap != NULL) { if (g_env_light.undwater_ef_heap != NULL) {
+28 -3
View File
@@ -5962,6 +5962,8 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) {
fopAc_ac_c* player = dComIfGp_getPlayer(0); fopAc_ac_c* player = dComIfGp_getPlayer(0);
if (evil_packet != NULL) { if (evil_packet != NULL) {
IF_DUSK(GXPushDebugGroup("dKyr_evil_draw2"));
j3dSys.reinitGX(); j3dSys.reinitGX();
if (dComIfGd_getView() != NULL) { if (dComIfGd_getView() != NULL) {
MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx); MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx);
@@ -6162,6 +6164,8 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) {
} }
} }
IF_DUSK(GXPopDebugGroup());
GXSetClipMode(GX_CLIP_ENABLE); GXSetClipMode(GX_CLIP_ENABLE);
J3DShape::resetVcdVatCache(); J3DShape::resetVcdVatCache();
} }
@@ -6199,6 +6203,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
f32 sp60 = fabsf(cM_ssin(g_Counter.mCounter0 * 215)); f32 sp60 = fabsf(cM_ssin(g_Counter.mCounter0 * 215));
if (evil_packet != NULL) { if (evil_packet != NULL) {
IF_DUSK(GXPushDebugGroup("dKyr_evil_draw"));
j3dSys.reinitGX(); j3dSys.reinitGX();
if (dComIfGd_getView() != NULL) { if (dComIfGd_getView() != NULL) {
MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx); MTXInverse(dComIfGd_getView()->viewMtxNoTrans, camMtx);
@@ -6231,8 +6237,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
GXLoadPosMtxImm(drawMtx, GX_PNMTX0); GXLoadPosMtxImm(drawMtx, GX_PNMTX0);
GXSetCurrentMtx(GX_PNMTX0); GXSetCurrentMtx(GX_PNMTX0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_F32, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBA4, 8); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_RGBA4, 8);
GXClearVtxDesc(); GXClearVtxDesc();
GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
@@ -6255,6 +6261,19 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
GXSetClipMode(GX_CLIP_DISABLE); GXSetClipMode(GX_CLIP_DISABLE);
GXSetNumIndStages(0); GXSetNumIndStages(0);
#if TARGET_PC
// move color_reg0 to vtx for perf
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
GXSetNumChans(1);
GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE);
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_C1, GX_CC_RASC, GX_CC_TEXC, GX_CC_ZERO);
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, GX_CA_ZERO);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
#endif
dComIfG_Ccsp()->PrepareMass(); dComIfG_Ccsp()->PrepareMass();
for (int i = 0; i < g_env_light.field_0x1054; i++) { for (int i = 0; i < g_env_light.field_0x1054; i++) {
@@ -6373,7 +6392,7 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
color_reg0.b = (115.0f * sp28) + (15.0f * fabsf(sp2C - sp64)); color_reg0.b = (115.0f * sp28) + (15.0f * fabsf(sp2C - sp64));
} }
GXSetTevColor(GX_TEVREG0, color_reg0); IF_NOT_DUSK(GXSetTevColor(GX_TEVREG0, color_reg0));
GXSetTevColor(GX_TEVREG1, color_reg1); GXSetTevColor(GX_TEVREG1, color_reg1);
spC8 = spA4; spC8 = spA4;
@@ -6412,12 +6431,16 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
GXBegin(GX_QUADS, GX_VTXFMT0, 4); GXBegin(GX_QUADS, GX_VTXFMT0, 4);
GXPosition3f32(pos[0].x, pos[0].y, pos[0].z); GXPosition3f32(pos[0].x, pos[0].y, pos[0].z);
IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a));
GXTexCoord2s16(0, 0); GXTexCoord2s16(0, 0);
GXPosition3f32(pos[1].x, pos[1].y, pos[1].z); GXPosition3f32(pos[1].x, pos[1].y, pos[1].z);
IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a));
GXTexCoord2s16(0xFF, 0); GXTexCoord2s16(0xFF, 0);
GXPosition3f32(pos[2].x, pos[2].y, pos[2].z); GXPosition3f32(pos[2].x, pos[2].y, pos[2].z);
IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a));
GXTexCoord2s16(0xFF, 0xFF); GXTexCoord2s16(0xFF, 0xFF);
GXPosition3f32(pos[3].x, pos[3].y, pos[3].z); GXPosition3f32(pos[3].x, pos[3].y, pos[3].z);
IF_DUSK(GXColor4u8(color_reg0.r, color_reg0.g, color_reg0.b, color_reg0.a));
GXTexCoord2s16(0, 0xFF); GXTexCoord2s16(0, 0xFF);
GXEnd(); GXEnd();
} }
@@ -6425,6 +6448,8 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) {
} }
} }
IF_DUSK(GXPopDebugGroup());
J3DShape::resetVcdVatCache(); J3DShape::resetVcdVatCache();
GXSetClipMode(GX_CLIP_ENABLE); GXSetClipMode(GX_CLIP_ENABLE);
+10 -7
View File
@@ -13,6 +13,9 @@
#include "SSystem/SComponent/c_math.h" #include "SSystem/SComponent/c_math.h"
#include "d/actor/d_a_player.h" #include "d/actor/d_a_player.h"
#include "d/d_com_inf_game.h" #include "d/d_com_inf_game.h"
#if TARGET_PC
#include <dolphin/gx/GXExtra.h>
#endif
#include <cstring> #include <cstring>
#if DEBUG #if DEBUG
@@ -539,17 +542,14 @@ void renderingAmap_c::rendering(dDrawPath_c::poly_class const* i_poly) {
} }
} }
/* Enabling the following definition will modify the following function to
* make the map look worse for extra speed in the emulator, especially in large
* areas such as hyrule field.
*/
#define HYRULE_FIELD_SPEEDHACK
bool renderingAmap_c::isDrawOutSideTrim() { bool renderingAmap_c::isDrawOutSideTrim() {
bool rt = false; bool rt = false;
#ifdef HYRULE_FIELD_SPEEDHACK #if TARGET_PC
return 0; if (!dusk::getSettings().game.enableMapBackground) {
return 0;
}
#endif #endif
if (getDispType() == 0 || getDispType() == 4 || getDispType() == 3 || getDispType() == 2 || if (getDispType() == 0 || getDispType() == 4 || getDispType() == 3 || getDispType() == 2 ||
@@ -1218,6 +1218,9 @@ void dMap_c::changeTextureSize(int param_1, int param_2, int param_3) {
void dMap_c::_remove() { void dMap_c::_remove() {
if (mImage_p != NULL) { if (mImage_p != NULL) {
#if TARGET_PC
GXDestroyCopyTex(mImage_p);
#endif
JKR_DELETE_ARRAY(mImage_p); JKR_DELETE_ARRAY(mImage_p);
mImage_p = NULL; mImage_p = NULL;
} }
+26 -8
View File
@@ -497,12 +497,6 @@ void dRenderingFDAmap_c::postRenderingMap() {
dMpath_n::dTexObjAggregate_c dMpath_n::m_texObjAgg; dMpath_n::dTexObjAggregate_c dMpath_n::m_texObjAgg;
/* Enabling the following definition will modify the following function to
* make the map look worse for extra speed in the emulator, especially in large
* areas such as hyrule field.
*/
#define HYRULE_FIELD_SPEEDHACK
void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_line) { void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_line) {
s32 width = getDecorationLineWidth(p_line->field_0x1); s32 width = getDecorationLineWidth(p_line->field_0x1);
if (width <= 0) { if (width <= 0) {
@@ -527,8 +521,32 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li
lineColor.r = lineColor.r - 4; lineColor.r = lineColor.r - 4;
GXSetTevColor(GX_TEVREG1, lineColor); GXSetTevColor(GX_TEVREG1, lineColor);
#if TARGET_PC
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_KONST);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXBegin(GX_LINESTRIP, GX_VTXFMT0, 2 * (data_num - 1));
for (int i = 0; i < data_num - 1; i++) {
GXPosition1x16(data_p[i]);
GXTexCoord2f32(0, 0);
GXPosition1x16(data_p[i + 1]);
GXTexCoord2f32(0, 0);
}
GXEnd();
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_KONST, GX_CC_TEXC, GX_CC_C1);
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXBegin(GX_POINTS, GX_VTXFMT0, data_num);
for (int i = 0; i < data_num; i++) {
GXPosition1x16(data_p[i]);
GXTexCoord2f32(0, 0);
}
GXEnd();
#else
for (int i = 0; i < data_num; i++) { for (int i = 0; i < data_num; i++) {
#ifndef HYRULE_FIELD_SPEEDHACK
if (i < data_num - 1) { if (i < data_num - 1) {
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0); GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0);
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE,
@@ -547,7 +565,6 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA); GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA);
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV);
#endif
GXBegin(GX_POINTS, GX_VTXFMT0, 1); GXBegin(GX_POINTS, GX_VTXFMT0, 1);
GXPosition1x16(data_p[0]); GXPosition1x16(data_p[0]);
@@ -555,6 +572,7 @@ void dRenderingFDAmap_c::renderingDecoration(dDrawPath_c::line_class const* p_li
GXEnd(); GXEnd();
data_p++; data_p++;
} }
#endif
setTevSettingNonTextureDirectColor(); setTevSettingNonTextureDirectColor();
GXClearVtxDesc(); GXClearVtxDesc();
+6
View File
@@ -11,6 +11,9 @@
#include "d/d_menu_dmap_map.h" #include "d/d_menu_dmap_map.h"
#include "f_op/f_op_msg_mng.h" #include "f_op/f_op_msg_mng.h"
#include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_graphic.h"
#if TARGET_PC
#include <dolphin/gx/GXExtra.h>
#endif
struct dMdm_HIO_prm_res_dst_s { struct dMdm_HIO_prm_res_dst_s {
static void* m_res; static void* m_res;
@@ -291,6 +294,9 @@ void dMenu_DmapMap_c::_create(u16 param_0, u16 param_1, u16 param_2, u16 param_3
void dMenu_DmapMap_c::_delete() { void dMenu_DmapMap_c::_delete() {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
if (mMapImage_p[i] != NULL) { if (mMapImage_p[i] != NULL) {
#if TARGET_PC
GXDestroyCopyTex(mMapImage_p[i]);
#endif
JKR_DELETE_ARRAY(mMapImage_p[i]); JKR_DELETE_ARRAY(mMapImage_p[i]);
} }
+1 -2
View File
@@ -21,7 +21,6 @@
#include "d/d_msg_object.h" #include "d/d_msg_object.h"
#include "d/d_msg_scrn_explain.h" #include "d/d_msg_scrn_explain.h"
#include "d/d_stage.h" #include "d/d_stage.h"
#include "dusk/memory.h"
#include "f_op/f_op_msg_mng.h" #include "f_op/f_op_msg_mng.h"
static dMf_HIO_c g_fmHIO; static dMf_HIO_c g_fmHIO;
@@ -190,7 +189,7 @@ dMenu_Fmap_c::dMenu_Fmap_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i
field_0x148[i] = 0.0f; field_0x148[i] = 0.0f;
} }
mpTalkHeap = JKRCreateExpHeap(HEAP_SIZE(0x32000, 0x40000), mpHeap, false); mpTalkHeap = JKRCreateExpHeap(0x32000, mpHeap, false);
JUT_ASSERT(359, mpTalkHeap != NULL); JUT_ASSERT(359, mpTalkHeap != NULL);
JKRHEAP_NAME(mpTalkHeap, "dMenu_Fmap_c::mpTalkHeap"); JKRHEAP_NAME(mpTalkHeap, "dMenu_Fmap_c::mpTalkHeap");
field_0x200 = 0; field_0x200 = 0;
+6
View File
@@ -8,6 +8,9 @@
#include "d/d_debug_viewer.h" #include "d/d_debug_viewer.h"
#include "d/d_menu_fmap_map.h" #include "d/d_menu_fmap_map.h"
#include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_graphic.h"
#if TARGET_PC
#include <dolphin/gx/GXExtra.h>
#endif
#include <cstring> #include <cstring>
static u8 twoValueLineInterpolation(u8 i_value1, u8 i_value2, f32 i_param) { static u8 twoValueLineInterpolation(u8 i_value1, u8 i_value2, f32 i_param) {
@@ -494,6 +497,9 @@ void dMenu_FmapMap_c::_delete() {
mResTIMG = NULL; mResTIMG = NULL;
} }
if (mMapImage_p != NULL) { if (mMapImage_p != NULL) {
#if TARGET_PC
GXDestroyCopyTex(mMapImage_p);
#endif
JKR_DELETE_ARRAY(mMapImage_p); JKR_DELETE_ARRAY(mMapImage_p);
mMapImage_p = NULL; mMapImage_p = NULL;
} }
+9 -13
View File
@@ -24,16 +24,12 @@
#include "d/actor/d_a_horse.h" #include "d/actor/d_a_horse.h"
#include <cstring> #include <cstring>
#include "dusk/memory.h"
#include "dusk/memory.h"
int dMeter2_c::_create() { int dMeter2_c::_create() {
stage_stag_info_class* stag_info = dComIfGp_getStageStagInfo(); stage_stag_info_class* stag_info = dComIfGp_getStageStagInfo();
if (dStage_stagInfo_GetUpButton(stag_info) == 1) { if (dStage_stagInfo_GetUpButton(stag_info) == 1) {
mpHeap = fopMsgM_createExpHeap(HEAP_SIZE(0x5A400, 0xA0000), NULL); mpHeap = fopMsgM_createExpHeap(0x5A400, NULL);
} else { } else {
mpHeap = fopMsgM_createExpHeap(HEAP_SIZE(0x60800, 0xC1000), NULL); mpHeap = fopMsgM_createExpHeap(0x60800, NULL);
} }
JKRHEAP_NAME(mpHeap, "dMeter2_c"); JKRHEAP_NAME(mpHeap, "dMeter2_c");
@@ -236,7 +232,7 @@ int dMeter2_c::_create() {
dMeter2Info_setMeterMapClass(mpMap); dMeter2Info_setMeterMapClass(mpMap);
mpHeap->getTotalFreeSize(); mpHeap->getTotalFreeSize();
mpSubHeap = fopMsgM_createExpHeap(HEAP_SIZE(0x5000, 0x6500), mpHeap); mpSubHeap = fopMsgM_createExpHeap(0x5000, mpHeap);
JKRHEAP_NAME(mpSubHeap, "dMeter2_c mpSubHeap"); JKRHEAP_NAME(mpSubHeap, "dMeter2_c mpSubHeap");
field_0x108 = NULL; field_0x108 = NULL;
mpSubContents = NULL; mpSubContents = NULL;
@@ -316,6 +312,12 @@ int dMeter2_c::_execute() {
} }
int dMeter2_c::_draw() { int dMeter2_c::_draw() {
#if TARGET_PC
if (dusk::getSettings().game.disableMainHUD) {
return 1;
}
#endif
if (mpMap != NULL) { if (mpMap != NULL) {
mpMap->_draw(); mpMap->_draw();
} }
@@ -424,12 +426,6 @@ void dMeter2_c::setLifeZero() {
void dMeter2_c::checkStatus() { void dMeter2_c::checkStatus() {
mStatus = 0; mStatus = 0;
#if TARGET_PC
if (dusk::getSettings().game.disableMainHUD) {
mStatus |= 0xF0000000;
}
#endif
field_0x12c = field_0x128; field_0x12c = field_0x128;
field_0x128 = daPy_py_c::checkNowWolf(); field_0x128 = daPy_py_c::checkNowWolf();
+18 -6
View File
@@ -36,15 +36,27 @@ dRes_info_c::dRes_info_c() {
dRes_info_c::~dRes_info_c() { dRes_info_c::~dRes_info_c() {
if (mDMCommand != NULL) { if (mDMCommand != NULL) {
mDMCommand->destroy(); #if TARGET_PC
if (JKRHeap::findFromRoot(mDMCommand) != nullptr) {
#endif
mDMCommand->destroy();
#if TARGET_PC
}
#endif
mDMCommand = NULL; mDMCommand = NULL;
} else if (mArchive != NULL) { } else if (mArchive != NULL) {
deleteArchiveRes(); #if TARGET_PC
if (mDataHeap != NULL) { if (JKRHeap::findFromRoot(mArchive) != nullptr) {
mDoExt_destroySolidHeap(mDataHeap); #endif
mDataHeap = NULL; deleteArchiveRes();
mArchive->unmount(); if (mDataHeap != NULL) {
mDoExt_destroySolidHeap(mDataHeap);
mDataHeap = NULL;
mArchive->unmount();
}
#if TARGET_PC
} }
#endif
mRes = NULL; mRes = NULL;
mArchive = NULL; mArchive = NULL;
} }
+16 -6
View File
@@ -5,19 +5,19 @@
#include "d/dolzel.h" // IWYU pragma: keep #include "d/dolzel.h" // IWYU pragma: keep
#include "d/d_s_name.h"
#include "JSystem/JKernel/JKRExpHeap.h" #include "JSystem/JKernel/JKRExpHeap.h"
#include "d/d_com_inf_game.h" #include "d/d_com_inf_game.h"
#include "d/d_meter2_info.h" #include "d/d_meter2_info.h"
#include "d/d_s_name.h"
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/settings.h"
#include "f_op/f_op_overlap_mng.h"
#include "f_op/f_op_scene_mng.h" #include "f_op/f_op_scene_mng.h"
#include "m_Do/m_Do_Reset.h" #include "m_Do/m_Do_Reset.h"
#include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_graphic.h"
#include "m_Do/m_Do_machine.h" #include "m_Do/m_Do_machine.h"
#include "m_Do/m_Do_mtx.h"
#include "m_Do/m_Do_main.h" #include "m_Do/m_Do_main.h"
#include "f_op/f_op_overlap_mng.h" #include "m_Do/m_Do_mtx.h"
#include "dusk/memory.h"
#include "dusk/settings.h"
#if TARGET_PC #if TARGET_PC
#define SHOW_TV_SETTINGS_SCREEN (this->mShowTvSettingsScreen) #define SHOW_TV_SETTINGS_SCREEN (this->mShowTvSettingsScreen)
@@ -76,7 +76,7 @@ static s32 resLoad(request_of_phase_process_class* i_phase, char* i_resName) {
s32 dScnName_c::create() { s32 dScnName_c::create() {
int phase_state = resLoad(&phase, "fileSel"); int phase_state = resLoad(&phase, "fileSel");
if (phase_state == cPhs_COMPLEATE_e) { if (phase_state == cPhs_COMPLEATE_e) {
mHeap = JKRCreateExpHeap(HEAP_SIZE(0x180000, 0x1C0000), mDoExt_getGameHeap(), false); mHeap = JKRCreateExpHeap(0x180000, mDoExt_getGameHeap(), false);
JUT_ASSERT(289, mHeap != NULL); JUT_ASSERT(289, mHeap != NULL);
JKRHEAP_NAME(mHeap, "File select"); JKRHEAP_NAME(mHeap, "File select");
@@ -412,6 +412,16 @@ void dScnName_c::changeGameScene() {
dKy_clear_game_init(); dKy_clear_game_init();
dComIfGs_resetDan(); dComIfGs_resetDan();
dComIfGs_setRestartRoomParam(0); dComIfGs_setRestartRoomParam(0);
#if TARGET_PC
if (dusk::getSettings().game.speedrunMode && dusk::getSettings().game.hideTvSettingsScreen) {
// start a new run on file load if a run isn't already in progress
if (!dusk::m_speedrunInfo.m_isRunStarted) {
dusk::ImGuiMenuGame::resetForSpeedrunMode();
dusk::m_speedrunInfo.startRun();
}
}
#endif
} }
} }
+2 -6
View File
@@ -39,10 +39,6 @@
#include "JSystem/JKernel/JKRAram.h" #include "JSystem/JKernel/JKRAram.h"
#include "JSystem/JKernel/JKRAramArchive.h" #include "JSystem/JKernel/JKRAramArchive.h"
#if TARGET_PC
#include "dusk/memory.h"
#endif
#if DEBUG #if DEBUG
#include "d/d_s_menu.h" #include "d/d_s_menu.h"
#include "d/d_debug_pad.h" #include "d/d_debug_pad.h"
@@ -1424,7 +1420,7 @@ static int phase_4(dScnPly_c* i_this) {
dComIfGd_setViewport(NULL); dComIfGd_setViewport(NULL);
dComIfGd_setView(NULL); dComIfGd_setView(NULL);
JKRExpHeap* heap = fopMsgM_createExpHeap(HEAP_SIZE(0xBB800, 0x177000), NULL); JKRExpHeap* heap = fopMsgM_createExpHeap(0xBB800, NULL);
#if TARGET_PC #if TARGET_PC
heap->setName("Scene2DHeap"); heap->setName("Scene2DHeap");
#endif #endif
@@ -1432,7 +1428,7 @@ static int phase_4(dScnPly_c* i_this) {
JUT_ASSERT(2704, heap != NULL); JUT_ASSERT(2704, heap != NULL);
dComIfGp_setExpHeap2D(heap); dComIfGp_setExpHeap2D(heap);
JKRExpHeap* heap2 = fopMsgM_createExpHeap(HEAP_SIZE(0xA800, 0x15000), NULL); JKRExpHeap* heap2 = fopMsgM_createExpHeap(0xA800, NULL);
#if TARGET_PC #if TARGET_PC
heap2->setName("SceneMsgHeap"); heap2->setName("SceneMsgHeap");
#endif #endif
+142
View File
@@ -0,0 +1,142 @@
#include "imgui.h"
#include "ImGuiMenuTools.hpp"
#include "d/actor/d_a_alink.h"
#include "d/d_com_inf_game.h"
#include "f_op/f_op_actor_mng.h"
#include "SSystem/SComponent/c_sxyz.h"
#include "SSystem/SComponent/c_xyz.h"
namespace dusk {
namespace {
struct ActorSpawnerState {
int actorId = 0;
int params = -1;
int argument = -1;
int angleX = 0;
int angleY = 0;
int angleZ = 0;
float scaleX = 1.0f;
float scaleY = 1.0f;
float scaleZ = 1.0f;
bool usePlayerRoom = true;
int manualRoom = 0;
int spawnCount = 1;
bool hasResult = false;
unsigned int lastResult = 0;
int lastAttempted = 0;
};
ActorSpawnerState s_state;
} // namespace
void ImGuiMenuTools::ShowActorSpawner() {
if (!m_showActorSpawner) {
return;
}
if (!ImGui::Begin("Actor Spawner", &m_showActorSpawner)) {
ImGui::End();
return;
}
daAlink_c* player = (daAlink_c*)dComIfGp_getPlayer(0);
ImGui::SeparatorText("Actor");
ImGui::InputInt("Actor ID", &s_state.actorId);
ImGui::InputInt("Params (hex)", &s_state.params, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
ImGui::InputInt("Argument", &s_state.argument);
s_state.argument = (s_state.argument < -128) ? -128 : (s_state.argument > 127) ? 127 : s_state.argument;
ImGui::SeparatorText("Angle");
ImGui::InputInt("Angle X", &s_state.angleX);
ImGui::InputInt("Angle Y", &s_state.angleY);
ImGui::InputInt("Angle Z", &s_state.angleZ);
ImGui::SeparatorText("Scale");
ImGui::InputFloat("Scale X", &s_state.scaleX, 0.1f, 1.0f);
ImGui::InputFloat("Scale Y", &s_state.scaleY, 0.1f, 1.0f);
ImGui::InputFloat("Scale Z", &s_state.scaleZ, 0.1f, 1.0f);
ImGui::SeparatorText("Spawn");
ImGui::InputInt("Count", &s_state.spawnCount);
if (s_state.spawnCount < 1) {
s_state.spawnCount = 1;
}
ImGui::SeparatorText("Position");
ImGui::Checkbox("Use player room", &s_state.usePlayerRoom);
if (!s_state.usePlayerRoom) {
ImGui::InputInt("Room No", &s_state.manualRoom);
}
if (player != nullptr) {
ImGui::Text("Spawn pos: %.2f, %.2f, %.2f",
player->current.pos.x, player->current.pos.y, player->current.pos.z);
} else {
ImGui::TextDisabled("Player not available");
}
ImGui::Separator();
bool canSpawn = player != nullptr;
if (!canSpawn) {
ImGui::BeginDisabled();
}
if (ImGui::Button("Spawn", ImVec2(-1, 0))) {
cXyz pos = player->current.pos;
csXyz angle;
angle.set((s16)s_state.angleX, (s16)s_state.angleY, (s16)s_state.angleZ);
cXyz scale(s_state.scaleX, s_state.scaleY, s_state.scaleZ);
int roomNo = s_state.usePlayerRoom ? player->current.roomNo : s_state.manualRoom;
layer_class* savedLayer = fpcLy_CurrentLayer();
base_process_class* playScene = fpcM_SearchByName(fpcNm_PLAY_SCENE_e);
if (playScene != nullptr) {
fpcLy_SetCurrentLayer(&((process_node_class*)playScene)->layer);
}
s_state.lastResult = 0;
s_state.lastAttempted = s_state.spawnCount;
for (int i = 0; i < s_state.spawnCount; ++i) {
unsigned int result = fopAcM_create(
(s16)s_state.actorId,
(u32)s_state.params,
&pos,
roomNo,
&angle,
&scale,
(s8)s_state.argument
);
if (result != 0) {
s_state.lastResult = result;
}
}
s_state.hasResult = true;
fpcLy_SetCurrentLayer(savedLayer);
}
if (!canSpawn) {
ImGui::EndDisabled();
}
if (s_state.hasResult) {
if (s_state.lastResult != 0) {
if (s_state.lastAttempted == 1) {
ImGui::Text("Spawned: proc ID %u", s_state.lastResult);
} else {
ImGui::Text("Spawned %d (last proc ID %u)", s_state.lastAttempted, s_state.lastResult);
}
} else {
ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), "Spawn failed (returned 0)");
}
}
ImGui::End();
}
} // namespace dusk
+25 -2
View File
@@ -19,6 +19,7 @@
#include "dusk/config.hpp" #include "dusk/config.hpp"
#include "dusk/dusk.h" #include "dusk/dusk.h"
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
#include "dusk/livesplit.h"
#include "dusk/main.h" #include "dusk/main.h"
#include "dusk/settings.h" #include "dusk/settings.h"
#include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_controller_pad.h"
@@ -65,6 +66,10 @@ namespace dusk {
ImGui::TextUnformatted(text.data(), text.data() + text.size()); ImGui::TextUnformatted(text.data(), text.data() + text.size());
} }
void DuskToast(std::string_view message, float duration) {
g_imguiConsole.AddToast(message, duration);
}
void ImGuiTextCenter(std::string_view text) { void ImGuiTextCenter(std::string_view text) {
ImGui::NewLine(); ImGui::NewLine();
float fontSize = ImGui::CalcTextSize( float fontSize = ImGui::CalcTextSize(
@@ -365,13 +370,26 @@ namespace dusk {
"Press F1 to toggle menu"s, "Press F1 to toggle menu"s,
2.5f); 2.5f);
m_isLaunchInitialized = true; m_isLaunchInitialized = true;
if (getSettings().game.liveSplitEnabled) {
dusk::speedrun::connectLiveSplit();
}
} }
UpdateDragScroll(); UpdateDragScroll();
m_menuGame.windowControllerConfig(); m_menuGame.windowControllerConfig();
m_menuGame.windowInputViewer(); m_menuGame.windowInputViewer();
if (dusk::IsGameLaunched) { m_menuGame.drawSpeedrunTimerOverlay();
if (getSettings().game.liveSplitEnabled) {
dusk::speedrun::updateLiveSplit();
if (dusk::speedrun::consumeConnectedEvent())
AddToast("LiveSplit connected");
else if (dusk::speedrun::consumeDisconnectedEvent())
AddToast("LiveSplit disconnected");
}
if (dusk::IsGameLaunched && !dusk::getSettings().game.speedrunMode) {
m_menuTools.ShowDebugOverlay(); m_menuTools.ShowDebugOverlay();
m_menuTools.ShowCameraOverlay(); m_menuTools.ShowCameraOverlay();
m_menuTools.ShowProcessManager(); m_menuTools.ShowProcessManager();
@@ -382,8 +400,9 @@ namespace dusk {
m_menuTools.ShowPlayerInfo(); m_menuTools.ShowPlayerInfo();
m_menuTools.ShowAudioDebug(); m_menuTools.ShowAudioDebug();
m_menuTools.ShowSaveEditor(); m_menuTools.ShowSaveEditor();
m_menuTools.ShowStateShare();
m_menuTools.ShowActorSpawner();
} }
m_menuTools.ShowStateShare();
m_menuTools.ShowAchievements(); m_menuTools.ShowAchievements();
DuskDebugPad(); // temporary, remove later DuskDebugPad(); // temporary, remove later
@@ -556,6 +575,10 @@ namespace dusk {
return false; return false;
} }
void ImGuiConsole::AddToast(std::string_view message, float duration) {
m_toasts.emplace_back(std::string(message), duration);
}
void ImGuiConsole::ShowToasts() { void ImGuiConsole::ShowToasts() {
if (m_toasts.empty()) { if (m_toasts.empty()) {
return; return;
+2
View File
@@ -27,6 +27,7 @@ public:
void PostDraw(); void PostDraw();
static bool CheckMenuViewToggle(ImGuiKey key, bool& active); static bool CheckMenuViewToggle(ImGuiKey key, bool& active);
void AddToast(std::string_view message, float duration = 3.f);
private: private:
struct Toast { struct Toast {
@@ -70,6 +71,7 @@ std::string BytesToString(size_t bytes);
void SetOverlayWindowLocation(int corner); void SetOverlayWindowLocation(int corner);
bool ShowCornerContextMenu(int& corner, int avoidCorner); bool ShowCornerContextMenu(int& corner, int avoidCorner);
void ImGuiStringViewText(std::string_view text); void ImGuiStringViewText(std::string_view text);
void DuskToast(std::string_view message, float duration = 3.f);
void ImGuiBeginGroupPanel(const char* name, const ImVec2& size); void ImGuiBeginGroupPanel(const char* name, const ImVec2& size);
void ImGuiEndGroupPanel(); void ImGuiEndGroupPanel();
void ImGuiTextCenter(std::string_view text); void ImGuiTextCenter(std::string_view text);
+1
View File
@@ -30,6 +30,7 @@ static void ApplyPresetHD() {
s.game.biggerWallets.setValue(true); s.game.biggerWallets.setValue(true);
s.game.invertCameraXAxis.setValue(true); s.game.invertCameraXAxis.setValue(true);
s.game.freeCamera.setValue(true); s.game.freeCamera.setValue(true);
s.game.no2ndFishForCat.setValue(true);
} }
static void ApplyPresetDusk() { static void ApplyPresetDusk() {
+28 -3
View File
@@ -6,6 +6,7 @@
#include "JSystem/JFramework/JFWSystem.h" #include "JSystem/JFramework/JFWSystem.h"
#include "JSystem/JKernel/JKRExpHeap.h" #include "JSystem/JKernel/JKRExpHeap.h"
#include "JSystem/JKernel/JKRHeap.h" #include "JSystem/JKernel/JKRHeap.h"
#include "JSystem/JKernel/JKRSolidHeap.h"
#include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_map.h"
#include "imgui.h" #include "imgui.h"
@@ -178,11 +179,11 @@ namespace dusk {
} }
void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open) { void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open) {
const char* heapName = data.Safe ? heap->getName() : "INVALID";
char title[128]; char title[128];
const char* name = data.Safe ? heap->getName() : "INVALID"; snprintf(title, sizeof(title), "Heap %s##%p", heapName, static_cast<const void*>(heap));
snprintf(title, sizeof(title), "Heap %s##%p", heap->getName(), static_cast<const void*>(heap));
if (!ImGui::Begin(name, &open)) { if (!ImGui::Begin(title, &open)) {
ImGui::End(); ImGui::End();
return; return;
} }
@@ -200,6 +201,30 @@ namespace dusk {
const auto freeSize = BytesToString(heap->getFreeSize()); const auto freeSize = BytesToString(heap->getFreeSize());
ImGui::Text("Size: %08X (%s), free: %08X (%s)", heap->getSize(), size.c_str(), heap->getFreeSize(), freeSize.c_str()); ImGui::Text("Size: %08X (%s), free: %08X (%s)", heap->getSize(), size.c_str(), heap->getFreeSize(), freeSize.c_str());
{
void* vmemBase = nullptr;
size_t vmemCapacity = 0;
size_t vmemCommitted = 0;
if (heap->getHeapType() == 'EXPH') {
auto* h = static_cast<JKRExpHeap*>(heap);
vmemBase = h->mVmemBase; vmemCapacity = h->mVmemCapacity; vmemCommitted = h->mVmemCommitted;
} else if (heap->getHeapType() == 'SLID') {
auto* h = static_cast<JKRSolidHeap*>(heap);
vmemBase = h->mVmemBase; vmemCapacity = h->mVmemCapacity; vmemCommitted = h->mVmemCommitted;
}
if (vmemBase) {
ImGui::SeparatorText("Virtual Memory");
ImGui::Text("Base: %p", vmemBase);
const auto committedStr = BytesToString(vmemCommitted);
const auto capacityStr = BytesToString(vmemCapacity);
ImGui::Text("Committed: %s / %s reserved", committedStr.c_str(), capacityStr.c_str());
float pct = vmemCapacity > 0 ? (float)vmemCommitted / (float)vmemCapacity : 0.0f;
char overlayBuf[32];
snprintf(overlayBuf, sizeof(overlayBuf), "%.1f%%", pct * 100.0f);
ImGui::ProgressBar(pct, ImVec2(-1.0f, 0.0f), overlayBuf);
}
}
if (ImGui::Button("Check")) { if (ImGui::Button("Check")) {
data.HeapCheckFailed = !heap->check(); data.HeapCheckFailed = !heap->check();
data.HeapCheckRan = true; data.HeapCheckRan = true;
+152 -4
View File
@@ -12,12 +12,15 @@
#include "dusk/main.h" #include "dusk/main.h"
#include "dusk/hotkeys.h" #include "dusk/hotkeys.h"
#include "dusk/settings.h" #include "dusk/settings.h"
#include "dusk/livesplit.h"
#include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_controller_pad.h"
#include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_graphic.h"
#include <aurora/gfx.h> #include <aurora/gfx.h>
#include <SDL3/SDL_gamepad.h> #include <SDL3/SDL_gamepad.h>
#include "m_Do/m_Do_main.h"
namespace { namespace {
constexpr int kInternalResolutionScaleMax = 12; constexpr int kInternalResolutionScaleMax = 12;
} // namespace } // namespace
@@ -167,6 +170,8 @@ namespace dusk {
config::ImGuiCheckbox("Enable Depth of Field", getSettings().game.enableDepthOfField); config::ImGuiCheckbox("Enable Depth of Field", getSettings().game.enableDepthOfField);
config::ImGuiCheckbox("Enable Mini-Map Shadows", getSettings().game.enableMapBackground);
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
@@ -199,6 +204,7 @@ namespace dusk {
ImGui::SeparatorText("Difficulty"); ImGui::SeparatorText("Difficulty");
ImGui::BeginDisabled(getSettings().game.speedrunMode);
config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d"); config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d");
config::ImGuiCheckbox("Instant Death", getSettings().game.instantDeath); config::ImGuiCheckbox("Instant Death", getSettings().game.instantDeath);
@@ -211,6 +217,7 @@ namespace dusk {
ImGui::SetTooltip("Hearts will never drop from enemies,\n" ImGui::SetTooltip("Hearts will never drop from enemies,\n"
"pots and various other places."); "pots and various other places.");
} }
ImGui::EndDisabled();
ImGui::SeparatorText("Quality of Life"); ImGui::SeparatorText("Quality of Life");
@@ -260,6 +267,11 @@ namespace dusk {
ImGui::SetTooltip("Link won't recoil when his sword hits walls."); ImGui::SetTooltip("Link won't recoil when his sword hits walls.");
} }
config::ImGuiCheckbox("No 2nd Fish for Cat", getSettings().game.no2ndFishForCat);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Only need to fish once for Sera's cat to return.");
}
config::ImGuiCheckbox("Skip TV Settings Screen", getSettings().game.hideTvSettingsScreen); config::ImGuiCheckbox("Skip TV Settings Screen", getSettings().game.hideTvSettingsScreen);
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Skip the TV calibration screen shown when loading a save."); ImGui::SetTooltip("Skip the TV calibration screen shown when loading a save.");
@@ -280,12 +292,39 @@ namespace dusk {
ImGui::SetTooltip("Transform instantly by pressing R and Y simultaneously."); ImGui::SetTooltip("Transform instantly by pressing R and Y simultaneously.");
} }
ImGui::SeparatorText("Speedrunning");
if (config::ImGuiCheckbox("Speedrun Mode", getSettings().game.speedrunMode)) {
resetForSpeedrunMode();
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Enables Speedrunning options, while restricting certain gameplay modifiers.");
}
ImGui::BeginDisabled(!getSettings().game.speedrunMode);
bool prevLiveSplit = getSettings().game.liveSplitEnabled;
config::ImGuiCheckbox("LiveSplit Connection", getSettings().game.liveSplitEnabled);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Connect to LiveSplit server on localhost:16834.");
}
ImGui::EndDisabled();
if ((bool)getSettings().game.liveSplitEnabled != prevLiveSplit) {
if (getSettings().game.liveSplitEnabled) {
dusk::speedrun::connectLiveSplit();
} else {
dusk::speedrun::disconnectLiveSplit();
DuskToast("LiveSplit disconnected", 3.f);
}
}
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
void ImGuiMenuGame::drawCheatsMenu() { void ImGuiMenuGame::drawCheatsMenu() {
if (ImGui::BeginMenu("Cheats")) { if (ImGui::BeginMenu("Cheats")) {
ImGui::BeginDisabled(getSettings().game.speedrunMode);
ImGui::SeparatorText("Resources"); ImGui::SeparatorText("Resources");
config::ImGuiCheckbox("Infinite Hearts", getSettings().game.infiniteHearts); config::ImGuiCheckbox("Infinite Hearts", getSettings().game.infiniteHearts);
config::ImGuiCheckbox("Infinite Arrows", getSettings().game.infiniteArrows); config::ImGuiCheckbox("Infinite Arrows", getSettings().game.infiniteArrows);
@@ -293,8 +332,8 @@ namespace dusk {
config::ImGuiCheckbox("Infinite Oil", getSettings().game.infiniteOil); config::ImGuiCheckbox("Infinite Oil", getSettings().game.infiniteOil);
config::ImGuiCheckbox("Infinite Oxygen", getSettings().game.infiniteOxygen); config::ImGuiCheckbox("Infinite Oxygen", getSettings().game.infiniteOxygen);
config::ImGuiCheckbox("Infinite Rupees", getSettings().game.infiniteRupees); config::ImGuiCheckbox("Infinite Rupees", getSettings().game.infiniteRupees);
config::ImGuiCheckbox("Items Don't Despawn", getSettings().game.enableIndefiniteItemDrops); config::ImGuiCheckbox("No Item Timer", getSettings().game.enableIndefiniteItemDrops);
ImGui::SetItemTooltip("Items Don't Despawn Unless You Load A Different Room In Which Case They Do But Even Under Some Circumstances They Don't, It Is Quite Rare Though"); ImGui::SetItemTooltip("Item drops such as Rupees, Hearts, etc. will never disappear after they drop.");
ImGui::SeparatorText("Abilities"); ImGui::SeparatorText("Abilities");
config::ImGuiCheckbox("Moon Jump (R+A)", getSettings().game.moonJump); config::ImGuiCheckbox("Moon Jump (R+A)", getSettings().game.moonJump);
@@ -317,6 +356,8 @@ namespace dusk {
ImGui::SetTooltip("Makes the magic armor work without rupees."); ImGui::SetTooltip("Makes the magic armor work without rupees.");
} }
ImGui::EndDisabled();
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
@@ -439,10 +480,12 @@ namespace dusk {
ImGui::SeparatorText("Tools"); ImGui::SeparatorText("Tools");
ImGui::BeginDisabled(getSettings().game.speedrunMode);
config::ImGuiCheckbox("Turbo Key", getSettings().game.enableTurboKeybind); config::ImGuiCheckbox("Turbo Key", getSettings().game.enableTurboKeybind);
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Hold TAB to increase game speed by up to 4x."); ImGui::SetTooltip("Hold TAB to increase game speed by up to 4x.");
} }
ImGui::EndDisabled();
ImGui::Checkbox("Show Input Viewer", &m_showInputViewer); ImGui::Checkbox("Show Input Viewer", &m_showInputViewer);
@@ -965,7 +1008,7 @@ namespace dusk {
ImGui::SameLine(); ImGui::SameLine();
// Options panel // Options panel
ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, 20 * scale)); ImGuiBeginGroupPanel("Options", ImVec2(150 * scale, -1));
if (deadZones != nullptr) { if (deadZones != nullptr) {
if (ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones)) { if (ImGui::Checkbox("Enable Dead Zones", &deadZones->useDeadzones)) {
@@ -975,9 +1018,114 @@ namespace dusk {
PADSerializeMappings(); PADSerializeMappings();
} }
} }
if (PADSupportsRumbleIntensity(m_controllerConfig.m_selectedPort)) {
ImGuiBeginGroupPanel("Rumble Intensity", ImVec2(150 * scale, -1));
u16 low;
u16 high;
(void)PADGetRumbleIntensity(m_controllerConfig.m_selectedPort, &low, &high);
float fLow = (static_cast<float>(low) / 32767.f) * 100.f;
bool changed = ImGui::SliderFloat("Low", &fLow, 0.f, 100.f, "%.0f%%");
float fHigh = (static_cast<float>(high) / 32767.f) * 100.f;
changed |= ImGui::SliderFloat("High", &fHigh, 0.f, 100.f, "%.0f%%");
if (changed) {
PADSetRumbleIntensity(m_controllerConfig.m_selectedPort,
static_cast<u16>((fLow / 100) * 32767),
static_cast<u16>((fHigh / 100) * 32767));
PADSerializeMappings();
}
if (ImGui::Button(fmt::format("{0}...##rumbleTest", m_controllerConfig.m_isRumbling ? "Stop": "Test").c_str(), {-1, 0})) {
PADControlMotor(m_controllerConfig.m_selectedPort, !m_controllerConfig.m_isRumbling ? PAD_MOTOR_RUMBLE : PAD_MOTOR_STOP_HARD);
m_controllerConfig.m_isRumbling ^= 1;
}
ImGuiEndGroupPanel();
}
ImGuiEndGroupPanel(); ImGuiEndGroupPanel();
ImGui::End(); ImGui::End();
} }
static std::string GetFormattedTime(OSTime ticks) {
OSCalendarTime time;
OSTicksToCalendarTime(ticks, &time);
return fmt::format("{0:02}:{1:02}:{2:02}.{3:03}", time.hour, time.min, time.sec, time.msec);
}
void ImGuiMenuGame::resetForSpeedrunMode() {
// reset settings that should be off for speedrun mode
mDoMain::developmentMode = -1;
getSettings().game.damageMultiplier.setValue(1);
getSettings().game.instantDeath.setValue(false);
getSettings().game.noHeartDrops.setValue(false);
getSettings().game.infiniteHearts.setValue(false);
getSettings().game.infiniteArrows.setValue(false);
getSettings().game.infiniteBombs.setValue(false);
getSettings().game.infiniteOil.setValue(false);
getSettings().game.infiniteOxygen.setValue(false);
getSettings().game.infiniteRupees.setValue(false);
getSettings().game.enableIndefiniteItemDrops.setValue(false);
getSettings().game.moonJump.setValue(false);
getSettings().game.superClawshot.setValue(false);
getSettings().game.alwaysGreatspin.setValue(false);
getSettings().game.enableFastIronBoots.setValue(false);
getSettings().game.canTransformAnywhere.setValue(false);
getSettings().game.fastSpinner.setValue(false);
getSettings().game.freeMagicArmor.setValue(false);
getSettings().game.enableTurboKeybind.setValue(false);
}
SpeedrunInfo m_speedrunInfo;
void ImGuiMenuGame::drawSpeedrunTimerOverlay() {
if (!getSettings().game.speedrunMode) {
return;
}
// L+R+A+Start to reset timer
if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigStart(PAD_1)) {
m_speedrunInfo.reset();
}
// L+R+A+Z to manually stop timer
if (mDoCPd_c::getHoldL(PAD_1) && mDoCPd_c::getHoldR(PAD_1) && mDoCPd_c::getHoldA(PAD_1) && mDoCPd_c::getTrigZ(PAD_1)) {
if (m_speedrunInfo.m_isRunStarted) {
m_speedrunInfo.m_endTimestamp = OSGetTime() - m_speedrunInfo.m_startTimestamp;
m_speedrunInfo.m_isRunStarted = false;
}
}
ImGui::SetNextWindowBgAlpha(0.65f);
ImGuiWindowFlags flags =
ImGuiWindowFlags_NoResize
| ImGuiWindowFlags_NoDocking
| ImGuiWindowFlags_NoTitleBar
| ImGuiWindowFlags_NoScrollbar;
if (ImGui::Begin("##SpeedrunTimerWindow", nullptr, flags)) {
OSTime elapsedTime = 0;
if (m_speedrunInfo.m_isRunStarted) {
elapsedTime = OSGetTime() - m_speedrunInfo.m_startTimestamp;
} else if (m_speedrunInfo.m_endTimestamp != 0) {
elapsedTime = m_speedrunInfo.m_endTimestamp;
}
ImGui::Text("RTA");
ImGui::SameLine(60.0f);
ImGuiStringViewText(GetFormattedTime(elapsedTime));
if (!m_speedrunInfo.m_isPauseIGT) {
m_speedrunInfo.m_igtTimer = elapsedTime - m_speedrunInfo.m_totalLoadTime;
}
ImGui::Text("IGT");
ImGui::SameLine(60.0f);
ImGuiStringViewText(GetFormattedTime(m_speedrunInfo.m_igtTimer));
}
ImGui::End();
}
} }
+39
View File
@@ -8,6 +8,39 @@
#include "imgui.h" #include "imgui.h"
namespace dusk { namespace dusk {
struct SpeedrunInfo {
void startRun() {
m_isRunStarted = true;
m_startTimestamp = OSGetTime();
}
void stopRun() {
m_isRunStarted = false;
m_endTimestamp = OSGetTime() - m_startTimestamp;
}
void reset() {
m_isRunStarted = false;
m_startTimestamp = 0;
m_endTimestamp = 0;
m_isPauseIGT = false;
m_loadStartTimestamp = 0;
m_totalLoadTime = 0;
m_igtTimer = 0;
}
bool m_isRunStarted = false;
OSTime m_startTimestamp = 0;
OSTime m_endTimestamp = 0;
bool m_isPauseIGT = false;
OSTime m_loadStartTimestamp = 0;
OSTime m_totalLoadTime = 0;
OSTime m_igtTimer = 0;
};
extern SpeedrunInfo m_speedrunInfo;
class ImGuiMenuGame { class ImGuiMenuGame {
public: public:
ImGuiMenuGame(); ImGuiMenuGame();
@@ -15,9 +48,12 @@ namespace dusk {
void windowInputViewer(); void windowInputViewer();
void windowControllerConfig(); void windowControllerConfig();
void drawSpeedrunTimerOverlay();
static void ToggleFullscreen(); static void ToggleFullscreen();
static void resetForSpeedrunMode();
private: private:
void drawAudioMenu(); void drawAudioMenu();
void drawInputMenu(); void drawInputMenu();
@@ -32,6 +68,7 @@ namespace dusk {
PADButtonMapping* m_pendingButtonMapping = nullptr; PADButtonMapping* m_pendingButtonMapping = nullptr;
PADAxisMapping* m_pendingAxisMapping = nullptr; PADAxisMapping* m_pendingAxisMapping = nullptr;
int m_pendingPort = -1; int m_pendingPort = -1;
bool m_isRumbling = false;
} m_controllerConfig; } m_controllerConfig;
bool m_showControllerConfig = false; bool m_showControllerConfig = false;
@@ -40,6 +77,8 @@ namespace dusk {
bool m_showInputViewerGyro = false; bool m_showInputViewerGyro = false;
int m_inputOverlayCorner = 3; int m_inputOverlayCorner = 3;
std::string m_controllerName; std::string m_controllerName;
bool m_showTimerWindow = false;
}; };
} }
+10
View File
@@ -50,10 +50,14 @@ namespace dusk {
ImGui::BeginDisabled(); ImGui::BeginDisabled();
} }
ImGui::BeginDisabled(getSettings().game.speedrunMode);
ImGui::MenuItem("Save Editor", hotkeys::SHOW_SAVE_EDITOR, &m_showSaveEditor); ImGui::MenuItem("Save Editor", hotkeys::SHOW_SAVE_EDITOR, &m_showSaveEditor);
ImGui::MenuItem("Map Loader", hotkeys::SHOW_MAP_LOADER, &m_showMapLoader); ImGui::MenuItem("Map Loader", hotkeys::SHOW_MAP_LOADER, &m_showMapLoader);
ImGui::MenuItem("State Share", hotkeys::SHOW_STATE_SHARE, &m_showStateShare); ImGui::MenuItem("State Share", hotkeys::SHOW_STATE_SHARE, &m_showStateShare);
ImGui::EndDisabled();
if (!dusk::IsGameLaunched) { if (!dusk::IsGameLaunched) {
ImGui::EndDisabled(); ImGui::EndDisabled();
} }
@@ -71,6 +75,8 @@ namespace dusk {
} }
if (ImGui::BeginMenu("Debug")) { if (ImGui::BeginMenu("Debug")) {
ImGui::BeginDisabled(getSettings().game.speedrunMode);
bool developmentMode = mDoMain::developmentMode == 1; bool developmentMode = mDoMain::developmentMode == 1;
if (ImGui::Checkbox("Development Mode", &developmentMode)) { if (ImGui::Checkbox("Development Mode", &developmentMode)) {
mDoMain::developmentMode = developmentMode ? 1 : -1; mDoMain::developmentMode = developmentMode ? 1 : -1;
@@ -113,12 +119,16 @@ namespace dusk {
ImGui::MenuItem("Audio Debug", hotkeys::SHOW_AUDIO_DEBUG, &m_showAudioDebug); ImGui::MenuItem("Audio Debug", hotkeys::SHOW_AUDIO_DEBUG, &m_showAudioDebug);
ImGui::MenuItem("Bloom", nullptr, &m_showBloomWindow); ImGui::MenuItem("Bloom", nullptr, &m_showBloomWindow);
ImGui::MenuItem("Stub Log", nullptr, &m_showStubLog); ImGui::MenuItem("Stub Log", nullptr, &m_showStubLog);
ImGui::MenuItem("Actor Spawner", nullptr, &m_showActorSpawner);
if (!dusk::IsGameLaunched) { if (!dusk::IsGameLaunched) {
ImGui::EndDisabled(); ImGui::EndDisabled();
} }
ImGui::MenuItem("OSReport Force", nullptr, &OSReportReallyForceEnable); ImGui::MenuItem("OSReport Force", nullptr, &OSReportReallyForceEnable);
ImGui::EndDisabled();
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
+3
View File
@@ -29,6 +29,7 @@ namespace dusk {
void ShowStateShare(); void ShowStateShare();
void ShowAchievements(); void ShowAchievements();
void notifyAchievement(std::string name); void notifyAchievement(std::string name);
void ShowActorSpawner();
private: private:
bool m_showDebugOverlay = false; bool m_showDebugOverlay = false;
@@ -71,6 +72,8 @@ namespace dusk {
bool m_showAchievements = false; bool m_showAchievements = false;
ImGuiAchievements m_achievementsWindow; ImGuiAchievements m_achievementsWindow;
bool m_showActorSpawner = false;
}; };
} }
+13 -11
View File
@@ -75,6 +75,7 @@ void fileDialogCallback(void* userdata, const char* path, const char* error) {
} }
self->m_selectedIsoPath = path; self->m_selectedIsoPath = path;
self->m_isPal = iso::isPal(path);
getSettings().backend.isoPath.setValue(self->m_selectedIsoPath); getSettings().backend.isoPath.setValue(self->m_selectedIsoPath);
config::Save(); config::Save();
} }
@@ -92,6 +93,7 @@ bool ImGuiPreLaunchWindow::isSelectedPathValid() const {
void ImGuiPreLaunchWindow::draw() { void ImGuiPreLaunchWindow::draw() {
if (m_IsFirstDraw) { if (m_IsFirstDraw) {
m_selectedIsoPath = getSettings().backend.isoPath; m_selectedIsoPath = getSettings().backend.isoPath;
m_isPal = !m_selectedIsoPath.empty() && iso::isPal(m_selectedIsoPath.c_str());
m_initialGraphicsBackend = getSettings().backend.graphicsBackend; m_initialGraphicsBackend = getSettings().backend.graphicsBackend;
m_IsFirstDraw = false; m_IsFirstDraw = false;
} }
@@ -193,24 +195,24 @@ void ImGuiPreLaunchWindow::drawOptions() {
ImGui::InputText("Game ISO Path", &m_selectedIsoPath, ImGuiInputTextFlags_ReadOnly); ImGui::InputText("Game ISO Path", &m_selectedIsoPath, ImGuiInputTextFlags_ReadOnly);
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Set")) { if (ImGui::Button(m_selectedIsoPath == "" ? "Set" : "Change")) {
ShowFileSelect(&fileDialogCallback, this, aurora::window::get_sdl_window(), ShowFileSelect(&fileDialogCallback, this, aurora::window::get_sdl_window(),
skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()), nullptr, skGameDiscFileFilters.data(), int(skGameDiscFileFilters.size()), nullptr,
false); false);
} }
// TODO: Only show if PAL disc selected? if (m_isPal) {
// Language selection auto selectedLanguage = getSettings().game.language.getValue();
auto selectedLanguage = getSettings().game.language.getValue(); if (ImGui::BeginCombo("Language", skLanguageNames[static_cast<u8>(selectedLanguage)])) {
if (ImGui::BeginCombo("Language", skLanguageNames[static_cast<u8>(selectedLanguage)])) { for (u8 i = 0; i < skLanguageNames.size(); ++i) {
for (u8 i = 0; i < skLanguageNames.size(); ++i) { if (ImGui::Selectable(skLanguageNames[i])) {
if (ImGui::Selectable(skLanguageNames[i])) { getSettings().game.language.setValue(static_cast<GameLanguage>(i));
getSettings().game.language.setValue(static_cast<GameLanguage>(i)); config::Save();
config::Save(); }
} }
}
ImGui::EndCombo(); ImGui::EndCombo();
}
} }
AuroraBackend configuredBackend = BACKEND_AUTO; AuroraBackend configuredBackend = BACKEND_AUTO;
+1
View File
@@ -18,5 +18,6 @@ public:
std::string m_selectedIsoPath; std::string m_selectedIsoPath;
std::string m_errorString; std::string m_errorString;
bool m_isPal = false;
}; };
} // namespace dusk } // namespace dusk
+31
View File
@@ -17,6 +17,11 @@ constexpr const char* TP_GAME_IDS[] = {
"RZDK01", // Wii KOR "RZDK01", // Wii KOR
}; };
constexpr const char* PAL_GAME_IDS[] = {
"GZ2P01", // GCN PAL
"RZDP01", // Wii PAL
};
constexpr const char* SUPPORTED_TP_GAME_IDS[] = { constexpr const char* SUPPORTED_TP_GAME_IDS[] = {
"GZ2E01", // GCN USA "GZ2E01", // GCN USA
"GZ2P01", // GCN PAL "GZ2P01", // GCN PAL
@@ -124,4 +129,30 @@ ValidationError validate(const char* path) {
return ValidationError::Success; return ValidationError::Success;
} }
bool isPal(const char* path) {
NodHandleWrapper disc;
const auto sdlStream = SDL_IOFromFile(path, "rb");
if (sdlStream == nullptr) {
return false;
}
const NodDiscStream nod_stream{
.user_data = sdlStream,
.read_at = StreamReadAt,
.stream_len = StreamLength,
.close = StreamClose,
};
if (nod_disc_open_stream(&nod_stream, nullptr, &disc.handle) != NOD_RESULT_OK || disc.handle == nullptr) {
return false;
}
NodDiscHeader header{};
if (nod_disc_header(disc.handle, &header) != NOD_RESULT_OK) {
return false;
}
return matches(header.game_id, PAL_GAME_IDS);
}
} // namespace dusk::iso } // namespace dusk::iso
+1
View File
@@ -13,6 +13,7 @@ namespace dusk::iso {
}; };
ValidationError validate(const char* path); ValidationError validate(const char* path);
bool isPal(const char* path);
} }
#endif // DUSK_ISO_VALIDATE_HPP #endif // DUSK_ISO_VALIDATE_HPP
+183
View File
@@ -0,0 +1,183 @@
#if _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
using socket_t = SOCKET;
static void closeSocket(socket_t s) { closesocket(s); }
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
using socket_t = int;
static void closeSocket(socket_t s) { close(s); }
#ifndef INVALID_SOCKET
#define INVALID_SOCKET -1
#endif
#endif
#include <cstdio>
#include "dusk/livesplit.h"
#include "f_op/f_op_overlap_mng.h"
namespace dusk::speedrun {
static bool running = false;
static uint64_t frameCount = 0;
static socket_t sock = INVALID_SOCKET;
static bool wasLoading = false;
static bool connected = false;
static bool connectPending = false;
static bool disconnectPending = false;
static void sendCmd(const char* cmd) {
if (sock == INVALID_SOCKET) {
return;
}
char msg[64];
int len = snprintf(msg, sizeof(msg), "%s\r\n", cmd);
if (send(sock, msg, len, 0) >= 0) {
if (!connected) {
connected = connectPending = true;
}
return;
}
#if _WIN32
int err = WSAGetLastError();
if (err == WSAEWOULDBLOCK || err == WSAENOTCONN) {
return;
}
#else
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOTCONN) {
return;
}
#endif
if (connected) disconnectPending = true;
closeSocket(sock);
sock = INVALID_SOCKET;
connected = connectPending = false;
}
uint64_t getFrameCount() {
return frameCount;
}
void onGameFrame() {
if (!running) {
return;
}
bool loading = fopOvlpM_IsDoingReq() != 0;
if (loading != wasLoading) {
sendCmd(loading ? "pausegametime" : "unpausegametime");
wasLoading = loading;
}
if (!loading) {
++frameCount;
}
}
void start() {
if (running) {
return;
}
running = true;
frameCount = 0;
wasLoading = false;
sendCmd("initgametime");
sendCmd("reset");
sendCmd("starttimer");
}
void reset() {
running = false;
frameCount = 0;
wasLoading = false;
sendCmd("reset");
}
void connectLiveSplit(const char* host, int port) {
#if _WIN32
WSADATA wd{}; WSAStartup(MAKEWORD(2, 2), &wd);
#endif
if (sock != INVALID_SOCKET) {
closeSocket(sock); sock = INVALID_SOCKET;
}
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET) {
return;
}
#if _WIN32
u_long nb = 1;
ioctlsocket(sock, FIONBIO, &nb);
#else
fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
#endif
sockaddr_in addr{}; addr.sin_family = AF_INET;
addr.sin_port = htons((uint16_t)port);
inet_pton(AF_INET, host, &addr.sin_addr);
connect(sock, (sockaddr*)&addr, sizeof(addr));
sendCmd("initgametime");
}
void disconnectLiveSplit() {
if (sock != INVALID_SOCKET) {
closeSocket(sock);
sock = INVALID_SOCKET;
connected = false;
}
}
bool consumeConnectedEvent() { bool v = connectPending; connectPending = false; return v; }
bool consumeDisconnectedEvent() { bool v = disconnectPending; disconnectPending = false; return v; }
void updateLiveSplit() {
if (sock == INVALID_SOCKET) {
return;
}
if (!connected) {
sendCmd("initgametime");
return;
}
if (!running) {
return;
}
const uint64_t totalMs = frameCount * 1000 / 30;
const uint64_t totalSec = totalMs / 1000;
char cmd[32];
snprintf(cmd, sizeof(cmd), "setgametime %u:%02u:%02u.%03u",
(uint32_t)(totalSec / 3600),
(uint32_t)((totalSec / 60) % 60),
(uint32_t)(totalSec % 60),
(uint32_t)(totalMs % 1000)
);
sendCmd(cmd);
}
void shutdown() {
disconnectLiveSplit();
#if _WIN32
WSACleanup();
#endif
}
}
+11 -1
View File
@@ -36,6 +36,7 @@ UserSettings g_userSettings = {
.fastClimbing {"game.fastClimbing", false}, .fastClimbing {"game.fastClimbing", false},
.noMissClimbing {"game.noMissClimbing", false}, .noMissClimbing {"game.noMissClimbing", false},
.fastTears {"game.fastTears", false}, .fastTears {"game.fastTears", false},
.no2ndFishForCat {"game.no2ndFishForCat", false},
.instantSaves {"game.instantSaves", false}, .instantSaves {"game.instantSaves", false},
.instantText {"game.instantText", false}, .instantText {"game.instantText", false},
.sunsSong {"game.sunsSong", false}, .sunsSong {"game.sunsSong", false},
@@ -55,6 +56,7 @@ UserSettings g_userSettings = {
.internalResolutionScale {"game.internalResolutionScale", 0}, .internalResolutionScale {"game.internalResolutionScale", 0},
.shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1}, .shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1},
.enableDepthOfField {"game.enableDepthOfField", true}, .enableDepthOfField {"game.enableDepthOfField", true},
.enableMapBackground {"game.enableMapBackground", true},
// Audio // Audio
.noLowHpSound {"game.noLowHpSound", false}, .noLowHpSound {"game.noLowHpSound", false},
@@ -95,7 +97,11 @@ UserSettings g_userSettings = {
.restoreWiiGlitches {"game.restoreWiiGlitches", false}, .restoreWiiGlitches {"game.restoreWiiGlitches", false},
// Controls // Controls
.enableTurboKeybind {"game.enableTurboKeybind", false} .enableTurboKeybind {"game.enableTurboKeybind", false},
// Tools
.speedrunMode {"game.speedrunMode", false},
.liveSplitEnabled {"game.liveSplitEnabled", false}
}, },
.backend = { .backend = {
@@ -142,6 +148,7 @@ void registerSettings() {
Register(g_userSettings.game.instantDeath); Register(g_userSettings.game.instantDeath);
Register(g_userSettings.game.fastClimbing); Register(g_userSettings.game.fastClimbing);
Register(g_userSettings.game.fastTears); Register(g_userSettings.game.fastTears);
Register(g_userSettings.game.no2ndFishForCat);
Register(g_userSettings.game.instantSaves); Register(g_userSettings.game.instantSaves);
Register(g_userSettings.game.instantText); Register(g_userSettings.game.instantText);
Register(g_userSettings.game.sunsSong); Register(g_userSettings.game.sunsSong);
@@ -157,6 +164,7 @@ void registerSettings() {
Register(g_userSettings.game.internalResolutionScale); Register(g_userSettings.game.internalResolutionScale);
Register(g_userSettings.game.shadowResolutionMultiplier); Register(g_userSettings.game.shadowResolutionMultiplier);
Register(g_userSettings.game.enableDepthOfField); Register(g_userSettings.game.enableDepthOfField);
Register(g_userSettings.game.enableMapBackground);
Register(g_userSettings.game.enableFastIronBoots); Register(g_userSettings.game.enableFastIronBoots);
Register(g_userSettings.game.canTransformAnywhere); Register(g_userSettings.game.canTransformAnywhere);
Register(g_userSettings.game.freeMagicArmor); Register(g_userSettings.game.freeMagicArmor);
@@ -167,6 +175,8 @@ void registerSettings() {
Register(g_userSettings.game.noLowHpSound); Register(g_userSettings.game.noLowHpSound);
Register(g_userSettings.game.midnasLamentNonStop); Register(g_userSettings.game.midnasLamentNonStop);
Register(g_userSettings.game.enableTurboKeybind); Register(g_userSettings.game.enableTurboKeybind);
Register(g_userSettings.game.speedrunMode);
Register(g_userSettings.game.liveSplitEnabled);
Register(g_userSettings.game.fastSpinner); Register(g_userSettings.game.fastSpinner);
Register(g_userSettings.game.infiniteHearts); Register(g_userSettings.game.infiniteHearts);
Register(g_userSettings.game.infiniteArrows); Register(g_userSettings.game.infiniteArrows);
+122
View File
@@ -0,0 +1,122 @@
#include "dusk/vmem.h"
#if _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <sys/mman.h>
#include <unistd.h>
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
#endif
#include <atomic>
#include <mutex>
#include <cstdint>
namespace dusk {
size_t vmem_page_size() {
#if _WIN32
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwPageSize;
#else
return (size_t)sysconf(_SC_PAGESIZE);
#endif
}
void* vmem_reserve(size_t size) {
#if _WIN32
return VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_NOACCESS);
#else
void* p = mmap(nullptr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
return (p == MAP_FAILED) ? nullptr : p;
#endif
}
bool vmem_commit(void* ptr, size_t size) {
#if _WIN32
return VirtualAlloc(ptr, size, MEM_COMMIT, PAGE_READWRITE) != nullptr;
#else
return mprotect(ptr, size, PROT_READ | PROT_WRITE) == 0;
#endif
}
void vmem_decommit(void* ptr, size_t size) {
#if _WIN32
VirtualFree(ptr, size, MEM_DECOMMIT);
#else
mprotect(ptr, size, PROT_NONE);
madvise(ptr, size, MADV_DONTNEED);
#endif
}
void vmem_release(void* ptr, size_t size) {
#if _WIN32
(void)size;
VirtualFree(ptr, 0, MEM_RELEASE);
#else
munmap(ptr, size);
#endif
}
namespace {
static void* s_arenaBase = nullptr;
static size_t s_arenaTotal = 0;
static std::atomic<size_t> s_arenaBump{0};
struct FreeSlot { void* ptr; size_t size; };
static FreeSlot s_free[JKR_VMEM_MAX_FREE_SLOTS];
static size_t s_freeCount = 0;
static std::mutex s_freeMutex;
} // namespace
void vmem_arena_init() {
s_arenaBase = vmem_reserve(JKR_VMEM_ARENA_SIZE);
s_arenaTotal = JKR_VMEM_ARENA_SIZE;
}
void* vmem_arena_alloc(size_t size) {
const size_t pageSize = vmem_page_size();
size = (size + pageSize - 1) & ~(pageSize - 1);
{
std::lock_guard<std::mutex> lock(s_freeMutex);
for (size_t i = 0; i < s_freeCount; ++i) {
if (s_free[i].size >= size) {
void* ptr = s_free[i].ptr;
s_free[i] = s_free[--s_freeCount];
return ptr;
}
}
}
size_t offset = s_arenaBump.fetch_add(size);
if (offset + size > s_arenaTotal) {
s_arenaBump.fetch_sub(size);
return nullptr;
}
return static_cast<uint8_t*>(s_arenaBase) + offset;
}
void vmem_arena_free(void* ptr, size_t size) {
if (!ptr) {
return;
}
const size_t pageSize = vmem_page_size();
size = (size + pageSize - 1) & ~(pageSize - 1);
vmem_decommit(ptr, size);
std::lock_guard<std::mutex> lock(s_freeMutex);
if (s_freeCount < JKR_VMEM_MAX_FREE_SLOTS) {
s_free[s_freeCount++] = {ptr, size};
}
}
} // namespace dusk
+4
View File
@@ -15,6 +15,7 @@
#include "d/d_model.h" #include "d/d_model.h"
#include "d/d_tresure.h" #include "d/d_tresure.h"
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
#include "dusk/livesplit.h"
#include "dusk/logging.h" #include "dusk/logging.h"
#include "f_op/f_op_camera_mng.h" #include "f_op/f_op_camera_mng.h"
#include "f_op/f_op_draw_tag.h" #include "f_op/f_op_draw_tag.h"
@@ -815,6 +816,9 @@ void fapGm_Execute() {
fpcM_ManagementFunc(NULL, fapGm_After); fpcM_ManagementFunc(NULL, fapGm_After);
#endif #endif
cCt_Counter(0); cCt_Counter(0);
#ifdef TARGET_PC
dusk::speedrun::onGameFrame();
#endif
} }
fapGm_HIO_c g_HIO; fapGm_HIO_c g_HIO;
+20
View File
@@ -7,6 +7,8 @@
#include "f_op/f_op_overlap_req.h" #include "f_op/f_op_overlap_req.h"
#include "f_pc/f_pc_manager.h" #include "f_pc/f_pc_manager.h"
#include "dusk/imgui/ImGuiMenuGame.hpp"
void fopOvlpReq_SetPeektime(overlap_request_class*, u16); void fopOvlpReq_SetPeektime(overlap_request_class*, u16);
static int fopOvlpReq_phase_Done(overlap_request_class* i_overlapReq) { static int fopOvlpReq_phase_Done(overlap_request_class* i_overlapReq) {
@@ -16,6 +18,16 @@ static int fopOvlpReq_phase_Done(overlap_request_class* i_overlapReq) {
i_overlapReq->peektime = 0; i_overlapReq->peektime = 0;
i_overlapReq->field_0x8 = 0; i_overlapReq->field_0x8 = 0;
i_overlapReq->field_0xc = 0; i_overlapReq->field_0xc = 0;
#if TARGET_PC
if (dusk::getSettings().game.speedrunMode) {
if (dusk::m_speedrunInfo.m_isRunStarted) {
dusk::m_speedrunInfo.m_isPauseIGT = false;
dusk::m_speedrunInfo.m_totalLoadTime += OSGetTime() - dusk::m_speedrunInfo.m_loadStartTimestamp;
dusk::m_speedrunInfo.m_loadStartTimestamp = OSGetTime();
}
}
#endif
return cPhs_NEXT_e; return cPhs_NEXT_e;
} }
@@ -81,6 +93,14 @@ static int fopOvlpReq_phase_Create(overlap_request_class* i_overlapReq) {
fpcLy_SetCurrentLayer(i_overlapReq->layer); fpcLy_SetCurrentLayer(i_overlapReq->layer);
i_overlapReq->request_id = i_overlapReq->request_id =
fpcM_Create(i_overlapReq->procname, NULL, NULL); fpcM_Create(i_overlapReq->procname, NULL, NULL);
#if TARGET_PC
if (dusk::m_speedrunInfo.m_isRunStarted) {
dusk::m_speedrunInfo.m_isPauseIGT = true;
dusk::m_speedrunInfo.m_loadStartTimestamp = OSGetTime();
}
#endif
return cPhs_NEXT_e; return cPhs_NEXT_e;
} }
+3 -2
View File
@@ -4,13 +4,14 @@
*/ */
#include "f_op/f_op_scene_req.h" #include "f_op/f_op_scene_req.h"
#include <cstdio>
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/logging.h"
#include "f_op/f_op_overlap_mng.h" #include "f_op/f_op_overlap_mng.h"
#include "f_op/f_op_scene.h" #include "f_op/f_op_scene.h"
#include "f_op/f_op_scene_pause.h" #include "f_op/f_op_scene_pause.h"
#include "f_pc/f_pc_executor.h" #include "f_pc/f_pc_executor.h"
#include "f_pc/f_pc_manager.h" #include "f_pc/f_pc_manager.h"
#include <cstdio>
#include "dusk/logging.h"
static cPhs_Step fopScnRq_phase_ClearOverlap(scene_request_class* i_sceneReq) { static cPhs_Step fopScnRq_phase_ClearOverlap(scene_request_class* i_sceneReq) {
return fopOvlpM_ClearOfReq() == 1 ? cPhs_NEXT_e : cPhs_INIT_e; return fopOvlpM_ClearOfReq() == 1 ? cPhs_NEXT_e : cPhs_INIT_e;
+9 -1
View File
@@ -71,6 +71,7 @@
#include "dusk/config.hpp" #include "dusk/config.hpp"
#include "dusk/imgui/ImGuiConsole.hpp" #include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/settings.h" #include "dusk/settings.h"
#include "dusk/vmem.h"
#include "dusk/version.hpp" #include "dusk/version.hpp"
#include "dusk/discord_presence.hpp" #include "dusk/discord_presence.hpp"
#include "tracy/Tracy.hpp" #include "tracy/Tracy.hpp"
@@ -551,12 +552,19 @@ int game_main(int argc, char* argv[]) {
config.desiredBackend = ResolveDesiredBackend(parsed_arg_options); config.desiredBackend = ResolveDesiredBackend(parsed_arg_options);
config.logCallback = &aurora_log_callback; config.logCallback = &aurora_log_callback;
config.logLevel = startupLogLevel; config.logLevel = startupLogLevel;
config.mem1Size = 256 * 1024 * 1024; // Child heaps use independent vmem reservations on PC
config.mem1Size = DUSK_IF_ELSE(16, 256) * 1024 * 1024;
config.mem2Size = 24 * 1024 * 1024; config.mem2Size = 24 * 1024 * 1024;
config.allowJoystickBackgroundEvents = true; config.allowJoystickBackgroundEvents = true;
config.imGuiInitCallback = &aurora_imgui_init_callback; config.imGuiInitCallback = &aurora_imgui_init_callback;
config.allowTextureReplacements = true; config.allowTextureReplacements = true;
config.allowTextureDumps = false; config.allowTextureDumps = false;
#if TARGET_PC
dusk::vmem_arena_init();
#endif
auroraInfo = aurora_initialize(argc, argv, &config); auroraInfo = aurora_initialize(argc, argv, &config);
} }