1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-19 13:03:11 +01:00

Merge pull request #14088 from IntelOrca/improve-network-messages

Improve network messages and logging
This commit is contained in:
Ted John
2021-02-18 13:36:44 +00:00
committed by GitHub
20 changed files with 126 additions and 93 deletions

View File

@@ -11,6 +11,7 @@
#include <openrct2-ui/interface/Widget.h>
#include <openrct2-ui/windows/Window.h>
#include <openrct2/Context.h>
#include <openrct2/core/Console.hpp>
#include <openrct2/core/Http.h>
#include <openrct2/core/Json.hpp>
#include <openrct2/core/String.hpp>
@@ -153,7 +154,7 @@ private:
{
try
{
std::printf("Downloading %s\n", url.c_str());
Console::WriteLine("Downloading %s", url.c_str());
Http::Request req;
req.method = Http::Method::GET;
req.url = url;
@@ -175,14 +176,14 @@ private:
}
else
{
std::printf(" Failed to download %s\n", name.c_str());
Console::Error::WriteLine(" Failed to download %s", name.c_str());
}
QueueNextDownload();
});
}
catch (const std::exception&)
{
std::printf(" Failed to download %s\n", name.c_str());
Console::Error::WriteLine(" Failed to download %s", name.c_str());
QueueNextDownload();
}
}
@@ -226,19 +227,20 @@ private:
}
else if (response.status == Http::Status::NotFound)
{
std::printf(" %s not found\n", name.c_str());
Console::Error::WriteLine(" %s not found", name.c_str());
QueueNextDownload();
}
else
{
std::printf(" %s query failed (status %d)\n", name.c_str(), static_cast<int32_t>(response.status));
Console::Error::WriteLine(
" %s query failed (status %d)", name.c_str(), static_cast<int32_t>(response.status));
QueueNextDownload();
}
});
}
catch (const std::exception&)
{
std::printf(" Failed to query %s\n", name.c_str());
Console::Error::WriteLine(" Failed to query %s", name.c_str());
}
}
};

View File

@@ -273,6 +273,11 @@ namespace OpenRCT2
_stdInOutConsole.WriteLine(s);
}
void WriteErrorLine(const std::string& s) override
{
_stdInOutConsole.WriteLineError(s);
}
/**
* Causes the OpenRCT2 game loop to finish.
*/

View File

@@ -141,6 +141,7 @@ namespace OpenRCT2
virtual bool LoadParkFromStream(
IStream* stream, const std::string& path, bool loadTitleScreenFirstOnFail = false) abstract;
virtual void WriteLine(const std::string& s) abstract;
virtual void WriteErrorLine(const std::string& s) abstract;
virtual void Finish() abstract;
virtual void Quit() abstract;

View File

@@ -9,6 +9,7 @@
#include "Diagnostic.h"
#include "core/Console.hpp"
#include "core/String.hpp"
#include <cstdarg>
@@ -73,6 +74,15 @@ static constexpr const char* _level_strings[] = {
"FATAL", "ERROR", "WARNING", "VERBOSE", "INFO",
};
static void diagnostic_print(DiagnosticLevel level, const std::string& prefix, const std::string& msg)
{
auto stream = diagnostic_get_stream(level);
if (stream == stdout)
Console::WriteLine("%s%s", prefix.c_str(), msg.c_str());
else
Console::Error::WriteLine("%s%s", prefix.c_str(), msg.c_str());
}
void diagnostic_log(DiagnosticLevel diagnosticLevel, const char* format, ...)
{
va_list args;
@@ -86,8 +96,7 @@ void diagnostic_log(DiagnosticLevel diagnosticLevel, const char* format, ...)
auto msg = String::StdFormat_VA(format, args);
va_end(args);
auto stream = diagnostic_get_stream(diagnosticLevel);
fprintf(stream, "%s%s\n", prefix.c_str(), msg.c_str());
diagnostic_print(diagnosticLevel, prefix, msg);
}
}
@@ -114,8 +123,7 @@ void diagnostic_log_with_location(
auto msg = String::StdFormat_VA(format, args);
va_end(args);
auto stream = diagnostic_get_stream(diagnosticLevel);
fprintf(stream, "%s%s\n", prefix.c_str(), msg.c_str());
diagnostic_print(diagnosticLevel, prefix, msg);
}
}

