mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
With new binaries in place, master moves everything onto them while the server keeps running (the dashboard's Live update, /liveupdate or SIGUSR2 to master): - database migrations of the new build first; a failure stops there - UGC finishes the jobs it is running (queued rows stay pending), auth restarts, chat hands its teams to master for the next chat server; master starts the new processes and retries ones that don't come back - once the new chat server is up (CHAT_SERVER_READY) every world connects at once and sends its players again (LoginSessionNotify resync, no login logged) - every world instance is replaced with an instance migration: public worlds and private ones (same password) at once, properties after the old instance saved and froze the property (MIGRATE_PREPARE: no building, claiming or saving there any more), activity zones and character select once their players left or after a wait; empty instances just stop, zones in prestart_worlds get a new one first - the dashboard restarts last and picks the status up again Players land where they stood (position carried in CarriedPlayerState, also on properties and Moon Base). Draining instances get no new players (InstanceMigration::AcceptsNewPlayers) and show as "Moving players" in the world list. The order lives in LiveUpdateMachine.h without master state and is unit tested; master's glue is LiveUpdateCoordinator. Master itself is not replaced. Message IDs are appended only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
323 lines
10 KiB
C++
323 lines
10 KiB
C++
#pragma once
|
|
|
|
#include "ePropertyPrivacyOption.h"
|
|
#include <chrono>
|
|
#include <map>
|
|
#include <set>
|
|
#include "Entity.h"
|
|
#include "Component.h"
|
|
#include "eReplicaComponentType.h"
|
|
#include "LDFFormat.h"
|
|
|
|
class Item;
|
|
|
|
namespace GameMessages {
|
|
struct DownloadPropertyData;
|
|
}
|
|
|
|
/**
|
|
* Main component that handles interactions with a property, generally the plaques you see on properties.
|
|
*/
|
|
class PropertyManagementComponent final : public Component {
|
|
public:
|
|
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::PROPERTY_MANAGEMENT;
|
|
PropertyManagementComponent(Entity* parent, const int32_t componentID);
|
|
~PropertyManagementComponent() override;
|
|
static PropertyManagementComponent* Instance();
|
|
|
|
/**
|
|
* Whether the player can build on this property: its owner, or with property_bff_build a best friend of the owner
|
|
* while the owner is building (and, once in build mode, until they leave it)
|
|
*/
|
|
bool CanBuild(const Entity& player) const;
|
|
|
|
// A player finished loading into this world: looks up whether they are a best friend of the owner
|
|
void OnPlayerLoaded(Entity& player);
|
|
|
|
// A player left this world: ends their building and updates who else can build
|
|
void OnPlayerRemoved(Entity& player);
|
|
|
|
// Tells every player whose right to build changed (CanBuild) and ends building for those who lost it
|
|
void UpdateBuildRights();
|
|
|
|
/**
|
|
* Event handler for when an entity requests information about this property, will send back whether it's owned, etc.
|
|
* @param originator the entity that triggered the event
|
|
* @param sysAddr the address to send game message responses to
|
|
* @param author optional explicit ID for the property, if not set defaults to the originator
|
|
*/
|
|
void OnQueryPropertyData(Entity* originator, const SystemAddress& sysAddr, LWOOBJID author = LWOOBJID_EMPTY);
|
|
|
|
/**
|
|
* Handles an OnUse event, telling the client who owns this property, etc.
|
|
* @param originator the entity that triggered the event
|
|
*/
|
|
void OnUse(Entity* originator) override;
|
|
|
|
/**
|
|
* Sets the owner of this property
|
|
* @param value the owner to set
|
|
*/
|
|
void SetOwnerId(LWOOBJID value);
|
|
|
|
/**
|
|
* Returns the ID of the owner of this property
|
|
* @return the ID of the owner of this property
|
|
*/
|
|
LWOOBJID GetOwnerId() const;
|
|
|
|
/**
|
|
* Returns the owner of this property
|
|
* @return the owner of this property
|
|
*/
|
|
Entity* GetOwner() const;
|
|
|
|
/**
|
|
* sets the owner of this property
|
|
* @param value the owner to set
|
|
*/
|
|
void SetOwner(Entity* value);
|
|
|
|
/**
|
|
* Returns the paths that this property has
|
|
* @return the paths that this property has
|
|
*/
|
|
std::vector<NiPoint3> GetPaths() const;
|
|
|
|
/**
|
|
* Returns the privacy options for this property
|
|
* @return the privacy options for this property
|
|
*/
|
|
PropertyPrivacyOption GetPrivacyOption() const;
|
|
|
|
/**
|
|
* Updates the privacy option for this property
|
|
* @param value the privacy option to set
|
|
*/
|
|
void SetPrivacyOption(PropertyPrivacyOption value);
|
|
|
|
/**
|
|
* Updates information of this property, saving it to the database
|
|
* @param name the name to set for the property
|
|
* @param description the description to set for the property
|
|
*/
|
|
void UpdatePropertyDetails(std::string name, std::string description);
|
|
|
|
/**
|
|
* Makes this property owned by the passed player ID, storing it in the database
|
|
* @param playerId the ID of the entity that claimed the property
|
|
*
|
|
* @return If the claim is successful return true.
|
|
*/
|
|
bool Claim(LWOOBJID playerId);
|
|
|
|
/**
|
|
* Event triggered when a player who can build starts building. The first one to start (the owner) makes the property
|
|
* private, pauses the models and sends away the players who can't build.
|
|
*/
|
|
void OnStartBuilding(Entity& builder);
|
|
|
|
/**
|
|
* Event triggered when a builder finished building. When the last one finishes the property is re-applied for
|
|
* moderation, gets its privacy back and the models run again.
|
|
*/
|
|
void OnFinishBuilding(const Entity& builder);
|
|
|
|
/**
|
|
* Places a model from the builder's inventory on the property
|
|
* @param builder the player placing the model
|
|
* @param id the ID of the model item to place
|
|
* @param position the position to place the model on
|
|
* @param rotation the rotation to place the model on
|
|
*/
|
|
void UpdateModelPosition(Entity& builder, LWOOBJID id, NiPoint3 position, NiQuaternion rotation);
|
|
|
|
/**
|
|
* Takes a model off the property, into the inventory of the player who placed it
|
|
* @param builder the player taking the model off
|
|
* @param id the ID of the model to delete
|
|
* @param deleteReason the reason of the deletion, e.g. picked up or destroyed (in case of UGC)
|
|
*/
|
|
void DeleteModel(Entity& builder, LWOOBJID id, int deleteReason);
|
|
|
|
/**
|
|
* Spawns a model on the property and records it in the property's models (not yet saved)
|
|
* @param lot the model object's LOT (14 for a brick built model)
|
|
* @param modelId the model's id in properties_contents (its UGID)
|
|
* @param config extra config for the model object
|
|
* @param placedBy the player who placed it
|
|
*/
|
|
Entity* SpawnModel(LOT lot, LWOOBJID modelId, const NiPoint3& position, const NiQuaternion& rotation, const LwoNameValue& config, LWOOBJID placedBy);
|
|
|
|
/**
|
|
* Places a model item of the builder's on the property, uses the item up and saves the property
|
|
* @return the placed model's id, or LWOOBJID_EMPTY if it could not be placed
|
|
*/
|
|
LWOOBJID PlaceModelFromItem(const Entity& builder, Item& item, const NiPoint3& position, const NiQuaternion& rotation);
|
|
|
|
// The player who placed a model (by its id in properties_contents); the owner for models placed before this was kept
|
|
LWOOBJID GetPlacedBy(LWOOBJID modelId) const;
|
|
|
|
// GetModelsOnProperty with every model on the property
|
|
void SendModelsOnProperty() const;
|
|
|
|
/**
|
|
* Updates whether or not this property is approved by a moderator
|
|
* @param value true if the property should be approved, false otherwise
|
|
*/
|
|
void UpdateApprovedStatus(bool value, const std::string& rejectionReason = "");
|
|
|
|
// A moderator decided on this property from the dashboard (already saved): keep this world's copy in step
|
|
void ApplyModeration(bool approved, const std::string& reason);
|
|
|
|
/**
|
|
* Loads all the models on this property from the database
|
|
*/
|
|
void Load();
|
|
|
|
/**
|
|
* Saves all the models from this property to the database
|
|
*/
|
|
void Save();
|
|
|
|
/**
|
|
* Adds a model to the cache of models
|
|
* @param modelId the ID of the model
|
|
* @param spawnerId the ID of the object that spawned the model
|
|
*/
|
|
void AddModel(LWOOBJID modelId, LWOOBJID spawnerId);
|
|
|
|
/**
|
|
* Returns all the models on this property, indexed by property ID, containing their spawn objects
|
|
* @return all the models on this proeprty
|
|
*/
|
|
const std::map<LWOOBJID, LWOOBJID>& GetModels() const;
|
|
|
|
LWOCLONEID GetCloneId() { return clone_Id; };
|
|
|
|
LWOOBJID GetId() const noexcept { return propertyId; }
|
|
|
|
// Reputation visitors just gave (PropertyReputation.h; the database is updated there), so property data shows it
|
|
void AddReputation(uint32_t points) { reputation += points; }
|
|
uint32_t GetReputation() const noexcept { return reputation; }
|
|
|
|
|
|
void OnChatMessageReceived(const std::string& sMessage) const;
|
|
|
|
/**
|
|
* Live updates (docs/LiveUpdate.md): a new instance of this property is about to load it from the database. Takes
|
|
* everyone out of build mode, saves, and from then on nobody can build or claim it here and it is never saved again,
|
|
* so the new instance's saves can't be overwritten by this one.
|
|
*/
|
|
void FreezeForHandOff();
|
|
|
|
// The hand-off was called off before anyone went to the new instance: building and saving work again
|
|
void Unfreeze();
|
|
|
|
bool IsFrozen() const noexcept { return frozen; }
|
|
|
|
// Players in build mode here now
|
|
size_t GetBuilderCount() const noexcept { return builders.size(); }
|
|
private:
|
|
// Sends the property's data to one player; a player who can build is told they own it, which is the client's only
|
|
// check before editing (the owner's name stays the owner's)
|
|
void SendPropertyData(const Entity& player, const GameMessages::DownloadPropertyData& message);
|
|
|
|
// Whether the player is a best friend of the owner (looked up the first time)
|
|
bool IsBestFriend(LWOOBJID player) const;
|
|
|
|
// OnFinishBuilding without updating who can build; false if they weren't building
|
|
bool EndBuilding(const Entity& builder);
|
|
|
|
/**
|
|
* This
|
|
*/
|
|
static PropertyManagementComponent* instance;
|
|
|
|
// Handed off to a new instance for a live update (FreezeForHandOff)
|
|
bool frozen = false;
|
|
|
|
/**
|
|
* The ID of the owner of this property
|
|
*/
|
|
LWOOBJID owner = LWOOBJID_EMPTY;
|
|
|
|
/**
|
|
* The LOT of this console
|
|
*/
|
|
uint32_t templateId = 0;
|
|
|
|
/**
|
|
* The unique ID for this property, if it's owned
|
|
*/
|
|
LWOOBJID propertyId = LWOOBJID_EMPTY;
|
|
|
|
/**
|
|
* The time since this property was claimed
|
|
*/
|
|
uint64_t claimedTime = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
|
|
|
/**
|
|
* The models that are placed on this property
|
|
*/
|
|
std::map<LWOOBJID /* ObjectID */, LWOOBJID /* SpawnerID */> models = {};
|
|
|
|
/**
|
|
* The name of this property
|
|
*/
|
|
std::string propertyName = "";
|
|
|
|
/**
|
|
* The clone ID of this property
|
|
*/
|
|
LWOCLONEID clone_Id = 0;
|
|
|
|
/**
|
|
* Whether a moderator was requested
|
|
*/
|
|
bool moderatorRequested = false;
|
|
|
|
/**
|
|
* The rejection reason for the property
|
|
*/
|
|
std::string rejectionReason = "";
|
|
|
|
/**
|
|
* The description of this property
|
|
*/
|
|
std::string propertyDescription = "";
|
|
|
|
/**
|
|
* The reputation of this property
|
|
*/
|
|
uint32_t reputation = 0;
|
|
|
|
/**
|
|
* The last time this property was updated
|
|
*/
|
|
uint32_t LastUpdatedTime = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
|
|
|
/**
|
|
* Determines which players may visit this property
|
|
*/
|
|
PropertyPrivacyOption privacyOption = PropertyPrivacyOption::Private;
|
|
|
|
/**
|
|
* The privacy setting before it was changed, saved to set back after a player finishes building
|
|
*/
|
|
PropertyPrivacyOption originalPrivacyOption = PropertyPrivacyOption::Private;
|
|
|
|
// Whether each player on the property is a best friend of the owner, looked up once per player (again when the
|
|
// owner changes)
|
|
mutable std::map<LWOOBJID, bool> bestFriends;
|
|
|
|
// Whether each player on the property was last told they can build (see SendPropertyData)
|
|
std::map<LWOOBJID, bool> sentBuildRights;
|
|
|
|
// Players building right now
|
|
std::set<LWOOBJID> builders;
|
|
|
|
// Who placed each model, by its id in properties_contents (LWOOBJID_EMPTY: the owner)
|
|
std::map<LWOOBJID, LWOOBJID> placedBy;
|
|
};
|