mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-17 16:17:06 +02:00
Other players' skaters and skateboards showed none of the game's skater effects: not the trail or fire a costume or deck comes with, and not the sparks, dust and puffs of a skater touching the world. Costume and skateboard effects. The game gives another player's skater and skateboard the right effect sets by itself, but builds them before their outfit is on, so nothing showed. They are now built again half a second after the outfit is applied. An always-on effect that a skater's item puts on the skateboard's wheel joints (the Ghost Skater trail) follows the skater's own copy of those joints, which only this player's skater keeps up to date: for other players it is taken out of the skater's sets and built on their skateboard, which has the same joints. Contact effects. They come from a skater touching the world, which only happens in that player's own game. Each game now captures its skater's contacts (position, velocity, surface normal, surface material) and sends up to three a tick in a new unreliable packet, PacketKind::effects. Other games play each through the game's own function, so the effect is still chosen from the surface and the speed. A contact is shown as late as that player's poses are, only within 30 m of their skater, and only for a material the level's table has: the game reads that table without a bound. Server. A dedicated server relays effects packets to players within 150 m of the sender, at most one packet a tick from each player. New setting players.sync_effects (default true), console and admin command "effects on|off". Off: the server relays none, and the roster tells games neither to send their contacts nor to build other players' costume and skateboard effects. Player-hosted lobbies relay through the host and always share them. The roster carries one more byte for the setting. Still protocol 45, which has not been released. New console command "mp effects": what has been captured and played, and why the last contact was refused if one was.
51 lines
2.4 KiB
C++
51 lines
2.4 KiB
C++
#pragma once
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cmath>
|
|
#include <cstdint>
|
|
#include <span>
|
|
|
|
// Skater effects other players see: the sparks, dust and puffs the game makes where a skater or
|
|
// their skateboard touches the world. Each is one contact; the game picks the effect from the
|
|
// surface's material and the speed.
|
|
namespace dingosdk::multiplayer {
|
|
struct Impact {
|
|
std::array<float, 3> position{}; // where, in the world
|
|
std::array<float, 3> velocity{}; // of the contact, metres a second; the game caps its length
|
|
std::array<float, 3> normal{}; // of the surface
|
|
std::uint16_t material{}; // the surface's index in the level's material table
|
|
bool operator==(const Impact &) const = default;
|
|
};
|
|
inline constexpr std::size_t max_impacts = 3; // in one packet: a frame or two of contacts
|
|
inline constexpr float max_impact_speed = 50; // the game's own cap
|
|
inline constexpr std::uint16_t max_impact_material = 0x1fff;
|
|
inline constexpr std::size_t impact_wire_size = 12 + 6 + 3 + 2;
|
|
inline bool valid_impact(const Impact &impact) noexcept {
|
|
float speed{}, facing{};
|
|
for (unsigned i = 0; i < 3; ++i) {
|
|
if (!std::isfinite(impact.position[i]) || std::abs(impact.position[i]) > 1000000.f ||
|
|
!std::isfinite(impact.velocity[i]) || !std::isfinite(impact.normal[i]))
|
|
return false;
|
|
speed += impact.velocity[i] * impact.velocity[i];
|
|
facing += impact.normal[i] * impact.normal[i];
|
|
}
|
|
// A little over the cap and the unit length: both are rounded on the way.
|
|
return speed <= (max_impact_speed + 1) * (max_impact_speed + 1) && facing <= 1.1f &&
|
|
impact.material <= max_impact_material;
|
|
}
|
|
inline bool valid_impacts(std::span<const Impact> impacts) noexcept {
|
|
if (impacts.empty() || impacts.size() > max_impacts) return false;
|
|
for (const auto &impact : impacts)
|
|
if (!valid_impact(impact)) return false;
|
|
return true;
|
|
}
|
|
// What a packet carries of one: the velocity to a centimetre a second, the normal in 127ths.
|
|
inline Impact wire_impact(Impact impact) noexcept {
|
|
for (unsigned i = 0; i < 3; ++i) {
|
|
impact.velocity[i] = std::round(std::clamp(impact.velocity[i], -max_impact_speed, max_impact_speed) * 100.f) / 100.f;
|
|
impact.normal[i] = std::round(std::clamp(impact.normal[i], -1.f, 1.f) * 127.f) / 127.f;
|
|
}
|
|
return impact;
|
|
}
|
|
} // namespace dingosdk::multiplayer
|