Core/DBLayer: Implement async transaction completion callbacks

Port From (https://github.com/TrinityCore/TrinityCore/commit/0f0ca3a9194d76afa0227943e86469ad8368c5e2)
This commit is contained in:
hondacrx
2020-04-26 00:53:43 -04:00
parent a9d1d3f2b0
commit d450f6db3d
14 changed files with 224 additions and 109 deletions
+3 -3
View File
@@ -55,7 +55,7 @@ namespace BNetServer.Networking
stmt.AddValue(0, ip_address); stmt.AddValue(0, ip_address);
stmt.AddValue(1, BitConverter.ToUInt32(GetRemoteIpAddress().GetAddressBytes(), 0)); stmt.AddValue(1, BitConverter.ToUInt32(GetRemoteIpAddress().GetAddressBytes(), 0));
_queryProcessor.AddQuery(DB.Login.AsyncQuery(stmt).WithCallback(CheckIpCallback)); _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(CheckIpCallback));
} }
void CheckIpCallback(SQLResult result) void CheckIpCallback(SQLResult result)
@@ -89,7 +89,7 @@ namespace BNetServer.Networking
if (!base.Update()) if (!base.Update())
return false; return false;
_queryProcessor.ProcessReadyQueries(); _queryProcessor.ProcessReadyCallbacks();
return true; return true;
} }
@@ -631,7 +631,7 @@ namespace BNetServer.Networking
bool _authed; bool _authed;
QueryCallbackProcessor _queryProcessor = new QueryCallbackProcessor(); AsyncCallbackProcessor<QueryCallback> _queryProcessor = new AsyncCallbackProcessor<QueryCallback>();
Dictionary<uint, Action<CodedInputStream>> _responseCallbacks = new Dictionary<uint, Action<CodedInputStream>>(); Dictionary<uint, Action<CodedInputStream>> _responseCallbacks = new Dictionary<uint, Action<CodedInputStream>>();
uint _requestToken; uint _requestToken;
@@ -19,21 +19,27 @@ using System.Collections.Generic;
namespace Framework.Database namespace Framework.Database
{ {
public class QueryCallbackProcessor public interface ISqlCallback
{ {
public void AddQuery(QueryCallback query) bool InvokeIfReady();
}
public class AsyncCallbackProcessor<T> where T : ISqlCallback
{
List<T> _callbacks = new List<T>();
public T AddCallback(T query)
{ {
_callbacks.Add(query); _callbacks.Add(query);
return query;
} }
public void ProcessReadyQueries() public void ProcessReadyCallbacks()
{ {
if (_callbacks.Empty()) if (_callbacks.Empty())
return; return;
_callbacks.RemoveAll(callback => callback.InvokeIfReady() == QueryCallbackStatus.Completed); _callbacks.RemoveAll(callback => callback.InvokeIfReady());
} }
List<QueryCallback> _callbacks = new List<QueryCallback>();
} }
} }
+11 -4
View File
@@ -253,7 +253,15 @@ namespace Framework.Database
_queue.Push(new TransactionTask(transaction)); _queue.Push(new TransactionTask(transaction));
} }
public bool DirectCommitTransaction(SQLTransaction transaction) public TransactionCallback AsyncCommitTransaction(SQLTransaction transaction)
{
TransactionWithResultTask task = new TransactionWithResultTask(transaction);
Task<bool> result = task.GetFuture();
_queue.Push(task);
return new TransactionCallback(result);
}
public MySqlErrorCode DirectCommitTransaction(SQLTransaction transaction)
{ {
using (var Connection = _connectionInfo.GetConnection()) using (var Connection = _connectionInfo.GetConnection())
{ {
@@ -277,13 +285,12 @@ namespace Framework.Database
trans.Commit(); trans.Commit();
scope.Complete(); scope.Complete();
} }
return true; return MySqlErrorCode.None;
} }
catch (MySqlException ex) //error occurred catch (MySqlException ex) //error occurred
{ {
HandleMySQLException(ex, query);
trans.Rollback(); trans.Rollback();
return false; return HandleMySQLException(ex, query);
} }
} }
} }
+5 -12
View File
@@ -21,7 +21,7 @@ using System.Threading.Tasks;
namespace Framework.Database namespace Framework.Database
{ {
public class QueryCallback public class QueryCallback : ISqlCallback
{ {
public QueryCallback(Task<SQLResult> result) public QueryCallback(Task<SQLResult> result)
{ {
@@ -49,7 +49,7 @@ namespace Framework.Database
_result = next._result; _result = next._result;
} }
public QueryCallbackStatus InvokeIfReady() public bool InvokeIfReady()
{ {
QueryCallbackData callback = _callbacks.Peek(); QueryCallbackData callback = _callbacks.Peek();
@@ -68,17 +68,17 @@ namespace Framework.Database
if (_callbacks.Count == 0) if (_callbacks.Count == 0)
{ {
Cypher.Assert(!hasNext); Cypher.Assert(!hasNext);
return QueryCallbackStatus.Completed; return true;
} }
// abort chain // abort chain
if (!hasNext) if (!hasNext)
return QueryCallbackStatus.Completed; return true;
callback = _callbacks.Peek(); callback = _callbacks.Peek();
} }
else else
return QueryCallbackStatus.NotReady; return false;
} }
} }
@@ -100,11 +100,4 @@ namespace Framework.Database
public Action<QueryCallback, SQLResult> _result; public Action<QueryCallback, SQLResult> _result;
} }
public enum QueryCallbackStatus
{
NotReady,
NextStep,
Completed
}
} }
@@ -17,6 +17,8 @@
using MySql.Data.MySqlClient; using MySql.Data.MySqlClient;
using System.Collections.Generic; using System.Collections.Generic;
using System;
using System.Threading.Tasks;
namespace Framework.Database namespace Framework.Database
{ {
@@ -52,10 +54,98 @@ namespace Framework.Database
} }
public bool Execute<T>(MySqlBase<T> mySqlBase) public bool Execute<T>(MySqlBase<T> mySqlBase)
{
MySqlErrorCode errorCode = TryExecute(mySqlBase);
if (errorCode == MySqlErrorCode.None)
return true;
if (errorCode == MySqlErrorCode.LockDeadlock)
{
// Make sure only 1 async thread retries a transaction so they don't keep dead-locking each other
lock (_deadlockLock)
{
byte loopBreaker = 5; // Handle MySQL Errno 1213 without extending deadlock to the core itself
for (byte i = 0; i < loopBreaker; ++i)
if (TryExecute(mySqlBase) == MySqlErrorCode.None)
return true;
}
}
return false;
}
public MySqlErrorCode TryExecute<T>(MySqlBase<T> mySqlBase)
{ {
return mySqlBase.DirectCommitTransaction(m_trans); return mySqlBase.DirectCommitTransaction(m_trans);
} }
SQLTransaction m_trans; SQLTransaction m_trans;
public static object _deadlockLock = new object();
}
class TransactionWithResultTask : TransactionTask
{
public TransactionWithResultTask(SQLTransaction trans) : base(trans) { }
public new bool Execute<T>(MySqlBase<T> mySqlBase)
{
MySqlErrorCode errorCode = TryExecute(mySqlBase);
if (errorCode == MySqlErrorCode.None)
{
m_result.SetResult(true);
return true;
}
if (errorCode == MySqlErrorCode.LockDeadlock)
{
// Make sure only 1 async thread retries a transaction so they don't keep dead-locking each other
lock (_deadlockLock)
{
byte loopBreaker = 5; // Handle MySQL Errno 1213 without extending deadlock to the core itself
for (byte i = 0; i < loopBreaker; ++i)
{
if (TryExecute(mySqlBase) == MySqlErrorCode.None)
{
m_result.SetResult(true);
return true;
}
}
}
}
m_result.SetResult(false);
return false;
}
public Task<bool> GetFuture() { return m_result.Task; }
TaskCompletionSource<bool> m_result = new TaskCompletionSource<bool>();
}
public class TransactionCallback : ISqlCallback
{
public TransactionCallback(Task<bool> future)
{
m_future = future;
}
public void AfterComplete(Action<bool> callback)
{
m_callback = callback;
}
public bool InvokeIfReady()
{
if (m_future != null && m_future.Wait(0))
{
m_callback(m_future.Result);
return true;
}
return false;
}
Task<bool> m_future;
Action<bool> m_callback;
} }
} }
@@ -73,6 +73,7 @@ namespace Game.Entities
{ {
return MapSpecificCreate(type, (byte)subType, (ushort)mapId, 0, entry, counter); return MapSpecificCreate(type, (byte)subType, (ushort)mapId, 0, entry, counter);
} }
static ObjectGuid GlobalCreate(HighGuid type, ulong counter) static ObjectGuid GlobalCreate(HighGuid type, ulong counter)
{ {
return new ObjectGuid((ulong)type << 58, counter); return new ObjectGuid((ulong)type << 58, counter);
+47 -42
View File
@@ -3107,6 +3107,17 @@ namespace Game.Entities
} }
public void SaveToDB(bool create = false) public void SaveToDB(bool create = false)
{
SQLTransaction loginTransaction = new SQLTransaction();
SQLTransaction characterTransaction = new SQLTransaction();
SaveToDB(loginTransaction, characterTransaction, create);
DB.Characters.CommitTransaction(characterTransaction);
DB.Login.CommitTransaction(loginTransaction);
}
public void SaveToDB(SQLTransaction loginTransaction, SQLTransaction characterTransaction, bool create = false)
{ {
// delay auto save at any saves (manual, in code, or autosave) // delay auto save at any saves (manual, in code, or autosave)
m_nextSave = WorldConfig.GetUIntValue(WorldCfg.IntervalSave); m_nextSave = WorldConfig.GetUIntValue(WorldCfg.IntervalSave);
@@ -3126,13 +3137,12 @@ namespace Game.Entities
if (!create) if (!create)
Global.ScriptMgr.OnPlayerSave(this); Global.ScriptMgr.OnPlayerSave(this);
SQLTransaction trans = new SQLTransaction();
PreparedStatement stmt; PreparedStatement stmt;
byte index = 0; byte index = 0;
stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_FISHINGSTEPS); stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_FISHINGSTEPS);
stmt.AddValue(0, GetGUID().GetCounter()); stmt.AddValue(0, GetGUID().GetCounter());
trans.Append(stmt); characterTransaction.Append(stmt);
float finiteAlways(float f) { return !float.IsInfinity(f) ? f : 0.0f; }; float finiteAlways(float f) { return !float.IsInfinity(f) ? f : 0.0f; };
@@ -3428,7 +3438,7 @@ namespace Game.Entities
stmt.AddValue(index, GetGUID().GetCounter()); stmt.AddValue(index, GetGUID().GetCounter());
} }
trans.Append(stmt); characterTransaction.Append(stmt);
if (m_fishingSteps != 0) if (m_fishingSteps != 0)
{ {
@@ -3436,58 +3446,55 @@ namespace Game.Entities
index = 0; index = 0;
stmt.AddValue(index++, GetGUID().GetCounter()); stmt.AddValue(index++, GetGUID().GetCounter());
stmt.AddValue(index++, m_fishingSteps); stmt.AddValue(index++, m_fishingSteps);
trans.Append(stmt); characterTransaction.Append(stmt);
} }
if (m_mailsUpdated) //save mails only when needed if (m_mailsUpdated) //save mails only when needed
_SaveMail(trans); _SaveMail(characterTransaction);
_SaveBGData(trans); _SaveBGData(characterTransaction);
_SaveInventory(trans); _SaveInventory(characterTransaction);
_SaveVoidStorage(trans); _SaveVoidStorage(characterTransaction);
_SaveQuestStatus(trans); _SaveQuestStatus(characterTransaction);
_SaveDailyQuestStatus(trans); _SaveDailyQuestStatus(characterTransaction);
_SaveWeeklyQuestStatus(trans); _SaveWeeklyQuestStatus(characterTransaction);
_SaveSeasonalQuestStatus(trans); _SaveSeasonalQuestStatus(characterTransaction);
_SaveMonthlyQuestStatus(trans); _SaveMonthlyQuestStatus(characterTransaction);
_SaveGlyphs(trans); _SaveGlyphs(characterTransaction);
_SaveTalents(trans); _SaveTalents(characterTransaction);
_SaveSpells(trans); _SaveSpells(characterTransaction);
GetSpellHistory().SaveToDB<Player>(trans); GetSpellHistory().SaveToDB<Player>(characterTransaction);
_SaveActions(trans); _SaveActions(characterTransaction);
_SaveAuras(trans); _SaveAuras(characterTransaction);
_SaveSkills(trans); _SaveSkills(characterTransaction);
m_achievementSys.SaveToDB(trans); m_achievementSys.SaveToDB(characterTransaction);
reputationMgr.SaveToDB(trans); reputationMgr.SaveToDB(characterTransaction);
m_questObjectiveCriteriaMgr.SaveToDB(trans); m_questObjectiveCriteriaMgr.SaveToDB(characterTransaction);
_SaveEquipmentSets(trans); _SaveEquipmentSets(characterTransaction);
GetSession().SaveTutorialsData(trans); // changed only while character in game GetSession().SaveTutorialsData(characterTransaction); // changed only while character in game
_SaveInstanceTimeRestrictions(trans); _SaveInstanceTimeRestrictions(characterTransaction);
_SaveCurrency(trans); _SaveCurrency(characterTransaction);
_SaveCUFProfiles(trans); _SaveCUFProfiles(characterTransaction);
if (_garrison != null) if (_garrison != null)
_garrison.SaveToDB(trans); _garrison.SaveToDB(characterTransaction);
// check if stats should only be saved on logout // check if stats should only be saved on logout
// save stats can be out of transaction // save stats can be out of transaction
if (GetSession().IsLogingOut() || !WorldConfig.GetBoolValue(WorldCfg.StatsSaveOnlyOnLogout)) if (GetSession().IsLogingOut() || !WorldConfig.GetBoolValue(WorldCfg.StatsSaveOnlyOnLogout))
_SaveStats(trans); _SaveStats(characterTransaction);
DB.Characters.CommitTransaction(trans);
// TODO: Move this out // TODO: Move this out
trans = new SQLTransaction(); GetSession().GetCollectionMgr().SaveAccountToys(loginTransaction);
GetSession().GetCollectionMgr().SaveAccountToys(trans); GetSession().GetBattlePetMgr().SaveToDB(loginTransaction);
GetSession().GetBattlePetMgr().SaveToDB(trans); GetSession().GetCollectionMgr().SaveAccountHeirlooms(loginTransaction);
GetSession().GetCollectionMgr().SaveAccountHeirlooms(trans); GetSession().GetCollectionMgr().SaveAccountMounts(loginTransaction);
GetSession().GetCollectionMgr().SaveAccountMounts(trans); GetSession().GetCollectionMgr().SaveAccountItemAppearances(loginTransaction);
GetSession().GetCollectionMgr().SaveAccountItemAppearances(trans);
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_BNET_LAST_PLAYER_CHARACTERS); stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_BNET_LAST_PLAYER_CHARACTERS);
stmt.AddValue(0, GetSession().GetAccountId()); stmt.AddValue(0, GetSession().GetAccountId());
stmt.AddValue(1, Global.WorldMgr.GetRealmId().Region); stmt.AddValue(1, Global.WorldMgr.GetRealmId().Region);
stmt.AddValue(2, Global.WorldMgr.GetRealmId().Site); stmt.AddValue(2, Global.WorldMgr.GetRealmId().Site);
trans.Append(stmt); loginTransaction.Append(stmt);
stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_BNET_LAST_PLAYER_CHARACTERS); stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_BNET_LAST_PLAYER_CHARACTERS);
stmt.AddValue(0, GetSession().GetAccountId()); stmt.AddValue(0, GetSession().GetAccountId());
@@ -3497,9 +3504,7 @@ namespace Game.Entities
stmt.AddValue(4, GetName()); stmt.AddValue(4, GetName());
stmt.AddValue(5, GetGUID().GetCounter()); stmt.AddValue(5, GetGUID().GetCounter());
stmt.AddValue(6, Time.UnixTime); stmt.AddValue(6, Time.UnixTime);
trans.Append(stmt); loginTransaction.Append(stmt);
DB.Login.CommitTransaction(trans);
// save pet (hunter pet level and experience and all type pets health/mana). // save pet (hunter pet level and experience and all type pets health/mana).
Pet pet = GetPet(); Pet pet = GetPet();
@@ -383,7 +383,7 @@ namespace Game.Entities
stmt.AddValue(1, GetActiveTalentGroup()); stmt.AddValue(1, GetActiveTalentGroup());
WorldSession mySess = GetSession(); WorldSession mySess = GetSession();
mySess.GetQueryProcessor().AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(result => mySess.GetQueryProcessor().AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(result =>
{ {
// in case player logs out before db response (player would be deleted in that case) // in case player logs out before db response (player would be deleted in that case)
Player thisPlayer = mySess.GetPlayer(); Player thisPlayer = mySess.GetPlayer();
+32 -26
View File
@@ -49,7 +49,7 @@ namespace Game
stmt.AddValue(0, PetSaveMode.AsCurrent); stmt.AddValue(0, PetSaveMode.AsCurrent);
stmt.AddValue(1, GetAccountId()); stmt.AddValue(1, GetAccountId());
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharEnumCallback)); _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharEnumCallback));
} }
void HandleCharEnumCallback(SQLResult result) void HandleCharEnumCallback(SQLResult result)
@@ -144,7 +144,7 @@ namespace Game
stmt.AddValue(0, (uint)PetSaveMode.AsCurrent); stmt.AddValue(0, (uint)PetSaveMode.AsCurrent);
stmt.AddValue(1, GetAccountId()); stmt.AddValue(1, GetAccountId());
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharUndeleteEnumCallback)); _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharUndeleteEnumCallback));
} }
void HandleCharUndeleteEnumCallback(SQLResult result) void HandleCharUndeleteEnumCallback(SQLResult result)
@@ -307,7 +307,7 @@ namespace Game
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHECK_NAME); PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHECK_NAME);
stmt.AddValue(0, charCreate.CreateInfo.Name); stmt.AddValue(0, charCreate.CreateInfo.Name);
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithChainingCallback((queryCallback, result) => _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithChainingCallback((queryCallback, result) =>
{ {
if (!result.IsEmpty()) if (!result.IsEmpty())
{ {
@@ -334,6 +334,7 @@ namespace Game
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_SUM_CHARS); stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_SUM_CHARS);
stmt.AddValue(0, GetAccountId()); stmt.AddValue(0, GetAccountId());
queryCallback.SetNextQuery(DB.Characters.AsyncQuery(stmt)); queryCallback.SetNextQuery(DB.Characters.AsyncQuery(stmt));
}).WithChainingCallback((queryCallback, result) => }).WithChainingCallback((queryCallback, result) =>
{ {
if (!result.IsEmpty()) if (!result.IsEmpty())
@@ -347,16 +348,15 @@ namespace Game
} }
} }
int demonHunterReqLevel = WorldConfig.GetIntValue(WorldCfg.CharacterCreatingMinLevelForDemonHunter);
bool hasDemonHunterReqLevel = demonHunterReqLevel == 0;
bool allowTwoSideAccounts = !Global.WorldMgr.IsPvPRealm() || HasPermission(RBACPermissions.TwoSideCharacterCreation); bool allowTwoSideAccounts = !Global.WorldMgr.IsPvPRealm() || HasPermission(RBACPermissions.TwoSideCharacterCreation);
int skipCinematics = WorldConfig.GetIntValue(WorldCfg.SkipCinematics); int skipCinematics = WorldConfig.GetIntValue(WorldCfg.SkipCinematics);
bool checkDemonHunterReqs = createInfo.ClassId == Class.DemonHunter && !HasPermission(RBACPermissions.SkipCheckCharacterCreationDemonHunter);
void finalizeCharacterCreation(SQLResult result1) void finalizeCharacterCreation(SQLResult result1)
{ {
bool haveSameRace = false; bool haveSameRace = false;
int demonHunterReqLevel = WorldConfig.GetIntValue(WorldCfg.CharacterCreatingMinLevelForDemonHunter);
bool hasDemonHunterReqLevel = (demonHunterReqLevel == 0);
bool checkDemonHunterReqs = createInfo.ClassId == Class.DemonHunter && !HasPermission(RBACPermissions.SkipCheckCharacterCreationDemonHunter);
if (result1 != null && !result1.IsEmpty()) if (result1 != null && !result1.IsEmpty())
{ {
Team team = Player.TeamForRace(createInfo.RaceId); Team team = Player.TeamForRace(createInfo.RaceId);
@@ -461,33 +461,39 @@ namespace Game
newChar.atLoginFlags = AtLoginFlags.FirstLogin; // First login newChar.atLoginFlags = AtLoginFlags.FirstLogin; // First login
// Player created, save it now SQLTransaction characterTransaction = new SQLTransaction();
newChar.SaveToDB(true); SQLTransaction loginTransaction = new SQLTransaction();
createInfo.CharCount += 1;
SQLTransaction trans = new SQLTransaction(); // Player created, save it now
newChar.SaveToDB(loginTransaction, characterTransaction, true);
createInfo.CharCount += 1;
stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_REALM_CHARACTERS_BY_REALM); stmt = DB.Login.GetPreparedStatement(LoginStatements.DEL_REALM_CHARACTERS_BY_REALM);
stmt.AddValue(0, GetAccountId()); stmt.AddValue(0, GetAccountId());
stmt.AddValue(1, Global.WorldMgr.GetRealm().Id.Realm); stmt.AddValue(1, Global.WorldMgr.GetRealm().Id.Realm);
trans.Append(stmt); loginTransaction.Append(stmt);
stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_REALM_CHARACTERS); stmt = DB.Login.GetPreparedStatement(LoginStatements.INS_REALM_CHARACTERS);
stmt.AddValue(0, createInfo.CharCount); stmt.AddValue(0, createInfo.CharCount);
stmt.AddValue(1, GetAccountId()); stmt.AddValue(1, GetAccountId());
stmt.AddValue(2, Global.WorldMgr.GetRealm().Id.Realm); stmt.AddValue(2, Global.WorldMgr.GetRealm().Id.Realm);
trans.Append(stmt); loginTransaction.Append(stmt);
DB.Login.CommitTransaction(trans); DB.Login.CommitTransaction(loginTransaction);
// Success AddTransactionCallback(DB.Characters.AsyncCommitTransaction(characterTransaction)).AfterComplete(success =>
SendCharCreate(ResponseCodes.CharCreateSuccess, newChar.GetGUID()); {
if (success)
{
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Create Character: {2} {3}", GetAccountId(), GetRemoteAddress(), createInfo.Name, newChar.GetGUID().ToString());
Global.ScriptMgr.OnPlayerCreate(newChar);
Global.CharacterCacheStorage.AddCharacterCacheEntry(newChar.GetGUID(), GetAccountId(), newChar.GetName(), newChar.m_playerData.NativeSex, (byte)newChar.GetRace(), (byte)newChar.GetClass(), (byte)newChar.GetLevel(), false);
Log.outInfo(LogFilter.Player, "Account: {0} (IP: {1}) Create Character: {2} {3}", GetAccountId(), GetRemoteAddress(), createInfo.Name, newChar.GetGUID().ToString()); SendCharCreate(ResponseCodes.CharCreateSuccess, newChar.GetGUID());
Global.ScriptMgr.OnPlayerCreate(newChar); }
Global.CharacterCacheStorage.AddCharacterCacheEntry(newChar.GetGUID(), GetAccountId(), newChar.GetName(), newChar.m_playerData.NativeSex, (byte)newChar.GetRace(), (byte)newChar.GetClass(), (byte)newChar.GetLevel(), false); else
SendCharCreate(ResponseCodes.CharCreateError);
newChar.CleanupsBeforeDelete(); });
} }
if (!allowTwoSideAccounts || skipCinematics == 1 || createInfo.ClassId == Class.DemonHunter) if (!allowTwoSideAccounts || skipCinematics == 1 || createInfo.ClassId == Class.DemonHunter)
@@ -1021,7 +1027,7 @@ namespace Game
stmt.AddValue(0, request.RenameInfo.Guid.GetCounter()); stmt.AddValue(0, request.RenameInfo.Guid.GetCounter());
stmt.AddValue(1, request.RenameInfo.NewName); stmt.AddValue(1, request.RenameInfo.NewName);
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharRenameCallBack, request.RenameInfo)); _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharRenameCallBack, request.RenameInfo));
} }
void HandleCharRenameCallBack(CharacterRenameInfo renameInfo, SQLResult result) void HandleCharRenameCallBack(CharacterRenameInfo renameInfo, SQLResult result)
@@ -1211,7 +1217,7 @@ namespace Game
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_CUSTOMIZE_INFO); PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_CUSTOMIZE_INFO);
stmt.AddValue(0, packet.CustomizeInfo.CharGUID.GetCounter()); stmt.AddValue(0, packet.CustomizeInfo.CharGUID.GetCounter());
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharCustomizeCallback, packet.CustomizeInfo)); _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharCustomizeCallback, packet.CustomizeInfo));
} }
void HandleCharCustomizeCallback(CharCustomizeInfo customizeInfo, SQLResult result) void HandleCharCustomizeCallback(CharCustomizeInfo customizeInfo, SQLResult result)
@@ -1492,7 +1498,7 @@ namespace Game
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS); PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_RACE_OR_FACTION_CHANGE_INFOS);
stmt.AddValue(0, packet.RaceOrFactionChangeInfo.Guid.GetCounter()); stmt.AddValue(0, packet.RaceOrFactionChangeInfo.Guid.GetCounter());
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharRaceOrFactionChangeCallback, packet.RaceOrFactionChangeInfo)); _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(HandleCharRaceOrFactionChangeCallback, packet.RaceOrFactionChangeInfo));
} }
void HandleCharRaceOrFactionChangeCallback(CharRaceOrFactionChangeInfo factionChangeInfo, SQLResult result) void HandleCharRaceOrFactionChangeCallback(CharRaceOrFactionChangeInfo factionChangeInfo, SQLResult result)
@@ -2045,7 +2051,7 @@ namespace Game
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_LAST_CHAR_UNDELETE); PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_LAST_CHAR_UNDELETE);
stmt.AddValue(0, GetBattlenetAccountId()); stmt.AddValue(0, GetBattlenetAccountId());
_queryProcessor.AddQuery(DB.Login.AsyncQuery(stmt).WithCallback(HandleUndeleteCooldownStatusCallback)); _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(HandleUndeleteCooldownStatusCallback));
} }
void HandleUndeleteCooldownStatusCallback(SQLResult result) void HandleUndeleteCooldownStatusCallback(SQLResult result)
@@ -2076,7 +2082,7 @@ namespace Game
stmt.AddValue(0, GetBattlenetAccountId()); stmt.AddValue(0, GetBattlenetAccountId());
CharacterUndeleteInfo undeleteInfo = undeleteCharacter.UndeleteInfo; CharacterUndeleteInfo undeleteInfo = undeleteCharacter.UndeleteInfo;
_queryProcessor.AddQuery(DB.Login.AsyncQuery(stmt).WithChainingCallback((queryCallback, result) => _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithChainingCallback((queryCallback, result) =>
{ {
if (!result.IsEmpty()) if (!result.IsEmpty())
{ {
+1 -1
View File
@@ -351,7 +351,7 @@ namespace Game
stmt.AddValue(1, PetSaveMode.FirstStableSlot); stmt.AddValue(1, PetSaveMode.FirstStableSlot);
stmt.AddValue(2, PetSaveMode.LastStableSlot); stmt.AddValue(2, PetSaveMode.LastStableSlot);
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(SendStablePetCallback, guid)); _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(SendStablePetCallback, guid));
} }
void SendStablePetCallback(ObjectGuid guid, SQLResult result) void SendStablePetCallback(ObjectGuid guid, SQLResult result)
+1 -1
View File
@@ -188,7 +188,7 @@ namespace Game
{ {
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_GIFT_BY_ITEM); PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_GIFT_BY_ITEM);
stmt.AddValue(0, item.GetGUID().GetCounter()); stmt.AddValue(0, item.GetGUID().GetCounter());
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt) _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt)
.WithCallback(result => HandleOpenWrappedItemCallback(item.GetPos(), item.GetGUID(), result))); .WithCallback(result => HandleOpenWrappedItemCallback(item.GetPos(), item.GetGUID(), result)));
} }
else else
+6 -6
View File
@@ -65,7 +65,7 @@ namespace Game.Network
stmt.AddValue(0, ip_address); stmt.AddValue(0, ip_address);
stmt.AddValue(1, BitConverter.ToUInt32(GetRemoteIpAddress().GetAddressBytes(), 0)); stmt.AddValue(1, BitConverter.ToUInt32(GetRemoteIpAddress().GetAddressBytes(), 0));
_queryProcessor.AddQuery(DB.Login.AsyncQuery(stmt).WithCallback(CheckIpCallback)); _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(CheckIpCallback));
} }
void CheckIpCallback(SQLResult result) void CheckIpCallback(SQLResult result)
@@ -356,7 +356,7 @@ namespace Game.Network
if (!base.Update()) if (!base.Update())
return false; return false;
_queryProcessor.ProcessReadyQueries(); _queryProcessor.ProcessReadyCallbacks();
return true; return true;
} }
@@ -378,7 +378,7 @@ namespace Game.Network
stmt.AddValue(0, Global.WorldMgr.GetRealm().Id.Realm); stmt.AddValue(0, Global.WorldMgr.GetRealm().Id.Realm);
stmt.AddValue(1, authSession.RealmJoinTicket); stmt.AddValue(1, authSession.RealmJoinTicket);
_queryProcessor.AddQuery(DB.Login.AsyncQuery(stmt).WithCallback(HandleAuthSessionCallback, authSession)); _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(HandleAuthSessionCallback, authSession));
} }
void HandleAuthSessionCallback(AuthSession authSession, SQLResult result) void HandleAuthSessionCallback(AuthSession authSession, SQLResult result)
@@ -559,7 +559,7 @@ namespace Game.Network
//if (wardenActive) //if (wardenActive)
//_worldSession.InitWarden(_sessionKey); //_worldSession.InitWarden(_sessionKey);
_queryProcessor.AddQuery(_worldSession.LoadPermissionsAsync().WithCallback(LoadSessionPermissionsCallback)); _queryProcessor.AddCallback(_worldSession.LoadPermissionsAsync().WithCallback(LoadSessionPermissionsCallback));
} }
void LoadSessionPermissionsCallback(SQLResult result) void LoadSessionPermissionsCallback(SQLResult result)
@@ -587,7 +587,7 @@ namespace Game.Network
PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_INFO_CONTINUED_SESSION); PreparedStatement stmt = DB.Login.GetPreparedStatement(LoginStatements.SEL_ACCOUNT_INFO_CONTINUED_SESSION);
stmt.AddValue(0, accountId); stmt.AddValue(0, accountId);
_queryProcessor.AddQuery(DB.Login.AsyncQuery(stmt).WithCallback(HandleAuthContinuedSessionCallback, authSession)); _queryProcessor.AddCallback(DB.Login.AsyncQuery(stmt).WithCallback(HandleAuthContinuedSessionCallback, authSession));
} }
void HandleAuthContinuedSessionCallback(AuthContinuedSession authSession, SQLResult result) void HandleAuthContinuedSessionCallback(AuthContinuedSession authSession, SQLResult result)
@@ -745,7 +745,7 @@ namespace Game.Network
ZLib.z_stream _compressionStream; ZLib.z_stream _compressionStream;
QueryCallbackProcessor _queryProcessor = new QueryCallbackProcessor(); AsyncCallbackProcessor<QueryCallback> _queryProcessor = new AsyncCallbackProcessor<QueryCallback>();
string _ipCountry; string _ipCountry;
} }
+3 -3
View File
@@ -1781,7 +1781,7 @@ namespace Game
{ {
PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_COUNT); PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHARACTER_COUNT);
stmt.AddValue(0, accountId); stmt.AddValue(0, accountId);
_queryProcessor.AddQuery(DB.Characters.AsyncQuery(stmt).WithCallback(_UpdateRealmCharCount)); _queryProcessor.AddCallback(DB.Characters.AsyncQuery(stmt).WithCallback(_UpdateRealmCharCount));
} }
void _UpdateRealmCharCount(SQLResult result) void _UpdateRealmCharCount(SQLResult result)
@@ -2145,7 +2145,7 @@ namespace Game
void ProcessQueryCallbacks() void ProcessQueryCallbacks()
{ {
_queryProcessor.ProcessReadyQueries(); _queryProcessor.ProcessReadyCallbacks();
} }
public void ReloadRBAC() public void ReloadRBAC()
@@ -2324,7 +2324,7 @@ namespace Game
ConcurrentQueue<Tuple<WorldSocket, ulong>> _linkSocketQueue = new ConcurrentQueue<Tuple<WorldSocket, ulong>>(); ConcurrentQueue<Tuple<WorldSocket, ulong>> _linkSocketQueue = new ConcurrentQueue<Tuple<WorldSocket, ulong>>();
QueryCallbackProcessor _queryProcessor = new QueryCallbackProcessor(); AsyncCallbackProcessor<QueryCallback> _queryProcessor = new AsyncCallbackProcessor<QueryCallback>();
Realm _realm; Realm _realm;
+10 -3
View File
@@ -631,7 +631,7 @@ namespace Game
public ulong GetConnectToInstanceKey() { return _instanceConnectKey.Raw; } public ulong GetConnectToInstanceKey() { return _instanceConnectKey.Raw; }
public QueryCallbackProcessor GetQueryProcessor() { return _queryProcessor; } public AsyncCallbackProcessor<QueryCallback> GetQueryProcessor() { return _queryProcessor; }
void SetLogoutStartTime(long requestTime) void SetLogoutStartTime(long requestTime)
{ {
@@ -645,7 +645,8 @@ namespace Game
void ProcessQueryCallbacks() void ProcessQueryCallbacks()
{ {
_queryProcessor.ProcessReadyQueries(); _queryProcessor.ProcessReadyCallbacks();
_transactionCallbacks.ProcessReadyCallbacks();
if (_realmAccountLoginCallback != null && _realmAccountLoginCallback.IsCompleted && _accountLoginCallback != null && _accountLoginCallback.IsCompleted) if (_realmAccountLoginCallback != null && _realmAccountLoginCallback.IsCompleted && _accountLoginCallback != null && _accountLoginCallback.IsCompleted)
{ {
@@ -662,6 +663,11 @@ namespace Game
} }
} }
TransactionCallback AddTransactionCallback(TransactionCallback callback)
{
return _transactionCallbacks.AddCallback(callback);
}
void InitWarden(BigInteger k) void InitWarden(BigInteger k)
{ {
if (_os == "Win") if (_os == "Win")
@@ -896,7 +902,8 @@ namespace Game
Task<SQLQueryHolder<AccountInfoQueryLoad>> _accountLoginCallback; Task<SQLQueryHolder<AccountInfoQueryLoad>> _accountLoginCallback;
Task<SQLQueryHolder<PlayerLoginQueryLoad>> _charLoginCallback; Task<SQLQueryHolder<PlayerLoginQueryLoad>> _charLoginCallback;
QueryCallbackProcessor _queryProcessor = new QueryCallbackProcessor(); AsyncCallbackProcessor<QueryCallback> _queryProcessor = new AsyncCallbackProcessor<QueryCallback>();
AsyncCallbackProcessor<TransactionCallback> _transactionCallbacks = new AsyncCallbackProcessor<TransactionCallback>();
#endregion #endregion
} }