fix jukebox, begin work on outpost rewards

This commit is contained in:
Mikhail
2024-09-02 13:26:16 -04:00
parent a68a201c13
commit ed3c6bb6a0
15 changed files with 332 additions and 25 deletions

View File

@@ -78,6 +78,12 @@ namespace EpinelPS.Database
/// </summary>
public long AvailableAt;
}
public class ResetableData
{
public int WipeoutCount = 0;
public bool ClearedSimulationRoom = false;
public int InterceptionTickets = 3;
}
public class User
{
// User info
@@ -112,6 +118,7 @@ namespace EpinelPS.Database
public bool SynchroDeviceUpgraded = false;
public int SynchroDeviceLevel = 200;
public ResetableData ResetableData = new();
public List<ItemData> Items = new();
public List<Character> Characters = [];
public NetWholeUserTeamData RepresentationTeamData = new();

View File

@@ -39,6 +39,7 @@ namespace EpinelPS.StaticInfo
public Dictionary<int, int> SidestoryRewardTable = [];
public Dictionary<string, int> PositionReward = new Dictionary<string, int>();
public Dictionary<int, FieldItemRecord> FieldItems = [];
public Dictionary<int, OutpostBattleTableRecord> OutpostBattle = [];
public byte[] Sha256Hash;
public int Size;
@@ -370,6 +371,12 @@ namespace EpinelPS.StaticInfo
{
FieldItems.Add(obj.id, obj);
}
var battleOutpostTable = await LoadZip<OutpostBattleTable>("OutpostBattleTable.json", progress);
foreach (var obj in battleOutpostTable.records)
{
OutpostBattle.Add(obj.id, obj);
}
}
public MainQuestCompletionRecord? GetMainQuestForStageClearCondition(int stage)

View File

@@ -147,4 +147,17 @@
{
public List<FieldItemRecord> records;
}
public class OutpostBattleTableRecord
{
public int id;
public int credit;
public int character_exp1;
public int character_exp2;
public int user_exp;
}
public class OutpostBattleTable
{
public List<OutpostBattleTableRecord> records;
}
}

View File

@@ -0,0 +1,22 @@
using EpinelPS.Utils;
using Google.Protobuf.WellKnownTypes;
namespace EpinelPS.LobbyServer.Msgs.Arena
{
[PacketPath("/arena/get")]
public class GetArena : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqGetArena>();
var user = GetUser();
var response = new ResGetArena();
response.BanInfo = new NetArenaBanInfo() { Description = "Not Implemented", StartAt = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow), EndAt = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow.AddYears(10)) };
response.User = new NetArenaData() {User = LobbyHandler.CreateWholeUserDataFromDbUser(user) };
await WriteDataAsync(response);
}
}
}

View File

@@ -1,4 +1,5 @@
using EpinelPS.Utils;
using Google.Protobuf.WellKnownTypes;
namespace EpinelPS.LobbyServer.Msgs.Arena
{
@@ -10,7 +11,9 @@ namespace EpinelPS.LobbyServer.Msgs.Arena
var req = await ReadData<ReqGetArenaBanInfo>();
var response = new ResGetArenaBanInfo();
// TODO
response.RookieArenaBanInfo = new NetArenaBanInfo() { Description = "Not Implemented", StartAt = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow), EndAt = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow.AddYears(10)) };
response.SpecialArenaBanInfo = new NetArenaBanInfo() { Description = "Not Implemented", StartAt = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow), EndAt = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow.AddYears(10)) };
await WriteDataAsync(response);
}
}

View File

@@ -0,0 +1,21 @@
using EpinelPS.Utils;
using Google.Protobuf.WellKnownTypes;
namespace EpinelPS.LobbyServer.Msgs.Arena
{
[PacketPath("/arena/champion/get")]
public class GetChampion : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqGetChampionArena>();
var response = new ResGetChampionArena();
response.Schedule = new NetChampionArenaSchedule();
// TODO
await WriteDataAsync(response);
}
}
}

View File

@@ -1,4 +1,5 @@
using EpinelPS.Utils;
using Google.Protobuf.WellKnownTypes;
namespace EpinelPS.LobbyServer.Msgs.Arena
{
@@ -10,7 +11,8 @@ namespace EpinelPS.LobbyServer.Msgs.Arena
var req = await ReadData<ReqShowSpecialArenaReward>();
var response = new ResShowSpecialArenaReward();
// TODO
response.IsBan = true;
response.BanInfo = new NetArenaBanInfo() { Description = "Not Implemented", StartAt = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow), EndAt = Timestamp.FromDateTimeOffset(DateTimeOffset.UtcNow.AddYears(10)) };
await WriteDataAsync(response);
}
}

