diff --git a/Campofinale/Game/MissionSys/MissionSystem.cs b/Campofinale/Game/MissionSys/MissionSystem.cs index 898447e..914dd0e 100644 --- a/Campofinale/Game/MissionSys/MissionSystem.cs +++ b/Campofinale/Game/MissionSys/MissionSystem.cs @@ -104,6 +104,7 @@ namespace Campofinale.Game.MissionSys missions.Add(new GameMission(id, state)); if (notify) { + ScMissionStateUpdate s = new() { MissionId = data.missionId, @@ -231,6 +232,38 @@ namespace Campofinale.Game.MissionSys quests.Remove(quest); } } + + public void TrackMission(string v) + { + curMission = v; + owner.Send(ScMsgId.ScTrackMissionChange, new ScTrackMissionChange() + { + MissionId = curMission, + }); + } + + public void CompleteMission(string v) + { + if(curMission == v) + { + TrackMission(""); + } + GameMission mission = missions.Find(m => m.missionId == v); + MissionDataTable data = ResourceManager.missionDataTable.Find(m => m.missionId == v); + if (mission != null && data != null) + { + mission.state=MissionState.Completed; + ScMissionStateUpdate s = new() + { + MissionId = mission.missionId, + MissionState = (int)mission.state, + SucceedId = -1, + + }; + owner.Send(ScMsgId.ScMissionStateUpdate, s); + //TODO rewards + } + } } public class GameQuest { diff --git a/Campofinale/Game/SceneManager.cs b/Campofinale/Game/SceneManager.cs index 589a499..e81d4ef 100644 --- a/Campofinale/Game/SceneManager.cs +++ b/Campofinale/Game/SceneManager.cs @@ -1,5 +1,6 @@ using Campofinale.Game.Entities; using Campofinale.Game.Inventory; +using Campofinale.Game.Spawners; using Campofinale.Packets.Sc; using Campofinale.Resource; using MongoDB.Bson.Serialization.Attributes; @@ -255,6 +256,8 @@ namespace Campofinale.Game public bool alreadyLoaded = false; [BsonIgnore, JsonIgnore] public List activeScripts = new(); + [BsonIgnore, JsonIgnore] + public List gameSpawners = new(); public int GetCollection(string id) { if (collections.ContainsKey(id)) @@ -359,6 +362,7 @@ namespace Campofinale.Game type = en.entityType, }; + entity.defaultHide = en.defaultHide; entities.Add(entity); }); GetEntityExcludingChar().ForEach(e => @@ -401,6 +405,15 @@ namespace Campofinale.Game } public void UpdateShowEntities() { + for (int i = 0; i < gameSpawners.Count; i++) + { + GameSpawner spawner = gameSpawners[i]; + if(spawner != null) + { + spawner.Update(GetOwner()); + } + } + List toSpawn = new(); foreach(Entity e in GetEntityExcludingChar()) { diff --git a/Campofinale/Game/Spawners/GameSpawner.cs b/Campofinale/Game/Spawners/GameSpawner.cs new file mode 100644 index 0000000..0016bab --- /dev/null +++ b/Campofinale/Game/Spawners/GameSpawner.cs @@ -0,0 +1,67 @@ +using Campofinale.Game.Entities; +using Campofinale.Resource; +using Campofinale.Resource.Dynamic; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Campofinale.Game.Spawners +{ + public class GameSpawner + { + public Scene scene; + public int curWave = 1; + public int curGroup = 1; + public string configId; + public bool spawned; + + public SpawnerConfig GetConfig() + { + return ResourceManager.spawnerConfigs.Find(s => s.configId == configId); + } + public SpawnerConfig.WaveGroup GetCurrentWaveGroup() + { + return GetConfig().waveMap[$"{curWave}"].groupMap[$"{curGroup}"]; + } + public int GetEnemiesOfCurrentWave() + { + return scene.entities.FindAll(e => e.dependencyGroupId == GetCurrentWaveGroup().groupId).Count; + } + + public void Update(Player player) + { + if (spawned) + { + if (GetEnemiesOfCurrentWave() < 1) + { + if (GetConfig().waveMap.ContainsKey($"{curWave + 1}")) + { + curWave++; + spawned = false; + } + } + } + else + { + + foreach (var item in GetCurrentWaveGroup().actionMap.Values) + { + Logger.Print($"Debug: Spawning {item.libraryKey}"); + scene.entities.Add(new EntityMonster(item.libraryKey, 1, player.roleId, item.position, item.rotation, scene.sceneNumId) + { + dependencyGroupId = GetCurrentWaveGroup().groupId, + defaultHide = false, + spawned = false + }); + + + } + spawned = true; + + } + + } + } +} diff --git a/Campofinale/Packets/Cs/HandleCsCharBagSetTeam.cs b/Campofinale/Packets/Cs/HandleCsCharBagSetTeam.cs index e588c68..0fa34ab 100644 --- a/Campofinale/Packets/Cs/HandleCsCharBagSetTeam.cs +++ b/Campofinale/Packets/Cs/HandleCsCharBagSetTeam.cs @@ -14,16 +14,7 @@ namespace Campofinale.Packets.Cs session.teams[req.TeamIndex].leader=req.LeaderId; session.teams[req.TeamIndex].members= req.CharTeam.ToList(); - ScCharBagSetTeam team = new() - { - CharTeam = { req.CharTeam }, - LeaderId = req.LeaderId, - ScopeName = 1, - TeamIndex = req.TeamIndex, - TeamType = CharBagTeamType.Main, - }; - - session.Send(ScMsgId.ScCharBagSetTeam,team); + session.Send(new PacketScCharBagSetTeam(session,session.teams[req.TeamIndex], req.TeamIndex)); session.Send(new PacketScSelfSceneInfo(session, Resource.SelfInfoReasonType.SlrChangeTeam)); } diff --git a/Campofinale/Packets/Cs/HandleCsCheckName.cs b/Campofinale/Packets/Cs/HandleCsCheckName.cs new file mode 100644 index 0000000..90f3a39 --- /dev/null +++ b/Campofinale/Packets/Cs/HandleCsCheckName.cs @@ -0,0 +1,22 @@ +using Campofinale.Network; +using Campofinale.Packets.Sc; +using Campofinale.Protocol; +using Campofinale.Resource; + +namespace Campofinale.Packets.Cs +{ + + public class HandleCsCheckName + { + [Server.Handler(CsMsgId.CsCheckName)] + public static void Handle(Player session, CsMsgId cmdId, Packet packet) + { + CsCheckName req = packet.DecodeBody(); + session.Send(ScMsgId.ScCheckName, new ScCheckName() + { + Name = req.Name, + Pass=true + },packet.csHead.UpSeqid); + } + } +} diff --git a/Campofinale/Packets/Cs/HandleCsCheckSensitive.cs b/Campofinale/Packets/Cs/HandleCsCheckSensitive.cs new file mode 100644 index 0000000..296a537 --- /dev/null +++ b/Campofinale/Packets/Cs/HandleCsCheckSensitive.cs @@ -0,0 +1,22 @@ +using Campofinale.Network; +using Campofinale.Packets.Sc; +using Campofinale.Protocol; +using Campofinale.Resource; + +namespace Campofinale.Packets.Cs +{ + + public class HandleCsCheckSensitive + { + [Server.Handler(CsMsgId.CsCheckSensitive)] + public static void Handle(Player session, CsMsgId cmdId, Packet packet) + { + CsCheckSensitive req = packet.DecodeBody(); + + session.Send(ScMsgId.ScCheckSensitive, new ScCheckSensitive() + { + + }); + } + } +} diff --git a/Campofinale/Packets/Cs/HandleCsSceneSetLevelScriptActive.cs b/Campofinale/Packets/Cs/HandleCsSceneSetLevelScriptActive.cs index 2229b04..3e98a2f 100644 --- a/Campofinale/Packets/Cs/HandleCsSceneSetLevelScriptActive.cs +++ b/Campofinale/Packets/Cs/HandleCsSceneSetLevelScriptActive.cs @@ -3,7 +3,7 @@ using Campofinale.Game.Entities; using Campofinale.Network; using Campofinale.Protocol; using Campofinale.Resource; -using Campofinale.Resource.Table; +using Campofinale.Resource.Json; using Pastel; using System.Net.Sockets; using static Campofinale.Resource.ResourceManager.LevelScene.LevelData; @@ -38,7 +38,20 @@ namespace Campofinale.Packets.Cs } else { + /* ScSceneLevelScriptStateNotify rsp = new ScSceneLevelScriptStateNotify() + { + SceneNumId = req.SceneNumId, + ScriptId = req.ScriptId, + State = 3 + }; + + if (!session.sceneManager.GetCurScene().activeScripts.Contains(req.ScriptId)) + { + session.sceneManager.GetCurScene().activeScripts.Add(req.ScriptId); + session.sceneManager.GetCurScene().UpdateShowEntities(); + } + session.Send(ScMsgId.ScSceneLevelScriptStateNotify, rsp);*/ } @@ -59,22 +72,11 @@ namespace Campofinale.Packets.Cs State = 4 }; - session.Send(ScMsgId.ScSceneLevelScriptStateNotify, rsp, packet.csHead.UpSeqid); - } - else - { - ScSceneLevelScriptStateNotify rsp = new ScSceneLevelScriptStateNotify() - { - SceneNumId = req.SceneNumId, - ScriptId = req.ScriptId, - - State = 4 - }; - - session.Send(ScMsgId.ScSceneLevelScriptStateNotify, rsp, packet.csHead.UpSeqid); + session.Send(ScMsgId.ScSceneLevelScriptStateNotify, rsp); } + } public static void ExecuteEventAction(Player player, ScriptAction action, CsSceneLevelScriptEventTrigger req) @@ -107,25 +109,98 @@ namespace Campofinale.Packets.Cs case ScriptActionType.EnterScene: player.EnterScene((int)action.valueUlong[0]); break; + case ScriptActionType.CompleteMission: + player.missionSystem.CompleteMission(action.valueStr[0]); + break; case ScriptActionType.AddMission: - player.missionSystem.AddMission(action.valueStr[0]); + player.missionSystem.AddMission(action.valueStr[0],MissionState.Processing,true); + if(action.valueUlong.Length > 0) + { + + player.missionSystem.TrackMission(action.valueStr[0]); + } + break; + case ScriptActionType.StartSpawner: + + player.sceneManager.GetCurScene().gameSpawners.Add(new Game.Spawners.GameSpawner() + { + configId = action.valueStr[0], + scene= player.sceneManager.GetCurScene() + }); + break; + case ScriptActionType.AddCharacter: + Character chara =player.AddCharacter(action.valueStr[0],(int) action.valueUlong[0],true); + player.AddToTeam(player.teamIndex, chara.guid); + break; + case ScriptActionType.ChangeScriptPropertyBool: + int i = 0; + ScSceneUpdateLevelScriptProperty update1 = new() + { + SceneNumId = req.SceneNumId, + ScriptId = req.ScriptId, + + }; + foreach (string keyId in action.valueStr) + { + long val = (long)action.valueUlong[i]; + + LevelScriptData levelscript = ResourceManager.GetLevelData(player.curSceneNumId).levelData.levelScripts.Find(l => l.scriptId == req.ScriptId); + if (levelscript != null) + { + int key = levelscript.GetPropertyId(keyId, new List()); + ParamKeyValue v = new() + { + key = keyId, + value = new ParamKeyValue.ParamValue() + { + type = ParamRealType.Bool, + valueArray = new[] + { + new ParamKeyValue.ParamValueAtom() + { + valueBit64=val, + + } + } + } + }; + update1.Properties.Add(key, v.ToProto()); + } + + i++; + + } + player.Send(ScMsgId.ScSceneUpdateLevelScriptProperty, update1); + break; + case ScriptActionType.StartScript: + foreach (ulong id in action.valueUlong) + { + + ScSceneLevelScriptStateNotify rsp = new ScSceneLevelScriptStateNotify() + { + SceneNumId = req.SceneNumId, + ScriptId = id, + + State = 4 + }; + + player.Send(ScMsgId.ScSceneLevelScriptStateNotify, rsp); + } break; case ScriptActionType.CallClientEvent: foreach(string id in action.valueStr) { + LevelScriptData levelscript = ResourceManager.GetLevelData(player.curSceneNumId).levelData.levelScripts.Find(l => l.actionMap.dataMap.headerList.Any(h=>h._eventKey.constValue==id)); ScSceneTriggerClientLevelScriptEvent trigger = new() { EventName = id, SceneNumId = req.SceneNumId, - ScriptId = req.ScriptId, + ScriptId = levelscript== null ? req.ScriptId : levelscript.scriptId, }; player.Send(ScMsgId.ScSceneTriggerClientLevelScriptEvent, trigger); } break; - case ScriptActionType.CompleteMission: - //player.missionSystem.C(action.valueStr[0]); - break; default: Logger.PrintWarn("Script Action not implemented"); break; diff --git a/Campofinale/Packets/Cs/HandleCsSetName.cs b/Campofinale/Packets/Cs/HandleCsSetName.cs new file mode 100644 index 0000000..ceb9c6c --- /dev/null +++ b/Campofinale/Packets/Cs/HandleCsSetName.cs @@ -0,0 +1,23 @@ +using Campofinale.Network; +using Campofinale.Packets.Sc; +using Campofinale.Protocol; +using Campofinale.Resource; + +namespace Campofinale.Packets.Cs +{ + + public class HandleCsSetName + { + [Server.Handler(CsMsgId.CsSetName)] + public static void Handle(Player session, CsMsgId cmdId, Packet packet) + { + CsSetName req = packet.DecodeBody(); + session.nickname = req.Name; + session.Send(ScMsgId.ScSetName, new ScSetName() + { + Name = req.Name, + + },packet.csHead.UpSeqid); + } + } +} diff --git a/Campofinale/Packets/Sc/PacketScCharBagSetTeam.cs b/Campofinale/Packets/Sc/PacketScCharBagSetTeam.cs new file mode 100644 index 0000000..5ac198f --- /dev/null +++ b/Campofinale/Packets/Sc/PacketScCharBagSetTeam.cs @@ -0,0 +1,24 @@ +using Campofinale.Game; +using Campofinale.Network; +using Campofinale.Protocol; + +namespace Campofinale.Packets.Sc +{ + public class PacketScCharBagSetTeam : Packet + { + + public PacketScCharBagSetTeam(Player client, Team team, int index) { + + ScCharBagSetTeam proto = new ScCharBagSetTeam() + { + CharTeam = {team.members }, + LeaderId = team.leader, + ScopeName = 1, + TeamIndex = index, + TeamType = CharBagTeamType.Main, + }; + SetData(ScMsgId.ScCharBagSetTeam, proto); + } + + } +} diff --git a/Campofinale/Packets/Sc/PacketScObjectEnterView.cs b/Campofinale/Packets/Sc/PacketScObjectEnterView.cs index 856153b..6f5ff3c 100644 --- a/Campofinale/Packets/Sc/PacketScObjectEnterView.cs +++ b/Campofinale/Packets/Sc/PacketScObjectEnterView.cs @@ -16,7 +16,8 @@ namespace Campofinale.Packets.Sc SummonList = { - } + }, + }, HasExtraObject = entities.Count > 1 diff --git a/Campofinale/Player.cs b/Campofinale/Player.cs index 7b9faeb..65de5b5 100644 --- a/Campofinale/Player.cs +++ b/Campofinale/Player.cs @@ -207,18 +207,37 @@ namespace Campofinale /// Add a character with template id if not present in the chars list *Added in 1.1.6* /// /// - public void AddCharacter(string id, bool notify = false) + public Character AddCharacter(string id, bool notify = false) { Character chara = GetCharacter(id); if (chara == null) { - Character c = new Character(roleId, id, 1); - chars.Add(c); + chara = new Character(roleId, id, 1); + chars.Add(chara); if (notify) { - Send(new PacketScCharBagAddChar(this,c)); + Send(new PacketScCharBagAddChar(this,chara)); } } + return chara; + } + /// + /// Add a character with template id and level if not present in the chars list *Added in 1.1.6* + /// + /// + public Character AddCharacter(string id, int level, bool notify = false) + { + Character chara = GetCharacter(id); + if (chara == null) + { + chara = new Character(roleId, id, level); + chars.Add(chara); + if (notify) + { + Send(new PacketScCharBagAddChar(this, chara)); + } + } + return chara; } /// /// Remove a character using template id *Added in 1.1.6* @@ -691,5 +710,17 @@ namespace Campofinale UnlockSystemType = (int)t }); } + + public void AddToTeam(int index, ulong guid) + { + if (teams[index].members.Count < 4) + { + teams[index].members.Add(guid); + Send(new PacketScCharBagSetTeam(this, teams[index], index)); + if(index==this.teamIndex) + Send(new PacketScSelfSceneInfo(this, Resource.SelfInfoReasonType.SlrChangeTeam)); + } + + } } } diff --git a/Campofinale/Resource/Dynamic/SpawnerConfig.cs b/Campofinale/Resource/Dynamic/SpawnerConfig.cs new file mode 100644 index 0000000..d739539 --- /dev/null +++ b/Campofinale/Resource/Dynamic/SpawnerConfig.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using static Campofinale.Resource.ResourceManager; + +namespace Campofinale.Resource.Dynamic +{ + public class SpawnerConfig + { + public string configId; + public Dictionary waveMap = new(); + + + + public SpawnerConfig() { } + + public class SpawnerWave + { + public int waveId; + public bool repeatable; + public int waveModeKillCount; + + + public Dictionary groupMap = new(); + + } + public class WaveGroup + { + public int groupId; + public int groupMode; + public int groupModeKillCount; + public float timestamp; + public Dictionary actionMap = new(); + + + } + public class GroupAction + { + [JsonPropertyName("$type")] + public string type; + public int actionId; + public float timestamp; + public string libraryKey; + public int spawnCount; + public float spawnInterval; + public Vector3f position; + public Vector3f rotation; + public float randomizeRadius; + public int routeId; + } + } +} diff --git a/Campofinale/Resource/Table/LevelScriptEvent.cs b/Campofinale/Resource/Json/LevelScriptEvent.cs similarity index 75% rename from Campofinale/Resource/Table/LevelScriptEvent.cs rename to Campofinale/Resource/Json/LevelScriptEvent.cs index f5d2d2d..ef6832c 100644 --- a/Campofinale/Resource/Table/LevelScriptEvent.cs +++ b/Campofinale/Resource/Json/LevelScriptEvent.cs @@ -4,10 +4,9 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Campofinale.Resource.Table +namespace Campofinale.Resource.Json { - [TableCfgType("Json/LevelScriptEvents.json", LoadPriority.LOW)] - public class LevelScriptEvent : TableCfgResource + public class LevelScriptEvent { public string eventName; public string comment; @@ -30,6 +29,10 @@ namespace Campofinale.Resource.Table AddMission = 6, CompleteMission = 7, SpawnEnemyByScriptId = 8, - CallClientEvent = 9 + CallClientEvent = 9, + StartScript = 10, + ChangeScriptPropertyBool = 11, + StartSpawner = 12, + AddCharacter = 13 } } diff --git a/Campofinale/Resource/ResourceManager.cs b/Campofinale/Resource/ResourceManager.cs index 109dbb5..7a0c04b 100644 --- a/Campofinale/Resource/ResourceManager.cs +++ b/Campofinale/Resource/ResourceManager.cs @@ -1,4 +1,6 @@ -using Campofinale.Resource.Table; +using Campofinale.Resource.Dynamic; +using Campofinale.Resource.Json; +using Campofinale.Resource.Table; using Newtonsoft.Json; using static Campofinale.Resource.ResourceManager.LevelScene; @@ -72,8 +74,8 @@ namespace Campofinale.Resource public static InteractiveTable interactiveTable = new(); // public static List levelDatas = new(); - public static List interactiveData = new(); - + public static List interactiveData = new(); + public static List spawnerConfigs = new(); public static int GetSceneNumIdFromLevelData(string name) { if (levelDatas.Find(a => a.id == name) == null) return 0; @@ -102,6 +104,7 @@ namespace Campofinale.Resource public static void Init() { Logger.Print("Loading TableCfg resources"); + // TODO: move all tables to the folder sceneAreaTable=JsonConvert.DeserializeObject>(ReadJsonFile("TableCfg/SceneAreaTable.json")); strIdNumTable = JsonConvert.DeserializeObject(ReadJsonFile("TableCfg/StrIdNumTable.json")); characterTable = JsonConvert.DeserializeObject>(ReadJsonFile("TableCfg/CharacterTable.json")); @@ -146,6 +149,8 @@ namespace Campofinale.Resource interactiveTable = JsonConvert.DeserializeObject(ReadJsonFile("Json/Interactive/InteractiveTable.json")); LoadInteractiveData(); LoadLevelDatas(); + LoadScriptsEvent(); + LoadSpawners(); ResourceLoader.LoadTableCfg(); if (missingResources) @@ -233,6 +238,43 @@ namespace Campofinale.Resource } } + public static void LoadScriptsEvent() + { + Logger.Print("Loading ScriptsEvents"); + string directoryPath = @"Json/ScriptEvents"; + string[] jsonFiles = Directory.GetFiles(directoryPath, "*.json", SearchOption.AllDirectories); + foreach (string json in jsonFiles) + { + Dictionary events = JsonConvert.DeserializeObject>(ReadJsonFile(json)); + foreach(KeyValuePair e in events) + { + if (levelScriptsEvents.ContainsKey(e.Key)) + { + Logger.PrintWarn($"{e.Key} already added, skipping the one in {json}"); + } + else + { + levelScriptsEvents.Add(e.Key,e.Value); + } + + } + + } + Logger.Print($"Loaded {levelScriptsEvents.Count} ScriptsEvents"); + } + public static void LoadSpawners() + { + Logger.Print("Loading Spawners"); + string directoryPath = @"DynamicAssets\gamedata\spawnerconfig"; + string[] jsonFiles = Directory.GetFiles(directoryPath, "*.json", SearchOption.AllDirectories); + foreach (string json in jsonFiles) + { + SpawnerConfig spawner = JsonConvert.DeserializeObject(ReadJsonFile(json)); + spawnerConfigs.Add(spawner); + + } + Logger.Print($"Loaded {spawnerConfigs.Count} Spawners"); + } public static void LoadLevelDatas() { Logger.Print("Loading LevelData resources"); @@ -512,8 +554,9 @@ namespace Campofinale.Resource public class LevelScriptData { public ulong scriptId; - public List properties; - public Dictionary propertyIdToKeyMap; + public List properties = new(); + public Dictionary propertyIdToKeyMap = new(); + public ScriptActionMap actionMap = new(); public int GetPropertyId(string key, List toExclude) @@ -527,6 +570,28 @@ namespace Campofinale.Resource } return 0; } + + public class ScriptActionMap + { + public ActionDataMap dataMap = new(); + + + public class ScriptHeader + { + public string _uid = ""; + + public EventKey _eventKey = new(); + + public class EventKey + { + public string constValue =""; + } + } + public class ActionDataMap + { + public List headerList = new(); + } + } } public class LevelFactoryRegionData {