Files
ReSkate/Extension/Multiplayer/Voice/voice_state.h
T
AyeZeeBB a7d95057ac Harden multiplayer against disruptive and spoofed traffic
Cap outfit packets and stop dropping recipients when a relay cannot be
built. Add per-player relay limits for outfits, skater sound and voice,
and a back-off for Steam IDs that keep failing to join.

Throwdowns: only participants can write rows, turns and scores; a copy
that fails to spawn no longer blocks the others.

Throttle remote skater and skateboard re-creation, cap remote objects
per session, and show developer and friend marks only for identities
Steam vouches for. Route all connections through Steam's relays.

Dedicated server: validate map changes, clean player names, keep vote
cooldowns across reconnects, and cut ban labels on a character boundary.
2026-10-04 13:49:11 -05:00

81 lines
3.4 KiB
C++

#pragma once
#include "Engine/Game/Multiplayer/voice_settings.h"
#include <array>
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <vector>
namespace dingosdk::multiplayer {
inline constexpr std::size_t max_voice_bytes = 16384;
struct VoiceData {
float distance = 35.f;
float gain = 1.f;
std::uint32_t policy_revision = 1;
std::vector<std::uint8_t> bytes;
};
struct VoicePolicy {
bool allowed = true;
std::uint32_t revision = 1;
bool operator==(const VoicePolicy &) const = default;
bool accepts(const VoiceData &voice) const noexcept {
return allowed && revision && voice.policy_revision == revision;
}
};
inline bool valid_voice(const VoiceData &voice) noexcept {
return !voice.bytes.empty() && voice.bytes.size() <= max_voice_bytes &&
voice.policy_revision && valid_voice_volume(voice.gain) &&
std::isfinite(voice.distance) && (voice.distance == 0.f ||
(voice.distance >= min_hearing_distance && voice.distance <= max_hearing_distance));
}
// One speaker per second. Steam's compressed voice is a few kilobytes a second, captured about
// fifty times a second: this leaves several times that and no more, since a host relays it all.
struct VoiceBudget {
std::uint64_t since{}, bytes{}, packets{};
bool accept(std::uint64_t now, std::size_t size) noexcept {
if (now < since || now - since >= 1000000) { since = now; bytes = packets = 0; }
if (!size || size > max_voice_bytes || packets >= 80 || bytes + size > 32 * 1024) return false;
++packets; bytes += size;
return true;
}
};
inline std::array<float, 2> voice_stereo(const std::array<float, 3> &listener,
const std::array<float, 3> &right, const std::array<float, 3> &speaker) noexcept {
float dot{}, length{}, axis{};
for (unsigned i = 0; i < 3; ++i) {
const auto d = speaker[i] - listener[i];
dot += d * right[i]; length += d * d; axis += right[i] * right[i];
}
const auto pan = std::isfinite(dot) && std::isfinite(length) && std::isfinite(axis) && length > .01f && axis > .01f ?
std::clamp(dot / (std::sqrt(length) * std::sqrt(axis)), -1.f, 1.f) : 0.f;
return {std::sqrt((1.f - pan) * .5f), std::sqrt((1.f + pan) * .5f)};
}
// How loud a speaker is at a distance, for a listener who hears out to `radius`
// (0: everywhere, full volume). Full volume up close, then a natural inverse-
// distance rolloff (about -6 dB per doubling), faded smoothly to silence over
// the last quarter of the radius, so a voice trails off instead of cutting out.
inline float voice_gain(const std::array<float, 3> &listener, const std::array<float, 3> &speaker,
float radius) noexcept {
float squared{};
for (unsigned i = 0; i < 3; ++i) {
const auto d = listener[i] - speaker[i];
squared += d * d;
}
if (!std::isfinite(squared) || !std::isfinite(radius) || radius < 0.f) return 0.f;
if (radius == 0.f) return 1.f;
const auto distance = std::sqrt(squared);
if (distance >= radius) return 0.f;
// (Not "near": Windows headers define it as a macro.)
const auto full_volume = std::max(3.f, radius * .15f);
if (distance <= full_volume) return 1.f;
auto gain = full_volume / distance;
const auto fade_start = radius * .75f;
if (distance > fade_start) {
const auto t = (distance - fade_start) / (radius - fade_start);
gain *= 1.f - t * t * (3.f - 2.f * t);
}
return gain;
}
}