Jump to content

Detect Resource Shortage Across Supply Line Network


niston

Recommended Posts

And now to fill the water tower:

[09/21/2020 - 06:32:46AM] [f4ms:f4ms_eventscheduler <CRP_SchedulerQuest_WaterTower (A7006630)>]: Early timer firing detected (Expected=459.958344, Actual=459.958008). Retarding scheduler event (29.003906 seconds gametime)...
[09/21/2020 - 06:32:46AM] [CRP:WaterTowerScript < (A7035D58)>]: F4MS_ScheduledEvent triggered.
[09/21/2020 - 06:32:48AM] [CRP:WaterTowerScript < (A7035D58)>]: INFO - Water availability forecast for settlement network (107 workshops): 133687 water available.
[09/21/2020 - 06:32:48AM] [CRP:WaterTowerScript < (A7035D58)>]: INFO - Tower currently has (40/500) water stored.
[09/21/2020 - 06:32:48AM] [CRP:WaterTowerScript < (A7035D58)>]: DEBUG - Sourced (40) water from linked Workshop (Id=80, [workshopscript < (A6000F99)>]).
[09/21/2020 - 06:32:48AM] [CRP:WaterTowerScript < (A7035D58)>]: INFO - Refilled Tower with (40) additional water from local or linked workshops. Tower has (80/500) water stored now.
Link to comment
Share on other sites

I noticed that Utility.WaitGameTime() -which takes hours as a parameter, unlike Utility.Wait()- is not even remotely precise with very small values, like waiting for a few seconds of in-game time.

 

So I tweaked things a bit and scheduler events fire extremely well timed now. Consider that this particular event is scheduled once every 24h gametime only and the scheduler generally uses zero script execution time while waiting for the next scheduled event to occur. I'd say this thing is, by Fallout standards, as accurate as an atomic clock.

[09/21/2020 - 09:59:24PM] [f4ms:f4ms_eventscheduler <CRP_SchedulerQuest_WaterTower (A7006630)>]: DEBUG - OnTimerGameTime triggered.
[09/21/2020 - 09:59:24PM] [f4ms:f4ms_eventscheduler <CRP_SchedulerQuest_WaterTower (A7006630)>]: DEBUG - Early timer firing detected (Gametime Expected=459.958344, Actual=459.958008). Retarding scheduler event by (29.003906) seconds gametime...
[09/21/2020 - 09:59:24PM] [f4ms:f4ms_eventscheduler <CRP_SchedulerQuest_WaterTower (A7006630)>]: DEBUG - Precise event retarding via Utility.Wait() for (9.667969) real time seconds (Timescale=3.000000).
[09/21/2020 - 09:59:36PM] [CRP:WaterTowerScript < (A7035D58)>]: INFO - Water availability forecast for settlement network (107 workshops): 133687 water available.
[09/21/2020 - 09:59:36PM] [CRP:WaterTowerScript < (A7035D58)>]: DEBUG - Water supply is PLENTYFUL.
[09/21/2020 - 09:59:36PM] [CRP:WaterTowerScript < (A7035D58)>]: DEBUG - Sourced (40) water from linked Workshop (Id=80, [workshopscript < (A6000F99)>]).
[09/21/2020 - 09:59:36PM] [CRP:WaterTowerScript < (A7035D58)>]: INFO - Refilled Tower with (40) additional water from local or linked workshops.
[09/21/2020 - 09:59:36PM] [CRP:WaterTowerScript < (A7035D58)>]: INFO - Stats: TankLevel=80/500, FillEnabled=Yes, FillPurifiedWaterOnly=Yes, FillRateMax=40, SupplyEnabled=Yes, SupplyRateMax=80, AttachedWorkshop=[workshopscript < (A7010B71)>]
Link to comment
Share on other sites

Careful that your calls for precision dont depend on hoovering up too many script time-slices. I am getting a constant stream of users telling me their games are becoming script bound as there are so many mods* now doing a lot of complex (and possibly unnecessary) real time stuff.

 

(*) actually the same two keep featuring as they enjoy broad adoption.

Link to comment
Share on other sites

The mechanism algorithm really doesn't use that much script time. This was, in fact, a design consideration:

 

1) Calculate offset, from current game time, in hours to next event on schedule

2) Program timer to fire after that number of hours gametime

3) Do nothing until timer fires

4) If timer fires early, delay execution for the necessary time difference - Utility.Wait()

5) fire scheduler event

6) Go to 1)

 

Almost all of the processing is done in Step 1, which only happens once per occurring event. During Step 3, execution is completely suspended, nothing is done by the scheduler. Utility.Wait() in Step 4 also suspends execution for the time it is waiting. That waiting time is limited to 60 seconds max, to prevent unexpected complications. There is no constant background processing or some such ugly. And since this type of scheduler is meant for long-running things, this particular implementation ends up doing mostly nothing, 99.999% of runtime. It is very Zen, I guess.

 

