Adds a lot of stuff

- new commands
SetLevel (level) - Set all characters' level (between 1 and 999 takes effect on game and server restart)

SetSkillLevel (level) - Set all characters' skill levels between 1 and 10 (takes effect on game and server restart)

addallcharacters - Add all missing characters to the selected user with default levels and skills (takes effect on game and server restart)

- partial gacha support works
only 10x adds bodies (they still cant be used and it includes normally inaccesible characters like marian)

-partial jukebox support allows for listening but not setting lobby / commanders room bgm unless manually changed in db.json
This commit is contained in:
SELEKCJONER
2024-09-10 01:14:00 +02:00
parent 61075aae37
commit 84c0d18255
38 changed files with 1316 additions and 49 deletions

View File

@@ -129,9 +129,9 @@ namespace EpinelPS.Database
public string Nickname = "SomePlayer";
public int ProfileIconId = 39900;
public bool ProfileIconIsPrism = false;
public int ProfileFrame = 1;
public int ProfileFrame = 25;
public bool IsAdmin = false;
public bool sickpulls = false;
public bool IsBanned = false;
public DateTime BanStart;
public DateTime BanEnd;
@@ -170,7 +170,7 @@ namespace EpinelPS.Database
public List<int> CompletedSideStoryStages = new();
public List<int> Memorial = new();
public List<int> JukeboxBgm = new();
public List<int> JukeboxBgm = new List<int>();
// Event data
public Dictionary<int, EventData> EventInfo = new();
@@ -442,5 +442,44 @@ namespace EpinelPS.Database
File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "/db.json", JsonConvert.SerializeObject(Instance, Formatting.Indented));
}
}
public static int CurrentJukeboxBgm(int position)
{
var activeJukeboxBgm = new List<int>();
//important first position holds lobby bgm id and second commanders room bgm id
foreach (var user in Instance.Users)
{
if (user.JukeboxBgm == null || user.JukeboxBgm.Count == 0)
{
// this if statemet only exists becaus some weird black magic copies default value over and over
//in the file when its set in public List<int> JukeboxBgm = new List<int>();
//delete when or if it gets fixed
user.JukeboxBgm = new List<int> { 2,5 };
}
activeJukeboxBgm.AddRange(user.JukeboxBgm);
}
if (activeJukeboxBgm.Count == 0)
{
return 8995001;
}
position = (position == 2 && activeJukeboxBgm.Count > 1) ? 2 : 1;
return activeJukeboxBgm[position - 1];
}
public static bool IsSickPulls(User selectedUser)
{
if (selectedUser != null)
{
return selectedUser.sickpulls;
}
else
{
throw new Exception($"User with ID {selectedUser.ID} not found");
}
}
}
}

View File

