Skip to content

Commit

Permalink
feat(skymp5-server): add NetImmerse.SetNodeTextureSet Papyrus native (s…
Browse files Browse the repository at this point in the history
  • Loading branch information
Pospelove authored Mar 31, 2024
1 parent e4a73a3 commit 2a958e2
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 11 deletions.
20 changes: 20 additions & 0 deletions skymp5-client/src/services/services/remoteServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,27 @@ export class RemoteServer extends ClientListener {
refr,
!!msg.props['isHarvested'],
);

// TODO: move to a separate module
if (msg.props.setNodeTextureSet) {
const setNodeTextureSet = msg.props.setNodeTextureSet as Record<string, number>;
for (const key in setNodeTextureSet) {
const textureSetId = setNodeTextureSet[key];
const firstPerson = false;

const textureSet = this.sp.TextureSet.from(Game.getFormEx(textureSetId));
if (textureSet !== null) {
sp.NetImmerse.setNodeTextureSet(refr, key, textureSet, firstPerson);
this.logTrace(`Applied texture set ${textureSetId.toString(16)} to ${key}`);
} else {
this.logError(`Failed to apply texture set ${textureSetId.toString(16)} to ${key}`);
}
}
}

ModelApplyUtils.applyModelIsDisabled(refr, !!msg.props['disabled']);

// TODO: move to a separate module
const animation = msg.props.lastAnimation;
if (typeof animation === "string") {
const refrid = refr.getFormID();
Expand Down
22 changes: 21 additions & 1 deletion skymp5-server/cpp/server_guest_lib/MpChangeForms.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ nlohmann::json MpChangeForm::ToJson(const MpChangeForm& changeForm)
// res["lastAnimation"] = *changeForm.lastAnimation;
// }

if (changeForm.setNodeTextureSet.has_value()) {
res["setNodeTextureSet"] = *changeForm.setNodeTextureSet;
}

if (changeForm.displayName.has_value()) {
res["displayName"] = *changeForm.displayName;
}
Expand All @@ -109,7 +113,7 @@ MpChangeForm MpChangeForm::JsonToChangeForm(simdjson::dom::element& element)
spawnPointCellOrWorldDesc("spawnPoint_cellOrWorldDesc"),
spawnDelay("spawnDelay"), effects("effects"),
templateChain("templateChain"), lastAnimation("lastAnimation"),
displayName("displayName");
setNodeTextureSet("setNodeTextureSet"), displayName("displayName");

MpChangeForm res;
ReadEx(element, recType, &res.recType);
Expand Down Expand Up @@ -233,6 +237,22 @@ MpChangeForm MpChangeForm::JsonToChangeForm(simdjson::dom::element& element)
res.lastAnimation = tmp;
}

if (element.at_pointer(setNodeTextureSet.GetData()).error() ==
simdjson::error_code::SUCCESS) {
simdjson::dom::element data;
ReadEx(element, setNodeTextureSet, &data);

if (res.setNodeTextureSet == std::nullopt) {
res.setNodeTextureSet = std::map<std::string, std::string>();
}

for (auto [key, value] : data.get_object()) {
std::string keyStr = key.data();
std::string valueStr = value.get_string().value().data();
res.setNodeTextureSet->emplace(keyStr, valueStr);
}
}

if (element.at_pointer(displayName.GetData()).error() ==
simdjson::error_code::SUCCESS) {
const char* tmp;
Expand Down
7 changes: 6 additions & 1 deletion skymp5-server/cpp/server_guest_lib/MpChangeForms.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "NiPoint3.h"
#include "Quest.h"
#include <cstdint>
#include <map>
#include <optional>
#include <ostream>
#include <set>
Expand Down Expand Up @@ -103,6 +104,9 @@ class MpChangeFormREFR
// Used for PlayAnimation (object reference)
std::optional<std::string> lastAnimation;

// Used for SetNodeTextureSet (node, texture set desc)
std::optional<std::map<std::string, std::string>> setNodeTextureSet;

// Used for SetDisplayName (object reference)
std::optional<std::string> displayName;

Expand All @@ -121,7 +125,8 @@ class MpChangeFormREFR
baseContainerAdded, nextRelootDatetime, isDisabled, profileId, isDeleted,
count, isRaceMenuOpen, isDead, consoleCommandsAllowed, appearanceDump,
equipmentDump, actorValues.ToTuple(), spawnPoint, dynamicFields,
spawnDelay, learnedSpells, templateChain, lastAnimation, displayName);
spawnDelay, learnedSpells, templateChain, lastAnimation,
setNodeTextureSet, displayName);
}