View File

@@ -22,6 +22,7 @@
#include "actions/LoadOrQuitAction.h"
#include "audio/audio.h"
#include "config/Config.h"
#include "core/Console.hpp"
#include "core/FileScanner.h"
#include "core/Path.hpp"
#include "interface/Colour.h"
@@ -762,7 +763,7 @@ void game_autosave()
}
if (!scenario_save(path, saveFlags))
std::fprintf(stderr, "Could not autosave the scenario. Is the save folder writeable?\n");
Console::Error::WriteLine("Could not autosave the scenario. Is the save folder writeable?");
}
static void game_load_or_quit_no_save_prompt_callback(int32_t result, const utf8* path)

View File

@@ -9,6 +9,7 @@
#include "Console.hpp"
#include "../Context.h"
#include "../platform/platform.h"
#include <cstdio>
@@ -49,10 +50,16 @@ namespace Console
void WriteLine(const utf8* format, ...)
{
va_list args;
va_start(args, format);
auto formatLn = std::string(format) + "\n";
vfprintf(stdout, formatLn.c_str(), args);
char buffer[4096];
std::vsnprintf(buffer, sizeof(buffer), format, args);
auto ctx = OpenRCT2::GetContext();
if (ctx != nullptr)
ctx->WriteLine(buffer);
else
std::printf("%s\n", buffer);
va_end(args);
}
@@ -92,8 +99,13 @@ namespace Console
void WriteLine_VA(const utf8* format, va_list args)
{
auto formatLn = std::string(format) + "\n";
vfprintf(stdout, formatLn.c_str(), args);
char buffer[4096];
std::vsnprintf(buffer, sizeof(buffer), format, args);
auto ctx = OpenRCT2::GetContext();
if (ctx != nullptr)
ctx->WriteErrorLine(buffer);
else
std::printf("%s\n", buffer);
}
} // namespace Error
} // namespace Console

View File

@@ -12,6 +12,7 @@
# include "Http.h"
# include "../Version.h"
# include "../core/Console.hpp"
# include "String.hpp"
# include <cstdio>
@@ -226,7 +227,7 @@ namespace Http
catch ([[maybe_unused]] const std::exception& e)
{
# ifdef DEBUG
std::fprintf(stderr, "HTTP request failed: %s\n", e.what());
Console::Error::WriteLine("HTTP request failed: %s", e.what());
# endif
WinHttpCloseHandle(hSession);
WinHttpCloseHandle(hConnect);

View File

@@ -10,6 +10,7 @@
#ifndef _WIN32
# include "RTL.h"
# include <algorithm>
# include <string>
# include <unicode/ubidi.h>
# include <unicode/unistr.h>
@@ -42,6 +43,10 @@ std::string FixRTL(std::string& input)
std::string cppstring;
shaped.toUTF8String(cppstring);
// libicu seems to leave a null terminator on the end
cppstring.erase(std::find(cppstring.begin(), cppstring.end(), '\0'), cppstring.end());
return cppstring;
}
#endif

View File

