mirror of
https://github.com/ACEmulator/ACE
synced 2026-08-17 12:26:06 -04:00
* typo fix
* WorldObject Position/Cache cleanup
The positionCache (formerly named Positions) should only be referenced by the Get/Set/Remove functions.
Furthermore, on save, we make sure that the positions in the biota have the latest up to date values from the cache.
We must do this because we don't wrap Positions like we do attributes/skills/vitals.
* ACE.DatLoader BinaryReaderExtensiosn cosmetic
* WorldObject Obsolete Model Properties removed
* Remove Player.SetCharacterPosition()
* Important summary regarding setting positions
/// !!! VERY IMPORTANT NOTE REGARDING SetPosition !!!<para />
/// Position objects are reference types. Lets say you want to create a new object and give it the location of a player,
/// If you do LandscapeItem.SetPosition(PositionType.Location, Player.Location), you've now set the Location position
/// for both the player and the LandscapeItem to the same exact object. Modifying one will affect the other.<para />
/// The proper way to would be: LandscapeItem.SetPosition(PositionType.Location, (Position)Player.Location.Clone())<para />
/// Any time you want to set a position of a different PositionType, or, positions between WorldObjects, you should use the above Clone method.
* Removed unecessary virtual on some properties
74 lines
4 KiB
C#
74 lines
4 KiB
C#
using System;
|
|
using System.Threading;
|
|
|
|
using ACE.Database;
|
|
using ACE.Database.Models.Shard;
|
|
|
|
namespace ACE.Server.WorldObjects
|
|
{
|
|
partial class WorldObject
|
|
{
|
|
private readonly bool biotaOriginatedFromDatabase;
|
|
|
|
public DateTime LastRequestedDatabaseSave { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// This variable is set to true when a change is made, and set to false before a save is requested.<para />
|
|
/// The primary use for this is to trigger save on add/modify/remove of properties.
|
|
/// </summary>
|
|
public bool ChangesDetected { get; set; }
|
|
|
|
/// <summary>
|
|
/// Best practice says you should use this lock any time you read/write the Biota.<para />
|
|
/// However, it's only a requirement to do this for properties/collections that will be modified after the initial biota has been created.<para />
|
|
/// There are several properties/collections of the biota that are simply duplicates of the original weenie and are never changed. You wouldn't need to use this lock to read those collections.<para />
|
|
/// <para />
|
|
/// For absolute maximum performance, if you're willing to assume (and risk) the following:<para />
|
|
/// - that the biota in the database will not be modified (in a way that adds or removes properties) outside of ACE while ACE is running with a reference to that biota<para />
|
|
/// - that the biota will only be read/modified by a single thread in ACE<para />
|
|
/// You can remove the lock usage for any Get/GetAll Property functions. You would simply use it for Set/Remove Property functions because each of these could end up adding/removing to the collections.<para />
|
|
/// The critical thing is that the collections are not added to or removed from while Entity Framework is iterating over them.<para />
|
|
/// Mag-nus 2018-08-19
|
|
/// </summary>
|
|
public readonly ReaderWriterLockSlim BiotaDatabaseLock = new ReaderWriterLockSlim();
|
|
|
|
/// <summary>
|
|
/// This will set the LastRequestedDatabaseSave to UtcNow and ChangesDetected to false.<para />
|
|
/// If enqueueSave is set to true, DatabaseManager.Shard.SaveBiota() will be called for the biota.<para />
|
|
/// Set enqueueSave to false if you want to perform all the normal routines for a save but not the actual save. This is useful if you're going to collect biotas in bulk for bulk saving.
|
|
/// </summary>
|
|
public virtual void SaveBiotaToDatabase(bool enqueueSave = true)
|
|
{
|
|
// Make sure all of our positions in the biota are up to date with our current cached values.
|
|
foreach (var kvp in positionCache)
|
|
Biota.SetPosition(kvp.Key, kvp.Value, BiotaDatabaseLock, out _);
|
|
|
|
LastRequestedDatabaseSave = DateTime.UtcNow;
|
|
ChangesDetected = false;
|
|
|
|
if (enqueueSave)
|
|
DatabaseManager.Shard.SaveBiota(Biota, BiotaDatabaseLock, null);
|
|
}
|
|
|
|
/// <summary>
|
|
/// This will set the LastRequestedDatabaseSave to MinValue and ChangesDetected to true.<para />
|
|
/// If enqueueRemove is set to true, DatabaseManager.Shard.RemoveBiota() will be called for the biota.<para />
|
|
/// Set enqueueRemove to false if you want to perform all the normal routines for a remove but not the actual removal. This is useful if you're going to collect biotas in bulk for bulk removing.
|
|
/// </summary>
|
|
public void RemoveBiotaFromDatabase(bool enqueueRemove = true)
|
|
{
|
|
// If this entity doesn't exist in the database, let's not queue up work unnecessary database work.
|
|
if (!biotaOriginatedFromDatabase && LastRequestedDatabaseSave == DateTime.MinValue)
|
|
{
|
|
ChangesDetected = true;
|
|
return;
|
|
}
|
|
|
|
LastRequestedDatabaseSave = DateTime.MinValue;
|
|
ChangesDetected = true;
|
|
|
|
if (enqueueRemove)
|
|
DatabaseManager.Shard.RemoveBiota(Biota, BiotaDatabaseLock, null);
|
|
}
|
|
}
|
|
}
|