View File

@@ -31,7 +31,7 @@ namespace EpinelPS.LobbyServer.Msgs.Auth
response.FeatureDataInfo = new NetFeatureDataInfo() { UseFeatureData = true };
response.Identifier = new NetLegacyUserIdentifier() { Server = 21769, Usn = (long)user.ID };
response.ShouldRestartAfter = Duration.FromTimeSpan(TimeSpan.FromSeconds(86400));
response.EncryptionToken = ByteString.CopyFromUtf8(rsp.ClientAuthToken);
await WriteDataAsync(response);
}

View File

@@ -9,8 +9,24 @@ namespace EpinelPS.LobbyServer.Msgs.Outpost
{
var req = await ReadData<ReqObtainFastBattleReward>();
var response = new ResObtainFastBattleReward();
var user = GetUser();
// TODO
if (user.ResetableData.WipeoutCount >= 12)
{
throw new InvalidOperationException("wipeout count cannot exceed 12.");
}
user.ResetableData.WipeoutCount++;
response.FastBattleCount = user.ResetableData.WipeoutCount;
response.Reward = NetUtils.GetOutpostReward(user, TimeSpan.FromHours(2));
NetUtils.RegisterRewardsForUser(user, response.Reward);
// TODO subtract currency as needed
foreach (var item in user.Currency)
{
response.Currencies.Add(new NetUserCurrencyData() { Type = (int)item.Key, Value = item.Value});
}
await WriteDataAsync(response);
}

View File

@@ -13,19 +13,26 @@ namespace EpinelPS.LobbyServer.Msgs.Outpost
var battleTime = DateTime.UtcNow - user.BattleTime;
var battleTimeMs = (long)(battleTime.TotalNanoseconds / 100);
long overBattleTime = battleTimeMs > 12096000000000 ? battleTimeMs - 12096000000000 : 0;
var response = new ResGetOutpostData
{
OutpostBattleLevel = new NetOutpostBattleLevel() { Level = 1 },
OutpostBattleLevel = user.OutpostBattleLevel,
Jukebox = new() { SelectTid = 5 },
JukeboxV2 = new NetUserJukeboxDataV2() { CommandBgm = new() { Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId, JukeboxTableId = 5 } },
BattleTime = 864000000000,
Jukebox = new(),
MaxBattleTime = 864000000000,
SkinGroupId = 1000
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 };
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 });
@@ -38,6 +45,8 @@ namespace EpinelPS.LobbyServer.Msgs.Outpost
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,36 @@
using EpinelPS.Database;
using EpinelPS.LobbyServer.Msgs.Stage;
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Outpost
{
[PacketPath("/outpost/obtainoutpostbattlereward")]
public class ObtainOutpostReward : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqObtainOutpostBattleReward>();
var user = GetUser();
var response = new ResObtainOutpostBattleReward();
var battleTime = DateTime.UtcNow - user.BattleTime;
var battleTimeMs = (long)(battleTime.TotalNanoseconds / 100);
long overBattleTime = battleTimeMs > 864000000000 ? battleTimeMs - 864000000000 : 0;
response.OutpostBattleTime = new NetOutpostBattleTime() { MaxBattleTime = 864000000000, MaxOverBattleTime = 12096000000000, BattleTime = 0, OverBattleTime = 0 };
response.BattleTime = 0;
response.MaxBattleTime = 864000000000;
response.Reward = NetUtils.GetOutpostReward(user, battleTime);
NetUtils.RegisterRewardsForUser(user, response.Reward);
user.BattleTime = DateTime.UtcNow;
JsonDb.Save();
await WriteDataAsync(response);
}
}
}

View File

