mirror of
https://github.com/EpinelPS/EpinelPS.git
synced 2025-12-13 15:34:36 +01:00
fix character counsel, server reset
This commit is contained in:
@@ -450,10 +450,16 @@ namespace EpinelPS.Data
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// sanity checks
|
||||||
|
if (QuestDataRecords.Count == 0) throw new Exception("QuestDataRecords should not be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
public MainQuestCompletionRecord? GetMainQuestForStageClearCondition(int stage)
|
public MainQuestCompletionRecord? GetMainQuestForStageClearCondition(int stage)
|
||||||
{
|
{
|
||||||
|
if (QuestDataRecords.Count == 0) throw new Exception("QuestDataRecords should not be empty");
|
||||||
foreach (var item in QuestDataRecords)
|
foreach (var item in QuestDataRecords)
|
||||||
{
|
{
|
||||||
if (item.Value.condition_id == stage)
|
if (item.Value.condition_id == stage)
|
||||||
@@ -581,7 +587,7 @@ namespace EpinelPS.Data
|
|||||||
|
|
||||||
int chVal = data.chapter_id - 1;
|
int chVal = data.chapter_id - 1;
|
||||||
|
|
||||||
if (chapterNumber == chVal && data.mod == mod && data.stage_type == StageType.Main)
|
if (chapterNumber == chVal && data.chapter_mod == mod && data.stage_type == StageType.Main)
|
||||||
{
|
{
|
||||||
yield return data.id;
|
yield return data.id;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,22 +107,22 @@ namespace EpinelPS.Data
|
|||||||
{
|
{
|
||||||
public int id;
|
public int id;
|
||||||
public int chapter_id;
|
public int chapter_id;
|
||||||
public ChapterMod mod;
|
public ChapterMod chapter_mod;
|
||||||
public int parent_id;
|
public int parent_id;
|
||||||
public int group_id;
|
public int group_id;
|
||||||
public string name = "";
|
public string name_localkey = "";
|
||||||
public StageCategory stage_category;
|
public StageCategory stage_category;
|
||||||
public StageType stage_type;
|
public StageType stage_type;
|
||||||
public bool allow_autobattle;
|
public bool spot_autocontrol;
|
||||||
public int enter_condition;
|
public int enter_condition;
|
||||||
public int monster_stage_level;
|
public int monster_stage_lv;
|
||||||
public int dynobj_stage_level;
|
public int dynamic_object_stage_lv;
|
||||||
public int standard_battle_power;
|
public int standard_battle_power;
|
||||||
public int statinc_groupid;
|
public int stage_stat_increase_group_id;
|
||||||
public bool allow_quickbattle;
|
public bool is_use_quick_battle;
|
||||||
public int fieldmonster_id;
|
public int field_monster_id;
|
||||||
public int spotid;
|
public int spot_id;
|
||||||
public int reward_id = 0;
|
public int reward_id;
|
||||||
public ScenarioType enter_scenario_type;
|
public ScenarioType enter_scenario_type;
|
||||||
public string enter_scenario = "";
|
public string enter_scenario = "";
|
||||||
public ScenarioType exit_scenario_type;
|
public ScenarioType exit_scenario_type;
|
||||||
|
|||||||
@@ -261,6 +261,7 @@ namespace EpinelPS.Database
|
|||||||
public DateTime BanStart;
|
public DateTime BanStart;
|
||||||
public DateTime BanEnd;
|
public DateTime BanEnd;
|
||||||
public int BanId = 0;
|
public int BanId = 0;
|
||||||
|
public DateTime LastReset = DateTime.MinValue;
|
||||||
|
|
||||||
// Game data
|
// Game data
|
||||||
public List<string> CompletedScenarios = [];
|
public List<string> CompletedScenarios = [];
|
||||||
@@ -411,7 +412,6 @@ namespace EpinelPS.Database
|
|||||||
foreach (var item in FieldInfoNew)
|
foreach (var item in FieldInfoNew)
|
||||||
{
|
{
|
||||||
if (item.Key.Contains("hard") && isNorm) continue;
|
if (item.Key.Contains("hard") && isNorm) continue;
|
||||||
if (item.Key.Contains("normal") && !isNorm) continue;
|
|
||||||
if (item.Value.CompletedStages.Contains(id))
|
if (item.Value.CompletedStages.Contains(id))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -601,6 +601,38 @@ namespace EpinelPS.Database
|
|||||||
MessengerData.Add(msg);
|
MessengerData.Add(msg);
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool ShouldResetUser()
|
||||||
|
{
|
||||||
|
var nowLocal = DateTime.Now;
|
||||||
|
|
||||||
|
// Compute the last reset threshold (most recent 2 PM before or at nowLocal)
|
||||||
|
DateTime todayResetTime = new(
|
||||||
|
nowLocal.Year,
|
||||||
|
nowLocal.Month,
|
||||||
|
nowLocal.Day,
|
||||||
|
JsonDb.Instance.ResetHourLocalTime, 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.Now;
|
||||||
|
ResetableData = new();
|
||||||
|
JsonDb.Save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public class CoreInfo
|
public class CoreInfo
|
||||||
{
|
{
|
||||||
@@ -615,6 +647,7 @@ namespace EpinelPS.Database
|
|||||||
public LogType LogLevel = LogType.Debug;
|
public LogType LogLevel = LogType.Debug;
|
||||||
|
|
||||||
public int MaxInterceptionCount = 3;
|
public int MaxInterceptionCount = 3;
|
||||||
|
public int ResetHourLocalTime = 14;
|
||||||
}
|
}
|
||||||
internal class JsonDb
|
internal class JsonDb
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<SelfContained>true</SelfContained>
|
<SelfContained>true</SelfContained>
|
||||||
<IncludeNativeLibrariesForSelfExtract>True</IncludeNativeLibrariesForSelfExtract>
|
<IncludeNativeLibrariesForSelfExtract>True</IncludeNativeLibrariesForSelfExtract>
|
||||||
<NoWarn>$(NoWarn);SYSLIB0057</NoWarn>
|
<NoWarn>$(NoWarn);SYSLIB0057</NoWarn>
|
||||||
<Version>0.134.4.3</Version>
|
<Version>0.135.4.3</Version>
|
||||||
<CETCompat>false</CETCompat>
|
<CETCompat>false</CETCompat>
|
||||||
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
<EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
|
||||||
|
|
||||||
|
|||||||
@@ -45,14 +45,18 @@ namespace EpinelPS.LobbyServer.Auth
|
|||||||
.Encode();
|
.Encode();
|
||||||
|
|
||||||
|
|
||||||
ResEnterServer response = new();
|
ResEnterServer response = new()
|
||||||
|
{
|
||||||
|
GameClientToken = token,
|
||||||
|
FeatureDataInfo = new NetFeatureDataInfo() { }, // TODO
|
||||||
|
Identifier = new NetLegacyUserIdentifier() { Server = 1000, Usn = (long)user.ID },
|
||||||
|
ShouldRestartAfter = Duration.FromTimeSpan(TimeSpan.FromSeconds(86400)),
|
||||||
|
|
||||||
response.GameClientToken = token;
|
EncryptionToken = ByteString.CopyFromUtf8(encryptionToken)
|
||||||
response.FeatureDataInfo = new NetFeatureDataInfo() { }; // TODO
|
};
|
||||||
response.Identifier = new NetLegacyUserIdentifier() { Server = 1000, Usn = (long)user.ID };
|
|
||||||
response.ShouldRestartAfter = Duration.FromTimeSpan(TimeSpan.FromSeconds(86400));
|
user.ResetDataIfNeeded();
|
||||||
|
|
||||||
response.EncryptionToken = ByteString.CopyFromUtf8(encryptionToken);
|
|
||||||
await WriteDataAsync(response);
|
await WriteDataAsync(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
using EpinelPS.Utils;
|
|
||||||
|
|
||||||
namespace EpinelPS.LobbyServer.Character
|
|
||||||
{
|
|
||||||
[PacketPath("/character/attractive/counsel")]
|
|
||||||
public class Counsel : LobbyMsgHandler
|
|
||||||
{
|
|
||||||
protected override async Task HandleAsync()
|
|
||||||
{
|
|
||||||
var req = await ReadData<ReqCharacterCounsel>();
|
|
||||||
var user = GetUser();
|
|
||||||
|
|
||||||
ResCharacterCounsel response = new();
|
|
||||||
response.Attractive = new();
|
|
||||||
response.Exp = new();
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
await WriteDataAsync(response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
18
EpinelPS/LobbyServer/Character/Counsel/Check.cs
Normal file
18
EpinelPS/LobbyServer/Character/Counsel/Check.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using EpinelPS.Utils;
|
||||||
|
|
||||||
|
namespace EpinelPS.LobbyServer.Character.Counsel;
|
||||||
|
|
||||||
|
[PacketPath("/character/attractive/check")]
|
||||||
|
public class CheckCharacterCounsel : LobbyMsgHandler
|
||||||
|
{
|
||||||
|
protected override async Task HandleAsync()
|
||||||
|
{
|
||||||
|
var req = await ReadData<ReqCounseledBefore>();
|
||||||
|
var user = GetUser();
|
||||||
|
|
||||||
|
ResCounseledBefore response = new();
|
||||||
|
|
||||||
|
// TODO: Validate response from real server and pull info from user info
|
||||||
|
await WriteDataAsync(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
49
EpinelPS/LobbyServer/Character/Counsel/DoCounsel.cs
Normal file
49
EpinelPS/LobbyServer/Character/Counsel/DoCounsel.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using EpinelPS.Database;
|
||||||
|
using EpinelPS.Utils;
|
||||||
|
|
||||||
|
namespace EpinelPS.LobbyServer.Character.Counsel;
|
||||||
|
|
||||||
|
[PacketPath("/character/attractive/counsel")]
|
||||||
|
public class DoCounsel : LobbyMsgHandler
|
||||||
|
{
|
||||||
|
protected override async Task HandleAsync()
|
||||||
|
{
|
||||||
|
var req = await ReadData<ReqCharacterCounsel>();
|
||||||
|
var user = GetUser();
|
||||||
|
|
||||||
|
ResCharacterCounsel response = new();
|
||||||
|
|
||||||
|
foreach (var currency in user.Currency)
|
||||||
|
{
|
||||||
|
response.Currencies.Add(new NetUserCurrencyData() { Type = (int)currency.Key, Value = currency.Value });
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentBondInfo = user.BondInfo.Where(x => x.NameCode == req.NameCode);
|
||||||
|
|
||||||
|
NetUserAttractiveData data;
|
||||||
|
|
||||||
|
if (currentBondInfo.Any())
|
||||||
|
{
|
||||||
|
data = currentBondInfo.First();
|
||||||
|
|
||||||
|
// TODO update
|
||||||
|
response.Attractive = data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = new()
|
||||||
|
{
|
||||||
|
NameCode = req.NameCode,
|
||||||
|
// TODO
|
||||||
|
};
|
||||||
|
|
||||||
|
response.Attractive = data;
|
||||||
|
user.BondInfo.Add(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonDb.Save();
|
||||||
|
|
||||||
|
// TODO: Validate response from real server and pull info from user info
|
||||||
|
await WriteDataAsync(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,8 @@ namespace EpinelPS.LobbyServer.Event
|
|||||||
Json = "{}"
|
Json = "{}"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Retrieve collected objects
|
// Retrieve collected objects
|
||||||
|
|
||||||
if (!user.FieldInfoNew.TryGetValue(req.MapId, out FieldInfoNew? field))
|
if (!user.FieldInfoNew.TryGetValue(req.MapId, out FieldInfoNew? field))
|
||||||
|
|||||||
24
EpinelPS/LobbyServer/Event/Shop/ListProductList.cs
Normal file
24
EpinelPS/LobbyServer/Event/Shop/ListProductList.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using EpinelPS.Utils;
|
||||||
|
|
||||||
|
namespace EpinelPS.LobbyServer.Event.Shop
|
||||||
|
{
|
||||||
|
[PacketPath("/event/shopproductlist")]
|
||||||
|
public class ListProductList : LobbyMsgHandler
|
||||||
|
{
|
||||||
|
protected override async Task HandleAsync()
|
||||||
|
{
|
||||||
|
var req = await ReadData<ReqShopProductList>();
|
||||||
|
var user = GetUser();
|
||||||
|
|
||||||
|
var response = new ResShopProductList();
|
||||||
|
response.Shops.Add(new NetShopProductData()
|
||||||
|
{
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO implement properly
|
||||||
|
|
||||||
|
await WriteDataAsync(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,7 @@ namespace EpinelPS.LobbyServer.Mission
|
|||||||
{
|
{
|
||||||
if (user.ResetableData.CompletedDailyMissions.Contains(item))
|
if (user.ResetableData.CompletedDailyMissions.Contains(item))
|
||||||
{
|
{
|
||||||
Console.WriteLine("already completed daily mission");
|
Logging.WriteLine("already completed daily mission", LogType.Warning);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ namespace EpinelPS.LobbyServer.Mission.Rewards
|
|||||||
await ReadData<ReqGetDailyRewardedData>();
|
await ReadData<ReqGetDailyRewardedData>();
|
||||||
var user = GetUser();
|
var user = GetUser();
|
||||||
|
|
||||||
|
user.ResetDataIfNeeded();
|
||||||
|
|
||||||
var response = new ResGetDailyRewardedData();
|
var response = new ResGetDailyRewardedData();
|
||||||
response.Ids.Add(user.ResetableData.CompletedDailyMissions);
|
response.Ids.Add(user.ResetableData.CompletedDailyMissions);
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ namespace EpinelPS.LobbyServer.Mission.Rewards
|
|||||||
await ReadData<ReqGetWeeklyRewardedData>();
|
await ReadData<ReqGetWeeklyRewardedData>();
|
||||||
var user = GetUser();
|
var user = GetUser();
|
||||||
|
|
||||||
|
user.ResetDataIfNeeded();
|
||||||
|
|
||||||
var response = new ResGetWeeklyRewardedData();
|
var response = new ResGetWeeklyRewardedData();
|
||||||
response.Ids.Add(user.WeeklyResetableData.CompletedWeeklyMissions);
|
response.Ids.Add(user.WeeklyResetableData.CompletedWeeklyMissions);
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ namespace EpinelPS.LobbyServer.Outpost
|
|||||||
{
|
{
|
||||||
var req = await ReadData<ReqGetOutpostData>();
|
var req = await ReadData<ReqGetOutpostData>();
|
||||||
var user = GetUser();
|
var user = GetUser();
|
||||||
|
user.ResetDataIfNeeded();
|
||||||
|
|
||||||
var battleTime = DateTime.UtcNow - user.BattleTime;
|
var battleTime = DateTime.UtcNow - user.BattleTime;
|
||||||
var battleTimeMs = (long)(battleTime.TotalNanoseconds / 100);
|
var battleTimeMs = (long)(battleTime.TotalNanoseconds / 100);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace EpinelPS.LobbyServer.Stage
|
|||||||
var response = new ResClearStage();
|
var response = new ResClearStage();
|
||||||
var clearedStage = GameData.Instance.GetStageData(StageId) ?? throw new Exception("cleared stage cannot be null");
|
var clearedStage = GameData.Instance.GetStageData(StageId) ?? throw new Exception("cleared stage cannot be null");
|
||||||
|
|
||||||
var stageMapId = GameData.Instance.GetMapIdFromChapter(clearedStage.chapter_id, clearedStage.mod);
|
var stageMapId = GameData.Instance.GetMapIdFromChapter(clearedStage.chapter_id, clearedStage.chapter_mod);
|
||||||
|
|
||||||
if (user.FieldInfoNew.Count == 0)
|
if (user.FieldInfoNew.Count == 0)
|
||||||
{
|
{
|
||||||
@@ -91,7 +91,7 @@ namespace EpinelPS.LobbyServer.Stage
|
|||||||
|
|
||||||
if (clearedStage.stage_category == StageCategory.Normal || clearedStage.stage_category == StageCategory.Boss || clearedStage.stage_category == StageCategory.Hard)
|
if (clearedStage.stage_category == StageCategory.Normal || clearedStage.stage_category == StageCategory.Boss || clearedStage.stage_category == StageCategory.Hard)
|
||||||
{
|
{
|
||||||
if (clearedStage.mod == ChapterMod.Hard)
|
if (clearedStage.chapter_mod == ChapterMod.Hard)
|
||||||
{
|
{
|
||||||
if (StageId > user.LastHardStageCleared)
|
if (StageId > user.LastHardStageCleared)
|
||||||
user.LastHardStageCleared = StageId;
|
user.LastHardStageCleared = StageId;
|
||||||
@@ -135,7 +135,7 @@ namespace EpinelPS.LobbyServer.Stage
|
|||||||
// Mark chapter as completed if boss stage was completed
|
// Mark chapter as completed if boss stage was completed
|
||||||
if (clearedStage.stage_category == StageCategory.Boss && clearedStage.stage_type == StageType.Main)
|
if (clearedStage.stage_category == StageCategory.Boss && clearedStage.stage_type == StageType.Main)
|
||||||
{
|
{
|
||||||
if (clearedStage.mod == ChapterMod.Hard)
|
if (clearedStage.chapter_mod == ChapterMod.Hard)
|
||||||
user.AddTrigger(TriggerType.HardChapterClear, 1, clearedStage.chapter_id);
|
user.AddTrigger(TriggerType.HardChapterClear, 1, clearedStage.chapter_id);
|
||||||
else
|
else
|
||||||
user.AddTrigger(TriggerType.ChapterClear, 1, clearedStage.chapter_id);
|
user.AddTrigger(TriggerType.ChapterClear, 1, clearedStage.chapter_id);
|
||||||
@@ -152,10 +152,11 @@ namespace EpinelPS.LobbyServer.Stage
|
|||||||
private static void DoQuestSpecificUserOperations(User user, int clearedStageId)
|
private static void DoQuestSpecificUserOperations(User user, int clearedStageId)
|
||||||
{
|
{
|
||||||
var quest = GameData.Instance.GetMainQuestForStageClearCondition(clearedStageId);
|
var quest = GameData.Instance.GetMainQuestForStageClearCondition(clearedStageId);
|
||||||
|
|
||||||
|
user.AddTrigger(TriggerType.CampaignClear, 1, clearedStageId);
|
||||||
if (quest != null)
|
if (quest != null)
|
||||||
{
|
{
|
||||||
user.SetQuest(quest.id, false);
|
user.SetQuest(quest.id, false);
|
||||||
user.AddTrigger(TriggerType.CampaignClear, 1, clearedStageId);
|
|
||||||
user.AddTrigger(TriggerType.MainQuestClear, 1, quest.id);
|
user.AddTrigger(TriggerType.MainQuestClear, 1, quest.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace EpinelPS.LobbyServer.Stage
|
|||||||
var response = new ResEnterStage();
|
var response = new ResEnterStage();
|
||||||
|
|
||||||
var clearedStage = GameData.Instance.GetStageData(req.StageId) ?? throw new Exception("cleared stage cannot be null");
|
var clearedStage = GameData.Instance.GetStageData(req.StageId) ?? throw new Exception("cleared stage cannot be null");
|
||||||
var map = GameData.Instance.GetMapIdFromChapter(clearedStage.chapter_id, clearedStage.mod);
|
var map = GameData.Instance.GetMapIdFromChapter(clearedStage.chapter_id, clearedStage.chapter_mod);
|
||||||
|
|
||||||
if (clearedStage.stage_category == StageCategory.Boss)
|
if (clearedStage.stage_category == StageCategory.Boss)
|
||||||
{
|
{
|
||||||
@@ -27,7 +27,7 @@ namespace EpinelPS.LobbyServer.Stage
|
|||||||
info.BossEntered = true;
|
info.BossEntered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.AddTrigger(TriggerType.CampaignStart, 1);
|
user.AddTrigger(TriggerType.CampaignStart, 1, req.StageId);
|
||||||
|
|
||||||
JsonDb.Save();
|
JsonDb.Save();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user