Implement side story + move jsondb class

This commit is contained in:
Mikhail
2024-07-25 15:50:51 -04:00
parent 8ea17003e6
commit e83dcdbfa8
43 changed files with 306 additions and 55 deletions

View File

@@ -33,8 +33,7 @@ To access the admin panel, go to https://127.0.0.1/admin/ and sign in. Note that
To skip stages, a basic command line interface is implemented.
## Progress
Stage, character, outpost and story information is saved and works, as well as player nickname.
## Screenshots
<img src="https://github.com/user-attachments/assets/16d72494-27ce-4af5-9551-2c25940b0704" width="480" height="270">
@@ -50,6 +49,8 @@ Stage, character, outpost and story information is saved and works, as well as p
- [X] Open Archives UI
- [X] Inventory system
- [X] Character level up
- [X] Side story
- [X] Archives
- [ ] Skill level up
- [ ] Outpost jukebox / relics saving
- [ ] Field obtain object
@@ -64,7 +65,15 @@ Stage, character, outpost and story information is saved and works, as well as p
- [ ] Lost sector
- [ ] Custom launcher
- [ ] Limit temporary participation
- [ ] Archives
## What is not working:
- Collecting items in campaign
- Events
- Skill upgrade, limit break
- Mission reward, daily/weekly missions
- Side quests
- Lots of things in the outpost
- And a lot more...
## Contributing
Server code structure:

View File

@@ -1,7 +1,7 @@
using EmbedIO;
using EmbedIO.Routing;
using EmbedIO.WebApi;
using nksrv.Utils;
using nksrv.Database;
using System.Security.Cryptography;
using System.Text;

View File

