forked from CaptainDreamcast/prism
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsaveload_dc.cpp
190 lines (161 loc) · 5.93 KB
/
saveload_dc.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#include "prism/saveload.h"
#include <kos.h>
#include <assert.h>
#include "prism/log.h"
#include "prism/compression.h"
static const auto MEM_BLOCK_SIZE = 512;
static maple_device_t* getVMUDeviceOrNull(PrismSaveSlot& tSaveSlot) {
if (tSaveSlot == PrismSaveSlot::AUTOMATIC) {
for (size_t index = 0; index < size_t(PrismSaveSlot::AMOUNT); index++) {
PrismSaveSlot tempSlot = PrismSaveSlot(index);
auto dev = getVMUDeviceOrNull(tempSlot);
if (!dev) continue;
tSaveSlot = tempSlot;
return dev;
}
return NULL;
}
else {
const auto index = int(tSaveSlot);
const auto controllerNumber = index / 2;
const auto deviceNumber = (index % 2) + 1;
auto dev = maple_enum_dev(controllerNumber, deviceNumber);
return (dev && (dev->info.functions & MAPLE_FUNC_MEMCARD)) ? dev : NULL;
}
}
static vmu_pkg_t packVMUPackageHeader(Buffer& tBuffer, const char* tApplicationName, const char* tShortDescription, const char* tLongDescription, const Buffer& tIconDataBuffer, const Buffer& tPaletteBuffer) {
compressBufferZSTD(&tBuffer);
assert(tIconDataBuffer.mLength == 512);
assert(tPaletteBuffer.mLength == 32);
vmu_pkg_t pkg;
strcpy(pkg.app_id, tApplicationName);
strcpy(pkg.desc_short, tShortDescription);
strcpy(pkg.desc_long, tLongDescription);
pkg.icon_cnt = 1;
memcpy(pkg.icon_pal, tPaletteBuffer.mData, tPaletteBuffer.mLength);
pkg.icon_data = (uint8_t*)tIconDataBuffer.mData;
pkg.icon_anim_speed = 0;
pkg.eyecatch_type = VMUPKG_EC_NONE;
pkg.data_len = tBuffer.mLength;
pkg.data = (uint8_t*)tBuffer.mData;
return pkg;
}
static std::string getSaveSlotPath(PrismSaveSlot tSaveSlot) {
assert(int(tSaveSlot) >= 0 && int(tSaveSlot) < int(PrismSaveSlot::AMOUNT));
static const char* SAVE_SLOT_PATHS[] = { "a1", "a2", "b1", "b2", "c1", "c2", "d1", "d2" };
return std::string(SAVE_SLOT_PATHS[int(tSaveSlot)]);
}
void savePrismGameSave(PrismSaveSlot tSaveSlot, const char* tFileName, const Buffer& tBuffer, const char* tApplicationName, const char* tShortDescription, const char* tLongDescription, const Buffer& tIconDataBuffer, const Buffer& tPaletteBuffer) {
auto dev = getVMUDeviceOrNull(tSaveSlot);
if (!dev) {
logErrorFormat("Writing VMU file %s to save slot %d failed, no device found. Aborting.\n", tFileName, int(tSaveSlot));
return;
}
auto bufferCopy = copyBuffer(tBuffer);
auto pkg = packVMUPackageHeader(bufferCopy, tApplicationName, tShortDescription, tLongDescription, tIconDataBuffer, tPaletteBuffer);
uint8* pkg_out;
int pkg_size;
vmu_pkg_build(&pkg, &pkg_out, &pkg_size);
const auto path = ("$/vmu/" + getSaveSlotPath(tSaveSlot) + "/" + tFileName);
if (isFile(path)) {
fileUnlink(path.c_str());
}
auto fileHandler = fileOpen(path.c_str(), O_WRONLY);
if (fileHandler == FILEHND_INVALID) {
logErrorFormat("Error writing VMU file %s. Aborting.\n", path.c_str());
free(pkg_out);
return;
}
fileWrite(fileHandler, pkg_out, pkg_size);
fileClose(fileHandler);
free(pkg_out);
freeBuffer(bufferCopy);
logFormat("Successfully wrote save to path %s", path.c_str());
}
Buffer loadPrismGameSave(PrismSaveSlot tSaveSlot, const char* tFileName) {
auto dev = getVMUDeviceOrNull(tSaveSlot);
if (!dev) {
logErrorFormat("Error loading VMU file %s from save slot %d. Aborting.\n", tFileName, int(tSaveSlot));
return makeBuffer(NULL, 0);
}
const auto path = ("$/vmu/" + getSaveSlotPath(tSaveSlot) + "/" + tFileName);
if (!isFile(path)) {
logErrorFormat("Error loading VMU file %s. Aborting.\n", path.c_str());
return makeBuffer(NULL, 0);
}
auto fileHandler = fileOpen(path.c_str(), O_RDONLY);
if (fileHandler == FILEHND_INVALID) {
logErrorFormat("Error reading VMU file %s. Aborting.\n", path.c_str());
return makeBuffer(NULL, 0);
}
vmu_pkg_t pkg;
vmu_pkg_parse((uint8_t*)fileMemoryMap(fileHandler), &pkg);
auto ret = copyBuffer(makeBuffer((void*)pkg.data, pkg.data_len));
decompressBufferZSTD(&ret);
fileClose(fileHandler);
logFormat("Successfully loaded save from path %s", path.c_str());
return ret;
}
void deletePrismGameSave(PrismSaveSlot tSaveSlot, const char* tFileName) {
const auto dev = getVMUDeviceOrNull(tSaveSlot);
if (!dev) {
return;
}
const auto path = ("$/vmu/" + getSaveSlotPath(tSaveSlot) + "/" + tFileName);
if (isFile(path)) {
fileUnlink(path.c_str());
}
}
int isPrismSaveSlotActive(PrismSaveSlot tSaveSlot) {
const auto dev = getVMUDeviceOrNull(tSaveSlot);
return dev != NULL;
}
int hasPrismGameSave(PrismSaveSlot tSaveSlot, const char* tFileName) {
auto dev = getVMUDeviceOrNull(tSaveSlot);
if (!dev) {
return 0;
}
const auto path = ("$/vmu/" + getSaveSlotPath(tSaveSlot) + "/" + tFileName);
return isFile(path);
}
size_t getAvailableSizeForSaveSlot(PrismSaveSlot tSaveSlot) {
auto dev = getVMUDeviceOrNull(tSaveSlot);
if (!dev) return 0;
return size_t(vmufs_free_blocks(dev) * MEM_BLOCK_SIZE);
}
size_t getPrismGameSaveSize(const Buffer& tBuffer, const char* tApplicationName, const char* tShortDescription, const char* tLongDescription, const Buffer& tIconDataBuffer, const Buffer& tPaletteBuffer) {
auto bufferCopy = copyBuffer(tBuffer);
auto pkg = packVMUPackageHeader(bufferCopy, tApplicationName, tShortDescription, tLongDescription, tIconDataBuffer, tPaletteBuffer);
uint8* pkg_out;
int pkg_size;
vmu_pkg_build(&pkg, &pkg_out, &pkg_size);
free(pkg_out);
freeBuffer(bufferCopy);
return size_t(((pkg_size + MEM_BLOCK_SIZE - 1) / MEM_BLOCK_SIZE) * MEM_BLOCK_SIZE);
}
void setVMUDisplayIcon(void* tBitmap, bool invertOnTheFly)
{
PrismSaveSlot tSaveSlot = PrismSaveSlot::AUTOMATIC;
auto dev = getVMUDeviceOrNull(tSaveSlot);
if (!dev) return;
if (!invertOnTheFly)
{
vmu_draw_lcd(dev, tBitmap);
}
else
{
uint8_t* vmuIcon = (uint8_t*)tBitmap;
std::vector<uint8_t> reversedIcon(192, 0);
for (int y = 0; y < 32; y++)
{
for (int x = 0; x < 48; x++)
{
const auto byteX = x / 8;
const auto bitX = x % 8;
const auto val = (vmuIcon[y * 6 + byteX] >> (7 - bitX)) & 1;
reversedIcon[((31 - y) * 6) + (5 - byteX)] |= (val << bitX);
}
}
vmu_draw_lcd(dev, reversedIcon.data());
}
}