Skip to content

Commit 37b1795

Browse files
committed
backport timer fixes
1 parent 2a93e57 commit 37b1795

File tree

4 files changed

+99
-30
lines changed

4 files changed

+99
-30
lines changed

game_patch/input/mouse.cpp

Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -304,36 +304,61 @@ void linear_pitch_test()
304304
}
305305
#endif // DEBUG
306306

307+
static float convert_pitch_delta_to_non_linear_space(
308+
const float current_yaw,
309+
const float current_pitch_non_lin,
310+
const float pitch_delta,
311+
const float yaw_delta
312+
) {
313+
// Convert to linear space. See `physics_make_orient`.
314+
const rf::Vector3 fvec =
315+
fw_vector_from_non_linear_yaw_pitch(current_yaw, current_pitch_non_lin);
316+
const float current_pitch_lin = linear_pitch_from_forward_vector(fvec);
317+
318+
// Calculate in linear space.
319+
constexpr float HALF_PI = 1.5707964f;
320+
const float new_pitch_lin =
321+
std::clamp(current_pitch_lin + pitch_delta, -HALF_PI, HALF_PI);
322+
const float new_yaw = current_yaw + yaw_delta;
323+
324+
// Convert back to non-linear space.
325+
const rf::Vector3 fvec_new =
326+
fw_vector_from_linear_yaw_pitch(new_yaw, new_pitch_lin);
327+
const float new_pitch_non_lin = non_linear_pitch_from_fw_vector(fvec_new);
328+
329+
// Update non-linear pitch delta.
330+
const float new_pitch_delta = new_pitch_non_lin - current_pitch_non_lin;
331+
xlog::trace(
332+
"non-lin {} lin {} delta {} new {}",
333+
current_pitch_non_lin,
334+
current_pitch_lin,
335+
pitch_delta,
336+
new_pitch_delta
337+
);
338+
339+
return new_pitch_delta;
340+
}
341+
307342
CodeInjection linear_pitch_patch{
308343
0x0049DEC9,
309-
[](auto& regs) {
310-
if (!g_alpine_game_config.mouse_linear_pitch)
344+
[] (const auto& regs) {
345+
if (!g_alpine_game_config.mouse_linear_pitch) {
311346
return;
312-
// Non-linear pitch value and delta from RF
313-
rf::Entity* entity = regs.esi;
314-
float current_yaw = entity->control_data.phb.y;
315-
float current_pitch_non_lin = entity->control_data.eye_phb.x;
316-
float& pitch_delta = *reinterpret_cast<float*>(regs.esp + 0x44 - 0x34);
317-
float& yaw_delta = *reinterpret_cast<float*>(regs.esp + 0x44 + 0x4);
318-
if (pitch_delta == 0)
347+
}
348+
float& pitch_delta = addr_as_ref<float>(regs.esp + 0x44 - 0x34);
349+
if (pitch_delta == .0f) {
319350
return;
320-
// Convert to linear space (see RotMatixFromEuler function at 004A0D70)
321-
auto fvec = fw_vector_from_non_linear_yaw_pitch(current_yaw, current_pitch_non_lin);
322-
float current_pitch_lin = linear_pitch_from_forward_vector(fvec);
323-
// Calculate new pitch in linear space
324-
float new_pitch_lin = current_pitch_lin + pitch_delta;
325-
float new_yaw = current_yaw + yaw_delta;
326-
// Clamp to [-pi, pi]
327-
constexpr float half_pi = 1.5707964f;
328-
new_pitch_lin = std::clamp(new_pitch_lin, -half_pi, half_pi);
329-
// Convert back to non-linear space
330-
auto fvec_new = fw_vector_from_linear_yaw_pitch(new_yaw, new_pitch_lin);
331-
float new_pitch_non_lin = non_linear_pitch_from_fw_vector(fvec_new);
332-
// Update non-linear pitch delta
333-
float new_pitch_delta = new_pitch_non_lin - current_pitch_non_lin;
334-
xlog::trace("non-lin {} lin {} delta {} new {}", current_pitch_non_lin, current_pitch_lin, pitch_delta,
335-
new_pitch_delta);
336-
pitch_delta = new_pitch_delta;
351+
}
352+
const rf::Entity* const entity = regs.esi;
353+
const float current_yaw = entity->control_data.phb.y;
354+
const float current_pitch_non_lin = entity->control_data.eye_phb.x;
355+
const float yaw_delta = addr_as_ref<float>(regs.esp + 0x44 + 0x4);
356+
pitch_delta = convert_pitch_delta_to_non_linear_space(
357+
current_yaw,
358+
current_pitch_non_lin,
359+
pitch_delta,
360+
yaw_delta
361+
);
337362
},
338363
};
339364

game_patch/misc/alpine_settings.cpp

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -953,15 +953,22 @@ bool alpine_player_settings_load(rf::Player* player)
953953
if (settings.count("MouseYInvert")) {
954954
player->settings.controls.axes[1].invert = std::stoi(settings["MouseYInvert"]);
955955
processed_keys.insert("MouseYInvert");
956+
}
957+
if (settings.count("SDLMouse")) {
958+
g_alpine_game_config.sdl_mouse = std::stoi(settings["SDLMouse"]);
959+
processed_keys.insert("SDLMouse");
960+
} else if (settings.count("DirectInput")) {
961+
// Legacy fallback: map DirectInput to the closest SDLMouse equivalent
962+
// DirectInput == 0 -> SDLMouse = 0 (keep legacy / non-SDL behavior)
963+
// DirectInput != 0 -> SDLMouse = 1 (use SDL-like backend)
964+
int direct_input = std::stoi(settings["DirectInput"]);
965+
g_alpine_game_config.sdl_mouse = (direct_input != 0) ? 1 : 0;
966+
processed_keys.insert("DirectInput");
956967
}
957968
if (settings.count("MouseLinearPitch")) {
958969
g_alpine_game_config.mouse_linear_pitch = std::stoi(settings["MouseLinearPitch"]);
959970
processed_keys.insert("MouseLinearPitch");
960971
}
961-
if (settings.count("SDLMouse")) {
962-
g_alpine_game_config.sdl_mouse = std::stoi(settings["SDLMouse"]);
963-
processed_keys.insert("SDLMouse");
964-
}
965972
if (settings.count("SwapARBinds")) {
966973
g_alpine_game_config.swap_ar_controls = std::stoi(settings["SwapARBinds"]);
967974
processed_keys.insert("SwapARBinds");

game_patch/os/frametime.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "../rf/hud.h"
1212
#include "../rf/entity.h"
1313
#include "../rf/os/frametime.h"
14+
#include "os.h"
1415
#include "../multi/multi.h"
1516
#include "../main/main.h"
1617
#include "../misc/alpine_settings.h"

game_patch/os/os.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include "../misc/alpine_settings.h"
1313
#include "win32_console.h"
1414
#include <xlog/xlog.h>
15+
#include <timeapi.h>
16+
#include "os.h"
1517

1618
const char* get_win_msg_name(UINT msg);
1719

@@ -145,6 +147,40 @@ static FunHook<void(char*, bool)> os_parse_params_hook{
145147
},
146148
};
147149

150+
void wait_for(const float ms, const WaitableTimer& timer) {
151+
if (ms <= .0f) {
152+
return;
153+
}
154+
155+
if (!timer.handle) {
156+
SLEEP:
157+
static const MMRESULT res = timeBeginPeriod(1);
158+
if (res != TIMERR_NOERROR) {
159+
ERR_ONCE(
160+
"The frame rate may be unstable, because `timeBeginPeriod` failed ({})",
161+
res
162+
);
163+
}
164+
Sleep(static_cast<DWORD>(ms));
165+
} else {
166+
// SetWaitableTimer requires 100-nanosecond intervals.
167+
// Negative values indicate relative time.
168+
LARGE_INTEGER dur{
169+
.QuadPart = -static_cast<LONGLONG>(static_cast<double>(ms) * 10'000.)
170+
};
171+
172+
if (!SetWaitableTimer(timer.handle, &dur, 0, nullptr, nullptr, FALSE)) {
173+
ERR_ONCE("`SetWaitableTimer` in `wait_for` failed ({})", GetLastError());
174+
goto SLEEP;
175+
}
176+
177+
if (WaitForSingleObject(timer.handle, INFINITE) != WAIT_OBJECT_0) {
178+
ERR_ONCE("`WaitForSingleObject` in `wait_for` failed ({})", GetLastError());
179+
goto SLEEP;
180+
}
181+
}
182+
}
183+
148184
void os_apply_patch()
149185
{
150186
// Lock to DPI_AWARENESS_CONTEXT_UNAWARE so the legacy D3D renderer's bitmap-scaling

0 commit comments

Comments
 (0)