@@ -1,9 +1,10 @@
using Newtonsoft.Json;
using nksrv.LobbyServer;
using nksrv.StaticInfo;
using nksrv.Utils;
using Swan.Logging;
namespace nksrv.Utils
namespace nksrv.Database
{
public class AccessToken
{
@@ -107,6 +108,7 @@ namespace nksrv.Utils
public NetOutpostBattleLevel OutpostBattleLevel = new() { Level = 1 };
public int GachaTutorialPlayCount = 0;
public List<int> CompletedTacticAcademyLessons = [];
public List<int> CompletedSideStoryStages = new();
// Event data
public Dictionary<int, EventData> EventInfo = new();
@@ -213,7 +215,7 @@ namespace nksrv.Utils
{
if (!File.Exists(AppDomain.CurrentDomain.BaseDirectory + "/db.json"))
{
Logger.Warn("users: warning: configuration not found, writing default data");
"users: warning: configuration not found, writing default data".Warn();
Instance = new CoreInfo();
Save();
}
@@ -281,7 +283,7 @@ namespace nksrv.Utils
Save();
ValidateDb();
Logger.Info("Loaded db");
"Loaded db".Info();
}
else
{
@@ -298,7 +300,7 @@ namespace nksrv.Utils
{
if (c.Level > 1000)
{
Logger.Warn($"Warning: Character level for character {c.Tid} cannot be above 1000, setting to 1000");
$"Warning: Character level for character {c.Tid} cannot be above 1000, setting to 1000".Warn();
c.Level = 1000;
}
}

View File

@@ -1,5 +1,6 @@
using EmbedIO;
using Newtonsoft.Json;
using nksrv.Database;
using nksrv.Utils;
using System.Net;
using static nksrv.IntlServer.IntlLogin2Endpoint;

View File

@@ -1,4 +1,5 @@
using EmbedIO;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.IntlServer

View File

@@ -1,6 +1,6 @@
using EmbedIO;
using Newtonsoft.Json;
using nksrv.Utils;
using nksrv.Database;
using System.Net;
using static nksrv.IntlServer.IntlLogin2Endpoint;

View File

@@ -1,6 +1,6 @@
using EmbedIO;
using Newtonsoft.Json;
using nksrv.Utils;
using nksrv.Database;
using System.Net;
namespace nksrv.IntlServer

View File

@@ -1,6 +1,6 @@
using EmbedIO;
using Newtonsoft.Json;
using nksrv.Utils;
using nksrv.Database;
using Swan.Logging;
using System.Text;

View File

@@ -1,6 +1,6 @@
using EmbedIO;
using Newtonsoft.Json;
using nksrv.Utils;
using nksrv.Database;
using System.Net;
using static nksrv.IntlServer.IntlLogin2Endpoint;

View File

@@ -1,6 +1,7 @@
using ASodium;
using EmbedIO;
using Google.Protobuf;
using nksrv.Database;
using nksrv.Utils;
using Swan.Logging;

View File

@@ -1,5 +1,6 @@
using EmbedIO;
using Google.Protobuf;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Auth
{

View File

@@ -1,6 +1,7 @@
using EmbedIO;
using Google.Protobuf;
using Google.Protobuf.WellKnownTypes;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Auth

View File

@@ -1,4 +1,5 @@
using nksrv.StaticInfo;
using nksrv.Database;
using nksrv.StaticInfo;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Campaign

View File

@@ -1,4 +1,5 @@
using nksrv.StaticInfo;
using nksrv.Database;
using nksrv.StaticInfo;
using nksrv.Utils;
using Swan.Logging;

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Character
{

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Event
{

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Event
{

View File

@@ -1,4 +1,5 @@
using nksrv.StaticInfo;
using nksrv.Database;
using nksrv.StaticInfo;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Gacha
@@ -25,7 +26,7 @@ namespace nksrv.LobbyServer.Msgs.Gacha
response.Gacha.Add(new NetGachaEntityData() { Corporation = 1, PieceCount = 1, CurrencyValue = 5, Sn = c, Tid = c, Type = 1 });
response.Characters.Add(new NetUserCharacterDefaultData() { CostumeId = 0, Csn = c, Grade = 0, Lv = 1, Skill1Lv = 1, Skill2Lv = 1, Tid = c, UltiSkillLv = 1 });
user.Characters.Add(new Utils.Character() { CostumeId = 0, Csn = c, Grade = 0, Level = 1, Skill1Lvl = 1, Skill2Lvl = 1, Tid = c, UltimateLevel = 1 });
user.Characters.Add(new Database.Character() { CostumeId = 0, Csn = c, Grade = 0, Level = 1, Skill1Lvl = 1, Skill2Lvl = 1, Tid = c, UltimateLevel = 1 });
}
user.GachaTutorialPlayCount++;
}

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Inventory
{

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Inventory
{

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Inventory
{

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Inventory
{

View File

@@ -0,0 +1,21 @@
using nksrv.Net;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Sidestory
{
[PacketPath("/sidestory/cut/clearbattle")]
public class ClearBattle : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqClearSideStoryCutForBattle>();
var user = GetUser();
var response = new ResClearSideStoryCutForBattle();
// TODO
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,26 @@
using nksrv.Net;
using nksrv.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace nksrv.LobbyServer.Msgs.Sidestory
{
[PacketPath("/sidestory/cut/clearscenario")]
public class ClearSideStoryCut : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqClearSideStoryCutForScenario>();
var user = GetUser();
var response = new ResClearSideStoryCutForScenario();
// TODO
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,45 @@
using nksrv.Database;
using nksrv.LobbyServer.Msgs.Stage;
using nksrv.Net;
using nksrv.StaticInfo;
using nksrv.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace nksrv.LobbyServer.Msgs.Sidestory
{
[PacketPath("/sidestory/stage/clear")]
public class ClearSideStoryStage : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqClearSideStoryStage>();
var user = GetUser();
var response = new ResClearSideStoryStage();
if (!user.CompletedSideStoryStages.Contains(req.SideStoryStageId))
{
user.CompletedSideStoryStages.Add(req.SideStoryStageId);
if (StaticDataParser.Instance.SidestoryRewardTable.ContainsKey(req.SideStoryStageId))
{
var rewardData = StaticDataParser.Instance.GetRewardTableEntry(StaticDataParser.Instance.SidestoryRewardTable[req.SideStoryStageId]);
if (rewardData != null)
response.Reward = ClearStage.RegisterRewardsForUser(user, rewardData);
else
throw new Exception("failed to find reward");
}
JsonDb.Save();
}
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,19 @@
using nksrv.Net;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Sidestory
{
[PacketPath("/sidestory/cut/enterbattle")]
public class EnterBattle : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqEnterSideStoryCutForBattle>();
var user = GetUser();
var response = new ResEnterSideStoryCutForBattle();
await WriteDataAsync(response);
}
}
}

View File

@@ -0,0 +1,26 @@
using nksrv.Net;
using nksrv.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace nksrv.LobbyServer.Msgs.Sidestory
{
[PacketPath("/sidestory/stage/enter")]
public class EnterSidestoryStage : LobbyMsgHandler
{
protected override async Task HandleAsync()
{
var req = await ReadData<ReqEnterSideStoryStage>();
var user = GetUser();
var response = new ResEnterSideStoryStage();
// TODO
await WriteDataAsync(response);
}
}
}

View File

@@ -1,4 +1,6 @@
using nksrv.Utils;
using Google.Protobuf.WellKnownTypes;
using nksrv.Net;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Sidestory
{
@@ -12,7 +14,11 @@ namespace nksrv.LobbyServer.Msgs.Sidestory
var response = new ResListSideStory();
// TODO
foreach (var item in user.CompletedSideStoryStages)
{
// TODO cleared at
response.SideStoryStageDataList.Add(new NetSideStoryStageData() { SideStoryStageId = item, ClearedAt = Timestamp.FromDateTime(DateTime.UtcNow) });
}
await WriteDataAsync(response);
}

View File

@@ -1,4 +1,5 @@
using nksrv.StaticInfo;
using nksrv.Database;
using nksrv.StaticInfo;
using nksrv.Utils;
using Swan.Logging;
@@ -26,7 +27,7 @@ namespace nksrv.LobbyServer.Msgs.Stage
}
public static ResClearStage CompleteStage(Utils.User user, int StageId, bool forceCompleteScenarios = false)
public static ResClearStage CompleteStage(Database.User user, int StageId, bool forceCompleteScenarios = false)
{
var response = new ResClearStage();
var clearedStage = StaticDataParser.Instance.GetStageData(StageId);
@@ -113,7 +114,7 @@ namespace nksrv.LobbyServer.Msgs.Stage
return response;
}
private static NetRewardData RegisterRewardsForUser(Utils.User user, RewardTableRecord rewardData)
public static NetRewardData RegisterRewardsForUser(Database.User user, RewardTableRecord rewardData)
{
NetRewardData ret = new();
if (rewardData.rewards == null) return ret;
@@ -222,7 +223,7 @@ namespace nksrv.LobbyServer.Msgs.Stage
return ret;
}
private static void DoQuestSpecificUserOperations(Utils.User user, int clearedStageId)
private static void DoQuestSpecificUserOperations(Database.User user, int clearedStageId)
{
var quest = StaticDataParser.Instance.GetMainQuestForStageClearCondition(clearedStageId);
if (quest != null)
@@ -240,11 +241,11 @@ namespace nksrv.LobbyServer.Msgs.Stage
team1.LastContentsTeamNumber = 1;
user.Characters.Add(new Utils.Character() { Csn = 47263455, Tid = 201001 });
user.Characters.Add(new Utils.Character() { Csn = 47273456, Tid = 330501 });
user.Characters.Add(new Utils.Character() { Csn = 47263457, Tid = 130201 });
user.Characters.Add(new Utils.Character() { Csn = 47263458, Tid = 230101 });
user.Characters.Add(new Utils.Character() { Csn = 47263459, Tid = 301201 });
user.Characters.Add(new Database.Character() { Csn = 47263455, Tid = 201001 });
user.Characters.Add(new Database.Character() { Csn = 47273456, Tid = 330501 });
user.Characters.Add(new Database.Character() { Csn = 47263457, Tid = 130201 });
user.Characters.Add(new Database.Character() { Csn = 47263458, Tid = 230101 });
user.Characters.Add(new Database.Character() { Csn = 47263459, Tid = 301201 });
var team1Sub = new NetTeamData();
team1Sub.TeamNumber = 1;

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Stage
{
@@ -21,7 +22,7 @@ namespace nksrv.LobbyServer.Msgs.Stage
await WriteDataAsync(response);
}
public static NetFieldObjectData CreateFieldInfo(Utils.User user, int chapter, string mod)
public static NetFieldObjectData CreateFieldInfo(Database.User user, int chapter, string mod)
{
var f = new NetFieldObjectData();
bool found = false;

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Team
{

View File

@@ -1,4 +1,5 @@
using nksrv.StaticInfo;
using nksrv.Database;
using nksrv.StaticInfo;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.Trigger

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.User
{

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.User
{

View File

@@ -1,4 +1,5 @@
using nksrv.Utils;
using nksrv.Database;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.User
{

View File

@@ -1,4 +1,5 @@
using nksrv.StaticInfo;
using nksrv.Database;
using nksrv.StaticInfo;
using nksrv.Utils;
namespace nksrv.LobbyServer.Msgs.User.Tutorial

View File

@@ -1,6 +1,7 @@
using EmbedIO;
using EmbedIO.Actions;
using EmbedIO.WebApi;
using nksrv.Database;
using nksrv.IntlServer;
using nksrv.LobbyServer;
using nksrv.LobbyServer.Msgs.Stage;

View File

@@ -2193,16 +2193,6 @@ message ResGetLostSectorData {
repeated NetFieldStageData ClearedStages = 4;
}
message NetSideStoryStageData {
int32 SideStoryStageId = 1;
google.protobuf.Timestamp ClearedAt = 2;
}
message ReqListSideStory {}
message ResListSideStory {
repeated NetSideStoryStageData SideStoryStageDataList = 1;
}
enum LiberateMissionState {
LiberateMissionState_Running = 0;
LiberateMissionState_Rewarded = 1;
@@ -2253,4 +2243,4 @@ message ReqGetSpecialLobbySlotData {
}
message ResGetSpecialLobbySlotData {
repeated SpecialLobbySlot SpecialLobbySlots = 1;
}
}

View File

@@ -0,0 +1,63 @@
syntax = "proto3";
option csharp_namespace = "nksrv.Net";
import "google/protobuf/timestamp.proto";
import "google/protobuf/Duration.proto";
import "Protos/allmsgs.proto";
// List completed
message NetSideStoryStageData {
int32 SideStoryStageId = 1;
google.protobuf.Timestamp ClearedAt = 2;
}
message ReqListSideStory {}
message ResListSideStory {
repeated NetSideStoryStageData SideStoryStageDataList = 1;
}
// Enter stage
message ReqEnterSideStoryStage {
int32 SideStoryId = 1;
int32 SideStoryStageId = 2;
int32 TeamNumber = 3;
NetAntiCheatBattleTLogAdditionalInfo AnticheatData = 4;
}
message ResEnterSideStoryStage {
}
// Clear sceneario
message ReqClearSideStoryCutForScenario {
int32 SideStoryStageId = 1;
int32 SideStoryCutId = 2;
}
message ResClearSideStoryCutForScenario {}
// Clear stage
message ReqClearSideStoryStage {
int32 SideStoryStageId = 1;
}
message ResClearSideStoryStage {
NetRewardData reward = 1;
}
// Enter battle
message ReqEnterSideStoryCutForBattle {
int32 SideStoryStageId = 1;
int32 SideStoryCutId = 2;
int32 TeamNumber = 3;
NetAntiCheatBattleTLogAdditionalInfo AnticheatData = 4;
}
message ResEnterSideStoryCutForBattle {}
// Clear battle
message ReqClearSideStoryCutForBattle {
int32 SideStoryStageId = 1;
int32 SideStoryCutId = 2;
int32 TeamNumber = 3;
int32 BattleResult = 4;
NetAntiCheatBattleData AnticheatBattleData = 5;
NetAntiCheatBattleTLogAdditionalInfo AnticheatData = 6;
}
message ResClearSideStoryCutForBattle {}

View File

@@ -49,6 +49,7 @@ namespace nksrv.StaticInfo
private Dictionary<string, JArray> FieldMapData = [];
private Dictionary<int, CharacterLevelData> LevelData = [];
private Dictionary<int, TacticAcademyLessonRecord> TacticAcademyLessons = [];
public Dictionary<int, int> SidestoryRewardTable = [];
public byte[] Sha256Hash;
public int Size;
@@ -273,6 +274,22 @@ namespace nksrv.StaticInfo
TacticAcademyLessons.Add(id, new TacticAcademyLessonRecord() { CurrencyId = (CurrencyType)currencyId, CurrencyValue = currencyValue, GroupId = groupid, Id = id });
}
var sideStoryTable = await LoadZip("SideStoryStageTable.json");
foreach (JToken item in sideStoryTable)
{
var idRaw = item["id"];
var rewardIdRaw = item["first_clear_reward"];
if (idRaw == null) throw new InvalidDataException();
if (rewardIdRaw != null)
{
var id2 = idRaw.ToObject<int>();
var reward = rewardIdRaw.ToObject<int>();
SidestoryRewardTable.Add(id2, reward);
}
}
}
public MainQuestCompletionData? GetMainQuestForStageClearCondition(int stage)

View File

@@ -1,4 +1,5 @@
using nksrv.StaticInfo;
using nksrv.Database;
using nksrv.StaticInfo;
using Swan.Logging;
namespace nksrv.Utils

View File

@@ -32,6 +32,7 @@
<ItemGroup>
<None Remove="Protos\liberate.proto" />
<None Remove="Protos\shop.proto" />
<None Remove="Protos\sidestory.proto" />
</ItemGroup>
<ItemGroup>