Synchro device

This commit is contained in:
Mikhail
2024-07-31 13:47:16 -04:00
parent fc0e2801ed
commit 42b17682b8
11 changed files with 338 additions and 24 deletions

View File

@@ -3,6 +3,8 @@ using EpinelPS.LobbyServer;
using EpinelPS.StaticInfo; using EpinelPS.StaticInfo;
using EpinelPS.Utils; using EpinelPS.Utils;
using Swan.Logging; using Swan.Logging;
using Google.Protobuf.WellKnownTypes;
using static Google.Rpc.Context.AttributeContext.Types;
namespace EpinelPS.Database namespace EpinelPS.Database
{ {
@@ -64,6 +66,21 @@ namespace EpinelPS.Database
public List<string> CompletedScenarios = new(); public List<string> CompletedScenarios = new();
} }
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 User public class User
{ {
// User info // User info
@@ -94,6 +111,9 @@ namespace EpinelPS.Database
public Dictionary<CurrencyType, long> Currency = new() { public Dictionary<CurrencyType, long> Currency = new() {
{ CurrencyType.ContentStamina, 2 } { CurrencyType.ContentStamina, 2 }
}; };
public List<SynchroSlot> SynchroSlots = new List<SynchroSlot>();
public bool SynchroDeviceUpgraded = false;
public int SynchroDeviceLevel = 200;
public List<ItemData> Items = new(); public List<ItemData> Items = new();
public List<Character> Characters = []; public List<Character> Characters = [];
@@ -219,6 +239,45 @@ namespace EpinelPS.Database
{ {
return Characters.Where(x => x.Csn == value).FirstOrDefault(); return Characters.Where(x => x.Csn == value).FirstOrDefault();
} }
internal bool GetSynchro(long csn)
{
return SynchroSlots.Where(x => x.CharacterSerialNumber == csn).Count() >= 1;
}
internal int GetCharacterLevel(int csn)
{
var c = GetCharacterBySerialNumber(csn);
if (c == null) 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;
}
}
} }
public class CoreInfo public class CoreInfo
{ {

View File

@@ -0,0 +1,54 @@
using EpinelPS.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EpinelPS.LobbyServer.Msgs.Character
{
[PacketPath("/character/SynchroDevice/Change")]
public class ChangeSynchroDevice : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqSynchroChange>();
var user = GetUser();
var response = new ResSynchroChange();
var highestLevelCharacters = user.Characters.OrderByDescending(x => x.Level).Take(5).ToList();
int slot = 1;
foreach (var item in highestLevelCharacters)
{
if (item.Level != 200)
{
throw new Exception("expected level to be 200");
}
response.Characters.Add(new NetUserCharacterData() { Default = new() { Csn = item.Csn, Skill1Lv = item.Skill1Lvl, Skill2Lv = item.Skill2Lvl, CostumeId = item.CostumeId, Level = item.Level, Grade = item.Grade, Tid = item.Tid, UltiSkillLv = item.UltimateLevel }, IsSynchro = user.GetSynchro(item.Csn) });
foreach (var s in user.SynchroSlots)
{
if (s.Slot == slot)
{
s.CharacterSerialNumber = item.Csn;
break;
}
}
slot++;
}
user.SynchroDeviceUpgraded = true;
foreach (var item in user.SynchroSlots)
{
response.Slots.Add(new NetSynchroSlot() { Slot = item.Slot, AvailableRegisterAt = item.AvailableAt, Csn = item.CharacterSerialNumber });
}
await WriteDataAsync(response);
}
}
}

View File

@@ -11,10 +11,10 @@ namespace EpinelPS.LobbyServer.Msgs.Character
var user = GetUser(); var user = GetUser();
var response = new ResGetCharacterData(); var response = new ResGetCharacterData();
// TODO: When Squad view opens in the game, or this request is sent, all character levels reset to 1 as well as cusume IDs // TODO: When Squad view opens in the game, or this request is sent, all character levels reset to 1 as well as costume IDs
//foreach (var item in user.Characters) //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, Lv = item.Level, Grade = item.Grade, Tid = item.Tid, UltiSkillLv = item.UltimateLevel }, IsSynchro = false, Artifact = 0 }); // 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) });
//} //}
var highestLevelCharacters = user.Characters.OrderByDescending(x => x.Level).Take(5).ToList(); var highestLevelCharacters = user.Characters.OrderByDescending(x => x.Level).Take(5).ToList();

