1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-24 00:03:11 +01:00

Merge pull request #10045 from ZehMatt/fix-9994

Fix #9994: Game action tick collision during server connect and map load
This commit is contained in:
ζeh Matt
2019-10-06 14:27:12 +02:00
committed by GitHub
4 changed files with 38 additions and 1 deletions

View File

@@ -25,6 +25,7 @@
- Fix: [#9955] Resizing map in while pause mode does not work and may result in freezes. - Fix: [#9955] Resizing map in while pause mode does not work and may result in freezes.
- Fix: [#9957] When using 'no money' cheat, guests complain of running out of cash. - Fix: [#9957] When using 'no money' cheat, guests complain of running out of cash.
- Fix: [#9970] Wait for quarter load fails. - Fix: [#9970] Wait for quarter load fails.
- Fix: [#9994] Game action tick collision during server connect and map load.
- Fix: [#10017] Ghost elements influencing ride excitement. - Fix: [#10017] Ghost elements influencing ride excitement.
- Fix: [#10036] Do not allocate large chunks of memory for save file classification. - Fix: [#10036] Do not allocate large chunks of memory for save file classification.
- Improved: [#9466] Add the rain weather effect to the OpenGL renderer. - Improved: [#9466] Add the rain weather effect to the OpenGL renderer.

View File

@@ -76,6 +76,7 @@ namespace GameActions
static GameActionFactory _actions[GAME_COMMAND_COUNT]; static GameActionFactory _actions[GAME_COMMAND_COUNT];
static std::multiset<QueuedGameAction> _actionQueue; static std::multiset<QueuedGameAction> _actionQueue;
static uint32_t _nextUniqueId = 0; static uint32_t _nextUniqueId = 0;
static bool _suspended = false;
GameActionFactory Register(uint32_t id, GameActionFactory factory) GameActionFactory Register(uint32_t id, GameActionFactory factory)
{ {
@@ -95,6 +96,16 @@ namespace GameActions
return false; return false;
} }
void SuspendQueue()
{
_suspended = true;
}
void ResumeQueue()
{
_suspended = false;
}
void Enqueue(const GameAction* ga, uint32_t tick) void Enqueue(const GameAction* ga, uint32_t tick)
{ {
auto action = Clone(ga); auto action = Clone(ga);
@@ -114,6 +125,12 @@ namespace GameActions
void ProcessQueue() void ProcessQueue()
{ {
if (_suspended)
{
// Do nothing if suspended, this is usually the case between connect and map loads.
return;
}
const uint32_t currentTick = gCurrentTicks; const uint32_t currentTick = gCurrentTicks;
while (_actionQueue.begin() != _actionQueue.end()) while (_actionQueue.begin() != _actionQueue.end())

View File

@@ -255,6 +255,14 @@ namespace GameActions
void Register(); void Register();
bool IsValidId(uint32_t id); bool IsValidId(uint32_t id);
// Halts the queue processing until ResumeQueue is called, any calls to ProcessQueue
// will have no effect during suspension. It has no effect of actions that will not
// cross the network.
void SuspendQueue();
// Resumes queue processing.
void ResumeQueue();
void Enqueue(const GameAction* ga, uint32_t tick); void Enqueue(const GameAction* ga, uint32_t tick);
void Enqueue(GameAction::Ptr&& ga, uint32_t tick); void Enqueue(GameAction::Ptr&& ga, uint32_t tick);
void ProcessQueue(); void ProcessQueue();

View File

@@ -34,7 +34,7 @@
// This string specifies which version of network stream current build uses. // This string specifies which version of network stream current build uses.
// It is used for making sure only compatible builds get connected, even within // It is used for making sure only compatible builds get connected, even within
// single OpenRCT2 version. // single OpenRCT2 version.
#define NETWORK_STREAM_VERSION "17" #define NETWORK_STREAM_VERSION "18"
#define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION
static Peep* _pickup_peep = nullptr; static Peep* _pickup_peep = nullptr;
@@ -417,6 +417,7 @@ void Network::Close()
client_connection_list.clear(); client_connection_list.clear();
GameActions::ClearQueue(); GameActions::ClearQueue();
GameActions::ResumeQueue();
player_list.clear(); player_list.clear();
group_list.clear(); group_list.clear();
_serverTickData.clear(); _serverTickData.clear();
@@ -493,6 +494,11 @@ bool Network::BeginClient(const std::string& host, uint16_t port)
BeginChatLog(); BeginChatLog();
BeginServerLog(); BeginServerLog();
// We need to wait for the map load before we execute any actions.
// If the client has the title screen running then theres a potential
// risk of tick collision with the server map and title screen map.
GameActions::SuspendQueue();
utf8 keyPath[MAX_PATH]; utf8 keyPath[MAX_PATH];
network_get_private_key_path(keyPath, sizeof(keyPath), gConfigNetwork.player_name); network_get_private_key_path(keyPath, sizeof(keyPath), gConfigNetwork.player_name);
if (!platform_file_exists(keyPath)) if (!platform_file_exists(keyPath))
@@ -2615,6 +2621,8 @@ void Network::Client_Handle_MAP([[maybe_unused]] NetworkConnection& connection,
// Start of a new map load, clear the queue now as we have to buffer them // Start of a new map load, clear the queue now as we have to buffer them
// until the map is fully loaded. // until the map is fully loaded.
GameActions::ClearQueue(); GameActions::ClearQueue();
GameActions::SuspendQueue();
_serverTickData.clear(); _serverTickData.clear();
_clientMapLoaded = false; _clientMapLoaded = false;
} }
@@ -2637,6 +2645,9 @@ void Network::Client_Handle_MAP([[maybe_unused]] NetworkConnection& connection,
std::memcpy(&chunk_buffer[offset], (void*)packet.Read(chunksize), chunksize); std::memcpy(&chunk_buffer[offset], (void*)packet.Read(chunksize), chunksize);
if (offset + chunksize == size) if (offset + chunksize == size)
{ {
// Allow queue processing of game actions again.
GameActions::ResumeQueue();
context_force_close_window_by_class(WC_NETWORK_STATUS); context_force_close_window_by_class(WC_NETWORK_STATUS);
bool has_to_free = false; bool has_to_free = false;
uint8_t* data = &chunk_buffer[0]; uint8_t* data = &chunk_buffer[0];