Merge branch 'master' into jgrpp

# Conflicts:
#	.github/workflows/ci-build.yml
#	.github/workflows/release-linux.yml
#	.github/workflows/release-macos.yml
#	.github/workflows/release-source.yml
#	.github/workflows/release.yml
#	CMakeLists.txt
#	COMPILING.md
#	src/ai/ai_core.cpp
#	src/ai/ai_gui.cpp
#	src/bridge_gui.cpp
#	src/company_gui.cpp
#	src/console_cmds.cpp
#	src/core/CMakeLists.txt
#	src/core/smallmap_type.hpp
#	src/disaster_vehicle.h
#	src/effectvehicle_base.h
#	src/fontcache.cpp
#	src/game/game_core.cpp
#	src/game/game_gui.cpp
#	src/gamelog.cpp
#	src/gamelog_internal.h
#	src/group_gui.cpp
#	src/linkgraph/linkgraph.h
#	src/misc.cpp
#	src/network/core/config.h
#	src/network/core/udp.cpp
#	src/network/network_chat_gui.cpp
#	src/network/network_content_gui.cpp
#	src/network/network_gui.cpp
#	src/newgrf.cpp
#	src/newgrf_gui.cpp
#	src/newgrf_profiling.cpp
#	src/newgrf_profiling.h
#	src/object_gui.cpp
#	src/openttd.cpp
#	src/openttd.h
#	src/order_gui.cpp
#	src/os/windows/font_win32.cpp
#	src/rail_gui.cpp
#	src/road.cpp
#	src/road_gui.cpp
#	src/saveload/afterload.cpp
#	src/saveload/saveload.h
#	src/script/api/script_controller.cpp
#	src/script/api/script_roadtypelist.cpp
#	src/script/script_config.cpp
#	src/script/script_config.hpp
#	src/script/script_instance.cpp
#	src/script/script_scanner.cpp
#	src/script/squirrel.cpp
#	src/script/squirrel_helper.hpp
#	src/settings_gui.cpp
#	src/settings_internal.h
#	src/settings_type.h
#	src/table/settings/network_private_settings.ini
#	src/timetable_gui.cpp
#	src/vehicle.cpp
#	src/vehicle_base.h
#	src/window_gui.h
This commit is contained in:
Jonathan G Rennison
2023-07-01 01:08:35 +01:00
246 changed files with 2023 additions and 1211 deletions

View File

@@ -24,9 +24,9 @@
return st != nullptr && (st->owner == ScriptObject::GetCompany() || ScriptCompanyMode::IsDeity() || st->owner == OWNER_NONE);
}
/* static */ char *ScriptBaseStation::GetName(StationID station_id)
/* static */ std::optional<std::string> ScriptBaseStation::GetName(StationID station_id)
{
if (!IsValidBaseStation(station_id)) return nullptr;
if (!IsValidBaseStation(station_id)) return std::nullopt;
::SetDParam(0, station_id);
return GetString(::Station::IsValidID(station_id) ? STR_STATION_NAME : STR_WAYPOINT_NAME);

View File

@@ -13,6 +13,8 @@
#include "script_text.hpp"
#include "script_date.hpp"
#include <optional>
/**
* Base class for stations and waypoints.
* @api ai game
@@ -43,7 +45,7 @@ public:
* @pre IsValidBaseStation(station_id).
* @return The name of the station.
*/
static char *GetName(StationID station_id);
static std::optional<std::string> GetName(StationID station_id);
/**
* Set the name this basestation.

View File

@@ -141,10 +141,10 @@ static void _DoCommandReturnBuildBridge1(class ScriptInstance *instance)
return ScriptObject::DoCommand(tile, 0, 0, CMD_LANDSCAPE_CLEAR);
}
/* static */ char *ScriptBridge::GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type)
/* static */ std::optional<std::string> ScriptBridge::GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type)
{
EnforcePrecondition(nullptr, vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER);
if (!IsValidBridge(bridge_id)) return nullptr;
EnforcePrecondition(std::nullopt, vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER);
if (!IsValidBridge(bridge_id)) return std::nullopt;
return GetString(vehicle_type == ScriptVehicle::VT_WATER ? STR_LAI_BRIDGE_DESCRIPTION_AQUEDUCT : ::GetBridgeSpec(bridge_id)->transport_name[vehicle_type]);
}

View File

@@ -11,6 +11,7 @@
#define SCRIPT_BRIDGE_HPP
#include "script_vehicle.hpp"
#include <optional>
/**
* Class that handles all bridge related functions.
@@ -69,7 +70,7 @@ public:
* @pre vehicle_type == ScriptVehicle::VT_ROAD || vehicle_type == ScriptVehicle::VT_RAIL || vehicle_type == ScriptVehicle::VT_WATER
* @return The name the bridge has.
*/
static char *GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type);
static std::optional<std::string> GetName(BridgeID bridge_id, ScriptVehicle::VehicleType vehicle_type);
/**
* Get the maximum speed of a bridge.

View File

@@ -27,26 +27,25 @@
return (towneffect_type >= (TownEffect)TE_BEGIN && towneffect_type < (TownEffect)TE_END);
}
/* static */ char *ScriptCargo::GetName(CargoID cargo_type)
/* static */ std::optional<std::string> ScriptCargo::GetName(CargoID cargo_type)
{
if (!IsValidCargo(cargo_type)) return nullptr;
if (!IsValidCargo(cargo_type)) return std::nullopt;
::SetDParam(0, 1ULL << cargo_type);
return GetString(STR_JUST_CARGO_LIST);
}
/* static */ char *ScriptCargo::GetCargoLabel(CargoID cargo_type)
/* static */ std::optional<std::string> ScriptCargo::GetCargoLabel(CargoID cargo_type)
{
if (!IsValidCargo(cargo_type)) return nullptr;
if (!IsValidCargo(cargo_type)) return std::nullopt;
const CargoSpec *cargo = ::CargoSpec::Get(cargo_type);
/* cargo->label is a uint32 packing a 4 character non-terminated string,
* like "PASS", "COAL", "OIL_". New ones can be defined by NewGRFs */
char *cargo_label = MallocT<char>(sizeof(cargo->label) + 1);
std::string cargo_label;
for (uint i = 0; i < sizeof(cargo->label); i++) {
cargo_label[i] = GB(cargo->label, (uint8)(sizeof(cargo->label) - i - 1) * 8, 8);
cargo_label.push_back(GB(cargo->label, (uint8)(sizeof(cargo->label) - i - 1) * 8, 8));
}
cargo_label[sizeof(cargo->label)] = '\0';
return cargo_label;
}

View File

@@ -13,6 +13,7 @@
#include "script_object.hpp"
#include "../../cargotype.h"
#include "../../linkgraph/linkgraph_type.h"
#include <optional>
/**
* Class that handles all cargo related functions.
@@ -90,7 +91,7 @@ public:
* @pre IsValidCargo(cargo_type).
* @return The name of the cargo type.
*/
static char *GetName(CargoID cargo_type);
static std::optional<std::string> GetName(CargoID cargo_type);
/**
* Gets the string representation of the cargo label.
@@ -107,7 +108,7 @@ public:
* - In other words: Only use the cargo label, if you know more about the behaviour
* of a specific cargo from a specific industry set, than the API methods can tell you.
*/
static char *GetCargoLabel(CargoID cargo_type);
static std::optional<std::string> GetCargoLabel(CargoID cargo_type);
/**
* Checks whether the give cargo is a freight or not.

View File

@@ -32,11 +32,11 @@ static NetworkClientInfo *FindClientInfo(ScriptClient::ClientID client)
return (FindClientInfo(client) == nullptr ? ScriptClient::CLIENT_INVALID : client);
}
/* static */ char *ScriptClient::GetName(ScriptClient::ClientID client)
/* static */ std::optional<std::string> ScriptClient::GetName(ScriptClient::ClientID client)
{
NetworkClientInfo *ci = FindClientInfo(client);
if (ci == nullptr) return nullptr;
return stredup(ci->client_name.c_str());
if (ci == nullptr) return std::nullopt;
return ci->client_name;
}
/* static */ ScriptCompany::CompanyID ScriptClient::GetCompany(ScriptClient::ClientID client)

View File

@@ -14,6 +14,7 @@
#include "script_date.hpp"
#include "script_company.hpp"
#include "../../network/network_type.h"
#include <optional>
/**
* Class that handles all client related functions.
@@ -45,7 +46,7 @@ public:
* @pre ResolveClientID(client) != CLIENT_INVALID.
* @return The name of the given client.
*/
static char *GetName(ClientID client);
static std::optional<std::string> GetName(ClientID client);
/**
* Get the company in which the given client is playing.

View File

@@ -53,10 +53,10 @@
return ScriptObject::DoCommand(0, 0, 0, CMD_RENAME_COMPANY, text);
}
/* static */ char *ScriptCompany::GetName(ScriptCompany::CompanyID company)
/* static */ std::optional<std::string> ScriptCompany::GetName(ScriptCompany::CompanyID company)
{
company = ResolveCompanyID(company);
if (company == COMPANY_INVALID) return nullptr;
if (company == COMPANY_INVALID) return std::nullopt;
::SetDParam(0, company);
return GetString(STR_COMPANY_NAME);
@@ -75,20 +75,13 @@
return ScriptObject::DoCommand(0, 0, 0, CMD_RENAME_PRESIDENT, text);
}
/* static */ char *ScriptCompany::GetPresidentName(ScriptCompany::CompanyID company)
/* static */ std::optional<std::string> ScriptCompany::GetPresidentName(ScriptCompany::CompanyID company)
{
company = ResolveCompanyID(company);
if (company == COMPANY_INVALID) return std::nullopt;
static const int len = 64;
char *president_name = MallocT<char>(len);
if (company != COMPANY_INVALID) {
::SetDParam(0, company);
::GetString(president_name, STR_PRESIDENT_NAME, &president_name[len - 1]);
} else {
*president_name = '\0';
}
return president_name;
::SetDParam(0, company);
return GetString(STR_PRESIDENT_NAME);
}
/* static */ bool ScriptCompany::SetPresidentGender(Gender gender)

View File