@@ -22,6 +22,7 @@ namespace EpinelPS.StaticInfo
return _instance;
}
}
private ZipFile MainZip;
private MemoryStream ZipStream;
private Dictionary<int, MainQuestCompletionRecord> questDataRecords;
@@ -30,16 +31,21 @@ namespace EpinelPS.StaticInfo
private JArray userExpDataRecords;
private Dictionary<int, CampaignChapterRecord> chapterCampaignData;
private JArray characterCostumeTable;
private Dictionary<int, CharacterRecord> characterTable;
public Dictionary<int, CharacterRecord> characterTable;
private Dictionary<int, ClearedTutorialData> tutorialTable;
private Dictionary<int, ItemEquipRecord> itemEquipTable;
private Dictionary<string, JArray> FieldMapData = [];
private Dictionary<int, CharacterLevelData> LevelData = [];
private Dictionary<int, TacticAcademyLessonRecord> TacticAcademyLessons = [];
public Dictionary<int, int> SidestoryRewardTable = [];
public Dictionary<string, int> PositionReward = new Dictionary<string, int>();
public Dictionary<int, FieldItemRecord> FieldItems = [];
public Dictionary<int, OutpostBattleTableRecord> OutpostBattle = [];
private Dictionary<string, JArray> FieldMapData = new Dictionary<string, JArray>(); // Fixed initialization
private Dictionary<int, CharacterLevelData> LevelData = new Dictionary<int, CharacterLevelData>(); // Fixed initialization
private Dictionary<int, TacticAcademyLessonRecord> TacticAcademyLessons = new Dictionary<int, TacticAcademyLessonRecord>(); // Fixed initialization
public Dictionary<int, int> SidestoryRewardTable = new Dictionary<int, int>(); // Fixed initialization
public Dictionary<string, int> PositionReward = new Dictionary<string, int>(); // Fixed initialization
public Dictionary<int, FieldItemRecord> FieldItems = new Dictionary<int, FieldItemRecord>(); // Fixed initialization
public Dictionary<int, OutpostBattleTableRecord> OutpostBattle = new Dictionary<int, OutpostBattleTableRecord>(); // Fixed initialization
public Dictionary<int, JukeboxListRecord> jukeboxListDataRecords;
private Dictionary<int, JukeboxThemeRecord> jukeboxThemeDataRecords;
public Dictionary<int, GachaType> gachaTypes = new Dictionary<int, GachaType>(); // Fixed initialization
public Dictionary<int, EventManager> eventManagers = new Dictionary<int, EventManager>();
public byte[] Sha256Hash;
public int Size;
@@ -74,6 +80,10 @@ namespace EpinelPS.StaticInfo
tutorialTable = new();
itemEquipTable = new();
// Initialize Jukebox data dictionaries
jukeboxListDataRecords = new Dictionary<int, JukeboxListRecord>();
jukeboxThemeDataRecords = new Dictionary<int, JukeboxThemeRecord>();
var rawBytes = File.ReadAllBytes(filePath);
Sha256Hash = SHA256.HashData(rawBytes);
Size = rawBytes.Length;
@@ -81,6 +91,7 @@ namespace EpinelPS.StaticInfo
LoadGameData(filePath);
if (MainZip == null) throw new Exception("failed to read zip file");
}
#region Data loading
private static byte[] PresharedValue = [0xCB, 0xC2, 0x1C, 0x6F, 0xF3, 0xF5, 0x07, 0xF5, 0x05, 0xBA, 0xCA, 0xD4, 0x98, 0x28, 0x84, 0x1F, 0xF0, 0xD1, 0x38, 0xC7, 0x61, 0xDF, 0xD6, 0xE6, 0x64, 0x9A, 0x85, 0x13, 0x3E, 0x1A, 0x6A, 0x0C, 0x68, 0x0E, 0x2B, 0xC4, 0xDF, 0x72, 0xF8, 0xC6, 0x55, 0xE4, 0x7B, 0x14, 0x36, 0x18, 0x3B, 0xA7, 0xD1, 0x20, 0x81, 0x22, 0xD1, 0xA9, 0x18, 0x84, 0x65, 0x13, 0x0B, 0xED, 0xA3, 0x00, 0xE5, 0xD9];
private static RSAParameters LoadParameters = new RSAParameters()
@@ -197,6 +208,7 @@ namespace EpinelPS.StaticInfo
outputStream.WriteByte((byte)(((byte)b) ^ mask));
}
}
public static async Task Load()
{
var targetFile = await AssetDownloadUtil.DownloadOrGetFileAsync(GameConfig.Root.StaticData.Url, CancellationToken.None);
@@ -205,6 +217,7 @@ namespace EpinelPS.StaticInfo
_instance = new(targetFile);
}
#endregion
private async Task<T> LoadZip<T>(string entry, ProgressBar bar)
{
var mainQuestData = MainZip.GetEntry(entry);
@@ -213,7 +226,6 @@ namespace EpinelPS.StaticInfo
using StreamReader mainQuestReader = new StreamReader(MainZip.GetInputStream(mainQuestData));
var mainQuestDataString = await mainQuestReader.ReadToEndAsync();
var questdata = JsonConvert.DeserializeObject<T>(mainQuestDataString);
if (questdata == null) throw new Exception("failed to parse " + entry);
@@ -222,6 +234,7 @@ namespace EpinelPS.StaticInfo
return questdata;
}
private async Task<JArray> LoadZip(string entry, ProgressBar bar)
{
var mainQuestData = MainZip.GetEntry(entry);
@@ -230,7 +243,6 @@ namespace EpinelPS.StaticInfo
using StreamReader mainQuestReader = new StreamReader(MainZip.GetInputStream(mainQuestData));
var mainQuestDataString = await mainQuestReader.ReadToEndAsync();
var questdata = JObject.Parse(mainQuestDataString);
if (questdata == null) throw new Exception("failed to parse " + entry);
@@ -243,6 +255,7 @@ namespace EpinelPS.StaticInfo
return records;
}
int totalFiles = 78;
int currentFile = 0;
@@ -347,18 +360,62 @@ namespace EpinelPS.StaticInfo
}
}
}
var battleOutpostTable = await LoadZip<OutpostBattleTable>("OutpostBattleTable.json", progress);
foreach (var obj in battleOutpostTable.records)
{
OutpostBattle.Add(obj.id, obj);
}
var gachaTypeTable = await LoadZip<GachaTypeTable>("GachaTypeTable.json", progress);
// Add the records to the dictionary
foreach (var obj in gachaTypeTable.records)
{
gachaTypes.Add(obj.id, obj); // Use obj.id as the key and obj (the GachaType) as the value
}
var eventManagerTable = await LoadZip<EventManagerTable>("EventManagerTable.json", progress);
var fieldItems = await LoadZip<FieldItemTable>("FieldItemTable.json", progress);
foreach (var obj in fieldItems.records)
// Add the records to the dictionary
foreach (var obj in eventManagerTable.records)
{
eventManagers.Add(obj.id, obj); // Use obj.id as the key and obj (the EventManager) as the value
}
// Load Jukebox data
await LoadJukeboxListData(progress);
await LoadJukeboxThemeData(progress);
}
public async Task LoadJukeboxListData(ProgressBar bar)
{
var jukeboxListData = await LoadZip("JukeboxListTable.json", bar);
foreach (JObject obj in jukeboxListData)
{
FieldItems.Add(obj.id, obj);
var record = obj.ToObject<JukeboxListRecord>();
if (record != null)
{
jukeboxListDataRecords.Add(record.id, record);
}
}
}
public Dictionary<int, JukeboxListRecord> GetJukeboxListDataRecords()
{
return jukeboxListDataRecords;
}
var battleOutpostTable = await LoadZip<OutpostBattleTable>("OutpostBattleTable.json", progress);
foreach (var obj in battleOutpostTable.records)
public async Task LoadJukeboxThemeData(ProgressBar bar)
{
var jukeboxThemeData = await LoadZip("JukeboxThemeTable.json", bar);
foreach (JObject obj in jukeboxThemeData)
{
OutpostBattle.Add(obj.id, obj);
var record = obj.ToObject<JukeboxThemeRecord>();
if (record != null)
{
jukeboxThemeDataRecords.Add(record.id, record);
}
}
}
@@ -507,5 +564,18 @@ namespace EpinelPS.StaticInfo
{
return TacticAcademyLessons[lessonId];
}
// Methods to access Jukebox data
public JukeboxListRecord? GetJukeboxListRecordById(int id)
{
jukeboxListDataRecords.TryGetValue(id, out var record);
return record;
}
public JukeboxThemeRecord? GetJukeboxThemeRecordById(int id)
{
jukeboxThemeDataRecords.TryGetValue(id, out var record);
return record;
}
}
}

View File

