this repo has no description
at master 99 lines 3.6 kB view raw
1using System.Collections.Concurrent; 2using System.Numerics; 3using GlmSharp; 4using Kestrel.Framework.Client.Graphics; 5using Kestrel.Framework.Client.Graphics.Buffers; 6using Kestrel.Framework.Client.Graphics.Camera; 7using Kestrel.Framework.Networking.Packets; 8using Kestrel.Framework.Networking.Packets.C2S; 9using Kestrel.Framework.Utils; 10using KestrelWorld = Kestrel.Framework.World.World; 11using LiteNetLib; 12using Silk.NET.OpenGL; 13using Silk.NET.Windowing; 14using ArchWorld = Arch.Core.World; 15using ArchEntity = Arch.Core.Entity; 16using Kestrel.Framework.Entity.Components; 17using Arch.Core; 18using Arch.Core.Extensions; 19using Kestrel.Framework.Entity; 20 21public enum ClientStatus 22{ 23 Connecting, 24 Connected, 25 Disconnected 26} 27 28public class ClientState 29{ 30 public ClientStatus status = ClientStatus.Connecting; 31 public Kestrel.Framework.Client.Graphics.Window Window; 32 public Camera Camera; 33 public ArchEntity Player; 34 public string PlayerName; 35 public ArchWorld Entities; 36 public ConcurrentDictionary<Guid, ArchEntity> NetworkableEntities = []; 37 public ConcurrentDictionary<Guid, ArchEntity> ServerIdToEntity = []; 38 public NetPeer NetServer; 39 public KestrelWorld World; 40 public ConcurrentDictionary<Vector3I, ChunkMesh> ChunkMeshes = []; 41 public ChunkMeshManager ChunkMeshManager = new(); 42 public int RenderDistance = 12; 43 public HashSet<Vector3I> RequestedChunks = []; 44 public HashSet<Vector3I> RequestedChunksQueue = []; 45 public Profiler Profiler = new(); 46 47#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. 48 public ClientState(GL gl, IWindow silkWindow) 49#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. 50 { 51 Window = new(gl, 800, 600); 52 silkWindow.FramebufferResize += @Window.OnResize; 53 54 Camera = new ThirdPersonCamera(this); 55 } 56 57 public void RequestChunk(Vector3I chunkPos) 58 { 59 if (RequestedChunks.Contains(chunkPos)) 60 return; 61 RequestedChunks.Add(chunkPos); 62 RequestedChunksQueue.Add(chunkPos); 63 } 64 65 public void RequestChunksFromQueue() 66 { 67 if (RequestedChunksQueue.Count == 0 || NetServer == null) return; 68 69 if (!Player.Has<Location>()) 70 throw new Exception("Player does not have required Location component."); 71 72 Location playerLocation = Player.Get<Location>(); 73 74 World.WorldToChunk( 75 (int)playerLocation.X, (int)playerLocation.Y, (int)playerLocation.Z, 76 out var playerChunk, out _); 77 78 var queueSortedByDistance = new List<Vector3I>(RequestedChunksQueue); 79 queueSortedByDistance.Sort((a, b) => 80 { 81 float aDistance = LocationUtil.HorizontallyWeightedDistance(playerChunk.ToVector3(), a.ToVector3()); 82 float bDistance = LocationUtil.HorizontallyWeightedDistance(playerChunk.ToVector3(), b.ToVector3()); 83 return aDistance.CompareTo(bDistance); 84 }); 85 86 87 int batchCount = Math.Min(8, queueSortedByDistance.Count); 88 NetServer.Send(IPacket.Serialize(new C2SChunkRequest 89 { 90 ChunkCount = batchCount, 91 Chunks = [.. queueSortedByDistance.Take(batchCount)] 92 }), DeliveryMethod.ReliableOrdered); 93 94 foreach (var chunkPos in queueSortedByDistance.Take(batchCount)) 95 { 96 RequestedChunksQueue.Remove(chunkPos); 97 } 98 } 99}