Move models out of JsonDb

This commit is contained in:
Mikhail Tyukin
2025-07-21 16:47:45 -04:00
parent f217be263a
commit 6310916920
101 changed files with 800 additions and 881 deletions

View File

@@ -0,0 +1,6 @@
namespace EpinelPS.Database;
public class DatabaseConnection
{
}

View File

@@ -9,643 +9,6 @@ using Paseto.Builder;
namespace EpinelPS.Database
{
public class AccessToken
{
public string Token = "";
public long ExpirationTime;
public ulong UserID;
}
public class FieldInfo
{
public List<NetFieldStageData> CompletedStages = [];
public List<NetFieldObject> CompletedObjects = [];
}
public class FieldInfoNew
{
public List<int> CompletedStages = [];
public List<NetFieldObject> CompletedObjects = [];
public bool BossEntered = false;
}
public class Character
{
public int Csn = 0;
public int Tid = 0;
public int CostumeId = 0;
public int Level = 1;
public int UltimateLevel = 1;
public int Skill1Lvl = 1;
public int Skill2Lvl = 1;
public int Grade = 0;
}
public class MainQuestData
{
public int TableId = 0;
public bool IsReceieved = false;
}
public class UserPointData
{
public int UserLevel = 1;
public int ExperiencePoint = 0;
}
public class ItemData
{
public int ItemType;
public long Csn;
public int Count;
public int Level;
public int Exp;
public int Position;
public int Corp;
public long Isn;
}
public class EventData
{
public List<string> CompletedScenarios = [];
public int Diff = 0; // Default value for Diff
public int LastStage = 0; // Default value for LastStage
}
public class SynchroSlot
{
/// <summary>
/// Index of slot, 1 based
/// </summary>
public int Slot;
/// <summary>
/// Character CSN
/// </summary>
public long CharacterSerialNumber;
/// <summary>
/// Time when slot cooldown expires
/// </summary>
public long AvailableAt;
}
public class RecycleRoomResearchProgress
{
public int Level = 1;
public int Exp;
public int Attack;
public int Defense;
public int Hp;
}
public class SimroomData
{
public int CurrentDifficulty;
public int CurrentChapter;
public bool Entered = false;
}
public class ResetableData
{
public int WipeoutCount = 0;
public bool ClearedSimulationRoom = false;
public int InterceptionTickets = 3;
public List<int> CompletedDailyMissions = [];
public int DailyMissionPoints;
public SimroomData SimRoomData = new();
}
public class WeeklyResetableData
{
public List<int> CompletedWeeklyMissions = [];
public int WeeklyMissionPoints;
}
public class OutpostBuffs
{
public List<int> CreditPercentages = [];
public List<int> CoreDustPercentages = [];
public List<int> BattleDataPercentages = [];
public List<int> UserExpPercentages = [];
public List<int> GetPercentages(CurrencyType currency)
{
if (currency == CurrencyType.Gold)
return CreditPercentages;
else if (currency == CurrencyType.UserExp)
return UserExpPercentages;
else if (currency == CurrencyType.CharacterExp)
return BattleDataPercentages;
else if (currency == CurrencyType.CharacterExp2)
return CoreDustPercentages;
throw new InvalidOperationException();
}
public int GetTotalPercentages(CurrencyType currency)
{
int result = 0;
var numbs = GetPercentages(currency);
foreach (var item in numbs)
{
result += item;
}
return result;
}
}
public class JukeBoxSetting
{
public NetJukeboxLocation Location;
public NetJukeboxBgmType Type;
public int TableId;
}
public class UnlockData
{
public bool ButtonAnimationPlayed = false;
public bool PopupAnimationPlayed = false;
public UnlockData() { }
public UnlockData(bool button, bool popup)
{
ButtonAnimationPlayed = button;
PopupAnimationPlayed = popup;
}
}
public class MogMinigameInfo
{
public List<string> CompletedScenarios = [];
}
public class Badge
{
public string Location = "";
public long Seq;
public BadgeContents BadgeContent;
public string BadgeGuid = "";
public Badge() { }
public Badge(NetBadge badge)
{
Location = badge.Location;
Seq = badge.Seq;
BadgeContent = badge.BadgeContent;
BadgeGuid = new Guid([.. badge.BadgeGuid]).ToString();
}
public NetBadge ToNet()
{
return new NetBadge()
{
BadgeContent = BadgeContent,
BadgeGuid = ByteString.CopyFrom(new Guid(BadgeGuid).ToByteArray()),
Location = Location,
Seq = Seq
};
}
}
public class Trigger
{
public TriggerType Type;
public long Id;
public long CreatedAt;
public int ConditionId;
public int Value;
public NetTrigger ToNet()
{
return new()
{
ConditionId = ConditionId,
CreatedAt = CreatedAt,
Seq = Id,
Trigger = (int)Type,
UserValue = Value
};
}
}
public class ConversationChoice
{
}
public class ConversationMessage
{
public string ConversationId { get; set; } = "";
public long CreatedAt { get; set; }
public ulong Seq { get; set; }
public string Id { get; set; } = "";
public int State { get; set; }
}
public class LostSectorData
{
public bool IsOpen { get; set; }
public bool IsPlaying { get; set; }
public string Json { get; set; } = "";
public Dictionary<string, NetLostSectorFieldObject> Objects { get; set; } = [];
public Dictionary<string, int> ClearedStages { get; set; } = [];
public List<NetLostSectorTeamPosition> TeamPositions { get; set; } = [];
public int ObtainedRewards { get; set; } = 0;
public bool RecievedFinalReward { get; set; }
public bool CompletedPerfectly { get; set; }
}
public class User
{
// User info
public string? Username;
public string? Password;
public string? PlayerName;
public ulong ID;
public long RegisterTime;
public int LastNormalStageCleared;
public int LastHardStageCleared;
public string? Nickname;
public int ProfileIconId = 39900;
public bool ProfileIconIsPrism = false;
public int ProfileFrame = 25;
public bool IsAdmin = false;
public bool sickpulls = false;
public bool IsBanned = false;
public int TitleId = 1;
public DateTime BanStart;
public DateTime BanEnd;
public int BanId = 0;
public DateTime LastReset = DateTime.MinValue;
// Game data
public List<string> CompletedScenarios = [];
public Dictionary<string, FieldInfo> FieldInfo = []; // here for backwards compatibility
public Dictionary<string, FieldInfoNew> FieldInfoNew = [];
public Dictionary<string, string> MapJson = [];
public Dictionary<CurrencyType, long> Currency = new() {
{ CurrencyType.ContentStamina, 2 }
};
public List<SynchroSlot> SynchroSlots = [];
public bool SynchroDeviceUpgraded = false;
public int SynchroDeviceLevel = 200;
public Dictionary<int, RecycleRoomResearchProgress> ResearchProgress = [];
public ResetableData ResetableData = new();
public WeeklyResetableData WeeklyResetableData = new();
public List<ItemData> Items = [];
public List<Character> Characters = [];
public long[] RepresentationTeamDataNew = [];
public Dictionary<int, ClearedTutorialData> ClearedTutorialData = [];
public NetWallpaperData[] WallpaperList = [];
public NetWallpaperBackground[] WallpaperBackground = [];
public NetWallpaperJukeboxFavorite[] WallpaperFavoriteList = [];
public NetWallpaperPlaylist[] WallpaperPlaylistList = [];
public NetWallpaperJukebox[] WallpaperJukeboxList = [];
public List<int> LobbyDecoBackgroundList = [];
public Dictionary<int, NetUserTeamData> UserTeams = [];
public Dictionary<int, bool> MainQuestData = [];
public Dictionary<int, bool> SubQuestData = [];
public int InfraCoreExp = 0;
public int InfraCoreLvl = 1;
public UserPointData userPointData = new();
public DateTime LastLogin = DateTime.UtcNow;
public DateTime BattleTime = DateTime.UtcNow;
public NetOutpostBattleLevel OutpostBattleLevel = new() { Level = 1 };
public int GachaTutorialPlayCount = 0;
public List<int> CompletedTacticAcademyLessons = [];
public List<int> CompletedSideStoryStages = [];
public List<int> Memorial = [];
public List<int> JukeboxBgm = [];
public Dictionary<int, int> TowerProgress = [];
public JukeBoxSetting LobbyMusic = new() { Location = NetJukeboxLocation.Lobby, TableId = 2, Type = NetJukeboxBgmType.JukeboxTableId };
public JukeBoxSetting CommanderMusic = new() { Location = NetJukeboxLocation.CommanderRoom, TableId = 5, Type = NetJukeboxBgmType.JukeboxTableId };
public OutpostBuffs OutpostBuffs = new();
public Dictionary<int, UnlockData> ContentsOpenUnlocked = [];
public List<NetStageClearInfo> StageClearHistorys = [];
public List<Badge> Badges = [];
public List<NetUserAttractiveData> BondInfo = [];
public List<Trigger> Triggers = [];
public int LastTriggerId = 1;
public List<int> CompletedAchievements = [];
public List<NetMessage> MessengerData = [];
public ulong LastMessageId = 1;
public long LastBadgeSeq = 1;
public Dictionary<int, LostSectorData> LostSectorData = [];
// Event data
public Dictionary<int, EventData> EventInfo = [];
public MogMinigameInfo MogInfo = new();
public Trigger AddTrigger(TriggerType type, int value, int conditionId = 0)
{
Trigger t = new()
{
Id = LastTriggerId++,
Type = type,
ConditionId = conditionId,
CreatedAt = DateTime.UtcNow.AddHours(9).Ticks,
Value = value
};
Triggers.Add(t);
return t;
}
public Badge AddBadge(BadgeContents type, string location)
{
// generate unique badge SEQ
var badge = new Badge()
{
BadgeContent = type,
Location = location,
BadgeGuid = Guid.NewGuid().ToString(),
Seq = LastBadgeSeq++
};
Badges.Add(badge);
return badge;
}
public void SetQuest(int tid, bool recievedReward)
{
if (!MainQuestData.TryAdd(tid, recievedReward))
{
MainQuestData[tid] = recievedReward;
return;
}
}
public void SetSubQuest(int tid, bool recievedReward)
{
if (!SubQuestData.TryAdd(tid, recievedReward))
{
SubQuestData[tid] = recievedReward;
return;
}
}
public int GenerateUniqueItemId()
{
var num = Rng.RandomId();
while (Items.Any(x => x.Isn == num))
{
num = Rng.RandomId();
}
return num;
}
public int GenerateUniqueCharacterId()
{
var num = Rng.RandomId();
while (Characters.Any(x => x.Csn == num))
{
num = Rng.RandomId();
}
return num;
}
public bool IsStageCompleted(int id)
{
foreach (var item in FieldInfoNew)
{
if (item.Value.CompletedStages.Contains(id))
{
return true;
}
}
return false;
}
public long GetCurrencyVal(CurrencyType type)
{
if (Currency.TryGetValue(type, out long value))
return value;
else
{
Currency.Add(type, 0);
return 0;
}
}
public void AddCurrency(CurrencyType type, long val)
{
if (!Currency.TryAdd(type, val)) Currency[type] += val;
}
public bool SubtractCurrency(CurrencyType type, long val)
{
if (Currency.ContainsKey(type)) Currency[type] -= val;
else return false;
if (Currency[type] < 0)
{
Currency[type] += val;
return false;
}
return true;
}
public bool CanSubtractCurrency(CurrencyType type, long val)
{
if (Currency.ContainsKey(type))
{
if (Currency[type] >= val) return true;
else return false;
}
else
{
if (val == 0) return true;
else return false;
}
}
public bool HasCharacter(int c)
{
// Step 1: Get the 'name_code' of the input character with Tid 'c'
if (GameData.Instance.CharacterTable.TryGetValue(c, out var inputCharacterRecord))
{
int targetNameCode = inputCharacterRecord.name_code;
// Step 2: Find all character IDs in 'characterTable' that have the same 'name_code'
var matchingCharacterIds = GameData.Instance.CharacterTable.Where(kvp => kvp.Value.name_code == targetNameCode).Select(kvp => kvp.Key).ToHashSet();
// Step 3: Check if any of your owned characters have a 'Tid' in the set of matching IDs
return Characters.Any(ownedCharacter => matchingCharacterIds.Contains(ownedCharacter.Tid));
}
else
{ // The character with Tid 'c' does not exist in 'characterTable'
return false;
}
}
public Character? GetCharacter(int c)
{
// Step 1: Get the 'name_code' of the input character with Tid 'c'
if (GameData.Instance.CharacterTable.TryGetValue(c, out var inputCharacterRecord))
{
int targetNameCode = inputCharacterRecord.name_code;
// Step 2: Find all character IDs in 'characterTable' that have the same 'name_code'
var matchingCharacterIds = GameData.Instance.CharacterTable.Where(kvp => kvp.Value.name_code == targetNameCode).Select(kvp => kvp.Key).ToHashSet();
// Step 3: Check if any of your owned characters have a 'Tid' in the set of matching IDs
return Characters.Where(ownedCharacter => matchingCharacterIds.Contains(ownedCharacter.Tid)).FirstOrDefault();
}
else
{ // The character with Tid 'c' does not exist in 'characterTable'
return null;
}
}
public Character? GetCharacterBySerialNumber(long value)
{
if (value == 0) return null;
return Characters.Where(x => x.Csn == value).FirstOrDefault();
}
internal bool GetSynchro(long csn)
{
return SynchroSlots.Where(x => x.CharacterSerialNumber == csn).Any();
}
internal int GetCharacterLevel(int csn)
{
var c = GetCharacterBySerialNumber(csn) ?? throw new Exception("failed to lookup character");
return GetCharacterLevel(csn, c.Level);
}
internal int GetCharacterLevel(int csn, int characterLevel)
{
foreach (var item in SynchroSlots)
{
if (item.CharacterSerialNumber == csn)
{
return GetSynchroLevel();
}
}
return characterLevel;
}
internal int GetSynchroLevel()
{
if (SynchroDeviceUpgraded)
return SynchroDeviceLevel;
var highestLevelCharacters = Characters.OrderByDescending(x => x.Level).Take(5).ToList();
if (highestLevelCharacters.Count > 0)
{
return highestLevelCharacters.Last().Level;
}
else
{
return 1;
}
}
/// <summary>
/// Removes the specified amount of items by their ID. Returns the amount of items removed.
/// </summary>
/// <param name="isn"></param>
/// <param name="count"></param>
/// <returns></returns>
public int RemoveItemBySerialNumber(long isn, int count)
{
int removed = 0;
foreach (var item in Items.ToList())
{
if (count == 0)
break;
if (item.Isn == isn)
{
removed++;
item.Count -= count;
if (item.Count < 0)
{
item.Count = 0;
}
}
}
return removed;
}
public NetMessage CreateMessage(MessengerDialogRecord r, int state = 0)
{
var msg = new NetMessage()
{
ConversationId = r.conversation_id,
CreatedAt = DateTime.UtcNow.Ticks,
MessageId = r.id,
Seq = (long)LastMessageId++,
State = state
};
MessengerData.Add(msg);
return msg;
}
public NetMessage CreateMessage(string conversationId, string messageId, int state = 0)
{
var msg = new NetMessage()
{
ConversationId = conversationId,
CreatedAt = DateTime.UtcNow.Ticks,
MessageId = messageId,
Seq = (long)LastMessageId++,
State = state
};
MessengerData.Add(msg);
return msg;
}
private bool ShouldResetUser()
{
var nowLocal = DateTime.UtcNow;
// Compute the last reset threshold (most recent 2 PM before or at nowLocal)
DateTime todayResetTime = new(
nowLocal.Year,
nowLocal.Month,
nowLocal.Day,
JsonDb.Instance.ResetHourUtcTime, 0, 0
);
if (nowLocal < todayResetTime)
{
todayResetTime = todayResetTime.AddDays(-1);
}
// If user's last reset was before the last scheduled 2 PM, they need reset
return LastReset < todayResetTime;
}
public void ResetDataIfNeeded()
{
if (!ShouldResetUser()) return;
Logging.WriteLine("Resetting user...", LogType.Warning);
LastReset = DateTime.UtcNow;
ResetableData = new();
JsonDb.Save();
}
}
public class CoreInfo
{
public int DbVersion = 3;
public List<User> Users = [];
public List<AccessToken> LauncherAccessTokens = [];
public Dictionary<string, ulong> AdminAuthTokens = [];
public byte[] LauncherTokenKey = [];
public byte[] EncryptionTokenKey = [];
public LogType LogLevel = LogType.Debug;
public int MaxInterceptionCount = 3;
public int ResetHourUtcTime = 20;
}
internal class JsonDb
{
public static CoreInfo Instance { get; internal set; }
@@ -670,109 +33,11 @@ namespace EpinelPS.Database
{
Instance = j;
if (Instance.DbVersion == 0)
if (Instance.DbVersion != 5)
{
Instance.DbVersion = 1;
// In older versions, field info key used chapter number, but now difficultly is appened.
Console.WriteLine("Starting database update...");
foreach (var user in Instance.Users)
{
foreach (var f in user.FieldInfoNew.ToList())
{
var isNumeric = int.TryParse(f.Key, out int n);
if (isNumeric)
{
var val = f.Value;
user.FieldInfoNew.Remove(f.Key);
user.FieldInfoNew.Add(n + "_Normal", val);
}
}
}
Console.WriteLine("Database update completed");
}
if (Instance.DbVersion == 1)
{
Console.WriteLine("Starting database update...");
// there was a bug where equipment position was not saved, so remove all items from each characters
Instance.DbVersion = 2;
foreach (var user in Instance.Users)
{
foreach (var f in user.Items.ToList())
{
f.Csn = 0;
}
}
Console.WriteLine("Database update completed");
}
if (Instance.DbVersion == 2)
{
Console.WriteLine("Starting database update...");
// I used to use a class for FieldInfo cleared stages, but now int list is used
Instance.DbVersion = 3;
foreach (var user in Instance.Users)
{
foreach (var f in user.FieldInfo)
{
var newField = new FieldInfoNew();
foreach (var stage in f.Value.CompletedStages)
{
newField.CompletedStages.Add(stage.StageId);
}
user.FieldInfoNew.Add(f.Key, newField);
}
user.FieldInfo.Clear();
}
Console.WriteLine("Database update completed");
}
if (Instance.DbVersion == 3)
{
Console.WriteLine("Starting database update...");
Instance.DbVersion = 4;
foreach (var user in Instance.Users)
{
user.RepresentationTeamDataNew = new long[5];
}
Console.WriteLine("Database update completed");
}
if (Instance.DbVersion == 4)
{
Console.WriteLine("Starting database update...");
Instance.DbVersion = 5;
// FieldInfoNew uses MapId instead of ChapterNum_ChapterDifficulty format
foreach (var user in Instance.Users)
{
Dictionary<string, FieldInfoNew> info = [];
foreach (var item in user.FieldInfoNew)
{
if (item.Key.EndsWith("_Normal") || item.Key.EndsWith("_Hard"))
{
var newKey = GameData.Instance.GetMapIdFromDBFieldName(item.Key);
if (newKey != null)
{
if (!info.ContainsKey(newKey))
{
info.Add(newKey, item.Value);
}
else
{
// overwrite old data
info[newKey] = item.Value;
}
}
else
Console.WriteLine("Unknown chapter/difficulty: " + item.Value + ", discarding");
}
else
{
if (!info.ContainsKey(item.Key))
info.Add(item.Key, item.Value);
}
}
user.FieldInfoNew = info;
}
Console.WriteLine("Database update completed");
Logging.Warn("!!!WARNING!!!");
Logging.Warn("Database version is extremely out of date.");
Logging.Warn("It is recommended to delete db.json to avoid issues.");
}
if (Instance.LauncherTokenKey.Length == 0)
@@ -888,6 +153,5 @@ namespace EpinelPS.Database
throw new Exception($"User not found");
}
}
}
}

