Add vanilla-compatible raw broadcasts
This commit is contained in:
parent
f02c053ed2
commit
c3bf7a3c87
@ -44,6 +44,7 @@ using std::mem_fn;
|
|||||||
using std::ref;
|
using std::ref;
|
||||||
using std::cref;
|
using std::cref;
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
using std::prev;
|
using std::prev;
|
||||||
// using std::next;
|
// using std::next;
|
||||||
|
@ -2468,7 +2468,7 @@ NetworkedAnimatorPtr Player::effectsAnimator() {
|
|||||||
return m_effectsAnimator;
|
return m_effectsAnimator;
|
||||||
}
|
}
|
||||||
|
|
||||||
const String secretProprefix = strf("{:c}JsonProperty{:c}", 0, 0);
|
const String secretProprefix = "\0JsonProperty\0"s;
|
||||||
|
|
||||||
Maybe<StringView> Player::getSecretPropertyView(String const& name) const {
|
Maybe<StringView> Player::getSecretPropertyView(String const& name) const {
|
||||||
if (auto tag = m_effectsAnimator->globalTagPtr(secretProprefix + name)) {
|
if (auto tag = m_effectsAnimator->globalTagPtr(secretProprefix + name)) {
|
||||||
|
@ -20,11 +20,14 @@
|
|||||||
#include "StarWorldTemplate.hpp"
|
#include "StarWorldTemplate.hpp"
|
||||||
#include "StarStoredFunctions.hpp"
|
#include "StarStoredFunctions.hpp"
|
||||||
#include "StarInspectableEntity.hpp"
|
#include "StarInspectableEntity.hpp"
|
||||||
|
#include "StarCurve25519.hpp"
|
||||||
|
|
||||||
namespace Star {
|
namespace Star {
|
||||||
|
|
||||||
const float WorldClient::DropDist = 6.0f;
|
const std::string SECRET_BROADCAST_PUBLIC_KEY = "SecretBroadcastPublicKey";
|
||||||
|
const std::string SECRET_BROADCAST_PREFIX = "\0Broadcast\0"s;
|
||||||
|
|
||||||
|
const float WorldClient::DropDist = 6.0f;
|
||||||
WorldClient::WorldClient(PlayerPtr mainPlayer) {
|
WorldClient::WorldClient(PlayerPtr mainPlayer) {
|
||||||
auto& root = Root::singleton();
|
auto& root = Root::singleton();
|
||||||
auto assets = root.assets();
|
auto assets = root.assets();
|
||||||
@ -792,7 +795,35 @@ void WorldClient::handleIncomingPackets(List<PacketPtr> const& packets) {
|
|||||||
m_damageManager->pushRemoteDamageRequest(damage->remoteDamageRequest);
|
m_damageManager->pushRemoteDamageRequest(damage->remoteDamageRequest);
|
||||||
|
|
||||||
} else if (auto damage = as<DamageNotificationPacket>(packet)) {
|
} else if (auto damage = as<DamageNotificationPacket>(packet)) {
|
||||||
|
auto& materialKind = damage->remoteDamageNotification.damageNotification.targetMaterialKind.utf8();
|
||||||
|
const size_t prefixSize = SECRET_BROADCAST_PREFIX.size();
|
||||||
|
const size_t signatureSize = Curve25519::SignatureSize;
|
||||||
|
const size_t dataSize = prefixSize + signatureSize;
|
||||||
|
|
||||||
|
if (materialKind.size() >= dataSize && materialKind.rfind(SECRET_BROADCAST_PREFIX, 0) != NPos) {
|
||||||
|
// this is actually a secret broadcast!!
|
||||||
|
if (auto player = m_entityMap->get<Player>(damage->remoteDamageNotification.sourceEntityId)) {
|
||||||
|
if (auto publicKey = player->getSecretPropertyView(SECRET_BROADCAST_PUBLIC_KEY)) {
|
||||||
|
if (publicKey->utf8Size() == Curve25519::PublicKeySize) {
|
||||||
|
std::string_view broadcast(materialKind);
|
||||||
|
auto signature = broadcast.substr(prefixSize, signatureSize);
|
||||||
|
|
||||||
|
auto rawBroadcast = broadcast.substr(dataSize);
|
||||||
|
if (Curve25519::verify(
|
||||||
|
(uint8_t const*)signature.data(),
|
||||||
|
(uint8_t const*)publicKey->utf8Ptr(),
|
||||||
|
(void*)rawBroadcast.data(),
|
||||||
|
rawBroadcast.size()
|
||||||
|
)) {
|
||||||
|
handleSecretBroadcast(player, rawBroadcast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
m_damageManager->pushRemoteDamageNotification(damage->remoteDamageNotification);
|
m_damageManager->pushRemoteDamageNotification(damage->remoteDamageNotification);
|
||||||
|
}
|
||||||
|
|
||||||
} else if (auto entityMessagePacket = as<EntityMessagePacket>(packet)) {
|
} else if (auto entityMessagePacket = as<EntityMessagePacket>(packet)) {
|
||||||
EntityPtr entity;
|
EntityPtr entity;
|
||||||
@ -917,6 +948,11 @@ void WorldClient::update() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Secret broadcasts are transmitted through DamageNotifications for vanilla server compatibility.
|
||||||
|
// Because DamageNotification packets are spoofable, we have to sign the data so other clients can validate that it is legitimate.
|
||||||
|
auto& publicKey = Curve25519::publicKey();
|
||||||
|
m_mainPlayer->setSecretProperty(SECRET_BROADCAST_PUBLIC_KEY, String((const char*)publicKey.data(), publicKey.size()));
|
||||||
|
|
||||||
++m_currentStep;
|
++m_currentStep;
|
||||||
//m_interpolationTracker.update(m_currentStep);
|
//m_interpolationTracker.update(m_currentStep);
|
||||||
m_interpolationTracker.update(Time::monotonicTime());
|
m_interpolationTracker.update(Time::monotonicTime());
|
||||||
@ -1847,6 +1883,33 @@ void WorldClient::connectWire(WireConnection const& output, WireConnection const
|
|||||||
m_outgoingPackets.append(make_shared<ConnectWirePacket>(output, input));
|
m_outgoingPackets.append(make_shared<ConnectWirePacket>(output, input));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WorldClient::sendSecretBroadcast(StringView broadcast, bool raw) {
|
||||||
|
if (!inWorld() || !m_mainPlayer || !m_mainPlayer->getSecretPropertyView(SECRET_BROADCAST_PUBLIC_KEY))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto signature = Curve25519::sign((void*)broadcast.utf8Ptr(), broadcast.utf8Size());
|
||||||
|
|
||||||
|
auto damageNotification = make_shared<DamageNotificationPacket>();
|
||||||
|
auto& remDmg = damageNotification->remoteDamageNotification;
|
||||||
|
auto& dmg = remDmg.damageNotification;
|
||||||
|
|
||||||
|
dmg.targetEntityId = dmg.sourceEntityId = remDmg.sourceEntityId = m_mainPlayer->entityId();
|
||||||
|
dmg.damageDealt = dmg.healthLost = 0.0f;
|
||||||
|
dmg.hitType = HitType::Hit;
|
||||||
|
dmg.damageSourceKind = "nodamage";
|
||||||
|
dmg.targetMaterialKind = raw ? broadcast : strf("{}{}{}", SECRET_BROADCAST_PREFIX, StringView((char*)&signature, sizeof(signature)), broadcast);
|
||||||
|
dmg.position = m_mainPlayer->position();
|
||||||
|
|
||||||
|
m_outgoingPackets.emplace_back(move(damageNotification));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WorldClient::handleSecretBroadcast(PlayerPtr player, StringView broadcast) {
|
||||||
|
Logger::info("Received broadcast '{}'", broadcast);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void WorldClient::ClientRenderCallback::addDrawable(Drawable drawable, EntityRenderLayer renderLayer) {
|
void WorldClient::ClientRenderCallback::addDrawable(Drawable drawable, EntityRenderLayer renderLayer) {
|
||||||
drawables[renderLayer].append(move(drawable));
|
drawables[renderLayer].append(move(drawable));
|
||||||
}
|
}
|
||||||
|
@ -150,6 +150,12 @@ public:
|
|||||||
void disconnectAllWires(Vec2I wireEntityPosition, WireNode const& node);
|
void disconnectAllWires(Vec2I wireEntityPosition, WireNode const& node);
|
||||||
void connectWire(WireConnection const& output, WireConnection const& input);
|
void connectWire(WireConnection const& output, WireConnection const& input);
|
||||||
|
|
||||||
|
// Functions for sending broadcast messages to other players that can receive them,
|
||||||
|
// on completely vanilla servers by smuggling it through a DamageNotification.
|
||||||
|
// It's cursed as fuck, but it works.
|
||||||
|
bool sendSecretBroadcast(StringView broadcast, bool raw = false);
|
||||||
|
bool handleSecretBroadcast(PlayerPtr player, StringView broadcast);
|
||||||
|
|
||||||
List<ChatAction> pullPendingChatActions();
|
List<ChatAction> pullPendingChatActions();
|
||||||
|
|
||||||
WorldStructure const& centralStructure() const;
|
WorldStructure const& centralStructure() const;
|
||||||
|
Loading…
Reference in New Issue
Block a user