Skip to content

Commit e98610d

Browse files
authored
Merge branch 'develop' into develop
2 parents 2dd59df + 2f3323a commit e98610d

23 files changed

Lines changed: 4116 additions & 312 deletions

Arrowgene.Ddon.Database/Sql/Core/DdonSqlDbCharacter.cs

Lines changed: 107 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,30 @@ public partial class DdonSqlDb : SqlDb
9999

100100
private readonly string SqlUpdatePartnerPawnId = "UPDATE \"ddon_character\" SET \"partner_pawn_id\" = @partner_pawn_id WHERE \"character_id\" = @character_id;";
101101

102+
private readonly string SqlSelectAllCompletedQuests =
103+
$"SELECT {BuildQueryField(CompletedQuestsFields)} FROM \"ddon_completed_quests\" WHERE \"character_common_id\" = @character_common_id;";
104+
105+
private static readonly string[] StorageItemFieldsForCharacter = new[]
106+
{
107+
"item_uid", "item_id", "safety", "color", "plus_value", "equip_points"
108+
};
109+
110+
private static readonly string[] CrestFieldsForCharacter = new[]
111+
{
112+
"character_common_id", "item_uid", "slot", "crest_id", "crest_amount"
113+
};
114+
115+
private static readonly string[] EquipmentLimitBreakFieldsForCharacter = new[]
116+
{
117+
"item_uid", "effect_id", "unk1", "effect_type", "unk0"
118+
};
119+
120+
private static readonly string SqlSelectStorageCrestDataByCharacter =
121+
$"SELECT {BuildQueryField(CrestFieldsForCharacter)} FROM \"ddon_crests\" WHERE \"character_common_id\" = @character_common_id;";
122+
123+
private static readonly string SqlSelectStorageLimitBreakByCharacter =
124+
$"SELECT {BuildQueryField(EquipmentLimitBreakFieldsForCharacter)} FROM \"ddon_equipment_limit_break\" WHERE \"character_id\" = @character_id;";
125+
102126
public override bool CreateCharacter(Character character)
103127
{
104128
return ExecuteInTransaction(conn =>
@@ -242,7 +266,7 @@ public override bool DeleteCharacter(uint characterId)
242266

243267
private void QueryCharacterData(DbConnection conn, Character character)
244268
{
245-
QueryCharacterCommonData(conn, character);
269+
QueryCharacterCommonData(conn, character, character.CharacterId);
246270

247271
// Shortcuts
248272
ExecuteReader(conn, SqlSelectShortcuts,
@@ -271,44 +295,78 @@ private void QueryCharacterData(DbConnection conn, Character character)
271295
character.Storage.AddStorage(tuple.Item1, tuple.Item2);
272296
}
273297
});
298+
299+
// Materialize storage item rows before running batch crest/limit-break queries.
300+
var storageRows = new List<(StorageType StorageType, ushort Slot, uint ItemNum, Item Item)>();
274301
ExecuteReader(conn, SqlSelectStorageItemsByCharacter,
275-
(Action<DbCommand>)(command2 => { AddParameter(command2, "@character_id", character.CharacterId); }),
276-
reader2 =>
302+
(Action<DbCommand>)(command => { AddParameter(command, "@character_id", character.CharacterId); }),
303+
reader =>
277304
{
278-
while (reader2.Read())
305+
while (reader.Read())
279306
{
280-
StorageType storageType = (StorageType)GetByte(reader2, "storage_type");
281-
ushort slot = GetUInt16(reader2, "slot_no");
282-
uint itemNum = GetUInt32(reader2, "item_num");
283-
Item item = new();
307+
storageRows.Add((
308+
(StorageType)GetByte(reader, "storage_type"),
309+
GetUInt16(reader, "slot_no"),
310+
GetUInt32(reader, "item_num"),
311+
new Item
312+
{
313+
UId = GetString(reader, "item_uid"),
314+
ItemId = GetUInt32(reader, "item_id"),
315+
SafetySetting = GetByte(reader, "safety"),
316+
Color = GetByte(reader, "color"),
317+
PlusValue = GetByte(reader, "plus_value"),
318+
EquipPoints = GetUInt32(reader, "equip_points")
319+
}
320+
));
321+
}
322+
});
284323

285-
item.UId = GetString(reader2, "item_uid");
286-
item.ItemId = GetUInt32(reader2, "item_id");
287-
item.SafetySetting = GetByte(reader2, "safety");
288-
item.Color = GetByte(reader2, "color");
289-
item.PlusValue = GetByte(reader2, "plus_value");
290-
item.EquipPoints = GetUInt32(reader2, "equip_points");
324+
if (storageRows.Count > 0)
325+
{
326+
var crestMap = new Dictionary<string, List<CDataEquipElementParam>>();
327+
using DbConnection crestConn = OpenNewConnection();
328+
ExecuteReader(crestConn, SqlSelectStorageCrestDataByCharacter,
329+
command => { AddParameter(command, "@character_common_id", character.CommonId); },
330+
reader =>
331+
{
332+
while (reader.Read())
333+
{
334+
string uid = GetString(reader, "item_uid");
335+
if (!crestMap.TryGetValue(uid, out var list))
336+
crestMap[uid] = list = new List<CDataEquipElementParam>();
337+
list.Add(ReadCrestData(reader).ToCDataEquipElementParam());
338+
}
339+
});
291340

292-
using DbConnection connection = OpenNewConnection();
293-
ExecuteReader(connection, SqlSelectAllCrestData,
294-
command4 =>
295-
{
296-
AddParameter(command4, "character_common_id", character.CommonId);
297-
AddParameter(command4, "item_uid", item.UId);
298-
}, reader4 =>
341+
var limitBreakMap = new Dictionary<string, List<CDataAddStatusParam>>();
342+
using DbConnection limitBreakConn = OpenNewConnection();
343+
ExecuteReader(limitBreakConn, SqlSelectStorageLimitBreakByCharacter,
344+
command => { AddParameter(command, "@character_id", character.CharacterId); },
345+
reader =>
346+
{
347+
while (reader.Read())
348+
{
349+
string uid = GetString(reader, "item_uid");
350+
if (!limitBreakMap.TryGetValue(uid, out var list))
351+
limitBreakMap[uid] = list = new List<CDataAddStatusParam>();
352+
list.Add(new CDataAddStatusParam
299353
{
300-
while (reader4.Read())
301-
{
302-
Crest result = ReadCrestData(reader4);
303-
item.EquipElementParamList.Add(result.ToCDataEquipElementParam());
304-
}
354+
EnhanceId = GetUInt16(reader, "effect_id"),
355+
Unk1 = GetUInt16(reader, "unk1"),
356+
EnhanceType = (EquipEnhanceType)GetByte(reader, "effect_type"),
357+
Unk0 = GetByte(reader, "unk0")
305358
});
359+
}
360+
});
306361

307-
item.AddStatusParamList = GetEquipmentLimitBreakRecord(item.UId, connection);
308-
309-
character.Storage.GetStorage(storageType).SetItem(item, itemNum, slot);
310-
}
311-
});
362+
foreach (var (storageType, slot, itemNum, item) in storageRows)
363+
{
364+
if (crestMap.TryGetValue(item.UId, out var crests))
365+
item.EquipElementParamList.AddRange(crests);
366+
item.AddStatusParamList = limitBreakMap.GetValueOrDefault(item.UId, new List<CDataAddStatusParam>());
367+
character.Storage.GetStorage(storageType).SetItem(item, itemNum, slot);
368+
}
369+
}
312370

