mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-11-14 07:47:13 +00:00
feat(character): the save's edit attribute is 1 for accounts at editor_gm_level
The client takes a non-zero edit as the editor being enabled. A character whose account GM level is at least editor_gm_level (worldconfig.ini, default 9) is saved with edit="1"; everyone else keeps 0. A civilian never gets it, whatever the setting. The setting is in the dashboard's settings catalog. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
@@ -159,6 +159,8 @@ namespace {
|
||||
c.Add(Int(SHARED, "version_current", "Version: current", "", "10", 0, 65535));
|
||||
c.Add(Int(SHARED, "version_minor", "Version: minor", "", "64", 0, 65535));
|
||||
|
||||
c.Add(Int(WORLD, "editor_gm_level", "Client editor from GM level", "Characters of accounts at or above this GM level are saved with the client's editor enabled (edit=\"1\" in the character data); everyone else with 0. Used the next time a character is saved.", "9", 1, 9));
|
||||
|
||||
c.AddSection("Logging and crashes");
|
||||
c.Add(Bool(SHARED, "log_to_console", "Log to the console", "Also print log lines to the terminal.", true, true));
|
||||
c.Add(Bool(SHARED, "log_debug_statements", "Debug logging", "Extra log lines for developers.", false, true));
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "BitStream.h"
|
||||
#include "tinyxml2.h"
|
||||
#include "Game.h"
|
||||
#include "dConfig.h"
|
||||
#include "Logger.h"
|
||||
#include "GeneralUtils.h"
|
||||
#include "dServer.h"
|
||||
@@ -480,8 +481,12 @@ void CharacterComponent::WriteSaveData(tinyxml2::XMLDocument& doc) {
|
||||
// cm, the most coins the character can hold: always 9223372036854775807 on live, the client's own value without
|
||||
// it. Nothing here caps coins by it, and one that is already in the save is left as it is.
|
||||
if (!character->FindAttribute("cm")) character->SetAttribute("cm", std::numeric_limits<int64_t>::max());
|
||||
// edit, the editor level: the client takes anything but 0 as the editor being on
|
||||
character->SetAttribute("edit", m_EditorEnabled ? static_cast<uint32_t>(m_EditorLevel) : 0u);
|
||||
// edit, the editor level: the client takes anything but 0 as the editor being on. 1 for a character whose account
|
||||
// has the GM level of editor_gm_level (9 unless set), 0 for everyone else
|
||||
const auto* const parentUser = m_Character ? m_Character->GetParentUser() : nullptr;
|
||||
const auto accountLevel = parentUser ? parentUser->GetMaxGMLevel() : eGameMasterLevel::CIVILIAN;
|
||||
const auto editorGmLevel = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("editor_gm_level")).value_or(DEFAULT_EDITOR_GM_LEVEL);
|
||||
character->SetAttribute("edit", EditAttribute(accountLevel, editorGmLevel, m_EditorEnabled, m_EditorLevel));
|
||||
// mldt, when the property moderation notice was last shown: not kept here, 0 as on most live saves
|
||||
if (!character->FindAttribute("mldt")) character->SetAttribute("mldt", 0);
|
||||
// gid and gn, the guild (0 and empty without one)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef CHARACTERCOMPONENT_H
|
||||
#define CHARACTERCOMPONENT_H
|
||||
|
||||
#include "eGameMasterLevel.h"
|
||||
#include "dCommonVars.h"
|
||||
#include "RakNetTypes.h"
|
||||
#include "Character.h"
|
||||
@@ -477,6 +478,22 @@ private:
|
||||
*/
|
||||
bool m_EditorEnabled;
|
||||
|
||||
public:
|
||||
// editor_gm_level when the settings don't have it
|
||||
static constexpr uint32_t DEFAULT_EDITOR_GM_LEVEL = 9;
|
||||
|
||||
/**
|
||||
* The save's edit attribute (the client takes anything but 0 as the editor being on): 1 for an account whose GM
|
||||
* level is at least editorGmLevel, else the editor level when the editor flag is on, else 0
|
||||
*/
|
||||
static uint32_t EditAttribute(const eGameMasterLevel accountLevel, const uint32_t editorGmLevel, const bool editorEnabled, const eGameMasterLevel editorLevel) {
|
||||
// (a civilian never, whatever the setting)
|
||||
if (accountLevel != eGameMasterLevel::CIVILIAN && static_cast<uint32_t>(accountLevel) >= editorGmLevel) return 1;
|
||||
return editorEnabled ? static_cast<uint32_t>(editorLevel) : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* The level of the character in HF
|
||||
*/
|
||||
|
||||
@@ -118,6 +118,10 @@ save_lxfmls=0
|
||||
# 1: saving a brick by brick model uses up the bricks in it, as live did. 0: they go back to the backpack.
|
||||
bbb_consume_bricks=0
|
||||
|
||||
# Characters of accounts at or above this GM level are saved with the client's editor enabled (edit="1" in the
|
||||
# character data); everyone else with 0.
|
||||
editor_gm_level=9
|
||||
|
||||
# 1: logging out on a property and back in returns to that property. 0 (as live): to the last world before it.
|
||||
save_property_location=0
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "Character.h"
|
||||
#include "CharacterComponent.h"
|
||||
#include "Entity.h"
|
||||
#include "User.h"
|
||||
#include "dConfig.h"
|
||||
#include "GameMessages.h"
|
||||
#include "MissionComponent.h"
|
||||
#include "SkillComponent.h"
|
||||
@@ -163,6 +165,43 @@ TEST_F(CharacterSaveFieldsTests, LiveCharacterAttributesRoundTrip) {
|
||||
EXPECT_STREQ(saved->Attribute("gn"), "Builders");
|
||||
}
|
||||
|
||||
// edit: 1 for a character whose account has the GM level of editor_gm_level (9 unless set), 0 for everyone else
|
||||
TEST_F(CharacterSaveFieldsTests, EditAttributeFollowsTheAccountGmLevel) {
|
||||
using enum eGameMasterLevel;
|
||||
EXPECT_EQ(CharacterComponent::EditAttribute(OPERATOR, 9, false, OPERATOR), 1u);
|
||||
EXPECT_EQ(CharacterComponent::EditAttribute(DEVELOPER, 9, false, DEVELOPER), 0u);
|
||||
EXPECT_EQ(CharacterComponent::EditAttribute(CIVILIAN, 9, false, CIVILIAN), 0u);
|
||||
EXPECT_EQ(CharacterComponent::EditAttribute(DEVELOPER, 8, false, DEVELOPER), 1u);
|
||||
EXPECT_EQ(CharacterComponent::EditAttribute(JUNIOR_DEVELOPER, 8, false, JUNIOR_DEVELOPER), 0u);
|
||||
// A civilian never, whatever the setting
|
||||
EXPECT_EQ(CharacterComponent::EditAttribute(CIVILIAN, 0, false, CIVILIAN), 0u);
|
||||
// The editor flag still writes its level
|
||||
EXPECT_EQ(CharacterComponent::EditAttribute(DEVELOPER, 9, true, DEVELOPER), 8u);
|
||||
|
||||
const auto savedEdit = [this](const eGameMasterLevel accountLevel) {
|
||||
tinyxml2::XMLDocument doc;
|
||||
Parse(doc, R"(<obj v="1"><mf/><char ls="0" edit="0"/></obj>)");
|
||||
User user(UNASSIGNED_SYSTEM_ADDRESS, "editor", "key");
|
||||
user.SetMaxGMLevel(accountLevel);
|
||||
Character character(1, &user);
|
||||
Entity player(43, info);
|
||||
auto* const characterComponent = player.AddComponent<CharacterComponent>(-1, &character, UNASSIGNED_SYSTEM_ADDRESS);
|
||||
characterComponent->LoadFromSaveData(doc);
|
||||
characterComponent->WriteSaveData(doc);
|
||||
return std::string(doc.FirstChildElement("obj")->FirstChildElement("char")->Attribute("edit"));
|
||||
};
|
||||
// The default level, 9
|
||||
EXPECT_EQ(savedEdit(OPERATOR), "1");
|
||||
EXPECT_EQ(savedEdit(DEVELOPER), "0");
|
||||
EXPECT_EQ(savedEdit(CIVILIAN), "0");
|
||||
|
||||
// editor_gm_level from the settings
|
||||
Game::config->SetDatabaseValues({ { "editor_gm_level", "8" } }, {});
|
||||
EXPECT_EQ(savedEdit(DEVELOPER), "1");
|
||||
EXPECT_EQ(savedEdit(JUNIOR_DEVELOPER), "0");
|
||||
Game::config->SetDatabaseValues({}, {});
|
||||
}
|
||||
|
||||
// Saves from before they were written load as before and gain them with the values live had: the coins are not
|
||||
// touched and cm is the client's own "no limit".
|
||||
TEST_F(CharacterSaveFieldsTests, LiveCharacterAttributesMissingInOldSave) {
|
||||
|
||||
Reference in New Issue
Block a user