Only shake the camera for a nearby source - #579
Open
nyyhao wants to merge 1 commit into
Open
Conversation
EarthQuake is a single global that DefaultCamera adds directly onto the camera pitch, and the effect handlers wrote to it unconditionally. Any object running one of those handlers therefore shook every nearby player's view at full strength, regardless of distance and including sources off-screen. It shows up most clearly with Hellfire (AT_SKILL_HELL_FIRE), whose MODEL_CIRCLE_LIGHT handler sets EarthQuake on every frame the effect is alive. On a populated map a couple of casters anywhere in scope is enough to make the camera judder continuously, which reads as an engine fault rather than as something happening in the world. It is easy to miss with a handful of players around and obvious with a busy town. Add SetEarthQuakeAt(), next to the global it writes, which applies the shake only when its source is within about twelve tiles - roughly a screen - and scales it linearly to zero at that edge. Magnitude at zero distance is unchanged, so an effect still feels the same to whoever is standing in it. Routed the seventeen object-driven sites in ZzzEffect, EffectBehaviors, MoveHandlers and GOBoid through it. The scripted map-wide shakes in Raklion, Hellas, Kanturu, Chaos Castle and Cursed Temple are deliberately left alone: those are meant to shake the whole map during an event, and several have no local object to measure a distance from.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What I saw
Playing in Lorencia, walking around town, the camera would start juddering
hard — like a constant earthquake — for a few seconds, stop, then start again a
little later somewhere else in the city. It was bad enough to be unplayable in
places, and it didn't happen out on the hunting maps.
Setup was the MuMain client on macOS against a local OpenMU server with its
bot population enabled (50 bot characters), which is what made it so obvious:
bots warp into Lorencia to shop and fight, so there was almost always somebody
casting something nearby.
Tracking it down
I logged
EarthQuakewhereDefaultCameraapplies it, along with the hero'stile. It fired around tiles (139–144, 131–137) with values between
-0.6and-0.1in0.1steps. That range identifies the source exactly — it's(rand() % 6 - 6) * 0.1finMove_MODEL_CIRCLE_LIGHT, and across 88 samples Inever saw
-0.7or-0.8, which rules out the similar-looking(rand() % 8 - 8) * 0.1fsites inZzzEffect.cpp.Working back from there:
MODEL_CIRCLE_LIGHTatSubType0 comes fromAT_SKILL_HELL_FIREinZzzCharacter.cpp. So it was other players' Hellfirecasts. The handler sets
EarthQuakeon every frame the effect is alive, andEarthQuakeis a single global thatDefaultCameraadds straight onto thecamera pitch — with no distance test anywhere in that path. A caster shakes
every nearby player's view at full strength no matter how far away they are,
including sources off-screen entirely.
Decay is
EarthQuake *= 0.2fonce per frame inInitializeSceneFrame, so itdies quickly on its own; the problem is purely that something in scope keeps
re-setting it.
The change
SetEarthQuakeAt(), declared next to the global it writes, applies the shakeonly when its source is within about twelve tiles — roughly a screen — and
scales it linearly to zero at that edge. Magnitude at zero distance is
unchanged, so an effect feels exactly the same to whoever is standing in it;
what stops is strangers across the map shaking your camera.
Routed the seventeen object-driven sites in
ZzzEffect,EffectBehaviors,MoveHandlersandGOBoidthrough it. The scripted map-wide shakes inRaklion, Hellas, Kanturu, Chaos Castle and Cursed Temple are deliberately left
alone — those are meant to shake the whole map during an event, and several
have no local object to measure a distance from.
On whether you want this
This is a behaviour change, not a port fix, so it's entirely your call. The
argument for it is that a screen shake from a caster you can't see is hard to
defend on any reading. The argument against is that it's long-standing
behaviour and someone may consider the current feel correct — it's only really
punishing when a map is busy, which a bot-populated test server exaggerates far
beyond a normal server.
Happy to drop it, narrow it to fewer effects, or make the radius configurable
if you'd rather.
Also noticed, deliberately not changed
(rand() % 6 - 6) * 0.1fyields-0.6 … -0.1— always negative, never zero orpositive. So it isn't a shake around a centre, it's a persistent downward pitch
with jitter on top, and every one of my 88 samples was negative. Several other
sites share the shape (
% 8 - 8,% 4 - 4). It looks like an off-by-one, butfixing it would change how every one of those effects looks, so I left it well
alone.
Testing
macOS 26.5.1 / arm64, GL 3.3 core, against OpenMU with 50 bots. No Windows or
Linux toolchain here, so those builds are unverified — this touches shared
files rather than sitting behind a platform guard.