View File

@@ -13,7 +13,7 @@
<Version>0.135.4.3</Version>
<CETCompat>false</CETCompat>
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
@@ -26,7 +26,6 @@
<PackageReference Include="DnsClient" Version="1.8.0" />
<PackageReference Include="Google.Api.CommonProtos" Version="2.17.0" />
<PackageReference Include="Google.Protobuf.Tools" Version="3.31.1" />
<PackageReference Include="Grpc.AspNetCore" Version="2.71.0" />
<PackageReference Include="MemoryPack" Version="1.21.4" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
<PackageReference Include="Paseto.Core" Version="1.4.1" />

1
EpinelPS/Global.cs Normal file
View File

@@ -0,0 +1 @@
global using EpinelPS.Models;

View File

@@ -1,6 +1,5 @@
using EpinelPS.Utils;
using EpinelPS.Database;
using EpinelPS.Data; // Ensure this namespace is included
namespace EpinelPS.LobbyServer.Archive
{

View File

@@ -9,7 +9,7 @@ namespace EpinelPS.LobbyServer.Arena
protected override async Task HandleAsync()
{
ReqGetArena req = await ReadData<ReqGetArena>();
Database.User user = GetUser();
User user = GetUser();
ResGetArena response = new()
{

View File

@@ -9,7 +9,7 @@ namespace EpinelPS.LobbyServer.Arena
protected override async Task HandleAsync()
{
ReqGetSpecialArena req = await ReadData<ReqGetSpecialArena>();
Database.User user = GetUser();
User user = GetUser();
ResGetSpecialArena response = new()
{

View File

@@ -9,11 +9,11 @@ namespace EpinelPS.LobbyServer.Badge
protected override async Task HandleAsync()
{
ReqSyncBadge req = await ReadData<ReqSyncBadge>();
Database.User user = GetUser();
User user = GetUser();
ResSyncBadge response = new();
foreach (Database.Badge item in user.Badges)
foreach (BadgeModel item in user.Badges)
{
response.BadgeList.Add(item.ToNet());
}

View File

@@ -10,7 +10,7 @@ namespace EpinelPS.LobbyServer.Campaign
protected override async Task HandleAsync()
{
ReqGetCampaignFieldData req = await ReadData<ReqGetCampaignFieldData>();
Database.User user = GetUser();
User user = GetUser();
Console.WriteLine("Map ID: " + req.MapId);

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Campaign
protected override async Task HandleAsync()
{
ReqSaveCampaignField req = await ReadData<ReqSaveCampaignField>();
Database.User user = GetUser();
User user = GetUser();
ResSaveCampaignField response = new();

View File

@@ -18,10 +18,10 @@ namespace EpinelPS.LobbyServer.Character
ResSynchroChange response = new();
List<Database.Character> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
List<CharacterModel> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
int slot = 1;
foreach (Database.Character? item in highestLevelCharacters)
foreach (CharacterModel? item in highestLevelCharacters)
{
if (item.Level != 200)
{

View File

@@ -8,7 +8,7 @@ public class CheckCharacterCounsel : LobbyMsgHandler
protected override async Task HandleAsync()
{
ReqCounseledBefore req = await ReadData<ReqCounseledBefore>();
Database.User user = GetUser();
User user = GetUser();
ResCounseledBefore response = new();

View File

@@ -17,7 +17,7 @@ namespace EpinelPS.LobbyServer.Character
// Get all character data from the game's character table
List<CharacterRecord> fullchardata = [.. GameData.Instance.CharacterTable.Values];
Database.Character targetCharacter = user.GetCharacterBySerialNumber(req.Csn) ?? throw new NullReferenceException();
CharacterModel targetCharacter = user.GetCharacterBySerialNumber(req.Csn) ?? throw new NullReferenceException();
// Find the element with the current csn from the request
CharacterRecord currentCharacter = fullchardata.FirstOrDefault(c => c.id == targetCharacter.Tid) ?? throw new NullReferenceException();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Character
protected override async Task HandleAsync()
{
ReqGetAttractiveList req = await ReadData<ReqGetAttractiveList>();
Database.User user = GetUser();
User user = GetUser();
ResGetAttractiveList response = new()
{

View File

@@ -8,17 +8,17 @@ namespace EpinelPS.LobbyServer.Character
protected override async Task HandleAsync()
{
ReqGetCharacterData req = await ReadData<ReqGetCharacterData>();
Database.User user = GetUser();
User user = GetUser();
ResGetCharacterData response = new();
foreach (Database.Character item in user.Characters)
foreach (CharacterModel item in user.Characters)
{
response.Character.Add(new NetUserCharacterData() { Default = new() { Csn = item.Csn, Skill1Lv = item.Skill1Lvl, Skill2Lv = item.Skill2Lvl, CostumeId = item.CostumeId, Lv = user.GetCharacterLevel(item.Csn, item.Level), Grade = item.Grade, Tid = item.Tid, UltiSkillLv = item.UltimateLevel }, IsSynchro = user.GetSynchro(item.Csn) });
}
List<Database.Character> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
List<CharacterModel> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
foreach (Database.Character? c in highestLevelCharacters)
foreach (CharacterModel? c in highestLevelCharacters)
{
response.SynchroStandardCharacters.Add(c.Csn);
}

View File

@@ -23,14 +23,14 @@ namespace EpinelPS.LobbyServer.Character
];
}
List<Database.Character> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
List<CharacterModel> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
ResGetSynchroData response = new()
{
Synchro = new NetUserSynchroData()
};
foreach (Database.Character? item in highestLevelCharacters)
foreach (CharacterModel? item in highestLevelCharacters)
{
response.Synchro.StandardCharacters.Add(new NetUserCharacterData() { Default = new() { Csn = item.Csn, Skill1Lv = item.Skill1Lvl, Skill2Lv = item.Skill2Lvl, CostumeId = item.CostumeId, Lv = item.Level, Grade = item.Grade, Tid = item.Tid, UltiSkillLv = item.UltimateLevel }, IsSynchro = user.GetSynchro(item.Csn) });
}

View File

@@ -14,7 +14,7 @@ namespace EpinelPS.LobbyServer.Character
ResCharacterLevelUp response = new();
Dictionary<int, CharacterLevelData> data = GameData.Instance.GetCharacterLevelUpData();
foreach (Database.Character item in user.Characters.ToArray())
foreach (CharacterModel item in user.Characters.ToArray())
{
if (item.Csn == req.Csn)
{
@@ -55,11 +55,11 @@ namespace EpinelPS.LobbyServer.Character
Grade = item.Grade,
Tid = item.Tid
};
List<Database.Character> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
List<CharacterModel> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
response.SynchroLv = user.GetSynchroLevel();
foreach (Database.Character? c in highestLevelCharacters)
foreach (CharacterModel? c in highestLevelCharacters)
{
response.SynchroStandardCharacters.Add(c.Csn);
}

View File

@@ -10,7 +10,7 @@ namespace EpinelPS.LobbyServer.Character
{
ReqSynchroRegister req = await ReadData<ReqSynchroRegister>();
User user = GetUser();
Database.Character? targetCharacter = user.GetCharacterBySerialNumber(req.Csn) ?? throw new Exception("target character does not exist");
CharacterModel? targetCharacter = user.GetCharacterBySerialNumber(req.Csn) ?? throw new Exception("target character does not exist");
ResSynchroRegister response = new();
foreach (SynchroSlot item in user.SynchroSlots)
{

View File

@@ -14,7 +14,7 @@ namespace EpinelPS.LobbyServer.Character
ResCharacterGrowReset response = new();
Dictionary<int, CharacterLevelData> data = GameData.Instance.GetCharacterLevelUpData();
foreach (Database.Character item in user.Characters.ToArray())
foreach (CharacterModel item in user.Characters.ToArray())
{
if (item.Csn == req.Csn)
{
@@ -56,11 +56,11 @@ namespace EpinelPS.LobbyServer.Character
Grade = item.Grade,
Tid = item.Tid
};
List<Database.Character> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
List<CharacterModel> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
response.SynchroLv = highestLevelCharacters.Last().Level;
foreach (Database.Character? c in highestLevelCharacters)
foreach (CharacterModel? c in highestLevelCharacters)
{
response.SynchroStandardCharacters.Add(c.Csn);
}

View File

@@ -11,7 +11,7 @@ namespace EpinelPS.LobbyServer.Character
ReqSetCharacterCostume req = await ReadData<ReqSetCharacterCostume>();
User user = GetUser();
foreach (Database.Character item in user.Characters)
foreach (CharacterModel item in user.Characters)
{
if (item.Csn == req.Csn)
{

View File

@@ -13,7 +13,7 @@ namespace EpinelPS.LobbyServer.Character
User user = GetUser();
ResCharacterSkillLevelUp response = new();
Database.Character character = user.Characters.FirstOrDefault(c => c.Csn == req.Csn) ?? throw new Exception("cannot find character");
CharacterModel character = user.Characters.FirstOrDefault(c => c.Csn == req.Csn) ?? throw new Exception("cannot find character");
CharacterRecord charRecord = GameData.Instance.CharacterTable.Values.FirstOrDefault(c => c.id == character.Tid) ?? throw new Exception("cannot find character record");
Dictionary<int, int> skillIdMap = new()

View File

@@ -25,7 +25,7 @@ namespace EpinelPS.LobbyServer.Character
{
long oldCSN = item.CharacterSerialNumber;
item.CharacterSerialNumber = 0;
Database.Character data = user.GetCharacterBySerialNumber(oldCSN) ?? throw new Exception("failed to lookup character");
CharacterModel data = user.GetCharacterBySerialNumber(oldCSN) ?? throw new Exception("failed to lookup character");
response.Character = new NetUserCharacterDefaultData()
{
@@ -41,10 +41,10 @@ namespace EpinelPS.LobbyServer.Character
response.Slot = new NetSynchroSlot() { AvailableRegisterAt = item.AvailableAt, Csn = item.CharacterSerialNumber, Slot = item.Slot };
response.IsSynchro = false;
List<Database.Character> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
List<CharacterModel> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
foreach (Database.Character? item2 in highestLevelCharacters)
foreach (CharacterModel? item2 in highestLevelCharacters)
{
response.SynchroStandardCharacters.Add(item2.Csn);
}

View File

@@ -18,7 +18,7 @@ namespace EpinelPS.LobbyServer.Character
// Get all character data from the game's character table
List<CharacterRecord> fullchardata = [.. GameData.Instance.CharacterTable.Values];
Database.Character targetCharacter = user.GetCharacterBySerialNumber(req.Csn) ?? throw new NullReferenceException();
CharacterModel targetCharacter = user.GetCharacterBySerialNumber(req.Csn) ?? throw new NullReferenceException();
// Find the element with the current csn from the request
CharacterRecord? currentCharacter = fullchardata.FirstOrDefault(c => c.id == targetCharacter.Tid);

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Event.CollectSystem
protected override async Task HandleAsync()
{
ReqListFieldEventCollectData req = await ReadData<ReqListFieldEventCollectData>();
Database.User user = GetUser();
User user = GetUser();
ResListFieldEventCollectData response = new();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Event.Field
protected override async Task HandleAsync()
{
ReqListFieldPasswordDoorData req = await ReadData<ReqListFieldPasswordDoorData>();
Database.User user = GetUser();
User user = GetUser();
ResListFieldPasswordDoorData response = new();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Event
protected override async Task HandleAsync()
{
ReqChallengeEventStageData req = await ReadData<ReqChallengeEventStageData>();
Database.User user = GetUser();
User user = GetUser();
ResChallengeEventStageData response = new()
{

View File

@@ -1,5 +1,4 @@
using EpinelPS.Database;
using EpinelPS.Utils;
using EpinelPS.Utils;
using EpinelPS.Data; // For GameData access
using System.Linq;
using System.Threading.Tasks;

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Event.Minigame.CE002
protected override async Task HandleAsync()
{
ReqGetMiniGameCe002Data req = await ReadData<ReqGetMiniGameCe002Data>();
Database.User user = GetUser();
User user = GetUser();
ResGetMiniGameCe002Data response = new()
{

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Event.Minigame.CE006
protected override async Task HandleAsync()
{
ReqGetStellarBladeStatistics req = await ReadData<ReqGetStellarBladeStatistics>();
Database.User user = GetUser();
User user = GetUser();
ResGetStellarBladeStatistics response = new();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Event.Shop
protected override async Task HandleAsync()
{
ReqShopProductList req = await ReadData<ReqShopProductList>();
Database.User user = GetUser();
User user = GetUser();
ResShopProductList response = new();
response.Shops.Add(new NetShopProductData()

View File

@@ -1,5 +1,4 @@
using EpinelPS.Utils;
using EpinelPS.Database;
namespace EpinelPS.LobbyServer.Event.StoryEvent
{

View File

@@ -10,7 +10,7 @@ namespace EpinelPS.LobbyServer.FavoriteItem
ReqGetFavoriteItemLibrary req = await ReadData<ReqGetFavoriteItemLibrary>();
ResGetFavoriteItemLibrary response = new();
Database.User user = GetUser();
User user = GetUser();
await WriteDataAsync(response);

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.FavoriteItem
protected override async Task HandleAsync()
{
ReqListFavoriteItem req = await ReadData<ReqListFavoriteItem>();
Database.User user = GetUser();
User user = GetUser();
ResListFavoriteItem response = new();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.FavoriteItem
protected override async Task HandleAsync()
{
ReqListFavoriteItemQuest req = await ReadData<ReqListFavoriteItemQuest>();
Database.User user = GetUser();
User user = GetUser();
ResListFavoriteItemQuest response = new();

View File

@@ -83,7 +83,7 @@ namespace EpinelPS.LobbyServer.Gacha
if (user.HasCharacter(characterData.id))
{
Database.Character character = user.GetCharacter(characterData.id) ?? throw new Exception("HasCharacter() returned true, however character was null");
CharacterModel character = user.GetCharacter(characterData.id) ?? throw new Exception("HasCharacter() returned true, however character was null");
ItemData? existingItem = user.Items.FirstOrDefault(item => item.ItemType == characterData.piece_id);
@@ -200,7 +200,7 @@ namespace EpinelPS.LobbyServer.Gacha
UltiSkillLv = 1
});
user.Characters.Add(new Database.Character()
user.Characters.Add(new CharacterModel()
{
CostumeId = 0,
Csn = (int)gacha.Sn,

View File

@@ -146,7 +146,7 @@ namespace EpinelPS.LobbyServer.Gacha
UltiSkillLv = 1
});
user.Characters.Add(new Database.Character()
user.Characters.Add(new CharacterModel()
{
CostumeId = 0,
Csn = id,

View File

@@ -9,7 +9,7 @@ namespace EpinelPS.LobbyServer
protected override async Task HandleAsync()
{
ReqGetGachaData req = await ReadData<ReqGetGachaData>();
Database.User user = GetUser();
User user = GetUser();
ResGetGachaData response = new();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Intercept
protected override async Task HandleAsync()
{
ReqEnterIntercept req = await ReadData<ReqEnterIntercept>();
Database.User user = GetUser();
User user = GetUser();
ResEnterIntercept response = new();

View File

@@ -8,10 +8,10 @@ namespace EpinelPS.LobbyServer.Inventory
protected override async Task HandleAsync()
{
ReqGetInventoryData req = await ReadData<ReqGetInventoryData>();
Database.User user = GetUser();
User user = GetUser();
ResGetInventoryData response = new();
foreach (Database.ItemData item in user.Items)
foreach (ItemData item in user.Items)
{
response.Items.Add(new NetUserItemData() { Count = item.Count, Tid = item.ItemType, Csn = item.Csn, Lv = item.Level, Exp = item.Exp, Corporation = item.Corp, Isn = item.Isn, Position = item.Position });
}

View File

@@ -46,7 +46,7 @@ namespace EpinelPS.LobbyServer.Inventory
{
ItemData? spareItem = user.Items.FirstOrDefault(i => i.ItemType == character.piece_id);
if (user.GetCharacter(character.id) is Database.Character ownedCharacter)
if (user.GetCharacter(character.id) is CharacterModel ownedCharacter)
{
// If the character already exists, we can increase its piece count
int maxLimitBroken = GetValueByRarity(character.original_rare, 0, 2, 11);
@@ -104,7 +104,7 @@ namespace EpinelPS.LobbyServer.Inventory
Csn = user.GenerateUniqueCharacterId(),
Tid = character.id,
});
user.Characters.Add(new Database.Character
user.Characters.Add(new CharacterModel
{
CostumeId = 0,
Csn = csn,
@@ -194,7 +194,7 @@ namespace EpinelPS.LobbyServer.Inventory
_ => throw new Exception($"Unknown character rarity: {rarity}")
};
private NetCharacterData GetNetCharacterData(Database.Character character, int bodyLabel = 0)
private NetCharacterData GetNetCharacterData(CharacterModel character, int bodyLabel = 0)
{
return new NetCharacterData
{

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Liberate
protected override async Task HandleAsync()
{
ReqChooseLiberateCharacter req = await ReadData<ReqChooseLiberateCharacter>();
Database.User user = GetUser();
User user = GetUser();
ResChooseLiberateCharacter response = new()
{

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Liberate
protected override async Task HandleAsync()
{
ReqGetLiberateData req = await ReadData<ReqGetLiberateData>();
Database.User user = GetUser();
User user = GetUser();
ResGetLiberateData response = new() { };

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Liberate
protected override async Task HandleAsync()
{
ReqGetLiberateProgressList req = await ReadData<ReqGetLiberateProgressList>();
Database.User user = GetUser();
User user = GetUser();
ResGetLiberateProgressList response = new();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.LobbyUser
protected override async Task HandleAsync()
{
ReqAcquireUserTitle req = await ReadData<ReqAcquireUserTitle>();
Database.User user = GetUser();
User user = GetUser();
ResAcquireUserTitle response = new();

View File

@@ -36,7 +36,7 @@ namespace EpinelPS.LobbyServer.LobbyUser
response.Currency.Add(new NetUserCurrencyData() { Type = (int)item.Key, Value = item.Value });
}
foreach (Database.Character item in user.Characters)
foreach (CharacterModel item in user.Characters)
{
response.Character.Add(new NetUserCharacterData() { Default = new() { Csn = item.Csn, Skill1Lv = item.Skill1Lvl, Skill2Lv = item.Skill2Lvl, CostumeId = item.CostumeId, Lv = user.GetCharacterLevel(item.Csn, item.Level), Grade = item.Grade, Tid = item.Tid, UltiSkillLv = item.UltimateLevel}, IsSynchro = user.GetSynchro(item.Csn) });
}
@@ -49,10 +49,10 @@ namespace EpinelPS.LobbyServer.LobbyUser
// Add squad data if there are characters
if (user.Characters.Count > 0)
{
List<Database.Character> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
List<CharacterModel> highestLevelCharacters = [.. user.Characters.OrderByDescending(x => x.Level).Take(5)];
response.SynchroLv = user.GetSynchroLevel();
foreach (Database.Character? item in highestLevelCharacters)
foreach (CharacterModel? item in highestLevelCharacters)
{
response.SynchroStandardCharacters.Add(item.Csn);
}

View File

@@ -8,14 +8,14 @@ namespace EpinelPS.LobbyServer.LobbyUser
protected override async Task HandleAsync()
{
ReqGetContentsOpenData req = await ReadData<ReqGetContentsOpenData>();
Database.User user = GetUser();
User user = GetUser();
// this request returns a list of "special" stages that mark when something is unlocked, ex: the shop or interception
List<int> specialStages = [6003003, 6002008, 6002016, 6005003, 6003021, 6011018, 6007021, 6004018, 6005013, 6003009, 6003012, 6009017, 6016039, 6001004, 6000003, 6000001, 6002001, 6004023, 6005026, 6020050, 6006004, 6006023,6022049];
ResGetContentsOpenData response = new();
foreach (Database.FieldInfoNew field in user.FieldInfoNew.Values)
foreach (FieldInfoNew field in user.FieldInfoNew.Values)
{
foreach (int stage in field.CompletedStages)
{

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.LobbyUser
protected override async Task HandleAsync()
{
ReqGetFieldTalkList req = await ReadData<ReqGetFieldTalkList>();
Database.User user = GetUser();
User user = GetUser();
ResGetFieldTalkList response = new();
// TODO

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.LobbyUser
protected override async Task HandleAsync()
{
ReqGetScenarioList req = await ReadData<ReqGetScenarioList>();
Database.User user = GetUser();
User user = GetUser();
// todo what are bookmark scenarios?

View File

@@ -8,8 +8,8 @@ namespace EpinelPS.LobbyServer.LobbyUser
protected override async Task HandleAsync()
{
ReqGetProfileData req = await ReadData<ReqGetProfileData>();
Database.User callingUser = GetUser();
Database.User? user = GetUser((ulong)req.TargetUsn);
User callingUser = GetUser();
User? user = GetUser((ulong)req.TargetUsn);
ResGetProfileData response = new();
if (user != null)
@@ -28,7 +28,7 @@ namespace EpinelPS.LobbyServer.LobbyUser
for (int i = 0; i < user.RepresentationTeamDataNew.Length; i++)
{
long csn = user.RepresentationTeamDataNew[i];
Database.Character? c = user.GetCharacterBySerialNumber(csn);
CharacterModel? c = user.GetCharacterBySerialNumber(csn);
if (c != null)
{

View File

@@ -13,7 +13,7 @@ namespace EpinelPS.LobbyServer.LobbyUser
ResExistScenario response = new();
Database.User user = GetUser();
User user = GetUser();
foreach (string? item in req.ScenarioGroupIds)
{

View File

@@ -9,7 +9,7 @@ namespace EpinelPS.LobbyServer.LobbyUser
{
ReqGetWallpaper req = await ReadData<ReqGetWallpaper>();
ResGetWallpaper response = new();
Database.User user = GetUser();
User user = GetUser();
response.WallpaperList.AddRange(user.WallpaperList);

View File

@@ -1,5 +1,4 @@
using EpinelPS.Utils;
using EpinelPS.Data; // For GameData access
namespace EpinelPS.LobbyServer.LobbyUser
{
@@ -10,7 +9,7 @@ namespace EpinelPS.LobbyServer.LobbyUser
{
ReqRecordNoticeLog req = await ReadData<ReqRecordNoticeLog>();
ResRecordNoticeLog r = new();
Database.User user = GetUser();
User user = GetUser();
// TODO

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.LobbyUser
protected override async Task HandleAsync()
{
ReqUnMarkUserTitleBadge req = await ReadData<ReqUnMarkUserTitleBadge>();
Database.User user = GetUser();
User user = GetUser();
ResUnMarkUserTitleBadge response = new();

View File

@@ -8,9 +8,9 @@ namespace EpinelPS.LobbyServer.Lostsector
protected override async Task HandleAsync()
{
ReqGetLostSectorFieldData req = await ReadData<ReqGetLostSectorFieldData>();
Database.User user = GetUser();
User user = GetUser();
Database.LostSectorData f = user.LostSectorData[req.SectorId];
LostSectorData f = user.LostSectorData[req.SectorId];
ResGetLostSectorFieldData response = new()
{
Field = new NetFieldObjectData(),

View File

@@ -9,7 +9,7 @@ namespace EpinelPS.LobbyServer.Lostsector
protected override async Task HandleAsync()
{
ReqGetLostSectorData req = await ReadData<ReqGetLostSectorData>();
Database.User user = GetUser();
User user = GetUser();
ResGetLostSectorData response = new();
@@ -20,7 +20,7 @@ namespace EpinelPS.LobbyServer.Lostsector
response.ClearStages.Add(new NetFieldStageData() { StageId = item.Value.open_condition_value });
}
if (user.LostSectorData.TryGetValue(item.Key, out Database.LostSectorData? val))
if (user.LostSectorData.TryGetValue(item.Key, out LostSectorData? val))
{
MapInfo map = GameData.Instance.MapData[item.Value.field_id];
response.LostSector.Add(new NetUserLostSectorData()

View File

@@ -14,7 +14,7 @@ namespace EpinelPS.LobbyServer.Lostsector
ResPlayLostSector response = new();
if (!user.LostSectorData.ContainsKey(req.SectorId))
user.LostSectorData.Add(req.SectorId, new Database.LostSectorData()
user.LostSectorData.Add(req.SectorId, new LostSectorData()
{
IsPlaying = true
});

View File

@@ -8,12 +8,12 @@ namespace EpinelPS.LobbyServer.Lostsector
protected override async Task HandleAsync()
{
ReqSaveLostSectorField req = await ReadData<ReqSaveLostSectorField>();
Database.User user = GetUser();
User user = GetUser();
ResSaveLostSectorField response = new();
if (!user.LostSectorData.TryGetValue(req.SectorId, out Database.LostSectorData? value))
user.LostSectorData.Add(req.SectorId, new Database.LostSectorData()
if (!user.LostSectorData.TryGetValue(req.SectorId, out LostSectorData? value))
user.LostSectorData.Add(req.SectorId, new LostSectorData()
{
Json = req.Json
});

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Lostsector
protected override async Task HandleAsync()
{
ReqSaveLostSectorFieldObject req = await ReadData<ReqSaveLostSectorFieldObject>();
Database.User user = GetUser();
User user = GetUser();
ResSaveLostSectorFieldObject response = new();

View File

@@ -1,5 +1,4 @@
using EpinelPS.Database;
using EpinelPS.Utils;
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Messenger
{

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Minigame.nksv2
protected override async Task HandleAsync()
{
ReqGetNKSV2Scenario req = await ReadData<ReqGetNKSV2Scenario>();
Database.User user = GetUser();
User user = GetUser();
ResGetNKSV2Scenario response = new();
response.ScenarioIdList.Add(user.MogInfo.CompletedScenarios);

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Misc
protected override async Task HandleAsync()
{
ReqGachaGetAllShutdownFlags req = await ReadData<ReqGachaGetAllShutdownFlags>();
Database.User user = GetUser();
User user = GetUser();
ResGachaGetAllShutdownFlags response = new();
if (user.GachaTutorialPlayCount > 0)

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Misc
protected override async Task HandleAsync()
{
ReqUserOnlineStateLog req = await ReadData<ReqUserOnlineStateLog>();
Database.User user = GetUser();
User user = GetUser();
ResUserOnlineStateLog response = new();
user.LastLogin = DateTime.UtcNow;

View File

@@ -13,7 +13,7 @@ namespace EpinelPS.LobbyServer.Misc
protected override async Task HandleAsync()
{
ReqRetroactive req = await ReadData<ReqRetroactive>();
Database.User user = GetUser();
User user = GetUser();
ResRetroactive response = new();
await WriteDataAsync(response);

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Mission
protected override async Task HandleAsync()
{
await ReadData<ReqGetAchievementRewardedData>();
Database.User user = GetUser();
User user = GetUser();
ResGetAchievementRewardedData response = new();
response.Ids.AddRange(user.CompletedAchievements);

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Mission
protected override async Task HandleAsync()
{
ReqGetRewardedData req = await ReadData<ReqGetRewardedData>();
Database.User user = GetUser();
User user = GetUser();
ResGetRewardedData response = new();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Mission.Rewards
protected override async Task HandleAsync()
{
await ReadData<ReqGetDailyRewardedData>();
Database.User user = GetUser();
User user = GetUser();
user.ResetDataIfNeeded();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Mission.Rewards
protected override async Task HandleAsync()
{
await ReadData<ReqGetWeeklyRewardedData>();
Database.User user = GetUser();
User user = GetUser();
user.ResetDataIfNeeded();

View File

@@ -40,7 +40,7 @@ namespace EpinelPS.LobbyServer.Outpost
await WriteDataAsync(response);
}
private static void ProcessLessonReward(Database.User user, TacticAcademyLessonRecord r)
private static void ProcessLessonReward(User user, TacticAcademyLessonRecord r)
{
if (r.lesson_reward == null)
{

View File

@@ -1,5 +1,4 @@
using EpinelPS.Utils;
using EpinelPS.Database;
using EpinelPS.Data;
namespace EpinelPS.LobbyServer.Outpost
{

View File

@@ -1,5 +1,4 @@
using EpinelPS.Database;
using EpinelPS.Utils;
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Outpost
{

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Outpost
protected override async Task HandleAsync()
{
ReqGetTacticAcademyData req = await ReadData<ReqGetTacticAcademyData>();
Database.User user = GetUser();
User user = GetUser();
ResGetTacticAcademyData response = new();
response.ClearLessons.AddRange(user.CompletedTacticAcademyLessons);

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Outpost
protected override async Task HandleAsync()
{
ReqGetMemoryList req = await ReadData<ReqGetMemoryList>();
Database.User user = GetUser();
User user = GetUser();
ResGetMemoryList response = new();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Outpost
protected override async Task HandleAsync()
{
ReqBuildingIsDone req = await ReadData<ReqBuildingIsDone>();
Database.User user = GetUser();
User user = GetUser();
ResBuildingIsDone response = new();

View File

@@ -1,5 +1,4 @@
using EpinelPS.Database;
using EpinelPS.Utils;
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Outpost
{

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.PartyMatch
protected override async Task HandleAsync()
{
ReqListInvitation req = await ReadData<ReqListInvitation>();
Database.User user = GetUser();
User user = GetUser();
ResListInvitation response = new();
// TODO

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Sidestory
protected override async Task HandleAsync()
{
ReqClearSideStoryCutForBattle req = await ReadData<ReqClearSideStoryCutForBattle>();
Database.User user = GetUser();
User user = GetUser();
ResClearSideStoryCutForBattle response = new();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Sidestory
protected override async Task HandleAsync()
{
ReqClearSideStoryCutForScenario req = await ReadData<ReqClearSideStoryCutForScenario>();
Database.User user = GetUser();
User user = GetUser();
ResClearSideStoryCutForScenario response = new();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Sidestory
protected override async Task HandleAsync()
{
ReqEnterSideStoryCutForBattle req = await ReadData<ReqEnterSideStoryCutForBattle>();
Database.User user = GetUser();
User user = GetUser();
ResEnterSideStoryCutForBattle response = new();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Sidestory
protected override async Task HandleAsync()
{
ReqEnterSideStoryStage req = await ReadData<ReqEnterSideStoryStage>();
Database.User user = GetUser();
User user = GetUser();
ResEnterSideStoryStage response = new();

View File

@@ -9,7 +9,7 @@ namespace EpinelPS.LobbyServer.Sidestory
protected override async Task HandleAsync()
{
ReqListSideStory req = await ReadData<ReqListSideStory>();
Database.User user = GetUser();
User user = GetUser();
ResListSideStory response = new();

View File

@@ -9,7 +9,7 @@ namespace EpinelPS.LobbyServer.Simroom
protected override async Task HandleAsync()
{
ReqGetSimRoom req = await ReadData<ReqGetSimRoom>();
Database.User user = GetUser();
User user = GetUser();
ResGetSimRoom response = new()
{

View File

@@ -10,9 +10,9 @@ namespace EpinelPS.LobbyServer.Stage
ReqCheckStageClear req = await ReadData<ReqCheckStageClear>();
ResCheckStageClear response = new();
Database.User user = GetUser();
User user = GetUser();
foreach (KeyValuePair<string, Database.FieldInfoNew> fields in user.FieldInfoNew)
foreach (KeyValuePair<string, FieldInfoNew> fields in user.FieldInfoNew)
{
foreach (int stages in fields.Value.CompletedStages)
{

View File

@@ -170,11 +170,11 @@ namespace EpinelPS.LobbyServer.Stage
LastContentsTeamNumber = 1
};
user.Characters.Add(new Database.Character() { Csn = 47263455, Tid = 201001 });
user.Characters.Add(new Database.Character() { Csn = 47273456, Tid = 330501 });
user.Characters.Add(new Database.Character() { Csn = 47263457, Tid = 130201 });
user.Characters.Add(new Database.Character() { Csn = 47263458, Tid = 230101 });
user.Characters.Add(new Database.Character() { Csn = 47263459, Tid = 301201 });
user.Characters.Add(new CharacterModel() { Csn = 47263455, Tid = 201001 });
user.Characters.Add(new CharacterModel() { Csn = 47273456, Tid = 330501 });
user.Characters.Add(new CharacterModel() { Csn = 47263457, Tid = 130201 });
user.Characters.Add(new CharacterModel() { Csn = 47263458, Tid = 230101 });
user.Characters.Add(new CharacterModel() { Csn = 47263459, Tid = 301201 });
user.BondInfo.Add(new() { NameCode = 3001, Lv = 1 });
user.BondInfo.Add(new() { NameCode = 3005, Lv = 1 });
@@ -193,7 +193,7 @@ namespace EpinelPS.LobbyServer.Stage
for (int i = 1; i < 6; i++)
{
Database.Character character = user.Characters[i - 1];
CharacterModel character = user.Characters[i - 1];
team1Sub.Slots.Add(new NetTeamSlot() { Slot = i, Value = character.Csn });
}
team1.Teams.Add(team1Sub);

View File

@@ -10,7 +10,7 @@ namespace EpinelPS.LobbyServer.Stage
{
ReqFastClearCampaignStage req = await ReadData<ReqFastClearCampaignStage>();
Database.User user = GetUser();
User user = GetUser();
Console.WriteLine($"Stage " + req.CampaignStageId + " completed using quick battle");

View File

@@ -9,7 +9,7 @@ namespace EpinelPS.LobbyServer.Stage
{
ReqGetStageClearInfo req = await ReadData<ReqGetStageClearInfo>();
ResGetStageClearInfo response = new();
Database.User user = GetUser();
User user = GetUser();
response.Historys.AddRange(user.StageClearHistorys);

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Subquest
protected override async Task HandleAsync()
{
ReqGetSubQuestList req = await ReadData<ReqGetSubQuestList>();
Database.User user = GetUser();
User user = GetUser();
ResGetSubQuestList response = new();

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Team
protected override async Task HandleAsync()
{
ReqGetTeamData req = await ReadData<ReqGetTeamData>();
Database.User user = GetUser();
User user = GetUser();
ResGetTeamData response = new();

View File

@@ -11,7 +11,7 @@ namespace EpinelPS.LobbyServer.Tower
ResGetTowerData response = new();
Database.User user = GetUser();
User user = GetUser();
// TODO: Load remain count for these
NetTowerData t0 = new() { Type = 1, RemainCount = 3 };

View File

@@ -8,7 +8,7 @@ namespace EpinelPS.LobbyServer.Trigger
protected override async Task HandleAsync()
{
ReqGetMainQuestData req = await ReadData<ReqGetMainQuestData>();
Database.User user = GetUser();
User user = GetUser();
ResGetMainQuestData response = new();
foreach (KeyValuePair<int, bool> item in user.MainQuestData)

View File

@@ -1,5 +1,4 @@
using EpinelPS.Database;
using EpinelPS.Utils;
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Trigger
{
@@ -25,11 +24,11 @@ namespace EpinelPS.LobbyServer.Trigger
Console.WriteLine("needs " + req.Seq);
// Look for triggers past that amount
Database.Trigger[] newTriggers = [.. user.Triggers.Where(x => x.Id > req.Seq)];
TriggerModel[] newTriggers = [.. user.Triggers.Where(x => x.Id > req.Seq)];
// Return all triggers
int triggerCount = 0;
foreach (Database.Trigger? item in newTriggers)
foreach (TriggerModel item in newTriggers)
{
triggerCount++;

View File

@@ -9,7 +9,7 @@ namespace EpinelPS.LobbyServer.Wallet
protected override async Task HandleAsync()
{
ReqGetCurrencyData req = await ReadData<ReqGetCurrencyData>();
Database.User user = GetUser();
User user = GetUser();
ResGetCurrencyData response = new();

View File

@@ -9,7 +9,7 @@ namespace EpinelPS.LobbyServer.Wallet
protected override async Task HandleAsync()
{
ReqRefreshChargeCurrencyData req = await ReadData<ReqRefreshChargeCurrencyData>();
Database.User user = GetUser();
User user = GetUser();
ResRefreshChargeCurrencyData response = new()
{

View File

@@ -0,0 +1,18 @@
using EpinelPS.Utils;
namespace EpinelPS.Models;
public class CoreInfo
{
public int DbVersion = 3;
public List<User> Users = [];
public List<AccessToken> LauncherAccessTokens = [];
public Dictionary<string, ulong> AdminAuthTokens = [];
public byte[] LauncherTokenKey = [];
public byte[] EncryptionTokenKey = [];
public LogType LogLevel = LogType.Debug;
public int MaxInterceptionCount = 3;
public int ResetHourUtcTime = 20;
}

244
EpinelPS/Models/DbModels.cs Normal file
View File

@@ -0,0 +1,244 @@
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
using EpinelPS.Data;
using EpinelPS.Utils;
using Google.Protobuf;
using Paseto;
using Paseto.Builder;
namespace EpinelPS.Models
{
public class AccessToken
{
public string Token = "";
public long ExpirationTime;
public ulong UserID;
}
public class FieldInfo
{
public List<NetFieldStageData> CompletedStages = [];
public List<NetFieldObject> CompletedObjects = [];
}
public class FieldInfoNew
{
public List<int> CompletedStages = [];
public List<NetFieldObject> CompletedObjects = [];
public bool BossEntered = false;
}
public class CharacterModel
{
public int Csn = 0;
public int Tid = 0;
public int CostumeId = 0;
public int Level = 1;
public int UltimateLevel = 1;
public int Skill1Lvl = 1;
public int Skill2Lvl = 1;
public int Grade = 0;
}
public class MainQuestData
{
public int TableId = 0;
public bool IsReceieved = false;
}
public class UserPointData
{
public int UserLevel = 1;
public int ExperiencePoint = 0;
}
public class ItemData
{
public int ItemType;
public long Csn;
public int Count;
public int Level;
public int Exp;
public int Position;
public int Corp;
public long Isn;
}
public class EventData
{
public List<string> CompletedScenarios = [];
public int Diff = 0; // Default value for Diff
public int LastStage = 0; // Default value for LastStage
}
public class SynchroSlot
{
/// <summary>
/// Index of slot, 1 based
/// </summary>
public int Slot;
/// <summary>
/// Character CSN
/// </summary>
public long CharacterSerialNumber;
/// <summary>
/// Time when slot cooldown expires
/// </summary>
public long AvailableAt;
}
public class RecycleRoomResearchProgress
{
public int Level = 1;
public int Exp;
public int Attack;
public int Defense;
public int Hp;
}
public class SimroomData
{
public int CurrentDifficulty;
public int CurrentChapter;
public bool Entered = false;
}
public class ResetableData
{
public int WipeoutCount = 0;
public bool ClearedSimulationRoom = false;
public int InterceptionTickets = 3;
public List<int> CompletedDailyMissions = [];
public int DailyMissionPoints;
public SimroomData SimRoomData = new();
}
public class WeeklyResetableData
{
public List<int> CompletedWeeklyMissions = [];
public int WeeklyMissionPoints;
}
public class OutpostBuffs
{
public List<int> CreditPercentages = [];
public List<int> CoreDustPercentages = [];
public List<int> BattleDataPercentages = [];
public List<int> UserExpPercentages = [];
public List<int> GetPercentages(CurrencyType currency)
{
if (currency == CurrencyType.Gold)
return CreditPercentages;
else if (currency == CurrencyType.UserExp)
return UserExpPercentages;
else if (currency == CurrencyType.CharacterExp)
return BattleDataPercentages;
else if (currency == CurrencyType.CharacterExp2)
return CoreDustPercentages;
throw new InvalidOperationException();
}
public int GetTotalPercentages(CurrencyType currency)
{
int result = 0;
var numbs = GetPercentages(currency);
foreach (var item in numbs)
{
result += item;
}
return result;
}
}
public class JukeBoxSetting
{
public NetJukeboxLocation Location;
public NetJukeboxBgmType Type;
public int TableId;
}
public class UnlockData
{
public bool ButtonAnimationPlayed = false;
public bool PopupAnimationPlayed = false;
public UnlockData() { }
public UnlockData(bool button, bool popup)
{
ButtonAnimationPlayed = button;
PopupAnimationPlayed = popup;
}
}
public class MogMinigameInfo
{
public List<string> CompletedScenarios = [];
}
public class BadgeModel
{
public string Location = "";
public long Seq;
public BadgeContents BadgeContent;
public string BadgeGuid = "";
public BadgeModel() { }
public BadgeModel(NetBadge badge)
{
Location = badge.Location;
Seq = badge.Seq;
BadgeContent = badge.BadgeContent;
BadgeGuid = new Guid([.. badge.BadgeGuid]).ToString();
}
public NetBadge ToNet()
{
return new NetBadge()
{
BadgeContent = BadgeContent,
BadgeGuid = ByteString.CopyFrom(new Guid(BadgeGuid).ToByteArray()),
Location = Location,
Seq = Seq
};
}
}
public class TriggerModel
{
public TriggerType Type;
public long Id;
public long CreatedAt;
public int ConditionId;
public int Value;
public NetTrigger ToNet()
{
return new()
{
ConditionId = ConditionId,
CreatedAt = CreatedAt,
Seq = Id,
Trigger = (int)Type,
UserValue = Value
};
}
}
public class ConversationChoice
{
}
public class ConversationMessage
{
public string ConversationId { get; set; } = "";
public long CreatedAt { get; set; }
public ulong Seq { get; set; }
public string Id { get; set; } = "";
public int State { get; set; }
}
public class LostSectorData
{
public bool IsOpen { get; set; }
public bool IsPlaying { get; set; }
public string Json { get; set; } = "";
public Dictionary<string, NetLostSectorFieldObject> Objects { get; set; } = [];
public Dictionary<string, int> ClearedStages { get; set; } = [];
public List<NetLostSectorTeamPosition> TeamPositions { get; set; } = [];
public int ObtainedRewards { get; set; } = 0;
public bool RecievedFinalReward { get; set; }
public bool CompletedPerfectly { get; set; }
}
}

View File

@@ -0,0 +1,396 @@
using EpinelPS.Data;
using EpinelPS.Database;
using EpinelPS.Utils;
namespace EpinelPS.Models;
public class User
{
// User info
public string? Username;
public string? Password;
public string? PlayerName;
public ulong ID;
public long RegisterTime;
public int LastNormalStageCleared;
public int LastHardStageCleared;
public string? Nickname;
public int ProfileIconId = 39900;
public bool ProfileIconIsPrism = false;
public int ProfileFrame = 25;
public bool IsAdmin = false;
public bool sickpulls = false;
public bool IsBanned = false;
public int TitleId = 1;
public DateTime BanStart;
public DateTime BanEnd;
public int BanId = 0;
public DateTime LastReset = DateTime.MinValue;
// Game data
public List<string> CompletedScenarios = [];
public Dictionary<string, FieldInfo> FieldInfo = []; // here for backwards compatibility
public Dictionary<string, FieldInfoNew> FieldInfoNew = [];
public Dictionary<string, string> MapJson = [];
public Dictionary<CurrencyType, long> Currency = new() {
{ CurrencyType.ContentStamina, 2 }
};
public List<SynchroSlot> SynchroSlots = [];
public bool SynchroDeviceUpgraded = false;
public int SynchroDeviceLevel = 200;
public Dictionary<int, RecycleRoomResearchProgress> ResearchProgress = [];
public ResetableData ResetableData = new();
public WeeklyResetableData WeeklyResetableData = new();
public List<ItemData> Items = [];
public List<CharacterModel> Characters = [];
public long[] RepresentationTeamDataNew = [];
public Dictionary<int, ClearedTutorialData> ClearedTutorialData = [];
public NetWallpaperData[] WallpaperList = [];
public NetWallpaperBackground[] WallpaperBackground = [];
public NetWallpaperJukeboxFavorite[] WallpaperFavoriteList = [];
public NetWallpaperPlaylist[] WallpaperPlaylistList = [];
public NetWallpaperJukebox[] WallpaperJukeboxList = [];
public List<int> LobbyDecoBackgroundList = [];
public Dictionary<int, NetUserTeamData> UserTeams = [];
public Dictionary<int, bool> MainQuestData = [];
public Dictionary<int, bool> SubQuestData = [];
public int InfraCoreExp = 0;
public int InfraCoreLvl = 1;
public UserPointData userPointData = new();
public DateTime LastLogin = DateTime.UtcNow;
public DateTime BattleTime = DateTime.UtcNow;
public NetOutpostBattleLevel OutpostBattleLevel = new() { Level = 1 };
public int GachaTutorialPlayCount = 0;
public List<int> CompletedTacticAcademyLessons = [];
public List<int> CompletedSideStoryStages = [];
public List<int> Memorial = [];
public List<int> JukeboxBgm = [];
public Dictionary<int, int> TowerProgress = [];
public JukeBoxSetting LobbyMusic = new() { Location = NetJukeboxLocation.Lobby, TableId = 2, Type = NetJukeboxBgmType.JukeboxTableId };
public JukeBoxSetting CommanderMusic = new() { Location = NetJukeboxLocation.CommanderRoom, TableId = 5, Type = NetJukeboxBgmType.JukeboxTableId };
public OutpostBuffs OutpostBuffs = new();
public Dictionary<int, UnlockData> ContentsOpenUnlocked = [];
public List<NetStageClearInfo> StageClearHistorys = [];
public List<BadgeModel> Badges = [];
public List<NetUserAttractiveData> BondInfo = [];
public List<TriggerModel> Triggers = [];
public int LastTriggerId = 1;
public List<int> CompletedAchievements = [];
public List<NetMessage> MessengerData = [];
public ulong LastMessageId = 1;
public long LastBadgeSeq = 1;
public Dictionary<int, LostSectorData> LostSectorData = [];
// Event data
public Dictionary<int, EventData> EventInfo = [];
public MogMinigameInfo MogInfo = new();
public TriggerModel AddTrigger(TriggerType type, int value, int conditionId = 0)
{
TriggerModel t = new()
{
Id = LastTriggerId++,
Type = type,
ConditionId = conditionId,
CreatedAt = DateTime.UtcNow.AddHours(9).Ticks,
Value = value
};
Triggers.Add(t);
return t;
}
public BadgeModel AddBadge(BadgeContents type, string location)
{
// generate unique badge SEQ
var badge = new BadgeModel()
{
BadgeContent = type,
Location = location,
BadgeGuid = Guid.NewGuid().ToString(),
Seq = LastBadgeSeq++
};
Badges.Add(badge);
return badge;
}
public void SetQuest(int tid, bool recievedReward)
{
if (!MainQuestData.TryAdd(tid, recievedReward))
{
MainQuestData[tid] = recievedReward;
return;
}
}
public void SetSubQuest(int tid, bool recievedReward)
{
if (!SubQuestData.TryAdd(tid, recievedReward))
{
SubQuestData[tid] = recievedReward;
return;
}
}
public int GenerateUniqueItemId()
{
var num = Rng.RandomId();
while (Items.Any(x => x.Isn == num))
{
num = Rng.RandomId();
}
return num;
}
public int GenerateUniqueCharacterId()
{
var num = Rng.RandomId();
while (Characters.Any(x => x.Csn == num))
{
num = Rng.RandomId();
}
return num;
}
public bool IsStageCompleted(int id)
{
foreach (var item in FieldInfoNew)
{
if (item.Value.CompletedStages.Contains(id))
{
return true;
}
}
return false;
}
public long GetCurrencyVal(CurrencyType type)
{
if (Currency.TryGetValue(type, out long value))
return value;
else
{
Currency.Add(type, 0);
return 0;
}
}
public void AddCurrency(CurrencyType type, long val)
{
if (!Currency.TryAdd(type, val)) Currency[type] += val;
}
public bool SubtractCurrency(CurrencyType type, long val)
{
if (Currency.ContainsKey(type)) Currency[type] -= val;
else return false;
if (Currency[type] < 0)
{
Currency[type] += val;
return false;
}
return true;
}
public bool CanSubtractCurrency(CurrencyType type, long val)
{
if (Currency.ContainsKey(type))
{
if (Currency[type] >= val) return true;
else return false;
}
else
{
if (val == 0) return true;
else return false;
}
}
public bool HasCharacter(int c)
{
// Step 1: Get the 'name_code' of the input character with Tid 'c'
if (GameData.Instance.CharacterTable.TryGetValue(c, out var inputCharacterRecord))
{
int targetNameCode = inputCharacterRecord.name_code;
// Step 2: Find all character IDs in 'characterTable' that have the same 'name_code'
var matchingCharacterIds = GameData.Instance.CharacterTable.Where(kvp => kvp.Value.name_code == targetNameCode).Select(kvp => kvp.Key).ToHashSet();
// Step 3: Check if any of your owned characters have a 'Tid' in the set of matching IDs
return Characters.Any(ownedCharacter => matchingCharacterIds.Contains(ownedCharacter.Tid));
}
else
{ // The character with Tid 'c' does not exist in 'characterTable'
return false;
}
}
public CharacterModel? GetCharacter(int c)
{
// Step 1: Get the 'name_code' of the input character with Tid 'c'
if (GameData.Instance.CharacterTable.TryGetValue(c, out var inputCharacterRecord))
{
int targetNameCode = inputCharacterRecord.name_code;
// Step 2: Find all character IDs in 'characterTable' that have the same 'name_code'
var matchingCharacterIds = GameData.Instance.CharacterTable.Where(kvp => kvp.Value.name_code == targetNameCode).Select(kvp => kvp.Key).ToHashSet();
// Step 3: Check if any of your owned characters have a 'Tid' in the set of matching IDs
return Characters.Where(ownedCharacter => matchingCharacterIds.Contains(ownedCharacter.Tid)).FirstOrDefault();
}
else
{ // The character with Tid 'c' does not exist in 'characterTable'
return null;
}
}
public CharacterModel? GetCharacterBySerialNumber(long value)
{
if (value == 0) return null;
return Characters.Where(x => x.Csn == value).FirstOrDefault();
}
internal bool GetSynchro(long csn)
{
return SynchroSlots.Where(x => x.CharacterSerialNumber == csn).Any();
}
internal int GetCharacterLevel(int csn)
{
var c = GetCharacterBySerialNumber(csn) ?? throw new Exception("failed to lookup character");
return GetCharacterLevel(csn, c.Level);
}
internal int GetCharacterLevel(int csn, int characterLevel)
{
foreach (var item in SynchroSlots)
{
if (item.CharacterSerialNumber == csn)
{
return GetSynchroLevel();
}
}
return characterLevel;
}
internal int GetSynchroLevel()
{
if (SynchroDeviceUpgraded)
return SynchroDeviceLevel;
var highestLevelCharacters = Characters.OrderByDescending(x => x.Level).Take(5).ToList();
if (highestLevelCharacters.Count > 0)
{
return highestLevelCharacters.Last().Level;
}
else
{
return 1;
}
}
/// <summary>
/// Removes the specified amount of items by their ID. Returns the amount of items removed.
/// </summary>
/// <param name="isn"></param>
/// <param name="count"></param>
/// <returns></returns>
public int RemoveItemBySerialNumber(long isn, int count)
{
int removed = 0;
foreach (var item in Items.ToList())
{
if (count == 0)
break;
if (item.Isn == isn)
{
removed++;
item.Count -= count;
if (item.Count < 0)
{
item.Count = 0;
}
}
}
return removed;
}
public NetMessage CreateMessage(MessengerDialogRecord r, int state = 0)
{
var msg = new NetMessage()
{
ConversationId = r.conversation_id,
CreatedAt = DateTime.UtcNow.Ticks,
MessageId = r.id,
Seq = (long)LastMessageId++,
State = state
};
MessengerData.Add(msg);
return msg;
}
public NetMessage CreateMessage(string conversationId, string messageId, int state = 0)
{
var msg = new NetMessage()
{
ConversationId = conversationId,
CreatedAt = DateTime.UtcNow.Ticks,
MessageId = messageId,
Seq = (long)LastMessageId++,
State = state
};
MessengerData.Add(msg);
return msg;
}
private bool ShouldResetUser()
{
var nowLocal = DateTime.UtcNow;
// Compute the last reset threshold (most recent 2 PM before or at nowLocal)
DateTime todayResetTime = new(
nowLocal.Year,
nowLocal.Month,
nowLocal.Day,
JsonDb.Instance.ResetHourUtcTime, 0, 0
);
if (nowLocal < todayResetTime)
{
todayResetTime = todayResetTime.AddDays(-1);
}
// If user's last reset was before the last scheduled 2 PM, they need reset
return LastReset < todayResetTime;
}
public void ResetDataIfNeeded()
{
if (!ShouldResetUser()) return;
Logging.WriteLine("Resetting user...", LogType.Warning);
LastReset = DateTime.UtcNow;
ResetableData = new();
JsonDb.Save();
}
}

View File

@@ -162,7 +162,7 @@ namespace EpinelPS.Utils
{
if (!user.HasCharacter(character.id))
{
user.Characters.Add(new Database.Character()
user.Characters.Add(new CharacterModel()
{
CostumeId = 0,
Csn = user.GenerateUniqueCharacterId(),
@@ -232,7 +232,7 @@ namespace EpinelPS.Utils
{
if (!(inputGrade >= 0 && inputGrade <= 11)) return new RunCmdResponse() { error = "core level out of range, must be between 0-12" };
foreach (Character character in user.Characters)
foreach (CharacterModel character in user.Characters)
{
// Get current character's Tid
int tid = character.Tid;
@@ -310,7 +310,7 @@ namespace EpinelPS.Utils
public static RunCmdResponse SetCharacterLevel(User user, int level)
{
if (level > 999 || level <= 0) return new RunCmdResponse() { error = "level must be between 1-999" };
foreach (Character character in user.Characters)
foreach (CharacterModel character in user.Characters)
{
character.Level = level;
}
@@ -322,7 +322,7 @@ namespace EpinelPS.Utils
public static RunCmdResponse SetSkillLevel(User user, int skillLevel)
{
if (skillLevel > 10 || skillLevel < 0) return new RunCmdResponse() { error = "level must be between 1-10" };
foreach (Character character in user.Characters)
foreach (CharacterModel character in user.Characters)
{
character.UltimateLevel = skillLevel;
character.Skill1Lvl = skillLevel;
@@ -337,7 +337,7 @@ namespace EpinelPS.Utils
{
if (!user.HasCharacter(characterId))
{
user.Characters.Add(new Database.Character()
user.Characters.Add(new CharacterModel()
{
CostumeId = 0,
Csn = user.GenerateUniqueCharacterId(),

View File

@@ -4,9 +4,9 @@ namespace EpinelPS.Utils
{
public class FormulaUtils
{
public static int CalculateCP(Database.User user, long csn)
public static int CalculateCP(User user, long csn)
{
Database.Character? character = user.Characters.FirstOrDefault(c => c.Csn == csn);
CharacterModel? character = user.Characters.FirstOrDefault(c => c.Csn == csn);
if (character == null) return 0;
CharacterRecord? charRecord = GameData.Instance.CharacterTable.Values.FirstOrDefault(c => c.id == character.Tid);

View File

@@ -336,7 +336,7 @@ namespace EpinelPS.Utils
NetWholeTeamSlot result = new();
Character? c = user.GetCharacterBySerialNumber(csn);
CharacterModel? c = user.GetCharacterBySerialNumber(csn);
if (c == null) return new() { Slot = slot };
return new NetWholeTeamSlot()

View File

@@ -1,4 +1,4 @@
@model EpinelPS.Database.User
@model EpinelPS.Models.User
@{
ViewData["Title"] = "Delete user";

View File

@@ -1,4 +1,4 @@
@model IEnumerable<EpinelPS.Database.User>
@model IEnumerable<EpinelPS.Models.User>
@{
ViewData["Title"] = "用户管理";
}

Some files were not shown because too many files have changed in this diff Show More