1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-06 06:32:56 +01:00

use SDL_RWops for save games

This commit is contained in:
zsilencer
2015-07-04 22:36:25 -06:00
committed by IntelOrca
parent abe3ff791d
commit b876591543
16 changed files with 229 additions and 207 deletions

View File

@@ -90,11 +90,8 @@ bool Source_Sample::LoadWAV(const char* filename)
{
log_verbose("Source_Sample::LoadWAV(%s)", filename);
utf8 utf8filename[512];
win1252_to_utf8(utf8filename, filename, sizeof(utf8filename));
Unload();
SDL_RWops* rw = SDL_RWFromFile(utf8filename, "rb");
SDL_RWops* rw = platform_sdl_rwfromfile(filename, "rb");
if (rw == NULL) {
log_verbose("Error loading %s", filename);
return false;
@@ -122,11 +119,8 @@ bool Source_Sample::LoadCSS1(const char* filename, unsigned int offset)
{
log_verbose("Source_Sample::LoadCSS1(%s, %d)", filename, offset);
utf8 utf8filename[512];
win1252_to_utf8(utf8filename, filename, sizeof(utf8filename));
Unload();
SDL_RWops* rw = SDL_RWFromFile(utf8filename, "rb");
SDL_RWops* rw = platform_sdl_rwfromfile(filename, "rb");
if (rw == NULL) {
log_verbose("Unable to load %s", filename);
return false;
@@ -854,10 +848,7 @@ void* Mixer_Play_Music(int pathid, int loop, int streaming)
if (streaming) {
const char* filename = get_file_path(pathid);
utf8 utf8filename[512];
win1252_to_utf8(utf8filename, filename, sizeof(utf8filename));
SDL_RWops* rw = SDL_RWFromFile(utf8filename, "rb");
SDL_RWops* rw = platform_sdl_rwfromfile(filename, "rb");
if (rw == NULL) {
return 0;
}

View File

@@ -339,16 +339,16 @@ static int editor_load_landscape_from_sc4(const char *path)
static int editor_read_s6(const char *path)
{
int i, j;
FILE *file;
SDL_RWops* rw;
rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4;
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
log_verbose("loading landscape, %s", path);
file = fopen(path, "rb");
if (file != NULL) {
if (!sawyercoding_validate_checksum(file)) {
fclose(file);
rw = platform_sdl_rwfromfile(path, "rb");
if (rw != NULL) {
if (!sawyercoding_validate_checksum(rw)) {
SDL_RWclose(rw);
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255;
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA;
@@ -357,10 +357,10 @@ static int editor_read_s6(const char *path)
}
// Read first chunk
sawyercoding_read_chunk(file, (uint8*)s6Header);
sawyercoding_read_chunk(rw, (uint8*)s6Header);
if (s6Header->type == S6_TYPE_SCENARIO) {
// Read second chunk
sawyercoding_read_chunk(file, (uint8*)s6Info);
sawyercoding_read_chunk(rw, (uint8*)s6Info);
if (s6Info->var_000 == 255)
s6Info->var_000 = 1;
@@ -374,50 +374,50 @@ static int editor_read_s6(const char *path)
if (s6Header->num_packed_objects > 0) {
j = 0;
for (i = 0; i < s6Header->num_packed_objects; i++)
j += object_load_packed(file);
j += object_load_packed(rw);
if (j > 0)
object_list_load();
}
uint8 load_success = object_read_and_load_entries(file);
uint8 load_success = object_read_and_load_entries(rw);
// Read flags (16 bytes). Loads:
// RCT2_ADDRESS_CURRENT_MONTH_YEAR
// RCT2_ADDRESS_CURRENT_MONTH_TICKS
// RCT2_ADDRESS_SCENARIO_TICKS
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR);
// Read map elements
memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element));
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS);
// Read game data, including sprites
sawyercoding_read_chunk(file, (uint8*)0x010E63B8);
sawyercoding_read_chunk(rw, (uint8*)0x010E63B8);
if (s6Header->type == S6_TYPE_SCENARIO) {
// Read number of guests in park and something else
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK);
// Read ?
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_LAST_GUESTS_IN_PARK);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_LAST_GUESTS_IN_PARK);
// Read park rating
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING);
// Read ?
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES);
// Read ?
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE);
// Read ?
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE);
// Read more game data, including research items and rides
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE);
}
fclose(file);
SDL_RWclose(rw);
if (!load_success){
log_error("failed to load all entries.");
set_load_objects_fail_reason();

View File

@@ -593,32 +593,12 @@ static void load_landscape()
*
* rct2: 0x00675E1B
*/
int game_load_sv6(const char *path)
int game_load_sv6(SDL_RWops* rw)
{
FILE *file;
int i, j;
log_verbose("loading saved game, %s", path);
strcpy((char*)0x0141EF68, path);
strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, path);
strcpy(gScenarioSaveName, path_get_filename(path));
path_remove_extension(gScenarioSaveName);
file = fopen(path, "rb");
if (file == NULL) {
log_error("unable to open %s", path);
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255;
RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA;
return 0;
}
if (!sawyercoding_validate_checksum(file)) {
fclose(file);
log_error("invalid checksum, %s", path);
if (!sawyercoding_validate_checksum(rw)) {
log_error("invalid checksum");
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255;
RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA;
@@ -629,31 +609,29 @@ int game_load_sv6(const char *path)
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
// Read first chunk
sawyercoding_read_chunk(file, (uint8*)s6Header);
sawyercoding_read_chunk(rw, (uint8*)s6Header);
if (s6Header->type == S6_TYPE_SAVEDGAME) {
// Read packed objects
if (s6Header->num_packed_objects > 0) {
j = 0;
for (i = 0; i < s6Header->num_packed_objects; i++)
j += object_load_packed(file);
j += object_load_packed(rw);
if (j > 0)
object_list_load();
}
}
uint8 load_success = object_read_and_load_entries(file);
uint8 load_success = object_read_and_load_entries(rw);
// Read flags (16 bytes)
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR);
// Read map elements
memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element));
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS);
// Read game data, including sprites
sawyercoding_read_chunk(file, (uint8*)0x010E63B8);
fclose(file);
sawyercoding_read_chunk(rw, (uint8*)0x010E63B8);
if (!load_success){
set_load_objects_fail_reason();
@@ -683,12 +661,30 @@ int game_load_save(const char *path)
{
rct_window *mainWindow;
if (!game_load_sv6(path)) {
title_load();
rct2_endupdate();
log_verbose("loading saved game, %s", path);
strcpy((char*)0x0141EF68, path);
strcpy((char*)RCT2_ADDRESS_SAVED_GAMES_PATH_2, path);
strcpy(gScenarioSaveName, path_get_filename(path));
path_remove_extension(gScenarioSaveName);
SDL_RWops* rw = platform_sdl_rwfromfile(path, "rb");
if (rw == NULL) {
log_error("unable to open %s", path);
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255;
RCT2_GLOBAL(RCT2_ADDRESS_GAME_COMMAND_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA;
return 0;
}
if (!game_load_sv6(rw)) {
title_load();
rct2_endupdate();
SDL_RWclose(rw);
return 0;
}
SDL_RWclose(rw);
RCT2_GLOBAL(RCT2_ADDRESS_SCREEN_FLAGS, uint8) = SCREEN_FLAGS_PLAYING;
viewport_init_all();
game_create_windows();
@@ -803,7 +799,7 @@ static int show_save_game_dialog(char *resultPath)
return result;
}
char save_game()
int save_game()
{
window_loadsave_open(LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME, gScenarioSaveName);
return 0;
@@ -818,13 +814,17 @@ char save_game()
// Ensure path has .SV6 extension
path_set_extension(path, ".SV6");
if (scenario_save(path, gConfigGeneral.save_plugin_data ? 1 : 0)) {
game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0);
gfx_invalidate_screen();
return 1;
} else {
return 0;
SDL_RWops* rw = platform_sdl_rwfromfile(path, "wb+");
if (rw != NULL) {
int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 1 : 0);
SDL_RWclose(rw);
if (success) {
game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0);
gfx_invalidate_screen();
return 1;
}
}
return 0;
}
void game_autosave()
@@ -834,7 +834,14 @@ void game_autosave()
platform_get_user_directory(path, "save");
strcat(path, "autosave.sv6");
scenario_save(path, 0x80000000);
strcpy(gScenarioSaveName, path_get_filename(path));
path_remove_extension(gScenarioSaveName);
SDL_RWops* rw = platform_sdl_rwfromfile(path, "wb+");
if (rw != NULL) {
scenario_save(rw, 0x80000000);
SDL_RWclose(rw);
}
}
/**

View File

@@ -22,6 +22,7 @@
#define _GAME_H_
#include "common.h"
#include "platform/platform.h"
enum GAME_COMMAND {
GAME_COMMAND_SET_RIDE_APPEARANCE,
@@ -107,11 +108,11 @@ void game_increase_game_speed();
void game_reduce_game_speed();
void game_load_or_quit_no_save_prompt();
int game_load_sv6(const char *path);
int game_load_sv6(SDL_RWops* rw);
int game_load_save(const char *path);
void game_pause_toggle(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp);
void pause_toggle();
char save_game();
int save_game();
void rct2_exit();
void rct2_exit_reason(rct_string_id title, rct_string_id body);
void game_autosave();

View File

@@ -55,19 +55,19 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi
uint8 objectType;
rct_object_entry openedEntry;
char path[260];
FILE *file;
SDL_RWops* rw;
subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), (char*)installedObject + 16);
log_verbose("loading object, %s", path);
file = fopen(path, "rb");
if (file == NULL)
rw = platform_sdl_rwfromfile(path, "rb");
if (rw == NULL)
return 0;
fread(&openedEntry, sizeof(rct_object_entry), 1, file);
SDL_RWread(rw, &openedEntry, sizeof(rct_object_entry), 1);
if (!object_entry_compare(&openedEntry, entry)) {
fclose(file);
SDL_RWclose(rw);
return 0;
}
@@ -82,14 +82,14 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi
if (*chunkSize == 0xFFFFFFFF) {
chunk = rct2_malloc(0x600000);
*chunkSize = sawyercoding_read_chunk(file, chunk);
*chunkSize = sawyercoding_read_chunk(rw, chunk);
chunk = rct2_realloc(chunk, *chunkSize);
}
else {
chunk = rct2_malloc(*chunkSize);
*chunkSize = sawyercoding_read_chunk(file, chunk);
*chunkSize = sawyercoding_read_chunk(rw, chunk);
}
fclose(file);
SDL_RWclose(rw);
@@ -177,7 +177,7 @@ int object_load(int groupIndex, rct_object_entry *entry, int* chunkSize)
* ebx : file
* ebp : entry
*/
int write_object_file(FILE *file, rct_object_entry* entry){
int write_object_file(SDL_RWops *rw, rct_object_entry* entry){
uint8 entryGroupIndex = 0, type = 0;
uint8* chunk = 0;
@@ -201,7 +201,7 @@ int write_object_file(FILE *file, rct_object_entry* entry){
chunkHeader.length = installed_entry->chunk_size;
size_dst += sawyercoding_write_chunk_buffer(dst_buffer + sizeof(rct_object_entry), chunk, chunkHeader);
fwrite(dst_buffer, 1, size_dst, file);
SDL_RWwrite(rw, dst_buffer, 1, size_dst);
free(dst_buffer);
return 1;
@@ -211,16 +211,16 @@ int write_object_file(FILE *file, rct_object_entry* entry){
*
* rct2: 0x006AA2B7
*/
int object_load_packed(FILE *file)
int object_load_packed(SDL_RWops* rw)
{
object_unload_all();
rct_object_entry entry;
fread(&entry, 16, 1, file);
SDL_RWread(rw, &entry, 16, 1);
uint8* chunk = rct2_malloc(0x600000);
uint32 chunkSize = sawyercoding_read_chunk(file, chunk);
uint32 chunkSize = sawyercoding_read_chunk(rw, chunk);
chunk = rct2_realloc(chunk, chunkSize);
if (chunk == NULL){
@@ -315,11 +315,11 @@ int object_load_packed(FILE *file)
}
// Actually write the object to the file
FILE* obj_file = fopen(path, "wb");
if (obj_file){
uint8 result = write_object_file(obj_file, &entry);
SDL_RWops* rw_out = platform_sdl_rwfromfile(path, "wb");
if (rw_out != NULL){
uint8 result = write_object_file(rw_out, &entry);
fclose(obj_file);
SDL_RWclose(rw_out);
object_unload_all();
return result;
@@ -1514,9 +1514,9 @@ int object_get_scenario_text(rct_object_entry *entry)
subsitute_path(path, RCT2_ADDRESS(RCT2_ADDRESS_OBJECT_DATA_PATH, char), objectPath);
rct_object_entry openedEntry;
FILE *file = fopen(path, "rb");
if (file != NULL) {
fread(&openedEntry, sizeof(rct_object_entry), 1, file);
SDL_RWops* rw = platform_sdl_rwfromfile(path, "rb");
if (rw != NULL) {
SDL_RWread(rw, &openedEntry, sizeof(rct_object_entry), 1);
if (object_entry_compare(&openedEntry, entry)) {
// Skip over the object entry
@@ -1530,14 +1530,14 @@ int object_get_scenario_text(rct_object_entry *entry)
char *chunk;
if (chunkSize == 0xFFFFFFFF) {
chunk = malloc(0x600000);
chunkSize = sawyercoding_read_chunk(file, chunk);
chunkSize = sawyercoding_read_chunk(rw, chunk);
chunk = realloc(chunk, chunkSize);
}
else {
chunk = malloc(chunkSize);
sawyercoding_read_chunk(file, chunk);
sawyercoding_read_chunk(rw, chunk);
}
fclose(file);
SDL_RWclose(rw);
// Calculate and check checksum
if (object_calculate_checksum(&openedEntry, chunk, chunkSize) != openedEntry.checksum) {
@@ -1578,7 +1578,7 @@ int object_get_scenario_text(rct_object_entry *entry)
return 1;
}
log_error("Opened object didn't match.");
fclose(file);
SDL_RWclose(rw);
return 0;
}
log_error("File failed to open.");

View File

@@ -22,6 +22,7 @@
#define _OBJECT_H_
#include "common.h"
#include "platform/platform.h"
// First 0xF of rct_object_entry->flags
typedef enum{
@@ -94,8 +95,8 @@ extern rct_object_entry_group object_entry_groups[];
int object_load_entry(const char *path, rct_object_entry *outEntry);
void object_list_load();
void set_load_objects_fail_reason();
int object_read_and_load_entries(FILE *file);
int object_load_packed(FILE *file);
int object_read_and_load_entries(SDL_RWops* rw);
int object_load_packed(SDL_RWops* rw);
void object_unload_all();
int check_object_entry(rct_object_entry *entry);
@@ -109,7 +110,7 @@ int object_entry_compare(const rct_object_entry *a, const rct_object_entry *b);
int object_calculate_checksum(const rct_object_entry *entry, const char *data, int dataLength);
int object_paint(int type, int eax, int ebx, int ecx, int edx, int esi, int edi, int ebp);
rct_object_entry *object_get_next(rct_object_entry *entry);
int write_object_file(FILE *file, rct_object_entry* entry);
int write_object_file(SDL_RWops* rw, rct_object_entry* entry);
void reset_loaded_objects();
int find_object_in_entry_group(rct_object_entry* entry, uint8* entry_type, uint8* entry_index);
void object_create_identifier_name(uint8* string_buffer, rct_object_entry* object);

View File

@@ -518,7 +518,7 @@ void set_load_objects_fail_reason(){
*
* rct2: 0x006AA0C6
*/
int object_read_and_load_entries(FILE *file)
int object_read_and_load_entries(SDL_RWops* rw)
{
object_unload_all();
@@ -529,7 +529,7 @@ int object_read_and_load_entries(FILE *file)
// Read all the object entries
entries = malloc(OBJECT_ENTRY_COUNT * sizeof(rct_object_entry));
sawyercoding_read_chunk(file, (uint8*)entries);
sawyercoding_read_chunk(rw, (uint8*)entries);
uint8 load_fail = 0;
// Load each object

View File

@@ -82,6 +82,7 @@ void platform_process_messages();
int platform_scancode_to_rct_keycode(int sdl_key);
void platform_start_text_input(char* buffer, int max_length);
void platform_stop_text_input();
SDL_RWops* platform_sdl_rwfromfile(const char* filename, const char* mode);
// Platform specific definitions
char platform_get_path_separator();

View File

@@ -28,6 +28,7 @@
#include "../interface/keyboard_shortcut.h"
#include "../interface/window.h"
#include "../input.h"
#include "../localisation/localisation.h"
#include "../openrct2.h"
#include "platform.h"
@@ -605,6 +606,13 @@ void platform_stop_text_input()
gTextInput = NULL;
}
SDL_RWops* platform_sdl_rwfromfile(const char* filename, const char* mode)
{
utf8 utf8filename[512];
win1252_to_utf8(utf8filename, filename, sizeof(utf8filename));
return SDL_RWFromFile(utf8filename, mode);
}
static void platform_unload_cursors()
{
for (int i = 0; i < CURSOR_COUNT; i++)

View File

@@ -58,18 +58,18 @@ static void scenario_objective_check();
*/
int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *info)
{
FILE *file;
SDL_RWops* rw;
log_verbose("loading scenario details, %s", path);
file = fopen(path, "rb");
if (file != NULL) {
rw = platform_sdl_rwfromfile(path, "rb");
if (rw != NULL) {
// Read first chunk
sawyercoding_read_chunk(file, (uint8*)header);
sawyercoding_read_chunk(rw, (uint8*)header);
if (header->type == S6_TYPE_SCENARIO) {
// Read second chunk
sawyercoding_read_chunk(file, (uint8*)info);
fclose(file);
sawyercoding_read_chunk(rw, (uint8*)info);
SDL_RWclose(rw);
RCT2_GLOBAL(0x009AA00C, uint8) = 0;
// Checks for a scenario string object (possibly for localisation)
@@ -84,7 +84,7 @@ int scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *in
}
return 1;
}
fclose(file);
SDL_RWclose(rw);
}
log_error("invalid scenario, %s", path);
@@ -102,15 +102,15 @@ int scenario_load(const char *path)
{
log_verbose("loading scenario, %s", path);
FILE *file;
SDL_RWops* rw;
int i, j;
rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4;
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
file = fopen(path, "rb");
if (file != NULL) {
if (!sawyercoding_validate_checksum(file)) {
fclose(file);
rw = platform_sdl_rwfromfile(path, "rb");
if (rw != NULL) {
if (!sawyercoding_validate_checksum(rw)) {
SDL_RWclose(rw);
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_TYPE, uint8) = 255;
RCT2_GLOBAL(RCT2_ADDRESS_ERROR_STRING_ID, uint16) = STR_FILE_CONTAINS_INVALID_DATA;
@@ -119,57 +119,57 @@ int scenario_load(const char *path)
}
// Read first chunk
sawyercoding_read_chunk(file, (uint8*)s6Header);
sawyercoding_read_chunk(rw, (uint8*)s6Header);
if (s6Header->type == S6_TYPE_SCENARIO) {
// Read second chunk
sawyercoding_read_chunk(file, (uint8*)s6Info);
sawyercoding_read_chunk(rw, (uint8*)s6Info);
// Read packed objects
if (s6Header->num_packed_objects > 0) {
j = 0;
for (i = 0; i < s6Header->num_packed_objects; i++)
j += object_load_packed(file);
j += object_load_packed(rw);
if (j > 0)
object_list_load();
}
uint8 load_success = object_read_and_load_entries(file);
uint8 load_success = object_read_and_load_entries(rw);
// Read flags (16 bytes). Loads:
// RCT2_ADDRESS_CURRENT_MONTH_YEAR
// RCT2_ADDRESS_CURRENT_MONTH_TICKS
// RCT2_ADDRESS_SCENARIO_TICKS
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR);
// Read map elements
memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element));
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS);
// Read game data, including sprites
sawyercoding_read_chunk(file, (uint8*)0x010E63B8);
sawyercoding_read_chunk(rw, (uint8*)0x010E63B8);
// Read number of guests in park and something else
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK);
// Read ?
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_LAST_GUESTS_IN_PARK);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_LAST_GUESTS_IN_PARK);
// Read park rating
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING);
// Read ?
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES);
// Read ?
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE);
// Read ?
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE);
// Read more game data, including research items and rides
sawyercoding_read_chunk(file, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE);
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE);
fclose(file);
SDL_RWclose(rw);
if (!load_success){
log_error("failed to load all entries.");
set_load_objects_fail_reason();
@@ -183,7 +183,7 @@ int scenario_load(const char *path)
return 1;
}
fclose(file);
SDL_RWclose(rw);
}
log_error("failed to find scenario file.");
@@ -745,7 +745,7 @@ int scenario_get_num_packed_objects_to_write()
*
* rct2: 0x006AA26E
*/
int scenario_write_packed_objects(FILE *file)
int scenario_write_packed_objects(SDL_RWops* rw)
{
int i;
rct_object_entry_extended *entry = (rct_object_entry_extended*)0x00F3F03C;
@@ -753,7 +753,7 @@ int scenario_write_packed_objects(FILE *file)
if (RCT2_ADDRESS(0x009ACFA4, uint32)[i] == 0xFFFFFFFF || (entry->flags & 0xF0))
continue;
if (!write_object_file(file, (rct_object_entry*)entry))
if (!write_object_file(rw, (rct_object_entry*)entry))
return 0;
}
@@ -878,21 +878,16 @@ static scenario_fix_ghosts(rct_s6_data *s6)
* rct2: 0x006754F5
* @param flags bit 0: pack objects, 1: save as scenario
*/
int scenario_save(char *path, int flags)
int scenario_save(SDL_RWops* rw, int flags)
{
rct_window *w;
rct_viewport *viewport;
int viewX, viewY, viewZoom, viewRotation;
if (strcmp(path_get_filename(path), "autosave.sv6")) {
strcpy(gScenarioSaveName, path_get_filename(path));
path_remove_extension(gScenarioSaveName);
}
if (flags & 2)
log_verbose("saving scenario, %s", path);
log_verbose("saving scenario");
else
log_verbose("saving game, %s", path);
log_verbose("saving game");
if (!(flags & 0x80000000))
@@ -949,7 +944,7 @@ int scenario_save(char *path, int flags)
memcpy(&s6->dword_010E63B8, (void*)0x010E63B8, 0x2E8570);
scenario_fix_ghosts(s6);
scenario_save_s6(path, s6);
scenario_save_s6(rw, s6);
free(s6);
@@ -961,25 +956,17 @@ int scenario_save(char *path, int flags)
return 1;
}
bool scenario_save_s6(char *path, rct_s6_data *s6)
bool scenario_save_s6(SDL_RWops* rw, rct_s6_data *s6)
{
FILE *file;
char *buffer;
sawyercoding_chunk_header chunkHeader;
int encodedLength;
long fileSize;
uint32 checksum;
file = fopen(path, "wb+");
if (file == NULL) {
log_error("Unable to write to %s", path);
return false;
}
buffer = malloc(0x600000);
if (buffer == NULL) {
log_error("Unable to allocate enough space for a write buffer.");
fclose(file);
return false;
}
@@ -987,21 +974,20 @@ bool scenario_save_s6(char *path, rct_s6_data *s6)
chunkHeader.encoding = CHUNK_ENCODING_ROTATE;
chunkHeader.length = sizeof(rct_s6_header);
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->header, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
// 1: Write scenario info chunk
if (s6->header.type == S6_TYPE_SCENARIO) {
chunkHeader.encoding = CHUNK_ENCODING_ROTATE;
chunkHeader.length = sizeof(rct_s6_info);
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->info, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
}
// 2: Write packed objects
if (s6->header.num_packed_objects > 0) {
if (!scenario_write_packed_objects(file)) {
if (!scenario_write_packed_objects(rw)) {
free(buffer);
fclose(file);
return false;
}
}
@@ -1010,92 +996,91 @@ bool scenario_save_s6(char *path, rct_s6_data *s6)
chunkHeader.encoding = CHUNK_ENCODING_ROTATE;
chunkHeader.length = 721 * sizeof(rct_object_entry);
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)s6->objects, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
// 4: Misc fields (data, rand...) chunk
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
chunkHeader.length = 16;
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->elapsed_months, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
// 5: Map elements + sprites and other fields chunk
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
chunkHeader.length = 0x180000;
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)s6->map_elements, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
if (s6->header.type == S6_TYPE_SCENARIO) {
// 6:
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
chunkHeader.length = 0x27104C;
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->dword_010E63B8, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
// 7:
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
chunkHeader.length = 4;
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->guests_in_park, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
// 8:
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
chunkHeader.length = 8;
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->last_guests_in_park, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
// 9:
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
chunkHeader.length = 2;
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->park_rating, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
// 10:
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
chunkHeader.length = 1082;
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->active_research_types, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
// 11:
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
chunkHeader.length = 16;
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->current_expenditure, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
// 12:
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
chunkHeader.length = 4;
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->park_value, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
// 13:
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
chunkHeader.length = 0x761E8;
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->completed_company_value, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
} else {
// 6: Everything else...
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
chunkHeader.length = 0x2E8570;
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->dword_010E63B8, chunkHeader);
fwrite(buffer, encodedLength, 1, file);
SDL_RWwrite(rw, buffer, encodedLength, 1);
}
free(buffer);
// Determine number of bytes written
fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
fileSize = (long)SDL_RWtell(rw);
SDL_RWseek(rw, 0, RW_SEEK_SET);
// Read all written bytes back into a single buffer
buffer = malloc(fileSize);
fread(buffer, fileSize, 1, file);
SDL_RWread(rw, buffer, fileSize, 1);
checksum = sawyercoding_calculate_checksum(buffer, fileSize);
free(buffer);
// Append the checksum
fseek(file, fileSize, SEEK_SET);
fwrite(&checksum, sizeof(uint32), 1, file);
fclose(file);
SDL_RWseek(rw, fileSize, RW_SEEK_SET);
SDL_RWwrite(rw, &checksum, sizeof(uint32), 1);
return true;
}

View File

@@ -425,8 +425,8 @@ void scenario_update();
unsigned int scenario_rand();
unsigned int scenario_rand_max(unsigned int max);
int scenario_prepare_for_save();
int scenario_save(char *path, int flags);
bool scenario_save_s6(char *path, rct_s6_data *s6);
int scenario_save(SDL_RWops* rw, int flags);
bool scenario_save_s6(SDL_RWops* rw, rct_s6_data *s6);
void scenario_set_filename(const char *value);
void scenario_failure();
void scenario_success();

View File

@@ -168,9 +168,15 @@ static int title_load_park(const char *path)
rct_window* w;
int successfulLoad;
successfulLoad = _strcmpi(path_get_extension(path), ".sv6") == 0 ?
game_load_sv6(path) :
scenario_load(path);
if (_strcmpi(path_get_extension(path), ".sv6") == 0) {
SDL_RWops* rw = platform_sdl_rwfromfile(path, "rb");
if (rw != NULL) {
successfulLoad = game_load_sv6(rw);
SDL_RWclose(rw);
}
} else {
successfulLoad = scenario_load(path);
}
if (!successfulLoad)
return 0;

View File

@@ -19,6 +19,7 @@
*****************************************************************************/
#include "../addresses.h"
#include "../platform/platform.h"
#include "sawyercoding.h"
static int decode_chunk_rle(uint8* src_buffer, uint8* dst_buffer, int length);
@@ -42,24 +43,24 @@ uint32 sawyercoding_calculate_checksum(uint8* buffer, uint32 length)
*
* rct2: 0x00676FD2
*/
int sawyercoding_validate_checksum(FILE *file)
int sawyercoding_validate_checksum(SDL_RWops* rw)
{
uint32 i, checksum, fileChecksum, dataSize, bufferSize;
uint8 buffer[1024];
// Get data size
fseek(file, 0, SEEK_END);
dataSize = ftell(file);
SDL_RWseek(rw, 0, RW_SEEK_END);
dataSize = (uint32)SDL_RWtell(rw);
if (dataSize < 8)
return 0;
dataSize -= 4;
// Calculate checksum
fseek(file, 0, SEEK_SET);
SDL_RWseek(rw, 0, RW_SEEK_SET);
checksum = 0;
do {
bufferSize = min(dataSize, 1024);
if (fread(buffer, bufferSize, 1, file) != 1)
if (SDL_RWread(rw, buffer, bufferSize, 1) != 1)
return 0;
for (i = 0; i < bufferSize; i++)
@@ -68,11 +69,11 @@ int sawyercoding_validate_checksum(FILE *file)
} while (dataSize != 0);
// Read file checksum
if (fread(&fileChecksum, sizeof(fileChecksum), 1, file) != 1)
if (SDL_RWread(rw, &fileChecksum, sizeof(fileChecksum), 1) != 1)
return 0;
// Reset file position
fseek(file, 0, SEEK_SET);
SDL_RWseek(rw, 0, RW_SEEK_SET);
// Validate
return checksum == fileChecksum;
@@ -83,12 +84,12 @@ int sawyercoding_validate_checksum(FILE *file)
* rct2: 0x0067685F
* buffer (esi)
*/
int sawyercoding_read_chunk(FILE *file, uint8 *buffer)
int sawyercoding_read_chunk(SDL_RWops* rw, uint8 *buffer)
{
sawyercoding_chunk_header chunkHeader;
// Read chunk header
if (fread(&chunkHeader, sizeof(sawyercoding_chunk_header), 1, file) != 1) {
if (SDL_RWread(rw, &chunkHeader, sizeof(sawyercoding_chunk_header), 1) != 1) {
log_error("Unable to read chunk header!");
return -1;
}
@@ -96,7 +97,7 @@ int sawyercoding_read_chunk(FILE *file, uint8 *buffer)
uint8* src_buffer = malloc(chunkHeader.length);
// Read chunk data
if (fread(src_buffer, chunkHeader.length, 1, file) != 1) {
if (SDL_RWread(rw, src_buffer, chunkHeader.length, 1) != 1) {
free(src_buffer);
log_error("Unable to read chunk data!");
return -1;

View File

@@ -47,9 +47,9 @@ enum {
FILE_TYPE_SC4 = (2 << 2)
};
int sawyercoding_validate_checksum(FILE *file);
int sawyercoding_validate_checksum(SDL_RWops* rw);
uint32 sawyercoding_calculate_checksum(uint8* buffer, uint32 length);
int sawyercoding_read_chunk(FILE *file, uint8 *buffer);
int sawyercoding_read_chunk(SDL_RWops* rw, uint8 *buffer);
int sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader);
int sawyercoding_decode_sv4(char *src, char *dst, int length);
int sawyercoding_decode_sc4(char *src, char *dst, int length);

View File

@@ -377,7 +377,11 @@ void window_editor_bottom_toolbar_jump_forward_to_save_scenario()
// Save the scenario
parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32);
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18;
success = scenario_save(path, gConfigGeneral.save_plugin_data ? 3 : 2);
SDL_RWops* rw = platform_sdl_rwfromfile(path, "wb+");
if (rw != NULL) {
success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2);
SDL_RWclose(rw);
}
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup;
if (success) {

View File

@@ -724,6 +724,7 @@ static void window_loadsave_populate_list(int includeNewItem, bool browsable, co
static void window_loadsave_select(rct_window *w, const char *path)
{
SDL_RWops* rw;
switch (_loadsaveType) {
case (LOADSAVETYPE_LOAD | LOADSAVETYPE_GAME) :
if (gLoadSaveTitleSequenceSave) {
@@ -752,13 +753,19 @@ static void window_loadsave_select(rct_window *w, const char *path)
}
break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_GAME) :
if (scenario_save((char*)path, gConfigGeneral.save_plugin_data ? 1 : 0)) {
window_close(w);
rw = platform_sdl_rwfromfile(path, "wb+");
if (rw != NULL) {
int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 1 : 0);
SDL_RWclose(rw);
if (success) {
window_close(w);
game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0);
gfx_invalidate_screen();
}
else {
game_do_command(0, 1047, 0, -1, GAME_COMMAND_SET_RIDE_APPEARANCE, 0, 0);
gfx_invalidate_screen();
} else {
window_error_open(STR_SAVE_GAME, 1047);
}
} else {
window_error_open(STR_SAVE_GAME, 1047);
}
break;
@@ -774,11 +781,17 @@ static void window_loadsave_select(rct_window *w, const char *path)
}
break;
case (LOADSAVETYPE_SAVE | LOADSAVETYPE_LANDSCAPE) :
if (scenario_save((char*)path, gConfigGeneral.save_plugin_data ? 3 : 2)) {
window_close(w);
gfx_invalidate_screen();
}
else {
rw = platform_sdl_rwfromfile(path, "wb+");
if (rw != NULL) {
int success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2);
SDL_RWclose(rw);
if (success) {
window_close(w);
gfx_invalidate_screen();
} else {
window_error_open(STR_SAVE_LANDSCAPE, 1049);
}
} else {
window_error_open(STR_SAVE_LANDSCAPE, 1049);
}
break;
@@ -788,14 +801,18 @@ static void window_loadsave_select(rct_window *w, const char *path)
int parkFlagsBackup = RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32);
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) &= ~PARK_FLAGS_18;
s6Info->var_000 = 255;
int success = scenario_save((char*)path, gConfigGeneral.save_plugin_data ? 3 : 2);
rw = platform_sdl_rwfromfile(path, "wb+");
int success = 0;
if (rw != NULL) {
success = scenario_save(rw, gConfigGeneral.save_plugin_data ? 3 : 2);
SDL_RWclose(rw);
}
RCT2_GLOBAL(RCT2_ADDRESS_PARK_FLAGS, uint32) = parkFlagsBackup;
if (success) {
window_close(w);
title_load();
}
else {
} else {
window_error_open(STR_SAVE_SCENARIO, STR_SCENARIO_SAVE_FAILED);
s6Info->var_000 = 4;
}