@@ -1,4 +1,5 @@
using EpinelPS.Utils;
using EpinelPS.Database;
using EpinelPS.Utils;
namespace EpinelPS.LobbyServer.Msgs.Outpost
{
@@ -12,13 +13,24 @@ namespace EpinelPS.LobbyServer.Msgs.Outpost
var battleTime = DateTime.UtcNow - user.BattleTime;
var battleTimeMs = (long)(battleTime.TotalNanoseconds / 100);
long overBattleTime = battleTimeMs > 864000000000 ? battleTimeMs - 864000000000 : 0;
// TODO
if (overBattleTime > 864000000000)
overBattleTime = 0;
var response = new ResShowOutpostBattleReward();
response.OutpostBattleLevel = user.OutpostBattleLevel;
response.OutpostBattleTime = new NetOutpostBattleTime() { MaxBattleTime = 864000000000, MaxOverBattleTime = 12096000000000, BattleTime = battleTimeMs };
response.BattleTime = battleTimeMs;
response.OutpostBattleTime = new NetOutpostBattleTime() { MaxBattleTime = 864000000000, MaxOverBattleTime = 12096000000000, BattleTime = battleTimeMs, OverBattleTime = 0 };
response.BattleTime = 0;
response.FastBattleCount = user.ResetableData.WipeoutCount;
response.MaxBattleTime = 864000000000;
response.Reward = new NetRewardData();
response.Reward = NetUtils.GetOutpostReward(user, battleTime);
response.TimeRewardBuffs.AddRange(NetUtils.GetOutpostTimeReward(user));
await WriteDataAsync(response);
}
}

View File

