mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-10 12:54:50 -04:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c803bfb545 | |||
| 2623c44cab | |||
| 24dd02fc81 | |||
| a97602b6dc | |||
| e2943e90dc | |||
| afe54f22ab | |||
| e15f5bcee9 | |||
| b26896cad5 | |||
| f75faf6b06 | |||
| 3e05789b58 | |||
| 4d12cc8ea2 | |||
| 2ed2268579 | |||
| 94a99e8da0 | |||
| ddaf50c01d | |||
| 7566949b42 | |||
| bb6db3caea | |||
| 2dc494dc1c | |||
| 3c25633ee9 | |||
| d99ed2729b | |||
| 782455d48b | |||
| 47863b34c2 | |||
| 92391d5eb8 | |||
| 0d37cb4e54 | |||
| ea528ed9d9 |
@@ -3,6 +3,10 @@
|
||||
- ### **[Official Website](https://twilitrealm.dev)**
|
||||
- ### **[Discord](https://discord.gg/QACynxeyna)**
|
||||
|
||||
# Overview
|
||||
Dusk is a reverse-engineered reimplementation of Twilight Princess.
|
||||
It aims to be as accurate as possible to the original while also providing new options, enhancements, and tools to customize your experience.
|
||||
|
||||
# Setup
|
||||
**⚠️ Dusk does NOT provide any copyrighted assets. You must provide your own copy of the game.**
|
||||
|
||||
@@ -27,5 +31,7 @@ First make sure your dump of the game is clean and supported by Dusk. You can do
|
||||
# Building
|
||||
If you'd like to build Dusk from source, please read the [build instructions](docs/building.md).
|
||||
|
||||
Pull Requests are welcomed! Note that we do not accept contributions that are primarily AI generated and will close your PR if we suspect as much.
|
||||
|
||||
# Credits
|
||||
Special thanks to the [TP decompilation](https://github.com/zeldaret/tp) team, the GC/Wii decompilation community, the [Aurora](https://github.com/encounter/aurora) developers, the [TP speedrunning community](https://zsrtp.link), and all [contributors](https://github.com/TwilitRealm/dusk/graphs/contributors).
|
||||
|
||||
Vendored
+1
-1
Submodule extern/aurora updated: 7784b6fc95...c77a4d0c3c
@@ -1453,7 +1453,6 @@ set(DUSK_FILES
|
||||
src/dusk/imgui/ImGuiProcessOverlay.cpp
|
||||
src/dusk/imgui/ImGuiCameraOverlay.cpp
|
||||
src/dusk/imgui/ImGuiHeapOverlay.cpp
|
||||
src/dusk/imgui/ImGuiActorSpawner.cpp
|
||||
src/dusk/imgui/ImGuiDebugPad.cpp
|
||||
src/dusk/imgui/ImGuiControllerOverlay.cpp
|
||||
src/dusk/imgui/ImGuiStubLog.cpp
|
||||
@@ -1467,7 +1466,6 @@ set(DUSK_FILES
|
||||
src/dusk/iso_validate.cpp
|
||||
src/dusk/livesplit.cpp
|
||||
src/dusk/offset_ptr.cpp
|
||||
src/dusk/vmem.cpp
|
||||
src/dusk/OSContext.cpp
|
||||
src/dusk/OSThread.cpp
|
||||
src/dusk/OSMutex.cpp
|
||||
|
||||
@@ -67,6 +67,9 @@ public:
|
||||
bool isStaffMessage();
|
||||
bool isSaveMessage();
|
||||
bool isTalkMessage();
|
||||
#if TARGET_PC
|
||||
bool isShopItemMessage();
|
||||
#endif
|
||||
const char* getSmellName();
|
||||
const char* getPortalName();
|
||||
const char* getBombName();
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
@@ -14,6 +16,7 @@ enum class AchievementCategory : uint8_t {
|
||||
Collection,
|
||||
Challenge,
|
||||
Minigame,
|
||||
Misc,
|
||||
Glitched
|
||||
};
|
||||
|
||||
@@ -40,6 +43,11 @@ public:
|
||||
void save();
|
||||
void tick();
|
||||
void clearAll();
|
||||
void clearOne(const char* key);
|
||||
|
||||
// Signals are visible to all achievement checks within the same tick, then cleared.
|
||||
void signal(const char* key);
|
||||
bool hasSignal(const char* key) const;
|
||||
|
||||
std::vector<Achievement> getAchievements() const;
|
||||
bool hasPendingUnlock() const { return !m_pendingUnlocks.empty(); }
|
||||
@@ -57,6 +65,7 @@ private:
|
||||
void processEntry(Entry& e);
|
||||
|
||||
std::vector<Entry> m_entries;
|
||||
std::unordered_set<std::string_view> m_signals;
|
||||
bool m_loaded = false;
|
||||
bool m_dirty = false;
|
||||
std::queue<std::string> m_pendingUnlocks;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#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
|
||||
@@ -1,54 +0,0 @@
|
||||
#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,13 +127,6 @@ public:
|
||||
[[nodiscard]] const CMemBlock* getFreeHead() const { return mHeadFreeList; }
|
||||
[[nodiscard]] CMemBlock* getUsedHead() { 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
|
||||
};
|
||||
|
||||
|
||||
@@ -61,15 +61,6 @@ public:
|
||||
static JKRSolidHeap* create(u32, JKRHeap*, bool);
|
||||
|
||||
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) {
|
||||
|
||||
@@ -10,11 +10,6 @@
|
||||
#include "JSystem/JUtility/JUTConsole.h"
|
||||
#include "JSystem/JUtility/JUTException.h"
|
||||
#include <cstdlib>
|
||||
#if TARGET_PC
|
||||
#include "dusk/vmem.h"
|
||||
#include <algorithm>
|
||||
#include "dusk/logging.h"
|
||||
#endif
|
||||
|
||||
JKRExpHeap* JKRExpHeap::createRoot(int maxHeaps, bool errorFlag) {
|
||||
JKRExpHeap* heap = NULL;
|
||||
@@ -76,49 +71,21 @@ JKRExpHeap* JKRExpHeap::create(u32 size, JKRHeap* parent, bool errorFlag) {
|
||||
|
||||
u32 alignedSize = ALIGN_PREV(size, 0x10);
|
||||
|
||||
if (alignedSize < expHeapSize + blockSize) {
|
||||
if (alignedSize < expHeapSize + blockSize)
|
||||
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* 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;
|
||||
u8* memory = (u8*)JKRAllocFromHeap(parent, alignedSize, 0x10);
|
||||
u8* dataPtr = (memory + expHeapSize);
|
||||
if (!memory) {
|
||||
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) {
|
||||
JKRFree(memory);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
if (newHeap) {
|
||||
u8* local_30 = dataPtr + sizeof(CMemBlock);
|
||||
@@ -135,16 +102,9 @@ JKRExpHeap* JKRExpHeap::create(u32 size, JKRHeap* parent, bool errorFlag) {
|
||||
JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* parent, bool errorFlag) {
|
||||
JKRHeap* parent2;
|
||||
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);
|
||||
#endif
|
||||
if (!parent2) {
|
||||
if (!parent2)
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
parent2 = parent;
|
||||
}
|
||||
@@ -176,15 +136,6 @@ JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* parent, bool errorF
|
||||
}
|
||||
|
||||
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) {
|
||||
JKRHeap* heap = getParent();
|
||||
if (heap) {
|
||||
@@ -212,11 +163,6 @@ JKRExpHeap::JKRExpHeap(void* data, u32 size, JKRHeap* parent, bool errorFlag)
|
||||
mHeadFreeList->initiate(NULL, NULL, size - sizeof(CMemBlock), 0, 0);
|
||||
mHeadUsedList = NULL;
|
||||
mTailUsedList = NULL;
|
||||
#if TARGET_PC
|
||||
mVmemBase = nullptr;
|
||||
mVmemCapacity = 0;
|
||||
mVmemCommitted = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
JKRExpHeap::~JKRExpHeap() {
|
||||
@@ -268,24 +214,6 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
|
||||
#endif
|
||||
|
||||
#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) {
|
||||
// Allocation failed.
|
||||
OSReport_Error(
|
||||
@@ -563,49 +491,6 @@ static void dummy() {
|
||||
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() {
|
||||
lock();
|
||||
JKRHeap::callAllDisposer();
|
||||
|
||||
@@ -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/JGadget/binary.h"
|
||||
@@ -7,11 +7,6 @@
|
||||
#include "global.h"
|
||||
#include <stdint.h>
|
||||
#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) {
|
||||
if (!heap) {
|
||||
@@ -24,56 +19,18 @@ JKRSolidHeap* JKRSolidHeap::create(u32 size, JKRHeap* heap, bool useErrorHandler
|
||||
}
|
||||
|
||||
u32 alignedSize = ALIGN_PREV(size, 0x10);
|
||||
if (alignedSize < solidHeapSize) {
|
||||
if (alignedSize < solidHeapSize)
|
||||
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);
|
||||
void* dataPtr = mem + solidHeapSize;
|
||||
if (!mem) {
|
||||
if (!mem)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return JKR_NEW_ARGS (mem) JKRSolidHeap(dataPtr, alignedSize - solidHeapSize, heap, useErrorHandler);
|
||||
#endif
|
||||
}
|
||||
|
||||
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();
|
||||
if (parent) {
|
||||
this->~JKRSolidHeap();
|
||||
@@ -87,11 +44,6 @@ JKRSolidHeap::JKRSolidHeap(void* start, u32 size, JKRHeap* parent, bool useError
|
||||
mSolidHead = (u8*)mStart;
|
||||
mSolidTail = (u8*)mEnd;
|
||||
field_0x78 = NULL;
|
||||
#if TARGET_PC
|
||||
mVmemBase = nullptr;
|
||||
mVmemCapacity = 0;
|
||||
mVmemCommitted = 0;
|
||||
#endif
|
||||
#if DEBUG
|
||||
if (mDebugFill) {
|
||||
JKRFillMemory(mStart, mSize, JKRValue_DEBUGFILL_NOTUSE);
|
||||
@@ -107,15 +59,6 @@ s32 JKRSolidHeap::adjustSize(void) {
|
||||
int r25 = 0;
|
||||
JKRHeap* parent = getParent();
|
||||
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();
|
||||
u32 thisSize = (uintptr_t)mStart - (uintptr_t)this;
|
||||
u32 newSize = ALIGN_NEXT(mSolidHead - mStart, 0x20);
|
||||
@@ -167,11 +110,6 @@ void* JKRSolidHeap::allocFromHead(u32 size, int alignment) {
|
||||
void* ptr = NULL;
|
||||
uintptr_t alignedStart = (alignment - 1 + (uintptr_t)mSolidHead) & ~(alignment - 1);
|
||||
u32 totalSize = size + (alignedStart - (uintptr_t)mSolidHead);
|
||||
#if TARGET_PC
|
||||
if (totalSize > mFreeSize && mVmemBase) {
|
||||
growHeap(totalSize);
|
||||
}
|
||||
#endif
|
||||
if (totalSize <= mFreeSize) {
|
||||
#if DEBUG
|
||||
if (mCheckMemoryFilled) {
|
||||
@@ -199,15 +137,6 @@ void* JKRSolidHeap::allocFromTail(u32 size, int alignment) {
|
||||
void* ptr = NULL;
|
||||
uintptr_t alignedStart = ALIGN_PREV((uintptr_t)mSolidTail - size, alignment);
|
||||
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) {
|
||||
ptr = (void*)alignedStart;
|
||||
mSolidTail -= totalSize;
|
||||
@@ -229,47 +158,6 @@ void* JKRSolidHeap::allocFromTail(u32 size, int alignment) {
|
||||
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) {
|
||||
JUTWarningConsole_f("free: cannot free memory block (%08x)\n", ptr);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
#include "d/actor/d_a_horse.h"
|
||||
#include "d/actor/d_a_crod.h"
|
||||
#include "d/d_msg_object.h"
|
||||
#ifdef TARGET_PC
|
||||
#include "d/actor/d_a_obj_carry.h"
|
||||
#include "dusk/achievements.h"
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
#include "d/d_s_menu.h"
|
||||
@@ -677,6 +681,15 @@ BOOL daAlink_c::checkDamageAction() {
|
||||
}
|
||||
|
||||
setDamagePoint(dmg, at_mtrl == dCcD_MTRL_FIRE || at_mtrl == dCcD_MTRL_ICE, TRUE, 0);
|
||||
|
||||
#ifdef TARGET_PC
|
||||
if (tghit_ac_name == fpcNm_Obj_Carry_e) {
|
||||
auto* carry = static_cast<daObjCarry_c*>(tghit_ac);
|
||||
if (carry->prm_chk_type_ironball() && carry->checkCannon()) {
|
||||
dusk::AchievementSystem::get().signal("iron_ball_hit_player");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (armor_no_dmg && at_mtrl != dCcD_MTRL_ELECTRIC && at_mtrl != dCcD_MTRL_ICE) {
|
||||
setGuardSe(var_r29);
|
||||
|
||||
@@ -18,6 +18,10 @@ enum {
|
||||
};
|
||||
|
||||
void daAlink_c::hsChainShape_c::draw() {
|
||||
if (dusk::getSettings().game.superClawshot) {
|
||||
return;
|
||||
}
|
||||
|
||||
static const int dummy = 0;
|
||||
|
||||
daAlink_c* alink = (daAlink_c*)getUserArea();
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "JSystem/J2DGraph/J2DAnmLoader.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/memory.h"
|
||||
|
||||
class daCoach2D_HIO_c : public mDoHIO_entry_c {
|
||||
public:
|
||||
struct Param {
|
||||
@@ -153,7 +155,7 @@ int daCoach2D_c::createHeap() {
|
||||
int daCoach2D_c::create() {
|
||||
int phase_state = dComIfG_resLoad(this, l_arcName);
|
||||
if (phase_state == cPhs_COMPLEATE_e) {
|
||||
if (!fopAcM_entrySolidHeap(this, daCoach2D_createHeap, 0x5050)) {
|
||||
if (!fopAcM_entrySolidHeap(this, daCoach2D_createHeap, HEAP_SIZE(0x5050, 0x6000))) {
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
|
||||
|
||||
@@ -282,6 +282,11 @@ static void e_th_spin_B(e_th_class* i_this) {
|
||||
i_this->current.pos += spC;
|
||||
|
||||
f32 speed_target;
|
||||
|
||||
#if AVOID_UB
|
||||
speed_target = 0;
|
||||
#endif
|
||||
|
||||
f32 anm_frame = i_this->mpModelMorf->getFrame();
|
||||
|
||||
switch (i_this->mMode) {
|
||||
|
||||
@@ -78,14 +78,7 @@ void dEyeHL_mng_c::remove(dEyeHL_c* i_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;
|
||||
#endif
|
||||
i_obj->m_timg = NULL;
|
||||
i_obj->m_pre = NULL;
|
||||
i_obj->m_next = NULL;
|
||||
|
||||
+2
-1
@@ -6,6 +6,7 @@
|
||||
#include "d/dolzel.h" // IWYU pragma: keep
|
||||
|
||||
#include "d/d_k_wmark.h"
|
||||
#include "dusk/memory.h"
|
||||
#include "JSystem/J3DGraphBase/J3DMaterial.h"
|
||||
#include "SSystem/SComponent/c_math.h"
|
||||
#include "d/actor/d_a_player.h"
|
||||
@@ -33,7 +34,7 @@ int dkWmark_c::create() {
|
||||
mColorType = this->parameters;
|
||||
}
|
||||
|
||||
mpHeap = mDoExt_createSolidHeapFromGameToCurrent(0x880, 0x20);
|
||||
mpHeap = mDoExt_createSolidHeapFromGameToCurrent(HEAP_SIZE(0x880, 0x1100), 0x20);
|
||||
if (mpHeap != NULL) {
|
||||
JKRHEAP_NAME(mpHeap, "dkWmark_c::mpHeap");
|
||||
J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes("Alink", 0x23);
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
#include "d/dolzel.h" // IWYU pragma: keep
|
||||
|
||||
#include "d/d_kankyo.h"
|
||||
#include "dusk/memory.h"
|
||||
#ifdef __REVOLUTION_SDK__
|
||||
#include <revolution.h>
|
||||
#else
|
||||
@@ -1185,7 +1186,7 @@ static void undwater_init() {
|
||||
J3DModelData* modelData2 = (J3DModelData*)dComIfG_getObjectRes("Always", 0x1D);
|
||||
JUT_ASSERT(1867, modelData2 != NULL);
|
||||
|
||||
g_env_light.undwater_ef_heap = mDoExt_createSolidHeapFromGameToCurrent(0x600, 0x20);
|
||||
g_env_light.undwater_ef_heap = mDoExt_createSolidHeapFromGameToCurrent(HEAP_SIZE(0x600, 0xC00), 0x20);
|
||||
JKRHEAP_NAME(g_env_light.undwater_ef_heap, "g_env_light.undwater_ef_heap");
|
||||
|
||||
if (g_env_light.undwater_ef_heap != NULL) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#ifdef TARGET_PC
|
||||
constexpr u16 kMapResolutionMultiplier = 4;
|
||||
constexpr u16 kMapCircleSize = 16 * kMapResolutionMultiplier;
|
||||
#endif
|
||||
|
||||
void dMpath_n::dTexObjAggregate_c::create() {
|
||||
@@ -32,6 +33,48 @@ void dMpath_n::dTexObjAggregate_c::create() {
|
||||
JUT_ASSERT(74, image->magFilter == GX_NEAR);
|
||||
mDoLib_setResTimgObj(image, mp_texObj[lp1], 0, NULL);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
auto hqCircle = JKR_NEW TGXTexObj();
|
||||
|
||||
static bool hqCircleDrawn = false;
|
||||
static u8 hqCircleData[kMapCircleSize * kMapCircleSize];
|
||||
|
||||
if (!hqCircleDrawn) {
|
||||
const auto center = kMapCircleSize / 2.0f;
|
||||
const auto radiusSq = center * center;
|
||||
const auto blocksAcross = kMapCircleSize >> 3;
|
||||
const auto totalPixels = sizeof(hqCircleData);
|
||||
|
||||
for (size_t i = 0; i < totalPixels; i++) {
|
||||
// 8x4 block swizzling for I8
|
||||
const auto blockIdx = i >> 5;
|
||||
const auto localIdx = i & 31;
|
||||
|
||||
const auto blockY = blockIdx / blocksAcross;
|
||||
const auto blockX = blockIdx % blocksAcross;
|
||||
|
||||
const auto localY = localIdx >> 3;
|
||||
const auto localX = localIdx & 7;
|
||||
|
||||
const auto x = (blockX << 3) + localX;
|
||||
const auto y = (blockY << 2) + localY;
|
||||
|
||||
const auto dx = (x + 0.5f) - center;
|
||||
const auto dy = (y + 0.5f) - center;
|
||||
|
||||
// the original texture is in I4 format and uses 1 to indicate if inside the circle
|
||||
// so we scale to I8 range: 255 / 15 = 17
|
||||
hqCircleData[i] = (dx * dx + dy * dy < radiusSq) ? 17 : 0;
|
||||
}
|
||||
hqCircleDrawn = true;
|
||||
}
|
||||
|
||||
GXInitTexObj(hqCircle, hqCircleData, kMapCircleSize, kMapCircleSize, GX_TF_I8, GX_CLAMP,
|
||||
GX_CLAMP, GX_FALSE);
|
||||
GXInitTexObjLOD(hqCircle, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1);
|
||||
mp_texObj[6] = hqCircle;
|
||||
#endif
|
||||
}
|
||||
|
||||
void dMpath_n::dTexObjAggregate_c::remove() {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "d/d_msg_object.h"
|
||||
#include "d/d_msg_scrn_explain.h"
|
||||
#include "d/d_stage.h"
|
||||
#include "dusk/memory.h"
|
||||
#include "f_op/f_op_msg_mng.h"
|
||||
|
||||
static dMf_HIO_c g_fmHIO;
|
||||
@@ -189,7 +190,7 @@ dMenu_Fmap_c::dMenu_Fmap_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i
|
||||
field_0x148[i] = 0.0f;
|
||||
}
|
||||
|
||||
mpTalkHeap = JKRCreateExpHeap(0x32000, mpHeap, false);
|
||||
mpTalkHeap = JKRCreateExpHeap(HEAP_SIZE(0x32000, 0x40000), mpHeap, false);
|
||||
JUT_ASSERT(359, mpTalkHeap != NULL);
|
||||
JKRHEAP_NAME(mpTalkHeap, "dMenu_Fmap_c::mpTalkHeap");
|
||||
field_0x200 = 0;
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
#include "d/d_msg_scrn_arrow.h"
|
||||
#include "d/d_lib.h"
|
||||
|
||||
#ifdef TARGET_PC
|
||||
#include "dusk/achievements.h"
|
||||
#endif
|
||||
|
||||
#if VERSION == VERSION_GCN_JPN
|
||||
#define D_MENU_LETTER_LINE_MAX 9
|
||||
#else
|
||||
@@ -514,6 +518,10 @@ void dMenu_Letter_c::read_open_init() {
|
||||
setAButtonString(0);
|
||||
setBButtonString(0);
|
||||
mpBlackTex->setAlpha(0);
|
||||
|
||||
#ifdef TARGET_PC
|
||||
dusk::AchievementSystem::get().signal("open_letter");
|
||||
#endif
|
||||
}
|
||||
|
||||
void dMenu_Letter_c::read_open_move() {
|
||||
|
||||
+7
-3
@@ -24,12 +24,16 @@
|
||||
#include "d/actor/d_a_horse.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/memory.h"
|
||||
|
||||
#include "dusk/memory.h"
|
||||
|
||||
int dMeter2_c::_create() {
|
||||
stage_stag_info_class* stag_info = dComIfGp_getStageStagInfo();
|
||||
if (dStage_stagInfo_GetUpButton(stag_info) == 1) {
|
||||
mpHeap = fopMsgM_createExpHeap(0x5A400, NULL);
|
||||
mpHeap = fopMsgM_createExpHeap(HEAP_SIZE(0x5A400, 0xA0000), NULL);
|
||||
} else {
|
||||
mpHeap = fopMsgM_createExpHeap(0x60800, NULL);
|
||||
mpHeap = fopMsgM_createExpHeap(HEAP_SIZE(0x60800, 0xC1000), NULL);
|
||||
}
|
||||
JKRHEAP_NAME(mpHeap, "dMeter2_c");
|
||||
|
||||
@@ -232,7 +236,7 @@ int dMeter2_c::_create() {
|
||||
dMeter2Info_setMeterMapClass(mpMap);
|
||||
|
||||
mpHeap->getTotalFreeSize();
|
||||
mpSubHeap = fopMsgM_createExpHeap(0x5000, mpHeap);
|
||||
mpSubHeap = fopMsgM_createExpHeap(HEAP_SIZE(0x5000, 0x6500), mpHeap);
|
||||
JKRHEAP_NAME(mpSubHeap, "dMeter2_c mpSubHeap");
|
||||
field_0x108 = NULL;
|
||||
mpSubContents = NULL;
|
||||
|
||||
@@ -1987,13 +1987,6 @@ bool jmessage_tSequenceProcessor::do_isReady() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) {
|
||||
field_0xb2 = 1;
|
||||
pReference->setSendTimer(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dComIfGp_checkMesgBgm()) {
|
||||
bool isItemMusicPlaying = true;
|
||||
if (mDoAud_checkPlayingSubBgmFlag() != Z2BGM_ITEM_GET &&
|
||||
@@ -2066,7 +2059,7 @@ bool jmessage_tSequenceProcessor::do_isReady() {
|
||||
case 0:
|
||||
case 5:
|
||||
case 6:
|
||||
if (mDoCPd_c::getTrigA(PAD_1) || field_0xb2 != 0) {
|
||||
if (mDoCPd_c::getTrigA(PAD_1) || field_0xb2 != 0 IF_DUSK(|| (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)))) {
|
||||
field_0xa4 = 0;
|
||||
pReference->onBatchFlag();
|
||||
pReference->setCharCnt(D_MSG_CLASS_CHAR_CNT_MAX);
|
||||
|
||||
+38
-1
@@ -32,6 +32,9 @@
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
static void dMsgObject_addFundRaising(s16 param_0);
|
||||
@@ -1594,7 +1597,7 @@ u8 dMsgObject_c::isSend() {
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
if (IF_DUSK((dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) ||)
|
||||
if (IF_DUSK((dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0) && !isShopItemMessage()) ||)
|
||||
mDoCPd_c::getTrigA(0) != 0 || mDoCPd_c::getTrigB(0) != 0) {
|
||||
return 2;
|
||||
}
|
||||
@@ -1866,6 +1869,40 @@ bool dMsgObject_c::isTalkMessage() {
|
||||
return true;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
bool dMsgObject_c::isShopItemMessage() {
|
||||
|
||||
// Probably a better way to do this than just listing every message id, but this works for now
|
||||
// Note: Keep contents sorted so we can use binary search
|
||||
const auto shopMsgIds = std::to_array<std::vector<s16>>({
|
||||
{},
|
||||
// zel_01.bmg - Seras Shop
|
||||
{7001, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, 7013, 7014, 7022, 7023, 7028, 7029,
|
||||
7044, 7045, 7053},
|
||||
// zel_02.bmg - Kakariko Shops
|
||||
{5251, 5253, 5254, 5256, 5258, 5259, 5653, 5654, 5656, 5660, 5661, 5664, 5665, 5697, 5698,
|
||||
5699, 5803, 5804, 5806, 5810, 5811, 5812, 5814, 5821, 5823, 5824, 5987, 5988, 5989, 5990,
|
||||
5991, 5992, 5993, 5994, 5995, 5996, 5997, 5998, 5999},
|
||||
// zel_03.bmg - Death Mountain Shop
|
||||
{5303, 5304, 5306, 5310, 5311, 5314, 5315, 5322, 5323, 5324, 5496, 5497, 5498, 5499},
|
||||
// zel_04.bmg - Castle Town Shops
|
||||
{5407, 5408, 5409, 5410, 5411, 5412, 5413, 5414, 5415, 5416, 5417, 5418, 5419, 5420, 5431,
|
||||
5432, 5433, 5434, 5435, 5436, 5437, 5438, 5439, 5440, 5441, 5444, 5449, 5450, 5451, 5452,
|
||||
5462},
|
||||
// zel_05.bmg - Oocca Shop
|
||||
{9428, 9429, 9430, 9431, 9432, 9437, 9443, 9448, 9449, 9451, 9459}
|
||||
});
|
||||
|
||||
u16 id = mMessageID;
|
||||
s16 group = dMsgObject_getGroupID();
|
||||
if (group < shopMsgIds.size()) {
|
||||
return std::ranges::binary_search(shopMsgIds[group], id);
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* dMsgObject_c::getSmellName() {
|
||||
JMSMesgInfo_c* info_header_p = (JMSMesgInfo_c*)((char*)mpMsgRes + 0x20);
|
||||
char* data_ptr = (char*)info_header_p + info_header_p->header.size;
|
||||
|
||||
+6
-18
@@ -36,27 +36,15 @@ dRes_info_c::dRes_info_c() {
|
||||
|
||||
dRes_info_c::~dRes_info_c() {
|
||||
if (mDMCommand != NULL) {
|
||||
#if TARGET_PC
|
||||
if (JKRHeap::findFromRoot(mDMCommand) != nullptr) {
|
||||
#endif
|
||||
mDMCommand->destroy();
|
||||
#if TARGET_PC
|
||||
}
|
||||
#endif
|
||||
mDMCommand->destroy();
|
||||
mDMCommand = NULL;
|
||||
} else if (mArchive != NULL) {
|
||||
#if TARGET_PC
|
||||
if (JKRHeap::findFromRoot(mArchive) != nullptr) {
|
||||
#endif
|
||||
deleteArchiveRes();
|
||||
if (mDataHeap != NULL) {
|
||||
mDoExt_destroySolidHeap(mDataHeap);
|
||||
mDataHeap = NULL;
|
||||
mArchive->unmount();
|
||||
}
|
||||
#if TARGET_PC
|
||||
deleteArchiveRes();
|
||||
if (mDataHeap != NULL) {
|
||||
mDoExt_destroySolidHeap(mDataHeap);
|
||||
mDataHeap = NULL;
|
||||
mArchive->unmount();
|
||||
}
|
||||
#endif
|
||||
mRes = NULL;
|
||||
mArchive = NULL;
|
||||
}
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@
|
||||
#include "d/d_meter2_info.h"
|
||||
#include "d/d_s_name.h"
|
||||
#include "dusk/imgui/ImGuiConsole.hpp"
|
||||
#include "dusk/memory.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "f_op/f_op_overlap_mng.h"
|
||||
#include "f_op/f_op_scene_mng.h"
|
||||
@@ -76,7 +77,7 @@ static s32 resLoad(request_of_phase_process_class* i_phase, char* i_resName) {
|
||||
s32 dScnName_c::create() {
|
||||
int phase_state = resLoad(&phase, "fileSel");
|
||||
if (phase_state == cPhs_COMPLEATE_e) {
|
||||
mHeap = JKRCreateExpHeap(0x180000, mDoExt_getGameHeap(), false);
|
||||
mHeap = JKRCreateExpHeap(HEAP_SIZE(0x180000, 0x1C0000), mDoExt_getGameHeap(), false);
|
||||
JUT_ASSERT(289, mHeap != NULL);
|
||||
JKRHEAP_NAME(mHeap, "File select");
|
||||
|
||||
|
||||
+6
-2
@@ -39,6 +39,10 @@
|
||||
#include "JSystem/JKernel/JKRAram.h"
|
||||
#include "JSystem/JKernel/JKRAramArchive.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/memory.h"
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
#include "d/d_s_menu.h"
|
||||
#include "d/d_debug_pad.h"
|
||||
@@ -1420,7 +1424,7 @@ static int phase_4(dScnPly_c* i_this) {
|
||||
dComIfGd_setViewport(NULL);
|
||||
dComIfGd_setView(NULL);
|
||||
|
||||
JKRExpHeap* heap = fopMsgM_createExpHeap(0xBB800, NULL);
|
||||
JKRExpHeap* heap = fopMsgM_createExpHeap(HEAP_SIZE(0xBB800, 0x177000), NULL);
|
||||
#if TARGET_PC
|
||||
heap->setName("Scene2DHeap");
|
||||
#endif
|
||||
@@ -1428,7 +1432,7 @@ static int phase_4(dScnPly_c* i_this) {
|
||||
JUT_ASSERT(2704, heap != NULL);
|
||||
dComIfGp_setExpHeap2D(heap);
|
||||
|
||||
JKRExpHeap* heap2 = fopMsgM_createExpHeap(0xA800, NULL);
|
||||
JKRExpHeap* heap2 = fopMsgM_createExpHeap(HEAP_SIZE(0xA800, 0x15000), NULL);
|
||||
#if TARGET_PC
|
||||
heap2->setName("SceneMsgHeap");
|
||||
#endif
|
||||
|
||||
+127
-8
@@ -8,6 +8,7 @@
|
||||
#include "d/actor/d_a_player.h"
|
||||
#include "d/d_demo.h"
|
||||
#include "f_pc/f_pc_name.h"
|
||||
#include "f_op/f_op_actor_mng.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <algorithm>
|
||||
@@ -46,6 +47,21 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"plumm_max",
|
||||
"Thank You Berry Much",
|
||||
"Score 61,454 points in the Plumm minigame.",
|
||||
AchievementCategory::Minigame,
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
if (dComIfGs_getBalloonScore() >= 61454) {
|
||||
a.progress = 1;
|
||||
}
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"rollgoal_8",
|
||||
@@ -258,6 +274,58 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"friendly_fire",
|
||||
"Friendly Fire",
|
||||
"Get hit by your own cannonball.",
|
||||
AchievementCategory::Misc,
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
if (AchievementSystem::get().hasSignal("iron_ball_hit_player")) {
|
||||
a.progress = 1;
|
||||
}
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"long_jump_attack",
|
||||
"Long Jump Attack",
|
||||
"Travel more than 20 meters in a single jump attack before landing.",
|
||||
AchievementCategory::Misc,
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
static bool inJump = false;
|
||||
static float startX = 0.0f, startZ = 0.0f;
|
||||
|
||||
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
|
||||
if (link == nullptr) {
|
||||
inJump = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!inJump) {
|
||||
if (link->mProcID == daAlink_c::PROC_CUT_JUMP) {
|
||||
inJump = true;
|
||||
startX = link->current.pos.x;
|
||||
startZ = link->current.pos.z;
|
||||
}
|
||||
} else if (link->mProcID == daAlink_c::PROC_CUT_JUMP_LAND) {
|
||||
inJump = false;
|
||||
const float dx = link->current.pos.x - startX;
|
||||
const float dz = link->current.pos.z - startZ;
|
||||
if (dx * dx + dz * dz >= 2000.0f * 2000.0f) {
|
||||
a.progress = 1;
|
||||
}
|
||||
} else if (link->mProcID != daAlink_c::PROC_CUT_JUMP) {
|
||||
inJump = false;
|
||||
}
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"back_in_time",
|
||||
@@ -267,18 +335,13 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
static int titleNoDemoFrames = 0;
|
||||
if (fopAcM_SearchByName(fpcNm_TITLE_e) == nullptr) {
|
||||
titleNoDemoFrames = 0;
|
||||
return;
|
||||
}
|
||||
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
|
||||
if (link != nullptr && dDemo_c::getMode() == 0) {
|
||||
if (++titleNoDemoFrames >= 60) {
|
||||
const auto* player = static_cast<const daPy_py_c*>(daPy_getPlayerActorClass());
|
||||
|
||||
if (player != nullptr && player->mDemo.getDemoMode() == 1) {
|
||||
a.progress = 1;
|
||||
}
|
||||
} else {
|
||||
titleNoDemoFrames = 0;
|
||||
}
|
||||
},
|
||||
{}
|
||||
@@ -345,6 +408,41 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
|
||||
}
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"email_me",
|
||||
"Email Me",
|
||||
"Read a letter during the Dark Beast Ganon fight.",
|
||||
AchievementCategory::Misc,
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
void* dbgExists = fopAcM_SearchByName(fpcNm_B_MGN_e);
|
||||
if (dbgExists && AchievementSystem::get().hasSignal("open_letter")) {
|
||||
a.progress = 1;
|
||||
}
|
||||
},
|
||||
{}
|
||||
},
|
||||
{
|
||||
{
|
||||
"heavy-hitter",
|
||||
"Heavy Hitter",
|
||||
"Wear the Iron Boots during the end credits.",
|
||||
AchievementCategory::Misc,
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
|
||||
if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) {
|
||||
return;
|
||||
}
|
||||
if (daPy_getPlayerActorClass()->checkEquipHeavyBoots()) {
|
||||
a.progress = 1;
|
||||
}
|
||||
},
|
||||
{}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -426,6 +524,26 @@ void AchievementSystem::clearAll() {
|
||||
save();
|
||||
}
|
||||
|
||||
void AchievementSystem::signal(const char* key) {
|
||||
m_signals.insert(key);
|
||||
}
|
||||
|
||||
bool AchievementSystem::hasSignal(const char* key) const {
|
||||
return m_signals.count(key) > 0;
|
||||
}
|
||||
|
||||
void AchievementSystem::clearOne(const char* key) {
|
||||
for (auto& e : m_entries) {
|
||||
if (std::string(e.achievement.key) == key) {
|
||||
e.achievement.progress = 0;
|
||||
e.achievement.unlocked = false;
|
||||
e.extra = {};
|
||||
break;
|
||||
}
|
||||
}
|
||||
save();
|
||||
}
|
||||
|
||||
void AchievementSystem::processEntry(Entry& e) {
|
||||
if (e.achievement.unlocked) {
|
||||
return;
|
||||
@@ -458,6 +576,7 @@ void AchievementSystem::tick() {
|
||||
for (auto& e : m_entries) {
|
||||
processEntry(e);
|
||||
}
|
||||
m_signals.clear();
|
||||
if (m_dirty) {
|
||||
save();
|
||||
m_dirty = false;
|
||||
|
||||
@@ -76,8 +76,8 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(640, 200), ImVec2(800, 900));
|
||||
ImGui::SetNextWindowSize(ImVec2(640, 480), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(800, 200), ImVec2(1280, 900));
|
||||
ImGui::SetNextWindowSize(ImVec2(800, 480), ImGuiCond_FirstUseEver);
|
||||
|
||||
if (!ImGui::Begin(
|
||||
"Achievements", &open,
|
||||
@@ -111,6 +111,7 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
{AchievementCategory::Collection, "Collection", ImVec4(0.3f, 0.85f, 0.4f, 1.0f)},
|
||||
{AchievementCategory::Challenge, "Challenge", ImVec4(1.0f, 0.65f, 0.15f, 1.0f)},
|
||||
{AchievementCategory::Minigame, "Minigame", ImVec4(0.5f, 0.85f, 1.0f, 1.0f)},
|
||||
{AchievementCategory::Misc, "Misc", ImVec4(0.65f, 0.65f, 0.65f, 1.0f)},
|
||||
{AchievementCategory::Glitched, "Glitched", ImVec4(0.75f, 0.4f, 1.0f, 1.0f)},
|
||||
};
|
||||
|
||||
@@ -131,7 +132,7 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string tabLabel = fmt::format("{} ({}/{})", catInfo.label, catUnlocked, catTotal);
|
||||
const std::string tabLabel = fmt::format("{} ({}/{})###{}", catInfo.label, catUnlocked, catTotal, catInfo.label);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, catInfo.color);
|
||||
const bool tabOpen = ImGui::BeginTabItem(tabLabel.c_str());
|
||||
@@ -152,6 +153,7 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
continue;
|
||||
}
|
||||
ImGui::PushID(a.key);
|
||||
ImGui::BeginGroup();
|
||||
|
||||
ImGui::PushStyleColor(
|
||||
ImGuiCol_Text,
|
||||
@@ -190,6 +192,21 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
|
||||
ImGui::OpenPopup("##ctx");
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("##ctx")) {
|
||||
ImGui::TextDisabled("%s", a.name);
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("Clear Achievement")) {
|
||||
AchievementSystem::get().clearOne(a.key);
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
#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
|
||||
@@ -401,7 +401,6 @@ namespace dusk {
|
||||
m_menuTools.ShowAudioDebug();
|
||||
m_menuTools.ShowSaveEditor();
|
||||
m_menuTools.ShowStateShare();
|
||||
m_menuTools.ShowActorSpawner();
|
||||
}
|
||||
m_menuTools.ShowAchievements();
|
||||
DuskDebugPad(); // temporary, remove later
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "JSystem/JFramework/JFWSystem.h"
|
||||
#include "JSystem/JKernel/JKRExpHeap.h"
|
||||
#include "JSystem/JKernel/JKRHeap.h"
|
||||
#include "JSystem/JKernel/JKRSolidHeap.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "imgui.h"
|
||||
|
||||
@@ -179,11 +178,11 @@ namespace dusk {
|
||||
}
|
||||
|
||||
void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open) {
|
||||
const char* heapName = data.Safe ? heap->getName() : "INVALID";
|
||||
char title[128];
|
||||
snprintf(title, sizeof(title), "Heap %s##%p", heapName, static_cast<const void*>(heap));
|
||||
const char* name = data.Safe ? heap->getName() : "INVALID";
|
||||
snprintf(title, sizeof(title), "Heap %s##%p", heap->getName(), static_cast<const void*>(heap));
|
||||
|
||||
if (!ImGui::Begin(title, &open)) {
|
||||
if (!ImGui::Begin(name, &open)) {
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
@@ -201,30 +200,6 @@ namespace dusk {
|
||||
const auto freeSize = BytesToString(heap->getFreeSize());
|
||||
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")) {
|
||||
data.HeapCheckFailed = !heap->check();
|
||||
data.HeapCheckRan = true;
|
||||
|
||||
@@ -119,7 +119,6 @@ namespace dusk {
|
||||
ImGui::MenuItem("Audio Debug", hotkeys::SHOW_AUDIO_DEBUG, &m_showAudioDebug);
|
||||
ImGui::MenuItem("Bloom", nullptr, &m_showBloomWindow);
|
||||
ImGui::MenuItem("Stub Log", nullptr, &m_showStubLog);
|
||||
ImGui::MenuItem("Actor Spawner", nullptr, &m_showActorSpawner);
|
||||
|
||||
if (!dusk::IsGameLaunched) {
|
||||
ImGui::EndDisabled();
|
||||
|
||||
@@ -29,7 +29,6 @@ namespace dusk {
|
||||
void ShowStateShare();
|
||||
void ShowAchievements();
|
||||
void notifyAchievement(std::string name);
|
||||
void ShowActorSpawner();
|
||||
|
||||
private:
|
||||
bool m_showDebugOverlay = false;
|
||||
@@ -72,8 +71,6 @@ namespace dusk {
|
||||
|
||||
bool m_showAchievements = false;
|
||||
ImGuiAchievements m_achievementsWindow;
|
||||
|
||||
bool m_showActorSpawner = false;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
#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
|
||||
@@ -71,7 +71,6 @@
|
||||
#include "dusk/config.hpp"
|
||||
#include "dusk/imgui/ImGuiConsole.hpp"
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/vmem.h"
|
||||
#include "dusk/version.hpp"
|
||||
#include "dusk/discord_presence.hpp"
|
||||
#include "tracy/Tracy.hpp"
|
||||
@@ -552,19 +551,12 @@ int game_main(int argc, char* argv[]) {
|
||||
config.desiredBackend = ResolveDesiredBackend(parsed_arg_options);
|
||||
config.logCallback = &aurora_log_callback;
|
||||
config.logLevel = startupLogLevel;
|
||||
// Child heaps use independent vmem reservations on PC
|
||||
config.mem1Size = DUSK_IF_ELSE(16, 256) * 1024 * 1024;
|
||||
config.mem1Size = 256 * 1024 * 1024;
|
||||
config.mem2Size = 24 * 1024 * 1024;
|
||||
config.allowJoystickBackgroundEvents = true;
|
||||
config.imGuiInitCallback = &aurora_imgui_init_callback;
|
||||
config.allowTextureReplacements = true;
|
||||
config.allowTextureDumps = false;
|
||||
|
||||
#if TARGET_PC
|
||||
dusk::vmem_arena_init();
|
||||
#endif
|
||||
|
||||
|
||||
auroraInfo = aurora_initialize(argc, argv, &config);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user