Merge branch 'master' into jgrpp

# Conflicts:
#	.github/workflows/ci-build.yml
#	.github/workflows/release-source.yml
#	CMakeLists.txt
#	COMPILING.md
#	src/network/network_survey.cpp
#	src/network/network_survey.h
#	src/openttd.cpp
#	src/tests/CMakeLists.txt
This commit is contained in:
Jonathan G Rennison
2023-11-17 19:16:55 +00:00
21 changed files with 217 additions and 103 deletions

View File

@@ -285,6 +285,76 @@ public:
#endif /* defined(WITH_FREETYPE) */
#if defined(__EMSCRIPTEN__)
# include <emscripten.h>
# include "network/network.h"
# include "network/network_content.h"
# include "openttd.h"
# include "video/video_driver.hpp"
class BootstrapEmscripten : public ContentCallback {
bool downloading{false};
uint total_files{0};
uint total_bytes{0};
uint downloaded_bytes{0};
public:
BootstrapEmscripten()
{
_network_content_client.AddCallback(this);
_network_content_client.Connect();
}
~BootstrapEmscripten()
{
_network_content_client.RemoveCallback(this);
}
void OnConnect(bool success) override
{
if (!success) {
EM_ASM({ if (window["openttd_bootstrap_failed"]) openttd_bootstrap_failed(); });
return;
}
/* Once connected, request the metadata. */
_network_content_client.RequestContentList(CONTENT_TYPE_BASE_GRAPHICS);
}
void OnReceiveContentInfo(const ContentInfo *ci) override
{
if (this->downloading) return;
/* And once the metadata is received, start downloading it. */
_network_content_client.Select(ci->id);
_network_content_client.DownloadSelectedContent(this->total_files, this->total_bytes);
this->downloading = true;
EM_ASM({ if (window["openttd_bootstrap"]) openttd_bootstrap($0, $1); }, this->downloaded_bytes, this->total_bytes);
}
void OnDownloadProgress(const ContentInfo *ci, int bytes) override
{
/* A negative value means we are resetting; for example, when retrying or using a fallback. */
if (bytes < 0) {
this->downloaded_bytes = 0;
} else {
this->downloaded_bytes += bytes;
}
EM_ASM({ if (window["openttd_bootstrap"]) openttd_bootstrap($0, $1); }, this->downloaded_bytes, this->total_bytes);
}
void OnDownloadComplete(ContentID cid) override
{
/* _exit_game is used to break out of the outer video driver's MainLoop. */
_exit_game = true;
delete this;
}
};
#endif /* __EMSCRIPTEN__ */
/**
* Handle all procedures for bootstrapping OpenTTD without a base graphics set.
* This requires all kinds of trickery that is needed to avoid the use of
@@ -299,12 +369,15 @@ bool HandleBootstrap()
if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) goto failure;
/* If there is no network or no non-sprite font, then there is nothing we can do. Go straight to failure. */
#if (defined(_WIN32) && defined(WITH_UNISCRIBE)) || (defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(__APPLE__))) || defined(WITH_COCOA)
#if defined(__EMSCRIPTEN__) || (defined(_WIN32) && defined(WITH_UNISCRIBE)) || (defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(__APPLE__))) || defined(WITH_COCOA)
if (!_network_available) goto failure;
/* First tell the game we're bootstrapping. */
_game_mode = GM_BOOTSTRAP;
#if defined(__EMSCRIPTEN__)
new BootstrapEmscripten();
#else
/* Initialise the font cache. */
InitializeUnicodeGlyphMap();
/* Next "force" finding a suitable non-sprite font as the local font is missing. */
@@ -323,6 +396,7 @@ bool HandleBootstrap()
/* Finally ask the question. */
new BootstrapBackground();
new BootstrapAskForDownloadWindow();
#endif /* __EMSCRIPTEN__ */
/* Process the user events. */
VideoDriver::GetInstance()->MainLoop();

View File

