Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Pospelove committed Dec 15, 2024
1 parent 31eed12 commit c03a2ac
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 115 deletions.
14 changes: 8 additions & 6 deletions skymp5-server/cpp/server_guest_lib/ActionListener.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include <spdlog/spdlog.h>
#include <unordered_set>

#include "HostStartMessage.h"
#include "HostStopMessage.h"
#include "UpdateEquipmentMessage.h"

MpActor* ActionListener::SendToNeighbours(
Expand Down Expand Up @@ -614,9 +616,9 @@ void ActionListener::OnHostAttempt(const RawMessageData& rawMsgData,
longFormId += 0x100000000;
}

Networking::SendFormatted(&partOne.GetSendTarget(), rawMsgData.userId,
R"({ "type": "hostStart", "target": %llu })",
longFormId);
HostStartMessage message;
message.target = longFormId;
partOne.GetSendTarget()->Send(rawMsgData.userId, message, true);

// Otherwise, health percentage would remain unsynced until someone hits
// npc
Expand All @@ -642,9 +644,9 @@ void ActionListener::OnHostAttempt(const RawMessageData& rawMsgData,
auto prevHosterUser = partOne.serverState.UserByActor(prevHosterActor);
if (prevHosterUser != Networking::InvalidUserId &&
prevHosterUser != rawMsgData.userId) {
Networking::SendFormatted(&partOne.GetSendTarget(), prevHosterUser,
R"({ "type": "hostStop", "target": %llu })",
longFormId);
HostStopMessage message;
message.target = longFormId;
partOne.GetSendTarget()->Send(prevHosterUser, message, true);
}
}
}
Expand Down
12 changes: 4 additions & 8 deletions skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <optional>

#include "OpenContainerMessage.h"
#include "SetInventoryMessage.h"
#include "TeleportMessage.h"

#include "script_classes/PapyrusObjectReference.h" // kOriginalNameExpression
Expand Down Expand Up @@ -1761,14 +1762,9 @@ void MpObjectReference::SendInventoryUpdate()
constexpr int kChannelSetInventory = 0;
auto actor = AsActor();
if (actor) {
std::string msg;
msg += Networking::MinPacketId;
msg += nlohmann::json{
{ "inventory", actor->GetInventory().ToJson() },
{ "type", "setInventory" }
}.dump();
actor->SendToUserDeferred(msg.data(), msg.size(), true,
kChannelSetInventory, true);
SetInventoryMessage message;
message.inventory = actor->GetInventory();
actor->SendToUserDeferred(message, true, kChannelSetInventory, true);
}
}

Expand Down
132 changes: 79 additions & 53 deletions skymp5-server/cpp/server_guest_lib/PartOne.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,53 @@
#include <type_traits>
#include <vector>

#include "CreateActorMessage.h"
#include "CustomPacketMessage.h"
#include "HostStopMessage.h"
#include "SetRaceMenuOpenMessage.h"

namespace {
MessageSerializer& GetMessageSerializerInstance()
{
static auto g_serializer =
MessageSerializerFactory::CreateMessageSerializer();
return *g_serializer;
}
}

PartOneSendTargetWrapper::PartOneSendTargetWrapper(
Networking::ISendTarget& underlyingSendTarget_)
: underlyingSendTarget(underlyingSendTarget_)
{
}

void PartOneSendTargetWrapper::Send(Networking::UserId targetUserId,
Networking::PacketData data, size_t length,
bool reliable)
{
return underlyingSendTarget.Send(targetUserId, data, length, reliable);
}

void PartOneSendTargetWrapper::Send(Networking::UserId targetUserId,
const IMessageBase& message, bool reliable)
{
SLNet::BitStream stream;

GetMessageSerializerInstance().Serialize(message, stream);

Send(targetUserId,
reinterpret_cast<Networking::PacketData>(stream.GetData()),
stream.GetNumberOfBytesUsed(), reliable);
}