View File

@@ -1,4 +1,5 @@
using EpinelPS.Utils; using EpinelPS.Database;
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Character namespace EpinelPS.LobbyServer.Msgs.Character
{ {
@@ -10,6 +11,24 @@ namespace EpinelPS.LobbyServer.Msgs.Character
var req = await ReadData<ReqGetSynchroData>(); var req = await ReadData<ReqGetSynchroData>();
var user = GetUser(); var user = GetUser();
if (user.SynchroSlots.Count == 0)
{
user.SynchroSlots = new() {
new SynchroSlot() { Slot = 1 },
new SynchroSlot() { Slot = 2},
new SynchroSlot() { Slot = 3 },
new SynchroSlot() { Slot = 4 },
new SynchroSlot() { Slot = 5 },
new SynchroSlot() { Slot = 6 },
new SynchroSlot() { Slot = 7 },
new SynchroSlot() { Slot = 8 },
new SynchroSlot() { Slot = 9 },
new SynchroSlot() { Slot = 10 },
};
}
var highestLevelCharacters = user.Characters.OrderByDescending(x => x.Level).Take(5).ToList(); var highestLevelCharacters = user.Characters.OrderByDescending(x => x.Level).Take(5).ToList();
var response = new ResGetSynchroData(); var response = new ResGetSynchroData();
@@ -17,26 +36,18 @@ namespace EpinelPS.LobbyServer.Msgs.Character
foreach (var item in highestLevelCharacters) foreach (var item in highestLevelCharacters)
{ {
response.Synchro.StandardCharacters.Add(new NetUserCharacterData() { Default = new() { Csn = item.Csn, Skill1Lv = item.Skill1Lvl, Skill2Lv = item.Skill2Lvl, CostumeId = item.CostumeId, Level = item.Level, Grade = item.Grade, Tid = item.Tid, UltiSkillLv = item.UltimateLevel } }); response.Synchro.StandardCharacters.Add(new NetUserCharacterData() { Default = new() { Csn = item.Csn, Skill1Lv = item.Skill1Lvl, Skill2Lv = item.Skill2Lvl, CostumeId = item.CostumeId, Level = item.Level, Grade = item.Grade, Tid = item.Tid, UltiSkillLv = item.UltimateLevel }, IsSynchro = user.GetSynchro(item.Csn) });
} }
response.Synchro.Slots.Add(new NetSynchroSlot() { Slot = 1 }); foreach (var item in user.SynchroSlots)
response.Synchro.Slots.Add(new NetSynchroSlot() { Slot = 2 });
response.Synchro.Slots.Add(new NetSynchroSlot() { Slot = 3 });
response.Synchro.Slots.Add(new NetSynchroSlot() { Slot = 4 });
response.Synchro.Slots.Add(new NetSynchroSlot() { Slot = 5 });
if (highestLevelCharacters.Count > 0)
{ {
response.Synchro.SynchroMaxLv = highestLevelCharacters.First().Level; response.Synchro.Slots.Add(new NetSynchroSlot() { Slot = item.Slot, AvailableRegisterAt = 1, Csn = item.CharacterSerialNumber });
response.Synchro.SynchroLv = highestLevelCharacters.Last().Level;
}
else
{
response.Synchro.SynchroLv = 1;
} }
// TODO: Validate response from real server and pull info from user info response.Synchro.SynchroMaxLv = 1000;
response.Synchro.SynchroLv = user.GetSynchroLevel();
response.Synchro.IsChanged = user.SynchroDeviceUpgraded;
await WriteDataAsync(response); await WriteDataAsync(response);
} }
} }

View File