@@ -1187,7 +1187,7 @@ STR_TERRAIN_TYPE_CUSTOM :Alçada persona
STR_TERRAIN_TYPE_CUSTOM_VALUE :Alçada personalitzada ({NUM})
###length 4
STR_CITY_APPROVAL_LENIENT :Tolerant
STR_CITY_APPROVAL_LENIENT :Indulgent
STR_CITY_APPROVAL_TOLERANT :Tolerant
STR_CITY_APPROVAL_HOSTILE :Hostil
STR_CITY_APPROVAL_PERMISSIVE :Permissiva (les accions de les companyies no l'afecten)
@@ -2651,6 +2651,7 @@ STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Commuta
STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Commuta la transparència dels ponts. Ctrl+Clic per bloquejar
STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Commuta la transparència de les estructures com ara fars i antenes. Ctrl+Clic per bloquejar
STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Commuta la transparència de la catenària. CTRL+clic per bloquejar
STR_TRANSPARENT_TEXT_TOOLTIP :{BLACK}Commuta la transparència dels indicadors de càrrega i el text de despesa/ingrés. Ctrl+Clic per a blocar.
STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Alternar entre transparència i invisibilitat dels objectes
# Linkgraph legend window

View File

@@ -2650,6 +2650,7 @@ STR_TRANSPARENT_BUILDINGS_TOOLTIP :{BLACK}Transpar
STR_TRANSPARENT_BRIDGES_TOOLTIP :{BLACK}Transparantie voor bruggen aan-uit. Ctrl+klik om vast te zetten.
STR_TRANSPARENT_STRUCTURES_TOOLTIP :{BLACK}Transparantie voor gebouwen zoals vuurtorens en zendmasten aan-uit. Ctrl+klik om vast te zetten.
STR_TRANSPARENT_CATENARY_TOOLTIP :{BLACK}Transparantie voor bovenleiding aan-uit. Ctrl+klik om vast te zetten.
STR_TRANSPARENT_TEXT_TOOLTIP :{BLACK}Transparantie omschakelen voor teksten bij laden en kosten/inkomsten. Ctrl+klik om vast te zetten
STR_TRANSPARENT_INVISIBLE_TOOLTIP :{BLACK}Maak objecten onzichtbaar in plaats van transparant
# Linkgraph legend window

View File

@@ -37,9 +37,7 @@
#include "../base_media_base.h"
#include "../blitter/factory.hpp"
#ifdef WITH_NLOHMANN_JSON
#include <nlohmann/json.hpp>
#endif /* WITH_NLOHMANN_JSON */
#include "../safeguards.h"
@@ -47,8 +45,6 @@ extern std::string _savegame_id;
NetworkSurveyHandler _survey = {};
#ifdef WITH_NLOHMANN_JSON
NLOHMANN_JSON_SERIALIZE_ENUM(NetworkSurveyHandler::Reason, {
{NetworkSurveyHandler::Reason::PREVIEW, "preview"},
{NetworkSurveyHandler::Reason::LEAVE, "leave"},
@@ -114,8 +110,12 @@ static void SurveySettings(nlohmann::json &survey)
*/
static void SurveyOpenTTD(nlohmann::json &survey)
{
survey["version"] = std::string(_openttd_revision);
survey["newgrf_version"] = _openttd_newgrf_version;
survey["version"]["revision"] = std::string(_openttd_revision);
survey["version"]["modified"] = _openttd_revision_modified;
survey["version"]["tagged"] = _openttd_revision_tagged;
survey["version"]["hash"] = std::string(_openttd_revision_hash);
survey["version"]["newgrf"] = fmt::format("{:X}", _openttd_newgrf_version);
survey["version"]["content"] = std::string(_openttd_content_version);
survey["build_date"] = std::string(_openttd_build_date);
survey["bits"] =
#ifdef POINTER_IS_64BIT
@@ -227,6 +227,21 @@ static void SurveyCompanies(nlohmann::json &survey)
}
}
/**
* Convert timer information to JSON.
*
* @param survey The JSON object.
*/
static void SurveyTimers(nlohmann::json &survey)
{
survey["ticks"] = _scaled_tick_counter;
survey["seconds"] = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - _switch_mode_time).count();
YearMonthDay ymd;
ConvertDateToYMD(_date, &ymd);
survey["calendar"] = fmt::format("{:04}-{:02}-{:02} ({})", ymd.year, ymd.month + 1, ymd.day, _date_fract);
}
/**
* Convert GRF information to JSON.
*
@@ -298,8 +313,6 @@ std::string SurveyMemoryToText(uint64_t memory)
return fmt::format("{} MiB", Ceil(memory, 4));
}
#endif /* WITH_NLOHMANN_JSON */
/**
* Create the payload for the survey.
*
@@ -309,9 +322,6 @@ std::string SurveyMemoryToText(uint64_t memory)
*/
std::string NetworkSurveyHandler::CreatePayload(Reason reason, bool for_preview)
{
#ifndef WITH_NLOHMANN_JSON
return "";
#else
nlohmann::json survey;
survey["schema"] = NETWORK_SURVEY_VERSION;
@@ -335,8 +345,7 @@ std::string NetworkSurveyHandler::CreatePayload(Reason reason, bool for_preview)
{
auto &game = survey["game"];
game["ticks"] = _scaled_tick_counter;
game["time"] = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - _switch_mode_time).count();
SurveyTimers(game["timers"]);
SurveyCompanies(game["companies"]);
SurveySettings(game["settings"]);
SurveyGrfs(game["grfs"]);
@@ -346,7 +355,6 @@ std::string NetworkSurveyHandler::CreatePayload(Reason reason, bool for_preview)
/* For preview, we indent with 4 whitespaces to make things more readable. */
int indent = for_preview ? 4 : -1;
return survey.dump(indent);
#endif /* WITH_NLOHMANN_JSON */
}
/**

View File

@@ -40,12 +40,12 @@ public:
constexpr static bool IsSurveyPossible()
{
#if !(defined(WITH_NLOHMANN_JSON) && defined(SURVEY_KEY))
/* Without JSON library, we cannot send a payload; so we disable the survey. */
#if !defined(SURVEY_KEY)
/* Without a survey key, we cannot send a payload; so we disable the survey. */
return false;
#else
return true;
#endif /* WITH_NLOHMANN_JSON */
#endif /* SURVEY_KEY */
}
private:

