Experimental archive support

Note archive event returns to stage 1 if hard mode is played and left unfinished
quick battle doesnt work as well
Prolouge always plays
This commit is contained in:
SELEKCJONER
2024-11-17 20:51:20 +01:00
parent 3a6cb469a6
commit f1e6899fc9
11 changed files with 381 additions and 2 deletions

View File

@@ -62,6 +62,8 @@ namespace EpinelPS.Database
public class EventData
{
public List<string> CompletedScenarios = new();
public int Diff = 0; // Default value for Diff
public int LastStage = 0; // Default value for LastStage
}
public class SynchroSlot

View File

@@ -48,6 +48,10 @@ namespace EpinelPS.StaticInfo
public Dictionary<int, LiveWallpaperRecord> lwptablemgrs = new Dictionary<int, LiveWallpaperRecord>(); // Fixed initialization
private Dictionary<int, AlbumResourceRecord> albumResourceRecords = new Dictionary<int, AlbumResourceRecord>();
public Dictionary<int, UserFrameTableRecord> userFrameTable = new Dictionary<int, UserFrameTableRecord>();
public Dictionary<int, ArchiveRecordManagerRecord> archiveRecordManagerTable = new Dictionary<int, ArchiveRecordManagerRecord>();
public Dictionary<int, ArchiveEventStoryRecord> archiveEventStoryRecords = new Dictionary<int, ArchiveEventStoryRecord>();
public Dictionary<int, ArchiveEventQuestRecord> archiveEventQuestRecords = new Dictionary<int, ArchiveEventQuestRecord>();
public Dictionary<int, ArchiveEventDungeonStageRecord> archiveEventDungeonStageRecords = new Dictionary<int, ArchiveEventDungeonStageRecord>();
@@ -378,6 +382,12 @@ namespace EpinelPS.StaticInfo
OutpostBattle.Add(obj.id, obj);
}
var archiveRecordManagerTableData = await LoadZip<ArchiveRecordManagerTable>("ArchiveRecordManagerTable.json", progress);
foreach (var obj in archiveRecordManagerTableData.records)
{
archiveRecordManagerTable.Add(obj.id, obj);
}
var gachaTypeTable = await LoadZip<GachaTypeTable>("GachaTypeTable.json", progress);
// Add the records to the dictionary
@@ -407,6 +417,26 @@ namespace EpinelPS.StaticInfo
{
userFrameTable[record.id] = record;
}
// Load and parse ArchiveEventDungeonStageTable.json
var archiveEventDungeonStageData = await LoadZip<ArchiveEventDungeonStageTable>("ArchiveEventDungeonStageTable.json", progress);
foreach (var obj in archiveEventDungeonStageData.records)
{
archiveEventDungeonStageRecords.Add(obj.id, obj);
}
// Load and parse ArchiveEventStoryTable.json
var archiveEventStoryTable = await LoadZip<ArchiveEventStoryTable>("ArchiveEventStoryTable.json", progress);
foreach (var obj in archiveEventStoryTable.records)
{
archiveEventStoryRecords.Add(obj.id, obj);
}
// Load and parse ArchiveEventQuestTable.json
var archiveEventQuestTable = await LoadZip<ArchiveEventQuestTable>("ArchiveEventQuestTable.json", progress);
foreach (var obj in archiveEventQuestTable.records)
{
archiveEventQuestRecords.Add(obj.id, obj);
}
var albumResourceTable = await LoadZip<AlbumResourceTable>("AlbumResourceTable.json", progress);
foreach (var obj in albumResourceTable.records)

View File