@@ -59,7 +59,7 @@ namespace EpinelPS.LobbyServer.Msgs.Character
}; };
var highestLevelCharacters = user.Characters.OrderByDescending(x => x.Level).Take(5).ToList(); var highestLevelCharacters = user.Characters.OrderByDescending(x => x.Level).Take(5).ToList();
response.SynchroLv = highestLevelCharacters.Last().Level; response.SynchroLv = user.GetSynchroLevel();
foreach (var c in highestLevelCharacters) foreach (var c in highestLevelCharacters)
{ {

View File

@@ -0,0 +1,54 @@
using EpinelPS.Utils;
using Swan.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EpinelPS.LobbyServer.Msgs.Character
{
[PacketPath("/character/SynchroDevice/Regist")]
public class RegisterSynchroDevice : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqSynchroRegister>();
var user = GetUser();
var targetCharacter = user.GetCharacterBySerialNumber(req.Csn);
if (targetCharacter == null) throw new Exception("target character does not exist");
var response = new ResSynchroRegister();
foreach (var item in user.SynchroSlots)
{
if (item.Slot == req.Slot)
{
if (item.CharacterSerialNumber != 0)
{
Logger.Warn("must remove character from synchrodevice first");
}
else
{
item.CharacterSerialNumber = req.Csn;
response.IsSynchro = true;
response.Character = new NetUserCharacterDefaultData()
{
Csn = item.CharacterSerialNumber,
CostumeId = targetCharacter.CostumeId,
Grade = targetCharacter.Grade,
Level = user.GetSynchroLevel(),
Skill1Lv = targetCharacter.Skill1Lvl,
Skill2Lv = targetCharacter.Skill2Lvl,
Tid = targetCharacter.Tid,
UltiSkillLv = targetCharacter.UltimateLevel
};
response.Slot = new NetSynchroSlot() { AvailableRegisterAt = item.AvailableAt, Csn = item.CharacterSerialNumber, Slot = item.Slot };
}
}
}
await WriteDataAsync(response);
}
}
}

View File

@@ -29,6 +29,11 @@ namespace EpinelPS.LobbyServer.Msgs.Character
Logger.Warn("Character level is already 1 - cannot reset"); Logger.Warn("Character level is already 1 - cannot reset");
return; return;
} }
if (item.Level == 200)
{
Logger.Warn("Character level is 200 - cannot reset");
return;
}
int requiredCredit = 0; int requiredCredit = 0;
int requiredBattleData = 0; int requiredBattleData = 0;

View File

@@ -0,0 +1,60 @@
using EpinelPS.Database;
using EpinelPS.StaticInfo;
using EpinelPS.Utils;
using Swan.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EpinelPS.LobbyServer.Msgs.Character
{
[PacketPath("/character/SynchroDevice/LevelUp")]
public class SynchroLevelUp : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqSynchroLevelUp>();
var user = GetUser();
var response = new ResSynchroLevelUp();
var data = GameData.Instance.GetCharacterLevelUpData();
int requiredCredit = 0;
int requiredBattleData = 0;
int requiredCoreDust = 0;
var levelUpData = data[user.SynchroDeviceLevel + 1];
requiredCredit += levelUpData.gold;
requiredBattleData += levelUpData.character_exp;
requiredCoreDust += levelUpData.character_exp2;
if (user.CanSubtractCurrency(CurrencyType.Gold, requiredCredit) &&
user.CanSubtractCurrency(CurrencyType.CharacterExp, requiredBattleData) &&
user.CanSubtractCurrency(CurrencyType.CharacterExp2, requiredCoreDust))
{
user.SubtractCurrency(CurrencyType.Gold, requiredCredit);
user.SubtractCurrency(CurrencyType.CharacterExp, requiredBattleData);
user.SubtractCurrency(CurrencyType.CharacterExp2, requiredCoreDust);
user.SynchroDeviceLevel++;
}
else
{
// TOOD: log this
Logger.Error("ERROR: Not enough currency for upgrade");
return;
}
foreach (var currency in user.Currency)
{
response.Currencies.Add(new NetUserCurrencyData() { Type = (int)currency.Key, Value = currency.Value });
}
response.SynchroLv = user.SynchroDeviceLevel;
JsonDb.Save();
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,70 @@
using EpinelPS.Database;
using EpinelPS.Utils;
using Swan.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EpinelPS.LobbyServer.Msgs.Character
{
[PacketPath("/character/SynchroDevice/Unregist")]
public class UnregisterSynchroDevice : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqSynchroUnregist>();
var user = GetUser();
var response = new ResSynchroUnregist();
foreach (var item in user.SynchroSlots)
{
if (item.Slot == req.Slot)
{
if (item.CharacterSerialNumber == 0)
{
Logger.Warn("must add character from synchrodevice first");
}
else
{
var oldCSN = item.CharacterSerialNumber;
item.CharacterSerialNumber = 0;
var data = user.GetCharacterBySerialNumber(oldCSN);
if (data == null) throw new Exception("failed to lookup character");
response.Character = new NetUserCharacterDefaultData()
{
Csn = data.Csn,
CostumeId = data.CostumeId,
Grade = data.Grade,
Level = data.Level,
Skill1Lv = data.Skill1Lvl,
Skill2Lv = data.Skill2Lvl,
Tid = data.Tid,
UltiSkillLv = data.UltimateLevel
};
response.Slot = new NetSynchroSlot() { AvailableRegisterAt = item.AvailableAt, Csn = item.CharacterSerialNumber, Slot = item.Slot };
response.IsSynchro = false;
var highestLevelCharacters = user.Characters.OrderByDescending(x => x.Level).Take(5).ToList();
foreach (var item2 in highestLevelCharacters)
{
response.SynchroStandardCharacters.Add(item2.Csn);
}
response.SynchroLv = user.GetSynchroLevel();
}
}
}
JsonDb.Save();
await WriteDataAsync(response);
}
}
}

