Restore freecam mouse look and block battle mouse actions
This commit is contained in:
1 parent
0d3881ae73
commit
1ed0fb73f9
3 files changed
+123
-20
No files matched your search
+107
-15
@@ -5,8 +5,6 @@ local Time = CS.UnityEngine.Time
|
||||
local Camera = CS.UnityEngine.Camera
|
||||
local GameObject = CS.UnityEngine.GameObject
|
||||
|
||||
-- Camera control tuning, in degrees per second (independent of frame rate).
|
||||
local KEYBOARD_TURN_SPEED = 90.0
|
||||
|
||||
_G.__FREECAM_ENABLED = _G.__FREECAM_ENABLED or false
|
||||
_G.__FREECAM_SPEED = _G.__FREECAM_SPEED or 15.0
|
||||
@@ -72,6 +70,88 @@ local function set_cinemachine_enabled(cam, enabled)
|
||||
end
|
||||
end
|
||||
|
||||
-- Client inspection: InControlInputModule.allowMouseInput controls UI
|
||||
-- clicks. Battle shortcuts also read MouseBindingSource independently.
|
||||
-- Mask only mouse button controls in memory; leave keyboard bindings intact.
|
||||
-- Do not use RemoveBinding/AddBinding (which emit OnBindingsChanged).
|
||||
_G.__FC_MOUSE_GATE = _G.__FC_MOUSE_GATE or {modules={}, bindings={}}
|
||||
local function restore_mouse_gate()
|
||||
local gate = _G.__FC_MOUSE_GATE
|
||||
for _, state in ipairs(gate.modules) do
|
||||
pcall(function() state.module.allowMouseInput = state.allowed end)
|
||||
end
|
||||
for _, state in ipairs(gate.bindings) do
|
||||
pcall(function()
|
||||
if state.binding.Control == CS.InControl.Mouse.None then
|
||||
gate.controlField:SetValue(state.binding, state.control)
|
||||
state.action:ClearInputState()
|
||||
end
|
||||
end)
|
||||
end
|
||||
gate.modules, gate.bindings, gate.sets = {}, {}, {}
|
||||
gate.active = false
|
||||
end
|
||||
|
||||
local function update_mouse_gate()
|
||||
local gate = _G.__FC_MOUSE_GATE
|
||||
local battleHUD = GameObject.Find("UIRoot/Page/BattleGamePhaseUI(Clone)")
|
||||
local wanted = _G.__FREECAM_ENABLED and battleHUD ~= nil
|
||||
-- Releasing Freecam while holding RMB must not become a battle click.
|
||||
if not wanted then
|
||||
if gate.active and not Input.GetMouseButton(0) and not Input.GetMouseButton(1) then
|
||||
restore_mouse_gate()
|
||||
end
|
||||
return
|
||||
end
|
||||
gate.active = true
|
||||
if not gate.controlField then
|
||||
local flags = CS.System.Enum.ToObject(typeof(CS.System.Reflection.BindingFlags), 60)
|
||||
gate.controlField = typeof(CS.InControl.MouseBindingSource):GetField("<Control>k__BackingField", flags)
|
||||
gate.setsField = typeof(CS.InControl.InputManager):GetField("playerActionSets", flags)
|
||||
assert(gate.controlField and gate.setsField, "Client mouse input schema is unavailable")
|
||||
end
|
||||
local eventSystem = CS.UnityEngine.EventSystems.EventSystem.current
|
||||
if eventSystem then
|
||||
local module = eventSystem:GetComponent(typeof(CS.InControl.InControlInputModule))
|
||||
if module then
|
||||
local recorded = false
|
||||
for _, state in ipairs(gate.modules) do
|
||||
if state.module == module then recorded = true; break end
|
||||
end
|
||||
if not recorded then
|
||||
gate.modules[#gate.modules + 1] = {module=module, allowed=module.allowMouseInput}
|
||||
end
|
||||
module.allowMouseInput = false
|
||||
end
|
||||
end
|
||||
gate.sets = gate.sets or {}
|
||||
local sets = gate.setsField:GetValue(nil)
|
||||
-- Scan each newly created action set once, rather than reflecting/scanning
|
||||
-- the assembly or all bindings on every render callback.
|
||||
for i = 0, sets.Count - 1 do
|
||||
local actionSet = sets[i]
|
||||
if not gate.sets[actionSet] then
|
||||
gate.sets[actionSet] = true
|
||||
local actions = actionSet.Actions
|
||||
for j = 0, actions.Count - 1 do
|
||||
local action = actions[j]
|
||||
local bindings = action.Bindings
|
||||
for k = 0, bindings.Count - 1 do
|
||||
local binding = bindings[k]
|
||||
if typeof(CS.InControl.MouseBindingSource):IsInstanceOfType(binding) then
|
||||
local control = binding.Control
|
||||
if control == CS.InControl.Mouse.LeftButton or control == CS.InControl.Mouse.RightButton then
|
||||
gate.bindings[#gate.bindings + 1] = {binding=binding, control=control, action=action}
|
||||
gate.controlField:SetValue(binding, CS.InControl.Mouse.None)
|
||||
action:ClearInputState()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function _G.__FREECAM_TICK()
|
||||
pcall(function()
|
||||
-- Render callbacks run for several cameras/passes in one frame. Consume
|
||||
@@ -98,7 +178,7 @@ function _G.__FREECAM_TICK()
|
||||
_G.__FC_EULER = cam.transform.eulerAngles
|
||||
set_cinemachine_enabled(cam, false)
|
||||
end
|
||||
show_ui("<color=#00FF88><b>[FreeCam: ON]</b> Speed: " .. string.format("%.1f", _G.__FREECAM_SPEED) .. " | Arrows: Fly | PgUp/PgDn: Up/Down | I/J/K/L: Look</color>")
|
||||
show_ui("<color=#00FF88><b>[FreeCam: ON]</b> Speed: " .. string.format("%.1f", _G.__FREECAM_SPEED) .. " | Arrows: Fly | PgUp/PgDn: Up/Down | RMB: Look</color>")
|
||||
else
|
||||
if cam then
|
||||
set_cinemachine_enabled(cam, true)
|
||||
@@ -107,6 +187,12 @@ function _G.__FREECAM_TICK()
|
||||
end
|
||||
end
|
||||
|
||||
local gateOK, gateError = pcall(update_mouse_gate)
|
||||
if not gateOK and not _G.__FC_GATE_ERROR then
|
||||
_G.__FC_GATE_ERROR = true
|
||||
CS.UnityEngine.Debug.Log("[FreeCam] Mouse gate error: " .. tostring(gateError))
|
||||
end
|
||||
|
||||
if _G.__FREECAM_ENABLED then
|
||||
local cam = get_active_cam()
|
||||
if cam then
|
||||
@@ -125,23 +211,21 @@ function _G.__FREECAM_TICK()
|
||||
-- Speed adjustment (+ / -)
|
||||
if Input.GetKeyDown(KeyCode.Equals) or Input.GetKeyDown(KeyCode.KeypadPlus) then
|
||||
_G.__FREECAM_SPEED = math.min(300.0, _G.__FREECAM_SPEED * 1.5)
|
||||
show_ui("<color=#00FF88><b>[FreeCam: ON]</b> Speed: " .. string.format("%.1f", _G.__FREECAM_SPEED) .. " | Arrows: Fly | PgUp/PgDn: Up/Down | I/J/K/L: Look</color>")
|
||||
show_ui("<color=#00FF88><b>[FreeCam: ON]</b> Speed: " .. string.format("%.1f", _G.__FREECAM_SPEED) .. " | Arrows: Fly | PgUp/PgDn: Up/Down | RMB: Look</color>")
|
||||
end
|
||||
if Input.GetKeyDown(KeyCode.Minus) or Input.GetKeyDown(KeyCode.KeypadMinus) then
|
||||
_G.__FREECAM_SPEED = math.max(0.5, _G.__FREECAM_SPEED / 1.5)
|
||||
show_ui("<color=#00FF88><b>[FreeCam: ON]</b> Speed: " .. string.format("%.1f", _G.__FREECAM_SPEED) .. " | Arrows: Fly | PgUp/PgDn: Up/Down | I/J/K/L: Look</color>")
|
||||
show_ui("<color=#00FF88><b>[FreeCam: ON]</b> Speed: " .. string.format("%.1f", _G.__FREECAM_SPEED) .. " | Arrows: Fly | PgUp/PgDn: Up/Down | RMB: Look</color>")
|
||||
end
|
||||
|
||||
-- Keyboard-only look: no mouse click is needed, so turning
|
||||
-- the camera does not require pressing a battle action button.
|
||||
local pitch, yaw = 0, 0
|
||||
if Input.GetKey(KeyCode.I) then pitch = pitch - 1 end
|
||||
if Input.GetKey(KeyCode.K) then pitch = pitch + 1 end
|
||||
if Input.GetKey(KeyCode.J) then yaw = yaw - 1 end
|
||||
if Input.GetKey(KeyCode.L) then yaw = yaw + 1 end
|
||||
_G.__FC_EULER = Vector3(
|
||||
_G.__FC_EULER.x + pitch * KEYBOARD_TURN_SPEED * dt,
|
||||
_G.__FC_EULER.y + yaw * KEYBOARD_TURN_SPEED * dt, 0)
|
||||
-- Raw Unity mouse input remains available to the camera while
|
||||
-- InControl battle clicks are gated separately below.
|
||||
if Input.GetMouseButton(1) then
|
||||
local rotX = Input.GetAxis("Mouse X") or 0
|
||||
local rotY = Input.GetAxis("Mouse Y") or 0
|
||||
_G.__FC_EULER = Vector3(_G.__FC_EULER.x - rotY * 2.5,
|
||||
_G.__FC_EULER.y + rotX * 2.5, 0)
|
||||
end
|
||||
|
||||
-- Compute 3D direction vectors from camera Euler angles
|
||||
local radY = _G.__FC_EULER.y * (math.pi / 180.0)
|
||||
@@ -204,3 +288,11 @@ end
|
||||
if not _G.__FREECAM_ENABLED then
|
||||
show_ui(RAINBOW_TEXT)
|
||||
end
|
||||
|
||||
-- Restore the in-memory controls before the Client tears down its settings.
|
||||
if not _G.__FC_MOUSE_QUIT_REGISTERED then
|
||||
local ok = pcall(function()
|
||||
CS.UnityEngine.Application.quitting('+', function() restore_mouse_gate() end)
|
||||
end)
|
||||
_G.__FC_MOUSE_QUIT_REGISTERED = ok
|
||||
end
|
||||
Reference in new issue
Block a user