313371
// Wallet Points
314372
ExecuteReader(conn, SqlSelectWalletPoints,
@@ -350,29 +408,25 @@ private void QueryCharacterData(DbConnection conn, Character character)
350408
while (reader.Read()) character.AbilityPresets.Add(ReadAbilityPreset(reader));
351409
});
352410

353-
// Quest Completion
354-
foreach (QuestType questType in Enum.GetValues<QuestType>())
355-
ExecuteReader(conn, SqlSelectCompletedQuestByType,
356-
command =>
357-
{
358-
AddParameter(command, "@character_common_id", character.CommonId);
359-
AddParameter(command, "@quest_type", (uint)questType);
360-
}, reader =>
411+
// Quest Completion - single query for all types, replaces per-QuestType loop.
412+
// QuestType is read directly from the stored column, identical end result to vanilla.
413+
ExecuteReader(conn, SqlSelectAllCompletedQuests,
414+
command => { AddParameter(command, "@character_common_id", character.CommonId); },
415+
reader =>
416+
{
417+
while (reader.Read())
361418
{
362-
while (reader.Read())
419+
CompletedQuest quest = new()
363420
{
364-
CompletedQuest quest = new()
365-
{
366-
QuestId = (QuestId)GetUInt32(reader, "quest_id"),
367-
QuestType = questType,
368-
ClearCount = GetUInt32(reader, "clear_count")
369-
};
370-
371-
character.CompletedQuests.TryAdd(quest.QuestId, quest);
372-
}
373-
});
421+
QuestId = (QuestId)GetUInt32(reader, "quest_id"),
422+
QuestType = (QuestType)GetUInt32(reader, "quest_type"),
423+
ClearCount = GetUInt32(reader, "clear_count")
424+
};
425+
character.CompletedQuests.TryAdd(quest.QuestId, quest);
426+
}
427+
});
374428