@@ -87,7 +87,7 @@ namespace EpinelPS.LobbyServer.Msgs.Stage
if (clearedStage.stage_type != "Sub")
{
// add outpost reward level if unlocked
if (user.MainQuestData.ContainsKey(21))
if (user.MainQuestData.TryGetValue(21, out bool c))
{
user.OutpostBattleLevel.Exp++;
if (user.OutpostBattleLevel.Exp >= 5)

View File

@@ -396,28 +396,42 @@ namespace EpinelPS
response.AddRange(Encoding.UTF8.GetBytes("\r\n"));
var bin = await item.ReadAsByteArrayAsync();
var res = await SendReqLocalAndReadResponseAsync(bin);
if (res != null)
try
{
List<byte> ResponseWithBytes =
[
.. Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\n"),
var res = await SendReqLocalAndReadResponseAsync(bin);
if (res != null)
{
List<byte> ResponseWithBytes =
[
.. Encoding.UTF8.GetBytes("HTTP/1.1 200 OK\r\n"),
.. Encoding.UTF8.GetBytes($"Content-Type: application/octet-stream+protobuf\r\n"),
.. Encoding.UTF8.GetBytes($"Content-Length: {res.Length}\r\n"),
.. Encoding.UTF8.GetBytes($"\r\n"),
.. res,
];
response.AddRange([.. ResponseWithBytes]);
}
else
{
List<byte> ResponseWithBytes =
[ .. Encoding.UTF8.GetBytes("HTTP/1.1 404 Not Found\r\n"),
response.AddRange([.. ResponseWithBytes]);
}
else
{
List<byte> ResponseWithBytes =
[ .. Encoding.UTF8.GetBytes("HTTP/1.1 404 Not Found\r\n"),
//.. Encoding.UTF8.GetBytes($"Content-Type: application/octet-stream+protobuf\r\n"),
.. Encoding.UTF8.GetBytes($"Content-Length: 0\r\n"),
.. Encoding.UTF8.GetBytes($"\r\n"),
];
response.AddRange([.. ResponseWithBytes]);
}
}
catch
{
List<byte> ResponseWithBytes =
[ .. Encoding.UTF8.GetBytes("HTTP/1.1 505 Internal Server Error\r\n"),
//.. Encoding.UTF8.GetBytes($"Content-Type: application/octet-stream+protobuf\r\n"),
.. Encoding.UTF8.GetBytes($"Content-Length: 0\r\n"),
.. Encoding.UTF8.GetBytes($"\r\n"),
];
response.AddRange([.. ResponseWithBytes]);
}
// add boundary, also include http newline if there is binary content

View File

@@ -1,5 +1,8 @@
using EpinelPS.Database;
using EpinelPS.StaticInfo;
using Google.Protobuf.WellKnownTypes;
using System.Collections.Generic;
using static Google.Rpc.Context.AttributeContext.Types;
namespace EpinelPS.Utils
{
@@ -141,5 +144,147 @@ namespace EpinelPS.Utils
}
return result;
}
private static long CalcOutpostRewardAmount(int value, double ratio, double boost, double elapsedMinutes)
{
double baseValue = value * ratio / 10000.0;
double minuteValue = baseValue + baseValue * boost / 100.0;
return (long)Math.Floor(minuteValue * elapsedMinutes);
}
public static double CalculateBoostValueForOutpost(User user, CurrencyType type)
{
double boost = 1.0;
if (user.CompletedTacticAcademyLessons.Contains(1003) && type == CurrencyType.Gold)
{
boost += .10;
}
return boost;
}
public static long GetOutpostRewardAmount(User user, CurrencyType type, double mins, bool includeBoost)
{
var battleData = GameData.Instance.OutpostBattle[user.OutpostBattleLevel.Level];
int value = 0;
double ratio = 0;
double boost = 1.0;
if (includeBoost)
boost += CalculateBoostValueForOutpost(user, type);
switch(type)
{
case CurrencyType.CharacterExp2:
value = battleData.character_exp2;
ratio = 1;
break;
case CurrencyType.CharacterExp:
value = battleData.character_exp1;
ratio = 3;
break;
case CurrencyType.Gold:
value = battleData.credit;
ratio = 3;
break;
case CurrencyType.UserExp:
value = battleData.user_exp;
ratio = 1;
break;
}
return CalcOutpostRewardAmount(value, ratio, boost, mins);
}
public static NetRewardData GetOutpostReward(User user, TimeSpan duration)
{
//duration = TimeSpan.FromHours(1);
NetRewardData result = new();
var battleData = GameData.Instance.OutpostBattle[user.OutpostBattleLevel.Level];
result.Currency.Add(new NetCurrencyData()
{
Type = (int)CurrencyType.CharacterExp2,
FinalValue = 0,
Value = CalcOutpostRewardAmount(battleData.character_exp2, 1, 1, duration.TotalMinutes)
});
result.Currency.Add(new NetCurrencyData()
{
Type = (int)CurrencyType.CharacterExp,
FinalValue = 0,
Value = CalcOutpostRewardAmount(battleData.character_exp1, 3, 1, duration.TotalMinutes)
});
result.Currency.Add(new NetCurrencyData()
{
Type = (int)CurrencyType.Gold,
FinalValue = 0,
Value = CalcOutpostRewardAmount(battleData.credit, 3, 1, duration.TotalMinutes)
});
result.Currency.Add(new NetCurrencyData()
{
Type = (int)CurrencyType.UserExp,
FinalValue = 0,
Value = CalcOutpostRewardAmount(battleData.user_exp, 3, 1, duration.TotalMinutes)
});
return result;
}
public static void RegisterRewardsForUser(User user, NetRewardData rewardData)
{
foreach (var item in rewardData.Currency)
{
user.AddCurrency((CurrencyType)item.Type, item.Value);
}
// TODO: other things that are used by the function above
}
internal static List<NetTimeReward> GetOutpostTimeReward(User user)
{
List<NetTimeReward> res = new List<NetTimeReward>();
var goldBuff = new NetTimeReward()
{
UseId = 1,
ValuePerMinAfterBuff = GetOutpostRewardAmount(user, CurrencyType.Gold, 1, true) * 10000,
ValuePerMinBeforeBuff = GetOutpostRewardAmount(user, CurrencyType.Gold, 1, false) * 10000
};
// goldBuff.Buffs.Add(new NetTimeRewardBuff() { Tid = 110101, FunctionType = 1, SourceType = OutpostBuffSourceType.OutpostBuffSourceTypeTacticAcademy, Value = 1000 });
var battleDataBuff = new NetTimeReward()
{
UseId = 2,
ValuePerMinAfterBuff = GetOutpostRewardAmount(user, CurrencyType.CharacterExp, 1, true) * 10000,
ValuePerMinBeforeBuff = GetOutpostRewardAmount(user, CurrencyType.CharacterExp, 1, false) * 10000
};
var xpBuff = new NetTimeReward()
{
UseId = 3,
ValuePerMinAfterBuff = GetOutpostRewardAmount(user, CurrencyType.UserExp, 1, true) * 10000,
ValuePerMinBeforeBuff = GetOutpostRewardAmount(user, CurrencyType.UserExp, 1, false) * 10000
};
var coredustBuff = new NetTimeReward()
{
UseId = 4,
ValuePerMinAfterBuff = GetOutpostRewardAmount(user, CurrencyType.CharacterExp2, 60, true) * 100,
ValuePerMinBeforeBuff = GetOutpostRewardAmount(user, CurrencyType.CharacterExp2, 60, false) * 100
};
res.Add(battleDataBuff);
res.Add(goldBuff);
res.Add(xpBuff);
res.Add(coredustBuff);
return res;
}
}
}