Btw, if the timer fires late, this will be considered by the calculation done in Step 1) and the timing error will be eliminated for the next occurrence. But from experience (testing since 02/18), they tend to rather fire early than late. Unless sleep/wait/fasttravel was used, then they could of course be late. Which the scheduler detects and compensates for. It even informs it's clients about how many events were missed due to sleep/wait/fasstravel.

Link to comment
Share on other sites

The scheduler can now pass data along with schedule events - A schedule entry can have a parameter (float, string, keyword for now), which will get passed along to the client(s) subscribed to the scheduler's events. This also works for events that were missed due to sleep/fasttravel/wait and the scheduler even informs it's clients of when (gametime) each event should have occurred. For 48h of waiting and 3 events a day:

[09/25/2020 - 10:42:23AM] [CRP:SchedulerTest < (A701E661)>]: DEBUG - F4MS_ScheduledEvents triggered (LateCount=6, EventBuffer=[F4MS:F4MS_SchedulerEventBuffer < (FF218C53)>]).
[09/25/2020 - 10:42:23AM] [CRP:SchedulerTest < (A701E661)>]: DEBUG - Event #0: ScheduleEntryIndex=0, EventTimestamp=465.625000, EventDataFloat=15.000000, EventDataString=15:00, EventDataKeyword=None
[09/25/2020 - 10:42:23AM] [CRP:SchedulerTest < (A701E661)>]: DEBUG - Event #1: ScheduleEntryIndex=1, EventTimestamp=465.989594, EventDataFloat=23.750000, EventDataString=23:45, EventDataKeyword=None
[09/25/2020 - 10:42:23AM] [CRP:SchedulerTest < (A701E661)>]: DEBUG - Event #2: ScheduleEntryIndex=2, EventTimestamp=466.375000, EventDataFloat=0.000000, EventDataString=9:00 event, EventDataKeyword=None
[09/25/2020 - 10:42:23AM] [CRP:SchedulerTest < (A701E661)>]: DEBUG - Event #3: ScheduleEntryIndex=0, EventTimestamp=466.625000, EventDataFloat=15.000000, EventDataString=15:00, EventDataKeyword=None
[09/25/2020 - 10:42:23AM] [CRP:SchedulerTest < (A701E661)>]: DEBUG - Event #4: ScheduleEntryIndex=1, EventTimestamp=466.989594, EventDataFloat=23.750000, EventDataString=23:45, EventDataKeyword=None
[09/25/2020 - 10:42:23AM] [CRP:SchedulerTest < (A701E661)>]: DEBUG - Event #5: ScheduleEntryIndex=2, EventTimestamp=467.375000, EventDataFloat=0.000000, EventDataString=9:00 event, EventDataKeyword=None

Almost ready for prime time.

Link to comment
Share on other sites

Leveraging the EventData* parameters, a new ScheduledSetOpen script lets one do timed SetOpen() operations like so:

[09/30/2020 - 08:20:49AM] [CRP:ScheduledSetOpen < (A7006687)>]: DEBUG - F4MS_ScheduledEvents triggered (LateCount=0, EventBuffer=[F4MS:F4MS_SchedulerEventBuffer < (FF22178E)>]).
[09/30/2020 - 08:20:50AM] [CRP:ScheduledSetOpen < (A7006687)>]: DEBUG - [CRP:ScheduledSetOpen < (A7006687)>].SetOpen(True) succeeded.

- There is an EventKeyword to trigger specific instances of the script upon receiving a scheduled event, whenever EventDataKeyword=EventKeyword.

- If EventDataFloat is 1.0, SetOpen(True) will be invoked. In any other case, SetOpen(false).

- The target of the operation is the reference to which the ScheduledSetOpen script is attached.

 

So the schedule could contain something like:

TimeOfDay=8.00, EventDataFloat=1.0, EventDataKeyword=SchedulerLightsKeyword, Description="Lights Out"
TimeOfDay=20.00, EventDataFloat=0.0, EventDataKeyword=SchedulerLightsKeyword, Descrption="Lights On"

Which would make the script do a (Self as ObjectReference).SetOpen(true) at 8:00am and (Self as ObjectReference).SetOpen(false) at 8:00pm, daily. If the script were attached to a switch or a generator, it would then turn on/off the switch or generator based on the schedule. It could also control a door, or really anything else that has an OpenState (GetOpenState() != 0).

 

There's also a similar script ScheduledEnableDisable which enables or disables its attached objectreference, but I'm not using it yet.

Link to comment
Share on other sites

I've added a schedule initializer to the scheduler.

If you mark daily schedule entries as "initialize", the scheduler will fire an scheduled event for these entries upon spinning up - even if said scheduled events did in fact never really occur in game, because they would have done so before the scheduler was running, or even installed.

 

In other words: If the daily 8pm schedule entry from the example above is configured with Initialize=True, but user installs/starts the scheduler not before 9:30pm gametime, the generator/switch/lights will nonetheless turn on. Setting Initialize=True would of course make sense for the 8am entry just as well.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...