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.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<Entity> entities = new();
[BsonIgnore, JsonIgnore]
public bool alreadyLoaded = false;
[BsonIgnore, JsonIgnore]
public List<ulong> activeScripts = new();
public List<LevelScript> 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<Entity>() { 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<Entity> toSpawn = new();
List<Entity> 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<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())
{
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<ulong>() { en.guid }));
en.Position=en.BornPos;
en.Rotation = en.Rotation;
}
}
}*/
}
if(toDespawn.Count > 0)
GetOwner().Send(new PacketScObjectLeaveView(GetOwner(), toDespawn));
}
public Player GetOwner()

View File

@ -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);

View File

@ -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> worldWayPointSets = new();
public List<LevelFactoryRegionData> factoryRegions = new();
public List<LevelSpawnerData> 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<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 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)
{

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;
}
}
}