@@ -130,7 +130,9 @@
public class CharacterRecord
{
public int id;
// TODO: There is more stuff here but it isn't needed yet
public int piece_id;
public string original_rare;
public string corporation;
}
public class CharacterTable
{
@@ -159,7 +161,39 @@
{
public List<FieldItemRecord> records;
}
public class JukeboxListRecord
{
public int id;
public int theme;
public string bgm ;
public bool is_loop;
public int play_time;
public string name ;
public int order;
public string artist;
public string get_info_type;
public string get_info_value;
}
public class JukeboxListTable
{
public List<JukeboxListRecord> records;
}
public class JukeboxThemeRecord
{
public int id;
public string name_localkey;
public string description_localkey;
public int order;
public string theme_resource;
public string bg_color;
}
public class JukeboxThemeTable
{
public List<JukeboxThemeRecord> records;
}
public class OutpostBattleTableRecord
{
public int id;
@@ -172,4 +206,68 @@
{
public List<OutpostBattleTableRecord> records;
}
public class GachaPriceGroup
{
public int gacha_price_type;
public int gacha_price_value_count_1;
public int daily_gacha_discount_price_value_1;
public int gacha_price_value_count_10;
}
public class GachaType
{
public int id;
public string type;
public int order_id;
public int event_id;
public string gacha_provide_count_type;
public bool use_daily_discount_one;
public int daily_free_gacha_event_id;
public List<GachaPriceGroup> gacha_price_group;
public int grade_prob_id;
public bool is_max_count;
public int max_ceiling_count;
public int fixed_char_amount;
public string gacha_page_prefab;
public int pickup_char_group_id;
public bool use_wish_list;
public int gacha_play_max_count;
public int gacha_reward_id;
public int gacha_play_max_count_reward_id;
public int previous_gacha_id;
}
public class GachaTypeTable
{
public List<GachaType> records;
}
public class EventManager
{
public int id;
public string event_system_type;
public string event_shortcut_id;
public string name_localkey;
public string description_localkey;
public string schedule_type;
public string schedule_value;
public string event_disable_locale;
public string event_resource_id;
public string event_thumbnail_resource_table;
public string event_thumbnail_resource_id;
public string thumbnail_color;
public string event_banner_resource_table;
public string event_banner_resource_id;
public long event_order;
public bool is_popup;
public string active_type;
public string banner_print_type;
}
public class EventManagerTable
{
public List<EventManager> records;
}
}

View File

@@ -100,8 +100,8 @@ namespace EpinelPS.LobbyServer.Msgs.Event
response.EventList.Add(new NetEventData()
{
Id = 40053,
EventSystemType = 5,
Id = 70034,
EventSystemType = 6,
EventVisibleDate = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)).Ticks,
EventStartDate = DateTime.UtcNow.Subtract(TimeSpan.FromDays(1)).Ticks,
EventEndDate = DateTime.Now.AddDays(20).Ticks,

View File

@@ -2,45 +2,185 @@
using EpinelPS.StaticInfo;
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Gacha
{
[PacketPath("/gacha/execute")]
public class ExecGacha : LobbyMsgHandler
{
private static readonly Random random = new Random();
// Exclusion lists for sick pulls mode and normal mode 2500601 is the broken R rarity dorothy
private static readonly List<int> sickPullsExclusionList = new List<int> { 2500601 }; // Add more IDs as needed
private static readonly List<int> normalPullsExclusionList = new List<int> { 2500601 }; // Add more IDs as needed
protected override async Task HandleAsync()
{
var req = await ReadData<ReqExecuteGacha>();
var user = GetUser();
var response = new ResExecuteGacha();
// TODO: Pick random character that player does not have unless it supports limit break.
var allCharacterData = GameData.Instance.characterTable.Values.ToList();
// TODO implement reward
response.Reward = new NetRewardData();
// Separate characters by rarity categories
var rCharacters = allCharacterData.Where(c => c.original_rare == "R").ToList();
var srCharacters = allCharacterData.Where(c => c.original_rare == "SR").ToList();
// Separate Pilgrim SSRs and non-Pilgrim SSRs
var pilgrimCharacters = allCharacterData.Where(c => c.original_rare == "SSR" && c.corporation == "PILGRIM").ToList();
var ssrCharacters = allCharacterData.Where(c => c.original_rare == "SSR" && c.corporation != "PILGRIM").ToList();
foreach (var c in GameData.Instance.GetAllCharacterTids())
var selectedCharacters = new List<CharacterRecord>();
// Check if user has 'sickpulls' set to true to use old method
if (user.sickpulls)
{
if (!user.HasCharacter(c))
// Old selection method: Randomly select 10 characters without rarity-based selection, excluding characters in the sickPullsExclusionList
selectedCharacters = allCharacterData
.Where(c => !sickPullsExclusionList.Contains(c.id)) // Exclude characters based on the exclusion list for sick pulls
.OrderBy(x => random.Next())
.Take(10)
.ToList();
}
else
{
// New method: Select 10 characters, with each character having its category determined independently, excluding characters in the normalPullsExclusionList
for (int i = 0; i < 10; i++)
{
var id = user.GenerateUniqueCharacterId();
response.Gacha.Add(new NetGachaEntityData() { Corporation = 1, PieceCount = 1, CurrencyValue = 5, Sn = id, Tid = c, Type = 1 });
response.Characters.Add(new NetUserCharacterDefaultData() { CostumeId = 0, Csn = id, Grade = 0, Level = 1, Skill1Lv = 1, Skill2Lv = 1, Tid = c, UltiSkillLv = 1 });
user.Characters.Add(new Database.Character() { CostumeId = 0, Csn = id, Grade = 0, Level = 1, Skill1Lvl = 1, Skill2Lvl = 1, Tid = c, UltimateLevel = 1 });
}
else
{
// TODO add spare body
var character = SelectRandomCharacter(rCharacters, srCharacters, ssrCharacters, pilgrimCharacters, normalPullsExclusionList);
selectedCharacters.Add(character);
}
}
var pieceIds = new List<Tuple<int, int>>(); // 2D array to store characterId and pieceId as Tuple
// Populate the 2D array with characterId and pieceId for each selected character
foreach (var characterData in selectedCharacters)
{
var characterId = characterData.id;
var pieceId = characterData.piece_id;
// Store characterId and pieceId in the array
pieceIds.Add(Tuple.Create(characterId, pieceId));
var id = user.GenerateUniqueCharacterId();
response.Gacha.Add(new NetGachaEntityData()
{
Corporation = 1,
PieceCount = 1,
CurrencyValue = 5,
Sn = id,
Tid = characterId,
Type = 1
});
// Check if the user already has the character, if not add it
if (!user.HasCharacter(characterId))
{
response.Characters.Add(new NetUserCharacterDefaultData()
{
CostumeId = 0,
Csn = id,
Grade = 0,
Level = 1,
Skill1Lv = 1,
Skill2Lv = 1,
Tid = characterId,
UltiSkillLv = 1
});
}
if (!user.HasCharacter(characterId))
{
user.Characters.Add(new Database.Character()
{
CostumeId = 0,
Csn = id,
Grade = 0,
Level = 1,
Skill1Lvl = 1,
Skill2Lvl = 1,
Tid = characterId,
UltimateLevel = 1
});
}
}
// Add each character's item to user.Items if the character exists in user.Characters
foreach (var characterData in selectedCharacters)
{
if (user.Characters.Any(c => c.Tid == characterData.id))
{
user.Items.Add(new Database.ItemData()
{
ItemType = characterData.piece_id, // Assuming item id corresponds to character id
Csn = characterData.piece_id,
Count = 1, // or any relevant count
Level = 0,
Exp = 0,
Position = 0,
Corp = 0,
Isn = user.GenerateUniqueItemId()
});
response.Items.Add(new NetUserItemData()
{
Tid = characterData.piece_id, // Assuming item id corresponds to character id
Csn = characterData.piece_id,
Count = 1, // or any relevant count
Level = 0,
Exp = 0,
Position = 0,
Isn = user.GenerateUniqueItemId()
});
}
}
user.GachaTutorialPlayCount++;
JsonDb.Save();
await WriteDataAsync(response);
}
private CharacterRecord SelectRandomCharacter(List<CharacterRecord> rCharacters, List<CharacterRecord> srCharacters, List<CharacterRecord> ssrCharacters, List<CharacterRecord> pilgrimCharacters, List<int> exclusionList)
{
// Remove excluded characters from each category
var availableRCharacters = rCharacters.Where(c => !exclusionList.Contains(c.id)).ToList();
var availableSRCharacters = srCharacters.Where(c => !exclusionList.Contains(c.id)).ToList();
var availableSSRCharacters = ssrCharacters.Where(c => !exclusionList.Contains(c.id)).ToList();
var availablePilgrimCharacters = pilgrimCharacters.Where(c => !exclusionList.Contains(c.id)).ToList();
// Each time we call this method, a new category will be selected for a single character
double roll = random.NextDouble() * 100; // Roll from 0 to 100
if (roll < 53 && availableRCharacters.Any())
{
// R category
return availableRCharacters[random.Next(availableRCharacters.Count)];
}
else if (roll < 53 + 43 && availableSRCharacters.Any())
{
// SR category
return availableSRCharacters[random.Next(availableSRCharacters.Count)];
}
else
{
// SSR category
double ssrRoll = random.NextDouble() * 100;
if (ssrRoll < 4.55 && availablePilgrimCharacters.Any())
{
// PILGRIM SSR
return availablePilgrimCharacters[random.Next(availablePilgrimCharacters.Count)];
}
else if (availableSSRCharacters.Any())
{
// Non-PILGRIM SSR
return availableSSRCharacters[random.Next(availableSSRCharacters.Count)];
}
}
// Fallback to a random R character if somehow no SSR characters are left after exclusion
return availableRCharacters.Any() ? availableRCharacters[random.Next(availableRCharacters.Count)] : null;
}
}
}

View File

@@ -1,4 +1,5 @@
using EpinelPS.Utils;
using EpinelPS.StaticInfo;
namespace EpinelPS.LobbyServer.Msgs
{
@@ -11,8 +12,24 @@ namespace EpinelPS.LobbyServer.Msgs
var user = GetUser();
var response = new ResGetGachaData();
// Adding a default GachaType if the tutorial is done
if (user.GachaTutorialPlayCount > 0)
{
response.Gacha.Add(new NetUserGachaData() { GachaType = 3, PlayCount = 1 });
}
// Now let's loop through gachaTypes and add those with "type" == "GachaPickup"
foreach (var gacha in GameData.Instance.gachaTypes.Values) // We're looping through the dictionary's values
{
if (gacha.type == "GachaPickup")
{
// Add this GachaType ID to the response
response.Gacha.Add(new NetUserGachaData() { GachaType = gacha.id, PlayCount = 1 });
}
}
// Write the response back
await WriteDataAsync(response);
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/changemasterrole")]
public class ChangeDaveMasterRole : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqChangeDaveMasterRole>();
var response = new ResChangeDaveMasterRole
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/clearbagnew")]
public class ClearDaveBagNewIcon : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqClearDaveBagNewIcon>();
var response = new ResClearDaveBagNewIcon
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/clearsushinew")]
public class ClearDaveSushiNewIcon : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqClearDaveSushiNewIcon>();
var response = new ResClearDaveSushiNewIcon
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,21 @@
using EpinelPS.Utils;
using Google.Protobuf.Collections;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/completedive")]
public class CompleteDaveDive : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqCompleteDaveDive>();
var response = new ResCompleteDaveDive
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,21 @@
using EpinelPS.Utils;
using Google.Protobuf.Collections;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/completesushi")]
public class CompleteDaveSushi : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqCompleteDaveSushi>();
var response = new ResCompleteDaveSushi
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,21 @@
using EpinelPS.Utils;
using Google.Protobuf.Collections;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/deductitem")]
public class DeductDaveItem : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqDeductDaveItem>();
var response = new ResDeductDaveItem
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,21 @@
using EpinelPS.Utils;
using Google.Protobuf.Collections;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/getalldavetrigger")]
public class GetAllMiniGameDaveTriggers : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqGetAllMiniGameDaveTriggers>();
var response = new ResGetAllMiniGameDaveTriggers
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/getdata")]
public class GetDaveData : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqGetDaveData>();
var response = new ResGetDaveData
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,21 @@
using EpinelPS.Utils;
using Google.Protobuf.Collections;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/driftbottle")]
public class MiniGameDaveDriftBottle : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqMiniGameDaveDriftBottle>();
var response = new ResMiniGameDaveDriftBottle
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,21 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/getranking")]
public class GetMiniGameDaveRanking : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqGetMiniGameDaveRanking>();
var response = new ResGetMiniGameDaveRanking
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/obtainmissionreward")]
public class ObtainMiniGameDaveMissionReward : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqObtainMiniGameDaveMissionReward>();
var response = new ResObtainMiniGameDaveMissionReward
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,21 @@
using EpinelPS.Utils;
using Google.Protobuf.Collections;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/reportdiverroundflow")]
public class ReportDiverRoundFlow : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqReportDiverRoundFlow>();
var response = new ResReportDiverRoundFlow
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/setmenus")]
public class SetDaveSushiMenus : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqSetDaveSushiMenus>();
var response = new ResSetDaveSushiMenus
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/sushiemploy")]
public class DaveSushiEmployee : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqDaveSushiEmployee>();
var response = new ResDaveSushiEmployee
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/unlockrole")]
public class UnlockDaveRole : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqUnlockDaveRole>();
var response = new ResUnlockDaveRole
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/unlocksushi")]
public class DaveUnlockSushi : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqDaveUnlockSushi>();
var response = new ResDaveUnlockSushi
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,21 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/upgradesushi")]
public class UpgradeDaveSushi : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqUpgradeDaveSushi>();
var response = new ResUpgradeDaveSushi
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("event/minigame/dave/upgradeequipment")]
public class UpgradeDaveEquipment : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqUpgradeDaveEquipment>();
var response = new ResUpgradeDaveEquipment
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,19 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("/event/minigame/islandadventure/get/currency")]
public class MiniGameIslandAdventureCurrency : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqGetMiniGameIslandAdventureCurrency>();
var response = new ResGetMiniGameIslandAdventureCurrency
{
Currency = 90000
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("/event/minigame/islandadventure/get/inventory")]
public class MiniGameIslandAdventureInventory : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqGetMiniGameIslandAdventureInventory>();
var response = new ResGetMiniGameIslandAdventureInventory
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("/event/minigame/islandadventure/get/fish/spotcount")]
public class MiniGameIslandAdventureFishingSpotCountHistory : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqMiniGameIslandAdventureFishingSpotCountHistory>();
var response = new ResMiniGameIslandAdventureFishingSpotCountHistory
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,20 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Event
{
[PacketPath("/event/minigame/islandadventure/get/photo/album")]
public class MiniGameIslandAdventurePhotoAlbum : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqMiniGameIslandAdventurePhotoAlbum>();
var response = new ResMiniGameIslandAdventurePhotoAlbum
{
};
await WriteDataAsync(response);
}
}
}