@@ -53,6 +53,7 @@ class StdInOutConsole final : public InteractiveConsole
{
private:
std::queue<std::tuple<std::promise<void>, std::string>> _evalQueue;
bool _isPromptShowing{};
public:
void Start();

View File

@@ -510,7 +510,7 @@ static void benchgfx_render_screenshots(const char* inputPath, std::unique_ptr<I
}
catch (const std::exception& e)
{
std::fprintf(stderr, "%s", e.what());
Console::Error::WriteLine("%s", e.what());
}
for (auto& dpi : dpis)

View File

@@ -24,8 +24,8 @@ using namespace OpenRCT2;
void StdInOutConsole::Start()
{
// Only start if stdin is a TTY
if (!isatty(fileno(stdin)))
// Only start if stdin/stdout is a TTY
if (!isatty(fileno(stdin)) || !isatty(fileno(stdout)))
{
return;
}
@@ -40,7 +40,9 @@ void StdInOutConsole::Start()
{
std::string line;
std::string left = prompt;
_isPromptShowing = true;
auto quit = linenoise::Readline(left.c_str(), line);
_isPromptShowing = false;
if (quit)
{
if (lastPromptQuit)
@@ -51,7 +53,7 @@ void StdInOutConsole::Start()
else
{
lastPromptQuit = true;
std::puts("(To exit, press ^C again or type exit)");
std::puts("(To exit, press ^C again)");
}
}
else
@@ -123,12 +125,23 @@ void StdInOutConsole::WriteLine(const std::string& s, FormatToken colourFormat)
break;
}
if (formatBegin.empty() || !Platform::IsColourTerminalSupported())
if (!Platform::IsColourTerminalSupported())
{
std::printf("%s\n", s.c_str());
std::fflush(stdout);
}
else
{
std::printf("%s%s%s\n", formatBegin.c_str(), s.c_str(), "\x1b[0m");
if (_isPromptShowing)
{
std::printf("\r%s%s\x1b[0m\x1b[0K\r\n", formatBegin.c_str(), s.c_str());
std::fflush(stdout);
linenoise::linenoiseEditRefreshLine();
}
else
{
std::printf("%s%s\x1b[0m\n", formatBegin.c_str(), s.c_str());
std::fflush(stdout);
}
}
}

View File

@@ -390,7 +390,8 @@ bool NetworkBase::BeginServer(uint16_t port, const std::string& address)
_userManager.Save();
}
printf("Ready for clients...\n");
auto* szAddress = address.empty() ? "*" : address.c_str();
Console::WriteLine("Listening for clients on %s:%hu", szAddress, port);
network_chat_show_connected_message();
network_chat_show_server_greeting();

View File

