Saveload: Use table format for order chunks

This commit is contained in:
Jonathan G Rennison 2024-07-23 18:27:07 +01:00
parent a6d0a37386
commit ce84b8995a
6 changed files with 332 additions and 210 deletions

View File

@ -42,7 +42,8 @@ namespace upstream_sl {
*/ */
struct OrderBackup : OrderBackupPool::PoolItem<&_order_backup_pool>, BaseConsist { struct OrderBackup : OrderBackupPool::PoolItem<&_order_backup_pool>, BaseConsist {
private: private:
friend SaveLoadTable GetOrderBackupDescription(); ///< Saving and loading of order backups. friend NamedSaveLoadTable GetOrderBackupDescription(); ///< Saving and loading of order backups.
friend struct OrderBackupDispatchScheduleStructHandler; ///< Saving and loading of order backups.
friend upstream_sl::SaveLoadTable upstream_sl::GetOrderBackupDescription(); ///< Saving and loading of order backups. friend upstream_sl::SaveLoadTable upstream_sl::GetOrderBackupDescription(); ///< Saving and loading of order backups.
friend void Load_BKOR(); ///< Creating empty orders upon savegame loading. friend void Load_BKOR(); ///< Creating empty orders upon savegame loading.
friend void Save_BKOR(); ///< Saving orders upon savegame saving. friend void Save_BKOR(); ///< Saving orders upon savegame saving.

View File

@ -104,12 +104,12 @@ struct Order : OrderPool::PoolItem<&_order_pool> {
private: private:
friend SaveLoadTable GetVehicleDescription(VehicleType vt); ///< Saving and loading the current order of vehicles. friend SaveLoadTable GetVehicleDescription(VehicleType vt); ///< Saving and loading the current order of vehicles.
friend void Load_VEHS(); ///< Loading of ancient vehicles. friend void Load_VEHS(); ///< Loading of ancient vehicles.
friend SaveLoadTable GetOrderDescription(); ///< Saving and loading of orders. friend NamedSaveLoadTable GetOrderDescription(); ///< Saving and loading of orders.
friend struct OrderExtraDataStructHandler; ///< Saving and loading of orders.
friend upstream_sl::SaveLoadTable upstream_sl::GetOrderDescription(); ///< Saving and loading of orders. friend upstream_sl::SaveLoadTable upstream_sl::GetOrderDescription(); ///< Saving and loading of orders.
friend upstream_sl::SlVehicleCommon; friend upstream_sl::SlVehicleCommon;
friend upstream_sl::SlVehicleDisaster; friend upstream_sl::SlVehicleDisaster;
friend void Load_ORDX(); ///< Saving and loading of orders. friend void Load_ORDX(); ///< Saving and loading of orders.
friend void Save_ORDX(); ///< Saving and loading of orders.
friend void Load_VEOX(); ///< Saving and loading of orders. friend void Load_VEOX(); ///< Saving and loading of orders.
friend void Save_VEOX(); ///< Saving and loading of orders. friend void Save_VEOX(); ///< Saving and loading of orders.
@ -750,7 +750,7 @@ struct DispatchSchedule {
static constexpr uint DEPARTURE_TAG_COUNT = 4; static constexpr uint DEPARTURE_TAG_COUNT = 4;
private: private:
friend SaveLoadTable GetDispatchScheduleDescription(); ///< Saving and loading of dispatch schedules friend NamedSaveLoadTable GetDispatchScheduleDescription(); ///< Saving and loading of dispatch schedules
std::vector<DispatchSlot> scheduled_dispatch; ///< Scheduled dispatch slots std::vector<DispatchSlot> scheduled_dispatch; ///< Scheduled dispatch slots
StateTicks scheduled_dispatch_start_tick = -1; ///< Scheduled dispatch start tick StateTicks scheduled_dispatch_start_tick = -1; ///< Scheduled dispatch start tick
@ -891,7 +891,7 @@ static_assert(DispatchSchedule::DEPARTURE_TAG_COUNT == 1 + (DispatchSlot::SDSF_L
struct OrderList : OrderListPool::PoolItem<&_orderlist_pool> { struct OrderList : OrderListPool::PoolItem<&_orderlist_pool> {
private: private:
friend void AfterLoadVehiclesPhase1(bool part_of_load); ///< For instantiating the shared vehicle chain friend void AfterLoadVehiclesPhase1(bool part_of_load); ///< For instantiating the shared vehicle chain
friend SaveLoadTable GetOrderListDescription(); ///< Saving and loading of order lists. friend NamedSaveLoadTable GetOrderListDescription(); ///< Saving and loading of order lists.
friend upstream_sl::SaveLoadTable upstream_sl::GetOrderListDescription(); ///< Saving and loading of order lists. friend upstream_sl::SaveLoadTable upstream_sl::GetOrderListDescription(); ///< Saving and loading of order lists.
friend void Ptrs_ORDL(); ///< Saving and loading of order lists. friend void Ptrs_ORDL(); ///< Saving and loading of order lists.

View File

@ -124,7 +124,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_TRAIN_FLAGS_EXTRA, XSCF_NULL, 1, 1, "train_flags_extra", nullptr, nullptr, nullptr }, { XSLFI_TRAIN_FLAGS_EXTRA, XSCF_NULL, 1, 1, "train_flags_extra", nullptr, nullptr, nullptr },
{ XSLFI_VEHICLE_FLAGS_EXTRA, XSCF_NULL, 1, 1, "veh_flags_extra", nullptr, nullptr, nullptr }, { XSLFI_VEHICLE_FLAGS_EXTRA, XSCF_NULL, 1, 1, "veh_flags_extra", nullptr, nullptr, nullptr },
{ XSLFI_TRAIN_THROUGH_LOAD, XSCF_NULL, 2, 2, "train_through_load", nullptr, nullptr, nullptr }, { XSLFI_TRAIN_THROUGH_LOAD, XSCF_NULL, 2, 2, "train_through_load", nullptr, nullptr, nullptr },
{ XSLFI_ORDER_EXTRA_DATA, XSCF_NULL, 3, 3, "order_extra_data", nullptr, nullptr, nullptr }, { XSLFI_ORDER_EXTRA_DATA, XSCF_NULL, 4, 4, "order_extra_data", nullptr, nullptr, nullptr },
{ XSLFI_WHOLE_MAP_CHUNK, XSCF_NULL, 2, 2, "whole_map_chunk", nullptr, nullptr, "WMAP" }, { XSLFI_WHOLE_MAP_CHUNK, XSCF_NULL, 2, 2, "whole_map_chunk", nullptr, nullptr, "WMAP" },
{ XSLFI_ST_LAST_VEH_TYPE, XSCF_NULL, 1, 1, "station_last_veh_type", nullptr, nullptr, nullptr }, { XSLFI_ST_LAST_VEH_TYPE, XSCF_NULL, 1, 1, "station_last_veh_type", nullptr, nullptr, nullptr },
{ XSLFI_SELL_AT_DEPOT_ORDER, XSCF_NULL, 1, 1, "sell_at_depot_order", nullptr, nullptr, nullptr }, { XSLFI_SELL_AT_DEPOT_ORDER, XSCF_NULL, 1, 1, "sell_at_depot_order", nullptr, nullptr, nullptr },

View File

@ -117,41 +117,77 @@ Order UnpackOldOrder(uint16_t packed)
return order; return order;
} }
SaveLoadTable GetOrderDescription() NamedSaveLoadTable GetOrderExtraInfoDescription()
{ {
static const SaveLoad _order_desc[] = { static const NamedSaveLoad _order_extra_info_desc[] = {
SLE_VAR(Order, type, SLE_UINT8), NSL("cargo_type_flags", SLE_CONDARR_X(OrderExtraInfo, cargo_type_flags, SLE_UINT8, 32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CARGO_TYPE_ORDERS, 1, 2))),
SLE_CONDVAR_X(Order, flags, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_FLAGS_EXTRA, 0, 0)), NSL("cargo_type_flags", SLE_CONDARR_X(OrderExtraInfo, cargo_type_flags, SLE_UINT8, NUM_CARGO, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CARGO_TYPE_ORDERS, 3))),
SLE_CONDVAR_X(Order, flags, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_FLAGS_EXTRA, 1)), NSL("xflags", SLE_CONDVAR_X(OrderExtraInfo, xflags, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA))),
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP)), NSL("xdata", SLE_CONDVAR_X(OrderExtraInfo, xdata, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_EXTRA_DATA))),
SLE_VAR(Order, dest, SLE_UINT16), NSL("xdata2", SLE_CONDVAR_X(OrderExtraInfo, xdata2, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_EXTRA_DATA, 3))),
SLE_REF(Order, next, REF_ORDER), NSL("dispatch_index", SLE_CONDVAR_X(OrderExtraInfo, dispatch_index, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 3))),
SLE_CONDVAR(Order, refit_cargo, SLE_UINT8, SLV_36, SL_MAX_VERSION), NSL("colour", SLE_CONDVAR_X(OrderExtraInfo, colour, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_EXTRA_DATA, 2))),
SLE_CONDNULL(1, SLV_36, SLV_182), // refit_subtype };
SLE_CONDVAR_X(Order, occupancy, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_OCCUPANCY)),
SLE_CONDVAR_X(Order, wait_time, SLE_FILE_U16 | SLE_VAR_U32, SLV_67, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA, 0, 5)), return _order_extra_info_desc;
SLE_CONDVAR_X(Order, wait_time, SLE_UINT32, SLV_67, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA, 6)), }
SLE_CONDVAR_X(Order, travel_time, SLE_FILE_U16 | SLE_VAR_U32, SLV_67, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA, 0, 5)),
SLE_CONDVAR_X(Order, travel_time, SLE_UINT32, SLV_67, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA, 6)), struct OrderExtraDataStructHandler final : public TypedSaveLoadStructHandler<OrderExtraDataStructHandler, Order> {
SLE_CONDVAR(Order, max_speed, SLE_UINT16, SLV_172, SL_MAX_VERSION), NamedSaveLoadTable GetDescription() const override
SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MORE_COND_ORDERS, 1, 6)), // jump_counter {
return GetOrderExtraInfoDescription();
}
void Save(Order *order) const override
{
if (!order->extra) return;
SlObjectSaveFiltered(order->extra.get(), this->GetLoadDescription());
}
void Load(Order *order) const override
{
order->AllocExtraInfo();
SlObjectLoadFiltered(order->extra.get(), this->GetLoadDescription());
}
};
NamedSaveLoadTable GetOrderDescription()
{
static const NamedSaveLoad _order_desc[] = {
NSL("type", SLE_VAR(Order, type, SLE_UINT8)),
NSL("flags", SLE_CONDVAR_X(Order, flags, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_FLAGS_EXTRA, 0, 0))),
NSL("flags", SLE_CONDVAR_X(Order, flags, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_FLAGS_EXTRA, 1))),
NSL("", SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP))),
NSL("dest", SLE_VAR(Order, dest, SLE_UINT16)),
NSL("next", SLE_REF(Order, next, REF_ORDER)),
NSL("refit_cargo", SLE_CONDVAR(Order, refit_cargo, SLE_UINT8, SLV_36, SL_MAX_VERSION)),
NSL("", SLE_CONDNULL(1, SLV_36, SLV_182)), // refit_subtype
NSL("occupancy", SLE_CONDVAR_X(Order, occupancy, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_OCCUPANCY))),
NSL("wait_time", SLE_CONDVAR_X(Order, wait_time, SLE_FILE_U16 | SLE_VAR_U32, SLV_67, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA, 0, 5))),
NSL("wait_time", SLE_CONDVAR_X(Order, wait_time, SLE_UINT32, SLV_67, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA, 6))),
NSL("travel_time", SLE_CONDVAR_X(Order, travel_time, SLE_FILE_U16 | SLE_VAR_U32, SLV_67, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA, 0, 5))),
NSL("travel_time", SLE_CONDVAR_X(Order, travel_time, SLE_UINT32, SLV_67, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA, 6))),
NSL("max_speed", SLE_CONDVAR(Order, max_speed, SLE_UINT16, SLV_172, SL_MAX_VERSION)),
NSL("", SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MORE_COND_ORDERS, 1, 6))), // jump_counter
/* Leftover from the minor savegame version stuff /* Leftover from the minor savegame version stuff
* We will never use those free bytes, but we have to keep this line to allow loading of old savegames */ * We will never use those free bytes, but we have to keep this line to allow loading of old savegames */
SLE_CONDNULL(10, SLV_5, SLV_36), NSL("", SLE_CONDNULL(10, SLV_5, SLV_36)),
NSLT_STRUCT<OrderExtraDataStructHandler>("extra"),
}; };
return _order_desc; return _order_desc;
} }
static std::vector<SaveLoad> _filtered_desc;
static void Save_ORDR() static void Save_ORDR()
{ {
_filtered_desc = SlFilterObject(GetOrderDescription()); SaveLoadTableData slt = SlTableHeader(GetOrderDescription());
for (Order *order : Order::Iterate()) { for (Order *order : Order::Iterate()) {
SlSetArrayIndex(order->index); SlSetArrayIndex(order->index);
SlObjectSaveFiltered(order, _filtered_desc); SlObjectSaveFiltered(order, slt);
} }
} }
@ -204,51 +240,26 @@ static void Load_ORDR()
if (prev != nullptr) prev->next = o; if (prev != nullptr) prev->next = o;
} }
} else { } else {
_filtered_desc = SlFilterObject(GetOrderDescription()); SaveLoadTableData slt = SlTableHeaderOrRiff(GetOrderDescription());
int index;
int index;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
Order *order = new (index) Order(); Order *order = new (index) Order();
SlObjectLoadFiltered(order, _filtered_desc); SlObjectLoadFiltered(order, slt);
}
}
}
const SaveLoadTable GetOrderExtraInfoDescription()
{
static const SaveLoad _order_extra_info_desc[] = {
SLE_CONDARR_X(OrderExtraInfo, cargo_type_flags, SLE_UINT8, 32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CARGO_TYPE_ORDERS, 1, 2)),
SLE_CONDARR_X(OrderExtraInfo, cargo_type_flags, SLE_UINT8, NUM_CARGO, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_CARGO_TYPE_ORDERS, 3)),
SLE_CONDVAR_X(OrderExtraInfo, xflags, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA)),
SLE_CONDVAR_X(OrderExtraInfo, xdata, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_EXTRA_DATA)),
SLE_CONDVAR_X(OrderExtraInfo, xdata2, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_EXTRA_DATA, 3)),
SLE_CONDVAR_X(OrderExtraInfo, dispatch_index, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 3)),
SLE_CONDVAR_X(OrderExtraInfo, colour, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_EXTRA_DATA, 2)),
};
return _order_extra_info_desc;
}
void Save_ORDX()
{
_filtered_desc = SlFilterObject(GetOrderExtraInfoDescription());
for (Order *order : Order::Iterate()) {
if (order->extra) {
SlSetArrayIndex(order->index);
SlObjectSaveFiltered(order->extra.get(), _filtered_desc);
} }
} }
} }
void Load_ORDX() void Load_ORDX()
{ {
_filtered_desc = SlFilterObject(GetOrderExtraInfoDescription()); SaveLoadTableData slt = SlTableHeaderOrRiff(GetOrderExtraInfoDescription());
int index; int index;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
Order *order = Order::GetIfValid(index); Order *order = Order::GetIfValid(index);
assert(order != nullptr); assert(order != nullptr);
order->AllocExtraInfo(); order->AllocExtraInfo();
SlObjectLoadFiltered(order->extra.get(), _filtered_desc); SlObjectLoadFiltered(order->extra.get(), slt);
} }
} }
@ -257,82 +268,122 @@ static void Ptrs_ORDR()
/* Orders from old savegames have pointers corrected in Load_ORDR */ /* Orders from old savegames have pointers corrected in Load_ORDR */
if (IsSavegameVersionBefore(SLV_5, 2)) return; if (IsSavegameVersionBefore(SLV_5, 2)) return;
SaveLoadTableData slt = SlPrepareNamedSaveLoadTableForPtrOrNull(GetOrderDescription());
for (Order *o : Order::Iterate()) { for (Order *o : Order::Iterate()) {
SlObject(o, GetOrderDescription()); SlObjectPtrOrNullFiltered(o, slt);
} }
} }
SaveLoadTable GetDispatchScheduleDescription() NamedSaveLoadTable GetDispatchSlotDescription()
{ {
static const SaveLoad _dispatch_scheduled_info_desc[] = { static const NamedSaveLoad _dispatch_slot_info_desc[] = {
SLEG_CONDVARVEC_X(_old_scheduled_dispatch_slots, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 1, 6)), NSL("offset", SLE_VAR(DispatchSlot, offset, SLE_UINT32)),
SLE_VAR(DispatchSchedule, scheduled_dispatch_duration, SLE_UINT32), NSL("flags", SLE_VAR(DispatchSlot, flags, SLE_UINT16)),
SLE_CONDVAR_X(DispatchSchedule, scheduled_dispatch_start_tick, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 1, 4)),
SLEG_CONDVAR_X(_old_scheduled_dispatch_start_full_date_fract, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 1, 4)),
SLE_CONDVAR_X(DispatchSchedule, scheduled_dispatch_start_tick, SLE_INT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 5)),
SLE_VAR(DispatchSchedule, scheduled_dispatch_last_dispatch, SLE_INT32),
SLE_VAR(DispatchSchedule, scheduled_dispatch_max_delay, SLE_INT32),
SLE_CONDSSTR_X(DispatchSchedule, name, SLE_STR, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 4)),
SLE_CONDVAR_X(DispatchSchedule, scheduled_dispatch_flags, SLE_FILE_U32 | SLE_VAR_U8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 6)),
};
return _dispatch_scheduled_info_desc;
}
SaveLoadTable GetDispatchSlotDescription()
{
static const SaveLoad _dispatch_slot_info_desc[] = {
SLE_VAR(DispatchSlot, offset, SLE_UINT32),
SLE_VAR(DispatchSlot, flags, SLE_UINT16),
}; };
return _dispatch_slot_info_desc; return _dispatch_slot_info_desc;
} }
SaveLoadTable GetOrderListDescription() struct DispatchSlotStructHandler final : public TypedSaveLoadStructHandler<DispatchSlotStructHandler, DispatchSchedule> {
NamedSaveLoadTable GetDescription() const override
{
return GetDispatchSlotDescription();
}
void Save(DispatchSchedule *ds) const override
{
SlSetStructListLength(ds->GetScheduledDispatchMutable().size());
for (DispatchSlot &slot : ds->GetScheduledDispatchMutable()) {
SlObjectSaveFiltered(&slot, this->GetLoadDescription());
}
}
void Load(DispatchSchedule *ds) const override
{
ds->GetScheduledDispatchMutable().resize(SlGetStructListLength(UINT32_MAX));
for (DispatchSlot &slot : ds->GetScheduledDispatchMutable()) {
SlObjectLoadFiltered(&slot, this->GetLoadDescription());
}
}
};
using DispatchSupplementaryNamePair = std::pair<const uint32_t, std::string>;
NamedSaveLoadTable GetDispatchSupplementaryNamePairDescription()
{ {
static const SaveLoad _orderlist_desc[] = { static const NamedSaveLoad _dispatch_name_pair_desc[] = {
SLE_REF(OrderList, first, REF_ORDER), NSL("key", SLTAG(SLTAG_CUSTOM_START, SLE_VAR(DispatchSupplementaryNamePair, first, SLE_UINT32))),
SLEG_CONDVAR_X(_jokerpp_separation_mode, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)), NSL("value", SLTAG(SLTAG_CUSTOM_START + 1, SLE_SSTR(DispatchSupplementaryNamePair, second, SLE_STR))),
SLE_CONDNULL_X(21, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)),
}; };
return _orderlist_desc; return _dispatch_name_pair_desc;
} }
static std::vector<SaveLoad> _filtered_ordl_desc; struct DispatchNameStructHandler final : public TypedSaveLoadStructHandler<DispatchNameStructHandler, DispatchSchedule> {
static std::vector<SaveLoad> _filtered_ordl_sd_desc; NamedSaveLoadTable GetDescription() const override
static std::vector<SaveLoad> _filtered_ordl_slot_desc;
static void SetupDescs_ORDL()
{
_filtered_ordl_desc = SlFilterObject(GetOrderListDescription());
_filtered_ordl_sd_desc = SlFilterObject(GetDispatchScheduleDescription());
_filtered_ordl_slot_desc = SlFilterObject(GetDispatchSlotDescription());
}
static void SaveDispatchSchedule(DispatchSchedule &ds)
{
SlObjectSaveFiltered(&ds, _filtered_ordl_sd_desc);
SlWriteUint32((uint32_t)ds.GetScheduledDispatchMutable().size());
for (DispatchSlot &slot : ds.GetScheduledDispatchMutable()) {
SlObjectSaveFiltered(&slot, _filtered_ordl_slot_desc);
}
{ {
btree::btree_map<uint32_t, std::string> &names = ds.GetSupplementaryNameMap(); return GetDispatchSupplementaryNamePairDescription();
SlWriteUint32((uint32_t)names.size()); }
for (auto &it : names) {
SlWriteUint32(it.first); void Save(DispatchSchedule *ds) const override
SlStdString(&(it.second), SLE_STR); {
btree::btree_map<uint32_t, std::string> &names = ds->GetSupplementaryNameMap();
SlSetStructListLength(names.size());
for (DispatchSupplementaryNamePair &it : names) {
SlObjectSaveFiltered(&it, this->GetLoadDescription());
} }
} }
void Load(DispatchSchedule *ds) const override
{
SaveLoadTable slt = this->GetLoadDescription();
if (slt.size() != 2 || slt[0].label_tag != SLTAG_CUSTOM_START || slt[1].label_tag != SLTAG_CUSTOM_START + 1) {
SlErrorCorrupt("Dispatch names sub-chunk fields not as expected");
}
size_t string_count = SlGetStructListLength(UINT32_MAX);
btree::btree_map<uint32_t, std::string> &names = ds->GetSupplementaryNameMap();
for (size_t i = 0; i < string_count; i++) {
uint32_t key = SlReadUint32();
SlStdString(&(names[key]), SLE_STR);
}
}
};
NamedSaveLoadTable GetDispatchScheduleDescription()
{
static const NamedSaveLoad _dispatch_scheduled_info_desc[] = {
NSL("", SLEG_CONDVARVEC_X(_old_scheduled_dispatch_slots, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 1, 6))),
NSL("duration", SLE_VAR(DispatchSchedule, scheduled_dispatch_duration, SLE_UINT32)),
NSL("", SLE_CONDVAR_X(DispatchSchedule, scheduled_dispatch_start_tick, SLE_FILE_I32 | SLE_VAR_I64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 1, 4))),
NSL("", SLEG_CONDVAR_X(_old_scheduled_dispatch_start_full_date_fract, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 1, 4))),
NSL("start_tick", SLE_CONDVAR_X(DispatchSchedule, scheduled_dispatch_start_tick, SLE_INT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 5))),
NSL("last_dispatch", SLE_VAR(DispatchSchedule, scheduled_dispatch_last_dispatch, SLE_INT32)),
NSL("max_delay", SLE_VAR(DispatchSchedule, scheduled_dispatch_max_delay, SLE_INT32)),
NSL("name", SLE_CONDSSTR_X(DispatchSchedule, name, SLE_STR, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 4))),
NSL("flags", SLE_CONDVAR_X(DispatchSchedule, scheduled_dispatch_flags, SLE_FILE_U32 | SLE_VAR_U8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 6))),
NSLT_STRUCTLIST<DispatchSlotStructHandler>("slots"),
NSLT_STRUCTLIST<DispatchNameStructHandler>("names"),
};
return _dispatch_scheduled_info_desc;
} }
static void LoadDispatchSchedule(DispatchSchedule &ds) struct ScheduledDispatchNonTableHelper {
{ std::vector<SaveLoad> dispatch_desc;
SlObjectLoadFiltered(&ds, _filtered_ordl_sd_desc); std::vector<SaveLoad> slot_desc;
void Setup()
{
this->dispatch_desc = SlFilterNamedSaveLoadTable(GetDispatchScheduleDescription());
this->slot_desc = SlFilterNamedSaveLoadTable(GetDispatchSlotDescription());
}
void LoadDispatchSchedule(DispatchSchedule &ds)
{
SlObjectLoadFiltered(&ds, this->dispatch_desc);
if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 1, 4) && _old_scheduled_dispatch_start_full_date_fract != 0) { if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 1, 4) && _old_scheduled_dispatch_start_full_date_fract != 0) {
_old_scheduled_dispatch_start_full_date_fract_map[&ds] = _old_scheduled_dispatch_start_full_date_fract; _old_scheduled_dispatch_start_full_date_fract_map[&ds] = _old_scheduled_dispatch_start_full_date_fract;
} }
@ -345,7 +396,7 @@ static void LoadDispatchSchedule(DispatchSchedule &ds)
} else { } else {
ds.GetScheduledDispatchMutable().resize(SlReadUint32()); ds.GetScheduledDispatchMutable().resize(SlReadUint32());
for (DispatchSlot &slot : ds.GetScheduledDispatchMutable()) { for (DispatchSlot &slot : ds.GetScheduledDispatchMutable()) {
SlObjectLoadFiltered(&slot, _filtered_ordl_slot_desc); SlObjectLoadFiltered(&slot, this->slot_desc);
} }
} }
@ -357,38 +408,119 @@ static void LoadDispatchSchedule(DispatchSchedule &ds)
SlStdString(&(names[key]), SLE_STR); SlStdString(&(names[key]), SLE_STR);
} }
} }
}
};
struct DispatchScheduleStructHandlerBase : public SaveLoadStructHandler {
NamedSaveLoadTable GetDescription() const override
{
return GetDispatchScheduleDescription();
}
void SaveSchedules(std::vector<DispatchSchedule> &schedules) const
{
SlSetStructListLength(schedules.size());
for (DispatchSchedule &ds : schedules) {
SlObjectSaveFiltered(&ds, this->GetLoadDescription());
}
}
void LoadSchedules(std::vector<DispatchSchedule> &schedules) const
{
schedules.resize(SlGetStructListLength(UINT32_MAX));
for (DispatchSchedule &ds : schedules) {
SlObjectLoadFiltered(&ds, this->GetLoadDescription());
}
}
};
struct OrderListDispatchScheduleStructHandler final : public DispatchScheduleStructHandlerBase {
void Save(void *object) const override { this->SaveSchedules(static_cast<OrderList *>(object)->GetScheduledDispatchScheduleSet()); }
void Load(void *object) const override { this->LoadSchedules(static_cast<OrderList *>(object)->GetScheduledDispatchScheduleSet()); }
};
struct OrderBackupDispatchScheduleStructHandler final : public DispatchScheduleStructHandlerBase {
void Save(void *object) const override { this->SaveSchedules(static_cast<OrderBackup *>(object)->dispatch_schedules); }
void Load(void *object) const override { this->LoadSchedules(static_cast<OrderBackup *>(object)->dispatch_schedules); }
};
NamedSaveLoadTable GetOrderListDescription()
{
static const NamedSaveLoad _orderlist_desc[] = {
NSL("first", SLE_REF(OrderList, first, REF_ORDER)),
NSL("", SLEG_CONDVAR_X(_jokerpp_separation_mode, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP))),
NSL("", SLE_CONDNULL_X(21, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP))),
NSLT_STRUCTLIST<OrderListDispatchScheduleStructHandler>("dispatch_schedule"),
};
return _orderlist_desc;
}
NamedSaveLoadTable GetOrderBackupDescription()
{
static const NamedSaveLoad _order_backup_desc[] = {
NSL("user", SLE_VAR(OrderBackup, user, SLE_UINT32)),
NSL("tile", SLE_VAR(OrderBackup, tile, SLE_UINT32)),
NSL("group", SLE_VAR(OrderBackup, group, SLE_UINT16)),
NSL("service_interval", SLE_CONDVAR(OrderBackup, service_interval, SLE_FILE_U32 | SLE_VAR_U16, SL_MIN_VERSION, SLV_192)),
NSL("service_interval", SLE_CONDVAR(OrderBackup, service_interval, SLE_UINT16, SLV_192, SL_MAX_VERSION)),
NSL("name", SLE_STR(OrderBackup, name, SLE_STR, 0)),
NSL("", SLE_CONDNULL(2, SL_MIN_VERSION, SLV_192)), // clone (2 bytes of pointer, i.e. garbage)
NSL("clone", SLE_CONDREF(OrderBackup, clone, REF_VEHICLE, SLV_192, SL_MAX_VERSION)),
NSL("cur_real_order_index", SLE_VAR(OrderBackup, cur_real_order_index, SLE_VEHORDERID)),
NSL("cur_implicit_order_index", SLE_CONDVAR(OrderBackup, cur_implicit_order_index, SLE_VEHORDERID, SLV_176, SL_MAX_VERSION)),
NSL("cur_timetable_order_index", SLE_CONDVAR_X(OrderBackup, cur_timetable_order_index, SLE_VEHORDERID, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA))),
NSL("current_order_time", SLE_CONDVAR(OrderBackup, current_order_time, SLE_UINT32, SLV_176, SL_MAX_VERSION)),
NSL("lateness_counter", SLE_CONDVAR(OrderBackup, lateness_counter, SLE_INT32, SLV_176, SL_MAX_VERSION)),
NSL("timetable_start", SLE_CONDVAR_X(OrderBackup, timetable_start, SLE_FILE_I32 | SLE_VAR_I64, SLV_176, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLES_START_TICKS, 0, 2))),
NSL("timetable_start", SLE_CONDVAR_X(OrderBackup, timetable_start, SLE_INT64, SLV_176, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLES_START_TICKS, 3))),
NSL("", SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLES_START_TICKS, 2, 2))),
NSL("vehicle_flags", SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_FILE_U8 | SLE_VAR_U32, SLV_176, SLV_180)),
NSL("vehicle_flags", SLE_CONDVAR_X(OrderBackup, vehicle_flags, SLE_FILE_U16 | SLE_VAR_U32, SLV_180, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VEHICLE_FLAGS_EXTRA, 0, 0))),
NSL("vehicle_flags", SLE_CONDVAR_X(OrderBackup, vehicle_flags, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VEHICLE_FLAGS_EXTRA, 1))),
NSL("orders", SLE_REF(OrderBackup, orders, REF_ORDER)),
NSL("", SLE_CONDNULL_X(18, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 2, 2))),
NSLT_STRUCTLIST<OrderBackupDispatchScheduleStructHandler>("dispatch_schedule"),
};
return _order_backup_desc;
} }
static void Save_ORDL() static void Save_ORDL()
{ {
SetupDescs_ORDL(); SaveLoadTableData slt = SlTableHeader(GetOrderListDescription());
for (OrderList *list : OrderList::Iterate()) { for (OrderList *list : OrderList::Iterate()) {
SlSetArrayIndex(list->index); SlSetArrayIndex(list->index);
SlAutolength([&]() { SlObjectSaveFiltered(list, slt);
SlObjectSaveFiltered(list, _filtered_ordl_desc);
SlWriteUint32(list->GetScheduledDispatchScheduleCount());
for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) {
SaveDispatchSchedule(ds);
}
});
} }
} }
static void Load_ORDL() static void Load_ORDL()
{ {
SetupDescs_ORDL();
_jokerpp_auto_separation.clear(); _jokerpp_auto_separation.clear();
_jokerpp_non_auto_separation.clear(); _jokerpp_non_auto_separation.clear();
_old_scheduled_dispatch_start_full_date_fract = 0; _old_scheduled_dispatch_start_full_date_fract = 0;
_old_scheduled_dispatch_start_full_date_fract_map.clear(); _old_scheduled_dispatch_start_full_date_fract_map.clear();
const bool is_table = SlIsTableChunk();
SaveLoadTableData slt = SlTableHeaderOrRiff(GetOrderListDescription());
if (is_table && SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 1, 6)) SlErrorCorrupt("XSLFI_SCHEDULED_DISPATCH versions 1 - 6 not supported in table format");
ScheduledDispatchNonTableHelper helper;
if (!is_table) helper.Setup();
int index; int index;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
/* set num_orders to 0 so it's a valid OrderList */ /* set num_orders to 0 so it's a valid OrderList */
OrderList *list = new (index) OrderList(0); OrderList *list = new (index) OrderList(0);
SlObjectLoadFiltered(list, _filtered_ordl_desc); SlObjectLoadFiltered(list, slt);
if (SlXvIsFeaturePresent(XSLFI_JOKERPP)) { if (SlXvIsFeaturePresent(XSLFI_JOKERPP)) {
if (_jokerpp_separation_mode == 0) { if (_jokerpp_separation_mode == 0) {
_jokerpp_auto_separation.push_back(list); _jokerpp_auto_separation.push_back(list);
@ -396,11 +528,11 @@ static void Load_ORDL()
_jokerpp_non_auto_separation.push_back(list); _jokerpp_non_auto_separation.push_back(list);
} }
} }
if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH)) { if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH) && !is_table) {
uint count = SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 3) ? SlReadUint32() : 1; uint count = SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 3) ? SlReadUint32() : 1;
list->GetScheduledDispatchScheduleSet().resize(count); list->GetScheduledDispatchScheduleSet().resize(count);
for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) { for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) {
LoadDispatchSchedule(ds); helper.LoadDispatchSchedule(ds);
} }
} }
} }
@ -410,81 +542,59 @@ static void Load_ORDL()
void Ptrs_ORDL() void Ptrs_ORDL()
{ {
std::vector<SaveLoad> filtered_desc = SlFilterObject(GetOrderListDescription()); SaveLoadTableData slt = SlPrepareNamedSaveLoadTableForPtrOrNull(GetOrderListDescription());
for (OrderList *list : OrderList::Iterate()) { for (OrderList *list : OrderList::Iterate()) {
SlObjectPtrOrNullFiltered(list, filtered_desc); SlObjectPtrOrNullFiltered(list, slt);
list->ReindexOrderList();
} }
} }
SaveLoadTable GetOrderBackupDescription()
{
static const SaveLoad _order_backup_desc[] = {
SLE_VAR(OrderBackup, user, SLE_UINT32),
SLE_VAR(OrderBackup, tile, SLE_UINT32),
SLE_VAR(OrderBackup, group, SLE_UINT16),
SLE_CONDVAR(OrderBackup, service_interval, SLE_FILE_U32 | SLE_VAR_U16, SL_MIN_VERSION, SLV_192),
SLE_CONDVAR(OrderBackup, service_interval, SLE_UINT16, SLV_192, SL_MAX_VERSION),
SLE_STR(OrderBackup, name, SLE_STR, 0),
SLE_CONDNULL(2, SL_MIN_VERSION, SLV_192), // clone (2 bytes of pointer, i.e. garbage)
SLE_CONDREF(OrderBackup, clone, REF_VEHICLE, SLV_192, SL_MAX_VERSION),
SLE_VAR(OrderBackup, cur_real_order_index, SLE_VEHORDERID),
SLE_CONDVAR(OrderBackup, cur_implicit_order_index, SLE_VEHORDERID, SLV_176, SL_MAX_VERSION),
SLE_CONDVAR_X(OrderBackup, cur_timetable_order_index, SLE_VEHORDERID, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA)),
SLE_CONDVAR(OrderBackup, current_order_time, SLE_UINT32, SLV_176, SL_MAX_VERSION),
SLE_CONDVAR(OrderBackup, lateness_counter, SLE_INT32, SLV_176, SL_MAX_VERSION),
SLE_CONDVAR_X(OrderBackup, timetable_start, SLE_FILE_I32 | SLE_VAR_I64, SLV_176, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLES_START_TICKS, 0, 2)),
SLE_CONDVAR_X(OrderBackup, timetable_start, SLE_INT64, SLV_176, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLES_START_TICKS, 3)),
SLE_CONDNULL_X(2, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLES_START_TICKS, 2, 2)),
SLE_CONDVAR(OrderBackup, vehicle_flags, SLE_FILE_U8 | SLE_VAR_U32, SLV_176, SLV_180),
SLE_CONDVAR_X(OrderBackup, vehicle_flags, SLE_FILE_U16 | SLE_VAR_U32, SLV_180, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VEHICLE_FLAGS_EXTRA, 0, 0)),
SLE_CONDVAR_X(OrderBackup, vehicle_flags, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_VEHICLE_FLAGS_EXTRA, 1)),
SLE_REF(OrderBackup, orders, REF_ORDER),
SLE_CONDNULL_X(18, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 2, 2)),
};
return _order_backup_desc;
}
void Save_BKOR() void Save_BKOR()
{ {
SaveLoadTableData slt = SlTableHeader(GetOrderBackupDescription());
/* We only save this when we're a network server /* We only save this when we're a network server
* as we want this information on our clients. For * as we want this information on our clients. For
* normal games this information isn't needed. */ * normal games this information isn't needed. */
if (!_networking || !_network_server) return; if (!_networking || !_network_server) return;
SetupDescs_ORDL();
for (OrderBackup *ob : OrderBackup::Iterate()) { for (OrderBackup *ob : OrderBackup::Iterate()) {
SlSetArrayIndex(ob->index); SlSetArrayIndex(ob->index);
SlAutolength([&]() { SlObjectSaveFiltered(ob, slt);
SlObject(ob, GetOrderBackupDescription());
SlWriteUint32((uint)ob->dispatch_schedules.size());
for (DispatchSchedule &ds : ob->dispatch_schedules) {
SaveDispatchSchedule(ds);
}
});
} }
} }
void Load_BKOR() void Load_BKOR()
{ {
SaveLoadTableData slt = SlTableHeaderOrRiff(GetOrderBackupDescription());
if (SlIsTableChunk()) {
if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 1, 6)) SlErrorCorrupt("XSLFI_SCHEDULED_DISPATCH versions 1 - 6 not supported in table format");
int index; int index;
SetupDescs_ORDL();
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
/* set num_orders to 0 so it's a valid OrderList */ /* set num_orders to 0 so it's a valid OrderList */
OrderBackup *ob = new (index) OrderBackup(); OrderBackup *ob = new (index) OrderBackup();
SlObject(ob, GetOrderBackupDescription()); SlObjectLoadFiltered(ob, slt);
}
return;
}
ScheduledDispatchNonTableHelper helper;
helper.Setup();
int index;
while ((index = SlIterateArray()) != -1) {
/* set num_orders to 0 so it's a valid OrderList */
OrderBackup *ob = new (index) OrderBackup();
SlObjectLoadFiltered(ob, slt);
if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 3)) { if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 3)) {
uint count = SlReadUint32(); uint count = SlReadUint32();
ob->dispatch_schedules.resize(count); ob->dispatch_schedules.resize(count);
for (DispatchSchedule &ds : ob->dispatch_schedules) { for (DispatchSchedule &ds : ob->dispatch_schedules) {
if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 8)) { if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 8)) {
LoadDispatchSchedule(ds); helper.LoadDispatchSchedule(ds);
} else { } else {
SlObject(&ds, GetDispatchScheduleDescription()); SlObjectLoadFiltered(&ds, helper.dispatch_desc);
} }
} }
} }
@ -493,16 +603,18 @@ void Load_BKOR()
static void Ptrs_BKOR() static void Ptrs_BKOR()
{ {
SaveLoadTableData slt = SlPrepareNamedSaveLoadTableForPtrOrNull(GetOrderBackupDescription());
for (OrderBackup *ob : OrderBackup::Iterate()) { for (OrderBackup *ob : OrderBackup::Iterate()) {
SlObject(ob, GetOrderBackupDescription()); SlObjectPtrOrNullFiltered(ob, slt);
} }
} }
static const ChunkHandler order_chunk_handlers[] = { static const ChunkHandler order_chunk_handlers[] = {
{ 'BKOR', Save_BKOR, Load_BKOR, Ptrs_BKOR, nullptr, CH_ARRAY }, { 'BKOR', Save_BKOR, Load_BKOR, Ptrs_BKOR, nullptr, CH_TABLE },
{ 'ORDR', Save_ORDR, Load_ORDR, Ptrs_ORDR, nullptr, CH_ARRAY }, { 'ORDR', Save_ORDR, Load_ORDR, Ptrs_ORDR, nullptr, CH_TABLE },
{ 'ORDL', Save_ORDL, Load_ORDL, Ptrs_ORDL, nullptr, CH_ARRAY }, { 'ORDL', Save_ORDL, Load_ORDL, Ptrs_ORDL, nullptr, CH_TABLE },
{ 'ORDX', Save_ORDX, Load_ORDX, nullptr, nullptr, CH_SPARSE_ARRAY }, { 'ORDX', nullptr, Load_ORDX, nullptr, nullptr, CH_READONLY },
}; };
extern const ChunkHandlerTable _order_chunk_handlers(order_chunk_handlers); extern const ChunkHandlerTable _order_chunk_handlers(order_chunk_handlers);

