From 254041985f43cca6a711a2193c22445b6d3316f0 Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Sun, 9 Apr 2017 20:38:36 +0100 Subject: [PATCH] Make servers work --- src/openrct2/actions/GameAction.cpp | 7 +++ src/openrct2/network/Network.cpp | 75 ++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/src/openrct2/actions/GameAction.cpp b/src/openrct2/actions/GameAction.cpp index 086fd693ac..f2de568ea7 100644 --- a/src/openrct2/actions/GameAction.cpp +++ b/src/openrct2/actions/GameAction.cpp @@ -126,6 +126,13 @@ namespace GameActions stream.WriteValue(flags); action->Serialise(&stream); network_send_game_action((uint8*)stream.GetData(), stream.GetLength(), action->GetType()); + if (network_get_mode() == NETWORK_MODE_CLIENT) { + // Client sent the command to the server, do not run it locally, just return. It will run when server sends it + //game_command_callback = 0; + // Decrement nest count + //gGameCommandNestLevel--; + return result; + } } } diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index 60e8106028..e1fe11d17f 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -2072,13 +2072,84 @@ void Network::Client_Handle_GAME_ACTION(NetworkConnection& connection, NetworkPa void Network::Server_Handle_GAME_ACTION(NetworkConnection& connection, NetworkPacket& packet) { uint32 tick; - uint32 type; - packet >> tick >> type; + uint32 commandType; + + if (!connection.Player) { + return; + } + + packet >> tick >> commandType; MemoryStream stream; for (int i = packet.BytesRead; i < packet.Size; ++i) { stream.WriteValue(((uint8*)packet.GetData())[i]); } stream.SetPosition(0); + + uint32 ticks = SDL_GetTicks(); //tick count is different by time last_action_time is set, keep same value. + // Check if player's group permission allows command to run + NetworkGroup* group = GetGroupByID(connection.Player->Group); + if (!group || (group && !group->CanPerformCommand(commandType))) { + Server_Send_SHOWERROR(connection, STR_CANT_DO_THIS, STR_PERMISSION_DENIED); + return; + } + + // In case someone modifies the code / memory to enable cluster build, + // require a small delay in between placing scenery to provide some security, as + // cluster mode is a for loop that runs the place_scenery code multiple times. + if (commandType == GAME_COMMAND_PLACE_SCENERY) { + if ( + ticks - connection.Player->LastPlaceSceneryTime < ACTION_COOLDOWN_TIME_PLACE_SCENERY && + // Incase SDL_GetTicks() wraps after ~49 days, ignore larger logged times. + ticks > connection.Player->LastPlaceSceneryTime + ) { + if (!(group->CanPerformCommand(MISC_COMMAND_TOGGLE_SCENERY_CLUSTER))) { + Server_Send_SHOWERROR(connection, STR_CANT_DO_THIS, STR_NETWORK_ACTION_RATE_LIMIT_MESSAGE); + return; + } + } + } + // This is to prevent abuse of demolishing rides. Anyone that is not the server + // host will have to wait a small amount of time in between deleting rides. + else if (commandType == GAME_COMMAND_DEMOLISH_RIDE) { + if ( + ticks - connection.Player->LastDemolishRideTime < ACTION_COOLDOWN_TIME_DEMOLISH_RIDE && + // Incase SDL_GetTicks() wraps after ~49 days, ignore larger logged times. + ticks > connection.Player->LastDemolishRideTime + ) { + Server_Send_SHOWERROR(connection, STR_CANT_DO_THIS, STR_NETWORK_ACTION_RATE_LIMIT_MESSAGE); + return; + } + } + // Don't let clients send pause or quit + else if (commandType == GAME_COMMAND_TOGGLE_PAUSE || + commandType == GAME_COMMAND_LOAD_OR_QUIT + ) { + return; + } + + // Set this to reference inside of game command functions + game_command_playerid = connection.Player->Id; + // Run game command, and if it is successful send to clients + auto ga = GameActions::Create(commandType); + uint16 flags = stream.ReadValue(); + ga->Deserialise(&stream); + auto result = GameActions::Execute(ga, nullptr, 0x80 | flags); + if (result.Error != GA_ERROR::OK) { + return; + } + + connection.Player->LastAction = NetworkActions::FindCommand(commandType); + connection.Player->LastActionTime = SDL_GetTicks(); + connection.Player->AddMoneySpent(result.Cost); + + if (commandType == GAME_COMMAND_PLACE_SCENERY) { + connection.Player->LastPlaceSceneryTime = connection.Player->LastActionTime; + } + else if (commandType == GAME_COMMAND_DEMOLISH_RIDE) { + connection.Player->LastDemolishRideTime = connection.Player->LastActionTime; + } + + Server_Send_GAME_ACTION((uint8*)stream.GetData(), stream.GetLength(), commandType); } void Network::Server_Handle_GAMECMD(NetworkConnection& connection, NetworkPacket& packet) {