@@ -146,6 +146,10 @@ private:
case ADVERTISE_STATUS::UNREGISTERED:
if (_lastAdvertiseTime == 0 || platform_get_ticks() > _lastAdvertiseTime + MASTER_SERVER_REGISTER_TIME)
{
if (_lastAdvertiseTime == 0)
{
Console::WriteLine("Registering server on master server");
}
SendRegistration(_forceIPv4);
}
break;
@@ -187,7 +191,7 @@ private:
Http::DoAsync(request, [&](Http::Response response) -> void {
if (response.status != Http::Status::Ok)
{
Console::WriteLine("Unable to connect to master server");
Console::Error::WriteLine("Unable to connect to master server");
return;
}
@@ -211,7 +215,7 @@ private:
Http::DoAsync(request, [&](Http::Response response) -> void {
if (response.status != Http::Status::Ok)
{
Console::WriteLine("Unable to connect to master server");
Console::Error::WriteLine("Unable to connect to master server");
return;
}
@@ -233,6 +237,7 @@ private:
if (status == MasterServerStatus::Ok)
{
Console::WriteLine("Server successfully registered on master server");
json_t jsonToken = jsonRoot["token"];
if (jsonToken.is_string())
{
@@ -247,7 +252,11 @@ private:
{
message = "Invalid response from server";
}
Console::Error::WriteLine("Unable to advertise (%d): %s", status, message.c_str());
Console::Error::WriteLine(
"Unable to advertise (%d): %s\n * Check that you have port forwarded %uh\n * Try setting "
"advertise_address in config.ini",
status, message.c_str(), _port);
// Hack for https://github.com/OpenRCT2/OpenRCT2/issues/6277
// Master server may not reply correctly if using IPv6, retry forcing IPv4,
// don't wait the full timeout.
@@ -255,7 +264,7 @@ private:
{
_forceIPv4 = true;
_lastAdvertiseTime = 0;
log_info("Retry with ipv4 only");
log_info("Forcing HTTP(S) over IPv4");
}
}
}
@@ -276,7 +285,7 @@ private:
else if (status == MasterServerStatus::InvalidToken)
{
_status = ADVERTISE_STATUS::UNREGISTERED;
Console::WriteLine("Master server heartbeat failed: Invalid Token");
Console::Error::WriteLine("Master server heartbeat failed: Invalid Token");
}
}

View File

@@ -316,16 +316,14 @@ public:
}
// Turn off IPV6_V6ONLY so we can accept both v4 and v6 connections
int32_t value = 0;
if (setsockopt(_socket, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<const char*>(&value), sizeof(value)) != 0)
if (!SetOption(_socket, IPPROTO_IPV6, IPV6_V6ONLY, false))
{
log_error("IPV6_V6ONLY failed. %d", LAST_SOCKET_ERROR());
log_verbose("setsockopt(socket, IPV6_V6ONLY) failed: %d", LAST_SOCKET_ERROR());
}
value = 1;
if (setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&value), sizeof(value)) != 0)
if (!SetOption(_socket, SOL_SOCKET, SO_REUSEADDR, true))
{
log_error("SO_REUSEADDR failed. %d", LAST_SOCKET_ERROR());
log_verbose("setsockopt(socket, SO_REUSEADDR) failed: %d", LAST_SOCKET_ERROR());
}
try
@@ -333,7 +331,8 @@ public:
// Bind to address:port and listen
if (bind(_socket, reinterpret_cast<sockaddr*>(&ss), ss_len) != 0)
{
throw SocketException("Unable to bind to socket.");
std::string addressOrStar = address.empty() ? "*" : address.c_str();
throw SocketException("Unable to bind to address " + addressOrStar + ":" + std::to_string(port));
}
if (listen(_socket, SOMAXCONN) != 0)
{
@@ -850,18 +849,18 @@ private:
// Enable send and receiving of broadcast messages
if (!SetOption(sock, SOL_SOCKET, SO_BROADCAST, true))
{
log_warning("SO_BROADCAST failed. %d", LAST_SOCKET_ERROR());
log_verbose("setsockopt(socket, SO_BROADCAST) failed: %d", LAST_SOCKET_ERROR());
}
// Turn off IPV6_V6ONLY so we can accept both v4 and v6 connections
if (!SetOption(sock, IPPROTO_IPV6, IPV6_V6ONLY, false))
if (!SetOption(_socket, IPPROTO_IPV6, IPV6_V6ONLY, false))
{
log_warning("IPV6_V6ONLY failed. %d", LAST_SOCKET_ERROR());
log_verbose("setsockopt(socket, IPV6_V6ONLY) failed: %d", LAST_SOCKET_ERROR());
}
if (!SetOption(sock, SOL_SOCKET, SO_REUSEADDR, true))
if (!SetOption(_socket, SOL_SOCKET, SO_REUSEADDR, true))
{
log_warning("SO_REUSEADDR failed. %d", LAST_SOCKET_ERROR());
log_verbose("setsockopt(socket, SO_REUSEADDR) failed: %d", LAST_SOCKET_ERROR());
}
if (!SetNonBlocking(sock, true))

View File

@@ -11,6 +11,7 @@
#ifdef ENABLE_SCRIPTING
# include "../core/Console.hpp"
# include "../world/Map.h"
# include <cstdio>
@@ -195,7 +196,7 @@ namespace OpenRCT2::Scripting
{
duk_set_top(_ctx, _top);
_ctx = {};
std::fprintf(stderr, "duktape stack was not returned to original state!");
Console::Error::WriteLine("duktape stack was not returned to original state!");
}
_ctx = {};
}

View File