View File

@@ -164,7 +164,6 @@ void CDECL usererror(const char *s, ...)
/* In effect, the game ends here. As emscripten_set_main_loop() caused
* the stack to be unwound, the code after MainLoop() in
* openttd_main() is never executed. */
EM_ASM(if (window["openttd_syncfs"]) openttd_syncfs());
EM_ASM(if (window["openttd_abort"]) openttd_abort());
#endif
@@ -682,6 +681,22 @@ struct AfterNewGRFScan : NewGRFScanCallback {
}
};
void PostMainLoop()
{
WaitTillSaved();
/* only save config if we have to */
if (_save_config) {
SaveToConfig(STCF_ALL);
SaveHotkeysToConfig();
WindowDesc::SaveToConfig();
SaveToHighScore();
}
/* Reset windowing system, stop drivers, free used memory, ... */
ShutdownGame();
}
#if defined(UNIX)
extern void DedicatedFork();
#endif
@@ -1040,18 +1055,7 @@ int openttd_main(int argc, char *argv[])
_general_worker_pool.Stop();
WaitTillSaved();
/* only save config if we have to */
if (_save_config) {
SaveToConfig(STCF_ALL);
SaveHotkeysToConfig();
WindowDesc::SaveToConfig();
SaveToHighScore();
}
/* Reset windowing system, stop drivers, free used memory, ... */
ShutdownGame();
PostMainLoop();
return ret;
}

View File