@@ -14,6 +14,7 @@
#include "../../economy_type.h"
#include "../../livery.h"
#include "../../gfx_type.h"
#include <optional>
/**
* Class that handles all company related functions.
@@ -151,7 +152,7 @@ public:
* @pre ResolveCompanyID(company) != COMPANY_INVALID.
* @return The name of the given company.
*/
static char *GetName(CompanyID company);
static std::optional<std::string> GetName(CompanyID company);
/**
* Set the name of your president.
@@ -169,7 +170,7 @@ public:
* @pre ResolveCompanyID(company) != COMPANY_INVALID.
* @return The name of the president of the given company.
*/
static char *GetPresidentName(CompanyID company);
static std::optional<std::string> GetPresidentName(CompanyID company);
/**
* Set the gender of the president of your company.

View File

@@ -45,15 +45,13 @@
throw Script_Suspend(ticks, nullptr);
}
/* static */ void ScriptController::Break(const char* message)
/* static */ void ScriptController::Break(const std::string &message)
{
if (_network_dedicated || !_settings_client.gui.ai_developer_tools) return;
ScriptObject::GetActiveInstance()->Pause();
char log_message[1024];
seprintf(log_message, lastof(log_message), "Break: %s", message);
ScriptLog::Log(ScriptLogTypes::LOG_SQ_ERROR, log_message);
ScriptLog::Log(ScriptLogTypes::LOG_SQ_ERROR, fmt::format("Break: {}", message));
/* Inform script developer that their script has been paused and
* needs manual action to continue. */
@@ -64,7 +62,7 @@
}
}
/* static */ void ScriptController::Print(bool error_msg, const char *message)
/* static */ void ScriptController::Print(bool error_msg, const std::string &message)
{
ScriptLog::Log(error_msg ? ScriptLogTypes::LOG_SQ_ERROR : ScriptLogTypes::LOG_SQ_INFO, message);
}
@@ -91,7 +89,7 @@ ScriptController::ScriptController(CompanyID company) :
Squirrel::DecreaseOps(ScriptObject::GetActiveInstance()->engine->GetVM(), amount);
}
/* static */ int ScriptController::GetSetting(const char *name)
/* static */ int ScriptController::GetSetting(const std::string &name)
{
return ScriptObject::GetActiveInstance()->GetSetting(name);
}
@@ -101,7 +99,7 @@ ScriptController::ScriptController(CompanyID company) :
return _openttd_newgrf_version;
}
/* static */ HSQOBJECT ScriptController::Import(const char *library, const char *class_name, int version)
/* static */ HSQOBJECT ScriptController::Import(const std::string &library, const std::string &class_name, int version)
{
ScriptController *controller = ScriptObject::GetActiveInstance()->GetController();
Squirrel *engine = ScriptObject::GetActiveInstance()->engine;
@@ -109,9 +107,7 @@ ScriptController::ScriptController(CompanyID company) :
ScriptInfo *lib = ScriptObject::GetActiveInstance()->FindLibrary(library, version);
if (lib == nullptr) {
char error[1024];
seprintf(error, lastof(error), "couldn't find library '%s' with version %d", library, version);
throw sq_throwerror(vm, error);
throw sq_throwerror(vm, fmt::format("couldn't find library '{}' with version {}", library, version));
}
/* Internally we store libraries as 'library.version' */
@@ -138,9 +134,7 @@ ScriptController::ScriptController(CompanyID company) :
sq_newclass(vm, SQFalse);
/* Load the library */
if (!engine->LoadScript(vm, lib->GetMainScript(), false)) {
char error[1024];
seprintf(error, lastof(error), "there was a compile error when importing '%s' version %d", library, version);
throw sq_throwerror(vm, error);
throw sq_throwerror(vm, fmt::format("there was a compile error when importing '{}' version {}", library, version));
}
/* Create the fake class */
sq_newslot(vm, -3, SQFalse);
@@ -157,15 +151,13 @@ ScriptController::ScriptController(CompanyID company) :
}
sq_pushstring(vm, lib->GetInstanceName(), -1);
if (SQ_FAILED(sq_get(vm, -2))) {
char error[1024];
seprintf(error, lastof(error), "unable to find class '%s' in the library '%s' version %d", lib->GetInstanceName(), library, version);
throw sq_throwerror(vm, error);
throw sq_throwerror(vm, fmt::format("unable to find class '{}' in the library '{}' version {}", lib->GetInstanceName(), library, version));
}
HSQOBJECT obj;
sq_getstackobj(vm, -1, &obj);
sq_pop(vm, 3);
if (StrEmpty(class_name)) return obj;
if (class_name.empty()) return obj;
/* Now link the name the user wanted to our 'fake' class */
sq_pushobject(vm, parent);

View File

@@ -131,7 +131,7 @@ public:
* @param name The name of the setting.
* @return the value for the setting, or -1 if the setting is not known.
*/
static int GetSetting(const char *name);
static int GetSetting(const std::string &name);
/**
* Get the OpenTTD version of this executable. The version is formatted
@@ -187,7 +187,7 @@ public:
* @note gui.ai_developer_tools setting must be enabled or the break is
* ignored.
*/
static void Break(const char* message);
static void Break(const std::string &message);
/**
* When Squirrel triggers a print, this function is called.
@@ -196,7 +196,7 @@ public:
* @param message The message Squirrel logged.
* @note Use ScriptLog.Info/Warning/Error instead of 'print'.
*/
static void Print(bool error_msg, const char *message);
static void Print(bool error_msg, const std::string &message);
/**
* Import a library.
@@ -207,7 +207,7 @@ public:
* @return The loaded library object. If class_name is set, it is also available (under the scope of the import) under that name.
* @note This command can be called from the global space, and does not need an instance.
*/
static HSQOBJECT Import(const char *library, const char *class_name, int version);
static HSQOBJECT Import(const std::string &library, const std::string &class_name, int version);
private:
typedef std::map<std::string, std::string, CaseInsensitiveComparator> LoadedLibraryList; ///< The type for loaded libraries.

View File