static nlohmann::json ToJson(const MpChangeFormREFR& changeForm);
Expand Down
29 changes: 29 additions & 0 deletions skymp5-server/cpp/server_guest_lib/MpObjectReference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,16 @@ void MpObjectReference::VisitProperties(const PropertiesVisitor& visitor,
visitor("lastAnimation", lastAnimationAsJson.data());
}

if (ChangeForm().setNodeTextureSet.has_value()) {
// worse performance than building json string manually but proper escaping
nlohmann::json setNodeTextureSetAsJson;
for (auto& [key, value] : *ChangeForm().setNodeTextureSet) {
setNodeTextureSetAsJson[key] =
FormDesc::FromString(value).ToFormId(GetParent()->espmFiles);
}
visitor("setNodeTextureSet", setNodeTextureSetAsJson.dump().data());
}

if (ChangeForm().displayName.has_value()) {
std::string raw = *ChangeForm().displayName;
nlohmann::json j = raw;
Expand Down Expand Up @@ -924,6 +934,25 @@ void MpObjectReference::SetLastAnimation(const std::string& lastAnimation)
});
}

void MpObjectReference::SetNodeTextureSet(const std::string& node,
const espm::LookupResult& textureSet,
bool firstPerson)
{
EditChangeForm([&](MpChangeForm& changeForm) {
if (changeForm.setNodeTextureSet == std::nullopt) {
changeForm.setNodeTextureSet = std::map<std::string, std::string>();
}

uint32_t textureSetId = textureSet.ToGlobalId(textureSet.rec->GetId());

FormDesc textureSetFormDesc =
FormDesc::FromFormId(textureSetId, GetParent()->espmFiles);

changeForm.setNodeTextureSet->insert_or_assign(
node, textureSetFormDesc.ToString());
});
}

void MpObjectReference::SetDisplayName(const std::string& newName)
{
EditChangeForm(
Expand Down
3 changes: 3 additions & 0 deletions skymp5-server/cpp/server_guest_lib/MpObjectReference.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ class MpObjectReference
MpObjectReference* listener);

void SetLastAnimation(const std::string& lastAnimation);
void SetNodeTextureSet(const std::string& node,
const espm::LookupResult& textureSet,
bool firstPerson);
void SetDisplayName(const std::string& newName);

const std::set<MpObjectReference*>& GetListeners() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,27 @@ VarValue PapyrusNetImmerse::SetNodeTextureSet(

std::ignore = firstPerson;

// for (auto listener : selfRefr->GetListeners()) {
// auto targetRefr = dynamic_cast<MpActor*>(listener);
// if (targetRefr) {
// SpSnippet(GetName(), funcName, serializedArgs.data(),
// selfRefr->GetFormId())
// .Execute(targetRefr);
// }
// }
if (!ref) {
throw std::runtime_error(
"PapyrusNetImmerse::SetNodeTextureSet - ref is nullptr");
}

// TODO
if (!tSet.rec) {
throw std::runtime_error(
"PapyrusNetImmerse::SetNodeTextureSet - tSet.rec is nullptr");
}

ref->SetNodeTextureSet(node, tSet, firstPerson);

auto funcName = "SetNodeTextureSet";
auto serializedArgs = SpSnippetFunctionGen::SerializeArguments(arguments);
for (auto listener : ref->GetListeners()) {
auto targetRefr = dynamic_cast<MpActor*>(listener);
if (targetRefr) {
SpSnippet(GetName(), funcName, serializedArgs.data())
.Execute(targetRefr);
}
}

return VarValue::None();
}
Expand Down

0 comments on commit 2a958e2

Please sign in to comment.