375-
//Clan membership
429+
// Clan membership
376430
character.ClanId = SelectClanMembershipByCharacterId(character.CharacterId, conn);
377431
character.ClanName = GetClanNameByClanId(character.ClanId);
378432

@@ -470,7 +524,7 @@ public override void CreateItems(DbConnection conn, Character character)
470524
continue;
471525

472526
// Give starter weapon for all classes
473-
// If creating a character for normal mode, Wwe are only interested in slot 1 and 2
527+
// If creating a character for normal mode, we are only interested in slot 1 and 2
474528
for (byte i = 0; i < 2; i++)
475529
{
476530
Item item = jobEquipment.Value[EquipType.Performance][i];
@@ -512,7 +566,7 @@ public override void CreateItems(DbConnection conn, Character character)
512566
}
513567
}
514568

515-
//Helper function to add specific items to a storage
569+
// Helper function to add specific items to a storage
516570
public override void CreateListItems(DbConnection conn, Character character, StorageType storageType, List<(uint ItemId, uint Amount)> itemList)
517571
{
518572
Storage itemType = character.Storage.GetAllStorages()[storageType];
@@ -533,11 +587,7 @@ public override Storages SelectAllStoragesByCharacterId(uint characterId)
533587
/// <summary>
534588
/// TODO: Optimize connection handling here and avoid nested loops re-using a single connection which is not supported with Npgsql.
535589
/// Temporary workaround: Open a new connection for each nested read.
536-
///
537590
/// </summary>
538-
/// <param name="connection"></param>
539-
/// <param name="characterId"></param>
540-
/// <returns></returns>
541591
public Storages SelectAllStoragesByCharacterId(DbConnection connection, uint characterId)
542592
{
543593
Storages storages = new(new Dictionary<StorageType, ushort>());
@@ -644,8 +694,6 @@ private Character ReadAllCharacterData(DbDataReader reader)
644694
character.MatchingProfile.Comment = GetString(reader, "comment");
645695
character.MatchingProfile.IsJoinParty = GetBoolean(reader, "is_join_party");
646696

647-
648-
649697
character.FavWarpSlotNum = GetUInt32(reader, "fav_warp_slot_num");
650698

651699
character.MaxBazaarExhibits = GetUInt32(reader, "max_bazaar_exhibits");

0 commit comments

Comments
 (0)