@@ -7,8 +7,6 @@
/** @file survey_osx.cpp OSX implementation of OS-specific survey information. */
#ifdef WITH_NLOHMANN_JSON
#include "../../stdafx.h"
#include "../../core/format.hpp"
@@ -38,5 +36,3 @@ void SurveyOS(nlohmann::json &json)
json["memory"] = SurveyMemoryToText(MacOSGetPhysicalMemory());
json["hardware_concurrency"] = std::thread::hardware_concurrency();
}
#endif /* WITH_NLOHMANN_JSON */

View File

@@ -7,8 +7,6 @@
/** @file survey_unix.cpp Unix implementation of OS-specific survey information. */
#ifdef WITH_NLOHMANN_JSON
#include "../../stdafx.h"
#include <nlohmann/json.hpp>
@@ -38,5 +36,3 @@ void SurveyOS(nlohmann::json &json)
json["memory"] = SurveyMemoryToText(pages * page_size);
json["hardware_concurrency"] = std::thread::hardware_concurrency();
}
#endif /* WITH_NLOHMANN_JSON */

View File

@@ -7,8 +7,6 @@
/** @file survey_win.cpp Windows implementation of OS-specific survey information. */
#ifdef WITH_NLOHMANN_JSON
#include "../../stdafx.h"
#include "../../core/format.hpp"
@@ -41,5 +39,3 @@ void SurveyOS(nlohmann::json &json)
json["memory"] = SurveyMemoryToText(status.ullTotalPhys);
json["hardware_concurrency"] = std::thread::hardware_concurrency();
}
#endif /* WITH_NLOHMANN_JSON */

View File

@@ -130,7 +130,10 @@
}
std::string json;
ScriptAdmin::MakeJSON(vm, -1, SQUIRREL_MAX_DEPTH, json);
if (!ScriptAdmin::MakeJSON(vm, -1, SQUIRREL_MAX_DEPTH, json)) {
sq_pushinteger(vm, 0);
return 1;
}
if (json.length() > NETWORK_GAMESCRIPT_JSON_LENGTH) {
ScriptLog::Error("You are trying to send a table that is too large to the AdminPort. No data sent.");

View File

@@ -37,7 +37,7 @@ public:
static bool Send(void *table);
#endif /* DOXYGEN_API */
private:
protected:
/**
* Convert a Squirrel structure into a JSON string.
* @param vm The VM to operate on.

View File

@@ -220,11 +220,11 @@ const char *ScriptEventAdminPort::ReadValue(HSQUIRRELVM vm, const char *p)
SKIP_EMPTY(p);
if (strncmp(p, "false", 5) == 0) {
sq_pushinteger(vm, 0);
sq_pushbool(vm, 0);
return p + 5;
}
if (strncmp(p, "true", 4) == 0) {
sq_pushinteger(vm, 1);
sq_pushbool(vm, 1);
return p + 4;
}
if (strncmp(p, "null", 4) == 0) {

View File

@@ -44,6 +44,7 @@ typedef bool (ScriptAsyncModeProc)();
class ScriptObject : public SimpleCountedObject {
friend class ScriptInstance;
friend class ScriptController;
friend class TestScriptController;
protected:
/**
* A class that handles the current active instance. By instantiating it at

View File

@@ -947,13 +947,19 @@ void VideoDriver_SDL_Base::LoopOnce()
* normally done at the end of the main loop for non-Emscripten.
* After that, Emscripten just halts, and the HTML shows a nice
* "bye, see you next time" message. */
extern void PostMainLoop();
PostMainLoop();
emscripten_cancel_main_loop();
emscripten_exit_pointerlock();
/* In effect, the game ends here. As emscripten_set_main_loop() caused
* the stack to be unwound, the code after MainLoop() in
* openttd_main() is never executed. */
EM_ASM(if (window["openttd_syncfs"]) openttd_syncfs());
EM_ASM(if (window["openttd_exit"]) openttd_exit());
if (_game_mode == GM_BOOTSTRAP) {
EM_ASM(if (window["openttd_bootstrap_reload"]) openttd_bootstrap_reload());
} else {
EM_ASM(if (window["openttd_exit"]) openttd_exit());
}
#endif
return;
}