From 4e92b008a306498fb5cb271ca287e59a8d056b70 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Thu, 10 Oct 2024 17:27:06 +0100 Subject: [PATCH] Link graph: Fix MP desync when day length changed between job start and join Add day length factor field to link graph job --- src/linkgraph/flowmapper.cpp | 2 +- src/linkgraph/linkgraph.cpp | 6 ++++++ src/linkgraph/linkgraphjob.cpp | 1 + src/linkgraph/linkgraphjob.h | 10 +++++++++- src/saveload/afterload.cpp | 6 ++++++ src/sl/extended_ver_sl.cpp | 2 +- src/sl/linkgraph_sl.cpp | 1 + src/station_base.h | 2 +- src/station_cmd.cpp | 5 +++-- 9 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/linkgraph/flowmapper.cpp b/src/linkgraph/flowmapper.cpp index 6bc4989804e..e4ee4be0734 100644 --- a/src/linkgraph/flowmapper.cpp +++ b/src/linkgraph/flowmapper.cpp @@ -55,7 +55,7 @@ void FlowMapper::Run(LinkGraphJob &job) const * LinkGraph::Monthly(). */ uint runtime = (uint)Clamp(job.StartTick() - job.LastCompression() + 1, 1, UINT32_MAX); for (auto &it : flows) { - it.ScaleToMonthly(runtime); + it.ScaleToMonthly(runtime, job.DayLengthFactor()); } } /* Clear paths. */ diff --git a/src/linkgraph/linkgraph.cpp b/src/linkgraph/linkgraph.cpp index 03d2cb22b84..1dd09fc3e5d 100644 --- a/src/linkgraph/linkgraph.cpp +++ b/src/linkgraph/linkgraph.cpp @@ -291,3 +291,9 @@ void LinkGraphFixupAfterLoad(bool compression_was_date) convert(lgj->start_tick); } } + +void LinkGraphJobSetDayLengthFactor() { + for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) { + lgj->day_length_factor = DayLengthFactor(); + } +} diff --git a/src/linkgraph/linkgraphjob.cpp b/src/linkgraph/linkgraphjob.cpp index d486aa2c002..65d957702ba 100644 --- a/src/linkgraph/linkgraphjob.cpp +++ b/src/linkgraph/linkgraphjob.cpp @@ -45,6 +45,7 @@ LinkGraphJob::LinkGraphJob(const LinkGraph &orig, uint duration_multiplier) : settings(_settings_game.linkgraph), join_tick(GetLinkGraphJobJoinTick(duration_multiplier)), start_tick(_scaled_tick_counter), + day_length_factor(DayLengthFactor()), job_completed(false), job_aborted(false) { diff --git a/src/linkgraph/linkgraphjob.h b/src/linkgraph/linkgraphjob.h index f8498f6c704..c6f4bb5e114 100644 --- a/src/linkgraph/linkgraphjob.h +++ b/src/linkgraph/linkgraphjob.h @@ -132,6 +132,7 @@ class LinkGraphJob : public LinkGraphJobPool::PoolItem<&_link_graph_job_pool>{ friend upstream_sl::SaveLoadTable upstream_sl::GetLinkGraphJobDesc(); friend void GetLinkGraphJobDayLengthScaleAfterLoad(LinkGraphJob *lgj); friend void LinkGraphFixupAfterLoad(bool compression_was_date); + friend void LinkGraphJobSetDayLengthFactor(); friend class LinkGraphSchedule; friend class LinkGraphJobGroup; @@ -144,6 +145,7 @@ class LinkGraphJob : public LinkGraphJobPool::PoolItem<&_link_graph_job_pool>{ ScaledTickCounter start_tick; ///< Tick when the job was started. NodeAnnotationVector nodes; ///< Extra node data necessary for link graph calculation. EdgeAnnotationVector edges; ///< Edge data necessary for link graph calculation. + uint8_t day_length_factor; ///< Day length factor for this job std::atomic job_completed; ///< Is the job still running. This is accessed by multiple threads and reads may be stale. std::atomic job_aborted; ///< Has the job been aborted. This is accessed by multiple threads and reads may be stale. @@ -264,7 +266,7 @@ class LinkGraphJob : public LinkGraphJobPool::PoolItem<&_link_graph_job_pool>{ * settings have to be brutally const-casted in order to populate them. */ LinkGraphJob() : settings(_settings_game.linkgraph), - join_tick(0), start_tick(0), job_completed(false), job_aborted(false) {} + join_tick(0), start_tick(0), day_length_factor(1), job_completed(false), job_aborted(false) {} LinkGraphJob(const LinkGraph &orig, uint duration_multiplier); ~LinkGraphJob(); @@ -313,6 +315,12 @@ class LinkGraphJob : public LinkGraphJobPool::PoolItem<&_link_graph_job_pool>{ */ inline ScaledTickCounter StartTick() const { return this->start_tick; } + /** + * Get the day length factor to use for this job. + * @return Day length factor. + */ + inline uint8_t DayLengthFactor() const { return this->day_length_factor; } + /** * Set the tick when the job should be joined. * @return Start date. diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index 1a38507d232..e126eec0e4f 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -956,6 +956,12 @@ bool AfterLoadGame() LinkGraphFixupAfterLoad(SlXvIsFeatureMissing(XSLFI_LINKGRAPH_DAY_SCALE, 4)); } + /* Set link graph job day length factor setting. */ + if (SlXvIsFeatureMissing(XSLFI_LINKGRAPH_DAY_SCALE, 7)) { + extern void LinkGraphJobSetDayLengthFactor(); + LinkGraphJobSetDayLengthFactor(); + } + /* Load the sprites */ GfxLoadSprites(); LoadStringWidthTable(); diff --git a/src/sl/extended_ver_sl.cpp b/src/sl/extended_ver_sl.cpp index 2ac8c866349..b04d4637c3a 100644 --- a/src/sl/extended_ver_sl.cpp +++ b/src/sl/extended_ver_sl.cpp @@ -109,7 +109,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_EXTRA_LARGE_MAP, XSCF_NULL, 0, 1, "extra_large_map", nullptr, nullptr, nullptr }, { XSLFI_REVERSE_AT_WAYPOINT, XSCF_NULL, 1, 1, "reverse_at_waypoint", nullptr, nullptr, nullptr }, { XSLFI_VEH_LIFETIME_PROFIT, XSCF_NULL, 1, 1, "veh_lifetime_profit", nullptr, nullptr, nullptr }, - { XSLFI_LINKGRAPH_DAY_SCALE, XSCF_NULL, 6, 6, "linkgraph_day_scale", nullptr, nullptr, nullptr }, + { XSLFI_LINKGRAPH_DAY_SCALE, XSCF_NULL, 7, 7, "linkgraph_day_scale", nullptr, nullptr, nullptr }, { XSLFI_TEMPLATE_REPLACEMENT, XSCF_NULL, 10, 10, "template_replacement", nullptr, nullptr, "TRPL,TMPL" }, { XSLFI_MORE_RAIL_TYPES, XSCF_NULL, 0, 1, "more_rail_types", nullptr, nullptr, nullptr }, { XSLFI_CARGO_TYPE_ORDERS, XSCF_NULL, 4, 4, "cargo_type_orders", nullptr, nullptr, nullptr }, diff --git a/src/sl/linkgraph_sl.cpp b/src/sl/linkgraph_sl.cpp index 16f68c7b1f6..3f08511497c 100644 --- a/src/sl/linkgraph_sl.cpp +++ b/src/sl/linkgraph_sl.cpp @@ -220,6 +220,7 @@ NamedSaveLoadTable GetLinkGraphJobDesc() NSL("start_tick", SLE_CONDVAR_X(LinkGraphJob, start_tick, SLE_FILE_I32 | SLE_VAR_U64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_DAY_SCALE, 1, 4))), NSL("start_tick", SLE_CONDVAR_X(LinkGraphJob, start_tick, SLE_FILE_I64 | SLE_VAR_U64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_DAY_SCALE, 5, 5))), NSL("start_tick", SLE_CONDVAR_X(LinkGraphJob, start_tick, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_DAY_SCALE, 6))), + NSL("day_length_factor",SLE_CONDVAR_X(LinkGraphJob, day_length_factor,SLE_UINT8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_LINKGRAPH_DAY_SCALE, 7))), NSL("link_graph.index", SLE_VAR(LinkGraphJob, link_graph.index, SLE_UINT16)), NSLT_STRUCT("linkgraph"), }; diff --git a/src/station_base.h b/src/station_base.h index def6c7bd8b6..713c5bd8031 100644 --- a/src/station_base.h +++ b/src/station_base.h @@ -241,7 +241,7 @@ class FlowStat { void ReleaseShare(StationID st); - void ScaleToMonthly(uint runtime); + void ScaleToMonthly(uint runtime, uint8_t day_length_factor); /** * Return total amount of unrestricted shares. diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 130113bc7fd..6358dc390b7 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -5565,14 +5565,15 @@ void FlowStat::ReleaseShare(StationID st) /** * Scale all shares from link graph's runtime to monthly values. * @param runtime Time the link graph has been running without compression, in scaled ticks. + * @param day_length_factor Day length factor to use. * @pre runtime must be greater than 0 as we don't want infinite flow values. */ -void FlowStat::ScaleToMonthly(uint runtime) +void FlowStat::ScaleToMonthly(uint runtime, uint8_t day_length_factor) { assert(runtime > 0); uint share = 0; for (iterator i = this->begin(); i != this->end(); ++i) { - share = std::max(share + 1, ClampTo((static_cast(i->first) * 30 * DAY_TICKS * DayLengthFactor()) / runtime)); + share = std::max(share + 1, ClampTo((static_cast(i->first) * 30 * DAY_TICKS * day_length_factor) / runtime)); if (this->unrestricted == i->first) this->unrestricted = share; i->first = share; }