@@ -774,9 +774,12 @@ struct ResourceEconomy {
774774 std::unordered_map<std::uint32_t , std::uint64_t > plannerTargetCounts;
775775 std::uint64_t socializeEvents{0 };
776776 std::unordered_map<std::uint32_t , std::uint64_t > socializePartnerCounts;
777- std::uint64_t stockoutStepsAny{0 };
778- std::uint64_t stockoutStepsSources{0 };
779- std::uint64_t stockoutStepsWorkshops{0 };
777+ std::uint64_t stockoutInteractionSamplesAnyTotal{0 };
778+ std::uint64_t stockoutInteractionSamplesAnyZero{0 };
779+ std::uint64_t stockoutInteractionSamplesSourcesTotal{0 };
780+ std::uint64_t stockoutInteractionSamplesSourcesZero{0 };
781+ std::uint64_t stockoutInteractionSamplesWorkshopsTotal{0 };
782+ std::uint64_t stockoutInteractionSamplesWorkshopsZero{0 };
780783 std::uint64_t stepsWithAnyConsumption{0 };
781784 std::uint64_t stepsWithAnyRegen{0 };
782785 std::uint64_t stepsWithAnyDecay{0 };
@@ -799,9 +802,12 @@ struct ResourceEconomy {
799802 plannerTargetCounts.clear ();
800803 socializeEvents = 0 ;
801804 socializePartnerCounts.clear ();
802- stockoutStepsAny = 0 ;
803- stockoutStepsSources = 0 ;
804- stockoutStepsWorkshops = 0 ;
805+ stockoutInteractionSamplesAnyTotal = 0 ;
806+ stockoutInteractionSamplesAnyZero = 0 ;
807+ stockoutInteractionSamplesSourcesTotal = 0 ;
808+ stockoutInteractionSamplesSourcesZero = 0 ;
809+ stockoutInteractionSamplesWorkshopsTotal = 0 ;
810+ stockoutInteractionSamplesWorkshopsZero = 0 ;
805811 stepsWithAnyConsumption = 0 ;
806812 stepsWithAnyRegen = 0 ;
807813 stepsWithAnyDecay = 0 ;
@@ -851,23 +857,28 @@ struct ResourceEconomy {
851857 };
852858 };
853859
854- auto buildWorldlineMetricsJson = [&](const WorldlineWindowAgg& agg) {
855- const double stepCount = static_cast <double >(std::max<std::uint64_t >(1 , agg.steps ));
856- const double criticalNeedRate = agg.needSamples > 0 ? static_cast <double >(agg.criticalNeedSamples ) / static_cast <double >(agg.needSamples ) : 0.0 ;
857- const double stockoutShareAny = agg.steps > 0 ? static_cast <double >(agg.stockoutStepsAny ) / stepCount : 0.0 ;
858- const double actionEntropy = entropyBitsFromCounts (agg.actionTypeCounts );
859- const double plannerTargetEntropy = entropyBitsFromCounts (agg.plannerTargetCounts );
860- const double plannerTravelCostMean = agg.plannerTravelCostSamples > 0 ? (agg.plannerTravelCostSum / static_cast <double >(agg.plannerTravelCostSamples )) : 0.0 ;
861-
862- return json{
863- {" criticalNeedRate" , criticalNeedRate},
864- {" stockoutShareAny" , stockoutShareAny},
865- {" stockoutShareSources" , agg.steps > 0 ? static_cast <double >(agg.stockoutStepsSources ) / stepCount : 0.0 },
866- {" stockoutShareWorkshops" , agg.steps > 0 ? static_cast <double >(agg.stockoutStepsWorkshops ) / stepCount : 0.0 },
867- {" stepsWithAnyConsumption" , agg.stepsWithAnyConsumption },
868- {" stepsWithAnyRegen" , agg.stepsWithAnyRegen },
869- {" stepsWithAnyDecay" , agg.stepsWithAnyDecay },
870- {" actionEntropyBits" , actionEntropy},
860+ auto buildWorldlineMetricsJson = [&](const WorldlineWindowAgg& agg) {
861+ const double criticalNeedRate = agg.needSamples > 0 ? static_cast <double >(agg.criticalNeedSamples ) / static_cast <double >(agg.needSamples ) : 0.0 ;
862+ const double stockoutShareAny = agg.stockoutInteractionSamplesAnyTotal > 0
863+ ? static_cast <double >(agg.stockoutInteractionSamplesAnyZero ) / static_cast <double >(agg.stockoutInteractionSamplesAnyTotal )
864+ : 0.0 ;
865+ const double actionEntropy = entropyBitsFromCounts (agg.actionTypeCounts );
866+ const double plannerTargetEntropy = entropyBitsFromCounts (agg.plannerTargetCounts );
867+ const double plannerTravelCostMean = agg.plannerTravelCostSamples > 0 ? (agg.plannerTravelCostSum / static_cast <double >(agg.plannerTravelCostSamples )) : 0.0 ;
868+
869+ return json{
870+ {" criticalNeedRate" , criticalNeedRate},
871+ {" stockoutShareAny" , stockoutShareAny},
872+ {" stockoutShareSources" , agg.stockoutInteractionSamplesSourcesTotal > 0
873+ ? static_cast <double >(agg.stockoutInteractionSamplesSourcesZero ) / static_cast <double >(agg.stockoutInteractionSamplesSourcesTotal )
874+ : 0.0 },
875+ {" stockoutShareWorkshops" , agg.stockoutInteractionSamplesWorkshopsTotal > 0
876+ ? static_cast <double >(agg.stockoutInteractionSamplesWorkshopsZero ) / static_cast <double >(agg.stockoutInteractionSamplesWorkshopsTotal )
877+ : 0.0 },
878+ {" stepsWithAnyConsumption" , agg.stepsWithAnyConsumption },
879+ {" stepsWithAnyRegen" , agg.stepsWithAnyRegen },
880+ {" stepsWithAnyDecay" , agg.stepsWithAnyDecay },
881+ {" actionEntropyBits" , actionEntropy},
871882 {" plannerTargetEntropyBits" , plannerTargetEntropy},
872883 {" plannerTravelCostMean" , plannerTravelCostMean},
873884 {" resourceAttempts" , agg.resourceAttempts },
@@ -886,13 +897,13 @@ struct ResourceEconomy {
886897 return 2 ;
887898 }
888899
889- json meta;
890- meta[" kind" ] = " runtime_worldline_meta" ;
891- meta[" schema_version" ] = 1 ;
892- meta[" worldFolder" ] = loadedWorldFolder.empty () ? std::string{} : std::filesystem::absolute (loadedWorldFolder).string ();
893- if (opts.worldgenConfigPath ) {
894- meta[" worldgenConfig" ] = resolvePathIfRelative (opts.rootPath , *opts.worldgenConfigPath ).string ();
895- }
900+ json meta;
901+ meta[" kind" ] = " runtime_worldline_meta" ;
902+ meta[" schema_version" ] = 2 ;
903+ meta[" worldFolder" ] = loadedWorldFolder.empty () ? std::string{} : std::filesystem::absolute (loadedWorldFolder).string ();
904+ if (opts.worldgenConfigPath ) {
905+ meta[" worldgenConfig" ] = resolvePathIfRelative (opts.rootPath , *opts.worldgenConfigPath ).string ();
906+ }
896907 if (opts.worldgenSeed ) {
897908 meta[" worldSeed" ] = *opts.worldgenSeed ;
898909 } else if (runtime.lastSeed ().has_value ()) {
@@ -947,26 +958,35 @@ struct ResourceEconomy {
947958 }
948959 }
949960
950- bool anyStockout = false ;
951- bool anyStockoutSource = false ;
952- bool anyStockoutWorkshop = false ;
953- bool anyConsumption = false ;
954- bool anyRegen = false ;
955- bool anyDecay = false ;
956-
957- for (const auto & resource : telemetry.resources ) {
958- if (resource.current == 0U ) {
959- anyStockout = true ;
960- const bool isWorkshop = workshopByInteraction.contains (resource.interactionId ) ? workshopByInteraction.at (resource.interactionId ) : false ;
961- if (isWorkshop) {
962- anyStockoutWorkshop = true ;
963- } else {
964- anyStockoutSource = true ;
965- }
966- }
967- if (resource.consumed > 0U ) {
968- anyConsumption = true ;
969- }
961+ bool anyConsumption = false ;
962+ bool anyRegen = false ;
963+ bool anyDecay = false ;
964+ std::uint64_t stockoutAnyTotal = 0 ;
965+ std::uint64_t stockoutAnyZero = 0 ;
966+ std::uint64_t stockoutSourcesTotal = 0 ;
967+ std::uint64_t stockoutSourcesZero = 0 ;
968+ std::uint64_t stockoutWorkshopsTotal = 0 ;
969+ std::uint64_t stockoutWorkshopsZero = 0 ;
970+
971+ for (const auto & resource : telemetry.resources ) {
972+ const bool isWorkshop = workshopByInteraction.contains (resource.interactionId ) ? workshopByInteraction.at (resource.interactionId ) : false ;
973+ stockoutAnyTotal++;
974+ if (isWorkshop) {
975+ stockoutWorkshopsTotal++;
976+ } else {
977+ stockoutSourcesTotal++;
978+ }
979+ if (resource.current == 0U ) {
980+ stockoutAnyZero++;
981+ if (isWorkshop) {
982+ stockoutWorkshopsZero++;
983+ } else {
984+ stockoutSourcesZero++;
985+ }
986+ }
987+ if (resource.consumed > 0U ) {
988+ anyConsumption = true ;
989+ }
970990 if (resource.produced > 0U ) {
971991 anyRegen = true ;
972992 }
@@ -975,28 +995,26 @@ struct ResourceEconomy {
975995 }
976996 }
977997
978- if (anyStockout) {
979- windowAgg.stockoutStepsAny ++;
980- }
981- if (anyStockoutSource) {
982- windowAgg.stockoutStepsSources ++;
983- }
984- if (anyStockoutWorkshop) {
985- windowAgg.stockoutStepsWorkshops ++;
986- }
987- if (anyConsumption) {
988- windowAgg.stepsWithAnyConsumption ++;
989- }
990- if (anyRegen) {
998+ if (anyConsumption) {
999+ windowAgg.stepsWithAnyConsumption ++;
1000+ }
1001+ if (anyRegen) {
9911002 windowAgg.stepsWithAnyRegen ++;
9921003 }
993- if (anyDecay) {
994- windowAgg.stepsWithAnyDecay ++;
995- }
1004+ if (anyDecay) {
1005+ windowAgg.stepsWithAnyDecay ++;
1006+ }
9961007
997- for (const auto & attempt : telemetry.workshopAttempts ) {
998- windowAgg.productionAttempts ++;
999- const bool ok = attempt.failureReason .empty () && attempt.producedUnits > 0U ;
1008+ windowAgg.stockoutInteractionSamplesAnyTotal += stockoutAnyTotal;
1009+ windowAgg.stockoutInteractionSamplesAnyZero += stockoutAnyZero;
1010+ windowAgg.stockoutInteractionSamplesSourcesTotal += stockoutSourcesTotal;
1011+ windowAgg.stockoutInteractionSamplesSourcesZero += stockoutSourcesZero;
1012+ windowAgg.stockoutInteractionSamplesWorkshopsTotal += stockoutWorkshopsTotal;
1013+ windowAgg.stockoutInteractionSamplesWorkshopsZero += stockoutWorkshopsZero;
1014+
1015+ for (const auto & attempt : telemetry.workshopAttempts ) {
1016+ windowAgg.productionAttempts ++;
1017+ const bool ok = attempt.failureReason .empty () && attempt.producedUnits > 0U ;
10001018 if (ok) {
10011019 windowAgg.productionSucceeded ++;
10021020 } else {
@@ -1208,14 +1226,14 @@ struct ResourceEconomy {
12081226 std::uint64_t stepsExecuted = 0 ;
12091227 bool endedByWallTime = false ;
12101228
1211- auto flushWorldlineWindow = [&](std::uint64_t windowEndStep) {
1212- if (worldlineOut.has_value ()) {
1213- json window;
1214- window[" kind" ] = " runtime_worldline_window" ;
1215- window[" schema_version" ] = 1 ;
1216- window[" index" ] = worldlineWindowIndex;
1217- window[" stepStart" ] = worldlineWindowStartStep;
1218- window[" stepEnd" ] = windowEndStep;
1229+ auto flushWorldlineWindow = [&](std::uint64_t windowEndStep) {
1230+ if (worldlineOut.has_value ()) {
1231+ json window;
1232+ window[" kind" ] = " runtime_worldline_window" ;
1233+ window[" schema_version" ] = 2 ;
1234+ window[" index" ] = worldlineWindowIndex;
1235+ window[" stepStart" ] = worldlineWindowStartStep;
1236+ window[" stepEnd" ] = windowEndStep;
12191237 window[" steps" ] = (windowEndStep >= worldlineWindowStartStep) ? (windowEndStep - worldlineWindowStartStep + 1 ) : 0 ;
12201238 window[" elapsedSeconds" ] = std::chrono::duration_cast<std::chrono::duration<double >>(std::chrono::steady_clock::now () - worldlineStartedAt).count ();
12211239 window[" metrics" ] = buildWorldlineMetricsJson (windowAgg);
0 commit comments