@@ -40,9 +40,9 @@
return e != nullptr && ::IsEngineBuildable(engine_id, e->type, ScriptObject::GetCompany());
}
/* static */ char *ScriptEngine::GetName(EngineID engine_id)
/* static */ std::optional<std::string> ScriptEngine::GetName(EngineID engine_id)
{
if (!IsValidEngine(engine_id)) return nullptr;
if (!IsValidEngine(engine_id)) return std::nullopt;
::SetDParam(0, engine_id);
return GetString(STR_ENGINE_NAME);

View File

@@ -14,6 +14,7 @@
#include "script_rail.hpp"
#include "script_airport.hpp"
#include "script_date.hpp"
#include <optional>
/**
* Class that handles all engine related functions.
@@ -44,7 +45,7 @@ public:
* @pre IsValidEngine(engine_id).
* @return The name the engine has.
*/
static char *GetName(EngineID engine_id);
static std::optional<std::string> GetName(EngineID engine_id);
/**
* Get the cargo-type of an engine. In case it can transport multiple cargoes, it

View File

@@ -23,9 +23,9 @@ ScriptError::ScriptErrorMapString ScriptError::error_map_string = ScriptError::S
return ScriptObject::GetLastError();
}
/* static */ char *ScriptError::GetLastErrorString()
/* static */ std::optional<std::string> ScriptError::GetLastErrorString()
{
return stredup((*error_map_string.find(ScriptError::GetLastError())).second);
return (*error_map_string.find(ScriptError::GetLastError())).second;
}
/* static */ ScriptErrorType ScriptError::StringToError(StringID internal_string_id)

View File

@@ -13,6 +13,7 @@
#include "script_object.hpp"
#include "script_companymode.hpp"
#include <map>
#include <optional>
/**
* Helper to write precondition enforcers for the script API in an abbreviated manner.
@@ -193,7 +194,7 @@ public:
* Get the last error in string format (for human readability).
* @return An ErrorMessage enum item, as string.
*/
static char *GetLastErrorString();
static std::optional<std::string> GetLastErrorString();
/**
* Get the error based on the OpenTTD StringID.

View File

@@ -26,9 +26,9 @@ bool ScriptEventEnginePreview::IsEngineValid() const
return e != nullptr && e->IsEnabled();
}
char *ScriptEventEnginePreview::GetName()
std::optional<std::string> ScriptEventEnginePreview::GetName()
{
if (!this->IsEngineValid()) return nullptr;
if (!this->IsEngineValid()) return std::nullopt;
::SetDParam(0, this->engine);
return GetString(STR_ENGINE_NAME);

View File

@@ -13,6 +13,7 @@
#include "script_event.hpp"
#include "script_goal.hpp"
#include "script_window.hpp"
#include <optional>
/**
* Event Vehicle Crash, indicating a vehicle of yours is crashed.
@@ -239,7 +240,7 @@ public:
* Get the name of the offered engine.
* @return The name the engine has.
*/
char *GetName();
std::optional<std::string> GetName();
/**
* Get the cargo-type of the offered engine. In case it can transport multiple cargoes, it

View File

@@ -15,13 +15,13 @@
#include "../../safeguards.h"
/* static */ bool ScriptGameSettings::IsValid(const char *setting)
/* static */ bool ScriptGameSettings::IsValid(const std::string &setting)
{
const SettingDesc *sd = GetSettingFromName(setting);
return sd != nullptr && sd->IsIntSetting();
}
/* static */ SQInteger ScriptGameSettings::GetValue(const char *setting)
/* static */ SQInteger ScriptGameSettings::GetValue(const std::string &setting)
{
if (!IsValid(setting)) return -1;
@@ -30,7 +30,7 @@
return sd->AsIntSetting()->Read(&_settings_game);
}
/* static */ bool ScriptGameSettings::SetValue(const char *setting, SQInteger value)
/* static */ bool ScriptGameSettings::SetValue(const std::string &setting, SQInteger value)
{
EnforceDeityOrCompanyModeValid(false);
if (!IsValid(setting)) return false;

View File

@@ -44,7 +44,7 @@ public:
* @note Results achieved in the past offer no guarantee for the future.
* @return True if and only if the setting is valid.
*/
static bool IsValid(const char *setting);
static bool IsValid(const std::string &setting);
/**
* Gets the value of the game setting.
@@ -57,7 +57,7 @@ public:
* @note Results achieved in the past offer no guarantee for the future.
* @return The value for the setting.
*/
static SQInteger GetValue(const char *setting);
static SQInteger GetValue(const std::string &setting);
/**
* Sets the value of the game setting.
@@ -69,7 +69,7 @@ public:
* @note Results achieved in the past offer no guarantee for the future.
* @api -ai
*/
static bool SetValue(const char *setting, SQInteger value);
static bool SetValue(const std::string &setting, SQInteger value);
/**
* Checks whether the given vehicle-type is disabled for companies.

View File

@@ -65,9 +65,9 @@
return ScriptObject::DoCommand(0, group_id, 0, CMD_ALTER_GROUP, text);
}
/* static */ char *ScriptGroup::GetName(GroupID group_id)
/* static */ std::optional<std::string> ScriptGroup::GetName(GroupID group_id)
{
if (!IsValidGroup(group_id)) return nullptr;
if (!IsValidGroup(group_id)) return std::nullopt;
::SetDParam(0, group_id);
return GetString(STR_GROUP_NAME);

View File

@@ -12,6 +12,7 @@
#include "script_vehicle.hpp"
#include "../../group_type.h"
#include <optional>
/**
* Class that handles all group related functions.
@@ -84,7 +85,7 @@ public:
* @pre IsValidGroup(group_id).
* @return The name the group has.
*/
static char *GetName(GroupID group_id);
static std::optional<std::string> GetName(GroupID group_id);
/**
* Set parent group of a group.

View File

@@ -40,9 +40,9 @@
return ::GetIndustryIndex(tile);
}
/* static */ char *ScriptIndustry::GetName(IndustryID industry_id)
/* static */ std::optional<std::string> ScriptIndustry::GetName(IndustryID industry_id)
{
if (!IsValidIndustry(industry_id)) return nullptr;
if (!IsValidIndustry(industry_id)) return std::nullopt;
::SetDParam(0, industry_id);
return GetString(STR_INDUSTRY_NAME);

View File

@@ -14,6 +14,7 @@
#include "script_date.hpp"
#include "script_object.hpp"
#include "../../industry.h"
#include <optional>
/**
* Class that handles all industry related functions.
@@ -79,7 +80,7 @@ public:
* @pre IsValidIndustry(industry_id).
* @return The name of the industry.
*/
static char *GetName(IndustryID industry_id);
static std::optional<std::string> GetName(IndustryID industry_id);
/**
* Set the custom text of an industry, shown in the GUI.

View File

@@ -56,9 +56,9 @@
return ::GetIndustrySpec(industry_type)->GetConstructionCost();
}
/* static */ char *ScriptIndustryType::GetName(IndustryType industry_type)
/* static */ std::optional<std::string> ScriptIndustryType::GetName(IndustryType industry_type)
{
if (!IsValidIndustryType(industry_type)) return nullptr;
if (!IsValidIndustryType(industry_type)) return std::nullopt;
return GetString(::GetIndustrySpec(industry_type)->name);
}

View File

@@ -11,6 +11,7 @@
#define SCRIPT_INDUSTRYTYPE_HPP
#include "script_list.hpp"
#include <optional>
/**
* Class that handles all industry-type related functions.
@@ -39,7 +40,7 @@ public:
* @pre IsValidIndustryType(industry_type).
* @return The name of an industry.
*/
static char *GetName(IndustryType industry_type);
static std::optional<std::string> GetName(IndustryType industry_type);
/**
* Get a list of CargoID possible produced by this industry-type.

View File

@@ -28,7 +28,7 @@ public:
/**
* Virtual dtor, needed to mute warnings.
*/
virtual ~ScriptListSorter() { }
virtual ~ScriptListSorter() = default;
/**
* Get the first item of the sorter.

View File

@@ -17,22 +17,22 @@
#include "../../safeguards.h"
/* static */ void ScriptLog::Info(const char *message)
/* static */ void ScriptLog::Info(const std::string &message)
{
ScriptLog::Log(ScriptLogTypes::LOG_INFO, message);
}
/* static */ void ScriptLog::Warning(const char *message)
/* static */ void ScriptLog::Warning(const std::string &message)
{
ScriptLog::Log(ScriptLogTypes::LOG_WARNING, message);
}
/* static */ void ScriptLog::Error(const char *message)
/* static */ void ScriptLog::Error(const std::string &message)
{
ScriptLog::Log(ScriptLogTypes::LOG_ERROR, message);
}
/* static */ void ScriptLog::Log(ScriptLogTypes::ScriptLogType level, const char *message)
/* static */ void ScriptLog::Log(ScriptLogTypes::ScriptLogType level, const std::string &message)
{
ScriptLogTypes::LogData &logdata = ScriptObject::GetLogData();
@@ -43,8 +43,7 @@
line.type = level;
/* Cut string after first \n */
const char *newline = strchr(message, '\n');
line.text = std::string(message, 0, newline == nullptr ? strlen(message) : newline - message);
line.text = message.substr(0, message.find_first_of('\n'));
char logc;

View File

@@ -27,21 +27,21 @@ public:
* @param message The message to log.
* @note Special characters such as U+0000-U+0019 and U+E000-U+E1FF are not supported and removed or replaced by a question mark. This includes newlines and tabs.
*/
static void Info(const char *message);
static void Info(const std::string &message);
/**
* Print a Warning message to the logs.
* @param message The message to log.
* @note Special characters such as U+0000-U+0019 and U+E000-U+E1FF are not supported and removed or replaced by a question mark. This includes newlines and tabs.
*/
static void Warning(const char *message);
static void Warning(const std::string &message);
/**
* Print an Error message to the logs.
* @param message The message to log.
* @note Special characters such as U+0000-U+0019 and U+E000-U+E1FF are not supported and removed or replaced by a question mark. This includes newlines and tabs.
*/
static void Error(const char *message);
static void Error(const std::string &message);
/**
* Log this message once.
@@ -53,7 +53,7 @@ private:
/**
* Internal command to log the message in a common way.
*/
static void Log(ScriptLogTypes::ScriptLogType level, const char *message);
static void Log(ScriptLogTypes::ScriptLogType level, const std::string &message);
};
#endif /* SCRIPT_LOG_HPP */

View File

@@ -50,15 +50,15 @@ ScriptNewGRFList::ScriptNewGRFList()
return 0;
}
/* static */ char *ScriptNewGRF::GetName(SQInteger grfid)
/* static */ std::optional<std::string> ScriptNewGRF::GetName(SQInteger grfid)
{
grfid = BSWAP32(GB(grfid, 0, 32)); // Match people's expectations.
for (auto c = _grfconfig; c != nullptr; c = c->next) {
if (!HasBit(c->flags, GCF_STATIC) && c->ident.grfid == grfid) {
return ::stredup(c->GetName());
return c->GetName();
}
}
return nullptr;
return std::nullopt;
}

View File

@@ -11,6 +11,7 @@
#define SCRIPT_NEWGRF_HPP
#include "script_list.hpp"
#include <optional>
/**
* Create a list of loaded NewGRFs.
@@ -50,7 +51,7 @@ public:
* @pre ScriptNewGRF::IsLoaded(grfid).
* @return The name of the NewGRF or null if no name is defined.
*/
static char *GetName(SQInteger grfid);
static std::optional<std::string> GetName(SQInteger grfid);
};
#endif /* SCRIPT_NEWGRF_HPP */

View File

@@ -311,12 +311,9 @@ ScriptObject::ActiveInstance::~ActiveInstance()
return GetStorage()->log_data;
}
/* static */ char *ScriptObject::GetString(StringID string)
/* static */ std::string ScriptObject::GetString(StringID string)
{
char buffer[64];
::GetString(buffer, string, lastof(buffer));
::StrMakeValidInPlace(buffer, lastof(buffer), SVS_NONE);
return ::stredup(buffer);
return ::StrMakeValid(::GetString(string));
}
/* static */ void ScriptObject::SetCallbackVariable(int index, int value)

View File

@@ -323,7 +323,7 @@ protected:
/**
* Get an allocated string with all control codes stripped off.
*/
static char *GetString(StringID string);
static std::string GetString(StringID string);
static bool IsNewUniqueLogMessage(const std::string &msg);

View File

@@ -22,9 +22,9 @@
return ObjectSpec::Get(object_type)->IsEverAvailable();
}
/* static */ char *ScriptObjectType::GetName(ObjectType object_type)
/* static */ std::optional<std::string> ScriptObjectType::GetName(ObjectType object_type)
{
EnforcePrecondition(nullptr, IsValidObjectType(object_type));
EnforcePrecondition(std::nullopt, IsValidObjectType(object_type));
return GetString(ObjectSpec::Get(object_type)->name);
}

View File

@@ -13,6 +13,7 @@
#include "script_list.hpp"
#include "../../newgrf_object.h"
#include <optional>
/**
* Class that handles all object-type related functions.
@@ -33,7 +34,7 @@ public:
* @pre IsValidObjectType(object_type).
* @return The name of an object.
*/
static char *GetName(ObjectType object_type);
static std::optional<std::string> GetName(ObjectType object_type);
/**
* Get the number of views for an object-type.

View File

@@ -21,9 +21,9 @@
#include "../../safeguards.h"
/* static */ char *ScriptRail::GetName(RailType rail_type)
/* static */ std::optional<std::string> ScriptRail::GetName(RailType rail_type)
{
if (!IsRailTypeAvailable(rail_type)) return nullptr;
if (!IsRailTypeAvailable(rail_type)) return std::nullopt;
return GetString(GetRailTypeInfo((::RailType)rail_type)->strings.menu_text);
}

View File

