Add option to only tick once per frame to Smooth Patch Precise#49
Add option to only tick once per frame to Smooth Patch Precise#49LazyDuchess wants to merge 7 commits intosims3fiend:mainfrom
Conversation
just-harry
left a comment
There was a problem hiding this comment.
As a performance optimisation, I'd recommend using std::memory_order_acq_rel for the atomic operations. Though it doesn't really matter in the grand scheme of things.
Anyway, feel free to ignore my comments, shapes is the one in charge.
patches/smooth_patch_precise.cpp
Outdated
|
|
||
| // I don't know what the boolean at 0xa60 is, but the game's code skips sleeping if it's zero, | ||
| // so if it's zero we'll avoid sleeping. | ||
| if ((idealTime == 0) | !*reinterpret_cast<const uint8_t*>((reinterpret_cast<uintptr_t>(this) + 0xa60))) { |
There was a problem hiding this comment.
This wasn't a bug :(
I intentionally used a bitwise-or here instead of a logical-or so that the branch-predictor would have only one branch to deal with instead of two
| extern "C" __declspec(dllimport) NTSTATUS __stdcall NtQueryTimerResolution(ULONG* MaximumTime, ULONG* MinimumTime, ULONG* CurrentTime); | ||
|
|
||
| static std::atomic<bool> frameSimulate{false}; | ||
| static std::atomic<bool> frameSimulate{true}; |
There was a problem hiding this comment.
To be on the safe side, it might be worthwhile to set this to true also in the Install method?
In case the user disables tickOnce while frameSimulate is false, and then re-enables it.
| double elapsed = (double)(now - beginWaitTime) / (double)performanceFrequency; | ||
| if (elapsed >= 1.0) { break; } |
There was a problem hiding this comment.
If I'm reading this correctly, this code bails out of the wait if a second-or-more has elapsed? If so, the floating-point calculations could be elided like so:
uint64_t elapsed = now - beginWaitTime;
if (elapsed >= performanceFrequency) { break; }| now = beginWaitTime; | ||
| while (frameSimulate.exchange(false) == false) | ||
| { | ||
| if (*reinterpret_cast<const uint32_t*>((reinterpret_cast<uintptr_t>(scriptHost) + 0xc08)) != 1) break; |
| .supportedVersions = VERSION_ALL, | ||
| .technicalDetails = { | ||
| "Credit goes to LazyDuchess for the original Smooth Patch.", | ||
| "This patch was authored by \"Just Harry\".", |
There was a problem hiding this comment.
You should note your contribution here—don't let me steal the credit for your effort! :)
| uint64_t idealTimeForThisCycle = previousSimulationCycleTime + idealTime; | ||
| if ((idealTime == 0) || !*reinterpret_cast<const uint8_t*>((reinterpret_cast<uintptr_t>(this) + 0xa60))) { | ||
| if (!tickOnce) return previousSimulationCycleTime; | ||
| return BusyWaitForFrame(this); |
There was a problem hiding this comment.
If BusyWaitForFrame was defined as an instance method of ScriptHostBase, this could be a tail-call; a very minor optimisation, albeit.
hi
this adds a checkbox to smooth patch precise that makes the simulate idle busy wait for the next frame after sleeping. has a fallback where it'll simulate anyways if it takes longer than 1 sec so we don't lock up.
i'm leaving it as a draft rn bc i'm not sure how beneficial it is, and there might be a lot of improvements or it might just be useless. tests haven't been super conclusive.