Merge branch 'master' into jgrpp
# Conflicts: # .github/workflows/commit-checker.yml # src/industry_cmd.cpp # src/industry_gui.cpp # src/landscape.cpp # src/linkgraph/linkgraph_gui.cpp # src/order_base.h # src/order_cmd.cpp # src/order_gui.cpp # src/saveload/afterload.cpp # src/saveload/league_sl.cpp # src/saveload/saveload.h # src/script/api/script_object.hpp # src/script/squirrel_helper.hpp # src/settings_table.cpp # src/station_cmd.cpp # src/table/settings.h.preamble # src/tree_cmd.cpp # src/tree_map.h # src/vehicle.cpp # src/waypoint_cmd.cpp
This commit is contained in:
@@ -19,6 +19,8 @@
|
||||
#include "../script_suspend.hpp"
|
||||
#include "../squirrel.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
struct CommandAuxiliaryBase;
|
||||
|
||||
/**
|
||||
@@ -342,4 +344,68 @@ private:
|
||||
static Randomizer random_states[OWNER_END]; ///< Random states for each of the scripts (game script uses OWNER_DEITY)
|
||||
};
|
||||
|
||||
/**
|
||||
* Internally used class to automate the ScriptObject reference counting.
|
||||
* @api -all
|
||||
*/
|
||||
template <typename T>
|
||||
class ScriptObjectRef {
|
||||
private:
|
||||
T *data; ///< The reference counted object.
|
||||
public:
|
||||
/**
|
||||
* Create the reference counter for the given ScriptObject instance.
|
||||
* @param data The underlying object.
|
||||
*/
|
||||
ScriptObjectRef(T *data) : data(data)
|
||||
{
|
||||
this->data->AddRef();
|
||||
}
|
||||
|
||||
/* No copy constructor. */
|
||||
ScriptObjectRef(const ScriptObjectRef<T> &ref) = delete;
|
||||
|
||||
/* Move constructor. */
|
||||
ScriptObjectRef(ScriptObjectRef<T> &&ref) noexcept : data(std::exchange(ref.data, nullptr))
|
||||
{
|
||||
}
|
||||
|
||||
/* No copy assignment. */
|
||||
ScriptObjectRef& operator=(const ScriptObjectRef<T> &other) = delete;
|
||||
|
||||
/* Move assignment. */
|
||||
ScriptObjectRef& operator=(ScriptObjectRef<T> &&other) noexcept
|
||||
{
|
||||
std::swap(this->data, other.data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the reference counted object.
|
||||
*/
|
||||
~ScriptObjectRef()
|
||||
{
|
||||
if (this->data != nullptr) this->data->Release();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dereferencing this reference returns a reference to the reference
|
||||
* counted object
|
||||
* @return Reference to the underlying object.
|
||||
*/
|
||||
T &operator*()
|
||||
{
|
||||
return *this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* The arrow operator on this reference returns the reference counted object.
|
||||
* @return Pointer to the underlying object.
|
||||
*/
|
||||
T *operator->()
|
||||
{
|
||||
return this->data;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* SCRIPT_OBJECT_HPP */
|
||||
|
@@ -45,7 +45,7 @@ SQInteger ScriptPriorityQueue::Insert(HSQUIRRELVM vm)
|
||||
this->queue.emplace_back(priority, item);
|
||||
std::push_heap(this->queue.begin(), this->queue.end(), this->comp);
|
||||
|
||||
return SQConvert::Return(vm, true);
|
||||
return SQConvert::Return<bool>::Set(vm, true);
|
||||
}
|
||||
|
||||
SQInteger ScriptPriorityQueue::Pop(HSQUIRRELVM vm)
|
||||
@@ -61,7 +61,7 @@ SQInteger ScriptPriorityQueue::Pop(HSQUIRRELVM vm)
|
||||
this->queue.pop_back();
|
||||
|
||||
/* Store the object on the Squirrel stack before releasing it to make sure the ref count can't drop to zero. */
|
||||
auto ret = SQConvert::Return(vm, item);
|
||||
auto ret = SQConvert::Return<HSQOBJECT>::Set(vm, item);
|
||||
sq_release(vm, &item);
|
||||
return ret;
|
||||
}
|
||||
@@ -74,7 +74,7 @@ SQInteger ScriptPriorityQueue::Peek(HSQUIRRELVM vm)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return SQConvert::Return(vm, this->queue.front().second);
|
||||
return SQConvert::Return<HSQOBJECT>::Set(vm, this->queue.front().second);
|
||||
}
|
||||
|
||||
SQInteger ScriptPriorityQueue::Exists(HSQUIRRELVM vm)
|
||||
@@ -83,7 +83,7 @@ SQInteger ScriptPriorityQueue::Exists(HSQUIRRELVM vm)
|
||||
sq_resetobject(&item);
|
||||
sq_getstackobj(vm, 2, &item);
|
||||
|
||||
return SQConvert::Return(vm, std::find(this->queue.cbegin(), this->queue.cend(), item) != this->queue.cend());
|
||||
return SQConvert::Return<bool>::Set(vm, std::find(this->queue.cbegin(), this->queue.cend(), item) != this->queue.cend());
|
||||
}
|
||||
|
||||
SQInteger ScriptPriorityQueue::Clear(HSQUIRRELVM vm)
|
||||
|
@@ -162,9 +162,9 @@
|
||||
* @param end The part that will be build second.
|
||||
* @return True if and only if the road bits can be build.
|
||||
*/
|
||||
static bool CheckAutoExpandedRoadBits(const Array *existing, int32 start, int32 end)
|
||||
static bool CheckAutoExpandedRoadBits(const Array<> &existing, int32 start, int32 end)
|
||||
{
|
||||
return (start + end == 0) && (existing->size == 0 || existing->array[0] == start || existing->array[0] == end);
|
||||
return (start + end == 0) && (existing.empty() || existing[0] == start || existing[0] == end);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,7 +177,7 @@ static bool CheckAutoExpandedRoadBits(const Array *existing, int32 start, int32
|
||||
* they are build or 2 when building the first part automatically
|
||||
* builds the second part.
|
||||
*/
|
||||
static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array *existing, int32 start, int32 end)
|
||||
static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array<> &existing, int32 start, int32 end)
|
||||
{
|
||||
switch (slope) {
|
||||
/* Flat slopes can always be build. */
|
||||
@@ -189,9 +189,9 @@ static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array *existing, in
|
||||
* in the game have been changed.
|
||||
*/
|
||||
case SLOPE_NE: case SLOPE_SW:
|
||||
return (CheckAutoExpandedRoadBits(existing, start, end) && (start == 1 || end == 1)) ? (existing->size == 0 ? 2 : 1) : 0;
|
||||
return (CheckAutoExpandedRoadBits(existing, start, end) && (start == 1 || end == 1)) ? (existing.empty() ? 2 : 1) : 0;
|
||||
case SLOPE_SE: case SLOPE_NW:
|
||||
return (CheckAutoExpandedRoadBits(existing, start, end) && (start != 1 && end != 1)) ? (existing->size == 0 ? 2 : 1) : 0;
|
||||
return (CheckAutoExpandedRoadBits(existing, start, end) && (start != 1 && end != 1)) ? (existing.empty() ? 2 : 1) : 0;
|
||||
|
||||
/* Any other tile cannot be built on. */
|
||||
default:
|
||||
@@ -241,7 +241,7 @@ static RoadBits NeighbourToRoadBits(int32 neighbour)
|
||||
* they are build or 2 when building the first part automatically
|
||||
* builds the second part.
|
||||
*/
|
||||
static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start, int32 end)
|
||||
static int32 LookupWithBuildOnSlopes(::Slope slope, const Array<> &existing, int32 start, int32 end)
|
||||
{
|
||||
/* Steep slopes behave the same as slopes with one corner raised. */
|
||||
if (IsSteepSlope(slope)) {
|
||||
@@ -291,9 +291,6 @@ static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start
|
||||
|
||||
/* Now perform the actual rotation. */
|
||||
for (int j = 0; j < base_rotate; j++) {
|
||||
for (size_t i = 0; i < existing->size; i++) {
|
||||
existing->array[i] = RotateNeighbour(existing->array[i]);
|
||||
}
|
||||
start = RotateNeighbour(start);
|
||||
end = RotateNeighbour(end);
|
||||
}
|
||||
@@ -302,8 +299,11 @@ static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start
|
||||
RoadBits start_roadbits = NeighbourToRoadBits(start);
|
||||
RoadBits new_roadbits = start_roadbits | NeighbourToRoadBits(end);
|
||||
RoadBits existing_roadbits = ROAD_NONE;
|
||||
for (size_t i = 0; i < existing->size; i++) {
|
||||
existing_roadbits |= NeighbourToRoadBits(existing->array[i]);
|
||||
for (int32 neighbour : existing) {
|
||||
for (int j = 0; j < base_rotate; j++) {
|
||||
neighbour = RotateNeighbour(neighbour);
|
||||
}
|
||||
existing_roadbits |= NeighbourToRoadBits(neighbour);
|
||||
}
|
||||
|
||||
switch (slope) {
|
||||
@@ -391,7 +391,7 @@ static bool NormaliseTileOffset(int32 *tile)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */ int32 ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array *existing, TileIndex start_, TileIndex end_)
|
||||
/* static */ int32 ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::Slope slope_, Array<> existing, TileIndex start_, TileIndex end_)
|
||||
{
|
||||
::Slope slope = (::Slope)slope_;
|
||||
int32 start = start_;
|
||||
@@ -400,8 +400,8 @@ static bool NormaliseTileOffset(int32 *tile)
|
||||
/* The start tile and end tile cannot be the same tile either. */
|
||||
if (start == end) return -1;
|
||||
|
||||
for (size_t i = 0; i < existing->size; i++) {
|
||||
if (!NormaliseTileOffset(&existing->array[i])) return -1;
|
||||
for (size_t i = 0; i < existing.size(); i++) {
|
||||
if (!NormaliseTileOffset(&existing[i])) return -1;
|
||||
}
|
||||
|
||||
if (!NormaliseTileOffset(&start)) return -1;
|
||||
@@ -419,8 +419,6 @@ static bool NormaliseTileOffset(int32 *tile)
|
||||
|
||||
/* ROAD_NW ROAD_SW ROAD_SE ROAD_NE */
|
||||
const TileIndexDiff neighbours[] = {::TileDiffXY(0, -1), ::TileDiffXY(1, 0), ::TileDiffXY(0, 1), ::TileDiffXY(-1, 0)};
|
||||
Array *existing = (Array*)alloca(sizeof(Array) + lengthof(neighbours) * sizeof(int32));
|
||||
existing->size = 0;
|
||||
|
||||
::RoadBits rb = ::ROAD_NONE;
|
||||
if (::IsNormalRoadTile(tile)) {
|
||||
@@ -428,8 +426,10 @@ static bool NormaliseTileOffset(int32 *tile)
|
||||
} else {
|
||||
rb = ::GetAnyRoadBits(tile, RTT_ROAD) | ::GetAnyRoadBits(tile, RTT_TRAM);
|
||||
}
|
||||
|
||||
Array<> existing;
|
||||
for (uint i = 0; i < lengthof(neighbours); i++) {
|
||||
if (HasBit(rb, i)) existing->array[existing->size++] = neighbours[i];
|
||||
if (HasBit(rb, i)) existing.emplace_back(neighbours[i]);
|
||||
}
|
||||
|
||||
return ScriptRoad::CanBuildConnectedRoadParts(ScriptTile::GetSlope(tile), existing, start - tile, end - tile);
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#define SCRIPT_ROAD_HPP
|
||||
|
||||
#include "script_tile.hpp"
|
||||
#include "../squirrel_helper_type.hpp"
|
||||
#include "../../../road.h"
|
||||
|
||||
/**
|
||||
@@ -264,7 +265,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 int32 CanBuildConnectedRoadParts(ScriptTile::Slope slope, struct Array *existing, TileIndex start, TileIndex end);
|
||||
static int32 CanBuildConnectedRoadParts(ScriptTile::Slope slope, Array<> existing, TileIndex start, TileIndex end);
|
||||
|
||||
/**
|
||||
* Lookup function for building road parts independent of whether the
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "../../stdafx.h"
|
||||
#include "../../string_func.h"
|
||||
#include "../../strings_func.h"
|
||||
#include "../../game/game_text.hpp"
|
||||
#include "script_text.hpp"
|
||||
#include "../script_fatalerror.hpp"
|
||||
#include "../../table/control_codes.h"
|
||||
@@ -24,7 +25,7 @@ RawText::RawText(const char *text) : text(text)
|
||||
|
||||
|
||||
ScriptText::ScriptText(HSQUIRRELVM vm) :
|
||||
string(STR_NULL), params(), parami(), paramt(), paramc(0)
|
||||
string(STR_NULL), param(), paramc(0)
|
||||
{
|
||||
int nparam = sq_gettop(vm) - 1;
|
||||
if (nparam < 1) {
|
||||
@@ -53,32 +54,16 @@ ScriptText::ScriptText(HSQUIRRELVM vm) :
|
||||
}
|
||||
}
|
||||
|
||||
ScriptText::~ScriptText()
|
||||
{
|
||||
for (int i = 0; i < SCRIPT_TEXT_MAX_PARAMETERS; i++) {
|
||||
free(this->params[i]);
|
||||
if (this->paramt[i] != nullptr) this->paramt[i]->Release();
|
||||
}
|
||||
}
|
||||
|
||||
SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
|
||||
{
|
||||
if (parameter >= SCRIPT_TEXT_MAX_PARAMETERS) return SQ_ERROR;
|
||||
|
||||
free(this->params[parameter]);
|
||||
if (this->paramt[parameter] != nullptr) this->paramt[parameter]->Release();
|
||||
|
||||
this->parami[parameter] = 0;
|
||||
this->params[parameter] = nullptr;
|
||||
this->paramt[parameter] = nullptr;
|
||||
|
||||
switch (sq_gettype(vm, -1)) {
|
||||
case OT_STRING: {
|
||||
const SQChar *value;
|
||||
sq_getstring(vm, -1, &value);
|
||||
|
||||
this->params[parameter] = stredup(value);
|
||||
StrMakeValidInPlace(this->params[parameter]);
|
||||
this->param[parameter] = StrMakeValid(value);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -86,7 +71,7 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
|
||||
SQInteger value;
|
||||
sq_getinteger(vm, -1, &value);
|
||||
|
||||
this->parami[parameter] = value;
|
||||
this->param[parameter] = value;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -109,8 +94,7 @@ SQInteger ScriptText::_SetParam(int parameter, HSQUIRRELVM vm)
|
||||
if (real_instance == nullptr) return SQ_ERROR;
|
||||
|
||||
ScriptText *value = static_cast<ScriptText *>(real_instance);
|
||||
value->AddRef();
|
||||
this->paramt[parameter] = value;
|
||||
this->param[parameter] = ScriptTextRef(value);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -185,19 +169,37 @@ char *ScriptText::_GetEncodedText(char *p, char *lastofp, int ¶m_count)
|
||||
{
|
||||
p += Utf8Encode(p, SCC_ENCODED);
|
||||
p += seprintf(p, lastofp, "%X", this->string);
|
||||
for (int i = 0; i < this->paramc; i++) {
|
||||
if (this->params[i] != nullptr) {
|
||||
p += seprintf(p, lastofp, ":\"%s\"", this->params[i]);
|
||||
param_count++;
|
||||
continue;
|
||||
|
||||
const StringParams ¶ms = GetGameStringParams(this->string);
|
||||
int cur_idx = 0;
|
||||
|
||||
for (const StringParam &cur_param : params) {
|
||||
if (cur_idx >= this->paramc) throw Script_FatalError("Not enough string parameters");
|
||||
|
||||
switch (cur_param.type) {
|
||||
case StringParam::RAW_STRING:
|
||||
if (!std::holds_alternative<std::string>(this->param[cur_idx])) throw Script_FatalError("Wrong string parameter type");
|
||||
p += seprintf(p, lastofp, ":\"%s\"", std::get<std::string>(this->param[cur_idx++]).c_str());
|
||||
break;
|
||||
|
||||
case StringParam::STRING: {
|
||||
if (!std::holds_alternative<ScriptTextRef>(this->param[cur_idx])) throw Script_FatalError("Wrong string parameter type");
|
||||
int count = 1; // 1 because the string id is included in consumed parameters
|
||||
p += seprintf(p, lastofp, ":");
|
||||
p = std::get<ScriptTextRef>(this->param[cur_idx++])->_GetEncodedText(p, lastofp, count);
|
||||
if (count != cur_param.consumes) throw Script_FatalError("Substring doesn't consume the expected amount of parameters.");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (cur_idx + cur_param.consumes > this->paramc) throw Script_FatalError("Not enough string parameters");
|
||||
for (int i = 0; i < cur_param.consumes; i++) {
|
||||
if (!std::holds_alternative<SQInteger>(this->param[cur_idx])) throw Script_FatalError("Wrong string parameter type");
|
||||
p += seprintf(p, lastofp,":" OTTD_PRINTFHEX64, std::get<SQInteger>(this->param[cur_idx++]));
|
||||
}
|
||||
}
|
||||
if (this->paramt[i] != nullptr) {
|
||||
p += seprintf(p, lastofp, ":");
|
||||
p = this->paramt[i]->_GetEncodedText(p, lastofp, param_count);
|
||||
continue;
|
||||
}
|
||||
p += seprintf(p, lastofp,":" OTTD_PRINTFHEX64, this->parami[i]);
|
||||
param_count++;
|
||||
|
||||
param_count += cur_param.consumes;
|
||||
}
|
||||
|
||||
return p;
|
||||
|
@@ -13,6 +13,8 @@
|
||||
#include "script_object.hpp"
|
||||
#include "../../core/alloc_type.hpp"
|
||||
|
||||
#include <variant>
|
||||
|
||||
/**
|
||||
* Internal parent object of all Text-like objects.
|
||||
* @api -all
|
||||
@@ -88,7 +90,6 @@ public:
|
||||
*/
|
||||
ScriptText(StringID string, ...);
|
||||
#endif /* DOXYGEN_API */
|
||||
~ScriptText();
|
||||
|
||||
#ifndef DOXYGEN_API
|
||||
/**
|
||||
@@ -127,10 +128,10 @@ public:
|
||||
virtual const std::string GetEncodedText();
|
||||
|
||||
private:
|
||||
using ScriptTextRef = ScriptObjectRef<ScriptText>;
|
||||
|
||||
StringID string;
|
||||
char *params[SCRIPT_TEXT_MAX_PARAMETERS];
|
||||
int64 parami[SCRIPT_TEXT_MAX_PARAMETERS];
|
||||
ScriptText *paramt[SCRIPT_TEXT_MAX_PARAMETERS];
|
||||
std::variant<SQInteger, std::string, ScriptTextRef> param[SCRIPT_TEXT_MAX_PARAMETERS];
|
||||
int paramc;
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user