View File

@ -2243,8 +2243,13 @@ void SlSkipTableHeader()
static uint8_t GetSavegameTableFileType(const SaveLoad &sld) static uint8_t GetSavegameTableFileType(const SaveLoad &sld)
{ {
switch (sld.cmd) { switch (sld.cmd) {
case SL_VAR: case SL_VAR: {
return GetVarFileType(sld.conv); break; VarType type = GetVarFileType(sld.conv);
if (type == SLE_FILE_VEHORDERID) {
return SlXvIsFeaturePresent(XSLFI_MORE_VEHICLE_ORDERS) ? SLE_FILE_U16 : SLE_FILE_U8;
}
return type;
}
case SL_STR: case SL_STR:
case SL_STDSTR: case SL_STDSTR:

View File

@ -1216,28 +1216,32 @@ static void Ptrs_VEHS()
} }
} }
const SaveLoadTable GetOrderExtraInfoDescription(); const NamedSaveLoadTable GetOrderExtraInfoDescription();
void Save_VEOX() void Save_VEOX()
{ {
std::vector<SaveLoad> slt = SlFilterNamedSaveLoadTable(GetOrderExtraInfoDescription());
/* save extended order info for vehicle current order */ /* save extended order info for vehicle current order */
for (Vehicle *v : Vehicle::Iterate()) { for (Vehicle *v : Vehicle::Iterate()) {
if (v->current_order.extra) { if (v->current_order.extra) {
SlSetArrayIndex(v->index); SlSetArrayIndex(v->index);
SlObject(v->current_order.extra.get(), GetOrderExtraInfoDescription()); SlObject(v->current_order.extra.get(), slt);
} }
} }
} }
void Load_VEOX() void Load_VEOX()
{ {
std::vector<SaveLoad> slt = SlFilterNamedSaveLoadTable(GetOrderExtraInfoDescription());
/* load extended order info for vehicle current order */ /* load extended order info for vehicle current order */
int index; int index;
while ((index = SlIterateArray()) != -1) { while ((index = SlIterateArray()) != -1) {
Vehicle *v = Vehicle::GetIfValid(index); Vehicle *v = Vehicle::GetIfValid(index);
assert(v != nullptr); assert(v != nullptr);
v->current_order.AllocExtraInfo(); v->current_order.AllocExtraInfo();
SlObject(v->current_order.extra.get(), GetOrderExtraInfoDescription()); SlObject(v->current_order.extra.get(), slt);
} }
} }