Core/Scripts: Save instance data in JSON format
Port From (https://github.com/TrinityCore/TrinityCore/commit/76be303351ae398b7f9e69e4c472cb5b05fce45e)
This commit is contained in:
@@ -116,9 +116,9 @@ namespace Game.Chat
|
||||
}
|
||||
|
||||
[Command("savedata", RBACPermissions.CommandInstanceSavedata)]
|
||||
static bool HandleInstanceSaveData(CommandHandler handler)
|
||||
static bool HandleInstanceSaveDataCommand(CommandHandler handler)
|
||||
{
|
||||
Player player = handler.GetSession().GetPlayer();
|
||||
/*Player player = handler.GetSession().GetPlayer();
|
||||
InstanceMap map = player.GetMap().ToInstanceMap();
|
||||
if (map == null)
|
||||
{
|
||||
@@ -132,7 +132,7 @@ namespace Game.Chat
|
||||
return false;
|
||||
}
|
||||
|
||||
map.GetInstanceScript().SaveToDB();
|
||||
map.GetInstanceScript().SaveToDB();*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -460,13 +460,13 @@ namespace Game.Maps
|
||||
_sharedData = sharedData;
|
||||
}
|
||||
|
||||
public void SetInstanceId(uint instanceId)
|
||||
public override void SetInstanceId(uint instanceId)
|
||||
{
|
||||
base.SetInstanceId(instanceId);
|
||||
_sharedData.InstanceId = instanceId;
|
||||
}
|
||||
|
||||
public InstanceLockData GetInstanceInitializationData() { return _sharedData; }
|
||||
public override InstanceLockData GetInstanceInitializationData() { return _sharedData; }
|
||||
|
||||
public SharedInstanceLockData GetSharedData() { return _sharedData; }
|
||||
}
|
||||
|
||||
@@ -44,17 +44,6 @@ namespace Game.Maps
|
||||
InstanceScenario scenario = instance.GetInstanceScenario();
|
||||
if (scenario != null)
|
||||
scenario.SaveToDB();
|
||||
|
||||
string data = GetSaveData();
|
||||
if (string.IsNullOrEmpty(data))
|
||||
return;
|
||||
|
||||
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.UPD_INSTANCE_DATA);
|
||||
stmt.AddValue(0, GetCompletedEncounterMask());
|
||||
stmt.AddValue(1, data);
|
||||
stmt.AddValue(2, _entranceId);
|
||||
stmt.AddValue(3, instance.GetInstanceId());
|
||||
DB.Characters.Execute(stmt);
|
||||
}
|
||||
|
||||
public virtual bool IsEncounterInProgress()
|
||||
@@ -104,9 +93,7 @@ namespace Game.Maps
|
||||
|
||||
public void SetHeaders(string dataHeaders)
|
||||
{
|
||||
foreach (char header in dataHeaders)
|
||||
if (char.IsLetter(header))
|
||||
headers.Add(header);
|
||||
headers = dataHeaders;
|
||||
}
|
||||
|
||||
public void LoadBossBoundaries(BossBoundaryEntry[] data)
|
||||
@@ -178,7 +165,7 @@ namespace Game.Maps
|
||||
for (int i = 0; i < MapConst.MaxDungeonEncountersPerBoss; ++i)
|
||||
bosses[bossId].DungeonEncounters[i] = CliDB.DungeonEncounterStorage.LookupByKey(dungeonEncounterIds[i]);
|
||||
}
|
||||
|
||||
|
||||
public virtual void UpdateDoorState(GameObject door)
|
||||
{
|
||||
var range = doors.LookupByKey(door.GetEntry());
|
||||
@@ -430,8 +417,8 @@ namespace Game.Maps
|
||||
|
||||
bossInfo.state = state;
|
||||
SaveToDB();
|
||||
if (state == EncounterState.Done && dungeonEncounter != null)
|
||||
instance.UpdateInstanceLock(dungeonEncounter, new(id, state));
|
||||
if (dungeonEncounter != null)
|
||||
instance.UpdateInstanceLock(new UpdateBossStateSaveDataEvent(dungeonEncounter, id, state));
|
||||
}
|
||||
|
||||
for (uint type = 0; type < (int)DoorType.Max; ++type)
|
||||
@@ -470,7 +457,7 @@ namespace Game.Maps
|
||||
UpdateSpawnGroups();
|
||||
}
|
||||
|
||||
public virtual void Load(string data)
|
||||
public void Load(string data)
|
||||
{
|
||||
if (string.IsNullOrEmpty(data))
|
||||
{
|
||||
@@ -480,12 +467,11 @@ namespace Game.Maps
|
||||
|
||||
OutLoadInstData(data);
|
||||
|
||||
var loadStream = new StringArguments(data);
|
||||
|
||||
if (ReadSaveDataHeaders(loadStream))
|
||||
InstanceScriptDataReader reader = new(this);
|
||||
if (reader.Load(data) == InstanceScriptDataReader.Result.Ok)
|
||||
{
|
||||
ReadSaveDataBossStates(loadStream);
|
||||
ReadSaveDataMore(loadStream);
|
||||
UpdateSpawnGroups();
|
||||
AfterDataLoad();
|
||||
}
|
||||
else
|
||||
OutLoadInstDataFail();
|
||||
@@ -493,84 +479,39 @@ namespace Game.Maps
|
||||
OutLoadInstDataComplete();
|
||||
}
|
||||
|
||||
bool ReadSaveDataHeaders(StringArguments data)
|
||||
{
|
||||
foreach (char header in headers)
|
||||
{
|
||||
char buff = data.NextChar();
|
||||
|
||||
if (header != buff)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReadSaveDataBossStates(StringArguments data)
|
||||
{
|
||||
foreach (var pair in bosses)
|
||||
{
|
||||
EncounterState buff = (EncounterState)data.NextUInt32();
|
||||
if (buff == EncounterState.InProgress || buff == EncounterState.Fail || buff == EncounterState.Special)
|
||||
buff = EncounterState.NotStarted;
|
||||
|
||||
if (buff < EncounterState.ToBeDecided)
|
||||
SetBossState(pair.Key, buff);
|
||||
}
|
||||
UpdateSpawnGroups();
|
||||
}
|
||||
|
||||
public virtual string GetSaveData()
|
||||
public string GetSaveData()
|
||||
{
|
||||
OutSaveInstData();
|
||||
|
||||
StringBuilder saveStream = new();
|
||||
InstanceScriptDataWriter writer = new(this);
|
||||
|
||||
WriteSaveDataHeaders(saveStream);
|
||||
WriteSaveDataBossStates(saveStream);
|
||||
WriteSaveDataMore(saveStream);
|
||||
writer.FillData();
|
||||
|
||||
OutSaveInstDataComplete();
|
||||
|
||||
return saveStream.ToString();
|
||||
return writer.GetString();
|
||||
}
|
||||
|
||||
public string UpdateSaveData(string oldData, UpdateSaveDataEvent saveEvent)
|
||||
public string UpdateBossStateSaveData(string oldData, UpdateBossStateSaveDataEvent saveEvent)
|
||||
{
|
||||
if (!instance.GetMapDifficulty().IsUsingEncounterLocks())
|
||||
return GetSaveData();
|
||||
|
||||
int position = (int)(headers.Count + saveEvent.BossId) * 2;
|
||||
StringBuilder newData = new(oldData);
|
||||
if (position >= oldData.Length)
|
||||
{
|
||||
// Initialize blank data
|
||||
StringBuilder saveStream = new();
|
||||
WriteSaveDataHeaders(saveStream);
|
||||
for (var i = 0; i < bosses.Count; ++i)
|
||||
saveStream.Append($"{(uint)EncounterState.NotStarted} ");
|
||||
|
||||
WriteSaveDataMore(saveStream);
|
||||
|
||||
newData = saveStream;
|
||||
}
|
||||
|
||||
newData.Remove(position, 2);
|
||||
newData.Insert(position, $"{(uint)saveEvent.NewState}0");
|
||||
|
||||
return newData.ToString();
|
||||
}
|
||||
|
||||
void WriteSaveDataHeaders(StringBuilder data)
|
||||
{
|
||||
foreach (char header in headers)
|
||||
data.AppendFormat("{0} ", header);
|
||||
InstanceScriptDataWriter writer = new(this);
|
||||
writer.FillDataFrom(oldData);
|
||||
writer.SetBossState(saveEvent);
|
||||
return writer.GetString();
|
||||
}
|
||||
|
||||
void WriteSaveDataBossStates(StringBuilder data)
|
||||
public string UpdateAdditionalSaveData(string oldData, UpdateAdditionalSaveDataEvent saveEvent)
|
||||
{
|
||||
foreach (BossInfo bossInfo in bosses.Values)
|
||||
data.AppendFormat("{0} ", (uint)bossInfo.state);
|
||||
if (!instance.GetMapDifficulty().IsUsingEncounterLocks())
|
||||
return GetSaveData();
|
||||
|
||||
InstanceScriptDataWriter writer = new(this);
|
||||
writer.FillDataFrom(oldData);
|
||||
writer.SetAdditionalData(saveEvent);
|
||||
return writer.GetString();
|
||||
}
|
||||
|
||||
public void HandleGameObject(ObjectGuid guid, bool open, GameObject go = null)
|
||||
@@ -763,7 +704,7 @@ namespace Game.Maps
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void SetEntranceLocation(uint worldSafeLocationId)
|
||||
{
|
||||
_entranceId = worldSafeLocationId;
|
||||
@@ -998,6 +939,12 @@ namespace Game.Maps
|
||||
|
||||
public byte GetCombatResurrectionCharges() { return _combatResurrectionCharges; }
|
||||
|
||||
public void RegisterPersistentScriptValue(PersistentInstanceScriptValueBase value) { _persistentScriptValues.Add(value); }
|
||||
|
||||
public string GetHeader() { return headers; }
|
||||
|
||||
public List<PersistentInstanceScriptValueBase> GetPersistentScriptValues() { return _persistentScriptValues; }
|
||||
|
||||
public void SetBossNumber(uint number)
|
||||
{
|
||||
for (uint i = 0; i < number; ++i)
|
||||
@@ -1010,15 +957,15 @@ namespace Game.Maps
|
||||
public void OutLoadInstDataComplete() { Log.outDebug(LogFilter.Scripts, "Instance Data Load for Instance {0} (Map {1}, Instance Id: {2}) is complete.", instance.GetMapName(), instance.GetId(), instance.GetInstanceId()); }
|
||||
public void OutLoadInstDataFail() { Log.outDebug(LogFilter.Scripts, "Unable to load Instance Data for Instance {0} (Map {1}, Instance Id: {2}).", instance.GetMapName(), instance.GetId(), instance.GetInstanceId()); }
|
||||
|
||||
public virtual void ReadSaveDataMore(StringArguments data) { }
|
||||
|
||||
public virtual void WriteSaveDataMore(StringBuilder data) { }
|
||||
|
||||
public List<InstanceSpawnGroupInfo> GetInstanceSpawnGroups() { return _instanceSpawnGroups; }
|
||||
|
||||
// Override this function to validate all additional data loads
|
||||
public virtual void AfterDataLoad() { }
|
||||
|
||||
public InstanceMap instance;
|
||||
List<char> headers = new();
|
||||
string headers;
|
||||
Dictionary<uint, BossInfo> bosses = new();
|
||||
List<PersistentInstanceScriptValueBase> _persistentScriptValues = new();
|
||||
MultiMap<uint, DoorInfo> doors = new();
|
||||
Dictionary<uint, MinionInfo> minions = new();
|
||||
Dictionary<uint, uint> _creatureInfo = new();
|
||||
@@ -1131,15 +1078,84 @@ namespace Game.Maps
|
||||
public BossInfo bossInfo;
|
||||
}
|
||||
|
||||
public struct UpdateSaveDataEvent
|
||||
public struct UpdateBossStateSaveDataEvent
|
||||
{
|
||||
public DungeonEncounterRecord DungeonEncounter;
|
||||
public uint BossId;
|
||||
public EncounterState NewState;
|
||||
|
||||
public UpdateSaveDataEvent(uint bossId, EncounterState state)
|
||||
public UpdateBossStateSaveDataEvent(DungeonEncounterRecord dungeonEncounter, uint bossId, EncounterState state)
|
||||
{
|
||||
DungeonEncounter = dungeonEncounter;
|
||||
BossId = bossId;
|
||||
NewState = state;
|
||||
}
|
||||
}
|
||||
|
||||
public struct UpdateAdditionalSaveDataEvent
|
||||
{
|
||||
public string Key;
|
||||
public object Value;
|
||||
|
||||
public UpdateAdditionalSaveDataEvent(string key, object value)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public class PersistentInstanceScriptValueBase
|
||||
{
|
||||
protected InstanceScript _instance;
|
||||
protected string _name;
|
||||
protected object _value;
|
||||
|
||||
protected PersistentInstanceScriptValueBase(InstanceScript instance, string name, object value)
|
||||
{
|
||||
_instance = instance;
|
||||
_name = name;
|
||||
_value = value;
|
||||
|
||||
_instance.RegisterPersistentScriptValue(this);
|
||||
}
|
||||
|
||||
public string GetName() { return _name; }
|
||||
|
||||
public UpdateAdditionalSaveDataEvent CreateEvent()
|
||||
{
|
||||
return new UpdateAdditionalSaveDataEvent(_name, _value);
|
||||
}
|
||||
|
||||
public void LoadValue(long value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public void LoadValue(double value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
class PersistentInstanceScriptValue<T> : PersistentInstanceScriptValueBase
|
||||
{
|
||||
public PersistentInstanceScriptValue(InstanceScript instance, string name, T value) : base(instance, name, value) { }
|
||||
|
||||
public PersistentInstanceScriptValue<T> SetValue(T value)
|
||||
{
|
||||
_value = value;
|
||||
NotifyValueChanged();
|
||||
return this;
|
||||
}
|
||||
|
||||
void NotifyValueChanged()
|
||||
{
|
||||
_instance.instance.UpdateInstanceLock(CreateEvent());
|
||||
}
|
||||
|
||||
void LoadValue(T value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.DataStorage;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace Game.Maps
|
||||
{
|
||||
class InstanceScriptDataReader
|
||||
{
|
||||
public enum Result
|
||||
{
|
||||
Ok,
|
||||
MalformedJson,
|
||||
RootIsNotAnObject,
|
||||
MissingHeader,
|
||||
UnexpectedHeader,
|
||||
MissingBossStates,
|
||||
BossStatesIsNotAnObject,
|
||||
UnknownBoss,
|
||||
BossStateIsNotAnObject,
|
||||
MissingBossState,
|
||||
BossStateValueIsNotANumber,
|
||||
AdditionalDataIsNotAnObject,
|
||||
AdditionalDataUnexpectedValueType
|
||||
}
|
||||
|
||||
InstanceScript _instance;
|
||||
JsonDocument _doc;
|
||||
|
||||
public InstanceScriptDataReader(InstanceScript instance)
|
||||
{
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
public Result Load(string data)
|
||||
{
|
||||
/*
|
||||
Expected JSON
|
||||
|
||||
{
|
||||
"Header": "HEADER_STRING_SET_BY_SCRIPT",
|
||||
"BossStates": [0,2,0,...] // indexes are boss ids, values are EncounterState
|
||||
"AdditionalData: { // optional
|
||||
"ExtraKey1": 123
|
||||
"AnotherExtraKey": 2.0
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
try
|
||||
{
|
||||
_doc = JsonDocument.Parse(data);
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, $"JSON parser error {ex.Message} at {ex.LineNumber} while loading data for instance {GetInstanceId()} [{GetMapId()}-{GetMapName()} | {GetDifficultyId()}-{GetDifficultyName()}]");
|
||||
return Result.MalformedJson;
|
||||
}
|
||||
|
||||
if (_doc.RootElement.ValueKind != JsonValueKind.Object)
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, $"Root JSON value is not an object for instance {GetInstanceId()} [{GetMapId()}-{GetMapName()} | {GetDifficultyId()}-{GetDifficultyName()}]");
|
||||
return Result.RootIsNotAnObject;
|
||||
}
|
||||
|
||||
Result result = ParseHeader();
|
||||
if (result != Result.Ok)
|
||||
return result;
|
||||
|
||||
result = ParseBossStates();
|
||||
if (result != Result.Ok)
|
||||
return result;
|
||||
|
||||
result = ParseAdditionalData();
|
||||
if (result != Result.Ok)
|
||||
return result;
|
||||
|
||||
return Result.Ok;
|
||||
}
|
||||
|
||||
Result ParseHeader()
|
||||
{
|
||||
if (!_doc.RootElement.TryGetProperty("Header", out JsonElement header))
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, $"Missing data header for instance {GetInstanceId()} [{GetMapId()}-{GetMapName()} | {GetDifficultyId()}-{GetDifficultyName()}]");
|
||||
return Result.MissingHeader;
|
||||
}
|
||||
|
||||
if (header.GetString() != _instance.GetHeader())
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, $"Incorrect data header for instance {GetInstanceId()} [{GetMapId()}-{GetMapName()} | {GetDifficultyId()}-{GetDifficultyName()}], expected \"{_instance.GetHeader()}\" got \"{header.GetString()}\"");
|
||||
return Result.UnexpectedHeader;
|
||||
}
|
||||
|
||||
return Result.Ok;
|
||||
}
|
||||
|
||||
Result ParseBossStates()
|
||||
{
|
||||
if (!_doc.RootElement.TryGetProperty("BossStates", out JsonElement bossStates))
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, $"Missing boss states for instance {GetInstanceId()} [{GetMapId()}-{GetMapName()} | {GetDifficultyId()}-{GetDifficultyName()}]");
|
||||
return Result.MissingBossStates;
|
||||
}
|
||||
|
||||
if (bossStates.ValueKind != JsonValueKind.Array)
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, $"Boss states is not an array for instance {GetInstanceId()} [{GetMapId()}-{GetMapName()} | {GetDifficultyId()}-{GetDifficultyName()}]");
|
||||
return Result.BossStatesIsNotAnObject;
|
||||
}
|
||||
|
||||
for (int bossId = 0; bossId < bossStates.GetArrayLength(); ++bossId)
|
||||
{
|
||||
if (bossId >= _instance.GetEncounterCount())
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, $"Boss states has entry for boss with higher id ({bossId}) than number of bosses ({_instance.GetEncounterCount()}) for instance {GetInstanceId()} [{GetMapId()}-{GetMapName()} | {GetDifficultyId()}-{GetDifficultyName()}]");
|
||||
return Result.UnknownBoss;
|
||||
}
|
||||
|
||||
var bossState = bossStates[bossId];
|
||||
if (bossState.ValueKind != JsonValueKind.Number)
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, $"Boss state for boss ({bossId}) is not a number for instance {GetInstanceId()} [{GetMapId()}-{GetMapName()} | {GetDifficultyId()}-{GetDifficultyName()}]");
|
||||
return Result.BossStateIsNotAnObject;
|
||||
}
|
||||
|
||||
EncounterState state = (EncounterState)bossState.GetInt32();
|
||||
if (state == EncounterState.InProgress || state == EncounterState.Fail || state == EncounterState.Special)
|
||||
state = EncounterState.NotStarted;
|
||||
|
||||
if (state < EncounterState.ToBeDecided)
|
||||
_instance.SetBossState((uint)bossId, state);
|
||||
}
|
||||
|
||||
return Result.Ok;
|
||||
}
|
||||
|
||||
Result ParseAdditionalData()
|
||||
{
|
||||
if (!_doc.RootElement.TryGetProperty("AdditionalData", out JsonElement moreData))
|
||||
return Result.Ok;
|
||||
|
||||
if (moreData.ValueKind != JsonValueKind.Object)
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, $"Additional data is not an object for instance {GetInstanceId()} [{GetMapId()}-{GetMapName()} | {GetDifficultyId()}-{GetDifficultyName()}]");
|
||||
return Result.AdditionalDataIsNotAnObject;
|
||||
}
|
||||
|
||||
foreach (PersistentInstanceScriptValueBase valueBase in _instance.GetPersistentScriptValues())
|
||||
{
|
||||
if (moreData.TryGetProperty(valueBase.GetName(), out JsonElement value) && value.ValueKind != JsonValueKind.Null)
|
||||
{
|
||||
if (value.ValueKind != JsonValueKind.Number)
|
||||
{
|
||||
Log.outError(LogFilter.Scripts, $"Additional data value for key {valueBase.GetName()} is not a number for instance {GetInstanceId()} [{GetMapId()}-{GetMapName()} | {GetDifficultyId()}-{GetDifficultyName()}]");
|
||||
return Result.AdditionalDataUnexpectedValueType;
|
||||
}
|
||||
|
||||
if (value.TryGetDouble(out double doubleValue))
|
||||
valueBase.LoadValue(doubleValue);
|
||||
else
|
||||
valueBase.LoadValue(value.GetInt64());
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Ok;
|
||||
}
|
||||
|
||||
uint GetInstanceId() { return _instance.instance.GetInstanceId(); }
|
||||
|
||||
uint GetMapId() { return _instance.instance.GetId(); }
|
||||
|
||||
string GetMapName() { return _instance.instance.GetMapName(); }
|
||||
|
||||
uint GetDifficultyId() { return (uint)_instance.instance.GetDifficultyID(); }
|
||||
|
||||
string GetDifficultyName() { return CliDB.DifficultyStorage.LookupByKey(_instance.instance.GetDifficultyID()).Name; }
|
||||
}
|
||||
|
||||
class InstanceScriptDataWriter
|
||||
{
|
||||
InstanceScript _instance;
|
||||
JsonObject _doc = new();
|
||||
|
||||
public InstanceScriptDataWriter(InstanceScript instance)
|
||||
{
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
public string GetString()
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
using (var writer = new Utf8JsonWriter(stream))
|
||||
{
|
||||
_doc.WriteTo(writer);
|
||||
}
|
||||
|
||||
return Encoding.UTF8.GetString(stream.ToArray());
|
||||
}
|
||||
|
||||
public void FillData(bool withValues = true)
|
||||
{
|
||||
_doc.Add("Header", _instance.GetHeader());
|
||||
|
||||
JsonArray bossStates = new();
|
||||
for (uint bossId = 0; bossId < _instance.GetEncounterCount(); ++bossId)
|
||||
bossStates.Add(JsonValue.Create((int)(withValues ? _instance.GetBossState(bossId) : EncounterState.NotStarted)));
|
||||
|
||||
_doc.Add("BossStates", bossStates);
|
||||
|
||||
if (!_instance.GetPersistentScriptValues().Empty())
|
||||
{
|
||||
JsonObject moreData = new();
|
||||
foreach (PersistentInstanceScriptValueBase additionalValue in _instance.GetPersistentScriptValues())
|
||||
{
|
||||
if (withValues)
|
||||
{
|
||||
UpdateAdditionalSaveDataEvent data = additionalValue.CreateEvent();
|
||||
if (data.Value is double)
|
||||
moreData.Add(data.Key, (double)data.Value);
|
||||
else
|
||||
moreData.Add(data.Key, (long)data.Value);
|
||||
}
|
||||
else
|
||||
moreData.Add(additionalValue.GetName(), null);
|
||||
}
|
||||
|
||||
_doc.Add("AdditionalData", moreData);
|
||||
}
|
||||
}
|
||||
|
||||
public void FillDataFrom(string data)
|
||||
{
|
||||
try
|
||||
{
|
||||
_doc = JsonNode.Parse(data).AsObject();
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
FillData(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetBossState(UpdateBossStateSaveDataEvent data)
|
||||
{
|
||||
var array = _doc["BossStates"].AsArray();
|
||||
array[(int)data.BossId] = (int)data.NewState;
|
||||
}
|
||||
|
||||
public void SetAdditionalData(UpdateAdditionalSaveDataEvent data)
|
||||
{
|
||||
var jObject = _doc["AdditionalData"].AsObject();
|
||||
if (data.Value is double)
|
||||
jObject[data.Key] = (double)data.Value;
|
||||
else
|
||||
jObject[data.Key] = (long)data.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
+46
-6
@@ -4990,20 +4990,18 @@ namespace Game.Maps
|
||||
return Global.ObjectMgr.GetScriptName(i_script_id);
|
||||
}
|
||||
|
||||
public void UpdateInstanceLock(DungeonEncounterRecord dungeonEncounter, UpdateSaveDataEvent updateSaveDataEvent)
|
||||
public void UpdateInstanceLock(UpdateBossStateSaveDataEvent updateSaveDataEvent)
|
||||
{
|
||||
if (i_instanceLock != null)
|
||||
{
|
||||
uint instanceCompletedEncounters = i_instanceLock.GetData().CompletedEncountersMask;
|
||||
if (dungeonEncounter != null)
|
||||
instanceCompletedEncounters |= 1u << dungeonEncounter.Bit;
|
||||
uint instanceCompletedEncounters = i_instanceLock.GetData().CompletedEncountersMask | (1u << updateSaveDataEvent.DungeonEncounter.Bit);
|
||||
|
||||
MapDb2Entries entries = new(GetEntry(), GetMapDifficulty());
|
||||
|
||||
SQLTransaction trans = new();
|
||||
|
||||
if (entries.IsInstanceIdBound())
|
||||
Global.InstanceLockMgr.UpdateSharedInstanceLock(trans, new InstanceLockUpdateEvent(GetInstanceId(), i_data.GetSaveData(), instanceCompletedEncounters, dungeonEncounter));
|
||||
Global.InstanceLockMgr.UpdateSharedInstanceLock(trans, new InstanceLockUpdateEvent(GetInstanceId(), i_data.GetSaveData(), instanceCompletedEncounters, updateSaveDataEvent.DungeonEncounter));
|
||||
|
||||
foreach (var player in GetPlayers())
|
||||
{
|
||||
@@ -5018,7 +5016,49 @@ namespace Game.Maps
|
||||
|
||||
bool isNewLock = playerLock == null || playerLock.GetData().CompletedEncountersMask == 0 || playerLock.IsExpired();
|
||||
|
||||
InstanceLock newLock = Global.InstanceLockMgr.UpdateInstanceLockForPlayer(trans, player.GetGUID(), entries, new InstanceLockUpdateEvent(GetInstanceId(), i_data.UpdateSaveData(oldData, updateSaveDataEvent), instanceCompletedEncounters, dungeonEncounter));
|
||||
InstanceLock newLock = Global.InstanceLockMgr.UpdateInstanceLockForPlayer(trans, player.GetGUID(), entries, new InstanceLockUpdateEvent(GetInstanceId(), i_data.UpdateBossStateSaveData(oldData, updateSaveDataEvent), instanceCompletedEncounters, updateSaveDataEvent.DungeonEncounter));
|
||||
|
||||
if (isNewLock)
|
||||
{
|
||||
InstanceSaveCreated data = new();
|
||||
data.Gm = player.IsGameMaster();
|
||||
player.SendPacket(data);
|
||||
|
||||
player.GetSession().SendCalendarRaidLockoutAdded(newLock);
|
||||
}
|
||||
}
|
||||
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateInstanceLock(UpdateAdditionalSaveDataEvent updateSaveDataEvent)
|
||||
{
|
||||
if (i_instanceLock != null)
|
||||
{
|
||||
uint instanceCompletedEncounters = i_instanceLock.GetData().CompletedEncountersMask;
|
||||
|
||||
MapDb2Entries entries = new(GetEntry(), GetMapDifficulty());
|
||||
|
||||
SQLTransaction trans = new();
|
||||
|
||||
if (entries.IsInstanceIdBound())
|
||||
Global.InstanceLockMgr.UpdateSharedInstanceLock(trans, new InstanceLockUpdateEvent(GetInstanceId(), i_data.GetSaveData(), instanceCompletedEncounters, null));
|
||||
|
||||
foreach (var player in GetPlayers())
|
||||
{
|
||||
// never instance bind GMs with GM mode enabled
|
||||
if (player.IsGameMaster())
|
||||
continue;
|
||||
|
||||
InstanceLock playerLock = Global.InstanceLockMgr.FindActiveInstanceLock(player.GetGUID(), entries);
|
||||
string oldData = "";
|
||||
if (playerLock != null)
|
||||
oldData = playerLock.GetData().Data;
|
||||
|
||||
bool isNewLock = playerLock == null || playerLock.GetData().CompletedEncountersMask == 0 || playerLock.IsExpired();
|
||||
|
||||
InstanceLock newLock = Global.InstanceLockMgr.UpdateInstanceLockForPlayer(trans, player.GetGUID(), entries, new InstanceLockUpdateEvent(GetInstanceId(), i_data.UpdateAdditionalSaveData(oldData, updateSaveDataEvent), instanceCompletedEncounters, null));
|
||||
|
||||
if (isNewLock)
|
||||
{
|
||||
|
||||
+14
-61
@@ -114,9 +114,6 @@ namespace Scripts.EasternKingdoms.BlackrockMountain.BlackrockDepths
|
||||
|
||||
class instance_blackrock_depths_InstanceMapScript : InstanceScript
|
||||
{
|
||||
uint[] encounter = new uint[MiscConst.MaxEncounter];
|
||||
string str_data;
|
||||
|
||||
ObjectGuid EmperorGUID;
|
||||
ObjectGuid PhalanxGUID;
|
||||
ObjectGuid MagmusGUID;
|
||||
@@ -155,6 +152,7 @@ namespace Scripts.EasternKingdoms.BlackrockMountain.BlackrockDepths
|
||||
public instance_blackrock_depths_InstanceMapScript(InstanceMap map) : base(map)
|
||||
{
|
||||
SetHeaders("BRD");
|
||||
SetBossNumber(MiscConst.MaxEncounter);
|
||||
|
||||
BarAleCount = 0;
|
||||
GhostKillCount = 0;
|
||||
@@ -238,40 +236,30 @@ namespace Scripts.EasternKingdoms.BlackrockMountain.BlackrockDepths
|
||||
switch (type)
|
||||
{
|
||||
case DataTypes.TypeRingOfLaw:
|
||||
encounter[0] = data;
|
||||
SetBossState(0, (EncounterState)data);
|
||||
break;
|
||||
case DataTypes.TypeVault:
|
||||
encounter[1] = data;
|
||||
SetBossState(1, (EncounterState)data);
|
||||
break;
|
||||
case DataTypes.TypeBar:
|
||||
if (data == (uint)EncounterState.Special)
|
||||
++BarAleCount;
|
||||
else
|
||||
encounter[2] = data;
|
||||
SetBossState(2, (EncounterState)data);
|
||||
break;
|
||||
case DataTypes.TypeTombOfSeven:
|
||||
encounter[3] = data;
|
||||
SetBossState(3, (EncounterState)data);
|
||||
break;
|
||||
case DataTypes.TypeLyceum:
|
||||
encounter[4] = data;
|
||||
SetBossState(4, (EncounterState)data);
|
||||
break;
|
||||
case DataTypes.TypeIronHall:
|
||||
encounter[5] = data;
|
||||
SetBossState(5, (EncounterState)data);
|
||||
break;
|
||||
case DataTypes.DataGhostkill:
|
||||
GhostKillCount += data;
|
||||
break;
|
||||
}
|
||||
|
||||
if (data == (uint)EncounterState.Done || GhostKillCount >= MiscConst.TombOfSevenBossNum)
|
||||
{
|
||||
OutSaveInstData();
|
||||
|
||||
str_data = $"{encounter[0]} {encounter[1]} {encounter[2]} {encounter[3]} {encounter[4]} {encounter[5]} {GhostKillCount}";
|
||||
|
||||
SaveToDB();
|
||||
OutSaveInstDataComplete();
|
||||
}
|
||||
}
|
||||
|
||||
public override uint GetData(uint type)
|
||||
@@ -279,20 +267,20 @@ namespace Scripts.EasternKingdoms.BlackrockMountain.BlackrockDepths
|
||||
switch (type)
|
||||
{
|
||||
case DataTypes.TypeRingOfLaw:
|
||||
return encounter[0];
|
||||
return (uint)GetBossState(0);
|
||||
case DataTypes.TypeVault:
|
||||
return encounter[1];
|
||||
return (uint)GetBossState(1);
|
||||
case DataTypes.TypeBar:
|
||||
if (encounter[2] == (uint)EncounterState.InProgress && BarAleCount == 3)
|
||||
if (GetBossState(2) == EncounterState.InProgress && BarAleCount == 3)
|
||||
return (uint)EncounterState.Special;
|
||||
else
|
||||
return encounter[2];
|
||||
return (uint)GetBossState(2);
|
||||
case DataTypes.TypeTombOfSeven:
|
||||
return encounter[3];
|
||||
return (uint)GetBossState(3);
|
||||
case DataTypes.TypeLyceum:
|
||||
return encounter[4];
|
||||
return (uint)GetBossState(4);
|
||||
case DataTypes.TypeIronHall:
|
||||
return encounter[5];
|
||||
return (uint)GetBossState(5);
|
||||
case DataTypes.DataGhostkill:
|
||||
return GhostKillCount;
|
||||
}
|
||||
@@ -343,41 +331,6 @@ namespace Scripts.EasternKingdoms.BlackrockMountain.BlackrockDepths
|
||||
return ObjectGuid.Empty;
|
||||
}
|
||||
|
||||
public override string GetSaveData()
|
||||
{
|
||||
return str_data;
|
||||
}
|
||||
|
||||
public override void Load(string str)
|
||||
{
|
||||
if (str.IsEmpty())
|
||||
{
|
||||
|
||||
OutLoadInstDataFail();
|
||||
return;
|
||||
}
|
||||
|
||||
OutLoadInstData(str);
|
||||
|
||||
StringArguments loadStream = new(str);
|
||||
|
||||
for (var i = 0; i < encounter.Length; ++i)
|
||||
encounter[i] = loadStream.NextUInt32();
|
||||
|
||||
GhostKillCount = loadStream.NextUInt32();
|
||||
|
||||
for (byte i = 0; i < encounter.Length; ++i)
|
||||
if (encounter[i] == (uint)EncounterState.InProgress)
|
||||
encounter[i] = (uint)EncounterState.NotStarted;
|
||||
|
||||
if (GhostKillCount > 0 && GhostKillCount < MiscConst.TombOfSevenBossNum)
|
||||
GhostKillCount = 0;//reset tomb of seven event
|
||||
if (GhostKillCount >= MiscConst.TombOfSevenBossNum)
|
||||
GhostKillCount = MiscConst.TombOfSevenBossNum;
|
||||
|
||||
OutLoadInstDataComplete();
|
||||
}
|
||||
|
||||
void TombOfSevenEvent()
|
||||
{
|
||||
if (GhostKillCount < MiscConst.TombOfSevenBossNum && !TombBossGUIDs[TombEventCounter].IsEmpty())
|
||||
|
||||
@@ -230,7 +230,7 @@ namespace Scripts.EasternKingdoms.BlackrockMountain.MoltenCore
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReadSaveDataMore(string data)
|
||||
public override void AfterDataLoad()
|
||||
{
|
||||
if (CheckMajordomoExecutus())
|
||||
_executusSchedule = true;
|
||||
|
||||
Reference in New Issue
Block a user