diff --git a/src/order_backup.h b/src/order_backup.h index 9f9cccfb90..3f4d3907de 100644 --- a/src/order_backup.h +++ b/src/order_backup.h @@ -42,7 +42,8 @@ namespace upstream_sl { */ struct OrderBackup : OrderBackupPool::PoolItem<&_order_backup_pool>, BaseConsist { 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 void Load_BKOR(); ///< Creating empty orders upon savegame loading. friend void Save_BKOR(); ///< Saving orders upon savegame saving. diff --git a/src/order_base.h b/src/order_base.h index 80e44bc33e..ddfcc49391 100644 --- a/src/order_base.h +++ b/src/order_base.h @@ -104,12 +104,12 @@ struct Order : OrderPool::PoolItem<&_order_pool> { private: friend SaveLoadTable GetVehicleDescription(VehicleType vt); ///< Saving and loading the current order of 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::SlVehicleCommon; friend upstream_sl::SlVehicleDisaster; 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 Save_VEOX(); ///< Saving and loading of orders. @@ -750,7 +750,7 @@ struct DispatchSchedule { static constexpr uint DEPARTURE_TAG_COUNT = 4; private: - friend SaveLoadTable GetDispatchScheduleDescription(); ///< Saving and loading of dispatch schedules + friend NamedSaveLoadTable GetDispatchScheduleDescription(); ///< Saving and loading of dispatch schedules std::vector scheduled_dispatch; ///< Scheduled dispatch slots 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> { private: 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 void Ptrs_ORDL(); ///< Saving and loading of order lists. diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index ff041720f8..78c9a4cfb0 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -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_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_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_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 }, diff --git a/src/sl/order_sl.cpp b/src/sl/order_sl.cpp index 7c2af243d0..355f09cc08 100644 --- a/src/sl/order_sl.cpp +++ b/src/sl/order_sl.cpp @@ -117,41 +117,77 @@ Order UnpackOldOrder(uint16_t packed) return order; } -SaveLoadTable GetOrderDescription() +NamedSaveLoadTable GetOrderExtraInfoDescription() { - static const SaveLoad _order_desc[] = { - SLE_VAR(Order, type, SLE_UINT8), - 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)), - SLE_CONDVAR_X(Order, flags, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_FLAGS_EXTRA, 1)), - SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SPRINGPP)), - SLE_VAR(Order, dest, SLE_UINT16), - SLE_REF(Order, next, REF_ORDER), - SLE_CONDVAR(Order, refit_cargo, SLE_UINT8, SLV_36, SL_MAX_VERSION), - 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)), - 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)), - SLE_CONDVAR(Order, max_speed, SLE_UINT16, SLV_172, SL_MAX_VERSION), - SLE_CONDNULL_X(1, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_MORE_COND_ORDERS, 1, 6)), // jump_counter + static const NamedSaveLoad _order_extra_info_desc[] = { + 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))), + 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))), + NSL("xflags", SLE_CONDVAR_X(OrderExtraInfo, xflags, SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TIMETABLE_EXTRA))), + NSL("xdata", SLE_CONDVAR_X(OrderExtraInfo, xdata, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_EXTRA_DATA))), + NSL("xdata2", SLE_CONDVAR_X(OrderExtraInfo, xdata2, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ORDER_EXTRA_DATA, 3))), + NSL("dispatch_index", SLE_CONDVAR_X(OrderExtraInfo, dispatch_index, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_SCHEDULED_DISPATCH, 3))), + NSL("colour", 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; +} + +struct OrderExtraDataStructHandler final : public TypedSaveLoadStructHandler { + NamedSaveLoadTable GetDescription() const override + { + 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 * 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("extra"), }; return _order_desc; } -static std::vector _filtered_desc; - static void Save_ORDR() { - _filtered_desc = SlFilterObject(GetOrderDescription()); + SaveLoadTableData slt = SlTableHeader(GetOrderDescription()); + for (Order *order : Order::Iterate()) { SlSetArrayIndex(order->index); - SlObjectSaveFiltered(order, _filtered_desc); + SlObjectSaveFiltered(order, slt); } } @@ -204,51 +240,26 @@ static void Load_ORDR() if (prev != nullptr) prev->next = o; } } else { - _filtered_desc = SlFilterObject(GetOrderDescription()); - int index; + SaveLoadTableData slt = SlTableHeaderOrRiff(GetOrderDescription()); + int index; while ((index = SlIterateArray()) != -1) { Order *order = new (index) Order(); - SlObjectLoadFiltered(order, _filtered_desc); - } - } -} - -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); + SlObjectLoadFiltered(order, slt); } } } void Load_ORDX() { - _filtered_desc = SlFilterObject(GetOrderExtraInfoDescription()); + SaveLoadTableData slt = SlTableHeaderOrRiff(GetOrderExtraInfoDescription()); + int index; while ((index = SlIterateArray()) != -1) { Order *order = Order::GetIfValid(index); assert(order != nullptr); order->AllocExtraInfo(); - SlObjectLoadFiltered(order->extra.get(), _filtered_desc); + SlObjectLoadFiltered(order->extra.get(), slt); } } @@ -257,138 +268,259 @@ static void Ptrs_ORDR() /* Orders from old savegames have pointers corrected in Load_ORDR */ if (IsSavegameVersionBefore(SLV_5, 2)) return; + SaveLoadTableData slt = SlPrepareNamedSaveLoadTableForPtrOrNull(GetOrderDescription()); + for (Order *o : Order::Iterate()) { - SlObject(o, GetOrderDescription()); + SlObjectPtrOrNullFiltered(o, slt); } } -SaveLoadTable GetDispatchScheduleDescription() +NamedSaveLoadTable GetDispatchSlotDescription() { - static const SaveLoad _dispatch_scheduled_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)), - SLE_VAR(DispatchSchedule, scheduled_dispatch_duration, SLE_UINT32), - 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), + static const NamedSaveLoad _dispatch_slot_info_desc[] = { + NSL("offset", SLE_VAR(DispatchSlot, offset, SLE_UINT32)), + NSL("flags", SLE_VAR(DispatchSlot, flags, SLE_UINT16)), }; return _dispatch_slot_info_desc; } -SaveLoadTable GetOrderListDescription() +struct DispatchSlotStructHandler final : public TypedSaveLoadStructHandler { + 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; + +NamedSaveLoadTable GetDispatchSupplementaryNamePairDescription() { - static const SaveLoad _orderlist_desc[] = { - SLE_REF(OrderList, first, REF_ORDER), - SLEG_CONDVAR_X(_jokerpp_separation_mode, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)), - SLE_CONDNULL_X(21, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_JOKERPP)), + static const NamedSaveLoad _dispatch_name_pair_desc[] = { + NSL("key", SLTAG(SLTAG_CUSTOM_START, SLE_VAR(DispatchSupplementaryNamePair, first, SLE_UINT32))), + NSL("value", SLTAG(SLTAG_CUSTOM_START + 1, SLE_SSTR(DispatchSupplementaryNamePair, second, SLE_STR))), + }; + + return _dispatch_name_pair_desc; +} + +struct DispatchNameStructHandler final : public TypedSaveLoadStructHandler { + NamedSaveLoadTable GetDescription() const override + { + return GetDispatchSupplementaryNamePairDescription(); + } + + void Save(DispatchSchedule *ds) const override + { + btree::btree_map &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 &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("slots"), + NSLT_STRUCTLIST("names"), + }; + + return _dispatch_scheduled_info_desc; +} + +struct ScheduledDispatchNonTableHelper { + std::vector dispatch_desc; + std::vector 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) { + _old_scheduled_dispatch_start_full_date_fract_map[&ds] = _old_scheduled_dispatch_start_full_date_fract; + } + + if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 1, 6)) { + ds.GetScheduledDispatchMutable().reserve(_old_scheduled_dispatch_slots.size()); + for (uint32_t slot : _old_scheduled_dispatch_slots) { + ds.GetScheduledDispatchMutable().push_back({ slot, 0 }); + } + } else { + ds.GetScheduledDispatchMutable().resize(SlReadUint32()); + for (DispatchSlot &slot : ds.GetScheduledDispatchMutable()) { + SlObjectLoadFiltered(&slot, this->slot_desc); + } + } + + if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 8)) { + uint32_t string_count = SlReadUint32(); + btree::btree_map &names = ds.GetSupplementaryNameMap(); + for (uint32_t i = 0; i < string_count; i++) { + uint32_t key = SlReadUint32(); + SlStdString(&(names[key]), SLE_STR); + } + } + } +}; + +struct DispatchScheduleStructHandlerBase : public SaveLoadStructHandler { + NamedSaveLoadTable GetDescription() const override + { + return GetDispatchScheduleDescription(); + } + + void SaveSchedules(std::vector &schedules) const + { + SlSetStructListLength(schedules.size()); + for (DispatchSchedule &ds : schedules) { + SlObjectSaveFiltered(&ds, this->GetLoadDescription()); + } + } + + void LoadSchedules(std::vector &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(object)->GetScheduledDispatchScheduleSet()); } + + void Load(void *object) const override { this->LoadSchedules(static_cast(object)->GetScheduledDispatchScheduleSet()); } +}; + +struct OrderBackupDispatchScheduleStructHandler final : public DispatchScheduleStructHandlerBase { + void Save(void *object) const override { this->SaveSchedules(static_cast(object)->dispatch_schedules); } + + void Load(void *object) const override { this->LoadSchedules(static_cast(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("dispatch_schedule"), }; return _orderlist_desc; } -static std::vector _filtered_ordl_desc; -static std::vector _filtered_ordl_sd_desc; -static std::vector _filtered_ordl_slot_desc; - -static void SetupDescs_ORDL() +NamedSaveLoadTable GetOrderBackupDescription() { - _filtered_ordl_desc = SlFilterObject(GetOrderListDescription()); - _filtered_ordl_sd_desc = SlFilterObject(GetDispatchScheduleDescription()); - _filtered_ordl_slot_desc = SlFilterObject(GetDispatchSlotDescription()); -} + 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))), -static void SaveDispatchSchedule(DispatchSchedule &ds) -{ - SlObjectSaveFiltered(&ds, _filtered_ordl_sd_desc); + NSLT_STRUCTLIST("dispatch_schedule"), + }; - SlWriteUint32((uint32_t)ds.GetScheduledDispatchMutable().size()); - for (DispatchSlot &slot : ds.GetScheduledDispatchMutable()) { - SlObjectSaveFiltered(&slot, _filtered_ordl_slot_desc); - } - - { - btree::btree_map &names = ds.GetSupplementaryNameMap(); - SlWriteUint32((uint32_t)names.size()); - for (auto &it : names) { - SlWriteUint32(it.first); - SlStdString(&(it.second), SLE_STR); - } - } -} - -static void LoadDispatchSchedule(DispatchSchedule &ds) -{ - SlObjectLoadFiltered(&ds, _filtered_ordl_sd_desc); - 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; - } - - if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 1, 6)) { - ds.GetScheduledDispatchMutable().reserve(_old_scheduled_dispatch_slots.size()); - for (uint32_t slot : _old_scheduled_dispatch_slots) { - ds.GetScheduledDispatchMutable().push_back({ slot, 0 }); - } - } else { - ds.GetScheduledDispatchMutable().resize(SlReadUint32()); - for (DispatchSlot &slot : ds.GetScheduledDispatchMutable()) { - SlObjectLoadFiltered(&slot, _filtered_ordl_slot_desc); - } - } - - if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 8)) { - uint32_t string_count = SlReadUint32(); - btree::btree_map &names = ds.GetSupplementaryNameMap(); - for (uint32_t i = 0; i < string_count; i++) { - uint32_t key = SlReadUint32(); - SlStdString(&(names[key]), SLE_STR); - } - } + return _order_backup_desc; } static void Save_ORDL() { - SetupDescs_ORDL(); + SaveLoadTableData slt = SlTableHeader(GetOrderListDescription()); + for (OrderList *list : OrderList::Iterate()) { SlSetArrayIndex(list->index); - SlAutolength([&]() { - SlObjectSaveFiltered(list, _filtered_ordl_desc); - SlWriteUint32(list->GetScheduledDispatchScheduleCount()); - for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) { - SaveDispatchSchedule(ds); - } - }); + SlObjectSaveFiltered(list, slt); } } static void Load_ORDL() { - SetupDescs_ORDL(); - _jokerpp_auto_separation.clear(); _jokerpp_non_auto_separation.clear(); _old_scheduled_dispatch_start_full_date_fract = 0; _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; while ((index = SlIterateArray()) != -1) { /* set num_orders to 0 so it's a valid OrderList */ OrderList *list = new (index) OrderList(0); - SlObjectLoadFiltered(list, _filtered_ordl_desc); + SlObjectLoadFiltered(list, slt); if (SlXvIsFeaturePresent(XSLFI_JOKERPP)) { if (_jokerpp_separation_mode == 0) { _jokerpp_auto_separation.push_back(list); @@ -396,11 +528,11 @@ static void Load_ORDL() _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; list->GetScheduledDispatchScheduleSet().resize(count); for (DispatchSchedule &ds : list->GetScheduledDispatchScheduleSet()) { - LoadDispatchSchedule(ds); + helper.LoadDispatchSchedule(ds); } } } @@ -410,81 +542,59 @@ static void Load_ORDL() void Ptrs_ORDL() { - std::vector filtered_desc = SlFilterObject(GetOrderListDescription()); + SaveLoadTableData slt = SlPrepareNamedSaveLoadTableForPtrOrNull(GetOrderListDescription()); + for (OrderList *list : OrderList::Iterate()) { - SlObjectPtrOrNullFiltered(list, filtered_desc); - list->ReindexOrderList(); + SlObjectPtrOrNullFiltered(list, slt); } } -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() { + SaveLoadTableData slt = SlTableHeader(GetOrderBackupDescription()); + /* We only save this when we're a network server * as we want this information on our clients. For * normal games this information isn't needed. */ if (!_networking || !_network_server) return; - SetupDescs_ORDL(); - for (OrderBackup *ob : OrderBackup::Iterate()) { SlSetArrayIndex(ob->index); - SlAutolength([&]() { - SlObject(ob, GetOrderBackupDescription()); - SlWriteUint32((uint)ob->dispatch_schedules.size()); - for (DispatchSchedule &ds : ob->dispatch_schedules) { - SaveDispatchSchedule(ds); - } - }); + SlObjectSaveFiltered(ob, slt); } } 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; + while ((index = SlIterateArray()) != -1) { + /* set num_orders to 0 so it's a valid OrderList */ + OrderBackup *ob = new (index) OrderBackup(); + SlObjectLoadFiltered(ob, slt); + } + return; + } + + ScheduledDispatchNonTableHelper helper; + helper.Setup(); + int index; - - SetupDescs_ORDL(); - while ((index = SlIterateArray()) != -1) { /* set num_orders to 0 so it's a valid OrderList */ OrderBackup *ob = new (index) OrderBackup(); - SlObject(ob, GetOrderBackupDescription()); + SlObjectLoadFiltered(ob, slt); if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 3)) { uint count = SlReadUint32(); ob->dispatch_schedules.resize(count); for (DispatchSchedule &ds : ob->dispatch_schedules) { if (SlXvIsFeaturePresent(XSLFI_SCHEDULED_DISPATCH, 8)) { - LoadDispatchSchedule(ds); + helper.LoadDispatchSchedule(ds); } else { - SlObject(&ds, GetDispatchScheduleDescription()); + SlObjectLoadFiltered(&ds, helper.dispatch_desc); } } } @@ -493,16 +603,18 @@ void Load_BKOR() static void Ptrs_BKOR() { + SaveLoadTableData slt = SlPrepareNamedSaveLoadTableForPtrOrNull(GetOrderBackupDescription()); + for (OrderBackup *ob : OrderBackup::Iterate()) { - SlObject(ob, GetOrderBackupDescription()); + SlObjectPtrOrNullFiltered(ob, slt); } } static const ChunkHandler order_chunk_handlers[] = { - { 'BKOR', Save_BKOR, Load_BKOR, Ptrs_BKOR, nullptr, CH_ARRAY }, - { 'ORDR', Save_ORDR, Load_ORDR, Ptrs_ORDR, nullptr, CH_ARRAY }, - { 'ORDL', Save_ORDL, Load_ORDL, Ptrs_ORDL, nullptr, CH_ARRAY }, - { 'ORDX', Save_ORDX, Load_ORDX, nullptr, nullptr, CH_SPARSE_ARRAY }, + { 'BKOR', Save_BKOR, Load_BKOR, Ptrs_BKOR, nullptr, CH_TABLE }, + { 'ORDR', Save_ORDR, Load_ORDR, Ptrs_ORDR, nullptr, CH_TABLE }, + { 'ORDL', Save_ORDL, Load_ORDL, Ptrs_ORDL, nullptr, CH_TABLE }, + { 'ORDX', nullptr, Load_ORDX, nullptr, nullptr, CH_READONLY }, }; extern const ChunkHandlerTable _order_chunk_handlers(order_chunk_handlers); diff --git a/src/sl/saveload.cpp b/src/sl/saveload.cpp index 2f4b16d920..dab8baa4f9 100644 --- a/src/sl/saveload.cpp +++ b/src/sl/saveload.cpp @@ -2243,8 +2243,13 @@ void SlSkipTableHeader() static uint8_t GetSavegameTableFileType(const SaveLoad &sld) { switch (sld.cmd) { - case SL_VAR: - return GetVarFileType(sld.conv); break; + case SL_VAR: { + 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_STDSTR: diff --git a/src/sl/vehicle_sl.cpp b/src/sl/vehicle_sl.cpp index 8885b129e2..3fd6f2a106 100644 --- a/src/sl/vehicle_sl.cpp +++ b/src/sl/vehicle_sl.cpp @@ -1216,28 +1216,32 @@ static void Ptrs_VEHS() } } -const SaveLoadTable GetOrderExtraInfoDescription(); +const NamedSaveLoadTable GetOrderExtraInfoDescription(); void Save_VEOX() { + std::vector slt = SlFilterNamedSaveLoadTable(GetOrderExtraInfoDescription()); + /* save extended order info for vehicle current order */ for (Vehicle *v : Vehicle::Iterate()) { if (v->current_order.extra) { SlSetArrayIndex(v->index); - SlObject(v->current_order.extra.get(), GetOrderExtraInfoDescription()); + SlObject(v->current_order.extra.get(), slt); } } } void Load_VEOX() { + std::vector slt = SlFilterNamedSaveLoadTable(GetOrderExtraInfoDescription()); + /* load extended order info for vehicle current order */ int index; while ((index = SlIterateArray()) != -1) { Vehicle *v = Vehicle::GetIfValid(index); assert(v != nullptr); v->current_order.AllocExtraInfo(); - SlObject(v->current_order.extra.get(), GetOrderExtraInfoDescription()); + SlObject(v->current_order.extra.get(), slt); } }