View File

@@ -125,7 +125,7 @@ namespace EpinelPS.LobbyServer.Msgs.Stage
var newXp = rewardData.user_exp + user.userPointData.ExperiencePoint; var newXp = rewardData.user_exp + user.userPointData.ExperiencePoint;
var oldXpData = GameData.Instance.GetUserLevelFromUserExp(user.userPointData.ExperiencePoint); var oldXpData = GameData.Instance.GetUserLevelFromUserExp(user.userPointData.ExperiencePoint);
var newLevelExp = GameData.Instance.GetUserMinXpForLevel(user.userPointData.UserLevel + 1); var newLevelExp = GameData.Instance.GetUserMinXpForLevel(user.userPointData.UserLevel);
var newLevel = user.userPointData.UserLevel; var newLevel = user.userPointData.UserLevel;
if (newLevelExp == -1) if (newLevelExp == -1)
@@ -143,7 +143,7 @@ namespace EpinelPS.LobbyServer.Msgs.Stage
else else
user.Currency.Add(CurrencyType.FreeCash, 30); user.Currency.Add(CurrencyType.FreeCash, 30);
newLevelExp = GameData.Instance.GetUserMinXpForLevel(newLevel + 1); newLevelExp = GameData.Instance.GetUserMinXpForLevel(newLevel);
} }

View File

@@ -46,9 +46,9 @@ namespace EpinelPS.LobbyServer.Msgs.User
foreach (var item in user.Characters) 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 = item.Level, Grade = item.Grade, Tid = item.Tid, UltiSkillLv = item.UltimateLevel } }); 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)) foreach (var item in NetUtils.GetUserItems(user))
{ {
response.Items.Add(item); response.Items.Add(item);
@@ -58,7 +58,8 @@ namespace EpinelPS.LobbyServer.Msgs.User
if (user.Characters.Count > 0) if (user.Characters.Count > 0)
{ {
var highestLevelCharacters = user.Characters.OrderByDescending(x => x.Level).Take(5).ToList(); var highestLevelCharacters = user.Characters.OrderByDescending(x => x.Level).Take(5).ToList();
response.SynchroLv = highestLevelCharacters.Last().Level; response.SynchroLv = user.GetSynchroLevel();
foreach (var item in highestLevelCharacters) foreach (var item in highestLevelCharacters)
{ {
response.SynchroStandardCharacters.Add(item.Csn); response.SynchroStandardCharacters.Add(item.Csn);