From ad70dbb84cc356165478f2467342c52ce9ffd382 Mon Sep 17 00:00:00 2001 From: zsilencer Date: Fri, 31 Jul 2015 08:14:44 -0600 Subject: [PATCH] map load on join --- src/game.c | 59 ++++++++++++++++++++++++++++++++++-- src/game.h | 1 + src/network/network.cpp | 13 +++++--- src/network/network.h | 2 +- src/scenario.c | 66 +++++++++++++++++++++++++++++++++++++++++ src/scenario.h | 1 + 6 files changed, 135 insertions(+), 7 deletions(-) diff --git a/src/game.c b/src/game.c index ded5d1dc6d..6a497edfa9 100644 --- a/src/game.c +++ b/src/game.c @@ -780,6 +780,63 @@ int game_load_sv6(SDL_RWops* rw) return 1; } +// Load game state for multiplayer +int game_load_network(SDL_RWops* rw) +{ + int i, j; + + rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4; + rct_s6_info *s6Info = (rct_s6_info*)0x0141F570; + + // Read first chunk + 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(rw); + if (j > 0) + object_list_load(); + } + } + + uint8 load_success = object_read_and_load_entries(rw); + + // Read flags (16 bytes) + 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(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS); + + // Read game data, including sprites + sawyercoding_read_chunk(rw, (uint8*)0x010E63B8); + + // Read checksum + uint32 checksum; + SDL_RWread(rw, &checksum, sizeof(uint32), 1); + + if (!load_success){ + set_load_objects_fail_reason(); + if (RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) & INPUT_FLAG_5){ + RCT2_GLOBAL(0x14241BC, uint32) = 2; + //call 0x0040705E Sets cursor position and something else. Calls maybe wind func 8 probably pointless + RCT2_GLOBAL(0x14241BC, uint32) = 0; + RCT2_GLOBAL(RCT2_ADDRESS_INPUT_FLAGS, uint32) &= ~INPUT_FLAG_5; + } + + return 0;//This never gets called + } + + // The rest is the same as in scenario load and play + reset_loaded_objects(); + map_update_tile_pointers(); + reset_0x69EBE4(); + openrct2_reset_object_tween_locations(); + return 1; +} + /** * * rct2: 0x00675E1B @@ -860,8 +917,6 @@ void game_load_init() gGameSpeed = 1; scenario_set_filename((char*)0x0135936C); - - RCT2_GLOBAL(0x01388698, uint16) = 0; } /* diff --git a/src/game.h b/src/game.h index dd0d2d9bc3..be95fcd879 100644 --- a/src/game.h +++ b/src/game.h @@ -127,6 +127,7 @@ void game_reduce_game_speed(); void game_load_or_quit_no_save_prompt(); int game_load_sv6(SDL_RWops* rw); +int game_load_network(SDL_RWops* rw); int game_load_save(const char *path); void game_load_init(); void game_pause_toggle(int *eax, int *ebx, int *ecx, int *edx, int *esi, int *edi, int *ebp); diff --git a/src/network/network.cpp b/src/network/network.cpp index 1df19ad80b..25eea2fcc8 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -492,12 +492,12 @@ void Network::Client_Send_AUTH(const char* gameversion, const char* name, const server_connection.QueuePacket(std::move(packet)); } -void Network::Server_Send_MAP() +void Network::Server_Send_MAP(NetworkConnection* connection) { int buffersize = 0x600000; std::vector buffer(buffersize); SDL_RWops* rw = SDL_RWFromMem(&buffer[0], buffersize); - scenario_save(rw, 0); + scenario_save_network(rw); int size = (int)SDL_RWtell(rw); int chunksize = 1000; for (int i = 0; i < size; i += chunksize) { @@ -505,7 +505,11 @@ void Network::Server_Send_MAP() std::unique_ptr packet = std::move(NetworkPacket::Allocate()); *packet << (uint32)NETWORK_COMMAND_MAP << (uint32)size << (uint32)i; packet->Write(&buffer[i], datasize); - SendPacketToClients(*packet); + if (connection) { + connection->QueuePacket(std::move(packet)); + } else { + SendPacketToClients(*packet); + } } SDL_RWclose(rw); } @@ -744,6 +748,7 @@ int Network::Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& pa sprintf(&text[2], "%s has joined the game", player->name); chat_history_add(text); gNetwork.Server_Send_CHAT(text); + Server_Send_MAP(&connection); } } std::unique_ptr responsepacket = std::move(NetworkPacket::Allocate()); @@ -774,7 +779,7 @@ int Network::Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& pac memcpy(&chunk_buffer[offset], (void*)packet.Read(chunksize), chunksize); if (offset + chunksize == size) { SDL_RWops* rw = SDL_RWFromMem(&chunk_buffer[0], size); - if (game_load_sv6(rw)) { + if (game_load_network(rw)) { game_load_init(); if (RCT2_GLOBAL(RCT2_ADDRESS_GAME_PAUSED, uint8) & 1) pause_toggle(); diff --git a/src/network/network.h b/src/network/network.h index 392e8ecff1..121ddf5b24 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -138,7 +138,7 @@ public: bool CheckSRAND(uint32 tick, uint32 srand0); void Client_Send_AUTH(const char* gameversion, const char* name, const char* password); - void Server_Send_MAP(); + void Server_Send_MAP(NetworkConnection* connection = nullptr); void Client_Send_CHAT(const char* text); void Server_Send_CHAT(const char* text); void Client_Send_GAMECMD(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 callback); diff --git a/src/scenario.c b/src/scenario.c index 9ecb98e4a3..52c072b186 100644 --- a/src/scenario.c +++ b/src/scenario.c @@ -979,6 +979,72 @@ int scenario_save(SDL_RWops* rw, int flags) return 1; } +// Save game state without modifying any of the state for multiplayer +int scenario_save_network(SDL_RWops* rw) +{ + rct_window *w; + rct_viewport *viewport; + int viewX, viewY, viewZoom, viewRotation; + + /*map_reorganise_elements(); + reset_0x69EBE4(); + sprite_clear_all_unused(); + sub_677552(); + sub_674BCF();*/ + + // Set saved view + w = window_get_main(); + if (w != NULL) { + viewport = w->viewport; + + viewX = viewport->view_width / 2 + viewport->view_x; + viewY = viewport->view_height / 2 + viewport->view_y; + viewZoom = viewport->zoom; + viewRotation = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_ROTATION, uint8); + } else { + viewX = 0; + viewY = 0; + viewZoom = 0; + viewRotation = 0; + } + + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, uint16) = viewX; + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, uint16) = viewY; + RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) = viewZoom | (viewRotation << 8); + + // Prepare S6 + rct_s6_data *s6 = malloc(sizeof(rct_s6_data)); + s6->header.type = S6_TYPE_SAVEDGAME; + s6->header.num_packed_objects = scenario_get_num_packed_objects_to_write(); + s6->header.version = S6_RCT2_VERSION; + s6->header.magic_number = S6_MAGIC_NUMBER; + + memcpy(&s6->info, (rct_s6_info*)0x0141F570, sizeof(rct_s6_info)); + + for (int i = 0; i < 721; i++) { + uint32 chunkPtr = RCT2_ADDRESS(0x009ACFA4, uint32)[i]; + rct_object_entry_extended *entry = &(RCT2_ADDRESS(0x00F3F03C, rct_object_entry_extended)[i]); + + if (RCT2_ADDRESS(0x009ACFA4, uint32)[i] == 0xFFFFFFFF) { + memset(&s6->objects[i], 0xFF, sizeof(rct_object_entry)); + } else { + s6->objects[i] = *((rct_object_entry*)entry); + } + } + + memcpy(&s6->elapsed_months, (void*)0x00F663A8, 16); + memcpy(s6->map_elements, (void*)0x00F663B8, 0x180000); + memcpy(&s6->dword_010E63B8, (void*)0x010E63B8, 0x2E8570); + + scenario_fix_ghosts(s6); + scenario_save_s6(rw, s6); + + free(s6); + + gfx_invalidate_screen(); + return 1; +} + bool scenario_save_s6(SDL_RWops* rw, rct_s6_data *s6) { char *buffer; diff --git a/src/scenario.h b/src/scenario.h index d2cdd74b98..80df725b6f 100644 --- a/src/scenario.h +++ b/src/scenario.h @@ -427,6 +427,7 @@ unsigned int scenario_rand(); unsigned int scenario_rand_max(unsigned int max); int scenario_prepare_for_save(); int scenario_save(SDL_RWops* rw, int flags); +int scenario_save_network(SDL_RWops* rw); bool scenario_save_s6(SDL_RWops* rw, rct_s6_data *s6); void scenario_set_filename(const char *value); void scenario_failure();