class FakeSendTarget : public Networking::ISendTarget
{
public:
void Send(Networking::UserId targetUserId, Networking::PacketData data,
size_t length, bool reliable) override
{
static auto g_serializer =
MessageSerializerFactory::CreateMessageSerializer();
auto deserializeResult = g_serializer->Deserialize(data, length);
auto deserializeResult =
GetMessageSerializerInstance().Deserialize(data, length);
nlohmann::json j;
if (deserializeResult) {
deserializeResult->message->WriteJson(j);
Expand Down Expand Up @@ -52,7 +90,7 @@ struct PartOne::Impl

std::shared_ptr<spdlog::logger> logger;

Networking::ISendTarget* sendTarget = nullptr;
std::unique_ptr<PartOneSendTargetWrapper> sendTarget;
std::unique_ptr<IDamageFormula> damageFormula{};
FakeSendTarget fakeSendTarget;

Expand Down Expand Up @@ -83,7 +121,11 @@ PartOne::~PartOne()

void PartOne::SetSendTarget(Networking::ISendTarget* sendTarget)
{
pImpl->sendTarget = sendTarget ? sendTarget : &pImpl->fakeSendTarget;
Networking::ISendTarget* underlyingSendTargetToSet =
sendTarget ? sendTarget : &pImpl->fakeSendTarget;

pImpl->sendTarget.reset(
new PartOneSendTargetWrapper(*underlyingSendTargetToSet));
}

void PartOne::SetDamageFormula(std::unique_ptr<IDamageFormula> dmgFormula)
Expand Down Expand Up @@ -218,28 +260,31 @@ void PartOne::SetRaceMenuOpen(uint32_t actorFormId, bool open)
{
auto& actor = worldState.GetFormAt<MpActor>(actorFormId);

if (actor.IsRaceMenuOpen() == open)
if (actor.IsRaceMenuOpen() == open) {
return;
}

actor.SetRaceMenuOpen(open);

auto userId = serverState.UserByActor(&actor);
if (userId == Networking::InvalidUserId) {
throw std::runtime_error(fmt::format(
"Actor with id {:#x} is not attached to any of users", actorFormId));
spdlog::warn(
"PartOne::SetRaceMenuOpen {:x} - actor is not attached to any of users",
actorFormId);
return;
}

Networking::SendFormatted(pImpl->sendTarget, userId,
R"({"type": "setRaceMenuOpen", "open": %s})",
open ? "true" : "false");
SetRaceMenuOpenMessage message;
message.open = open;
pImpl->sendTarget->Send(userId, message, true);
}

void PartOne::SendCustomPacket(Networking::UserId userId,
const std::string& jContent)
{
Networking::SendFormatted(pImpl->sendTarget, userId,
R"({"type": "customPacket", "content":%s})",
jContent.data());
CustomPacketMessage message;
message.contentJsonDump = jContent;
pImpl->sendTarget->Send(userId, message, true);
}

std::string PartOne::GetActorName(uint32_t actorFormId)
Expand Down Expand Up @@ -415,7 +460,7 @@ void PartOne::HandlePacket(void* partOneInstance, Networking::UserId userId,
}
}

Networking::ISendTarget& PartOne::GetSendTarget() const
PartOneSendTargetWrapper& PartOne::GetSendTarget() const
{
if (!pImpl->sendTarget) {
throw std::runtime_error("No send target found");
Expand Down Expand Up @@ -532,16 +577,13 @@ void PartOne::SendHostStop(Networking::UserId badHosterUserId,
longFormId += 0x100000000;
}

Networking::SendFormatted(&GetSendTarget(), badHosterUserId,
R"({ "type": "hostStop", "target": %llu })",
longFormId);
HostStopMessage message;
message.target = longFormId;
GetSendTarget()->Send(badHosterUserId, message, true);
}

FormCallbacks PartOne::CreateFormCallbacks()
{
static auto g_serializer =
MessageSerializerFactory::CreateMessageSerializer();

auto st = &serverState;

FormCallbacks::SubscribeCallback
Expand All @@ -557,12 +599,14 @@ FormCallbacks PartOne::CreateFormCallbacks()
FormCallbacks::SendToUserFn sendToUser =
[this, st](MpActor* actor, const IMessageBase& message, bool reliable) {
SLNet::BitStream stream;
g_serializer->Serialize(message, stream);
GetMessageSerializerInstance().Serialize(message, stream);

bool isOffline = st->UserByActor(actor) == Networking::InvalidUserId;

// Only send to hoster if actor is offline (no active user)
// This fixes December 2023 Update "invisible chat" bug
// TODO: make send-to-hoster mechanism explicit, instead of implicitly
// redirecting packets
if (isOffline) {
auto hosterIterator = worldState.hosters.find(actor->GetFormId());
if (hosterIterator != worldState.hosters.end()) {
Expand Down Expand Up @@ -673,58 +717,40 @@ void PartOne::Init()

MpActor* emitterAsActor = emitter->AsActor();

std::string jEquipment, jAppearance, jAnimation;
CreateActorMessage message;

std::string jAnimation;

const char *appearancePrefix = "", *appearance = "";
if (emitterAsActor) {
jAppearance = emitterAsActor->GetAppearanceAsJson();
if (!jAppearance.empty()) {
appearancePrefix = R"(, "appearance": )";
appearance = jAppearance.data();
}
auto appearance = emitterAsActor->GetAppearance();
message.appearance = appearance
? std::optional<Appearance>(*appearance)
: std::optional<Appearance>(std::nullopt);
}

const char *equipmentPrefix = "", *equipment = "";
if (emitterAsActor) {
jEquipment = emitterAsActor->GetEquipmentAsJson();
if (!jEquipment.empty()) {
equipmentPrefix = R"(, "equipment": )";
equipment = jEquipment.data();
}
message.equipment = emitterAsActor->GetEquipment();
}

const char *animationPrefix = "", *animation = "";
if (emitterAsActor) {
jAnimation = emitterAsActor->GetLastAnimEventAsJson();
if (!jAnimation.empty()) {
animationPrefix = R"(, "animation": )";
animation = jAnimation.data();
}
message.animation = emitterAsActor->GetLastAnimEvent();
}

const char* refrIdPrefix = "";
char refrId[32] = { 0 };
refrIdPrefix = R"(, "refrId": )";

long long unsigned int longFormId = emitter->GetFormId();
uint64_t longFormId = emitter->GetFormId();
if (emitterAsActor && longFormId < 0xff000000) {
longFormId += 0x100000000;
}
sprintf(refrId, "%llu", longFormId);
message.refrId = longFormId;

const char* baseIdPrefix = "";
char baseId[32] = { 0 };
if (emitter->GetBaseId() != 0x00000000 &&
emitter->GetBaseId() != 0x00000007) {
baseIdPrefix = R"(, "baseId": )";
sprintf(baseId, "%u", emitter->GetBaseId());
message.baseId = emitter->GetBaseId();
}

const char* isDeadPrefix = "";
const char* isDead = "";
if (emitterAsActor && emitterAsActor->IsDead()) {
isDeadPrefix = R"(, "isDead": )";
isDead = "\"true\"";
message.= true;
}

const bool isOwner = emitter == listener;
Expand Down
18 changes: 17 additions & 1 deletion skymp5-server/cpp/server_guest_lib/PartOne.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ class ActionListener;

struct HitData;

class PartOneSendTargetWrapper : public Networking::ISendTarget
{
public:
explicit PartOneSendTargetWrapper(
Networking::ISendTarget& underlyingSendTarget_);

void Send(Networking::UserId targetUserId, Networking::PacketData data,
size_t length, bool reliable) override;

void Send(Networking::UserId targetUserId, const IMessageBase& message,
bool reliable);

private:
Networking::ISendTarget& underlyingSendTarget;
};

class PartOne
{
public:
Expand Down Expand Up @@ -82,7 +98,7 @@ class PartOne
ServerState serverState;
AnimationSystem animationSystem;

Networking::ISendTarget& GetSendTarget() const;
PartOneSendTargetWrapper& GetSendTarget() const;

float CalculateDamage(const MpActor& aggressor, const MpActor& target,
const HitData& hitData) const;
Expand Down
30 changes: 18 additions & 12 deletions skymp5-server/cpp/server_guest_lib/SpSnippet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@

#include "MpActor.h"
#include "NetworkingInterface.h" // Format
#include "SpSnippetMessage.h"

SpSnippet::SpSnippet(const char* cl_, const char* func_, const char* args_,
uint32_t selfId_)
SpSnippet::SpSnippet(
const char* cl_, const char* func_,

const std::vector<std::optional<
std::variant<bool, double, std::string, SpSnippetObjectArgument>>>& args_,
uint32_t selfId_)
: cl(cl_)
, func(func_)
, args(args_)
Expand Down Expand Up @@ -33,16 +38,17 @@ Viet::Promise<VarValue> SpSnippet::Execute(MpActor* actor, SpSnippetMode mode)
auto targetSelfId =
(selfId < 0xff000000 || selfId != actor->GetFormId()) ? selfId : 0x14;

Networking::Format(
[&](Networking::PacketData data, size_t len) {
// The only reason for deferred here is that it still supports raw binary
// data send
// TODO: change to SendToUser
constexpr int kChannelSpSnippet = 1;
actor->SendToUserDeferred(data, len, true, kChannelSpSnippet, false);
},
R"({"type": "spSnippet", "class": "%s", "function": "%s", "arguments": %s, "selfId": %u, "snippetIdx": %u})",
cl, func, args, targetSelfId, snippetIdx);
SpSnippetMessage message;
message.class_ = cl;
message.function = func;
message.args = args;
message.selfId = targetSelfId;
message.snippetIdx = static_cast<int64_t>(snippetIdx);

// TODO: change to SendToUser, probably was deferred only for ability to send
// text packets
constexpr int kChannelSpSnippet = 1;
actor->SendToUserDeferred(message, true, kChannelSpSnippet, false);

return promise;
}
9 changes: 7 additions & 2 deletions skymp5-server/cpp/server_guest_lib/SpSnippet.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,17 @@ enum class SpSnippetMode
class SpSnippet
{
public:
SpSnippet(const char* cl_, const char* func_, const char* args_,
SpSnippet(const char* cl_, const char* func_,
const std::vector<std::optional<std::variant<
bool, double, std::string, SpSnippetObjectArgument>>>& args_,
uint32_t selfId_ = 0);

Viet::Promise<VarValue> Execute(MpActor* actor, SpSnippetMode mode);

private:
const char *const cl, *const func, *const args;
const char* const cl;
const char* const func;
const std::vector<std::optional<
std::variant<bool, double, std::string, SpSnippetObjectArgument>>>& args;
const uint32_t selfId;
};
Loading

0 comments on commit c03a2ac

Please sign in to comment.