spawners, todo: saving levelscript states and properties

This commit is contained in:
AlessandroCH
2025-05-30 15:36:49 +02:00
parent 5ae50be507
commit e26138d170
7 changed files with 86 additions and 115 deletions

View File

@@ -7,6 +7,7 @@ namespace Campofinale.Game.Entities
public class EntityMonster : Entity public class EntityMonster : Entity
{ {
public string templateId; public string templateId;
public ulong originId;
public EntityMonster() public EntityMonster()
{ {
@@ -83,7 +84,7 @@ namespace Campofinale.Game.Entities
Type =(int) ObjectTypeIndex.Enemy, Type =(int) ObjectTypeIndex.Enemy,
}, },
OriginId= originId,
Attrs = Attrs =
{ {
GetAttributes() GetAttributes()

View File

@@ -3,10 +3,14 @@ using Campofinale.Game.Inventory;
using Campofinale.Game.Spawners; using Campofinale.Game.Spawners;
using Campofinale.Packets.Sc; using Campofinale.Packets.Sc;
using Campofinale.Resource; using Campofinale.Resource;
using Campofinale.Resource.Dynamic;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using System.Numerics;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using static Campofinale.Resource.Dynamic.SpawnerConfig;
using static Campofinale.Resource.ResourceManager; using static Campofinale.Resource.ResourceManager;
using static Campofinale.Resource.ResourceManager.LevelScene.LevelData; using static Campofinale.Resource.ResourceManager.LevelScene.LevelData;
using static System.Formats.Asn1.AsnWriter;
namespace Campofinale.Game namespace Campofinale.Game
{ {
@@ -256,8 +260,6 @@ namespace Campofinale.Game
public bool alreadyLoaded = false; public bool alreadyLoaded = false;
[BsonIgnore, JsonIgnore] [BsonIgnore, JsonIgnore]
public List<ulong> activeScripts = new(); public List<ulong> activeScripts = new();
[BsonIgnore, JsonIgnore]
public List<GameSpawner> gameSpawners = new();
public int GetCollection(string id) public int GetCollection(string id)
{ {
if (collections.ContainsKey(id)) if (collections.ContainsKey(id))
@@ -354,7 +356,7 @@ namespace Campofinale.Game
lv_scene.levelData.npcs.ForEach(en => lv_scene.levelData.npcs.ForEach(en =>
{ {
if (en.npcGroupId.Contains("chr") && sceneNumId== 99) return; if (en.npcGroupId.Contains("chr")) return;
EntityNpc entity = new(en.entityDataIdKey,ownerId,en.position,en.rotation, sceneNumId, en.levelLogicId) EntityNpc entity = new(en.entityDataIdKey,ownerId,en.position,en.rotation, sceneNumId, en.levelLogicId)
{ {
belongLevelScriptId = en.belongLevelScriptId, belongLevelScriptId = en.belongLevelScriptId,
@@ -365,22 +367,7 @@ namespace Campofinale.Game
entity.defaultHide = en.defaultHide; entity.defaultHide = en.defaultHide;
entities.Add(entity); entities.Add(entity);
}); });
GetEntityExcludingChar().ForEach(e =>
{
if(e is EntityInteractive)
{
// e.spawned = true;
// GetOwner().Send(new PacketScObjectEnterView(GetOwner(), new List<Entity>() { e }));
}
});
GetEntityExcludingChar().FindAll(e=> e is not EntityInteractive).ForEach(e =>
{
// e.spawned = true;
// GetOwner().Send(new PacketScObjectEnterView(GetOwner(), new List<Entity>() { e }));
});
UpdateShowEntities(); UpdateShowEntities();
@@ -389,31 +376,13 @@ namespace Campofinale.Game
public void SpawnEntity(Entity en,bool spawnedCheck=true) public void SpawnEntity(Entity en,bool spawnedCheck=true)
{ {
if (!activeScripts.Contains(en.belongLevelScriptId) && en.defaultHide && en.belongLevelScriptId != 0)
{
return;
}
en.spawned = true;
ParamKeyValue targetList=en.properties.Find(p => p.key == "target_list");
if(targetList!=null)
foreach (Entity e in GetEntityExcludingChar().FindAll(e=>e.spawned == false && targetList.value.valueArray.Any(v=>v.valueBit64== (long)e.levelLogicId)))
{
SpawnEntity(e);
}
en.spawned = true;
GetOwner().Send(new PacketScObjectEnterView(GetOwner(), new List<Entity>() { en })); GetOwner().Send(new PacketScObjectEnterView(GetOwner(), new List<Entity>() { en }));
} }
public void UpdateShowEntities() public void UpdateShowEntities()
{ {
for (int i = 0; i < gameSpawners.Count; i++)
{
GameSpawner spawner = gameSpawners[i];
if(spawner != null)
{
spawner.Update(GetOwner());
}
}
List<Entity> toSpawn = new(); List<Entity> toSpawn = new();
foreach(Entity e in GetEntityExcludingChar()) foreach(Entity e in GetEntityExcludingChar())
{ {
@@ -489,6 +458,34 @@ namespace Campofinale.Game
} }
} }
public void SpawnWaveEnemy(ulong spawnerId, int waveId)
{
LevelSpawnerData data=info().levelData.spawners.Find(s => s.spawnerId == spawnerId);
if (data!=null)
{
SpawnerConfig config = spawnerConfigs.Find(s => s.configId == data.configId);
if (config != null)
{
foreach(var group in config.waveMap[$"{waveId}"].groupMap.Values)
{
foreach (var act in group.actionMap.Values)
{
EnemyLibraryData enemyData = config.enemyLibrary.Find(e=>e.key==act.libraryKey);
if (enemyData != null)
{
entities.Add(new EntityMonster(enemyData.enemyId, enemyData.enemyLevel, ownerId, act.position, act.rotation, sceneNumId)
{
defaultHide = false,
spawned = false,
belongLevelScriptId = data.belongLevelScriptId
});
}
}
}
}
}
}
} }
} }

View File

@@ -1,67 +0,0 @@
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;
}
}
}
}

View File

@@ -0,0 +1,24 @@
using Campofinale.Network;
using Campofinale.Protocol;
namespace Campofinale.Packets.Cs
{
public class HandleCsSceneMonsterSpawnerBeginWave
{
[Server.Handler(CsMsgId.CsSceneMonsterSpawnerBeginWave)]
public static void Handle(Player session, CsMsgId cmdId, Packet packet)
{
CsSceneMonsterSpawnerBeginWave req = packet.DecodeBody<CsSceneMonsterSpawnerBeginWave>();
session.sceneManager.GetCurScene().SpawnWaveEnemy(req.SpawnerId, req.WaveId);
session.Send(ScMsgId.ScSceneMonsterSpawnerBeginWave, new ScSceneMonsterSpawnerBeginWave()
{
SceneNumId=req.SceneNumId,
SpawnerId=req.SpawnerId,
WaveId=req.WaveId,
});
}
}
}

View File

@@ -71,7 +71,7 @@ namespace Campofinale.Packets.Cs
State = 4 State = 4
}; };
session.Send(ScMsgId.ScSceneLevelScriptStateNotify, rsp); session.Send(ScMsgId.ScSceneLevelScriptStateNotify, rsp);
} }
@@ -122,11 +122,13 @@ namespace Campofinale.Packets.Cs
break; break;
case ScriptActionType.StartSpawner: case ScriptActionType.StartSpawner:
player.sceneManager.GetCurScene().gameSpawners.Add(new Game.Spawners.GameSpawner() ScSceneMonsterSpawnerStart start = new()
{ {
configId = action.valueStr[0], SceneNumId = player.curSceneNumId,
scene= player.sceneManager.GetCurScene() SpawnerId = action.valueUlong[0],
});
};
player.Send(ScMsgId.ScSceneMonsterSpawnerStart,start);
break; break;
case ScriptActionType.AddCharacter: case ScriptActionType.AddCharacter:
Character chara =player.AddCharacter(action.valueStr[0],(int) action.valueUlong[0],true); Character chara =player.AddCharacter(action.valueStr[0],(int) action.valueUlong[0],true);

