From 35f8fbb2b26e3add8497655d9d6b5d6c596cda34 Mon Sep 17 00:00:00 2001 From: AlessandroCH Date: Fri, 18 Jul 2025 14:49:33 +0200 Subject: [PATCH] another try to improve entity spawning and fix loading but still loading issues --- Campofinale/Game/SceneManager.cs | 65 +++++++++---------- .../Packets/Cs/HandleCsSceneMoveStateSet.cs | 2 +- .../Packets/Cs/HandleCsSceneTeleport.cs | 6 ++ Campofinale/Resource/ResourceManager.cs | 28 ++++++++ Campofinale/Utils/SnowflakeIdGenerator.cs | 56 ++++++++++++++++ 5 files changed, 120 insertions(+), 37 deletions(-) create mode 100644 Campofinale/Utils/SnowflakeIdGenerator.cs diff --git a/Campofinale/Game/SceneManager.cs b/Campofinale/Game/SceneManager.cs index 35a1ada..ff9e569 100644 --- a/Campofinale/Game/SceneManager.cs +++ b/Campofinale/Game/SceneManager.cs @@ -4,10 +4,12 @@ using Campofinale.Packets.Sc; using Campofinale.Resource; using Campofinale.Resource.Dynamic; using MongoDB.Bson.Serialization.Attributes; +using System; using System.Text.Json.Serialization; using static Campofinale.Resource.Dynamic.SpawnerConfig; using static Campofinale.Resource.ResourceManager; using static Campofinale.Resource.ResourceManager.LevelScene.LevelData; +using static Campofinale.Resource.ResourceManager.LevelScene.LevelData.LevelFunctionAreaData; namespace Campofinale.Game { @@ -235,7 +237,6 @@ namespace Campofinale.Game { if (scene != null) { - scene.alreadyLoaded = false; scene.Unload(); } } @@ -256,11 +257,11 @@ namespace Campofinale.Game [BsonIgnore,JsonIgnore] public List entities = new(); [BsonIgnore, JsonIgnore] - public bool alreadyLoaded = false; - [BsonIgnore, JsonIgnore] public List activeScripts = new(); public List scripts = new(); + [BsonIgnore, JsonIgnore] + private LevelFunctionRangeData currentAreaRange = new(); public int GetCollection(string id) { if (collections.ContainsKey(id)) @@ -367,17 +368,12 @@ namespace Campofinale.Game entities.Add(entity); }); - - - UpdateShowEntities(); } public void SpawnEntity(Entity en,bool spawnedCheck=true) { - en.spawned = true; - GetOwner().Send(new PacketScObjectEnterView(GetOwner(), new List() { en })); } public bool GetActiveScript(ulong id) @@ -392,10 +388,22 @@ namespace Campofinale.Game 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 public async void UpdateShowEntities() { - + UpdateArea(); List toSpawn = new(); List toCheck = GetEntityExcludingChar().FindAll(e => e.spawned == false); 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(currentAreaRange.IsObjectInside(e.Position)) if (!e.defaultHide) { toSpawn.Add(e); @@ -423,34 +432,18 @@ namespace Campofinale.Game GetOwner().Send(new PacketScObjectEnterView(GetOwner(), chunk)); } } + List 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()) - { - float minDis = 100; - - //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() { en.guid })); - en.Position=en.BornPos; - en.Rotation = en.Rotation; - } - } - }*/ + } + if(toDespawn.Count > 0) + GetOwner().Send(new PacketScObjectLeaveView(GetOwner(), toDespawn)); } public Player GetOwner() diff --git a/Campofinale/Packets/Cs/HandleCsSceneMoveStateSet.cs b/Campofinale/Packets/Cs/HandleCsSceneMoveStateSet.cs index 21c3f0c..5a7f8e8 100644 --- a/Campofinale/Packets/Cs/HandleCsSceneMoveStateSet.cs +++ b/Campofinale/Packets/Cs/HandleCsSceneMoveStateSet.cs @@ -11,7 +11,7 @@ namespace Campofinale.Packets.Cs { CsSceneMoveStateSet req = packet.DecodeBody(); //req. - + } } diff --git a/Campofinale/Packets/Cs/HandleCsSceneTeleport.cs b/Campofinale/Packets/Cs/HandleCsSceneTeleport.cs index 06a9ded..b4c77b6 100644 --- a/Campofinale/Packets/Cs/HandleCsSceneTeleport.cs +++ b/Campofinale/Packets/Cs/HandleCsSceneTeleport.cs @@ -1,5 +1,6 @@ using Campofinale.Network; using Campofinale.Protocol; +using Campofinale.Utils; namespace Campofinale.Packets.Cs { @@ -26,6 +27,9 @@ namespace Campofinale.Packets.Cs } else { + uint unixTimestamp = (uint)DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + var generator = new SnowflakeIdGenerator(machineId: 1); + long id = generator.GenerateId(); ScSceneTeleport t = new() { TeleportReason = req.TeleportReason, @@ -33,6 +37,8 @@ namespace Campofinale.Packets.Cs Position = req.Position, Rotation = req.Rotation, SceneNumId = req.SceneNumId, + ServerTime = unixTimestamp, + TpUuid= (ulong)id }; session.curSceneNumId = t.SceneNumId; session.Send(ScMsgId.ScSceneTeleport, t); diff --git a/Campofinale/Resource/ResourceManager.cs b/Campofinale/Resource/ResourceManager.cs index 63ec522..448d3a5 100644 --- a/Campofinale/Resource/ResourceManager.cs +++ b/Campofinale/Resource/ResourceManager.cs @@ -2,6 +2,8 @@ using Campofinale.Resource.Json; using Campofinale.Resource.Table; using Newtonsoft.Json; +using System.Numerics; +using System; using static Campofinale.Resource.ResourceManager.LevelScene; namespace Campofinale.Resource @@ -549,6 +551,7 @@ namespace Campofinale.Resource public List worldWayPointSets = new(); public List factoryRegions = new(); public List spawners = new(); + public LevelFunctionAreaData functionArea = new(); public void Merge(LevelData other) { this.sceneId = other.sceneId; @@ -560,6 +563,7 @@ namespace Campofinale.Resource this.worldWayPointSets.AddRange(other.worldWayPointSets); this.factoryRegions.AddRange(other.factoryRegions); this.spawners.AddRange(other.spawners); + this.functionArea.ranges.AddRange(other.functionArea.ranges); } public class WorldWayPointSets @@ -567,6 +571,26 @@ namespace Campofinale.Resource public int id; public Dictionary pointIdToIndex = new(); } + + public class LevelFunctionAreaData + { + public List 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 ulong spawnerId; @@ -949,6 +973,10 @@ namespace Campofinale.Resource 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) { diff --git a/Campofinale/Utils/SnowflakeIdGenerator.cs b/Campofinale/Utils/SnowflakeIdGenerator.cs new file mode 100644 index 0000000..8568db4 --- /dev/null +++ b/Campofinale/Utils/SnowflakeIdGenerator.cs @@ -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. 0–31 (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; + } + } + +}