View File

@@ -1,5 +1,6 @@
using EpinelPS.Utils;
using EpinelPS.Database;
using EpinelPS.StaticInfo;
namespace EpinelPS.LobbyServer.Msgs.Outpost
{
[PacketPath("/outpost/getoutpostdata")]
@@ -20,16 +21,24 @@ namespace EpinelPS.LobbyServer.Msgs.Outpost
{
OutpostBattleLevel = user.OutpostBattleLevel,
Jukebox = new() { SelectTid = 5 },
JukeboxV2 = new NetUserJukeboxDataV2() { CommandBgm = new() { Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, JukeboxTableId = 5 } },
JukeboxV2 = new NetUserJukeboxDataV2() { CommandBgm = new() { Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, JukeboxTableId = JsonDb.CurrentJukeboxBgm(2) } },
BattleTime = 864000000000,
MaxBattleTime = 864000000000,
SkinGroupId = 1000,
};
// TODO: do not hard code this!
response.Jukebox.List.AddRange([5, 9999901, 4001, 4002, 4003, 4004, 4005, 4006, 12, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4036, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012]);
response.JukeboxV2.JukeboxTableIds.AddRange([5, 9999901, 4001, 4002, 4003, 4004, 4005, 4006, 12, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4036, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012]);
//response.Jukebox.List.AddRange([5, 9999901, 4001, 4002, 4003, 4004, 4005, 4006, 12, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4036, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012]);
//response.JukeboxV2.JukeboxTableIds.AddRange([5, 9999901, 4001, 4002, 4003, 4004, 4005, 4006, 12, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4036, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012]);
// Directly use jukeboxListDataRecords
var jukeboxIds = GameData.Instance.jukeboxListDataRecords.Keys.ToList();
// Update response lists with the IDs
response.Jukebox.List.AddRange(jukeboxIds);
response.JukeboxV2.JukeboxTableIds.AddRange(jukeboxIds);
response.OutpostBattleLevel = user.OutpostBattleLevel;
response.OutpostBattleTime = new NetOutpostBattleTime() { MaxBattleTime = 864000000000, MaxOverBattleTime = 12096000000000, BattleTime = battleTimeMs, OverBattleTime = overBattleTime };

View File

@@ -0,0 +1,54 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Outpost
{
[PacketPath("/outpost/getoutpostdata")]
public class GetOutpostData : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqGetOutpostData>();
var user = GetUser();
var battleTime = DateTime.UtcNow - user.BattleTime;
var battleTimeMs = (long)(battleTime.TotalNanoseconds / 100);
long overBattleTime = battleTimeMs > 12096000000000 ? battleTimeMs - 12096000000000 : 0;
var response = new ResGetOutpostData
{
OutpostBattleLevel = user.OutpostBattleLevel,
Jukebox = new() { SelectTid = 5 },
JukeboxV2 = new NetUserJukeboxDataV2() { CommandBgm = new() { Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, JukeboxTableId = 5 } },
BattleTime = 864000000000,
MaxBattleTime = 864000000000,
SkinGroupId = 1000,
};
// TODO: do not hard code this!
response.Jukebox.List.AddRange([5, 9999901, 4001, 4002, 4003, 4004, 4005, 4006, 12, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4036, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012]);
response.JukeboxV2.JukeboxTableIds.AddRange([5, 9999901, 4001, 4002, 4003, 4004, 4005, 4006, 12, 4007, 4008, 4009, 4010, 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, 4029, 4030, 4031, 4032, 4033, 4034, 4036, 5001, 5002, 5003, 5004, 5005, 5006, 5007, 5008, 5009, 5010, 5011, 5012]);
response.OutpostBattleLevel = user.OutpostBattleLevel;
response.OutpostBattleTime = new NetOutpostBattleTime() { MaxBattleTime = 864000000000, MaxOverBattleTime = 12096000000000, BattleTime = battleTimeMs, OverBattleTime = overBattleTime };
response.Data.Add(new NetUserOutpostData() { SlotId = 1, BuildingId = 22401, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Data.Add(new NetUserOutpostData() { SlotId = 4, BuildingId = 22701, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Data.Add(new NetUserOutpostData() { SlotId = 5, BuildingId = 22801, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Data.Add(new NetUserOutpostData() { SlotId = 6, BuildingId = 22901, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Data.Add(new NetUserOutpostData() { SlotId = 7, BuildingId = 23001, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Data.Add(new NetUserOutpostData() { SlotId = 3, BuildingId = 23101, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Data.Add(new NetUserOutpostData() { SlotId = 2, BuildingId = 23201, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Data.Add(new NetUserOutpostData() { SlotId = 9, BuildingId = 23301, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Data.Add(new NetUserOutpostData() { SlotId = 8, BuildingId = 23401, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Data.Add(new NetUserOutpostData() { SlotId = 10, BuildingId = 23501, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Data.Add(new NetUserOutpostData() { SlotId = 38, BuildingId = 33601, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.TimeRewardBuffs.AddRange(NetUtils.GetOutpostTimeReward(user));
// TODO
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,30 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Jukebox
{
[PacketPath("/jukebox/playlist/get")]
public class JukeboxPlaylistGet : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
// Prepare response with static data
var response = new ResGetJukeboxPlaylist
{
Playlists = {}, // Assuming Playlists is a list or similar collection type, you may want to add items here.
FavoriteSongs = new NetJukeboxFavorite
{
Songs =
{
new NetJukeboxPlaylistSong { JukeboxTableId = 8995001,Order = 899 },
new NetJukeboxPlaylistSong { JukeboxTableId = 9020001, Order = 902 }
}
},
// JukeboxPlaylistUid = 123456789 // Assign a static UID, if required
};
// Send the response
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,16 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Jukebox
{
[PacketPath("/jukebox/record/playhistory")]
public class JukeboxPlayHistory : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = ReadData<ReqRecordJukeboxPlayHistory>();
var response = new ResRecordJukeboxPlayHistory();
await WriteDataAsync(response);
}
}
}

View File

@@ -23,8 +23,9 @@ namespace EpinelPS.LobbyServer.Msgs.User
response.SynchroLv = 1;
response.OutpostBattleLevel = user.OutpostBattleLevel;
response.OutpostBattleTime = new NetOutpostBattleTime() { MaxBattleTime = 864000000000, MaxOverBattleTime = 12096000000000, BattleTime = battleTimeMs };
response.CommanderRoomJukeboxBgm = new NetJukeboxBgm() { JukeboxTableId = 5, Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, Location = NetJukeboxLocation.NetJukeboxLocationCommanderRoom };
response.LobbyJukeboxBgm = new NetJukeboxBgm() { JukeboxTableId = 2, Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, Location = NetJukeboxLocation.NetJukeboxLocationLobby };
response.CommanderRoomJukeboxBgm = new NetJukeboxBgm() { JukeboxTableId = JsonDb.CurrentJukeboxBgm(2), Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, Location = NetJukeboxLocation.NetJukeboxLocationCommanderRoom };
response.LobbyJukeboxBgm = new NetJukeboxBgm() { JukeboxTableId = JsonDb.CurrentJukeboxBgm(1), Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, Location = NetJukeboxLocation.NetJukeboxLocationLobby };
// Add default slot data
if (user.RepresentationTeamData.Slots.Count == 0)

View File

@@ -0,0 +1,92 @@
using EpinelPS.Database;
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.User
{
[PacketPath("/enterlobbyserver")]
public class EnterLobbyServer : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqEnterLobbyServer>();
var user = GetUser();
var battleTime = DateTime.UtcNow - user.BattleTime;
var battleTimeMs = (long)(battleTime.TotalNanoseconds / 100);
// NOTE: Keep this in sync with GetUser code
var response = new ResEnterLobbyServer();
response.User = LobbyHandler.CreateNetUserDataFromUser(user);
response.ResetHour = 20;
response.Nickname = user.Nickname;
response.SynchroLv = 1;
response.OutpostBattleLevel = user.OutpostBattleLevel;
response.OutpostBattleTime = new NetOutpostBattleTime() { MaxBattleTime = 864000000000, MaxOverBattleTime = 12096000000000, BattleTime = battleTimeMs };
response.CommanderRoomJukeboxBgm = new NetJukeboxBgm() { JukeboxTableId = JsonDb.CurrentJukeboxBgm(2), Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, Location = NetJukeboxLocation.NetJukeboxLocationCommanderRoom };
response.LobbyJukeboxBgm = new NetJukeboxBgm() { JukeboxTableId = JsonDb.CurrentJukeboxBgm(1), Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, Location = NetJukeboxLocation.NetJukeboxLocationLobby };
// Add default slot data
if (user.RepresentationTeamData.Slots.Count == 0)
{
user.RepresentationTeamData = new NetWholeUserTeamData() { TeamNumber = 1, Type = 2 };
user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 1 });
user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 2 });
user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 3 });
user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 4 });
user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 5 });
JsonDb.Save();
}
response.RepresentationTeam = user.RepresentationTeamData;
foreach (var item in user.Currency)
{
response.Currency.Add(new NetUserCurrencyData() { Type = (int)item.Key, Value = item.Value });
}
foreach (var item in user.Characters)
{
response.Character.Add(new NetUserCharacterData() { Default = new() { Csn = item.Csn, Skill1Lv = item.Skill1Lvl, Skill2Lv = item.Skill2Lvl, CostumeId = item.CostumeId, Level = user.GetCharacterLevel(item.Csn, item.Level), Grade = item.Grade, Tid = item.Tid, UltiSkillLv = item.UltimateLevel}, IsSynchro = user.GetSynchro(item.Csn) });
}
foreach (var item in NetUtils.GetUserItems(user))
{
response.Items.Add(item);
}
// Add squad data if there are characters
if (user.Characters.Count > 0)
{
var highestLevelCharacters = user.Characters.OrderByDescending(x => x.Level).Take(5).ToList();
response.SynchroLv = user.GetSynchroLevel();
foreach (var item in highestLevelCharacters)
{
response.SynchroStandardCharacters.Add(item.Csn);
}
foreach (var teamInfo in user.UserTeams)
response.TypeTeams.Add(teamInfo.Value);
}
// TODO: Save outpost data
response.Outposts.Add(new NetUserOutpostData() { SlotId = 1, BuildingId = 22401, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 4, BuildingId = 22701, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 5, BuildingId = 22801, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 6, BuildingId = 22901, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 7, BuildingId = 23001, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 3, BuildingId = 23101, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 2, BuildingId = 23201, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 9, BuildingId = 23301, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 8, BuildingId = 23401, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 10, BuildingId = 23501, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 38, BuildingId = 33601, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.LastClearedNormalMainStageId = user.LastNormalStageCleared;
response.TimeRewardBuffs.AddRange(NetUtils.GetOutpostTimeReward(user));
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,91 @@
using EpinelPS.Database;
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.User
{
[PacketPath("/enterlobbyserver")]
public class EnterLobbyServer : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqEnterLobbyServer>();
var user = GetUser();
var battleTime = DateTime.UtcNow - user.BattleTime;
var battleTimeMs = (long)(battleTime.TotalNanoseconds / 100);
// NOTE: Keep this in sync with GetUser code
var response = new ResEnterLobbyServer();
response.User = LobbyHandler.CreateNetUserDataFromUser(user);
response.ResetHour = 20;
response.Nickname = user.Nickname;
response.SynchroLv = 1;
response.OutpostBattleLevel = user.OutpostBattleLevel;
response.OutpostBattleTime = new NetOutpostBattleTime() { MaxBattleTime = 864000000000, MaxOverBattleTime = 12096000000000, BattleTime = battleTimeMs };
response.CommanderRoomJukeboxBgm = new NetJukeboxBgm() { JukeboxTableId = 5, Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, Location = NetJukeboxLocation.NetJukeboxLocationCommanderRoom };
response.LobbyJukeboxBgm = new NetJukeboxBgm() { JukeboxTableId = 2, Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, Location = NetJukeboxLocation.NetJukeboxLocationLobby };
// Add default slot data
if (user.RepresentationTeamData.Slots.Count == 0)
{
user.RepresentationTeamData = new NetWholeUserTeamData() { TeamNumber = 1, Type = 2 };
user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 1 });
user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 2 });
user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 3 });
user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 4 });
user.RepresentationTeamData.Slots.Add(new NetWholeTeamSlot() { Slot = 5 });
JsonDb.Save();
}
response.RepresentationTeam = user.RepresentationTeamData;
foreach (var item in user.Currency)
{
response.Currency.Add(new NetUserCurrencyData() { Type = (int)item.Key, Value = item.Value });
}
foreach (var item in user.Characters)
{
response.Character.Add(new NetUserCharacterData() { Default = new() { Csn = item.Csn, Skill1Lv = item.Skill1Lvl, Skill2Lv = item.Skill2Lvl, CostumeId = item.CostumeId, Level = user.GetCharacterLevel(item.Csn, item.Level), Grade = item.Grade, Tid = item.Tid, UltiSkillLv = item.UltimateLevel}, IsSynchro = user.GetSynchro(item.Csn) });
}
foreach (var item in NetUtils.GetUserItems(user))
{
response.Items.Add(item);
}
// Add squad data if there are characters
if (user.Characters.Count > 0)
{
var highestLevelCharacters = user.Characters.OrderByDescending(x => x.Level).Take(5).ToList();
response.SynchroLv = user.GetSynchroLevel();
foreach (var item in highestLevelCharacters)
{
response.SynchroStandardCharacters.Add(item.Csn);
}
foreach (var teamInfo in user.UserTeams)
response.TypeTeams.Add(teamInfo.Value);
}
// TODO: Save outpost data
response.Outposts.Add(new NetUserOutpostData() { SlotId = 1, BuildingId = 22401, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 4, BuildingId = 22701, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 5, BuildingId = 22801, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 6, BuildingId = 22901, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 7, BuildingId = 23001, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 3, BuildingId = 23101, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 2, BuildingId = 23201, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 9, BuildingId = 23301, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 8, BuildingId = 23401, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 10, BuildingId = 23501, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.Outposts.Add(new NetUserOutpostData() { SlotId = 38, BuildingId = 33601, IsDone = true, StartAt = 638549982076760660, CompleteAt = 638549982076760660 });
response.LastClearedNormalMainStageId = user.LastNormalStageCleared;
response.TimeRewardBuffs.AddRange(NetUtils.GetOutpostTimeReward(user));
await WriteDataAsync(response);
}
}
}

View File

@@ -1,4 +1,5 @@
using EpinelPS.Utils;
using EpinelPS.Database;
namespace EpinelPS.LobbyServer.Msgs.User
{
@@ -38,8 +39,8 @@ namespace EpinelPS.LobbyServer.Msgs.User
response.User.Tutorials.Add(new NetTutorialData() { GroupId = groupId, LastClearedTid = item.Key, LastClearedVersion = version });
}
response.CommanderRoomJukeboxBgm = new NetJukeboxBgm() { JukeboxTableId = 2, Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, Location = NetJukeboxLocation.NetJukeboxLocationCommanderRoom };
response.LobbyJukeboxBgm = new NetJukeboxBgm() { JukeboxTableId = 2, Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, Location = NetJukeboxLocation.NetJukeboxLocationLobby };
response.CommanderRoomJukeboxBgm = new NetJukeboxBgm() { JukeboxTableId = JsonDb.CurrentJukeboxBgm(2), Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, Location = NetJukeboxLocation.NetJukeboxLocationCommanderRoom };
response.LobbyJukeboxBgm = new NetJukeboxBgm() { JukeboxTableId = JsonDb.CurrentJukeboxBgm(1), Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, Location = NetJukeboxLocation.NetJukeboxLocationLobby };
await WriteDataAsync(response);
}

View File

@@ -0,0 +1,17 @@
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.User
{
[PacketPath("/lobby/usertitle/set")]
public class SetUserTitleData : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqSetUserTitle>();
var response = new ResSetUserTitle();
await WriteDataAsync(response);
}
}
}

View File

@@ -208,7 +208,12 @@ namespace EpinelPS
Console.WriteLine(" unban - unban selected user from game");
Console.WriteLine(" exit - exit server application");
Console.WriteLine(" completestage (chapter num)-(stage number) - complete selected stage and get rewards (and all previous ones). Example completestage 15-1. Note that the exact stage number cleared may not be exact.");
}
Console.WriteLine(" sickpulls (requires selecting user first) allows for all characters to have equal chances of getting pulled");
Console.WriteLine(" SetLevel (level) - Set all characters' level (between 1 and 999 takes effect on game and server restart)");
Console.WriteLine(" SetSkillLevel (level) - Set all characters' skill levels between 1 and 10 (takes effect on game and server restart)");
Console.WriteLine(" addallcharacters - Add all missing characters to the selected user with default levels and skills (takes effect on game and server restart)");
}
else if (input == "ls /users")
{
Console.WriteLine("Id,Username,Nickname");
@@ -248,6 +253,146 @@ namespace EpinelPS
Console.WriteLine("Usage: chroot (user id)");
}
}
else if (input == "addallcharacters")
{
if (selectedUser == 0)
{
Console.WriteLine("No user selected");
}
else
{
var user = JsonDb.Instance.Users.FirstOrDefault(x => x.ID == selectedUser);
if (user == null)
{
Console.WriteLine("Selected user does not exist");
selectedUser = 0;
prompt = "# ";
}
else
{
// Add all characters to the selected user
foreach (var c in GameData.Instance.GetAllCharacterTids())
{
if (!user.HasCharacter(c))
{
// Generate a unique character ID
int id = user.GenerateUniqueCharacterId();
user.Characters.Add(new Database.Character()
{
CostumeId = 0,
Csn = id,
Grade = 0,
Level = 1,
Skill1Lvl = 1,
Skill2Lvl = 1,
Tid = c,
UltimateLevel = 1
});
}
}
Console.WriteLine("Added all missing characters to user " + user.Username);
JsonDb.Save();
}
}
}
else if (input == "sickpulls")
{
if (selectedUser == 0)
{
Console.WriteLine("No user selected");
}
else
{
var user = JsonDb.Instance.Users.FirstOrDefault(x => x.ID == selectedUser);
if (user == null)
{
Console.WriteLine("Selected user does not exist");
selectedUser = 0;
prompt = "# ";
}
else
{
// Check current value of sickpulls and toggle it
bool currentSickPulls = EpinelPS.Database.JsonDb.IsSickPulls(user);
if (currentSickPulls)
{
user.sickpulls = false;
Console.WriteLine("sickpulls is now set to false for user " + user.Username);
}
else
{
user.sickpulls = true;
Console.WriteLine("sickpulls is now set to true for user " + user.Username);
}
// Save the changes to the database
JsonDb.Save();
}
}
}
else if (input.StartsWith("SetLevel"))
{
if (selectedUser == 0)
{
Console.WriteLine("No user selected");
}
else
{
var user = JsonDb.Instance.Users.FirstOrDefault(x => x.ID == selectedUser);
if (user == null)
{
Console.WriteLine("Selected user does not exist");
selectedUser = 0;
prompt = "# ";
}
else if (args.Length == 2 && int.TryParse(args[1], out int level) && level >= 1 && level <= 999)
{
foreach (var character in user.Characters)
{
character.Level = level;
}
Console.WriteLine("Set all characters' level to " + level);
JsonDb.Save();
}
else
{
Console.WriteLine("Invalid argument. Level must be between 1 and 999.");
}
}
}
else if (input.StartsWith("SetSkillLevel"))
{
if (selectedUser == 0)
{
Console.WriteLine("No user selected");
}
else
{
var user = JsonDb.Instance.Users.FirstOrDefault(x => x.ID == selectedUser);
if (user == null)
{
Console.WriteLine("Selected user does not exist");
selectedUser = 0;
prompt = "# ";
}
else if (args.Length == 2 && int.TryParse(args[1], out int skillLevel) && skillLevel >= 1 && skillLevel <= 10)
{
foreach (var character in user.Characters)
{
character.UltimateLevel = skillLevel;
character.Skill1Lvl = skillLevel;
character.Skill2Lvl = skillLevel;
}
Console.WriteLine("Set all characters' skill levels to " + skillLevel);
JsonDb.Save();
}
else
{
Console.WriteLine("Invalid argument. Skill level must be between 1 and 10.");
}
}
}
else if (input.StartsWith("rmuser"))
{
if (selectedUser == 0)