@@ -318,4 +318,76 @@
public List<UserFrameTableRecord> records;
}
public class ArchiveRecordManagerRecord
{
public int id;
public string record_type;
public string record_title_locale;
public int record_main_archive_event_id;
public int record_list_order;
public int unlock_ticket_id;
public int unlock_ticket_count;
public int reward_info_list_id;
public int event_quest_clear_reward_id;
public int recommended_story_list_id;
public int included_contents_group_id;
public string record_slot_bg_addressable;
public string record_unlock_bg_addressable;
}
public class ArchiveRecordManagerTable
{
public List<ArchiveRecordManagerRecord> records;
}
public class ArchiveEventStoryRecord
{
public int id;
public int event_id;
public string prologue_scenario = "";
public int dungeon_id;
public int album_category_group;
public string ui_prefab = "";
public int archive_ticket_item_id;
public int archive_currency_item_id;
}
public class ArchiveEventStoryTable
{
public List<ArchiveEventStoryRecord> records;
}
public class ArchiveEventQuestRecord
{
public int id;
public int event_quest_manager_id;
public string condition_type = "";
public int condition_value;
public string name_localkey = "";
public string description_localkey = "";
public int next_quest_id;
public string end_scenario_id = "";
}
public class ArchiveEventQuestTable
{
public List<ArchiveEventQuestRecord> records;
}
public class ArchiveEventDungeonStageRecord
{
public int id;
public int group;
public int step;
public string stage_name = "";
public string stage_contents_type = "";
public int stage_id;
public bool is_repeat_clear;
}
public class ArchiveEventDungeonStageTable
{
public List<ArchiveEventDungeonStageRecord> records;
}
}

View File

