another try to improve entity spawning and fix loading but still loading issues

This commit is contained in:
AlessandroCH 2025-07-18 14:49:33 +02:00
parent f47ec48073
commit 35f8fbb2b2
5 changed files with 120 additions and 37 deletions

View File

@ -4,10 +4,12 @@ using Campofinale.Packets.Sc;
using Campofinale.Resource; using Campofinale.Resource;
using Campofinale.Resource.Dynamic; using Campofinale.Resource.Dynamic;
using MongoDB.Bson.Serialization.Attributes; using MongoDB.Bson.Serialization.Attributes;
using System;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using static Campofinale.Resource.Dynamic.SpawnerConfig; 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 Campofinale.Resource.ResourceManager.LevelScene.LevelData.LevelFunctionAreaData;
namespace Campofinale.Game namespace Campofinale.Game
{ {
@ -235,7 +237,6 @@ namespace Campofinale.Game
{ {
if (scene != null) if (scene != null)
{ {
scene.alreadyLoaded = false;
scene.Unload(); scene.Unload();
} }
} }
@ -256,11 +257,11 @@ namespace Campofinale.Game
[BsonIgnore,JsonIgnore] [BsonIgnore,JsonIgnore]
public List<Entity> entities = new(); public List<Entity> entities = new();
[BsonIgnore, JsonIgnore] [BsonIgnore, JsonIgnore]
public bool alreadyLoaded = false;
[BsonIgnore, JsonIgnore]
public List<ulong> activeScripts = new(); public List<ulong> activeScripts = new();
public List<LevelScript> scripts = new(); public List<LevelScript> scripts = new();
[BsonIgnore, JsonIgnore]
private LevelFunctionRangeData currentAreaRange = new();
public int GetCollection(string id) public int GetCollection(string id)
{ {
if (collections.ContainsKey(id)) if (collections.ContainsKey(id))
@ -367,17 +368,12 @@ namespace Campofinale.Game
entities.Add(entity); entities.Add(entity);
}); });
UpdateShowEntities(); UpdateShowEntities();
} }
public void SpawnEntity(Entity en,bool spawnedCheck=true) public void SpawnEntity(Entity en,bool spawnedCheck=true)
{ {
en.spawned = true; en.spawned = true;
GetOwner().Send(new PacketScObjectEnterView(GetOwner(), new List<Entity>() { en })); GetOwner().Send(new PacketScObjectEnterView(GetOwner(), new List<Entity>() { en }));
} }
public bool GetActiveScript(ulong id) public bool GetActiveScript(ulong id)
@ -392,10 +388,22 @@ namespace Campofinale.Game
return true; return true;
} }
} }
private void UpdateArea()
{
LevelScene lv_scene = ResourceManager.GetLevelData(sceneNumId);
lv_scene.levelData.functionArea.ranges.ForEach(range =>
{
if (range.IsObjectInside(GetOwner().position))
{
currentAreaRange=range;
}
});
}
//Bug on scene 101: spawning entities in this way make the game break if you try to load another scene from scene 101 //Bug on scene 101: spawning entities in this way make the game break if you try to load another scene from scene 101
public async void UpdateShowEntities() public async void UpdateShowEntities()
{ {
UpdateArea();
List<Entity> toSpawn = new(); List<Entity> toSpawn = new();
List<Entity> toCheck = GetEntityExcludingChar().FindAll(e => e.spawned == false); List<Entity> toCheck = GetEntityExcludingChar().FindAll(e => e.spawned == false);
toCheck.Sort((a, b) => a.Position.Distance(GetOwner().position).CompareTo(b.Position.Distance(GetOwner().position))); toCheck.Sort((a, b) => a.Position.Distance(GetOwner().position).CompareTo(b.Position.Distance(GetOwner().position)));
@ -404,6 +412,7 @@ namespace Campofinale.Game
if(e.spawned==false && (GetActiveScript(e.belongLevelScriptId) || e.belongLevelScriptId==0)) if(e.spawned==false && (GetActiveScript(e.belongLevelScriptId) || e.belongLevelScriptId==0))
{ {
if(currentAreaRange.IsObjectInside(e.Position))
if (!e.defaultHide) if (!e.defaultHide)
{ {
toSpawn.Add(e); toSpawn.Add(e);
@ -423,34 +432,18 @@ namespace Campofinale.Game
GetOwner().Send(new PacketScObjectEnterView(GetOwner(), chunk)); GetOwner().Send(new PacketScObjectEnterView(GetOwner(), chunk));
} }
} }
List<ulong> toDespawn=new();
foreach(Entity en in GetEntityExcludingChar().FindAll(e=> e.spawned==true))
{
if (!currentAreaRange.IsObjectInside(en.Position))
{
toDespawn.Add(en.guid);
en.spawned = false;
}
/* foreach(Entity en in GetEntityExcludingChar()) }
{ if(toDespawn.Count > 0)
float minDis = 100; GetOwner().Send(new PacketScObjectLeaveView(GetOwner(), toDespawn));
//todo new system
if (en.Position.DistanceXZ(GetOwner().position) < minDis)
{
if (!en.spawned)
{
SpawnEntity(en);
}
}
else
{
/*if (en.spawned)
{
en.spawned = false;
GetOwner().Send(new PacketScObjectLeaveView(GetOwner(), new List<ulong>() { en.guid }));
en.Position=en.BornPos;
en.Rotation = en.Rotation;
}
}
}*/
} }
public Player GetOwner() public Player GetOwner()

View File

@ -11,7 +11,7 @@ namespace Campofinale.Packets.Cs
{ {
CsSceneMoveStateSet req = packet.DecodeBody<CsSceneMoveStateSet>(); CsSceneMoveStateSet req = packet.DecodeBody<CsSceneMoveStateSet>();
//req. //req.
} }
} }