@@ -528,7 +528,7 @@ void ScriptEngine::SetupHotReloading()
}
catch (const std::exception& e)
{
std::fprintf(stderr, "Unable to enable hot reloading of plugins: %s\n", e.what());
Console::Error::WriteLine("Unable to enable hot reloading of plugins: %s", e.what());
}
}
@@ -1199,7 +1199,7 @@ void ScriptEngine::LoadSharedStorage()
}
catch (const std::exception&)
{
fprintf(stderr, "Unable to read '%s'\n", path.c_str());
Console::Error::WriteLine("Unable to read '%s'", path.c_str());
}
}
@@ -1216,7 +1216,7 @@ void ScriptEngine::SaveSharedStorage()
}
catch (const std::exception&)
{
fprintf(stderr, "Unable to write to '%s'\n", path.c_str());
Console::Error::WriteLine("Unable to write to '%s'", path.c_str());
}
}

View File

@@ -1094,6 +1094,8 @@ struct linenoiseState {
int history_index; /* The history index we are currently editing. */
};
static struct linenoiseState lnstate;
enum KEY_ACTION {
KEY_NULL = 0, /* NULL */
CTRL_A = 1, /* Ctrl+a */
@@ -2088,6 +2090,11 @@ inline void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
refreshLine(l);
}
inline void linenoiseEditRefreshLine()
{
refreshLine(&lnstate);
}
/* This function is the core of the line editing capability of linenoise.
* It expects 'fd' to be already in "raw mode" so that every key pressed
* will be returned ASAP to read().
@@ -2098,7 +2105,7 @@ inline void linenoiseEditDeletePrevWord(struct linenoiseState *l) {
* The function returns the length of the current buffer. */
inline int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, int buflen, const char *prompt)
{
struct linenoiseState l;
auto& l = lnstate;
/* Populate the linenoise state that we pass to functions implementing
* specific editing functionalities. */

View File

@@ -9,6 +9,7 @@
#include "Addresses.h"
#include <openrct2/Context.h>
#include <openrct2/config/Config.h>
#include <openrct2/interface/Colour.h>
#include <openrct2/interface/Viewport.h>
@@ -884,3 +885,11 @@ void TileElementBase::SetOwner(uint8_t newOwner)
owner &= ~OWNER_MASK;
owner |= (newOwner & OWNER_MASK);
}
namespace OpenRCT2
{
IContext* GetContext()
{
return nullptr;
}
} // namespace OpenRCT2

View File

