Voice goes through a separate relay (moonwell-voice-relay, from the
MoonWell client repo), never the world socket. mangosd only vouches:
`.mwvoice` answers the player with an HMAC-signed ticket and the relay
address as an addon line (prefix MWV), and every 250 ms the world thread
sends the relay each character in the world: faction, map, instance,
position, group and guild, so no client can claim a place, group or
guild of its own. The feed is read after the map update, under the
lock that keeps async packets out. Sends are counted and logged every
30 s.
MoonWell.Voice.* in mangosd.conf (off by default); the production
compose adds the voice-relay container (UDP 3725) and the voice_secret
secret, deploy/local enables voice against a relay on the Windows host.
Checked: the changed units build in vmangos-buildenv; a ticket and a
feed datagram made by this code verify in the relay tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A 1.12 client is never told which quests were handed in, so MoonWell UI
showed quests already done as available. `.mwquests` (player level) now
answers with the character's rewarded quests, and each quest rewarded
later is sent at once, as addon lines to the player alone (LANG_ADDON,
prefix MWQ; never shown, fired as CHAT_MSG_ADDON).
Checked on the local server with MoonWell UI: the list matches
character_queststatus, a live reward arrives as +id.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Step-by-step guide with a working example for adding loot that drops
only for a full group, linked from the content README.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Creatures in party dungeons scale health, healing and damage to the number
of players inside (DungeonScaling.* settings). A full group that stays inside
for the whole fight gets a higher chance of rare or better weapons and armor,
including world drops behind chanced references, and condition type 60 marks
loot that drops only for a full group.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Keep launcher tickets mandatory by default and compile password authentication only into the dedicated local image. Build the shared local image once and add an end-to-end SRP login check.
_ScheduleFunctionOnceMs compared the new timer against
`m_orderedPendingTimer.end()->m_whenToTriggerMe`, which dereferences
the deque's past-the-end iterator. AddressSanitizer reports a
container-overflow there as soon as a second timer is scheduled
while one is pending, e.g. two concurrent realmd sessions with
MaxSessionDuration.
Compare against back() instead, and append when the new timer is due
at the same time as the last one. With a strict `<`, an entry equal
to the last one fell through to the search loop, which looks for a
strictly later entry, found none and dropped the timer.
kqueue reports read and write readiness as separate events, so one
kevent() batch can hold an EVFILT_READ and an EVFILT_WRITE event for
the same socket. When the read event closes the connection and the
last reference to the socket goes away, the following write event is
dispatched to the destroyed object and realmd or mangosd crashes with
SIGSEGV in IoContext::RunUntilShutdown.
On macOS this happens every time realmd's MaxSessionDuration timer
closes a session (300 seconds by default): the shutdown sets EV_EOF
on both filters and both arrive in the same batch. One idle TCP
connection with MaxSessionDuration = 5 reproduces it in seconds.
Linux is unaffected because epoll reports both directions in one
event.
The BSD event loop now records the batch it is dispatching per
thread, and ~AsyncSocket removes the socket from the rest of that
batch, so its remaining events are skipped.