View File

@@ -12,11 +12,17 @@ namespace Campofinale.Resource.Dynamic
{ {
public string configId; public string configId;
public Dictionary<string, SpawnerWave> waveMap = new(); public Dictionary<string, SpawnerWave> waveMap = new();
public List<EnemyLibraryData> enemyLibrary = new();
public SpawnerConfig() { } public SpawnerConfig() { }
public class EnemyLibraryData
{
public string key;
public string enemyId;
public int enemyLevel;
}
public class SpawnerWave public class SpawnerWave
{ {
public int waveId; public int waveId;

View File

@@ -534,6 +534,7 @@ namespace Campofinale.Resource
public List<LevelScriptData> levelScripts = new(); public List<LevelScriptData> levelScripts = new();
public List<WorldWayPointSets> worldWayPointSets = new(); public List<WorldWayPointSets> worldWayPointSets = new();
public List<LevelFactoryRegionData> factoryRegions = new(); public List<LevelFactoryRegionData> factoryRegions = new();
public List<LevelSpawnerData> spawners = new();
public void Merge(LevelData other) public void Merge(LevelData other)
{ {
this.sceneId = other.sceneId; this.sceneId = other.sceneId;
@@ -544,6 +545,7 @@ namespace Campofinale.Resource
this.levelScripts.AddRange(other.levelScripts); this.levelScripts.AddRange(other.levelScripts);
this.worldWayPointSets.AddRange(other.worldWayPointSets); this.worldWayPointSets.AddRange(other.worldWayPointSets);
this.factoryRegions.AddRange(other.factoryRegions); this.factoryRegions.AddRange(other.factoryRegions);
this.spawners.AddRange(other.spawners);
} }
public class WorldWayPointSets public class WorldWayPointSets
@@ -551,6 +553,12 @@ namespace Campofinale.Resource
public int id; public int id;
public Dictionary<string, int> pointIdToIndex = new(); public Dictionary<string, int> pointIdToIndex = new();
} }
public class LevelSpawnerData
{
public ulong spawnerId;
public string configId;
public ulong belongLevelScriptId;
}
public class LevelScriptData public class LevelScriptData
{ {
public ulong scriptId; public ulong scriptId;