added update for xdotool to prevent keyboard from going stuck after long session. explained in readme that the DXVK version is replaced
This commit is contained in:
parent
2024f4cbe0
commit
53787723c1
@ -35,7 +35,7 @@ overlay /mnt/merged-cstrike/models overlay ro,lowerdir=/home/gameservers/css_
|
|||||||
overlay /mnt/merged-cstrike/sound overlay ro,lowerdir=/home/gameservers/css_ze/cstrike/sound:/home/gameservers/css_mg/cstrike/sound:/home/gameservers/css_zr/cstrike/sound,nofail 0 0
|
overlay /mnt/merged-cstrike/sound overlay ro,lowerdir=/home/gameservers/css_ze/cstrike/sound:/home/gameservers/css_mg/cstrike/sound:/home/gameservers/css_zr/cstrike/sound,nofail 0 0
|
||||||
|
|
||||||
## third run
|
## third run
|
||||||
docker run -d --name css-test -e SIG_URL=ws://172.17.0.1:3000 -e CONTAINER_NAME=css-test -e CF_APP_ID= -e CF_APP_TOKEN= -e CAP_FPS=60 -e CAP_W=800 -e CAP_H=600 --cpus="8.0" \
|
docker run -d --name css-test -e SIG_URL=ws://172.17.0.1:3000 -e CONTAINER_NAME=css-test -e CF_APP_ID= -e CF_APP_TOKEN= -e CAP_FPS=60 -e CAP_W=800 -e CAP_H=600 --cpus="10.0" \
|
||||||
-v /mnt/merged-cstrike/maps:/home/ubuntu/Counter-Strike\ Source/cstrike/maps:ro \
|
-v /mnt/merged-cstrike/maps:/home/ubuntu/Counter-Strike\ Source/cstrike/maps:ro \
|
||||||
-v /mnt/merged-cstrike/materials:/home/ubuntu/Counter-Strike\ Source/cstrike/materials:ro \
|
-v /mnt/merged-cstrike/materials:/home/ubuntu/Counter-Strike\ Source/cstrike/materials:ro \
|
||||||
-v /mnt/merged-cstrike/models:/home/ubuntu/Counter-Strike\ Source/cstrike/models:ro \
|
-v /mnt/merged-cstrike/models:/home/ubuntu/Counter-Strike\ Source/cstrike/models:ro \
|
||||||
@ -64,3 +64,5 @@ css-client
|
|||||||
## CSS DirectX9 → built-in DXVK → Vulkan → Wine Wayland driver → Weston (lavapipe/llvmpipe) → Xwayland → X11 → ximagesrc capture for gst_agent
|
## CSS DirectX9 → built-in DXVK → Vulkan → Wine Wayland driver → Weston (lavapipe/llvmpipe) → Xwayland → X11 → ximagesrc capture for gst_agent
|
||||||
|
|
||||||
## using DXVK cache and MESA_SHADER_CACHE which are mounted volumes
|
## using DXVK cache and MESA_SHADER_CACHE which are mounted volumes
|
||||||
|
|
||||||
|
## the inbuilt DXVK version 2.3 is replaced with DXVK 3.0 downloaded from https://github.com/doitsujin/dxvk/releases/download/v3.0/dxvk-3.0.tar.gz
|
||||||
|
|||||||
@ -79,6 +79,20 @@ def xdotool(*args):
|
|||||||
stderr=subprocess.DEVNULL,
|
stderr=subprocess.DEVNULL,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Track held keys so we can release them all on controller change
|
||||||
|
_held_keys = set()
|
||||||
|
|
||||||
|
def release_all_keys():
|
||||||
|
# Release all currently held keys and reset X11 modifier state
|
||||||
|
for key in list(_held_keys):
|
||||||
|
try:
|
||||||
|
xdotool('keyup', key)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
_held_keys.clear()
|
||||||
|
# Reset X11 modifier state (clears stuck shift/ctrl/alt etc.)
|
||||||
|
xdotool('key', '--clearmodifiers', 'Escape')
|
||||||
|
|
||||||
def handle_input(event):
|
def handle_input(event):
|
||||||
t = event.get('type')
|
t = event.get('type')
|
||||||
if t == 'mouse_move':
|
if t == 'mouse_move':
|
||||||
@ -91,12 +105,18 @@ def handle_input(event):
|
|||||||
elif t == 'mouse_up':
|
elif t == 'mouse_up':
|
||||||
xdotool('mouseup', str(event.get('button', 1)))
|
xdotool('mouseup', str(event.get('button', 1)))
|
||||||
elif t == 'key_down':
|
elif t == 'key_down':
|
||||||
xdotool('keydown', event.get('key', ''))
|
key = event.get('key', '')
|
||||||
|
_held_keys.add(key)
|
||||||
|
xdotool('keydown', key)
|
||||||
elif t == 'key_up':
|
elif t == 'key_up':
|
||||||
xdotool('keyup', event.get('key', ''))
|
key = event.get('key', '')
|
||||||
|
_held_keys.discard(key)
|
||||||
|
xdotool('keyup', key)
|
||||||
elif t == 'mouse_wheel':
|
elif t == 'mouse_wheel':
|
||||||
button = '4' if event.get('direction') == 'up' else '5'
|
button = '4' if event.get('direction') == 'up' else '5'
|
||||||
xdotool('click', button)
|
xdotool('click', button)
|
||||||
|
elif t == 'release_keys':
|
||||||
|
release_all_keys()
|
||||||
|
|
||||||
# ── GStreamer Pipeline ────────────────────────────────────────────────────────
|
# ── GStreamer Pipeline ────────────────────────────────────────────────────────
|
||||||
class CSSStreamAgent:
|
class CSSStreamAgent:
|
||||||
@ -125,18 +145,10 @@ class CSSStreamAgent:
|
|||||||
f'webrtcbin. '
|
f'webrtcbin. '
|
||||||
|
|
||||||
# Game audio: pipewiresrc → Opus
|
# Game audio: pipewiresrc → Opus
|
||||||
# pipewiresrc with no target follows PipeWire's default *capture*
|
# pipewiresrc is the native PipeWire GStreamer source (Ubuntu 24+/26).
|
||||||
# node (the microphone, virtual_mic) — not the default sink's
|
# It connects to the default audio output monitor via PipeWire directly,
|
||||||
# monitor — so without explicit targeting it silently captured
|
# avoiding the PulseAudio compatibility layer entirely.
|
||||||
# the mic into this track instead of game audio.
|
f'pipewiresrc ! '
|
||||||
# game_output is a single PipeWire node with both playback ports
|
|
||||||
# (what CSS writes to) and monitor ports (the loopback read side)
|
|
||||||
# on the same node — there's no separate "game_output.monitor"
|
|
||||||
# node. stream.capture.sink=true tells PipeWire's autoconnect to
|
|
||||||
# link to that node's monitor/capture-sink ports rather than
|
|
||||||
# treating it as a regular source.
|
|
||||||
f'pipewiresrc target-object=game_output '
|
|
||||||
f'stream-properties="props,stream.capture.sink=(boolean)true" ! '
|
|
||||||
f'audio/x-raw,format=F32LE,rate=48000,channels=2 ! '
|
f'audio/x-raw,format=F32LE,rate=48000,channels=2 ! '
|
||||||
f'audioconvert ! '
|
f'audioconvert ! '
|
||||||
f'opusenc ! '
|
f'opusenc ! '
|
||||||
|
|||||||
@ -182,6 +182,15 @@ function releaseControl(entry, reason) {
|
|||||||
entry.ws.send(JSON.stringify({ type: 'control_released', reason }));
|
entry.ws.send(JSON.stringify({ type: 'control_released', reason }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tell gst_agent to release all held keys and reset X11 modifier state.
|
||||||
|
// Without this, stuck keys (shift/ctrl/w/etc.) persist across controller
|
||||||
|
// handoffs and eventually corrupt xdotool's input state, requiring a
|
||||||
|
// full container restart to recover.
|
||||||
|
const agent = [...agentSessions.values()][0];
|
||||||
|
if (agent && agent.agentWs && agent.agentWs.readyState === WebSocket.OPEN) {
|
||||||
|
agent.agentWs.send(JSON.stringify({ type: 'release_keys' }));
|
||||||
|
}
|
||||||
|
|
||||||
if (controlQueue.length > 0) {
|
if (controlQueue.length > 0) {
|
||||||
const next = controlQueue.shift();
|
const next = controlQueue.shift();
|
||||||
applyController(next);
|
applyController(next);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user