diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index b1ca7b1895..932c9eec43 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -4373,6 +4373,42 @@ STR_6061 :{SMALLFONT}{BLACK}Show animated money effect{NEWLINE}when guests ma STR_6062 :{OUTLINE}{GREEN}+ {CURRENCY2DP} STR_6063 :{OUTLINE}{RED}- {CURRENCY2DP} STR_6064 :Own all land +STR_6065 :Log user actions +STR_6066 :{SMALLFONT}{BLACK}Logs all user actions to files in your user directory. +STR_6067 :Server started. +STR_6068 :Server shutdown. +STR_6069 :{STRING} was kicked from the server by {STRING}. +STR_6070 :{STRING} was set to group '{STRING}' by {STRING}. +STR_6071 :{STRING} created new player group '{STRING}'. +STR_6072 :{STRING} deleted player group '{String}'. +STR_6073 :{STRING} edited permissions for player group '{String}'. +STR_6074 :{STRING} changed player group name from '{String}' to '{String}'. +STR_6075 :{STRING} changed the default player group to '{String}'. +STR_6076 :{STRING} used/toggled cheat '{STRING}'. +STR_6077 :Add Money +STR_6078 :{STRING} created ride '{STRING}'. +STR_6079 :{STRING} demolished ride '{STRING}'. +STR_6080 :{STRING} changed the appearance of ride '{STRING}'. +STR_6081 :{STRING} changed the status of ride '{STRING}' to closed. +STR_6082 :{STRING} changed the status of ride '{STRING}' to open. +STR_6083 :{STRING} changed the status of ride '{STRING}' to testing. +STR_6084 :{STRING} changed the vehicle settings of ride '{STRING}'. +STR_6085 :{STRING} changed the ride settings of ride '{STRING}'. +STR_6086 :{STRING} renamed the ride '{STRING}' to '{STRING}'. +STR_6087 :{STRING} changed the price of ride '{STRING}' to {STRING} +STR_6088 :{STRING} changed the secondary price of ride '{STRING}' to {STRING} +STR_6089 :{STRING} renamed the park from '{STRING}' to '{STRING}'. +STR_6090 :{STRING} opened the park. +STR_6091 :{STRING} closed the park. +STR_6092 :{STRING} changed the park entrance fee to {STRING} +STR_6093 :{STRING} placed new scenery. +STR_6094 :{STRING} removed scenery. +STR_6095 :{STRING} edited scenery. +STR_6096 :{STRING} set sign name to '{STRING}'. +STR_6097 :{STRING} placed a track of ride '{STRING}'. +STR_6098 :{STRING} removed a track of ride. +STR_6099 :You connected to the server. +STR_6100 :You disconnected from the server. ############# # Scenarios # diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index 204089f8f7..bcf74fa755 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -49,6 +49,7 @@ extern "C" #include "intro.h" #include "localisation/localisation.h" #include "network/http.h" + #include "network/network.h" #include "object_list.h" #include "rct1.h" #include "rct2.h" @@ -218,6 +219,7 @@ namespace OpenRCT2 } http_init(); + network_set_env(_env); theme_manager_initialise(); rct2_interop_setup_hooks(); diff --git a/src/openrct2/cheats.c b/src/openrct2/cheats.c index d93393c275..ce10050cba 100644 --- a/src/openrct2/cheats.c +++ b/src/openrct2/cheats.c @@ -19,13 +19,14 @@ #include "editor.h" #include "game.h" #include "interface/window.h" -#include "localisation/date.h" +#include "localisation/localisation.h" #include "management/finance.h" #include "network/network.h" #include "util/util.h" #include "world/Climate.h" #include "world/footpath.h" #include "world/map.h" +#include "world/park.h" #include "world/scenery.h" #include "world/sprite.h" @@ -569,3 +570,209 @@ void cheats_reset() gCheatsDisablePlantAging = false; gCheatsAllowArbitraryRideTypeChanges = false; } + +//Generates the string to print for the server log when a cheat is used. +const char* cheats_get_cheat_string(int cheat, int edx, int edi) { + switch (cheat) { + case CHEAT_SANDBOXMODE: + if (gCheatsSandboxMode) { + return language_get_string(STR_CHEAT_SANDBOX_MODE_DISABLE); + } else { + return language_get_string(STR_CHEAT_SANDBOX_MODE); + } + case CHEAT_DISABLECLEARANCECHECKS: return language_get_string(STR_DISABLE_CLEARANCE_CHECKS); + case CHEAT_DISABLESUPPORTLIMITS: return language_get_string(STR_DISABLE_SUPPORT_LIMITS); + case CHEAT_SHOWALLOPERATINGMODES: return language_get_string(STR_CHEAT_SHOW_ALL_OPERATING_MODES); + case CHEAT_SHOWVEHICLESFROMOTHERTRACKTYPES: return language_get_string(STR_CHEAT_SHOW_VEHICLES_FROM_OTHER_TRACK_TYPES); + case CHEAT_FASTLIFTHILL: return language_get_string(STR_CHEAT_UNLOCK_OPERATING_LIMITS); + case CHEAT_DISABLEBRAKESFAILURE: return language_get_string(STR_CHEAT_DISABLE_BRAKES_FAILURE); + case CHEAT_DISABLEALLBREAKDOWNS: return language_get_string(STR_CHEAT_DISABLE_BREAKDOWNS); + case CHEAT_DISABLETRAINLENGTHLIMIT: return language_get_string(STR_CHEAT_DISABLE_TRAIN_LENGTH_LIMIT); + case CHEAT_ENABLECHAINLIFTONALLTRACK: return language_get_string(STR_CHEAT_ENABLE_CHAIN_LIFT_ON_ALL_TRACK); + case CHEAT_UNLOCKALLPRICES: return language_get_string(STR_CHEAT_UNLOCK_PRICES); + case CHEAT_BUILDINPAUSEMODE: return language_get_string(STR_CHEAT_BUILD_IN_PAUSE_MODE); + case CHEAT_IGNORERIDEINTENSITY: return language_get_string(STR_CHEAT_IGNORE_INTENSITY); + case CHEAT_DISABLEVANDALISM: return language_get_string(STR_CHEAT_DISABLE_VANDALISM); + case CHEAT_DISABLELITTERING: return language_get_string(STR_CHEAT_DISABLE_LITTERING); + case CHEAT_ADDMONEY: return language_get_string(STR_LOG_CHEAT_ADD_MONEY); + case CHEAT_CLEARLOAN: return language_get_string(STR_CHEAT_CLEAR_LOAN); + case CHEAT_SETGUESTPARAMETER: + { + static char cheat_string[128]; + safe_strcpy(cheat_string, language_get_string(STR_CHEAT_SET_GUESTS_PARAMETERS), 128); + safe_strcat(cheat_string, " ", 128); + switch (edx) { + case GUEST_PARAMETER_HAPPINESS: + safe_strcat(cheat_string, language_get_string(STR_CHEAT_GUEST_HAPPINESS), 128); + safe_strcat(cheat_string, " ", 128); + if (edi == 255) { + safe_strcat(cheat_string, language_get_string(STR_MAX), 128); + } else if (edi == 0) { + safe_strcat(cheat_string, language_get_string(STR_MIN), 128); + } + break; + case GUEST_PARAMETER_ENERGY: + safe_strcat(cheat_string, language_get_string(STR_CHEAT_GUEST_ENERGY), 128); + safe_strcat(cheat_string, " ", 128); + if (edi == 127) { + safe_strcat(cheat_string, language_get_string(STR_MAX), 128); + } else if (edi == 0) { + safe_strcat(cheat_string, language_get_string(STR_MIN), 128); + } + break; + case GUEST_PARAMETER_HUNGER: + safe_strcat(cheat_string, language_get_string(STR_CHEAT_GUEST_HUNGER), 128); + safe_strcat(cheat_string, " ", 128); + if (edi == 255) { + safe_strcat(cheat_string, language_get_string(STR_MIN), 128); + } else if (edi == 0) { + safe_strcat(cheat_string, language_get_string(STR_MAX), 128); + } + break; + case GUEST_PARAMETER_THIRST: + safe_strcat(cheat_string, language_get_string(STR_CHEAT_GUEST_THIRST), 128); + safe_strcat(cheat_string, " ", 128); + if (edi == 255) { + safe_strcat(cheat_string, language_get_string(STR_MIN), 128); + } else if (edi == 0) { + safe_strcat(cheat_string, language_get_string(STR_MAX), 128); + } + break; + case GUEST_PARAMETER_NAUSEA: + safe_strcat(cheat_string, language_get_string(STR_CHEAT_GUEST_NAUSEA), 128); + safe_strcat(cheat_string, " ", 128); + if (edi == 255) { + safe_strcat(cheat_string, language_get_string(STR_MAX), 128); + } else if (edi == 0) { + safe_strcat(cheat_string, language_get_string(STR_MIN), 128); + } + break; + case GUEST_PARAMETER_NAUSEA_TOLERANCE: + safe_strcat(cheat_string, language_get_string(STR_CHEAT_GUEST_NAUSEA_TOLERANCE), 128); + safe_strcat(cheat_string, " ", 128); + if (edi == PEEP_NAUSEA_TOLERANCE_HIGH) { + safe_strcat(cheat_string, language_get_string(STR_MAX), 128); + } else if (edi == PEEP_NAUSEA_TOLERANCE_NONE) { + safe_strcat(cheat_string, language_get_string(STR_MIN), 128); + } + break; + case GUEST_PARAMETER_BATHROOM: + safe_strcat(cheat_string, language_get_string(STR_CHEAT_GUEST_BATHROOM), 128); + safe_strcat(cheat_string, " ", 128); + if (edi == 255) { + safe_strcat(cheat_string, language_get_string(STR_MAX), 128); + } else if (edi == 0) { + safe_strcat(cheat_string, language_get_string(STR_MIN), 128); + } + break; + case GUEST_PARAMETER_PREFERRED_RIDE_INTENSITY: + safe_strcat(cheat_string, language_get_string(STR_CHEAT_GUEST_PREFERRED_INTENSITY), 128); + safe_strcat(cheat_string, " ", 128); + if (edi == 1) { + safe_strcat(cheat_string, language_get_string(STR_CHEAT_MORE_THAN_1), 128); + } else if (edi == 0) { + safe_strcat(cheat_string, language_get_string(STR_CHEAT_LESS_THAN_15), 128); + } + break; + } + return cheat_string; + } + case CHEAT_GENERATEGUESTS: return language_get_string(STR_CHEAT_LARGE_TRAM_GUESTS); + case CHEAT_REMOVEALLGUESTS: return language_get_string(STR_CHEAT_REMOVE_ALL_GUESTS); + case CHEAT_EXPLODEGUESTS: return language_get_string(STR_CHEAT_EXPLODE); + case CHEAT_GIVEALLGUESTS: + { + static char cheat_string[64]; + safe_strcpy(cheat_string, language_get_string(STR_CHEAT_GIVE_ALL_GUESTS), 64); + safe_strcat(cheat_string, " ", 64); + switch (edx) { + case OBJECT_MONEY: + { + char money[16]; + set_format_arg(0, money32, CHEATS_GIVE_GUESTS_MONEY); + format_string(money, 16, STR_CHEAT_CURRENCY_FORMAT, gCommonFormatArgs); + safe_strcat(cheat_string, money, 64); + break; + } + case OBJECT_PARK_MAP: safe_strcat(cheat_string, language_get_string(STR_SHOP_ITEM_PLURAL_PARK_MAP), 64); break; + case OBJECT_BALLOON: safe_strcat(cheat_string, language_get_string(STR_SHOP_ITEM_PLURAL_BALLOON), 64); break; + case OBJECT_UMBRELLA: safe_strcat(cheat_string, language_get_string(STR_SHOP_ITEM_PLURAL_UMBRELLA), 64); break; + } + return cheat_string; + } + case CHEAT_SETGRASSLENGTH: + if (edx == 0) { + return language_get_string(STR_CHEAT_MOWED_GRASS); + } else if (edx == 1) { + return language_get_string(STR_CHEAT_CLEAR_GRASS); + } + case CHEAT_WATERPLANTS: return language_get_string(STR_CHEAT_WATER_PLANTS); + case CHEAT_FIXVANDALISM: return language_get_string(STR_CHEAT_FIX_VANDALISM); + case CHEAT_REMOVELITTER: return language_get_string(STR_CHEAT_REMOVE_LITTER); + case CHEAT_DISABLEPLANTAGING: return language_get_string(STR_CHEAT_DISABLE_PLANT_AGING); + case CHEAT_SETSTAFFSPEED: + { + static char cheat_string[64]; + safe_strcpy(cheat_string, language_get_string(STR_CHEAT_STAFF_SPEED), 64); + safe_strcat(cheat_string, " ", 64); + if (edx == CHEATS_STAFF_FAST_SPEED) { + safe_strcat(cheat_string, language_get_string(STR_FAST), 64); + } else if (edx == CHEATS_STAFF_NORMAL_SPEED) { + safe_strcat(cheat_string, language_get_string(STR_NORMAL), 64); + } + return cheat_string; + } + case CHEAT_RENEWRIDES: return language_get_string(STR_CHEAT_RENEW_RIDES); + case CHEAT_MAKEDESTRUCTIBLE: return language_get_string(STR_CHEAT_MAKE_DESTRUCTABLE); + case CHEAT_FIXRIDES: return language_get_string(STR_CHEAT_FIX_ALL_RIDES); + case CHEAT_RESETCRASHSTATUS: return language_get_string(STR_CHEAT_RESET_CRASH_STATUS); + case CHEAT_10MINUTEINSPECTIONS: return language_get_string(STR_CHEAT_10_MINUTE_INSPECTIONS); + case CHEAT_WINSCENARIO: return language_get_string(STR_CHEAT_WIN_SCENARIO); + case CHEAT_FORCEWEATHER: + { + static char cheat_string[64]; + safe_strcpy(cheat_string, language_get_string(STR_FORCE_WEATHER), 64); + safe_strcat(cheat_string, " ", 64); + switch (edx) { + case 0: safe_strcat(cheat_string, language_get_string(STR_SUNNY), 64); break; + case 1: safe_strcat(cheat_string, language_get_string(STR_PARTIALLY_CLOUDY), 64); break; + case 2: safe_strcat(cheat_string, language_get_string(STR_CLOUDY), 64); break; + case 3: safe_strcat(cheat_string, language_get_string(STR_RAIN), 64); break; + case 4: safe_strcat(cheat_string, language_get_string(STR_HEAVY_RAIN), 64); break; + case 5: safe_strcat(cheat_string, language_get_string(STR_THUNDERSTORM), 64); break; + } + return cheat_string; + } + case CHEAT_FREEZECLIMATE: + if (gCheatsFreezeClimate) { + return language_get_string(STR_CHEAT_UNFREEZE_CLIMATE); + } else { + return language_get_string(STR_CHEAT_FREEZE_CLIMATE); + } + case CHEAT_NEVERENDINGMARKETING: return language_get_string(STR_CHEAT_NEVERENDING_MARKETING); + case CHEAT_OPENCLOSEPARK: + if (park_is_open()) { + return language_get_string(STR_CHEAT_CLOSE_PARK); + } else { + return language_get_string(STR_CHEAT_OPEN_PARK); + } + case CHEAT_HAVEFUN: return language_get_string(STR_CHEAT_HAVE_FUN); + case CHEAT_SETFORCEDPARKRATING: + { + static char cheat_string[64]; + safe_strcpy(cheat_string, language_get_string(STR_FORCE_PARK_RATING), 64); + safe_strcat(cheat_string, " ", 64); + + char buffer[8]; + snprintf(buffer, sizeof(buffer), "%d", park_rating_spinner_value); + char* park_rating = buffer; + safe_strcat(cheat_string, park_rating, 64); + + return cheat_string; + } + case CHEAT_RESETDATE: return language_get_string(STR_CHEAT_RESET_DATE); + case CHEAT_ALLOW_ARBITRARY_RIDE_TYPE_CHANGES: return language_get_string(STR_CHEAT_ALLOW_ARBITRARY_RIDE_TYPE_CHANGES); + } + + return ""; +} diff --git a/src/openrct2/cheats.h b/src/openrct2/cheats.h index 449f9dcb30..ba0f02e9ee 100644 --- a/src/openrct2/cheats.h +++ b/src/openrct2/cheats.h @@ -107,7 +107,10 @@ enum { }; #define CHEATS_MONEY_INCREMENT MONEY(5000,00) +#define CHEATS_GIVE_GUESTS_MONEY MONEY(1000,00) #define CHEATS_TRAM_INCREMENT 250 +#define CHEATS_STAFF_FAST_SPEED 0xFF +#define CHEATS_STAFF_NORMAL_SPEED 0x60 extern sint32 park_rating_spinner_value; @@ -115,4 +118,6 @@ void game_command_cheat(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint void cheats_reset(); +const char* cheats_get_cheat_string(int cheat, int edx, int edi); + #endif diff --git a/src/openrct2/config/Config.cpp b/src/openrct2/config/Config.cpp index 88abd27bef..2ac39abd1a 100644 --- a/src/openrct2/config/Config.cpp +++ b/src/openrct2/config/Config.cpp @@ -359,6 +359,7 @@ namespace Config model->provider_website = reader->GetCString("provider_website", nullptr); model->known_keys_only = reader->GetBoolean("known_keys_only", false); model->log_chat = reader->GetBoolean("log_chat", false); + model->log_server_actions = reader->GetBoolean("log_server_actions", false); } } @@ -382,6 +383,7 @@ namespace Config writer->WriteString("provider_website", model->provider_website); writer->WriteBoolean("known_keys_only", model->known_keys_only); writer->WriteBoolean("log_chat", model->log_chat); + writer->WriteBoolean("log_server_actions", model->log_server_actions); } static void ReadNotifications(IIniReader * reader) diff --git a/src/openrct2/config/Config.h b/src/openrct2/config/Config.h index 920940ce73..9885d325c8 100644 --- a/src/openrct2/config/Config.h +++ b/src/openrct2/config/Config.h @@ -152,6 +152,7 @@ typedef struct NetworkConfiguration utf8 * provider_website; bool known_keys_only; bool log_chat; + bool log_server_actions; } NetworkConfiguration; typedef struct NotificationConfiguration diff --git a/src/openrct2/game.c b/src/openrct2/game.c index 9b1edb5048..ddb57511b2 100644 --- a/src/openrct2/game.c +++ b/src/openrct2/game.c @@ -512,6 +512,13 @@ sint32 game_do_command_p(sint32 command, sint32 *eax, sint32 *ebx, sint32 *ecx, game_command_playerid = network_get_current_player_id(); } + // Log certain commands if we are in multiplayer and logging is enabled + bool serverLog = (network_get_mode() == NETWORK_MODE_SERVER) && gGameCommandNestLevel == 1 && gConfigNetwork.log_server_actions; + bool clientLog = (network_get_mode() == NETWORK_MODE_CLIENT) && (flags & GAME_COMMAND_FLAG_NETWORKED) && gGameCommandNestLevel == 1 && gConfigNetwork.log_server_actions; + if (serverLog || clientLog) { + game_log_multiplayer_command(command, eax, ebx, ecx, edx, edi, ebp); + } + *ebx &= ~GAME_COMMAND_FLAG_APPLY; // First call for validity and price check @@ -611,6 +618,228 @@ sint32 game_do_command_p(sint32 command, sint32 *eax, sint32 *ebx, sint32 *ecx, return MONEY32_UNDEFINED; } +void game_log_multiplayer_command(int command, int *eax, int* ebx, int* ecx, int* edx, int* edi, int* ebp) +{ + // Get player name + int player_index = network_get_player_index(game_command_playerid); + const char* player_name = network_get_player_name(player_index); + + char log_msg[256]; + if (command == GAME_COMMAND_CHEAT) { + // Get cheat name + const char* cheat = cheats_get_cheat_string(*ecx, *edx, *edi); + char* args[2] = { + (char *)player_name, + (char *)cheat + }; + format_string(log_msg, 256, STR_LOG_CHEAT_USED, args); + network_append_server_log(log_msg); + } else if (command == GAME_COMMAND_CREATE_RIDE && *ebp == 1) { // ebp is 1 if the command comes from ride_create method in ride.c, other calls send ride_entry instead of ride and wont work + // Get ride name + rct_ride* ride = get_ride(*edx); + char ride_name[128]; + format_string(ride_name, 128, ride->name, &ride->name_arguments); + + char* args[2] = { + (char *)player_name, + ride_name + }; + + format_string(log_msg, 256, STR_LOG_CREATE_RIDE, args); + network_append_server_log(log_msg); + } else if (command == GAME_COMMAND_DEMOLISH_RIDE && (*ebp == 1 || *ebp == 0)) { // ebp is 1 if command comes from ride window prompt, so we don't log "demolishing" ride previews + // Get ride name + rct_ride* ride = get_ride(*edx); + char ride_name[128]; + format_string(ride_name, 128, ride->name, &ride->name_arguments); + + char* args[2] = { + (char *) player_name, + ride_name + }; + + format_string(log_msg, 256, STR_LOG_DEMOLISH_RIDE, args); + network_append_server_log(log_msg); + } else if (command == GAME_COMMAND_SET_RIDE_APPEARANCE || command == GAME_COMMAND_SET_RIDE_VEHICLES || command == GAME_COMMAND_SET_RIDE_SETTING) { + // Get ride name + int ride_index = *edx & 0xFF; + rct_ride* ride = get_ride(ride_index); + char ride_name[128]; + format_string(ride_name, 128, ride->name, &ride->name_arguments); + + char* args[2] = { + (char *) player_name, + ride_name + }; + + switch (command) { + case GAME_COMMAND_SET_RIDE_APPEARANCE: format_string(log_msg, 256, STR_LOG_RIDE_APPEARANCE, args); break; + case GAME_COMMAND_SET_RIDE_VEHICLES: format_string(log_msg, 256, STR_LOG_RIDE_VEHICLES, args); break; + case GAME_COMMAND_SET_RIDE_SETTING: format_string(log_msg, 256, STR_LOG_RIDE_SETTINGS, args); break; + } + + network_append_server_log(log_msg); + } else if (command == GAME_COMMAND_SET_RIDE_STATUS) { + // Get ride name + int ride_index = *edx & 0xFF; + rct_ride* ride = get_ride(ride_index); + char ride_name[128]; + format_string(ride_name, 128, ride->name, &ride->name_arguments); + + char* args[2] = { + (char *) player_name, + ride_name + }; + + int status = *edx >> 8; + switch (status) { + case 0: format_string(log_msg, 256, STR_LOG_RIDE_STATUS_CLOSED, args); break; + case 1: format_string(log_msg, 256, STR_LOG_RIDE_STATUS_OPEN, args); break; + case 2: format_string(log_msg, 256, STR_LOG_RIDE_STATUS_TESTING, args); break; + } + + network_append_server_log(log_msg); + } else if (command == GAME_COMMAND_SET_RIDE_PRICE) { + // Get ride name + int ride_index = *edx & 0xFF; + rct_ride* ride = get_ride(ride_index); + char ride_name[128]; + format_string(ride_name, 128, ride->name, &ride->name_arguments); + + // Format price + int price_args[1] = {*edi}; + char price_str[16]; + format_string(price_str, 16, STR_BOTTOM_TOOLBAR_CASH, price_args); + + // Log change in primary or secondary price + char* args[3] = { + (char *) player_name, + ride_name, + price_str + }; + + if (*edx >> 8 == 0) { + format_string(log_msg, 256, STR_LOG_RIDE_PRICE, args); + } else if (*edx >> 8 == 1) { + format_string(log_msg, 256, STR_LOG_RIDE_SECONDARY_PRICE, args); + } + + network_append_server_log(log_msg); + } else if (command == GAME_COMMAND_SET_PARK_OPEN) { + // Log change in park open/close + char* args[1] = { + (char *) player_name + }; + + if (*edx >> 8 == 0) { + format_string(log_msg, 256, STR_LOG_PARK_OPEN, args); + } else if (*edx >> 8 == 1) { + format_string(log_msg, 256, STR_LOG_PARK_CLOSED, args); + } + + network_append_server_log(log_msg); + } else if (command == GAME_COMMAND_SET_PARK_ENTRANCE_FEE) { + // Format price + int price_args[1] = {*edi}; + char price_str[16]; + format_string(price_str, 16, STR_BOTTOM_TOOLBAR_CASH, price_args); + + // Log change in park entrance fee + char* args[2] = { + (char *) player_name, + price_str + }; + + format_string(log_msg, 256, STR_LOG_PARK_ENTRANCE_FEE, args); + network_append_server_log(log_msg); + } else if (command == GAME_COMMAND_PLACE_SCENERY || command == GAME_COMMAND_PLACE_WALL || + command == GAME_COMMAND_PLACE_LARGE_SCENERY || command == GAME_COMMAND_PLACE_BANNER) { + uint8 flags = *ebx & 0xFF; + if (flags & GAME_COMMAND_FLAG_GHOST) { + // Don't log ghost previews being removed + return; + } + + // Log placing scenery + char* args[1] = { + (char *)player_name + }; + + format_string(log_msg, 256, STR_LOG_PLACE_SCENERY, args); + network_append_server_log(log_msg); + } else if (command == GAME_COMMAND_REMOVE_SCENERY || command == GAME_COMMAND_REMOVE_WALL || + command == GAME_COMMAND_REMOVE_LARGE_SCENERY || command == GAME_COMMAND_REMOVE_BANNER) { + uint8 flags = *ebx & 0xFF; + if (flags & GAME_COMMAND_FLAG_GHOST) { + // Don't log ghost previews being removed + return; + } + + // Log removing scenery + char* args[1] = { + (char *)player_name + }; + + format_string(log_msg, 256, STR_LOG_REMOVE_SCENERY, args); + network_append_server_log(log_msg); + } else if (command == GAME_COMMAND_SET_SCENERY_COLOUR || command == GAME_COMMAND_SET_WALL_COLOUR || + command == GAME_COMMAND_SET_LARGE_SCENERY_COLOUR || command == GAME_COMMAND_SET_BANNER_COLOUR || + command == GAME_COMMAND_SET_BANNER_NAME || command == GAME_COMMAND_SET_SIGN_NAME || + command == GAME_COMMAND_SET_BANNER_STYLE || command == GAME_COMMAND_SET_SIGN_STYLE) { + // Log editing scenery + char* args[1] = { + (char *)player_name + }; + + format_string(log_msg, 256, STR_LOG_EDIT_SCENERY, args); + network_append_server_log(log_msg); + if (command == GAME_COMMAND_SET_BANNER_NAME || command == GAME_COMMAND_SET_SIGN_NAME) { + static char banner_name[128]; + + memset(banner_name, ' ', sizeof(banner_name)); + int nameChunkIndex = *eax & 0xFFFF; + + int nameChunkOffset = nameChunkIndex - 1; + if (nameChunkOffset < 0) + nameChunkOffset = 2; + nameChunkOffset *= 12; + nameChunkOffset = min(nameChunkOffset, countof(banner_name) - 12); + memcpy(banner_name + nameChunkOffset + 0, edx, 4); + memcpy(banner_name + nameChunkOffset + 4, ebp, 4); + memcpy(banner_name + nameChunkOffset + 8, edi, 4); + banner_name[sizeof(banner_name) - 1] = '\0'; + char* args_sign[2] = { + (char *)player_name, + (char *)banner_name + }; + + format_string(log_msg, 256, STR_LOG_SET_SIGN_NAME, args_sign); + network_append_server_log(log_msg); + } + } else if (command == GAME_COMMAND_PLACE_TRACK) { + // Get ride name + int ride_index = *edx & 0xFF; + rct_ride* ride = get_ride(ride_index); + char ride_name[128]; + format_string(ride_name, 128, ride->name, &ride->name_arguments); + + char* args[2] = { + (char *) player_name, + ride_name + }; + + format_string(log_msg, 256, STR_LOG_PLACE_TRACK, args); + network_append_server_log(log_msg); + } else if (command == GAME_COMMAND_REMOVE_TRACK) { + char* args[1] = { + (char *) player_name + }; + + format_string(log_msg, 256, STR_LOG_REMOVE_TRACK, args); + network_append_server_log(log_msg); + } +} + void pause_toggle() { gGamePaused ^= GAME_PAUSED_NORMAL; diff --git a/src/openrct2/game.h b/src/openrct2/game.h index f932ea69ec..5e03fdeec4 100644 --- a/src/openrct2/game.h +++ b/src/openrct2/game.h @@ -166,6 +166,8 @@ void update_palette_effects(); sint32 game_do_command(sint32 eax, sint32 ebx, sint32 ecx, sint32 edx, sint32 esi, sint32 edi, sint32 ebp); sint32 game_do_command_p(sint32 command, sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *edx, sint32 *esi, sint32 *edi, sint32 *ebp); +void game_log_multiplayer_command(int command, int *eax, int* ebx, int* ecx, int* edx, int* edi, int* ebp); + void game_load_or_quit_no_save_prompt(); bool game_load_sv6_path(const char * path); bool game_load_save(const utf8 *path); diff --git a/src/openrct2/localisation/string_ids.h b/src/openrct2/localisation/string_ids.h index ab42aa4a6a..0c3d3a89a5 100644 --- a/src/openrct2/localisation/string_ids.h +++ b/src/openrct2/localisation/string_ids.h @@ -3728,6 +3728,43 @@ enum { STR_CHEAT_OWN_ALL_LAND = 6064, + STR_LOG_SERVER_ACTIONS = 6065, + STR_LOG_SERVER_ACTIONS_TIP = 6066, + STR_LOG_SERVER_STARTED = 6067, + STR_LOG_SERVER_STOPPED = 6068, + STR_LOG_PLAYER_KICKED = 6069, + STR_LOG_SET_PLAYER_GROUP = 6070, + STR_LOG_ADD_PLAYER_GROUP = 6071, + STR_LOG_REMOVE_PLAYER_GROUP = 6072, + STR_LOG_EDIT_PLAYER_GROUP_PERMISSIONS = 6073, + STR_LOG_EDIT_PLAYER_GROUP_NAME = 6074, + STR_LOG_EDIT_DEFAULT_PLAYER_GROUP = 6075, + STR_LOG_CHEAT_USED = 6076, + STR_LOG_CHEAT_ADD_MONEY = 6077, + STR_LOG_CREATE_RIDE = 6078, + STR_LOG_DEMOLISH_RIDE = 6079, + STR_LOG_RIDE_APPEARANCE = 6080, + STR_LOG_RIDE_STATUS_CLOSED = 6081, + STR_LOG_RIDE_STATUS_OPEN = 6082, + STR_LOG_RIDE_STATUS_TESTING = 6083, + STR_LOG_RIDE_VEHICLES = 6084, + STR_LOG_RIDE_SETTINGS = 6085, + STR_LOG_RIDE_NAME = 6086, + STR_LOG_RIDE_PRICE = 6087, + STR_LOG_RIDE_SECONDARY_PRICE = 6088, + STR_LOG_PARK_NAME = 6089, + STR_LOG_PARK_CLOSED = 6090, + STR_LOG_PARK_OPEN = 6091, + STR_LOG_PARK_ENTRANCE_FEE = 6092, + STR_LOG_PLACE_SCENERY = 6093, + STR_LOG_REMOVE_SCENERY = 6094, + STR_LOG_EDIT_SCENERY = 6095, + STR_LOG_SET_SIGN_NAME = 6096, + STR_LOG_PLACE_TRACK = 6097, + STR_LOG_REMOVE_TRACK = 6098, + STR_LOG_CLIENT_STARTED = 6099, + STR_LOG_CLIENT_STOPPED = 6100, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working STR_COUNT = 32768 }; diff --git a/src/openrct2/network/network.cpp b/src/openrct2/network/network.cpp index 29578cd9ec..f56676c7b1 100644 --- a/src/openrct2/network/network.cpp +++ b/src/openrct2/network/network.cpp @@ -16,6 +16,7 @@ #include "../core/Guard.hpp" #include "../OpenRCT2.h" +#include "../PlatformEnvironment.h" extern "C" { #include "../platform/platform.h" @@ -125,6 +126,11 @@ Network::~Network() Close(); } +void Network::SetEnvironment(IPlatformEnvironment * env) +{ + _env = env; +} + bool Network::Init() { if (!InitialiseWSA()) { @@ -170,6 +176,9 @@ void Network::Close() _advertiser = nullptr; } + CloseChatLog(); + CloseServerLog(); + mode = NETWORK_MODE_NONE; status = NETWORK_STATUS_NONE; _lastConnectStatus = SOCKET_STATUS_CLOSED; @@ -185,7 +194,6 @@ void Network::Close() DisposeWSA(); - CloseChatLog(); gfx_invalidate_screen(); _requireClose = false; @@ -210,6 +218,7 @@ bool Network::BeginClient(const char* host, uint16 port) _lastConnectStatus = SOCKET_STATUS_CLOSED; BeginChatLog(); + BeginServerLog(); utf8 keyPath[MAX_PATH]; network_get_private_key_path(keyPath, sizeof(keyPath), gConfigNetwork.player_name); @@ -313,6 +322,7 @@ bool Network::BeginServer(uint16 port, const char* address) cheats_reset(); LoadGroups(); BeginChatLog(); + BeginServerLog(); NetworkPlayer *player = AddPlayer(gConfigNetwork.player_name, ""); player->Flags |= NETWORK_PLAYER_FLAG_ISSERVER; @@ -823,62 +833,97 @@ void Network::LoadGroups() group_list.at(0)->ActionsAllowed.fill(0xFF); } -void Network::BeginChatLog() +std::string Network::BeginLog(const std::string &directory, const std::string &filenameFormat) { - utf8 filename[32]; + utf8 filename[256]; time_t timer; - struct tm * tmInfo; time(&timer); - tmInfo = localtime(&timer); - strftime(filename, sizeof(filename), "%Y%m%d-%H%M%S.txt", tmInfo); - - utf8 path[MAX_PATH]; - platform_get_user_directory(path, "chatlogs", sizeof(path)); - Path::Append(path, sizeof(path), filename); - - _chatLogPath = std::string(path); -} - -void Network::AppendChatLog(const utf8 *text) -{ - if (!gConfigNetwork.log_chat) { - return; + auto tmInfo = localtime(&timer); + if (strftime(filename, sizeof(filename), filenameFormat.c_str(), tmInfo) == 0) { + throw std::runtime_error("strftime failed"); } - const utf8 *chatLogPath = _chatLogPath.c_str(); + return Path::Combine(directory, filename); +} - utf8 directory[MAX_PATH]; - Path::GetDirectory(directory, sizeof(directory), chatLogPath); - if (platform_ensure_directory_exists(directory)) { +void Network::AppendLog(const std::string &logPath, const std::string &s) +{ + std::string directory = Path::GetDirectory(logPath); + if (platform_ensure_directory_exists(directory.c_str())) { try { - _chatLogStream = new FileStream(chatLogPath, FILE_MODE_APPEND); + auto fs = FileStream(logPath, FILE_MODE_APPEND); utf8 buffer[256]; time_t timer; - struct tm * tmInfo; time(&timer); - tmInfo = localtime(&timer); - strftime(buffer, sizeof(buffer), "[%Y/%m/%d %H:%M:%S] ", tmInfo); + auto tmInfo = localtime(&timer); + if (strftime(buffer, sizeof(buffer), "[%Y/%m/%d %H:%M:%S] ", tmInfo) != 0) { + String::Append(buffer, sizeof(buffer), s.c_str()); + utf8_remove_formatting(buffer, false); + String::Append(buffer, sizeof(buffer), PLATFORM_NEWLINE); - String::Append(buffer, sizeof(buffer), text); - utf8_remove_formatting(buffer, false); - String::Append(buffer, sizeof(buffer), PLATFORM_NEWLINE); - - _chatLogStream->Write(buffer, strlen(buffer)); - delete _chatLogStream; - _chatLogStream = nullptr; + fs.Write(buffer, strlen(buffer)); + } } - catch (const Exception &) + catch (const Exception &ex) { + log_error("%s", ex.GetMessage()); } } } +void Network::BeginChatLog() +{ + auto directory = _env->GetDirectoryPath(DIRBASE::USER, DIRID::LOG_CHAT); + _chatLogPath = BeginLog(directory, _chatLogFilenameFormat); +} + +void Network::AppendChatLog(const std::string &s) +{ + if (gConfigNetwork.log_chat) { + AppendLog(_chatLogPath, s); + } +} + void Network::CloseChatLog() { } +void Network::BeginServerLog() +{ + auto directory = _env->GetDirectoryPath(DIRBASE::USER, DIRID::LOG_SERVER); + _serverLogPath = BeginLog(directory, (ServerName + _serverLogFilenameFormat)); + + // Log server start event + utf8 logMessage[256]; + if (GetMode() == NETWORK_MODE_CLIENT) { + format_string(logMessage, sizeof(logMessage), STR_LOG_CLIENT_STARTED, NULL); + } else if (GetMode() == NETWORK_MODE_SERVER) { + format_string(logMessage, sizeof(logMessage), STR_LOG_SERVER_STARTED, NULL); + } + AppendServerLog(logMessage); +} + +void Network::AppendServerLog(const std::string &s) +{ + if (gConfigNetwork.log_server_actions) { + AppendLog(_serverLogPath.c_str(), s); + } +} + +void Network::CloseServerLog() +{ + // Log server stopped event + char logMessage[256]; + if (GetMode() == NETWORK_MODE_CLIENT) { + format_string(logMessage, sizeof(logMessage), STR_LOG_CLIENT_STOPPED, NULL); + } else if (GetMode() == NETWORK_MODE_SERVER) { + format_string(logMessage, sizeof(logMessage), STR_LOG_SERVER_STOPPED, NULL); + } + AppendServerLog(logMessage); +} + void Network::Client_Send_TOKEN() { log_verbose("requesting token"); @@ -1292,6 +1337,9 @@ void Network::AddClient(ITcpSocket * socket) { auto connection = std::unique_ptr(new NetworkConnection); // change to make_unique in c++14 connection->Socket = socket; + char addr[128]; + snprintf(addr, sizeof(addr), "Client joined from %s", socket->GetHostName()); + AppendServerLog(addr); client_connection_list.push_back(std::move(connection)); } @@ -1317,6 +1365,9 @@ void Network::RemoveClient(std::unique_ptr& connection) game_do_command(pickup_peep->sprite_index, GAME_COMMAND_FLAG_APPLY, 1, 0, pickup_peep->type == PEEP_TYPE_GUEST ? GAME_COMMAND_PICKUP_GUEST : GAME_COMMAND_PICKUP_STAFF, network_get_pickup_peep_old_x(connection_player->Id), 0); } gNetwork.Server_Send_EVENT_PLAYER_DISCONNECTED((char*)connection_player->Name.c_str(), connection->GetLastDisconnectReason()); + + // Log player disconnected event + AppendServerLog(text); } player_list.erase(std::remove_if(player_list.begin(), player_list.end(), [connection_player](std::unique_ptr& player){ return player.get() == connection_player; @@ -1516,6 +1567,9 @@ void Network::Server_Client_Joined(const char* name, const std::string &keyhash, IObjectManager * objManager = GetObjectManager(); auto objects = objManager->GetPackableObjects(); Server_Send_OBJECTS(connection, objects); + + // Log player joining event + AppendServerLog(text); } } @@ -2138,9 +2192,9 @@ void Network::Client_Handle_GAMEINFO(NetworkConnection& connection, NetworkPacke network_chat_show_server_greeting(); } -sint32 network_init() +void network_set_env(void * env) { - return gNetwork.Init(); + gNetwork.SetEnvironment((IPlatformEnvironment *)env); } void network_close() @@ -2375,6 +2429,18 @@ void game_command_set_player_group(sint32* eax, sint32* ebx, sint32* ecx, sint32 } window_invalidate_by_number(WC_PLAYER, playerid); + + // Log set player group event + NetworkPlayer* game_command_player = gNetwork.GetPlayerByID(game_command_playerid); + NetworkGroup* new_player_group = gNetwork.GetGroupByID(groupid); + char log_msg[256]; + const char * args[3] = { + (char *) player->Name.c_str(), + (char *) new_player_group->GetName().c_str(), + (char *) game_command_player->Name.c_str() + }; + format_string(log_msg, 256, STR_LOG_SET_PLAYER_GROUP, args); + network_append_server_log(log_msg); } *ebx = 0; } @@ -2385,9 +2451,6 @@ void game_command_modify_groups(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *e uint8 groupid = (uint8)(*eax >> 8); uint8 nameChunkIndex = (uint8)(*eax >> 16); - char oldName[128] = { 0 }; - static char newName[128]; - switch (action) { case 0:{ // add group @@ -2399,6 +2462,16 @@ void game_command_modify_groups(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *e *ebx = MONEY32_UNDEFINED; return; } + + // Log add player group event + NetworkPlayer* game_command_player = gNetwork.GetPlayerByID(game_command_playerid); + char log_msg[256]; + const char * args[2] = { + (char *) game_command_player->Name.c_str(), + (char *) newgroup->GetName().c_str() + }; + format_string(log_msg, 256, STR_LOG_ADD_PLAYER_GROUP, args); + network_append_server_log(log_msg); } }break; case 1:{ // remove group @@ -2417,6 +2490,18 @@ void game_command_modify_groups(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *e } } if (*ebx & GAME_COMMAND_FLAG_APPLY) { + // Log remove player group event + NetworkPlayer* game_command_player = gNetwork.GetPlayerByID(game_command_playerid); + NetworkGroup* group = gNetwork.GetGroupByID(groupid); + char* groupName = (char *)group->GetName().c_str(); + char log_msg[256]; + const char * args[2] = { + (char *) game_command_player->Name.c_str(), + groupName + }; + format_string(log_msg, 256, STR_LOG_REMOVE_PLAYER_GROUP, args); + network_append_server_log(log_msg); + gNetwork.RemoveGroup(groupid); } }break; @@ -2456,9 +2541,22 @@ void game_command_modify_groups(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *e group->ToggleActionPermission(index); } } + + // Log edit player group permissions event + char log_msg[256]; + const char * args[2] = { + (char *) player->Name.c_str(), + (char *) group->GetName().c_str() + }; + format_string(log_msg, 256, STR_LOG_EDIT_PLAYER_GROUP_PERMISSIONS, args); + network_append_server_log(log_msg); } }break; case 3:{ // set group name + NetworkGroup* group = gNetwork.GetGroupByID(groupid); + const char * oldName = group->GetName().c_str(); + static char newName[128]; + size_t nameChunkOffset = nameChunkIndex - 1; if (nameChunkIndex == 0) nameChunkOffset = 2; @@ -2486,8 +2584,18 @@ void game_command_modify_groups(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *e } if (*ebx & GAME_COMMAND_FLAG_APPLY) { - NetworkGroup* group = gNetwork.GetGroupByID(groupid); if (group) { + // Log edit player group name event + NetworkPlayer* player = gNetwork.GetPlayerByID(game_command_playerid); + char log_msg[256]; + const char * args[3] = { + (char *) player->Name.c_str(), + oldName, + newName + }; + format_string(log_msg, 256, STR_LOG_EDIT_PLAYER_GROUP_NAME, args); + network_append_server_log(log_msg); + group->SetName(newName); } } @@ -2501,6 +2609,17 @@ void game_command_modify_groups(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *e } if (*ebx & GAME_COMMAND_FLAG_APPLY) { gNetwork.SetDefaultGroup(groupid); + + // Log edit default player group event + NetworkPlayer* player = gNetwork.GetPlayerByID(game_command_playerid); + NetworkGroup* group = gNetwork.GetGroupByID(groupid); + char log_msg[256]; + const char * args[2] = { + (char *) player->Name.c_str(), + (char *) group->GetName().c_str() + }; + format_string(log_msg, 256, STR_LOG_EDIT_DEFAULT_PLAYER_GROUP, args); + network_append_server_log(log_msg); } }break; } @@ -2529,6 +2648,16 @@ void game_command_kick_player(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *edx networkUserManager->RemoveUser(player->KeyHash); networkUserManager->Save(); } + + // Log kick player event + NetworkPlayer* kicker = gNetwork.GetPlayerByID(game_command_playerid); + char log_msg[256]; + const char * args[2] = { + (char *) player->Name.c_str(), + (char *) kicker->Name.c_str(), + }; + format_string(log_msg, 256, STR_LOG_PLAYER_KICKED, args); + network_append_server_log(log_msg); } *ebx = 0; } @@ -2657,6 +2786,11 @@ void network_append_chat_log(const utf8 *text) gNetwork.AppendChatLog(text); } +void network_append_server_log(const utf8 *text) +{ + gNetwork.AppendServerLog(text); +} + static void network_get_keys_directory(utf8 *buffer, size_t bufferSize) { platform_get_user_directory(buffer, "keys", bufferSize); @@ -2729,11 +2863,13 @@ sint32 network_get_pickup_peep_old_x(uint8 playerid) { return _pickup_peep_old_x void network_send_chat(const char* text) {} void network_send_password(const char* password) {} void network_close() {} +void network_set_env(void * env) {} void network_shutdown_client() {} void network_set_password(const char* password) {} uint8 network_get_current_player_id() { return 0; } sint32 network_get_current_player_group_index() { return 0; } void network_append_chat_log(const utf8 *text) { } +void network_append_server_log(const utf8 *text) { } const utf8 * network_get_server_name() { return nullptr; } const utf8 * network_get_server_description() { return nullptr; } const utf8 * network_get_server_greeting() { return nullptr; } diff --git a/src/openrct2/network/network.h b/src/openrct2/network/network.h index b38209f082..01fa4aff51 100644 --- a/src/openrct2/network/network.h +++ b/src/openrct2/network/network.h @@ -85,13 +85,15 @@ enum { NETWORK_TICK_FLAG_CHECKSUMS = 1 << 0, }; -struct ObjectRepositoryItem; +interface IPlatformEnvironment; +struct ObjectRepositoryItem; class Network { public: Network(); ~Network(); + void SetEnvironment(IPlatformEnvironment * env); bool Init(); void Close(); bool BeginClient(const char* host, uint16 port); @@ -120,10 +122,17 @@ public: void SaveGroups(); void LoadGroups(); + std::string BeginLog(const std::string &directory, const std::string &filenameFormat); + void AppendLog(const std::string &logPath, const std::string &s); + void BeginChatLog(); - void AppendChatLog(const utf8 *text); + void AppendChatLog(const std::string &s); void CloseChatLog(); + void BeginServerLog(); + void AppendServerLog(const std::string &s); + void CloseServerLog(); + void Client_Send_TOKEN(); void Client_Send_AUTH(const char* name, const char* password, const char *pubkey, const char *sig, size_t sigsize); void Client_Send_AUTH(const char* name, const char* password, const char *pubkey); @@ -217,9 +226,12 @@ private: INetworkServerAdvertiser * _advertiser = nullptr; uint32 server_connect_time = 0; uint8 default_group = 0; - IStream * _chatLogStream = nullptr; - std::string _chatLogPath; uint32 game_commands_processed_this_tick = 0; + std::string _chatLogPath; + std::string _chatLogFilenameFormat = "%Y%m%d-%H%M%S.txt"; + std::string _serverLogPath; + std::string _serverLogFilenameFormat = "-%Y%m%d-%H%M%S.txt"; + IPlatformEnvironment * _env; void UpdateServer(); void UpdateClient(); @@ -262,7 +274,7 @@ private: #ifdef __cplusplus extern "C" { #endif // __cplusplus -sint32 network_init(); +void network_set_env(void * env); void network_close(); void network_shutdown_client(); sint32 network_begin_client(const char *host, sint32 port); @@ -316,6 +328,7 @@ void network_set_password(const char* password); void network_print_error(); void network_append_chat_log(const utf8 *text); +void network_append_server_log(const utf8 *text); const utf8 * network_get_server_name(); const utf8 * network_get_server_description(); const utf8 * network_get_server_greeting(); diff --git a/src/openrct2/ride/ride.c b/src/openrct2/ride/ride.c index 481a90553f..1b8d1e4a67 100644 --- a/src/openrct2/ride/ride.c +++ b/src/openrct2/ride/ride.c @@ -5594,6 +5594,22 @@ void game_command_set_ride_name(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *e } if (*ebx & GAME_COMMAND_FLAG_APPLY) { + // Log ride rename command if we are in multiplayer and logging is enabled + if ((network_get_mode() == NETWORK_MODE_CLIENT || network_get_mode() == NETWORK_MODE_SERVER) && gConfigNetwork.log_server_actions) { + // Get player name + int player_index = network_get_player_index(game_command_playerid); + const char* player_name = network_get_player_name(player_index); + + char log_msg[256]; + char* args[3] = { + (char *) player_name, + oldName, + newName + }; + format_string(log_msg, 256, STR_LOG_RIDE_NAME, args); + network_append_server_log(log_msg); + } + if (ride->overall_view != (uint16)-1) { rct_xyz16 coord; coord.x = (ride->overall_view & 0xFF) * 32 + 16; @@ -6158,6 +6174,10 @@ foundRideEntry: ride_set_vehicle_colours_to_random_preset(ride, 0xFF & (*outRideColour >> 8)); window_invalidate_by_class(WC_RIDE_LIST); + // Log ride creation + int ebp = 1; + game_log_multiplayer_command(GAME_COMMAND_CREATE_RIDE, 0, 0, 0, &rideIndex, 0, &ebp); + gCommandExpenditureType = RCT_EXPENDITURE_TYPE_RIDE_CONSTRUCTION; gCommandPosition.x = 0x8000; return 0; diff --git a/src/openrct2/windows/cheats.c b/src/openrct2/windows/cheats.c index fbfdccd708..a0d23552b1 100644 --- a/src/openrct2/windows/cheats.c +++ b/src/openrct2/windows/cheats.c @@ -746,10 +746,10 @@ static void window_cheats_misc_mouseup(rct_window *w, rct_widgetindex widgetInde game_do_command(0, GAME_COMMAND_FLAG_APPLY, CHEAT_RESETDATE, 0, GAME_COMMAND_CHEAT, 0, 0); break; case WIDX_FAST_STAFF: - game_do_command(0, GAME_COMMAND_FLAG_APPLY, CHEAT_SETSTAFFSPEED, 0xFF, GAME_COMMAND_CHEAT, 0, 0); + game_do_command(0, GAME_COMMAND_FLAG_APPLY, CHEAT_SETSTAFFSPEED, CHEATS_STAFF_FAST_SPEED, GAME_COMMAND_CHEAT, 0, 0); break; case WIDX_NORMAL_STAFF: - game_do_command(0, GAME_COMMAND_FLAG_APPLY, CHEAT_SETSTAFFSPEED, 0x60, GAME_COMMAND_CHEAT, 0, 0); + game_do_command(0, GAME_COMMAND_FLAG_APPLY, CHEAT_SETSTAFFSPEED, CHEATS_STAFF_NORMAL_SPEED, GAME_COMMAND_CHEAT, 0, 0); break; case WIDX_PARK_PARAMETERS: window_editor_scenario_options_open(); diff --git a/src/openrct2/windows/demolish_ride_prompt.c b/src/openrct2/windows/demolish_ride_prompt.c index a04aaf144c..67a2c53e95 100644 --- a/src/openrct2/windows/demolish_ride_prompt.c +++ b/src/openrct2/windows/demolish_ride_prompt.c @@ -105,7 +105,7 @@ static void window_ride_demolish_mouseup(rct_window *w, rct_widgetindex widgetIn switch (widgetIndex) { case WIDX_DEMOLISH: gGameCommandErrorTitle = STR_CANT_DEMOLISH_RIDE; - game_do_command(0, 1, 0, w->number, GAME_COMMAND_DEMOLISH_RIDE, 0, 0); + game_do_command(0, 1, 0, w->number, GAME_COMMAND_DEMOLISH_RIDE, 0, 1); // Set ebp to 1 to be used to log demolish from window prompt break; case WIDX_CANCEL: case WIDX_CLOSE: diff --git a/src/openrct2/windows/multiplayer.c b/src/openrct2/windows/multiplayer.c index 45c4be79ab..cb5858ea5b 100644 --- a/src/openrct2/windows/multiplayer.c +++ b/src/openrct2/windows/multiplayer.c @@ -52,6 +52,7 @@ enum WINDOW_MULTIPLAYER_WIDGET_IDX { WIDX_PERMISSIONS_LIST, WIDX_LOG_CHAT_CHECKBOX = 8, + WIDX_LOG_SERVER_ACTIONS_CHECKBOX, WIDX_KNOWN_KEYS_ONLY_CHECKBOX, }; @@ -92,7 +93,8 @@ static rct_widget window_multiplayer_groups_widgets[] = { static rct_widget window_multiplayer_options_widgets[] = { MAIN_MULTIPLAYER_WIDGETS, { WWT_CHECKBOX, 1, 3, 297, 50, 61, STR_LOG_CHAT, STR_LOG_CHAT_TIP }, - { WWT_CHECKBOX, 1, 3, 297, 64, 75, STR_ALLOW_KNOWN_KEYS_ONLY, STR_ALLOW_KNOWN_KEYS_ONLY_TIP }, + { WWT_CHECKBOX, 1, 3, 297, 64, 75, STR_LOG_SERVER_ACTIONS, STR_LOG_SERVER_ACTIONS_TIP }, + { WWT_CHECKBOX, 1, 3, 297, 78, 89, STR_ALLOW_KNOWN_KEYS_ONLY, STR_ALLOW_KNOWN_KEYS_ONLY_TIP }, { WIDGETS_END } }; @@ -107,7 +109,7 @@ const uint64 window_multiplayer_page_enabled_widgets[] = { (1 << WIDX_CLOSE) | (1 << WIDX_TAB1) | (1 << WIDX_TAB2) | (1 << WIDX_TAB3) | (1 << WIDX_TAB4), (1 << WIDX_CLOSE) | (1 << WIDX_TAB1) | (1 << WIDX_TAB2) | (1 << WIDX_TAB3) | (1 << WIDX_TAB4), (1 << WIDX_CLOSE) | (1 << WIDX_TAB1) | (1 << WIDX_TAB2) | (1 << WIDX_TAB3) | (1 << WIDX_TAB4) | (1 << WIDX_DEFAULT_GROUP) | (1 << WIDX_DEFAULT_GROUP_DROPDOWN) | (1 << WIDX_ADD_GROUP) | (1 << WIDX_REMOVE_GROUP) | (1 << WIDX_RENAME_GROUP) | (1 << WIDX_SELECTED_GROUP) | (1 << WIDX_SELECTED_GROUP_DROPDOWN), - (1 << WIDX_CLOSE) | (1 << WIDX_TAB1) | (1 << WIDX_TAB2) | (1 << WIDX_TAB3) | (1 << WIDX_TAB4) | (1 << WIDX_LOG_CHAT_CHECKBOX) | (1 << WIDX_KNOWN_KEYS_ONLY_CHECKBOX), + (1 << WIDX_CLOSE) | (1 << WIDX_TAB1) | (1 << WIDX_TAB2) | (1 << WIDX_TAB3) | (1 << WIDX_TAB4) | (1 << WIDX_LOG_CHAT_CHECKBOX) | (1 << WIDX_LOG_SERVER_ACTIONS_CHECKBOX) | (1 << WIDX_KNOWN_KEYS_ONLY_CHECKBOX), }; static uint8 _selectedGroup = 0; @@ -918,6 +920,10 @@ static void window_multiplayer_options_mouseup(rct_window *w, rct_widgetindex wi gConfigNetwork.log_chat = !gConfigNetwork.log_chat; config_save_default(); break; + case WIDX_LOG_SERVER_ACTIONS_CHECKBOX: + gConfigNetwork.log_server_actions = !gConfigNetwork.log_server_actions; + config_save_default(); + break; case WIDX_KNOWN_KEYS_ONLY_CHECKBOX: gConfigNetwork.known_keys_only = !gConfigNetwork.known_keys_only; config_save_default(); @@ -947,6 +953,7 @@ static void window_multiplayer_options_invalidate(rct_window *w) } widget_set_checkbox_value(w, WIDX_LOG_CHAT_CHECKBOX, gConfigNetwork.log_chat); + widget_set_checkbox_value(w, WIDX_LOG_SERVER_ACTIONS_CHECKBOX, gConfigNetwork.log_server_actions); widget_set_checkbox_value(w, WIDX_KNOWN_KEYS_ONLY_CHECKBOX, gConfigNetwork.known_keys_only); } diff --git a/src/openrct2/world/park.c b/src/openrct2/world/park.c index 7cbfd8c0e5..ddbd79be88 100644 --- a/src/openrct2/world/park.c +++ b/src/openrct2/world/park.c @@ -25,6 +25,7 @@ #include "../management/marketing.h" #include "../management/news_item.h" #include "../management/research.h" +#include "../network/network.h" #include "../peep/peep.h" #include "../peep/staff.h" #include "../rct2.h" @@ -840,6 +841,22 @@ void game_command_set_park_name(sint32 *eax, sint32 *ebx, sint32 *ecx, sint32 *e } if (*ebx & GAME_COMMAND_FLAG_APPLY) { + // Log park rename command if we are in multiplayer and logging is enabled + if ((network_get_mode() == NETWORK_MODE_CLIENT || network_get_mode() == NETWORK_MODE_SERVER) && gConfigNetwork.log_server_actions) { + // Get player name + int player_index = network_get_player_index(game_command_playerid); + const char* player_name = network_get_player_name(player_index); + + char log_msg[256]; + char* args[3] = { + (char *) player_name, + oldName, + newName + }; + format_string(log_msg, 256, STR_LOG_PARK_NAME, args); + network_append_server_log(log_msg); + } + // Free the old ride name user_string_free(gParkName); gParkName = newUserStringId;