diff --git a/Common/Data/Excel/Rogue3DDailyBuffExcel.cs b/Common/Data/Excel/Rogue3DDailyBuffExcel.cs new file mode 100644 index 0000000..5e4e6b9 --- /dev/null +++ b/Common/Data/Excel/Rogue3DDailyBuffExcel.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +namespace MikuSB.Data.Excel; + +[ResourceEntity("dailybuff.json")] +public class Rogue3DDailyBuffExcel : ExcelResource +{ + [JsonProperty("ID")] public uint Id { get; set; } + [JsonProperty("GroupID")] public uint GroupId { get; set; } + [JsonProperty("ScoreBuffID")] public uint ScoreBuffId { get; set; } + + public override uint GetId() => Id; + + public override void Loaded() + { + GameData.Rogue3DDailyBuffData[Id] = this; + } +} diff --git a/Common/Data/GameData.cs b/Common/Data/GameData.cs index 177f591..96e05cb 100644 --- a/Common/Data/GameData.cs +++ b/Common/Data/GameData.cs @@ -18,6 +18,7 @@ public static class GameData public static Dictionary Rogue3DDifficultData { get; private set; } = []; public static Dictionary Rogue3DSeasonData { get; private set; } = []; public static Dictionary Rogue3DTalentData { get; private set; } = []; + public static Dictionary Rogue3DDailyBuffData { get; private set; } = []; public static Dictionary BreakData { get; private set; } = []; public static Dictionary SpineData { get; private set; } = []; public static Dictionary NodeConditionData { get; private set; } = []; diff --git a/GameServer/Server/CallGS/Handlers/Rogue3D/Rogue3DStateHelper.cs b/GameServer/Server/CallGS/Handlers/Rogue3D/Rogue3DStateHelper.cs index c79119e..390bdb2 100644 --- a/GameServer/Server/CallGS/Handlers/Rogue3D/Rogue3DStateHelper.cs +++ b/GameServer/Server/CallGS/Handlers/Rogue3D/Rogue3DStateHelper.cs @@ -9,10 +9,16 @@ internal static class Rogue3DStateHelper { private const uint GroupId = 124; private const uint LevelPassStart = 20; + private const uint DailyBuffStart = 51; + private const uint DailyBuffEnd = 65; + private const int DailyBuffBitCount = 10; + private const int DailyBuffBitsPerValue = DailyBuffBitCount + 1; + private const uint DailyBuffMask = (1u << DailyBuffBitCount) - 1; private const uint UnlockDiff1Sid = LevelPassStart + 1; private const uint UnlockDiff2Sid = LevelPassStart + 2; private const uint UnlockDiff3Sid = LevelPassStart + 3; private const uint UnlockDiff4Sid = LevelPassStart + 4; + private static uint[]? ShuffledDailyBuffIds; public static NtfSyncPlayer EnsureUnlockState(PlayerInstance player) { @@ -28,6 +34,8 @@ internal static class Rogue3DStateHelper EnsureMinAttr(player, scienceSid, 1, sync); } + EnsureDailyBuffAttrs(player, sync); + return sync; } @@ -40,6 +48,90 @@ internal static class Rogue3DStateHelper .OrderBy(x => x); } + private static void EnsureDailyBuffAttrs(PlayerInstance player, NtfSyncPlayer sync) + { + var buffIds = GetOrCreateDailyBuffIds() + .Take((int)(DailyBuffEnd - DailyBuffStart + 1) * 3) + .ToArray(); + + var index = 0; + for (var sid = DailyBuffStart; sid <= DailyBuffEnd; sid++) + { + uint packed = 0; + for (var slot = 0; slot < 3 && index < buffIds.Length; slot++, index++) + { + packed |= (buffIds[index] & DailyBuffMask) << (slot * DailyBuffBitsPerValue); + } + + SetAttr(player, sid, packed, sync); + } + } + + private static uint[] GetOrCreateDailyBuffIds() + { + if (ShuffledDailyBuffIds != null) + { + return ShuffledDailyBuffIds; + } + + var groupedBuffIds = GameData.Rogue3DDailyBuffData.Values + .Where(x => x.ScoreBuffId > 0 && x.ScoreBuffId <= DailyBuffMask) + .GroupBy(x => x.GroupId) + .OrderBy(x => x.Key) + .Select(x => x + .OrderBy(y => y.Id) + .Select(y => y.ScoreBuffId) + .Distinct() + .ToList()) + .ToList(); + + var random = new Random(); + foreach (var group in groupedBuffIds) + { + Shuffle(group, random); + } + Shuffle(groupedBuffIds, random); + + var buffIds = new List(); + var indexByGroup = new int[groupedBuffIds.Count]; + var hasRemaining = true; + + while (hasRemaining) + { + hasRemaining = false; + for (var i = 0; i < groupedBuffIds.Count; i++) + { + var group = groupedBuffIds[i]; + var index = indexByGroup[i]; + if (index >= group.Count) + { + continue; + } + + buffIds.Add(group[index]); + indexByGroup[i] = index + 1; + hasRemaining = true; + } + } + + ShuffledDailyBuffIds = buffIds.ToArray(); + return ShuffledDailyBuffIds; + } + + private static IEnumerable GetDailyBuffIds() + { + return GetOrCreateDailyBuffIds(); + } + + private static void Shuffle(IList list, Random random) + { + for (var i = list.Count - 1; i > 0; i--) + { + var swapIndex = random.Next(i + 1); + (list[i], list[swapIndex]) = (list[swapIndex], list[i]); + } + } + private static void EnsureMinAttr(PlayerInstance player, uint sid, uint value, NtfSyncPlayer sync, bool overwrite = false) { var attr = player.Data.Attrs.FirstOrDefault(x => x.Gid == GroupId && x.Sid == sid); @@ -60,6 +152,24 @@ internal static class Rogue3DStateHelper AddSync(player, sync, sid, value); } + private static void SetAttr(PlayerInstance player, uint sid, uint value, NtfSyncPlayer sync) + { + var attr = player.Data.Attrs.FirstOrDefault(x => x.Gid == GroupId && x.Sid == sid); + if (attr == null) + { + attr = new PlayerAttr { Gid = GroupId, Sid = sid }; + player.Data.Attrs.Add(attr); + } + + if (attr.Val == value) + { + return; + } + + attr.Val = value; + AddSync(player, sync, sid, value); + } + private static void AddSync(PlayerInstance player, NtfSyncPlayer sync, uint sid, uint value) { sync.Custom[player.ToPackedAttrKey(GroupId, sid)] = value; diff --git a/version.txt b/version.txt index 90e5764..9eb3a97 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -v=1.6 \ No newline at end of file +v=1.7 \ No newline at end of file