@@ -0,0 +1,43 @@
using EpinelPS.Utils;
using EpinelPS.Database;
namespace EpinelPS.LobbyServer.Msgs.Archive
{
[PacketPath("/archive/storydungeon/clearstage")]
public class ClearArchiveStage : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqClearArchiveStage>(); // has fields EventId, StageId, BattleResult
var evid = req.EventId;
var stgid = req.StageId;
var result = req.BattleResult; // if 2 add to event info as last stage
var user = GetUser();
if (user == null)
{
throw new Exception("User not found.");
}
// Check if the EventInfo exists for the given EventId
if (!user.EventInfo.ContainsKey(evid))
{
throw new Exception($"Event with ID {evid} not found.");
}
// Update the EventData if BattleResult is 2
if (result == 1)
{
var eventData = user.EventInfo[evid];
// Update the LastStage in EventData
eventData.LastStage = stgid;
}
JsonDb.Save();
var response = new ResClearArchiveStage();
// Send the response back to the client
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,18 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Archive
{
[PacketPath("/archive/storydungeon/enterstage")]
public class EnterArchiveStage : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqEnterArchiveStage>();// has fields EventId StageId TeamNumber
var evid = req.EventId;
var response = new ResEnterArchiveStage();
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,38 @@
using EpinelPS.Utils;
using EpinelPS.Database;
using EpinelPS.StaticInfo; // Ensure this namespace is included
namespace EpinelPS.LobbyServer.Msgs.Archive
{
[PacketPath("/archive/scenario/complete")]
public class CompleteScenario : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqCompleteArchiveScenario>(); // req has EventId, ScenarioId, DialogType fields
var evid = req.EventId;
var scenid = req.ScenarioId;
var dialtyp = req.DialogType;
var user = GetUser();
// Ensure we are working with the user's EventInfo and not CompletedScenarios
if (!user.EventInfo.TryGetValue(evid, out var evt))
{
// Create a new EventData if the event doesn't exist
evt = new EventData();
user.EventInfo[evid] = evt;
}
// Ensure the CompletedScenarios list is initialized and add the ScenarioId
if (!evt.CompletedScenarios.Contains(scenid))
{
evt.CompletedScenarios.Add(scenid);
}
JsonDb.Save();
// Prepare and send the response
var response = new ResCompleteArchiveScenario();
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,38 @@
using EpinelPS.Utils;
using EpinelPS.Database;
namespace EpinelPS.LobbyServer.Msgs.Archive
{
[PacketPath("/archive/storydungeon/fastclearstage")]
public class FastClearArchiveStage : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqFastClearArchiveStage>();
var evid = req.EventId;
var stgid = req.StageId;
var user = GetUser();
if (user == null)
{
throw new Exception("User not found.");
}
// Check if the EventInfo exists for the given EventId
if (!user.EventInfo.ContainsKey(evid))
{
throw new Exception($"Event with ID {evid} not found.");
}
var eventData = user.EventInfo[evid];
// Update the LastStage in EventData
eventData.LastStage = stgid;
JsonDb.Save();
var response = new ResFastClearArchiveStage();
// Send the response back to the client
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,50 @@
using EpinelPS.Utils;
using EpinelPS.Database;
namespace EpinelPS.LobbyServer.Msgs.Archive
{
[PacketPath("/archive/storydungeon/get")]
public class GetArchiveStoryDungeon : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqGetArchiveStoryDungeon>(); // has EventId field
var evid = req.EventId;
// Retrieve the user based on session (assuming GetCurrentUser is defined elsewhere)
var user = GetUser();
if (user == null)
{
throw new Exception("User not found.");
}
// Access EventData directly
if (!user.EventInfo.ContainsKey(evid))
{
throw new Exception($"Event with ID {evid} not found.");
}
var eventData = user.EventInfo[evid];
// Prepare the response
var response = new ResGetArchiveStoryDungeon();
// Populate team data
response.TeamData = new NetUserTeamData()
{
LastContentsTeamNumber = 1,
Type = 1
};
// Populate the last cleared stage
response.LastClearedArchiveStageList.Add(new NetLastClearedArchiveStage()
{
DifficultyId = eventData.Diff,
StageId = eventData.LastStage
});
// Send the response
await WriteDataAsync(response);
}
}
}

View File

@@ -1,4 +1,5 @@
using EpinelPS.Utils;
using EpinelPS.StaticInfo;
namespace EpinelPS.LobbyServer.Msgs.Archive
{
@@ -10,8 +11,20 @@ namespace EpinelPS.LobbyServer.Msgs.Archive
var req = await ReadData<ReqGetArchiveRecord>();
var response = new ResGetArchiveRecord();
response.ArchiveRecordManagerList.AddRange([100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800]);
response.UnlockedArchiveRecordList.AddRange([100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800]);
// Explicitly select IDs from the records
var allIds = GameData.Instance.archiveRecordManagerTable.Values.Select(record => record.id).ToList();
// Add the IDs to the response lists
response.ArchiveRecordManagerList.AddRange(allIds);
response.UnlockedArchiveRecordList.AddRange(allIds);
// Get entries with record_type "EventQuest"
var eventQuestRecords = GameData.Instance.archiveRecordManagerTable.Values.Where(record => record.record_type == "EventQuest").ToList();
response.UnlockedArchiveEventQuestList.AddRange(eventQuestRecords.Select(record => record.id));
// TODO: allow unlocking
await WriteDataAsync(response);
}

View File

@@ -0,0 +1,53 @@
using EpinelPS.Utils;
using EpinelPS.StaticInfo; // Ensure this namespace is included
namespace EpinelPS.LobbyServer.Msgs.Archive
{
[PacketPath("/archive/scenario/getnonresettable")]
public class GetNonResettable : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqGetNonResettableArchiveScenario>(); // req has EventId field
var evid = req.EventId;
var response = new ResGetNonResettableArchiveScenario();
// Access the GameData instance
var gameData = GameData.Instance;
if (evid == 130002)
{
// Directly use the archiveEventQuestRecords dictionary
foreach (var record in gameData.archiveEventQuestRecords.Values)
{
if (record.event_quest_manager_id == evid)
{
// Add the end_scenario_id to the ScenarioIdList
if (!string.IsNullOrEmpty(record.end_scenario_id))
{
response.ScenarioIdList.Add(record.end_scenario_id);
}
}
}
}
else
{
// Directly use the archiveEventStoryRecords dictionary
foreach (var record in gameData.archiveEventStoryRecords.Values)
{
if (record.event_id == evid)
{
// Add the prologue_scenario to the ScenarioIdList
if (!string.IsNullOrEmpty(record.prologue_scenario))
{
response.ScenarioIdList.Add(record.prologue_scenario);
}
}
}
}
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,22 @@
using EpinelPS.Utils;
using EpinelPS.StaticInfo;
namespace EpinelPS.LobbyServer.Msgs.Archive
{
[PacketPath("/archive/scenario/getresettable")]
public class GetResettable : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqGetResettableArchiveScenario>();
var response = new ResGetResettableArchiveScenario(); // has ScenarioIdList field that takes in strings
// Retrieve stage IDs from GameData
var stageIds = GameData.Instance.archiveEventDungeonStageRecords.Values.Select(record => record.stage_id.ToString()).ToList();
// Add them to the response
response.ScenarioIdList.Add(stageIds);
await WriteDataAsync(response);
}
}
}