View File

@ -1,5 +1,6 @@
using Campofinale.Network; using Campofinale.Network;
using Campofinale.Protocol; using Campofinale.Protocol;
using Campofinale.Utils;
namespace Campofinale.Packets.Cs namespace Campofinale.Packets.Cs
{ {
@ -26,6 +27,9 @@ namespace Campofinale.Packets.Cs
} }
else else
{ {
uint unixTimestamp = (uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var generator = new SnowflakeIdGenerator(machineId: 1);
long id = generator.GenerateId();
ScSceneTeleport t = new() ScSceneTeleport t = new()
{ {
TeleportReason = req.TeleportReason, TeleportReason = req.TeleportReason,
@ -33,6 +37,8 @@ namespace Campofinale.Packets.Cs
Position = req.Position, Position = req.Position,
Rotation = req.Rotation, Rotation = req.Rotation,
SceneNumId = req.SceneNumId, SceneNumId = req.SceneNumId,
ServerTime = unixTimestamp,
TpUuid= (ulong)id
}; };
session.curSceneNumId = t.SceneNumId; session.curSceneNumId = t.SceneNumId;
session.Send(ScMsgId.ScSceneTeleport, t); session.Send(ScMsgId.ScSceneTeleport, t);

View File

@ -2,6 +2,8 @@
using Campofinale.Resource.Json; using Campofinale.Resource.Json;
using Campofinale.Resource.Table; using Campofinale.Resource.Table;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Numerics;
using System;
using static Campofinale.Resource.ResourceManager.LevelScene; using static Campofinale.Resource.ResourceManager.LevelScene;
namespace Campofinale.Resource namespace Campofinale.Resource
@ -549,6 +551,7 @@ namespace Campofinale.Resource
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 List<LevelSpawnerData> spawners = new();
public LevelFunctionAreaData functionArea = new();
public void Merge(LevelData other) public void Merge(LevelData other)
{ {
this.sceneId = other.sceneId; this.sceneId = other.sceneId;
@ -560,6 +563,7 @@ namespace Campofinale.Resource
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); this.spawners.AddRange(other.spawners);
this.functionArea.ranges.AddRange(other.functionArea.ranges);
} }
public class WorldWayPointSets public class WorldWayPointSets
@ -567,6 +571,26 @@ namespace Campofinale.Resource
public int id; public int id;
public Dictionary<string, int> pointIdToIndex = new(); public Dictionary<string, int> pointIdToIndex = new();
} }
public class LevelFunctionAreaData
{
public List<LevelFunctionRangeData> ranges = new();
public class LevelFunctionRangeData
{
public Vector3f m_center = new();
public Vector3f m_size = new();
public bool IsObjectInside(Vector3f position)
{
Vector3f halfSize = m_size * 0.5f;
return Math.Abs(position.x - m_center.x) <= halfSize.x &&
Math.Abs(position.y - m_center.y) <= halfSize.y &&
Math.Abs(position.z - m_center.z) <= halfSize.z;
}
}
}
public class LevelSpawnerData public class LevelSpawnerData
{ {
public ulong spawnerId; public ulong spawnerId;
@ -949,6 +973,10 @@ namespace Campofinale.Resource
public Vector3f() public Vector3f()
{ {
}
public static Vector3f operator *(Vector3f v, float scalar)
{
return new Vector3f(v.x * scalar, v.y * scalar, v.z * scalar);
} }
public Vector3f(float x, float y, float z) public Vector3f(float x, float y, float z)
{ {

View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Campofinale.Utils
{
public class SnowflakeIdGenerator
{
private static readonly DateTime Epoch = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc);
private readonly int _machineId; // es. 031 (5 bit)
private int _sequence = 0;
private long _lastTimestamp = -1L;
private readonly object _lock = new object();
public SnowflakeIdGenerator(int machineId)
{
_machineId = machineId & 0x1F; // 5 bit
}
public long GenerateId()
{
lock (_lock)
{
long timestamp = GetCurrentTimestamp();
if (timestamp == _lastTimestamp)
{
_sequence = (_sequence + 1) & 0xFFF; // 12 bit
if (_sequence == 0)
{
// Attendi il prossimo millisecondo
while ((timestamp = GetCurrentTimestamp()) <= _lastTimestamp) ;
}
}
else
{
_sequence = 0;
}
_lastTimestamp = timestamp;
return ((timestamp << 22) | ((long)_machineId << 12) | (long)_sequence);
}
}
private long GetCurrentTimestamp()
{
return (long)(DateTime.UtcNow - Epoch).TotalMilliseconds;
}
}
}