@@ -13,6 +13,7 @@
#include "script_tile.hpp"
#include "../../signal_type.h"
#include "../../track_type.h"
#include <optional>
/**
* Class that handles all rail related functions.
@@ -101,7 +102,7 @@ public:
* means that the name could be something like "Maglev construction" instead
* of just "Maglev".
*/
static char *GetName(RailType rail_type);
static std::optional<std::string> GetName(RailType rail_type);
/**
* Checks whether the given tile is actually a tile with rail that can be

View File

@@ -21,9 +21,9 @@
return ScriptCargo::HasCargoClass(cargo_type, ScriptCargo::CC_PASSENGERS) ? ROADVEHTYPE_BUS : ROADVEHTYPE_TRUCK;
}
/* static */ char *ScriptRoad::GetName(RoadType road_type)
/* static */ std::optional<std::string> ScriptRoad::GetName(RoadType road_type)
{
if (!IsRoadTypeAvailable(road_type)) return nullptr;
if (!IsRoadTypeAvailable(road_type)) return std::nullopt;
return GetString(GetRoadTypeInfo((::RoadType)road_type)->strings.name);
}
@@ -392,7 +392,7 @@ static bool NormaliseTileOffset(int32 *tile)
return false;
}
/* static */ SQInteger ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array<> existing, TileIndex start_, TileIndex end_)
/* static */ SQInteger ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array<> &&existing, TileIndex start_, TileIndex end_)
{
::Slope slope = (::Slope)slope_;
int32 start = start_;
@@ -433,7 +433,7 @@ static bool NormaliseTileOffset(int32 *tile)
if (HasBit(rb, i)) existing.emplace_back(neighbours[i]);
}
return ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::GetSlope(tile), existing, start - tile, end - tile);
return ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::GetSlope(tile), std::move(existing), start - tile, end - tile);
}
/**

View File

@@ -13,6 +13,7 @@
#include "script_tile.hpp"
#include "../squirrel_helper_type.hpp"
#include "../../../road.h"
#include <optional>
/**
* Class that handles all road related functions.
@@ -90,7 +91,7 @@ public:
* @pre IsRoadTypeAvailable(road_type).
* @return The name the road type has.
*/
static char *GetName(RoadType road_type);
static std::optional<std::string> GetName(RoadType road_type);
/**
* Determines whether a busstop or a truckstop is needed to transport a certain cargo.
@@ -265,7 +266,7 @@ public:
* they are build or 2 when building the first part automatically
* builds the second part. -1 means the preconditions are not met.
*/
static SQInteger CanBuildConnectedRoadParts(ScriptTile::Slope slope, Array<> existing, TileIndex start, TileIndex end);
static SQInteger CanBuildConnectedRoadParts(ScriptTile::Slope slope, Array<> &&existing, TileIndex start, TileIndex end);
/**
* Lookup function for building road parts independent of whether the

View File

@@ -18,7 +18,7 @@ ScriptRoadTypeList::ScriptRoadTypeList(ScriptRoad::RoadTramTypes rtts)
EnforceDeityOrCompanyModeValid_Void();
for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
if (!HasBit(rtts, GetRoadTramType(rt))) continue;
if ((ScriptCompanyMode::IsDeity() || ::HasRoadTypeAvail(ScriptObject::GetCompany(), rt)) &&
if (::HasRoadTypeAvail(ScriptObject::GetCompany(), rt) &&
!HasBit(GetRoadTypeInfo(rt)->extra_flags, RXTF_NOT_AVAILABLE_AI_GS)) {
this->AddItem(rt);
}

View File

@@ -46,9 +46,9 @@
return ScriptObject::DoCommand(0, sign_id, 0, CMD_RENAME_SIGN, text);
}
/* static */ char *ScriptSign::GetName(SignID sign_id)
/* static */ std::optional<std::string> ScriptSign::GetName(SignID sign_id)
{
if (!IsValidSign(sign_id)) return nullptr;
if (!IsValidSign(sign_id)) return std::nullopt;
::SetDParam(0, sign_id);
return GetString(STR_SIGN_NAME);

View File

@@ -12,6 +12,7 @@
#include "script_company.hpp"
#include "script_error.hpp"
#include <optional>
/**
* Class that handles all sign related functions.
@@ -55,7 +56,7 @@ public:
* @pre IsValidSign(sign_id).
* @return The name of the sign.
*/
static char *GetName(SignID sign_id);
static std::optional<std::string> GetName(SignID sign_id);
/**
* Get the owner of a sign.

View File

@@ -23,7 +23,7 @@
#include "../../safeguards.h"
RawText::RawText(const char *text) : text(text)
RawText::RawText(const std::string &text) : text(text)
{
}

View File

@@ -42,7 +42,7 @@ public:
*/
class RawText : public Text {
public:
RawText(const char *text);
RawText(const std::string &text);
const std::string GetEncodedText() override { return this->text; }
private:

View File

@@ -32,9 +32,9 @@
return ::Town::IsValidID(town_id);
}
/* static */ char *ScriptTown::GetName(TownID town_id)
/* static */ std::optional<std::string> ScriptTown::GetName(TownID town_id)
{
if (!IsValidTown(town_id)) return nullptr;
if (!IsValidTown(town_id)) return std::nullopt;
::SetDParam(0, town_id);
return GetString(STR_TOWN_NAME);

View File

@@ -13,6 +13,7 @@
#include "script_cargo.hpp"
#include "script_company.hpp"
#include "../../town_type.h"
#include <optional>
/**
* Class that handles all town related functions.
@@ -142,7 +143,7 @@ public:
* @pre IsValidTown(town_id).
* @return The name of the town.
*/
static char *GetName(TownID town_id);
static std::optional<std::string> GetName(TownID town_id);
/**
* Rename a town.

View File

@@ -298,9 +298,9 @@
return ::Vehicle::Get(vehicle_id)->unitnumber;
}
/* static */ char *ScriptVehicle::GetName(VehicleID vehicle_id)
/* static */ std::optional<std::string> ScriptVehicle::GetName(VehicleID vehicle_id)
{
if (!IsPrimaryVehicle(vehicle_id)) return nullptr;
if (!IsPrimaryVehicle(vehicle_id)) return std::nullopt;
::SetDParam(0, vehicle_id);
return GetString(STR_VEHICLE_NAME);

View File

@@ -11,6 +11,7 @@
#define SCRIPT_VEHICLE_HPP
#include "script_road.hpp"
#include <optional>
/**
* Class that handles all vehicle related functions.
@@ -137,7 +138,7 @@ public:
* @pre IsPrimaryVehicle(vehicle_id).
* @return The name the vehicle has.
*/
static char *GetName(VehicleID vehicle_id);
static std::optional<std::string> GetName(VehicleID vehicle_id);
/**
* Get the owner of a vehicle.

View File

@@ -15,14 +15,18 @@
#include "../textfile_gui.h"
#include "../string_func.h"
#include "../3rdparty/fmt/format.h"
#include <charconv>
#include "../safeguards.h"
void ScriptConfig::Change(const char *name, int version, bool force_exact_match, bool is_random)
void ScriptConfig::Change(std::optional<const std::string> name, int version, bool force_exact_match, bool is_random)
{
free(this->name);
this->name = (name == nullptr) ? nullptr : stredup(name);
this->info = (name == nullptr) ? nullptr : this->FindInfo(this->name, version, force_exact_match);
if (name.has_value()) {
this->name = std::move(name.value());
this->info = this->FindInfo(this->name, version, force_exact_match);
} else {
this->info = nullptr;
}
this->version = (info == nullptr) ? -1 : info->GetVersion();
this->is_random = is_random;
this->config_list.reset();
@@ -45,7 +49,7 @@ void ScriptConfig::Change(const char *name, int version, bool force_exact_match,
ScriptConfig::ScriptConfig(const ScriptConfig *config)
{
this->name = (config->name == nullptr) ? nullptr : stredup(config->name);
this->name = config->name;
this->info = config->info;
this->version = config->version;
this->is_random = config->is_random;
@@ -61,7 +65,6 @@ ScriptConfig::ScriptConfig(const ScriptConfig *config)
ScriptConfig::~ScriptConfig()
{
free(this->name);
this->ResetSettings();
this->to_load_data.reset();
}
@@ -101,7 +104,7 @@ int ScriptConfig::GetSetting(const std::string &name) const
return (*it).second;
}
void ScriptConfig::SetSetting(const std::string &name, int value)
void ScriptConfig::SetSetting(const std::string_view name, int value)
{
/* You can only set Script specific settings if an Script is selected. */
if (this->info == nullptr) return;
@@ -111,7 +114,7 @@ void ScriptConfig::SetSetting(const std::string &name, int value)
value = Clamp(value, config_item->min_value, config_item->max_value);
this->settings[name] = value;
this->settings[std::string{name}] = value;
}
void ScriptConfig::ResetSettings()
@@ -157,7 +160,7 @@ bool ScriptConfig::IsRandom() const
return this->is_random;
}
const char *ScriptConfig::GetName() const
const std::string &ScriptConfig::GetName() const
{
return this->name;
}
@@ -169,28 +172,24 @@ int ScriptConfig::GetVersion() const
void ScriptConfig::StringToSettings(const std::string &value)
{
char *value_copy = stredup(value.c_str());
char *s = value_copy;
while (s != nullptr) {
std::string_view to_process = value;
for (;;) {
/* Analyze the string ('name=value,name=value\0') */
char *item_name = s;
s = strchr(s, '=');
if (s == nullptr) break;
if (*s == '\0') break;
*s = '\0';
s++;
size_t pos = to_process.find_first_of('=');
if (pos == std::string_view::npos) return;
char *item_value = s;
s = strchr(s, ',');
if (s != nullptr) {
*s = '\0';
s++;
}
std::string_view item_name = to_process.substr(0, pos);
this->SetSetting(item_name, atoi(item_value));
to_process.remove_prefix(pos + 1);
pos = to_process.find_first_of(',');
int item_value = 0;
std::from_chars(to_process.data(), to_process.data() + std::min(pos, to_process.size()), item_value);
this->SetSetting(item_name, item_value);
if (pos == std::string_view::npos) return;
to_process.remove_prefix(pos + 1);
}
free(value_copy);
}
std::string ScriptConfig::SettingsToString() const

View File

@@ -12,10 +12,10 @@
#include <map>
#include <list>
#include "../core/smallmap_type.hpp"
#include "../company_type.h"
#include "../textfile_gui.h"
#include "script_instance.hpp"
#include <optional>
/** Maximum of 10 digits for MIN / MAX_INT32, 1 for the sign and 1 for '\0'. */
static const int INT32_DIGITS_WITH_SIGN_AND_TERMINATION = 10 + 1 + 1;
@@ -60,7 +60,6 @@ protected:
public:
ScriptConfig() :
name(nullptr),
version(-1),
info(nullptr),
is_random(false),
@@ -84,7 +83,7 @@ public:
* as specified. If false any compatible version is ok.
* @param is_random Is the Script chosen randomly?
*/
void Change(const char *name, int version = -1, bool force_exact_match = false, bool is_random = false);
void Change(std::optional<const std::string> name, int version = -1, bool force_exact_match = false, bool is_random = false);
/**
* Get the ScriptInfo linked to this ScriptConfig.
@@ -128,7 +127,7 @@ public:
/**
* Set the value of a setting for this config.
*/
void SetSetting(const std::string &name, int value);
void SetSetting(const std::string_view name, int value);
/**
* Reset all settings to their default value.
@@ -159,7 +158,7 @@ public:
/**
* Get the name of the Script.
*/
const char *GetName() const;
const std::string &GetName() const;
/**
* Get the version of the Script.
@@ -190,7 +189,7 @@ public:
ScriptInstance::ScriptData *GetToLoadData();
protected:
const char *name; ///< Name of the Script
std::string name; ///< Name of the Script
int version; ///< Version of the Script
class ScriptInfo *info; ///< ScriptInfo object for related to this Script version
SettingValueList settings; ///< List with all setting=>value pairs that are configure for this Script
@@ -207,7 +206,7 @@ protected:
* This function should call back to the Scanner in charge of this Config,
* to find the ScriptInfo belonging to a name+version.
*/
virtual ScriptInfo *FindInfo(const char *name, int version, bool force_exact_match) = 0;
virtual ScriptInfo *FindInfo(const std::string &name, int version, bool force_exact_match) = 0;
};
#endif /* SCRIPT_CONFIG_HPP */

View File

@@ -154,7 +154,7 @@ struct ScriptListWindow : public Window {
SetDParam(0, selected_info->GetVersion());
DrawString(tr, STR_AI_LIST_VERSION);
tr.top += FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_normal;
if (selected_info->GetURL() != nullptr) {
if (!selected_info->GetURL().empty()) {
SetDParamStr(0, selected_info->GetURL());
DrawString(tr, STR_AI_LIST_URL);
tr.top += FONT_HEIGHT_NORMAL + WidgetDimensions::scaled.vsep_normal;
@@ -174,7 +174,7 @@ struct ScriptListWindow : public Window {
{
if (_game_mode == GM_NORMAL && slot == OWNER_DEITY) Game::Uninitialize(false);
if (this->selected == -1) {
GetConfig(slot)->Change(nullptr);
GetConfig(slot)->Change(std::nullopt);
} else {
ScriptInfoList::const_iterator it = this->info_list->cbegin();
std::advance(it, this->selected);
@@ -439,13 +439,13 @@ struct ScriptSettingsWindow : public Window {
{
switch (widget) {
case WID_SCRS_BACKGROUND: {
Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero);
int num = (pt.y - r.top) / this->line_height + this->vscroll->GetPosition();
if (num >= (int)this->visible_settings.size()) break;
auto it = this->vscroll->GetScrolledItemFromWidget(this->visible_settings, pt.y, this, widget);
if (it == this->visible_settings.end()) break;
const ScriptConfigItem &config_item = *this->visible_settings[num];
const ScriptConfigItem &config_item = **it;
if (!this->IsEditableItem(config_item)) return;
int num = it - this->visible_settings.begin();
if (this->clicked_row != num) {
this->DeleteChildWindows(WC_QUERY_STRING);
HideDropDownMenu(this);
@@ -455,6 +455,7 @@ struct ScriptSettingsWindow : public Window {
bool bool_item = (config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0;
Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix, RectPadding::zero);
int x = pt.x - r.left;
if (_current_text_dir == TD_RTL) x = r.Width() - 1 - x;
@@ -711,7 +712,7 @@ struct ScriptDebugWindow : public Window {
bool autoscroll; ///< Whether automatically scrolling should be enabled or not.
bool show_break_box; ///< Whether the break/debug box is visible.
static bool break_check_enabled; ///< Stop an AI when it prints a matching string
static char break_string[MAX_BREAK_STR_STRING_LENGTH]; ///< The string to match to the AI output
static std::string break_string; ///< The string to match to the AI output
QueryString break_editbox; ///< Break editbox
static StringFilter break_string_filter; ///< Log filter for break.
static bool case_sensitive_break_check; ///< Is the matching done case-sensitive
@@ -1044,7 +1045,7 @@ struct ScriptDebugWindow : public Window {
if (wid != WID_SCRD_BREAK_STR_EDIT_BOX) return;
/* Save the current string to static member so it can be restored next time the window is opened. */
strecpy(this->break_string, this->break_editbox.text.buf, lastof(this->break_string));
this->break_string = this->break_editbox.text.buf;
break_string_filter.SetFilterTerm(this->break_string);
}
@@ -1121,7 +1122,7 @@ struct ScriptDebugWindow : public Window {
};
CompanyID ScriptDebugWindow::script_debug_company = INVALID_COMPANY;
char ScriptDebugWindow::break_string[MAX_BREAK_STR_STRING_LENGTH] = "";
std::string ScriptDebugWindow::break_string;
bool ScriptDebugWindow::break_check_enabled = true;
bool ScriptDebugWindow::case_sensitive_break_check = false;
StringFilter ScriptDebugWindow::break_string_filter(&ScriptDebugWindow::case_sensitive_break_check);

View File

@@ -14,27 +14,14 @@
#include "script_info.hpp"
#include "script_scanner.hpp"
#include "../3rdparty/fmt/format.h"
#include "../safeguards.h"
ScriptInfo::~ScriptInfo()
{
free(this->author);
free(this->name);
free(this->short_name);
free(this->description);
free(this->date);
free(this->instance_name);
free(this->url);
free(this->SQ_instance);
}
bool ScriptInfo::CheckMethod(const char *name) const
{
if (!this->engine->MethodExists(*this->SQ_instance, name)) {
char error[1024];
seprintf(error, lastof(error), "your info.nut/library.nut doesn't have the method '%s'", name);
this->engine->ThrowError(error);
if (!this->engine->MethodExists(this->SQ_instance, name)) {
this->engine->ThrowError(fmt::format("your info.nut/library.nut doesn't have the method '{}'", name));
return false;
}
return true;
@@ -43,10 +30,9 @@ bool ScriptInfo::CheckMethod(const char *name) const
/* static */ SQInteger ScriptInfo::Constructor(HSQUIRRELVM vm, ScriptInfo *info)
{
/* Set some basic info from the parent */
info->SQ_instance = MallocT<SQObject>(1);
Squirrel::GetInstance(vm, info->SQ_instance, 2);
Squirrel::GetInstance(vm, &info->SQ_instance, 2);
/* Make sure the instance stays alive over time */
sq_addref(vm, info->SQ_instance);
sq_addref(vm, &info->SQ_instance);
info->scanner = (ScriptScanner *)Squirrel::GetGlobalPointer(vm);
info->engine = info->scanner->GetEngine();
@@ -70,21 +56,21 @@ bool ScriptInfo::CheckMethod(const char *name) const
info->tar_file = info->scanner->GetTarFile();
/* Cache the data the info file gives us. */
if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAuthor", &info->author, MAX_GET_OPS)) return SQ_ERROR;
if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetName", &info->name, MAX_GET_OPS)) return SQ_ERROR;
if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetShortName", &info->short_name, MAX_GET_OPS)) return SQ_ERROR;
if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetDescription", &info->description, MAX_GET_OPS)) return SQ_ERROR;
if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetDate", &info->date, MAX_GET_OPS)) return SQ_ERROR;
if (!info->engine->CallIntegerMethod(*info->SQ_instance, "GetVersion", &info->version, MAX_GET_OPS)) return SQ_ERROR;
if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "CreateInstance", &info->instance_name, MAX_CREATEINSTANCE_OPS)) return SQ_ERROR;
if (!info->engine->CallStringMethod(info->SQ_instance, "GetAuthor", &info->author, MAX_GET_OPS)) return SQ_ERROR;
if (!info->engine->CallStringMethod(info->SQ_instance, "GetName", &info->name, MAX_GET_OPS)) return SQ_ERROR;
if (!info->engine->CallStringMethod(info->SQ_instance, "GetShortName", &info->short_name, MAX_GET_OPS)) return SQ_ERROR;
if (!info->engine->CallStringMethod(info->SQ_instance, "GetDescription", &info->description, MAX_GET_OPS)) return SQ_ERROR;
if (!info->engine->CallStringMethod(info->SQ_instance, "GetDate", &info->date, MAX_GET_OPS)) return SQ_ERROR;
if (!info->engine->CallIntegerMethod(info->SQ_instance, "GetVersion", &info->version, MAX_GET_OPS)) return SQ_ERROR;
if (!info->engine->CallStringMethod(info->SQ_instance, "CreateInstance", &info->instance_name, MAX_CREATEINSTANCE_OPS)) return SQ_ERROR;
/* The GetURL function is optional. */
if (info->engine->MethodExists(*info->SQ_instance, "GetURL")) {
if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetURL", &info->url, MAX_GET_OPS)) return SQ_ERROR;
if (info->engine->MethodExists(info->SQ_instance, "GetURL")) {
if (!info->engine->CallStringMethod(info->SQ_instance, "GetURL", &info->url, MAX_GET_OPS)) return SQ_ERROR;
}
/* Check if we have settings */
if (info->engine->MethodExists(*info->SQ_instance, "GetSettings")) {
if (info->engine->MethodExists(info->SQ_instance, "GetSettings")) {
if (!info->GetSettings()) return SQ_ERROR;
}
@@ -93,7 +79,7 @@ bool ScriptInfo::CheckMethod(const char *name) const
bool ScriptInfo::GetSettings()
{
return this->engine->CallMethod(*this->SQ_instance, "GetSettings", nullptr, MAX_GET_SETTING_OPS);
return this->engine->CallMethod(this->SQ_instance, "GetSettings", nullptr, MAX_GET_SETTING_OPS);
}
SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
@@ -168,9 +154,7 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
config.flags = (ScriptConfigFlags)res;
items |= 0x100;
} else {
char error[1024];
seprintf(error, lastof(error), "unknown setting property '%s'", key);
this->engine->ThrowError(error);
this->engine->ThrowError(fmt::format("unknown setting property '{}'", key));
return SQ_ERROR;
}
@@ -181,9 +165,7 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
/* Don't allow both random_deviation and SCRIPTCONFIG_RANDOM to
* be set for the same config item. */
if ((items & 0x200) != 0 && (config.flags & SCRIPTCONFIG_RANDOM) != 0) {
char error[1024];
seprintf(error, lastof(error), "Setting both random_deviation and SCRIPTCONFIG_RANDOM is not allowed");
this->engine->ThrowError(error);
this->engine->ThrowError("Setting both random_deviation and SCRIPTCONFIG_RANDOM is not allowed");
return SQ_ERROR;
}
/* Reset the bit for random_deviation as it's optional. */
@@ -192,9 +174,7 @@ SQInteger ScriptInfo::AddSetting(HSQUIRRELVM vm)
/* Make sure all properties are defined */
uint mask = (config.flags & SCRIPTCONFIG_BOOLEAN) ? 0x1F3 : 0x1FF;
if (items != mask) {
char error[1024];
seprintf(error, lastof(error), "please define all properties of a setting (min/max not allowed for booleans)");
this->engine->ThrowError(error);
this->engine->ThrowError("please define all properties of a setting (min/max not allowed for booleans)");
return SQ_ERROR;
}
@@ -214,9 +194,7 @@ SQInteger ScriptInfo::AddLabels(HSQUIRRELVM vm)
}
if (config == nullptr) {
char error[1024];
seprintf(error, lastof(error), "Trying to add labels for non-defined setting '%s'", setting_name);
this->engine->ThrowError(error);
this->engine->ThrowError(fmt::format("Trying to add labels for non-defined setting '{}'", setting_name));
return SQ_ERROR;
}
if (!config->labels.empty()) return SQ_ERROR;
@@ -263,7 +241,7 @@ const ScriptConfigItemList *ScriptInfo::GetConfigList() const
return &this->config_list;
}
const ScriptConfigItem *ScriptInfo::GetConfigItem(const std::string &name) const
const ScriptConfigItem *ScriptInfo::GetConfigItem(const std::string_view name) const
{
for (const auto &item : this->config_list) {
if (item.name == name) return &item;

View File

@@ -31,38 +31,29 @@ class ScriptInfo : public SimpleCountedObject {
public:
ScriptInfo() :
engine(nullptr),
SQ_instance(nullptr),
author(nullptr),
name(nullptr),
short_name(nullptr),
description(nullptr),
date(nullptr),
instance_name(nullptr),
version(0),
url(nullptr),
scanner(nullptr)
{}
~ScriptInfo();
/**
* Get the Author of the script.
*/
const char *GetAuthor() const { return this->author; }
const std::string &GetAuthor() const { return this->author; }
/**
* Get the Name of the script.
*/
const char *GetName() const { return this->name; }
const std::string &GetName() const { return this->name; }
/**
* Get the 4 character long short name of the script.
*/
const char *GetShortName() const { return this->short_name; }
const std::string &GetShortName() const { return this->short_name; }
/**
* Get the description of the script.
*/
const char *GetDescription() const { return this->description; }
const std::string &GetDescription() const { return this->description; }
/**
* Get the version of the script.
@@ -72,27 +63,27 @@ public:
/**
* Get the last-modified date of the script.
*/
const char *GetDate() const { return this->date; }
const std::string &GetDate() const { return this->date; }
/**
* Get the name of the instance of the script to create.
*/
const char *GetInstanceName() const { return this->instance_name; }
const std::string &GetInstanceName() const { return this->instance_name; }
/**
* Get the website for this script.
*/
const char *GetURL() const { return this->url; }
const std::string &GetURL() const { return this->url; }
/**
* Get the filename of the main.nut script.
*/
const char *GetMainScript() const { return this->main_script.c_str(); }
const std::string &GetMainScript() const { return this->main_script; }
/**
* Get the filename of the tar the script is in.
*/
std::string GetTarFile() const { return this->tar_file; }
const std::string &GetTarFile() const { return this->tar_file; }
/**
* Check if a given method exists.
@@ -122,7 +113,7 @@ public:
/**
* Get the description of a certain Script config option.
*/
const ScriptConfigItem *GetConfigItem(const std::string &name) const;
const ScriptConfigItem *GetConfigItem(const std::string_view name) const;
/**
* Set a setting.
@@ -146,20 +137,20 @@ public:
protected:
class Squirrel *engine; ///< Engine used to register for Squirrel.
HSQOBJECT *SQ_instance; ///< The Squirrel instance created for this info.
HSQOBJECT SQ_instance; ///< The Squirrel instance created for this info.
ScriptConfigItemList config_list; ///< List of settings from this Script.
private:
std::string main_script; ///< The full path of the script.
std::string tar_file; ///< If, which tar file the script was in.
const char *author; ///< Author of the script.
const char *name; ///< Full name of the script.
const char *short_name; ///< Short name (4 chars) which uniquely identifies the script.
const char *description; ///< Small description of the script.
const char *date; ///< The date the script was written at.
const char *instance_name; ///< Name of the main class in the script.
std::string author; ///< Author of the script.
std::string name; ///< Full name of the script.
std::string short_name; ///< Short name (4 chars) which uniquely identifies the script.
std::string description; ///< Small description of the script.
std::string date; ///< The date the script was written at.
std::string instance_name; ///< Name of the main class in the script.
int version; ///< Version of the script.
const char *url; ///< URL of the script.
std::string url; ///< URL of the script.
class ScriptScanner *scanner; ///< ScriptScanner object that was used to scan this script info.
};

View File

@@ -12,6 +12,7 @@
#include "../string_func.h"
#include "../strings_func.h"
#include "../3rdparty/fmt/format.h"
#include "../safeguards.h"
@@ -27,24 +28,21 @@
/** Run the dummy info.nut. */
void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir)
{
char dummy_script[4096];
char *dp = dummy_script;
dp += seprintf(dp, lastof(dummy_script), "class Dummy%s extends %sInfo {\n", type, type);
dp += seprintf(dp, lastof(dummy_script), "function GetAuthor() { return \"OpenTTD Developers Team\"; }\n");
dp += seprintf(dp, lastof(dummy_script), "function GetName() { return \"Dummy%s\"; }\n", type);
dp += seprintf(dp, lastof(dummy_script), "function GetShortName() { return \"DUMM\"; }\n");
dp += seprintf(dp, lastof(dummy_script), "function GetDescription() { return \"A Dummy %s that is loaded when your %s/ dir is empty\"; }\n", type, dir);
dp += seprintf(dp, lastof(dummy_script), "function GetVersion() { return 1; }\n");
dp += seprintf(dp, lastof(dummy_script), "function GetDate() { return \"2008-07-26\"; }\n");
dp += seprintf(dp, lastof(dummy_script), "function CreateInstance() { return \"Dummy%s\"; }\n", type);
dp += seprintf(dp, lastof(dummy_script), "} RegisterDummy%s(Dummy%s());\n", type, type);
const SQChar *sq_dummy_script = dummy_script;
std::string dummy_script = fmt::format(
"class Dummy{0} extends {0}Info {{\n"
"function GetAuthor() {{ return \"OpenTTD Developers Team\"; }}\n"
"function GetName() {{ return \"Dummy{0}\"; }}\n"
"function GetShortName() {{ return \"DUMM\"; }}\n"
"function GetDescription() {{ return \"A Dummy {0} that is loaded when your {1}/ dir is empty\"; }}\n"
"function GetVersion() {{ return 1; }}\n"
"function GetDate() {{ return \"2008-07-26\"; }}\n"
"function CreateInstance() {{ return \"Dummy{0}\"; }}\n"
"}} RegisterDummy{0}(Dummy{0}());\n", type, dir);
sq_pushroottable(vm);
/* Load and run the script */
if (SQ_SUCCEEDED(sq_compilebuffer(vm, sq_dummy_script, strlen(sq_dummy_script), "dummy", SQTrue))) {
if (SQ_SUCCEEDED(sq_compilebuffer(vm, dummy_script.c_str(), dummy_script.size(), "dummy", SQTrue))) {
sq_push(vm, -2);
if (SQ_SUCCEEDED(sq_call(vm, 1, SQFalse, SQTrue))) {
sq_pop(vm, 1);
@@ -54,52 +52,56 @@ void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir)
NOT_REACHED();
}
/**
* Split the given message on newlines ('\n') and escape quotes and (back)slashes,
* so they can be properly interpreted as string constants by the Squirrel compiler.
* @param message The message that we want to sanitize for use in Squirrel code.
* @return Vector with sanitized strings to use as string constant in Squirrel code.
*/
static std::vector<std::string> EscapeQuotesAndSlashesAndSplitOnNewLines(const std::string &message)
{
std::vector<std::string> messages;
std::string safe_message;
for (auto c : message) {
if (c == '\n') {
messages.emplace_back(std::move(safe_message));
continue;
}
if (c == '"' || c == '\\') safe_message.push_back('\\');
safe_message.push_back(c);
}
messages.emplace_back(std::move(safe_message));
return messages;
}
/** Run the dummy AI and let it generate an error message. */
void Script_CreateDummy(HSQUIRRELVM vm, StringID string, const char *type)
{
/* We want to translate the error message.
* We do this in three steps:
* 1) We get the error message
* 1) We get the error message, escape quotes and slashes, and split on
* newlines because Log.Error terminates passed strings at newlines.
*/
char error_message[1024];
GetString(error_message, string, lastof(error_message));
/* Make escapes for all quotes and slashes. */
char safe_error_message[1024];
char *q = safe_error_message;
for (const char *p = error_message; *p != '\0' && q < lastof(safe_error_message) - 2; p++, q++) {
if (*p == '"' || *p == '\\') *q++ = '\\';
*q = *p;
}
*q = '\0';
std::string error_message = GetString(string);
std::vector<std::string> messages = EscapeQuotesAndSlashesAndSplitOnNewLines(error_message);
/* 2) We construct the AI's code. This is done by merging a header, body and footer */
char dummy_script[4096];
char *dp = dummy_script;
dp += seprintf(dp, lastof(dummy_script), "class Dummy%s extends %sController {\n function Start()\n {\n", type, type);
std::string dummy_script;
auto back_inserter = std::back_inserter(dummy_script);
/* Just a rough ballpark estimate. */
dummy_script.reserve(error_message.size() + 128 + 64 * messages.size());
/* As special trick we need to split the error message on newlines and
* emit each newline as a separate error printing string. */
char *newline;
char *p = safe_error_message;
do {
newline = strchr(p, '\n');
if (newline != nullptr) *newline = '\0';
fmt::format_to(back_inserter, "class Dummy{0} extends {0}Controller {{\n function Start()\n {{\n", type);
for (std::string &message : messages) {
fmt::format_to(back_inserter, " {}Log.Error(\"{}\");\n", type, message);
}
dummy_script += " }\n}\n";
dp += seprintf(dp, lastof(dummy_script), " %sLog.Error(\"%s\");\n", type, p);
p = newline + 1;
} while (newline != nullptr);
strecpy(dp, " }\n}\n", lastof(dummy_script));
/* 3) We translate the error message in the character format that Squirrel wants.
* We can use the fact that the wchar string printing also uses %s to print
* old style char strings, which is what was generated during the script generation. */
const SQChar *sq_dummy_script = dummy_script;
/* And finally we load and run the script */
/* 3) Finally we load and run the script */
sq_pushroottable(vm);
if (SQ_SUCCEEDED(sq_compilebuffer(vm, sq_dummy_script, strlen(sq_dummy_script), "dummy", SQTrue))) {
if (SQ_SUCCEEDED(sq_compilebuffer(vm, dummy_script.c_str(), dummy_script.size(), "dummy", SQTrue))) {
sq_push(vm, -2);
if (SQ_SUCCEEDED(sq_call(vm, 1, SQFalse, SQTrue))) {
sq_pop(vm, 1);

View File

@@ -52,7 +52,6 @@ static void PrintFunc(bool error_msg, const SQChar *message)
ScriptInstance::ScriptInstance(const char *APIName, ScriptType script_type) :
engine(nullptr),
versionAPI(nullptr),
controller(nullptr),
storage(nullptr),
instance(nullptr),
@@ -72,7 +71,7 @@ ScriptInstance::ScriptInstance(const char *APIName, ScriptType script_type) :
this->engine->SetPrintFunction(&PrintFunc);
}
void ScriptInstance::Initialize(const char *main_script, const char *instance_name, CompanyID company)
void ScriptInstance::Initialize(const std::string &main_script, const std::string &instance_name, CompanyID company)
{
ScriptObject::ActiveInstance active(this);
@@ -85,7 +84,7 @@ void ScriptInstance::Initialize(const char *main_script, const char *instance_na
try {
ScriptObject::SetAllowDoCommand(false);
/* Load and execute the script for this script */
if (strcmp(main_script, "%_dummy") == 0) {
if (main_script == "%_dummy") {
this->LoadDummyScript();
} else if (!this->engine->LoadScript(main_script) || this->engine->IsSuspended()) {
if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to load script. AI is not started.");
@@ -94,7 +93,7 @@ void ScriptInstance::Initialize(const char *main_script, const char *instance_na
}
if (this->script_type == ScriptType::GS) {
if (strcmp(instance_name, "BeeRewardClass") == 0) {
if (instance_name == "BeeRewardClass") {
this->LoadCompatibilityScripts("brgs", GAME_DIR);
}
}
@@ -112,7 +111,7 @@ void ScriptInstance::Initialize(const char *main_script, const char *instance_na
ScriptObject::SetAllowDoCommand(true);
} catch (Script_FatalError &e) {
this->is_dead = true;
this->engine->ThrowError(e.GetErrorMessage().c_str());
this->engine->ThrowError(e.GetErrorMessage());
this->engine->ResumeError();
this->Died();
}
@@ -123,12 +122,12 @@ void ScriptInstance::RegisterAPI()
squirrel_register_std(this->engine);
}
bool ScriptInstance::LoadCompatibilityScripts(const char *api_version, Subdirectory dir)
bool ScriptInstance::LoadCompatibilityScripts(const std::string &api_version, Subdirectory dir)
{
const char *api_vers[] = { "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "1.9", "1.10", "1.11", "12", "13", "14" };
uint api_idx = 0;
for (; api_idx < lengthof(api_vers) ; api_idx++) {
if (strcmp(api_version, api_vers[api_idx]) == 0) break;
if (api_version == api_vers[api_idx]) break;
}
if (api_idx < 12) {
/* 13 and below */
@@ -136,13 +135,13 @@ bool ScriptInstance::LoadCompatibilityScripts(const char *api_version, Subdirect
}
char script_name[32];
seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version);
seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version.c_str());
for (Searchpath sp : _valid_searchpaths) {
std::string buf = FioGetDirectory(sp, dir);
buf += script_name;
if (!FileExists(buf)) continue;
if (this->engine->LoadScript(buf.c_str())) return true;
if (this->engine->LoadScript(buf)) return true;
ScriptLog::Error("Failed to load API compatibility script");
DEBUG(script, 0, "Error compiling / running API compatibility script: %s", buf.c_str());
@@ -265,7 +264,7 @@ void ScriptInstance::GameLoop()
this->callback = e.GetSuspendCallback();
} catch (Script_FatalError &e) {
this->is_dead = true;
this->engine->ThrowError(e.GetErrorMessage().c_str());
this->engine->ThrowError(e.GetErrorMessage());
this->engine->ResumeError();
this->Died();
}
@@ -286,7 +285,7 @@ void ScriptInstance::GameLoop()
this->callback = e.GetSuspendCallback();
} catch (Script_FatalError &e) {
this->is_dead = true;
this->engine->ThrowError(e.GetErrorMessage().c_str());
this->engine->ThrowError(e.GetErrorMessage());
this->engine->ResumeError();
this->Died();
}
@@ -544,7 +543,7 @@ void ScriptInstance::Save()
/* If we don't mark the script as dead here cleaning up the squirrel
* stack could throw Script_FatalError again. */
this->is_dead = true;
this->engine->ThrowError(e.GetErrorMessage().c_str());
this->engine->ThrowError(e.GetErrorMessage());
this->engine->ResumeError();
SaveEmpty();
/* We can't kill the script here, so mark it as crashed (not dead) and

View File

@@ -56,14 +56,14 @@ public:
* @param instance_name The name of the instance out of the script to load.
* @param company Which company this script is serving.
*/
void Initialize(const char *main_script, const char *instance_name, CompanyID company);
void Initialize(const std::string &main_script, const std::string &instance_name, CompanyID company);
/**
* Get the value of a setting of the current instance.
* @param name The name of the setting.
* @return the value for the setting, or -1 if the setting is not known.
*/
virtual int GetSetting(const char *name) = 0;
virtual int GetSetting(const std::string &name) = 0;
/**
* Find a library.
@@ -71,7 +71,7 @@ public:
* @param version The version the library should have.
* @return The library if found, nullptr otherwise.
*/
virtual class ScriptInfo *FindLibrary(const char *library, int version) = 0;
virtual class ScriptInfo *FindLibrary(const std::string &library, int version) = 0;
/**
* A script in multiplayer waits for the server to handle its DoCommand.
@@ -256,7 +256,7 @@ public:
protected:
class Squirrel *engine; ///< A wrapper around the squirrel vm.
const char *versionAPI; ///< Current API used by this script.
std::string versionAPI; ///< Current API used by this script.
/**
* Register all API functions to the VM.
@@ -269,7 +269,7 @@ protected:
* @param dir Subdirectory to find the scripts in
* @return true iff script loading should proceed
*/
bool LoadCompatibilityScripts(const char *api_version, Subdirectory dir);
bool LoadCompatibilityScripts(const std::string &api_version, Subdirectory dir);
/**
* Tell the script it died.

View File

@@ -29,7 +29,7 @@ bool ScriptScanner::AddFile(const std::string &filename, size_t basepath_length,
this->main_script = filename;
this->tar_file = tar_filename;
auto p = this->main_script.rfind(PATHSEPCHAR);
auto p = this->main_script.find_last_of(PATHSEPCHAR);
this->main_script.erase(p != std::string::npos ? p + 1 : 0);
this->main_script += "main.nut";
@@ -37,7 +37,7 @@ bool ScriptScanner::AddFile(const std::string &filename, size_t basepath_length,
this->ResetEngine();
try {
this->engine->LoadScript(filename.c_str());
this->engine->LoadScript(filename);
} catch (Script_FatalError &e) {
DEBUG(script, 0, "Fatal error '%s' when trying to load the script '%s'.", e.GetErrorMessage().c_str(), filename.c_str());
return false;
@@ -98,8 +98,8 @@ void ScriptScanner::RegisterScript(ScriptInfo *info)
std::string script_name = fmt::format("{}.{}", script_original_name, info->GetVersion());
/* Check if GetShortName follows the rules */
if (strlen(info->GetShortName()) != 4) {
DEBUG(script, 0, "The script '%s' returned a string from GetShortName() which is not four characaters. Unable to load the script.", info->GetName());
if (info->GetShortName().size() != 4) {
DEBUG(script, 0, "The script '%s' returned a string from GetShortName() which is not four characaters. Unable to load the script.", info->GetName().c_str());
delete info;
return;
}
@@ -108,17 +108,17 @@ void ScriptScanner::RegisterScript(ScriptInfo *info)
/* This script was already registered */
#ifdef _WIN32
/* Windows doesn't care about the case */
if (StrEqualsIgnoreCase(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) {
if (StrEqualsIgnoreCase(this->info_list[script_name]->GetMainScript(), info->GetMainScript())) {
#else
if (strcmp(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) {
if (this->info_list[script_name]->GetMainScript() == info->GetMainScript()) {
#endif
delete info;
return;
}
DEBUG(script, 1, "Registering two scripts with the same name and version");
DEBUG(script, 1, " 1: %s", this->info_list[script_name]->GetMainScript());
DEBUG(script, 1, " 2: %s", info->GetMainScript());
DEBUG(script, 1, " 1: %s", this->info_list[script_name]->GetMainScript().c_str());
DEBUG(script, 1, " 2: %s", info->GetMainScript().c_str());
DEBUG(script, 1, "The first is taking precedence.");
delete info;
@@ -146,7 +146,7 @@ std::string ScriptScanner::GetConsoleList(bool newest_only) const
const ScriptInfoList &list = newest_only ? this->info_single_list : this->info_list;
for (const auto &item : list) {
ScriptInfo *i = item.second;
p += stdstr_fmt("%10s (v%d): %s\n", i->GetName(), i->GetVersion(), i->GetDescription());
p += stdstr_fmt("%10s (v%d): %s\n", i->GetName().c_str(), i->GetVersion(), i->GetDescription().c_str());
}
p += "\n";
@@ -207,7 +207,7 @@ struct ScriptFileChecksumCreator : FileScanner {
static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, Subdirectory dir)
{
uint32 id = 0;
const char *str = info->GetShortName();
const char *str = info->GetShortName().c_str();
for (int j = 0; j < 4 && *str != '\0'; j++, str++) id |= *str << (8 * j);
if (id != ci->unique_id) return false;
@@ -230,12 +230,11 @@ static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, S
checksum.AddFile(tar.first, 0, tar_filename);
}
} else {
char path[MAX_PATH];
strecpy(path, info->GetMainScript(), lastof(path));
/* There'll always be at least 1 path separator character in a script
* main script name as the search algorithm requires the main script to
* be in a subdirectory of the script directory; so <dir>/<path>/main.nut. */
*strrchr(path, PATHSEPCHAR) = '\0';
const std::string &main_script = info->GetMainScript();
std::string path = main_script.substr(0, main_script.find_last_of(PATHSEPCHAR));
checksum.Scan(".nut", path);
}
@@ -253,7 +252,7 @@ bool ScriptScanner::HasScript(const ContentInfo *ci, bool md5sum)
const char *ScriptScanner::FindMainScript(const ContentInfo *ci, bool md5sum)
{
for (const auto &item : this->info_list) {
if (IsSameScript(ci, md5sum, item.second, this->GetDirectory())) return item.second->GetMainScript();
if (IsSameScript(ci, md5sum, item.second, this->GetDirectory())) return item.second->GetMainScript().c_str();
}
return nullptr;
}

View File

@@ -459,13 +459,12 @@ bool Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT
return true;
}
bool Squirrel::CallStringMethodStrdup(HSQOBJECT instance, const char *method_name, const char **res, int suspend)
bool Squirrel::CallStringMethod(HSQOBJECT instance, const char *method_name, std::string *res, int suspend)
{
HSQOBJECT ret;
if (!this->CallMethod(instance, method_name, &ret, suspend)) return false;
if (ret._type != OT_STRING) return false;
*res = stredup(ObjectToString(&ret));
StrMakeValidInPlace(const_cast<char *>(*res));
*res = StrMakeValid(ObjectToString(&ret));
return true;
}
@@ -487,7 +486,7 @@ bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool
return true;
}
/* static */ bool Squirrel::CreateClassInstanceVM(HSQUIRRELVM vm, const char *class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name)
/* static */ bool Squirrel::CreateClassInstanceVM(HSQUIRRELVM vm, const std::string &class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name)
{
Squirrel *engine = (Squirrel *)sq_getforeignptr(vm);
@@ -497,24 +496,22 @@ bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool
sq_pushroottable(vm);
if (prepend_API_name) {
size_t len = strlen(class_name) + strlen(engine->GetAPIName()) + 1;
char *class_name2 = (char *)alloca(len);
seprintf(class_name2, class_name2 + len - 1, "%s%s", engine->GetAPIName(), class_name);
sq_pushstring(vm, class_name2, -1);
std::string prepended_class_name = engine->GetAPIName();
prepended_class_name += class_name;
sq_pushstring(vm, prepended_class_name, -1);
} else {
sq_pushstring(vm, class_name, -1);
}
if (SQ_FAILED(sq_get(vm, -2))) {
DEBUG(misc, 0, "[squirrel] Failed to find class by the name '%s%s'", prepend_API_name ? engine->GetAPIName() : "", class_name);
DEBUG(misc, 0, "[squirrel] Failed to find class by the name '%s%s'", prepend_API_name ? engine->GetAPIName() : "", class_name.c_str());
sq_settop(vm, oldtop);
return false;
}
/* Create the instance */
if (SQ_FAILED(sq_createinstance(vm, -1))) {
DEBUG(misc, 0, "[squirrel] Failed to create instance for class '%s%s'", prepend_API_name ? engine->GetAPIName() : "", class_name);
DEBUG(misc, 0, "[squirrel] Failed to create instance for class '%s%s'", prepend_API_name ? engine->GetAPIName() : "", class_name.c_str());
sq_settop(vm, oldtop);
return false;
}
@@ -537,7 +534,7 @@ bool Squirrel::CallBoolMethod(HSQOBJECT instance, const char *method_name, bool
return true;
}
bool Squirrel::CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance)
bool Squirrel::CreateClassInstance(const std::string &class_name, void *real_instance, HSQOBJECT *instance)
{
ScriptAllocatorScope alloc_scope(this);
return Squirrel::CreateClassInstanceVM(this->vm, class_name, real_instance, instance, nullptr);
@@ -651,7 +648,7 @@ static SQInteger _io_file_read(SQUserPointer file, SQUserPointer buf, SQInteger
return ret;
}
SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printerror)
SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const std::string &filename, SQBool printerror)
{
ScriptAllocatorScope alloc_scope(this);
@@ -729,7 +726,7 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printer
}
SQFile f(file, size);
if (SQ_SUCCEEDED(sq_compile(vm, func, &f, filename, printerror))) {
if (SQ_SUCCEEDED(sq_compile(vm, func, &f, filename.c_str(), printerror))) {
FioFCloseFile(file);
return SQ_OK;
}
@@ -737,7 +734,7 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printer
return SQ_ERROR;
}
bool Squirrel::LoadScript(HSQUIRRELVM vm, const char *script, bool in_root)
bool Squirrel::LoadScript(HSQUIRRELVM vm, const std::string &script, bool in_root)
{
ScriptAllocatorScope alloc_scope(this);
@@ -757,11 +754,11 @@ bool Squirrel::LoadScript(HSQUIRRELVM vm, const char *script, bool in_root)
}
vm->_ops_till_suspend = ops_left;
DEBUG(misc, 0, "[squirrel] Failed to compile '%s'", script);
DEBUG(misc, 0, "[squirrel] Failed to compile '%s'", script.c_str());
return false;
}
bool Squirrel::LoadScript(const char *script)
bool Squirrel::LoadScript(const std::string &script)
{
return LoadScript(this->vm, script);
}

View File

@@ -84,13 +84,13 @@ public:
* @param script The full script-name to load.
* @return False if loading failed.
*/
bool LoadScript(const char *script);
bool LoadScript(HSQUIRRELVM vm, const char *script, bool in_root = true);
bool LoadScript(const std::string &script);
bool LoadScript(HSQUIRRELVM vm, const std::string &script, bool in_root = true);
/**
* Load a file to a given VM.
*/
SQRESULT LoadFile(HSQUIRRELVM vm, const char *filename, SQBool printerror);
SQRESULT LoadFile(HSQUIRRELVM vm, const std::string &filename, SQBool printerror);
/**
* Adds a function to the stack. Depending on the current state this means
@@ -159,7 +159,7 @@ public:
*/
bool CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend);
bool CallMethod(HSQOBJECT instance, const char *method_name, int suspend) { return this->CallMethod(instance, method_name, nullptr, suspend); }
bool CallStringMethodStrdup(HSQOBJECT instance, const char *method_name, const char **res, int suspend);
bool CallStringMethod(HSQOBJECT instance, const char *method_name, std::string *res, int suspend);
bool CallIntegerMethod(HSQOBJECT instance, const char *method_name, int *res, int suspend);
bool CallBoolMethod(HSQOBJECT instance, const char *method_name, bool *res, int suspend);
@@ -178,12 +178,12 @@ public:
* @param prepend_API_name Optional parameter; if true, the class_name is prefixed with the current API name.
* @return False if creating failed.
*/
static bool CreateClassInstanceVM(HSQUIRRELVM vm, const char *class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name = false);
static bool CreateClassInstanceVM(HSQUIRRELVM vm, const std::string &class_name, void *real_instance, HSQOBJECT *instance, SQRELEASEHOOK release_hook, bool prepend_API_name = false);
/**
* Exactly the same as CreateClassInstanceVM, only callable without instance of Squirrel.
*/
bool CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance);
bool CreateClassInstance(const std::string &class_name, void *real_instance, HSQOBJECT *instance);
/**
* Get the real-instance pointer.
@@ -233,7 +233,7 @@ public:
/**
* Throw a Squirrel error that will be nicely displayed to the user.
*/
void ThrowError(const char *error) { sq_throwerror(this->vm, error); }
void ThrowError(const std::string_view error) { sq_throwerror(this->vm, error); }
/**
* Release a SQ object.

View File

@@ -16,6 +16,7 @@
#include "../string_func.h"
#include "../tile_type.h"
#include "squirrel_helper_type.hpp"
#include <optional>
template <class CL, ScriptType ST> const char *GetClassName();
@@ -23,19 +24,6 @@ template <class CL, ScriptType ST> const char *GetClassName();
* The Squirrel convert routines
*/
namespace SQConvert {
/**
* Pointers assigned to this class will be free'd when this instance
* comes out of scope. Useful to make sure you can use stredup(),
* without leaking memory.
*/
struct SQAutoFreePointers : std::vector<void *> {
~SQAutoFreePointers()
{
for (void * p : *this) free(p);
}
};
/**
* To return a value to squirrel, we use this helper class. It converts to the right format.
* We use a class instead of a plain function to allow us to use partial template specializations.
@@ -52,48 +40,58 @@ namespace SQConvert {
template <> struct Return<Money> { static inline int Set(HSQUIRRELVM vm, Money res) { sq_pushinteger(vm, res); return 1; } };
//template <> struct Return<TileIndex> { static inline int Set(HSQUIRRELVM vm, TileIndex res) { sq_pushinteger(vm, (int32)res.value); return 1; } };
template <> struct Return<bool> { static inline int Set(HSQUIRRELVM vm, bool res) { sq_pushbool (vm, res); return 1; } };
template <> struct Return<char *> { static inline int Set(HSQUIRRELVM vm, char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); free(res); } return 1; } };
template <> struct Return<const char *> { static inline int Set(HSQUIRRELVM vm, const char *res) { if (res == nullptr) sq_pushnull(vm); else { sq_pushstring(vm, res, -1); } return 1; } };
template <> struct Return<char *> { /* Do not use char *, use std::optional<std::string> instead. */ };
template <> struct Return<const char *> { /* Do not use const char *, use std::optional<std::string> instead. */ };
template <> struct Return<void *> { static inline int Set(HSQUIRRELVM vm, void *res) { sq_pushuserpointer(vm, res); return 1; } };
template <> struct Return<HSQOBJECT> { static inline int Set(HSQUIRRELVM vm, HSQOBJECT res) { sq_pushobject(vm, res); return 1; } };
template <> struct Return<std::optional<std::string>> {
static inline int Set(HSQUIRRELVM vm, std::optional<std::string> res) {
if (res.has_value()) {
sq_pushstring(vm, res.value(), -1);
} else {
sq_pushnull(vm);
}
return 1;
}
};
/**
* To get a param from squirrel, we use this helper class. It converts to the right format.
* We use a class instead of a plain function to allow us to use partial template specializations.
*/
template <typename T> struct Param;
template <> struct Param<uint8> { static inline uint8 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<uint16> { static inline uint16 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<uint32> { static inline uint32 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<int8> { static inline int8 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<int16> { static inline int16 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<int32> { static inline int32 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<int64> { static inline int64 Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
//template <> struct Param<TileIndex> { static inline TileIndex Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return TileIndex((uint32)(int32)tmp); } };
template <> struct Param<Money> { static inline Money Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<bool> { static inline bool Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQBool tmp; sq_getbool (vm, index, &tmp); return tmp != 0; } };
template <> struct Param<void *> { static inline void *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer tmp; sq_getuserpointer(vm, index, &tmp); return tmp; } };
template <> struct Param<uint8> { static inline uint8 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<uint16> { static inline uint16 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<uint32> { static inline uint32 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<int8> { static inline int8 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<int16> { static inline int16 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<int32> { static inline int32 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<int64> { static inline int64 Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
//template <> struct Param<TileIndex> { static inline TileIndex Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return TileIndex((uint32)(int32)tmp); } };
template <> struct Param<Money> { static inline Money Get(HSQUIRRELVM vm, int index) { SQInteger tmp; sq_getinteger (vm, index, &tmp); return tmp; } };
template <> struct Param<bool> { static inline bool Get(HSQUIRRELVM vm, int index) { SQBool tmp; sq_getbool (vm, index, &tmp); return tmp != 0; } };
template <> struct Param<const char *> { /* Do not use const char *, use std::string& instead. */ };
template <> struct Param<void *> { static inline void *Get(HSQUIRRELVM vm, int index) { SQUserPointer tmp; sq_getuserpointer(vm, index, &tmp); return tmp; } };
template <> struct Param<const char *> {
static inline const char *Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr)
template <> struct Param<const std::string &> {
static inline const std::string Get(HSQUIRRELVM vm, int index)
{
/* Convert what-ever there is as parameter to a string */
sq_tostring(vm, index);
const SQChar *tmp;
sq_getstring(vm, -1, &tmp);
char *tmp_str = stredup(tmp);
std::string result = StrMakeValid(tmp);
sq_poptop(vm);
ptr->push_back((void *)tmp_str);
StrMakeValidInPlace(tmp_str);
return tmp_str;
return result;
}
};
template <typename Titem>
struct Param<Array<Titem>> {
static inline Array<Titem> Get(HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr)
struct Param<Array<Titem> &&> {
static inline Array<Titem> Get(HSQUIRRELVM vm, int index)
{
/* Sanity check of the size. */
if (sq_getsize(vm, index) > UINT16_MAX) throw sq_throwerror(vm, "an array used as parameter to a function is too large");
@@ -106,7 +104,7 @@ namespace SQConvert {
Array<Titem> data;
while (SQ_SUCCEEDED(sq_next(vm, -2))) {
data.emplace_back(Param<Titem>::Get(vm, -1, ptr));
data.emplace_back(Param<Titem>::Get(vm, -1));
sq_pop(vm, 2);
}
sq_pop(vm, 2);
@@ -136,15 +134,14 @@ namespace SQConvert {
template <size_t... i>
static int SQCall(void *instance, Tretval(*func)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence<i...>)
{
[[maybe_unused]] SQAutoFreePointers ptr;
if constexpr (std::is_void_v<Tretval>) {
(*func)(
Param<Targs>::Get(vm, 2 + i, &ptr)...
Param<Targs>::Get(vm, 2 + i)...
);
return 0;
} else {
Tretval ret = (*func)(
Param<Targs>::Get(vm, 2 + i, &ptr)...
Param<Targs>::Get(vm, 2 + i)...
);
return Return<Tretval>::Set(vm, ret);
}
@@ -170,15 +167,14 @@ namespace SQConvert {
template <size_t... i>
static int SQCall(Tcls *instance, Tretval(Tcls:: *func)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence<i...>)
{
[[maybe_unused]] SQAutoFreePointers ptr;
if constexpr (std::is_void_v<Tretval>) {
(instance->*func)(
Param<Targs>::Get(vm, 2 + i, &ptr)...
Param<Targs>::Get(vm, 2 + i)...
);
return 0;
} else {
Tretval ret = (instance->*func)(
Param<Targs>::Get(vm, 2 + i, &ptr)...
Param<Targs>::Get(vm, 2 + i)...
);
return Return<Tretval>::Set(vm, ret);
}
@@ -187,9 +183,8 @@ namespace SQConvert {
template <size_t... i>
static Tcls *SQConstruct(Tcls *, Tretval(Tcls:: *func)(Targs...), [[maybe_unused]] HSQUIRRELVM vm, std::index_sequence<i...>)
{
[[maybe_unused]] SQAutoFreePointers ptr;
Tcls *inst = new Tcls(
Param<Targs>::Get(vm, 2 + i, &ptr)...
Param<Targs>::Get(vm, 2 + i)...
);
return inst;

View File

@@ -54,18 +54,14 @@ SQInteger SquirrelStd::require(HSQUIRRELVM vm)
return SQ_ERROR;
}
char path[MAX_PATH];
strecpy(path, si.source, lastof(path));
/* Keep the dir, remove the rest */
SQChar *s = strrchr(path, PATHSEPCHAR);
if (s != nullptr) {
/* Keep the PATHSEPCHAR there, remove the rest */
s++;
*s = '\0';
}
strecat(path, filename, lastof(path));
std::string path = si.source;
auto p = path.find_last_of(PATHSEPCHAR);
/* Keep the PATHSEPCHAR there, remove the rest */
if (p != std::string::npos) path.erase(p + 1);
path += filename;
#if (PATHSEPCHAR != '/')
for (char *n = path; *n != '\0'; n++) if (*n == '/') *n = PATHSEPCHAR;
std::transform(path.begin(), path.end(), path.begin(), [](char &c) { return c == '/' ? PATHSEPCHAR : c; });
#endif
Squirrel *engine = (Squirrel *)sq_getforeignptr(vm);