feat(upserver): 接入认证与KV存档并完成限定钓鱼闭环

This commit is contained in:
Liubing\LB
2026-09-28 18:14:01 +08:00
parent f40a816cc4
commit 0eb43b2b40
129 changed files with 11612 additions and 573 deletions

View File

@@ -0,0 +1,969 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
namespace game.PlayerDataStorage
{
internal enum PlayerKVSchemaVerdict { Valid, EmptyNew, EmptyExisting, MissingCore, Malformed, ConflictingRepresentations, UnsupportedSchema, Stale }
internal sealed class PlayerKVProgressPackPair
{
internal PlayerKVProgressPackState Current { get; }
internal PlayerKVProgressPackState Migration { get; }
internal PlayerKVProgressPackPair(PlayerKVProgressPackState current,PlayerKVProgressPackState migration)
{ Current=current; Migration=migration; }
}
internal sealed class PlayerKVDecodedSave
{
readonly object[] modules;
internal string PlayerId { get; }
internal long Epoch { get; }
internal string ConfigurationVersion { get; }
internal IReadOnlyDictionary<string,string> Raw { get; }
internal int ModuleCount => modules.Length;
internal int UnconsumedTopLevelCount { get; }
internal int UnconsumedModernCount { get; }
internal int UnconsumedCount => UnconsumedTopLevelCount+UnconsumedModernCount;
internal PlayerKVDecodedSave(string playerId,long epoch,string version,IReadOnlyDictionary<string,string> raw,object[] modules,int unconsumedTop=0,int unconsumedModern=0)
{
if(modules==null || modules.Length!=31 || modules.Any(m=>m==null)) throw new ArgumentException("Complete decoded save required.");
PlayerId=playerId; Epoch=epoch; ConfigurationVersion=version;
Raw=new ReadOnlyDictionary<string,string>(raw.ToDictionary(p=>p.Key,p=>p.Value,StringComparer.Ordinal));
this.modules=(object[])modules.Clone();
UnconsumedTopLevelCount=unconsumedTop; UnconsumedModernCount=unconsumedModern;
}
internal object Module(int id) { if(id<1 || id>31) throw new ArgumentOutOfRangeException(nameof(id)); return modules[id-1]; }
internal T Module<T>(int id) where T:class => Module(id) as T ?? throw new InvalidOperationException("Module state mismatch.");
}
internal sealed class PlayerKVSchemaResult
{
internal PlayerKVSchemaVerdict Verdict { get; }
internal PlayerKVSchemaDiagnostics Diagnostics { get; }
internal PlayerKVDecodedSave Data { get; }
internal PlayerKVSchemaResult(PlayerKVSchemaVerdict verdict,PlayerKVSchemaDiagnostics diagnostics,PlayerKVDecodedSave data=null)
{ Verdict=verdict; Diagnostics=diagnostics; Data=verdict==PlayerKVSchemaVerdict.Valid ? data : null; }
}
internal enum PlayerKVIdentityChannel { hwGoogle, hwFacebook, hwGuest, hwVkid, Apple, none }
internal sealed class PlayerKVIdentitySnapshot
{
internal string UserId { get; }
internal bool NewlyCreated { get; }
internal PlayerKVIdentityChannel Channel { get; }
internal IReadOnlyList<PlayerKVIdentityChannel> Linked { get; }
internal PlayerKVIdentitySnapshot(string userId,bool newlyCreated,PlayerKVIdentityChannel channel,IEnumerable<PlayerKVIdentityChannel> linked)
{
if(!Enum.IsDefined(typeof(PlayerKVIdentityChannel),channel) || linked==null) throw new ArgumentException("Identity snapshot required.");
var copy=linked.Distinct().ToList();
if(copy.Any(c=>!Enum.IsDefined(typeof(PlayerKVIdentityChannel),c))) throw new ArgumentException("Unknown identity channel.");
UserId=userId; NewlyCreated=newlyCreated; Channel=channel; Linked=copy.AsReadOnly();
}
}
internal sealed class PlayerKVLoginState
{
internal int MMTest { get; }
internal int TapJoyBalance { get; }
internal IReadOnlyDictionary<string,string> AccountUrls { get; }
internal IReadOnlyDictionary<string,string> Normalizations { get; }
internal IReadOnlyList<PlayerKVIdentityChannel> Linked { get; }
internal PlayerKVIdentityChannel Channel { get; }
internal PlayerKVLoginState(int mm,int balance,IDictionary<string,string> urls,IDictionary<string,string> normalizations,
IEnumerable<PlayerKVIdentityChannel> linked,PlayerKVIdentityChannel channel)
{
MMTest=mm; TapJoyBalance=balance;
AccountUrls=new ReadOnlyDictionary<string,string>(new Dictionary<string,string>(urls,StringComparer.Ordinal));
Normalizations=new ReadOnlyDictionary<string,string>(new Dictionary<string,string>(normalizations,StringComparer.Ordinal));
Linked=linked.Distinct().ToList().AsReadOnly(); Channel=channel;
}
}
internal sealed class PlayerKVPartnerBot
{
internal string Id { get; }
internal int ScorePlayer { get; }
internal int ScoreBot { get; }
internal int Grade { get; }
internal int TargetScore { get; }
internal DateTime WakeStartTime { get; }
internal int WakingSeconds { get; }
internal PlayerKVPartnerBot(string id,int player,int bot,int grade,int target,DateTime wake,int seconds)
{ Id=id; ScorePlayer=player; ScoreBot=bot; Grade=grade; TargetScore=target; WakeStartTime=wake; WakingSeconds=seconds; }
}
internal sealed class PlayerKVPartnerState
{
internal bool Present { get; }
internal bool FirstOpen { get; }
internal int EventId { get; }
internal DateTime StartTime { get; }
internal DateTime EndTime { get; }
internal int CurrentPoints { get; }
internal int CurrentMiningProgress { get; }
internal int Token { get; }
internal int InvitedCount { get; }
internal int TicketCount { get; }
internal IReadOnlyList<IReadOnlyList<int>> CompletedNodesList { get; }
internal IReadOnlyList<(int myScore,int FriendScore)> BuilderPartnerScore { get; }
internal float BonusPercent { get; }
internal DateTime BonusExpireUtc { get; }
internal int FreeSpinNum { get; }
internal IReadOnlyDictionary<int,PlayerKVPartnerBot> Bots { get; }
internal bool IsRecvFinalReward { get; }
internal IReadOnlyList<bool> UIFinishedPartners { get; }
internal bool IsFinished { get; }
internal int SpinState { get; }
internal float InflationRate { get; }
internal bool IsEnableAutoMatch { get; }
internal DateTime LastAutoMatchTime { get; }
internal PlayerKVPartnerState(bool present,bool firstOpen,int eventId,DateTime start,DateTime end,
int points,int progress,int token,int invited,int tickets,IEnumerable<IEnumerable<int>> nodes,
IEnumerable<(int,int)> scores,float bonus,DateTime expires,int free,IDictionary<int,PlayerKVPartnerBot> bots,
bool reward,IEnumerable<bool> ui,bool finished,int spin,float inflation,bool autoMatch,DateTime lastMatch)
{
Present=present; FirstOpen=firstOpen; EventId=eventId; StartTime=start; EndTime=end;
CurrentPoints=points; CurrentMiningProgress=progress; Token=token; InvitedCount=invited; TicketCount=tickets;
CompletedNodesList=nodes.Select(n=>(IReadOnlyList<int>)new List<int>(n).AsReadOnly()).ToList().AsReadOnly();
BuilderPartnerScore=new List<(int,int)>(scores).AsReadOnly(); BonusPercent=bonus; BonusExpireUtc=expires;
FreeSpinNum=free; Bots=new ReadOnlyDictionary<int,PlayerKVPartnerBot>(new Dictionary<int,PlayerKVPartnerBot>(bots));
IsRecvFinalReward=reward; UIFinishedPartners=new List<bool>(ui).AsReadOnly(); IsFinished=finished;
SpinState=spin; InflationRate=inflation; IsEnableAutoMatch=autoMatch; LastAutoMatchTime=lastMatch;
}
internal static PlayerKVPartnerState Missing() => new PlayerKVPartnerState(false,false,0,default,default,
0,0,0,0,0,Array.Empty<int[]>(),Array.Empty<(int,int)>(),0,default,0,new Dictionary<int,PlayerKVPartnerBot>(),
false,Array.Empty<bool>(),false,0,0,false,default);
}
internal enum PlayerKVSchemaError { Malformed, MissingCore, ConflictingRepresentations, UnsupportedSchema }
internal sealed class PlayerKVSchemaException : Exception
{
internal PlayerKVSchemaError Code { get; }
internal PlayerKVSchemaException(PlayerKVSchemaError code = PlayerKVSchemaError.Malformed)
: base("KV schema rejected.") { Code = code; }
}
internal sealed class PlayerKVSchemaDetail
{
internal int Module { get; }
internal int Field { get; }
internal PlayerKVSchemaError Code { get; }
internal PlayerKVSchemaDetail(int module, int field, PlayerKVSchemaError code)
{ Module = module; Field = field; Code = code; }
}
// Values, save keys and exception messages are deliberately absent from diagnostic output.
internal sealed class PlayerKVSchemaDiagnostics
{
readonly List<PlayerKVSchemaDetail> details = new List<PlayerKVSchemaDetail>();
readonly SortedDictionary<int, Dictionary<PlayerKVSchemaError, int>> counts =
new SortedDictionary<int, Dictionary<PlayerKVSchemaError, int>>();
internal int TotalErrors { get; private set; }
internal int OmittedDetails => TotalErrors - details.Count;
internal IReadOnlyList<PlayerKVSchemaDetail> Details => details.AsReadOnly();
internal int Count(int module, PlayerKVSchemaError code) =>
counts.TryGetValue(module, out var codes) && codes.TryGetValue(code, out var count) ? count : 0;
internal void Add(int module, int field, PlayerKVSchemaError code)
{
if (module < 1 || module > 31 || field < 0) throw new ArgumentOutOfRangeException();
TotalErrors++;
if (!counts.TryGetValue(module, out var codes)) counts.Add(module, codes = new Dictionary<PlayerKVSchemaError, int>());
codes[code] = Count(module, code) + 1;
// Only retain 32 items, even when callers visit representations in different orders.
var item = new PlayerKVSchemaDetail(module, field, code);
int index = details.FindIndex(x => x.Module > module || (x.Module == module && x.Field > field));
if (index < 0) index = details.Count;
if (index < 32) details.Insert(index, item);
if (details.Count > 32) details.RemoveAt(32);
}
internal T Capture<T>(int module, int field, Func<T> parse)
{
try { return parse(); }
catch (PlayerKVSchemaException ex) { Add(module, field, ex.Code); return default; }
}
}
// Captured copies only: decoding never resolves Unity services or reads current culture/time.
internal sealed class PlayerKVSchemaSnapshot
{
readonly HashSet<int> rods, maps;
readonly IReadOnlyDictionary<int, int> packTypes;
readonly IReadOnlyDictionary<int, PlayerKVEventConfig> events;
readonly IReadOnlyDictionary<string, int> conditions;
readonly HashSet<int> conditionValues;
readonly IReadOnlyDictionary<int,PlayerKVFishConfig> fish;
readonly IReadOnlyDictionary<int,PlayerKVFishCardConfig> cards;
internal string Version { get; }
internal CultureInfo Culture { get; }
internal DateTime NowUtc { get; }
internal DateTime NowGame { get; }
internal int InitWheelTicket { get; }
internal PlayerKVSchemaSnapshot(string version, IEnumerable<int> rods, IEnumerable<int> maps,
IDictionary<string, int> conditions, CultureInfo culture, DateTime nowUtc, int initWheelTicket,
IDictionary<int, int> packTypes = null, IDictionary<int, PlayerKVEventConfig> events = null, int globalTimeOffset = 0,
IDictionary<int,PlayerKVFishConfig> fish = null, IDictionary<int,PlayerKVFishCardConfig> cards = null)
{
if (string.IsNullOrEmpty(version) || rods == null || maps == null || conditions == null || culture == null)
throw new ArgumentException("Schema snapshot required.");
Version = version; this.rods = new HashSet<int>(rods); this.maps = new HashSet<int>(maps);
this.packTypes = new ReadOnlyDictionary<int, int>(new Dictionary<int, int>(packTypes ?? new Dictionary<int, int>()));
this.events = new ReadOnlyDictionary<int, PlayerKVEventConfig>(new Dictionary<int, PlayerKVEventConfig>(events ?? new Dictionary<int, PlayerKVEventConfig>()));
this.conditions = new ReadOnlyDictionary<string, int>(new Dictionary<string, int>(conditions, StringComparer.Ordinal));
conditionValues = new HashSet<int>(conditions.Values);
Culture = CultureInfo.ReadOnly((CultureInfo)culture.Clone()); NowUtc = nowUtc; InitWheelTicket = initWheelTicket;
NowGame = nowUtc.AddHours(-(double)globalTimeOffset);
this.fish=new ReadOnlyDictionary<int,PlayerKVFishConfig>(new Dictionary<int,PlayerKVFishConfig>(fish ?? new Dictionary<int,PlayerKVFishConfig>()));
this.cards=new ReadOnlyDictionary<int,PlayerKVFishCardConfig>(new Dictionary<int,PlayerKVFishCardConfig>(cards ?? new Dictionary<int,PlayerKVFishCardConfig>()));
}
internal PlayerKVFishConfig Fish(int id) => fish.TryGetValue(id,out var value) ? value : null;
internal PlayerKVFishCardConfig Card(int id) => cards.TryGetValue(id,out var value) ? value : null;
internal bool HasRod(int id) => rods.Contains(id);
internal bool HasPack(int id) => packTypes.ContainsKey(id);
internal PlayerKVEventConfig Event(int id) => events.TryGetValue(id,out var value) ? value : null;
internal bool HasPackType(int id, int type) => packTypes.TryGetValue(id, out var actual) && actual == type;
internal bool HasMap(int id) => maps.Contains(id);
internal int Condition(string text)
{
if (conditions.TryGetValue(text, out var named)) return named;
if (int.TryParse(text, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out var numeric)
&& conditionValues.Contains(numeric)) return numeric;
throw new PlayerKVSchemaException();
}
}
internal sealed class PlayerKVCoreState
{
readonly object[] slots;
internal PlayerKVCoreState(object[] slots) { this.slots = (object[])slots.Clone(); }
internal int Integer(int slot) => (int)slots[slot];
internal ulong Unsigned(int slot) => (ulong)slots[slot];
internal DateTime EnergyTime => (DateTime)slots[7];
internal bool Matches(int slot, object value) => Equals(slots[slot], value);
}
internal sealed class PlayerKVAchievementValue
{
internal int Id { get; }
internal ulong Target { get; }
internal int Day { get; }
internal PlayerKVAchievementValue(int id, ulong target, int day) { Id = id; Target = target; Day = day; }
internal bool Same(PlayerKVAchievementValue other) => Id == other.Id && Target == other.Target && Day == other.Day;
}
internal sealed class PlayerKVAchievementState
{
internal IReadOnlyDictionary<int, PlayerKVAchievementValue> Values { get; }
internal PlayerKVAchievementState(IDictionary<int, PlayerKVAchievementValue> values)
{ Values = new ReadOnlyDictionary<int, PlayerKVAchievementValue>(new Dictionary<int, PlayerKVAchievementValue>(values)); }
}
internal sealed class PlayerKVPiggyBankState
{
internal bool IsPresent { get; }
internal int currentEventID { get; }
internal int purchaseCount { get; }
internal int VIPLvlWhenEventActivate { get; }
internal int savingProgress { get; }
internal int redirectID { get; }
internal bool doNeedTrigger { get; }
internal bool isTriggered { get; }
internal float inflation { get; }
internal PlayerKVPiggyBankState(bool present, int currentEventID, int purchaseCount, int VIPLvlWhenEventActivate, int savingProgress, int redirectID, bool doNeedTrigger, bool isTriggered, float inflation)
{
IsPresent = present;
this.currentEventID = currentEventID;
this.purchaseCount = purchaseCount;
this.VIPLvlWhenEventActivate = VIPLvlWhenEventActivate;
this.savingProgress = savingProgress;
this.redirectID = redirectID;
this.doNeedTrigger = doNeedTrigger;
this.isTriggered = isTriggered;
this.inflation = inflation;
}
internal static PlayerKVPiggyBankState Missing() => new PlayerKVPiggyBankState(false, 0, 0, 0, 0, 0, false, false, 0);
}
internal sealed class PlayerKVBargainState
{
internal bool IsPresent { get; }
internal int currentEventID { get; }
internal int redirectID { get; }
internal int VIPLvlWhenEventActivate { get; }
internal int purchaseCount { get; }
internal int savingProgress { get; }
internal int discountLvl { get; }
internal int visualProgress { get; }
internal int visualDiscountLvl { get; }
internal int rodID { get; }
internal int lastPackIDBought { get; }
internal int packID { get; }
internal bool doNeedTrigger { get; }
internal bool isTriggered { get; }
internal float inflation { get; }
internal IReadOnlyList<int> selections { get; }
internal PlayerKVBargainState(bool present, int currentEventID, int redirectID, int VIPLvlWhenEventActivate, int purchaseCount, int savingProgress, int discountLvl, int visualProgress, int visualDiscountLvl, int rodID, int lastPackIDBought, int packID, bool doNeedTrigger, bool isTriggered, float inflation, IEnumerable<int> selections)
{
IsPresent = present;
this.currentEventID = currentEventID;
this.redirectID = redirectID;
this.VIPLvlWhenEventActivate = VIPLvlWhenEventActivate;
this.purchaseCount = purchaseCount;
this.savingProgress = savingProgress;
this.discountLvl = discountLvl;
this.visualProgress = visualProgress;
this.visualDiscountLvl = visualDiscountLvl;
this.rodID = rodID;
this.lastPackIDBought = lastPackIDBought;
this.packID = packID;
this.doNeedTrigger = doNeedTrigger;
this.isTriggered = isTriggered;
this.inflation = inflation;
this.selections = selections == null ? null : new List<int>(selections).AsReadOnly();
}
internal static PlayerKVBargainState Missing() => new PlayerKVBargainState(false, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, false, false, 0, Array.Empty<int>());
}
internal sealed class PlayerKVShootingRangeState
{
internal bool IsPresent { get; }
internal int EventId { get; }
internal int CycleId { get; }
internal int RedirectId { get; }
internal int AmmoCount { get; }
internal int CurrentStageIdx { get; }
internal int ChainProgress { get; }
internal long RewardFlag { get; }
internal long TargetFlag { get; }
internal bool HasBeenOpened { get; }
internal float Inflation { get; }
internal PlayerKVShootingRangeState(bool present, int EventId, int CycleId, int RedirectId, int AmmoCount, int CurrentStageIdx, int ChainProgress, long RewardFlag, long TargetFlag, bool HasBeenOpened, float Inflation)
{
IsPresent = present;
this.EventId = EventId;
this.CycleId = CycleId;
this.RedirectId = RedirectId;
this.AmmoCount = AmmoCount;
this.CurrentStageIdx = CurrentStageIdx;
this.ChainProgress = ChainProgress;
this.RewardFlag = RewardFlag;
this.TargetFlag = TargetFlag;
this.HasBeenOpened = HasBeenOpened;
this.Inflation = Inflation;
}
internal static PlayerKVShootingRangeState Missing() => new PlayerKVShootingRangeState(false, 0, 0, 0, 0, 0, 0, 0, 0, false, 0);
}
internal sealed class PlayerKVBuffValue
{
internal int SortID { get; }
internal int sourceID { get; }
internal int buffID { get; }
internal bool isEnd { get; }
internal DateTime buffEndTime { get; }
internal PlayerKVBuffValue(int SortID,int sourceID,int buffID,bool isEnd,DateTime buffEndTime)
{ this.SortID=SortID; this.sourceID=sourceID; this.buffID=buffID; this.isEnd=isEnd; this.buffEndTime=buffEndTime; }
}
internal sealed class PlayerKVTriggerValue
{
internal int ID { get; }
internal int index { get; }
internal int lastID { get; }
internal int vipLevel { get; }
internal int mapID { get; }
internal string time { get; }
internal PlayerKVTriggerValue(int ID,int index,int lastID,int vipLevel,int mapID,string time)
{ this.ID=ID; this.index=index; this.lastID=lastID; this.vipLevel=vipLevel; this.mapID=mapID; this.time=time; }
}
internal sealed class PlayerKVGiftVipValue
{
internal int oldVipLevel { get; }
internal int curVipLevel { get; }
internal int timer { get; }
internal PlayerKVGiftVipValue(int oldVipLevel,int curVipLevel,int timer)
{ this.oldVipLevel=oldVipLevel; this.curVipLevel=curVipLevel; this.timer=timer; }
}
internal sealed class PlayerKVFixedTimeValue
{
internal int id { get; }
internal string endTime { get; }
internal PlayerKVFixedTimeValue(int id,string endTime)
{ this.id=id; this.endTime=endTime; }
}
internal sealed class PlayerKVBuffState
{
internal IReadOnlyDictionary<int,PlayerKVBuffValue> Map { get; }
internal IReadOnlyDictionary<int,PlayerKVBuffValue> Global { get; }
internal IReadOnlyList<PlayerKVBuffValue> Target { get; }
internal PlayerKVBuffValue Daily { get; }
internal PlayerKVBuffState(IDictionary<int,PlayerKVBuffValue> map,IDictionary<int,PlayerKVBuffValue> global,
IEnumerable<PlayerKVBuffValue> target,PlayerKVBuffValue daily)
{
Map=new ReadOnlyDictionary<int,PlayerKVBuffValue>(new Dictionary<int,PlayerKVBuffValue>(map));
Global=new ReadOnlyDictionary<int,PlayerKVBuffValue>(new Dictionary<int,PlayerKVBuffValue>(global));
Target=new List<PlayerKVBuffValue>(target).AsReadOnly(); Daily=daily;
}
}
internal sealed class PlayerKVTriggerState
{
internal IReadOnlyList<PlayerKVTriggerValue> Packs { get; }
internal IReadOnlyDictionary<string,PlayerKVGiftVipValue> Gifts { get; }
internal IReadOnlyDictionary<int,PlayerKVFixedTimeValue> Fixed { get; }
internal PlayerKVTriggerState(IEnumerable<PlayerKVTriggerValue> packs,IDictionary<string,PlayerKVGiftVipValue> gifts,
IDictionary<int,PlayerKVFixedTimeValue> fixedValues)
{
Packs=new List<PlayerKVTriggerValue>(packs).AsReadOnly();
Gifts=new ReadOnlyDictionary<string,PlayerKVGiftVipValue>(new Dictionary<string,PlayerKVGiftVipValue>(gifts,StringComparer.Ordinal));
Fixed=new ReadOnlyDictionary<int,PlayerKVFixedTimeValue>(new Dictionary<int,PlayerKVFixedTimeValue>(fixedValues));
}
}
internal sealed class PlayerKVPlayerState
{
internal PlayerKVCoreState Core { get; }
internal IReadOnlyDictionary<string,string> Modern { get; }
internal IReadOnlyDictionary<int,int> VipScores { get; }
internal IReadOnlyList<int> NewRods { get; }
internal int Season { get; }
internal bool Appraise { get; }
internal string Building { get; }
internal PlayerKVPlayerState(PlayerKVCoreState core,IDictionary<string,string> modern,IDictionary<int,int> scores,
IEnumerable<int> rods,int season,bool appraise,string building)
{
Core=core; Modern=new ReadOnlyDictionary<string,string>(new Dictionary<string,string>(modern,StringComparer.Ordinal));
VipScores=new ReadOnlyDictionary<int,int>(new Dictionary<int,int>(scores)); NewRods=new List<int>(rods).AsReadOnly();
Season=season; Appraise=appraise; Building=building;
}
}
internal sealed class PlayerKVPotionItem
{
internal string Name { get; }
internal int Index { get; }
internal bool IsOver { get; }
internal int DataType { get; }
internal IReadOnlyList<int> Colors { get; }
internal IReadOnlyList<int> Shelves { get; }
internal IReadOnlyList<int> Grids { get; }
internal IReadOnlyList<int> FromDisplay { get; }
internal PlayerKVPotionItem(string name,int index,bool over,int type,IEnumerable<int> colors,
IEnumerable<int> shelves,IEnumerable<int> grids,IEnumerable<int> fromDisplay)
{
Name=name; Index=index; IsOver=over; DataType=type;
Colors=new List<int>(colors).AsReadOnly(); Shelves=new List<int>(shelves).AsReadOnly();
Grids=new List<int>(grids).AsReadOnly(); FromDisplay=new List<int>(fromDisplay).AsReadOnly();
}
}
internal sealed class PlayerKVPotionState
{
internal bool IsPresent { get; }
internal int EventID { get; }
internal int PotionID { get; }
internal int StageID { get; }
internal int Stage1TotalLevel { get; }
internal int Stage2TotalLevel { get; }
internal int LevelID { get; }
internal int LevelIndex { get; }
internal int CorrectNum { get; }
internal int SubmitNum { get; }
internal int Token { get; }
internal int ConsumedToken { get; }
internal int Rule { get; }
internal int PreEventID { get; }
internal int PrePotionID { get; }
internal int PreStageID { get; }
internal int PreLevelID { get; }
internal int Round { get; }
internal int FirstPlayedEventId { get; }
internal bool IsOver { get; }
internal string Name { get; }
internal float InflationRate { get; }
internal PlayerKVPotionItem LevelTargetData { get; }
internal PlayerKVPotionItem LevelDisplayData { get; }
internal IReadOnlyList<PlayerKVPotionItem> LevelProcessedList { get; }
internal PlayerKVPotionState(bool present,int EventID,int PotionID,int StageID,int Stage1TotalLevel,int Stage2TotalLevel,int LevelID,int LevelIndex,int CorrectNum,int SubmitNum,int Token,int ConsumedToken,int Rule,int PreEventID,int PrePotionID,int PreStageID,int PreLevelID,int Round,int FirstPlayedEventId,bool IsOver,string Name,float InflationRate,PlayerKVPotionItem LevelTargetData,PlayerKVPotionItem LevelDisplayData,List<PlayerKVPotionItem> LevelProcessedList)
{
IsPresent=present;
this.EventID=EventID;
this.PotionID=PotionID;
this.StageID=StageID;
this.Stage1TotalLevel=Stage1TotalLevel;
this.Stage2TotalLevel=Stage2TotalLevel;
this.LevelID=LevelID;
this.LevelIndex=LevelIndex;
this.CorrectNum=CorrectNum;
this.SubmitNum=SubmitNum;
this.Token=Token;
this.ConsumedToken=ConsumedToken;
this.Rule=Rule;
this.PreEventID=PreEventID;
this.PrePotionID=PrePotionID;
this.PreStageID=PreStageID;
this.PreLevelID=PreLevelID;
this.Round=Round;
this.FirstPlayedEventId=FirstPlayedEventId;
this.IsOver=IsOver;
this.Name=Name;
this.InflationRate=InflationRate;
this.LevelTargetData=LevelTargetData;
this.LevelDisplayData=LevelDisplayData;
this.LevelProcessedList=new List<PlayerKVPotionItem>(LevelProcessedList).AsReadOnly();
}
internal static PlayerKVPotionState Missing() => new PlayerKVPotionState(false,default,default,default,default,default,default,default,default,default,default,default,default,default,default,default,default,default,default,default,default,default,default,default,new List<PlayerKVPotionItem>());
}
internal sealed class PlayerKVPassRecord
{
internal int ID { get; }
internal int Level { get; }
internal int Exp { get; }
internal int BuyVipToastIndex { get; }
internal int IsUnlockVip { get; }
internal IReadOnlyList<int> Normal { get; }
internal IReadOnlyList<int> Vip { get; }
internal IReadOnlyList<int> LastDrops { get; }
internal float Inflation { get; }
internal PlayerKVPassRecord(int id,int level,int exp,int toast,int unlock,IEnumerable<int> normal,
IEnumerable<int> vip,IEnumerable<int> lastDrops,float inflation)
{
ID=id; Level=level; Exp=exp; BuyVipToastIndex=toast; IsUnlockVip=unlock;
Normal=new List<int>(normal).AsReadOnly(); Vip=new List<int>(vip).AsReadOnly();
LastDrops=new List<int>(lastDrops).AsReadOnly(); Inflation=inflation;
}
internal bool CommonEquals(PlayerKVPassRecord other) => ID==other.ID && Level==other.Level && Exp==other.Exp &&
BuyVipToastIndex==other.BuyVipToastIndex && IsUnlockVip==other.IsUnlockVip && Normal.SequenceEqual(other.Normal) && Vip.SequenceEqual(other.Vip);
internal static PlayerKVPassRecord Empty() => new PlayerKVPassRecord(0,1,0,0,0,Array.Empty<int>(),Array.Empty<int>(),Array.Empty<int>(),0);
}
internal sealed class PlayerKVPassTask
{
internal IReadOnlyDictionary<int,int> Daily { get; }
internal IReadOnlyDictionary<int,int> Weekly { get; }
internal IReadOnlyList<int> LoginDays { get; }
internal DateTime DailyEnd { get; }
internal DateTime WeeklyEnd { get; }
internal PlayerKVPassTask(IDictionary<int,int> daily,IDictionary<int,int> weekly,IEnumerable<int> days,DateTime dailyEnd,DateTime weeklyEnd)
{
Daily=new ReadOnlyDictionary<int,int>(new Dictionary<int,int>(daily)); Weekly=new ReadOnlyDictionary<int,int>(new Dictionary<int,int>(weekly));
LoginDays=new List<int>(days).AsReadOnly(); DailyEnd=dailyEnd; WeeklyEnd=weeklyEnd;
}
internal bool Same(PlayerKVPassTask other) => Daily.Count==other.Daily.Count && Weekly.Count==other.Weekly.Count &&
Daily.All(p=>other.Daily.TryGetValue(p.Key,out var value) && value==p.Value) &&
Weekly.All(p=>other.Weekly.TryGetValue(p.Key,out var value) && value==p.Value) &&
LoginDays.SequenceEqual(other.LoginDays) && DailyEnd==other.DailyEnd && WeeklyEnd==other.WeeklyEnd;
internal static PlayerKVPassTask Empty() => new PlayerKVPassTask(new Dictionary<int,int>(),new Dictionary<int,int>(),Array.Empty<int>(),default,default);
}
internal sealed class PlayerKVBattlePassState
{
internal PlayerKVPassRecord Record { get; }
internal PlayerKVPassTask Task { get; }
internal PlayerKVBattlePassState(PlayerKVPassRecord record,PlayerKVPassTask task) { Record=record; Task=task; }
}
internal sealed class PlayerKVCollectValue
{
internal int ItemId { get; }
internal int Count { get; }
internal int MaxCount { get; }
internal int ItemTrueId { get; }
internal PlayerKVCollectValue(int itemId,int count,int maxCount,int trueId)
{ ItemId=itemId; Count=count; MaxCount=maxCount; ItemTrueId=trueId; }
}
internal sealed class PlayerKVCubeState
{
internal bool IsPresent { get; }
internal int TicketCount { get; }
internal bool FirstOpen { get; }
internal bool IsFinished { get; }
internal int EventId { get; }
internal bool IsInGuide { get; }
internal DateTime StartTime { get; }
internal DateTime EndTime { get; }
internal int CurrentStagetId { get; }
internal IReadOnlyList<PlayerKVCollectValue> CollectItems { get; }
internal IReadOnlyList<int> BoardData { get; }
internal int Width { get; }
internal int Height { get; }
internal IReadOnlyList<int> CollectRewardsId { get; }
internal bool IsFinalRewardGet { get; }
internal IReadOnlyList<IReadOnlyList<int>> PieceDatas { get; }
internal int Cycle { get; }
internal float InflationRate { get; }
internal PlayerKVCubeState(bool present,int ticketCount,bool firstOpen,bool finished,int eventId,bool guide,
DateTime start,DateTime end,int stage,IEnumerable<PlayerKVCollectValue> items,IEnumerable<int> board,
int width,int height,IEnumerable<int> rewards,bool final,IEnumerable<IEnumerable<int>> pieces,int cycle,float inflation)
{
IsPresent=present; TicketCount=ticketCount; FirstOpen=firstOpen; IsFinished=finished; EventId=eventId; IsInGuide=guide;
StartTime=start; EndTime=end; CurrentStagetId=stage; CollectItems=new List<PlayerKVCollectValue>(items).AsReadOnly();
BoardData=new List<int>(board).AsReadOnly(); Width=width; Height=height; CollectRewardsId=new List<int>(rewards).AsReadOnly();
IsFinalRewardGet=final; PieceDatas=pieces.Select(p=>(IReadOnlyList<int>)new List<int>(p).AsReadOnly()).ToList().AsReadOnly();
Cycle=cycle; InflationRate=inflation;
}
internal static PlayerKVCubeState Missing() => new PlayerKVCubeState(false,0,false,false,0,false,default,default,0,
Array.Empty<PlayerKVCollectValue>(),Array.Empty<int>(),0,0,Array.Empty<int>(),false,Array.Empty<IEnumerable<int>>(),0,0);
}
internal sealed class PlayerKVPinataState
{
internal int EventID { get; }
internal int PinataMainID { get; }
internal int PurchasedCount { get; }
internal PlayerKVPinataState(int eventId,int mainId,int count) { EventID=eventId; PinataMainID=mainId; PurchasedCount=count; }
}
internal sealed class PlayerKVEmptyModuleState
{
internal static readonly PlayerKVEmptyModuleState Instance=new PlayerKVEmptyModuleState();
private PlayerKVEmptyModuleState() { }
}
internal sealed class PlayerKVStampValue
{
internal int EventScratchCardID { get; }
internal int Count { get; }
internal PlayerKVStampValue(int id,int count) { EventScratchCardID=id; Count=count; }
}
internal sealed class PlayerKVChallengeState
{
internal bool IsPresent { get; }
/// <summary>Internal in-memory representation of a present JSON null; not serialized to the server.</summary>
internal bool IsExplicitNull { get; }
internal bool FirstOpen { get; }
internal int EventId { get; }
internal int RankTierLevel { get; }
internal int Finished { get; }
internal int RedirectID { get; }
internal int Score { get; }
internal int ProcessedScore { get; }
internal int step { get; }
internal int uiStep { get; }
internal int index { get; }
internal DateTime StartTime { get; }
internal DateTime EndTime { get; }
internal IReadOnlyList<int> eliminateNumber { get; }
internal IReadOnlyList<int> robotAccountList { get; }
internal float InflationRate { get; }
internal PlayerKVChallengeState(bool present,bool FirstOpen,int EventId,int RankTierLevel,int Finished,int RedirectID,int Score,int ProcessedScore,int step,int uiStep,int index,DateTime StartTime,DateTime EndTime,List<int> eliminateNumber,List<int> robotAccountList,float InflationRate,bool explicitNull=false)
{
if (explicitNull && !present) throw new ArgumentException("An explicit null must have a present key.", nameof(explicitNull));
IsPresent=present;
IsExplicitNull=explicitNull;
this.FirstOpen=FirstOpen;
this.EventId=EventId;
this.RankTierLevel=RankTierLevel;
this.Finished=Finished;
this.RedirectID=RedirectID;
this.Score=Score;
this.ProcessedScore=ProcessedScore;
this.step=step;
this.uiStep=uiStep;
this.index=index;
this.StartTime=StartTime;
this.EndTime=EndTime;
this.eliminateNumber=new List<int>(eliminateNumber).AsReadOnly();
this.robotAccountList=new List<int>(robotAccountList).AsReadOnly();
this.InflationRate=InflationRate;
}
internal static PlayerKVChallengeState Missing() => new PlayerKVChallengeState(false,default,default,default,default,default,default,default,default,default,default,default,default,new List<int>(),new List<int>(),default);
/// <summary>Creates an internal empty-state marker, not a server serialization payload.</summary>
internal static PlayerKVChallengeState ExplicitNull() => new PlayerKVChallengeState(true,default,default,default,default,default,default,default,default,default,default,default,default,new List<int>(),new List<int>(),default,true);
}
internal sealed class PlayerKVPinballState
{
internal bool IsPresent { get; }
internal int EventID { get; }
internal int PinballMainID { get; }
internal int SpinPoint { get; }
internal int Scores { get; }
internal int Multiple { get; }
internal int Token { get; }
internal int ConsumedToken { get; }
internal int RewardIndex { get; }
internal float Force { get; }
internal float LuckyValue { get; }
internal float InflationRate { get; }
internal PlayerKVPinballState(bool present,int EventID,int PinballMainID,int SpinPoint,int Scores,int Multiple,int Token,int ConsumedToken,int RewardIndex,float Force,float LuckyValue,float InflationRate)
{
IsPresent=present;
this.EventID=EventID;
this.PinballMainID=PinballMainID;
this.SpinPoint=SpinPoint;
this.Scores=Scores;
this.Multiple=Multiple;
this.Token=Token;
this.ConsumedToken=ConsumedToken;
this.RewardIndex=RewardIndex;
this.Force=Force;
this.LuckyValue=LuckyValue;
this.InflationRate=InflationRate;
}
internal static PlayerKVPinballState Missing() => new PlayerKVPinballState(false,default,default,default,default,default,default,default,default,default,default,default);
}
internal sealed class PlayerKVScratchState
{
internal bool IsPresent { get; }
internal int EventID { get; }
internal int ScratchMainID { get; }
internal int ChainPackID { get; }
internal int Token { get; }
internal int ConsumedToken { get; }
internal int RewardTaskConsumedToken { get; }
internal int EventScratchRewardTaskID { get; }
internal int EventScratchCardID { get; }
internal int TotalConsumedToken { get; }
internal int ChainPackProgress { get; }
internal int magIndex { get; }
internal bool IsOver { get; }
internal float LuckyValue { get; }
internal float InflationRate { get; }
internal IReadOnlyList<int> StampRewardList { get; }
internal IReadOnlyDictionary<int,PlayerKVStampValue> StampRewardDict { get; }
internal PlayerKVScratchState(bool present,int EventID,int ScratchMainID,int ChainPackID,int Token,int ConsumedToken,int RewardTaskConsumedToken,int EventScratchRewardTaskID,int EventScratchCardID,int TotalConsumedToken,int ChainPackProgress,int magIndex,bool IsOver,float LuckyValue,float InflationRate,List<int> StampRewardList,Dictionary<int,PlayerKVStampValue> StampRewardDict)
{
IsPresent=present;
this.EventID=EventID;
this.ScratchMainID=ScratchMainID;
this.ChainPackID=ChainPackID;
this.Token=Token;
this.ConsumedToken=ConsumedToken;
this.RewardTaskConsumedToken=RewardTaskConsumedToken;
this.EventScratchRewardTaskID=EventScratchRewardTaskID;
this.EventScratchCardID=EventScratchCardID;
this.TotalConsumedToken=TotalConsumedToken;
this.ChainPackProgress=ChainPackProgress;
this.magIndex=magIndex;
this.IsOver=IsOver;
this.LuckyValue=LuckyValue;
this.InflationRate=InflationRate;
this.StampRewardList=new List<int>(StampRewardList).AsReadOnly();
this.StampRewardDict=new ReadOnlyDictionary<int,PlayerKVStampValue>(new Dictionary<int,PlayerKVStampValue>(StampRewardDict));
}
internal static PlayerKVScratchState Missing() => new PlayerKVScratchState(false,default,default,default,default,default,default,default,default,default,default,default,default,default,default,new List<int>(),new Dictionary<int,PlayerKVStampValue>());
}
internal sealed class PlayerKVOfferItem
{
internal int Id { get; }
internal int Item { get; }
internal int Number { get; }
internal int Status { get; }
internal PlayerKVOfferItem(int id,int item,int number,int status) { Id=id; Item=item; Number=number; Status=status; }
}
internal sealed class PlayerKVOfferState
{
internal bool IsPresent { get; }
internal bool FirstOpen { get; }
internal int EventId { get; }
internal DateTime StartTime { get; }
internal DateTime EndTime { get; }
internal int ItemId { get; }
internal int LotteryNum { get; }
internal IReadOnlyList<PlayerKVOfferItem> Items { get; }
internal IReadOnlyList<int> RewardList { get; }
internal bool Finished { get; }
internal int ChestReward { get; }
internal PlayerKVOfferState(bool present,bool firstOpen,int eventId,DateTime startTime,DateTime endTime,
int itemId,int lotteryNum,IEnumerable<PlayerKVOfferItem> items,IEnumerable<int> rewardList,bool finished,int chestReward)
{
IsPresent=present; FirstOpen=firstOpen; EventId=eventId; StartTime=startTime; EndTime=endTime;
ItemId=itemId; LotteryNum=lotteryNum; Items=new List<PlayerKVOfferItem>(items).AsReadOnly();
RewardList=new List<int>(rewardList).AsReadOnly(); Finished=finished; ChestReward=chestReward;
}
internal static PlayerKVOfferState Missing() => new PlayerKVOfferState(false,false,0,default,default,0,0,
Array.Empty<PlayerKVOfferItem>(),Array.Empty<int>(),false,0);
}
internal sealed class PlayerKVEventConfig
{
internal int RedirectId { get; }
internal string EndTime { get; }
internal PlayerKVEventConfig(int redirectId,string endTime) { RedirectId=redirectId; EndTime=endTime; }
}
internal sealed class PlayerKVEventPackState
{
internal int EventId { get; }
internal int PurchaseCount { get; }
internal int VipLevel { get; }
internal int RedirectId { get; }
internal PlayerKVEventPackState(int eventId,int purchaseCount,int vipLevel,int redirectId)
{ EventId=eventId; PurchaseCount=purchaseCount; VipLevel=vipLevel; RedirectId=redirectId; }
}
internal sealed class PlayerKVCampState
{
internal bool IsFix { get; }
internal string Skyscraper { get; }
internal IReadOnlyDictionary<string,int> Values { get; }
internal PlayerKVCampState(bool isFix,string skyscraper,IDictionary<string,int> values)
{ IsFix=isFix; Skyscraper=skyscraper; Values=new ReadOnlyDictionary<string,int>(new Dictionary<string,int>(values,StringComparer.Ordinal)); }
}
internal sealed class PlayerKVClubState
{
internal DateTime? SignTime { get; }
internal DateTime DonateTime { get; }
internal int DonateCount { get; }
internal DateTime RequestEnd { get; }
internal bool OpenRed { get; }
internal PlayerKVClubState(DateTime? signTime, DateTime donateTime, int donateCount, DateTime requestEnd, bool openRed)
{ SignTime=signTime; DonateTime=donateTime; DonateCount=donateCount; RequestEnd=requestEnd; OpenRed=openRed; }
}
internal sealed class PlayerKVProgressPackState
{
internal bool IsPresent { get; }
internal int EventId { get; }
internal int RedirectId { get; }
internal int TokenProgress { get; }
internal int ChainProgress { get; }
internal PlayerKVProgressPackState(bool present, int eventId, int redirectId, int tokenProgress, int chainProgress)
{ IsPresent=present; EventId=eventId; RedirectId=redirectId; TokenProgress=tokenProgress; ChainProgress=chainProgress; }
}
internal sealed class PlayerKVIntMapState
{
internal IReadOnlyDictionary<int, int> Values { get; }
internal PlayerKVIntMapState(IDictionary<int, int> values)
{ Values = new ReadOnlyDictionary<int, int>(new Dictionary<int, int>(values)); }
}
internal sealed class PlayerKVGuideValue
{
internal int Index { get; }
internal bool Finished { get; }
internal string Group { get; }
internal PlayerKVGuideValue(int index, bool finished, string group)
{ Index = index; Finished = finished; Group = group; }
internal bool Same(PlayerKVGuideValue other) => Index == other.Index && Finished == other.Finished && Group == other.Group;
}
internal sealed class PlayerKVGuideState
{
internal IReadOnlyDictionary<string, PlayerKVGuideValue> Values { get; }
internal PlayerKVGuideState(IDictionary<string, PlayerKVGuideValue> values)
{ Values = new ReadOnlyDictionary<string, PlayerKVGuideValue>(new Dictionary<string, PlayerKVGuideValue>(values, StringComparer.Ordinal)); }
}
internal sealed class PlayerKVMonthlySignState
{
internal bool IsPresent { get; }
internal int Index { get; }
internal int DailyId { get; }
internal int DailyIndex { get; }
internal int LastId { get; }
internal string Time { get; }
internal PlayerKVMonthlySignState(bool present, int index, int dailyId, int dailyIndex, int lastId, string time)
{ IsPresent = present; Index = index; DailyId = dailyId; DailyIndex = dailyIndex; LastId = lastId; Time = time; }
}
internal sealed class PlayerKVDailyValue
{
internal int Id { get; } internal int Index { get; } internal int LastId { get; } internal string Time { get; }
internal PlayerKVDailyValue(int id,int index,int lastId,string time) { Id=id; Index=index; LastId=lastId; Time=time; }
}
internal sealed class PlayerKVAdvertValue
{
internal int Id { get; } internal int Index { get; } internal int Day { get; }
internal string Time { get; } internal bool Open { get; }
internal PlayerKVAdvertValue(int id,int index,int day,string time,bool open) { Id=id; Index=index; Day=day; Time=time; Open=open; }
}
internal sealed class PlayerKVShopItemValue
{
internal int Id { get; } internal float Discount { get; } internal int Bought { get; }
internal PlayerKVShopItemValue(int id,float discount,int bought) { Id=id; Discount=discount; Bought=bought; }
}
internal sealed class PlayerKVCouponState
{
internal DateTime ActivateTime { get; } internal int EventId { get; } internal int RedirectId { get; } internal bool Bought { get; }
internal PlayerKVCouponState(DateTime time,int eventId,int redirectId,bool bought) { ActivateTime=time; EventId=eventId; RedirectId=redirectId; Bought=bought; }
}
internal sealed class PlayerKVShopState
{
internal IReadOnlyDictionary<string,int> Daily { get; }
internal IReadOnlyDictionary<int,int> All { get; } internal IReadOnlyDictionary<int,int> Gift { get; }
internal IReadOnlyDictionary<int,int> Advert { get; }
internal IReadOnlyDictionary<int,PlayerKVShopItemValue> Items { get; }
internal IReadOnlyList<float> Buy { get; }
internal int Voucher { get; } internal int RefreshCount { get; } internal DateTime RefreshTime { get; }
internal PlayerKVDailyValue Chain { get; } internal PlayerKVDailyValue Turntable { get; }
internal PlayerKVAdvertValue Vip { get; } internal PlayerKVCouponState Coupon { get; }
internal PlayerKVShopState(IDictionary<string,int> daily,IDictionary<int,int> all,IDictionary<int,int> gift,
IDictionary<int,int> advert,IDictionary<int,PlayerKVShopItemValue> items,IEnumerable<float> buy,int voucher,int refreshCount,
DateTime refreshTime,PlayerKVDailyValue chain,PlayerKVDailyValue turntable,PlayerKVAdvertValue vip,PlayerKVCouponState coupon)
{
Daily=new ReadOnlyDictionary<string,int>(new Dictionary<string,int>(daily,StringComparer.Ordinal));
All=new ReadOnlyDictionary<int,int>(new Dictionary<int,int>(all)); Gift=new ReadOnlyDictionary<int,int>(new Dictionary<int,int>(gift));
Advert=new ReadOnlyDictionary<int,int>(new Dictionary<int,int>(advert));
Items=new ReadOnlyDictionary<int,PlayerKVShopItemValue>(new Dictionary<int,PlayerKVShopItemValue>(items));
Buy=new List<float>(buy).AsReadOnly(); Voucher=voucher; RefreshCount=refreshCount; RefreshTime=refreshTime;
Chain=chain; Turntable=turntable; Vip=vip; Coupon=coupon;
}
}
internal sealed class PlayerKVLimitedValue
{
internal int Id { get; } internal double Duration { get; } internal string StartTime { get; }
internal PlayerKVLimitedValue(int id,double duration,string time) { Id=id; Duration=duration; StartTime=time; }
}
internal sealed class PlayerKVEventBaseState
{
internal IReadOnlyDictionary<int,PlayerKVLimitedValue> Limited { get; }
internal IReadOnlyDictionary<int,PlayerKVFixedTimeValue> Fixed { get; }
internal IReadOnlyDictionary<int,int> Target { get; } internal IReadOnlyDictionary<int,int> Rank { get; }
internal IReadOnlyDictionary<int,int> Wheel { get; }
internal int Coupon { get; } internal int Operate { get; } internal int AllOperate { get; }
internal int Free { get; } internal int PvpToken { get; }
internal PlayerKVEventBaseState(IDictionary<int,PlayerKVLimitedValue> limited,IDictionary<int,PlayerKVFixedTimeValue> fixedValues,
IDictionary<int,int> target,IDictionary<int,int> rank,IDictionary<int,int> wheel,int coupon,int operate,int allOperate,int free,int pvpToken)
{
Limited=new ReadOnlyDictionary<int,PlayerKVLimitedValue>(new Dictionary<int,PlayerKVLimitedValue>(limited));
Fixed=new ReadOnlyDictionary<int,PlayerKVFixedTimeValue>(new Dictionary<int,PlayerKVFixedTimeValue>(fixedValues));
Target=new ReadOnlyDictionary<int,int>(new Dictionary<int,int>(target)); Rank=new ReadOnlyDictionary<int,int>(new Dictionary<int,int>(rank));
Wheel=new ReadOnlyDictionary<int,int>(new Dictionary<int,int>(wheel)); Coupon=coupon; Operate=operate; AllOperate=allOperate; Free=free; PvpToken=pvpToken;
}
}
internal sealed class PlayerKVFishConfig
{
internal int Id { get; } internal int Area { get; } internal int Quality { get; } internal int Card { get; }
internal float Weight { get; } internal float Extra { get; } internal float Random { get; }
internal PlayerKVFishConfig(int id,int area,int quality,int card,float weight,float extra,float random)
{ Id=id; Area=area; Quality=quality; Card=card; Weight=weight; Extra=extra; Random=random; }
}
internal sealed class PlayerKVFishCardConfig
{
internal int Id { get; } internal int MaxLevel { get; }
internal IReadOnlyList<int> Required { get; } internal IReadOnlyList<float> Weights { get; }
internal PlayerKVFishCardConfig(int id,int max,IEnumerable<int> required,IEnumerable<float> weights)
{ Id=id; MaxLevel=max; Required=new List<int>(required).AsReadOnly(); Weights=new List<float>(weights).AsReadOnly(); }
}
internal sealed class PlayerKVFishValue
{
internal int Level { get; } internal float Weight { get; } internal int Cards { get; }
internal int Number { get; } internal bool New { get; }
internal IReadOnlyList<string> Compatibility { get; }
internal PlayerKVFishValue(int level,float weight,int cards,int number,bool isNew,IEnumerable<string> compatibility=null)
{ Level=level; Weight=weight; Cards=cards; Number=number; New=isNew; Compatibility=new List<string>(compatibility ?? Array.Empty<string>()).AsReadOnly(); }
internal bool Same(PlayerKVFishValue other) => Level==other.Level && Weight==other.Weight && Cards==other.Cards && Number==other.Number && New==other.New;
}
internal sealed class PlayerKVRodAccessories
{
internal int Glove { get; } internal IReadOnlyDictionary<int,int> RodSkin { get; }
internal IReadOnlyList<int> Gloves { get; } internal IReadOnlyList<int> Skins { get; }
internal IReadOnlyList<int> NewGloves { get; } internal IReadOnlyList<int> NewSkins { get; }
internal PlayerKVRodAccessories(int glove,IDictionary<int,int> rodSkin,IEnumerable<int> gloves,IEnumerable<int> skins,IEnumerable<int> newGloves,IEnumerable<int> newSkins)
{ Glove=glove; RodSkin=new ReadOnlyDictionary<int,int>(new Dictionary<int,int>(rodSkin)); Gloves=new List<int>(gloves).AsReadOnly();
Skins=new List<int>(skins).AsReadOnly(); NewGloves=new List<int>(newGloves).AsReadOnly(); NewSkins=new List<int>(newSkins).AsReadOnly(); }
}
internal sealed class PlayerKVFishState
{
internal IReadOnlyDictionary<int,int> Rods { get; } internal IReadOnlyDictionary<int,int> RodLevels { get; }
internal IReadOnlyDictionary<int,int> Swim { get; } internal IReadOnlyDictionary<int,int> SwimCount { get; }
internal IReadOnlyDictionary<int,int> Progress { get; } internal IReadOnlyDictionary<int,int> Honor { get; }
internal IReadOnlyDictionary<string,float> Luck { get; } internal PlayerKVRodAccessories Accessories { get; }
internal IReadOnlyDictionary<int,IReadOnlyDictionary<int,PlayerKVFishValue>> RawMaps { get; }
internal IReadOnlyDictionary<int,IReadOnlyDictionary<int,PlayerKVFishValue>> Maps { get; }
internal IReadOnlyDictionary<int,PlayerKVFishValue> Fish { get; } internal IReadOnlyDictionary<int,int> Cards { get; }
static IReadOnlyDictionary<int,int> Copy(IDictionary<int,int> values) => new ReadOnlyDictionary<int,int>(new Dictionary<int,int>(values));
static IReadOnlyDictionary<int,IReadOnlyDictionary<int,PlayerKVFishValue>> CopyMaps(IDictionary<int,Dictionary<int,PlayerKVFishValue>> maps) =>
new ReadOnlyDictionary<int,IReadOnlyDictionary<int,PlayerKVFishValue>>(maps.ToDictionary(p=>p.Key,p=>(IReadOnlyDictionary<int,PlayerKVFishValue>)new ReadOnlyDictionary<int,PlayerKVFishValue>(new Dictionary<int,PlayerKVFishValue>(p.Value))));
internal PlayerKVFishState(IDictionary<int,int> rods,IDictionary<int,int> rodLevels,IDictionary<int,int> swim,IDictionary<int,int> swimCount,
IDictionary<int,int> progress,IDictionary<int,int> honor,IDictionary<string,float> luck,PlayerKVRodAccessories accessories,
IDictionary<int,Dictionary<int,PlayerKVFishValue>> rawMaps,IDictionary<int,Dictionary<int,PlayerKVFishValue>> maps,
IDictionary<int,PlayerKVFishValue> fish,IDictionary<int,int> cards)
{ Rods=Copy(rods); RodLevels=Copy(rodLevels); Swim=Copy(swim); SwimCount=Copy(swimCount); Progress=Copy(progress); Honor=Copy(honor);
Luck=new ReadOnlyDictionary<string,float>(new Dictionary<string,float>(luck,StringComparer.Ordinal)); Accessories=accessories;
RawMaps=CopyMaps(rawMaps); Maps=CopyMaps(maps); Fish=new ReadOnlyDictionary<int,PlayerKVFishValue>(new Dictionary<int,PlayerKVFishValue>(fish)); Cards=Copy(cards); }
}
internal sealed class PlayerKVFootPrintState
{
internal ulong Bits { get; }
internal PlayerKVFootPrintState(ulong bits) { Bits = bits; }
}
}