@@ -105,34 +105,22 @@ endif ()
set(SAWYERCODING_TEST_SOURCES
"${CMAKE_CURRENT_LIST_DIR}/sawyercoding_test.cpp"
"${ROOT_DIR}/src/openrct2/core/IStream.cpp"
"${ROOT_DIR}/src/openrct2/core/MemoryStream.cpp"
"${ROOT_DIR}/src/openrct2/rct12/SawyerChunk.cpp"
"${ROOT_DIR}/src/openrct2/rct12/SawyerChunkReader.cpp"
"${ROOT_DIR}/src/openrct2/util/SawyerCoding.cpp"
)
add_executable(test_sawyercoding ${SAWYERCODING_TEST_SOURCES})
target_link_libraries(test_sawyercoding ${GTEST_LIBRARIES} test-common ${LDL} z)
target_link_libraries(test_sawyercoding ${GTEST_LIBRARIES} libopenrct2 ${LDL} z)
target_link_platform_libraries(test_sawyercoding)
add_test(NAME sawyercoding COMMAND test_sawyercoding)
# LanguagePack test
set(LANGUAGEPACK_TEST_SOURCES
"${CMAKE_CURRENT_LIST_DIR}/LanguagePackTest.cpp"
"${ROOT_DIR}/src/openrct2/localisation/LanguagePack.cpp"
"${ROOT_DIR}/src/openrct2/core/FileStream.cpp"
"${ROOT_DIR}/src/openrct2/core/Path.cpp"
"${ROOT_DIR}/src/openrct2/core/RTL.FriBidi.cpp"
"${ROOT_DIR}/src/openrct2/core/RTL.ICU.cpp"
"${ROOT_DIR}/src/openrct2/core/StringBuilder.cpp"
"${ROOT_DIR}/src/openrct2/core/StringReader.cpp"
)
add_executable(test_languagepack ${LANGUAGEPACK_TEST_SOURCES})
if (UNIX AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "BSD")
# Include libdl for dlopen
set(LDL dl)
endif ()
target_link_libraries(test_languagepack ${GTEST_LIBRARIES} test-common ${LDL} z)
target_link_libraries(test_languagepack ${GTEST_LIBRARIES} libopenrct2 ${LDL} z)
target_link_platform_libraries(test_languagepack)
add_test(NAME languagepack COMMAND test_languagepack)
@@ -140,16 +128,10 @@ add_test(NAME languagepack COMMAND test_languagepack)
set(INI_TEST_SOURCES
"${CMAKE_CURRENT_LIST_DIR}/IniWriterTest.cpp"
"${CMAKE_CURRENT_LIST_DIR}/IniReaderTest.cpp"
"${ROOT_DIR}/src/openrct2/config/IniReader.cpp"
"${ROOT_DIR}/src/openrct2/config/IniWriter.cpp"
"${ROOT_DIR}/src/openrct2/core/IStream.cpp"
"${ROOT_DIR}/src/openrct2/core/MemoryStream.cpp"
"${ROOT_DIR}/src/openrct2/core/StringBuilder.cpp"
"${ROOT_DIR}/src/openrct2/core/StringReader.cpp"
)
add_executable(test_ini ${INI_TEST_SOURCES})
SET_CHECK_CXX_FLAGS(test_ini)
target_link_libraries(test_ini ${GTEST_LIBRARIES} test-common ${LDL} z)
target_link_libraries(test_ini ${GTEST_LIBRARIES} libopenrct2 ${LDL} z)
target_link_platform_libraries(test_ini)
add_test(NAME ini COMMAND test_ini)
@@ -166,7 +148,7 @@ set(STRING_TEST_SOURCES
)
add_executable(test_string ${STRING_TEST_SOURCES})
SET_CHECK_CXX_FLAGS(test_string)
target_link_libraries(test_string ${GTEST_LIBRARIES} test-common ${LDL} z)
target_link_libraries(test_string ${GTEST_LIBRARIES} libopenrct2 ${LDL} z)
target_link_platform_libraries(test_string)
add_test(NAME string COMMAND test_string)
@@ -182,7 +164,7 @@ add_test(NAME formatting COMMAND test_formatting)
set(STRING_TEST_SOURCES "${CMAKE_CURRENT_LIST_DIR}/Localisation.cpp")
add_executable(test_localisation ${STRING_TEST_SOURCES})
SET_CHECK_CXX_FLAGS(test_localisation)
target_link_libraries(test_localisation ${GTEST_LIBRARIES} test-common ${LDL} z)
target_link_libraries(test_localisation ${GTEST_LIBRARIES} libopenrct2 ${LDL} z)
target_link_platform_libraries(test_localisation)
add_test(NAME localisation COMMAND test_localisation)

View File

@@ -14,13 +14,6 @@
#include <gtest/gtest.h>
#ifndef _WIN32
# include "openrct2/core/File.h"
# include "openrct2/platform/platform.h"
const language_descriptor LanguagesDescriptors[] = {};
#endif
class LanguagePackTest : public testing::Test
{
protected:
@@ -127,20 +120,3 @@ const unsigned char LanguagePackTest::LanguageZhTW[] = {
0x59, 0x20, 0x20, 0x20, 0x20, 0x3a, 0xe6, 0xaf, 0x8f, 0xe8, 0xbb, 0x8a, 0xe5, 0x8d, 0xa1, 0x34, 0xe4, 0xbd, 0x8d, 0xe4,
0xb9, 0x98, 0xe5, 0xae, 0xa2, 0x0a, 0x00,
};
#ifndef _WIN32
bool platform_ensure_directory_exists(const utf8* path)
{
return true;
}
bool platform_directory_exists(const utf8* path)
{
return true;
}
bool File::Exists(const std::string& path)
{
return true;
}
#endif