Explorar el Código

try to impl bigworld

JasonWang hace 6 años
padre
commit
a9c9de659e
Se han modificado 80 ficheros con 942 adiciones y 91 borrados
  1. 1 1
      src/MineCase.Core/Block/AirBlock.cs
  2. 31 1
      src/MineCase.Core/Block/Block.cs
  3. 5 5
      src/MineCase.Core/Block/Blocks.cs
  4. 12 0
      src/MineCase.Core/Network/DataType.cs
  5. 2 2
      src/MineCase.Core/Util/Math/Position.cs
  6. 2 0
      src/MineCase.Core/Util/Palette/IPalette.cs
  7. 12 0
      src/MineCase.Core/Util/Palette/PaletteArray.cs
  8. 7 1
      src/MineCase.Core/Util/Palette/PaletteGlobal.cs
  9. 21 1
      src/MineCase.Core/Util/Palette/PaletteHashMap.cs
  10. 5 0
      src/MineCase.Core/Util/Palette/PalettedData.cs
  11. 1 1
      src/MineCase.Core/World/Biome/BiomeId.cs
  12. 61 0
      src/MineCase.Core/World/Chunk/ChunkColumn.cs
  13. 1 1
      src/MineCase.Core/World/Chunk/ChunkPrimer.cs
  14. 5 0
      src/MineCase.Core/World/Chunk/ChunkSection.cs
  15. 5 5
      src/MineCase.Gateway/Network/ClientSession.cs
  16. 2 2
      src/MineCase.Protocol/Protocol/Handshaking/Server/Handshake.cs
  17. 1 1
      src/MineCase.Protocol/Protocol/Login/Client/EncryptionRequest.cs
  18. 1 1
      src/MineCase.Protocol/Protocol/Login/Client/LoginDisconnect.cs
  19. 1 1
      src/MineCase.Protocol/Protocol/Login/Client/LoginPluginRequest.cs
  20. 1 1
      src/MineCase.Protocol/Protocol/Login/Client/LoginSuccess.cs
  21. 1 1
      src/MineCase.Protocol/Protocol/Login/Client/SetCompression.cs
  22. 1 1
      src/MineCase.Protocol/Protocol/Login/Server/EncryptionResponse.cs
  23. 1 1
      src/MineCase.Protocol/Protocol/Login/Server/LoginPluginResponse.cs
  24. 1 1
      src/MineCase.Protocol/Protocol/Login/Server/LoginStart.cs
  25. 1 1
      src/MineCase.Protocol/Protocol/Packet.cs
  26. 1 1
      src/MineCase.Protocol/Protocol/PacketDecoder.cs
  27. 1 1
      src/MineCase.Protocol/Protocol/PacketDirection.cs
  28. 1 1
      src/MineCase.Protocol/Protocol/PacketEncoder.cs
  29. 1 1
      src/MineCase.Protocol/Protocol/Play/Client/ChunkData.cs
  30. 30 0
      src/MineCase.Protocol/Protocol/Play/Client/UnloadChunk.cs
  31. 1 1
      src/MineCase.Protocol/Protocol/Protocol.cs
  32. 6 6
      src/MineCase.Protocol/Protocol/ProtocolType.cs
  33. 1 1
      src/MineCase.Protocol/Protocol/SessionState.cs
  34. 1 1
      src/MineCase.Protocol/Protocol/Status/Client/Pong.cs
  35. 1 1
      src/MineCase.Protocol/Protocol/Status/Client/Response.cs
  36. 2 2
      src/MineCase.Protocol/Protocol/Status/Server/Ping.cs
  37. 1 1
      src/MineCase.Protocol/Protocol/Status/Server/Request.cs
  38. 11 0
      src/MineCase.Server.Grains/Engine/BigWorldBaseApp.cs
  39. 21 0
      src/MineCase.Server.Grains/Engine/BigWorldCellApp.cs
  40. 12 0
      src/MineCase.Server.Grains/Engine/BigWorldClient.cs
  41. 53 0
      src/MineCase.Server.Grains/Engine/BigWorldEntity.cs
  42. 2 2
      src/MineCase.Server.Grains/Engine/BigWorldMethods.cs
  43. 50 0
      src/MineCase.Server.Grains/Engine/BigWorldObject.cs
  44. 10 0
      src/MineCase.Server.Grains/Engine/BigWorldObjectState.cs
  45. 108 0
      src/MineCase.Server.Grains/Engine/BigWorldProperty.cs
  46. 22 0
      src/MineCase.Server.Grains/Engine/BigWorldPropertyMetadata.cs
  47. 41 0
      src/MineCase.Server.Grains/Engine/BigWorldSpace.cs
  48. 15 0
      src/MineCase.Server.Grains/Engine/BigWorldValue.cs
  49. 34 0
      src/MineCase.Server.Grains/Engine/Data/IBigWorldValue.cs
  50. 23 0
      src/MineCase.Server.Grains/Engine/EntityObjectTest.cs
  51. 7 4
      src/MineCase.Server.Grains/Entity/Entity.cs
  52. 5 0
      src/MineCase.Server.Grains/Entity/EntityHolder.cs
  53. 3 2
      src/MineCase.Server.Grains/Entity/LivingEntity.cs
  54. 4 2
      src/MineCase.Server.Grains/Entity/Player/PlayerEntity.cs
  55. 24 4
      src/MineCase.Server.Grains/Game/MinecraftServer.cs
  56. 13 4
      src/MineCase.Server.Grains/Game/MultiPlayer/User.cs
  57. 78 0
      src/MineCase.Server.Grains/Network/ClientPlayPacketGenerator.cs
  58. 1 1
      src/MineCase.Server.Grains/Network/ClientboundPacketSink.cs
  59. 1 1
      src/MineCase.Server.Grains/Network/Handler/Handshaking/IHandshakeNetHandler.cs
  60. 4 4
      src/MineCase.Server.Grains/Network/Handler/Handshaking/ServerHandshakeNetHandler.cs
  61. 1 1
      src/MineCase.Server.Grains/Network/Handler/Login/IServerLoginNetHandler.cs
  62. 3 3
      src/MineCase.Server.Grains/Network/Handler/Login/ServerLoginNetHandler.cs
  63. 1 1
      src/MineCase.Server.Grains/Network/Handler/Status/IServerStatusNetHandler.cs
  64. 2 2
      src/MineCase.Server.Grains/Network/Handler/Status/ServerStatusNetHandler.cs
  65. 4 4
      src/MineCase.Server.Grains/Network/PacketRouter.cs
  66. 8 0
      src/MineCase.Server.Grains/World/Chunk/Chunk.cs
  67. 4 4
      src/MineCase.Server.Grains/World/Chunk/ChunkHolder.cs
  68. 26 3
      src/MineCase.Server.Grains/World/Chunk/ChunkManager.cs
  69. 11 0
      src/MineCase.Server.Interfaces/Engine/IBigWorldBaseApp.cs
  70. 15 0
      src/MineCase.Server.Interfaces/Engine/IBigWorldCellApp.cs
  71. 13 0
      src/MineCase.Server.Interfaces/Engine/IBigWorldClient.cs
  72. 11 0
      src/MineCase.Server.Interfaces/Engine/IBigWorldSpace.cs
  73. 46 0
      src/MineCase.Server.Interfaces/Engine/IEntityMessage.cs
  74. 2 0
      src/MineCase.Server.Interfaces/Entity/IEntityHolder.cs
  75. 1 1
      src/MineCase.Server.Interfaces/Network/IClientboundPacketObserver.cs
  76. 1 1
      src/MineCase.Server.Interfaces/Network/IPacketRouter.cs
  77. 0 1
      src/MineCase.Server.Interfaces/Network/IPacketSink.cs
  78. 3 0
      src/MineCase.Server.Interfaces/Server/MultiPlayer/IUser.cs
  79. 3 0
      src/MineCase.Server.Interfaces/World/Chunk/IChunk.cs
  80. 16 0
      tests/UnitTest/BigWorldEngineTest.cs

+ 1 - 1
src/MineCase.Core/Block/AirBlock.cs

@@ -7,7 +7,7 @@ namespace MineCase.Block
     public class AirBlock : Block
     {
         public AirBlock(BlockProperties properties)
-            :base(properties)
+            :base("minecraft:air", properties)
         {
         }
     }

+ 31 - 1
src/MineCase.Core/Block/Block.cs

@@ -22,6 +22,8 @@ namespace MineCase.Block
 
     public class Block
     {
+        // Name
+        public string Name { get; set; }
         // Default state
         private BlockState _defaultState;
 
@@ -35,8 +37,10 @@ namespace MineCase.Block
 
         public BlockState Default { get => _defaultState; }
 
-        public Block(BlockProperties properties)
+        public Block(string name, BlockProperties properties)
         {
+            Name = name;
+
             _lightValue = properties.LightValue;
             _hardness = properties.Hardness;
             _resistance = properties.Resistance;
@@ -46,6 +50,32 @@ namespace MineCase.Block
             _defaultState = new BlockState(this);
         }
 
+
+        public override bool Equals(object obj)
+        {
+            return (obj is Block || obj.GetType().IsSubclassOf(typeof(Block))) && Equals((Block)obj);
+        }
+
+        public bool Equals(Block other)
+        {
+            return Name == other.Name;
+        }
+
+        public override int GetHashCode()
+        {
+            return Name.GetHashCode();
+        }
+
+        public static bool operator ==(Block pos1, Block pos2)
+        {
+            return pos1.Equals(pos2);
+        }
+
+        public static bool operator !=(Block pos1, Block pos2)
+        {
+            return !(pos1 == pos2);
+        }
+
         [ObsoleteAttribute("This method will soon be deprecated. Use Default property instead.")]
         public BlockState GetDefaultState()
         {

+ 5 - 5
src/MineCase.Core/Block/Blocks.cs

@@ -19,18 +19,18 @@ namespace MineCase.Block
 
         public static Dictionary<BlockState, int> BlockStateToId { get; } = new Dictionary<BlockState, int>()
         {
-            { Air.GetDefaultState(), 0 },
-            { VoidAir.GetDefaultState(), 1 },
+            { Air.Default, 0 },
+            { VoidAir.Default, 1 },
         };
 
         public static Dictionary<int, BlockState> IdToBlockState { get; } = new Dictionary<int, BlockState>()
         {
-            { 0, Air.GetDefaultState() },
-            { 1, VoidAir.GetDefaultState() },
+            { 0, Air.Default },
+            { 1, VoidAir.Default },
         };
 
         public static BiDictionary<int, BlockState> BlockStateRegistry { get; } = new BiDictionary<int, BlockState>(IdToBlockState, BlockStateToId);
 
-        public static IPalette<BlockState> GlobalPalette { get; } = new PaletteIdentity<BlockState>(BlockStateRegistry, Blocks.Air.GetDefaultState()); 
+        public static IPalette<BlockState> GlobalPalette { get; } = new PaletteIdentity<BlockState>(BlockStateRegistry, Blocks.Air.Default); 
     }
 }

+ 12 - 0
src/MineCase.Core/Network/DataType.cs

@@ -18,6 +18,18 @@ namespace MineCase.Network
             return numWrite;
         }
 
+        public static uint SizeOfVarInt(this int value)
+        {
+            uint numWrite = 0;
+            do
+            {
+                value >>= 7;
+                numWrite++;
+            }
+            while (value != 0);
+            return numWrite;
+        }
+
         public static ushort ToBigEndian(this ushort value)
         {
             return (ushort)((value >> 8) | (((byte)value) << 8));

+ 2 - 2
src/MineCase.Core/Util/Math/Position.cs

@@ -188,10 +188,10 @@ namespace MineCase.Util.Math
 
         public override bool Equals(object obj)
         {
-            return obj is ChunkWorldPos && Equals((ChunkWorldPos)obj);
+            return obj is ChunkPos && Equals((ChunkPos)obj);
         }
 
-        public bool Equals(ChunkWorldPos other)
+        public bool Equals(ChunkPos other)
         {
             return X == other.X &&
                    Z == other.Z;

+ 2 - 0
src/MineCase.Core/Util/Palette/IPalette.cs

@@ -14,5 +14,7 @@ namespace MineCase.Util.Palette
         void Read(BinaryReader br);
 
         void Write(BinaryWriter bw);
+
+        int GetSerializedSize();
     }
 }

+ 12 - 0
src/MineCase.Core/Util/Palette/PaletteArray.cs

@@ -53,6 +53,18 @@ namespace MineCase.Util.Palette
             return _values[index];
         }
 
+        public int GetSerializedSize()
+        {
+            uint size = Length.SizeOfVarInt();
+
+            for (int i = 0; i < Length; ++i)
+            {
+                size += _stateRegistry.GetSecond(_values[i]).SizeOfVarInt();
+            }
+
+            return (int)size;
+        }
+
         public void Read(BinaryReader br)
         {
             Length = br.ReadAsVarInt(out _);

+ 7 - 1
src/MineCase.Core/Util/Palette/PaletteGlobal.cs

@@ -1,4 +1,5 @@
-using MineCase.Util.Collections;
+using MineCase.Network;
+using MineCase.Util.Collections;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -43,5 +44,10 @@ namespace MineCase.Util.Palette
         {
             throw new NotImplementedException();
         }
+
+        public int GetSerializedSize()
+        {
+            return (int)0.SizeOfVarInt();
+        }
     }
 }

+ 21 - 1
src/MineCase.Core/Util/Palette/PaletteHashMap.cs

@@ -1,4 +1,5 @@
-using MineCase.Util.Collections;
+using MineCase.Network;
+using MineCase.Util.Collections;
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -8,6 +9,10 @@ namespace MineCase.Util.Palette
 {
     public class PaletteHashMap<T> : IPalette<T>
     {
+        private readonly BiDictionary<int, T> _stateRegistry;
+
+        // private readonly T[] _values;
+        public int Length { get; set; }
         public PaletteHashMap(BiDictionary<int, T> registry, int bits)
         {
         }
@@ -21,6 +26,21 @@ namespace MineCase.Util.Palette
             throw new NotImplementedException();
         }
 
+        public int GetSerializedSize()
+        {
+            /*
+            uint size = Length.SizeOfVarInt();
+
+            for (int i = 0; i < Length; ++i)
+            {
+                size += _stateRegistry.GetSecond(_values[i]).SizeOfVarInt();
+            }
+
+            return (int)size;
+            */
+            throw new NotImplementedException();
+        }
+
         public int IndexOf(T value)
         {
             throw new NotImplementedException();

+ 5 - 0
src/MineCase.Core/Util/Palette/PalettedData.cs

@@ -97,6 +97,11 @@ namespace MineCase.Util.Palette
             return _storage.GetRawArray();
         }
 
+        public int GetSerializedSize()
+        {
+            return 1 + _palette.GetSerializedSize() + (int)_storage.Count.SizeOfVarInt() + _storage.GetRawArray().Length * 8;
+        }
+
         public void Read(BinaryReader br)
         {
             int bits = br.ReadAsByte();

+ 1 - 1
src/MineCase.Core/World/Biome/BiomeId.cs

@@ -4,7 +4,7 @@ using System.Text;
 
 namespace MineCase.World.Biome
 {
-    public enum BiomeId : byte
+    public enum BiomeId : Int32
     {
         Ocean = 0,
         Plains = 1,

+ 61 - 0
src/MineCase.Core/World/Chunk/ChunkColumn.cs

@@ -0,0 +1,61 @@
+using MineCase.Block;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MineCase.World.Chunk
+{
+    public class ChunkColumn
+    {
+        public static ChunkSection EmptySection = null;
+        public ChunkSection[] Sections { get; set; } = new ChunkSection[ChunkConstants.BlockEdgeWidthInSection];
+
+        public Biome.BiomeId[] Biomes { get; set; }
+
+        public UInt16 SectionBitMask {
+            get {
+                UInt16 mask = 0;
+                for (int i = 0; i < Sections.Length; ++i)
+                {
+                    ChunkSection chunksection = Sections[i];
+                    if (chunksection != EmptySection)
+                    {
+                        mask |= (UInt16)(1 << i);
+                    }
+                }
+                return mask;
+            }
+        }
+
+        public bool FullChunk { get => SectionBitMask == 0xFFFF; }
+
+        public BlockState this[int x, int y, int z]
+        {
+            get
+            {
+                ChunkSection chunksection = Sections[y >> 4];
+                if ((y >= 0 && y < ChunkConstants.ChunkHeight))
+                    throw new IndexOutOfRangeException("ChunkColumn.operator[]: position out of range.");
+                if (chunksection.Empty)
+                    return Blocks.Air.Default;
+                else
+                    return chunksection[x & 0xFFFF, y & 0xFFFF, z & 0xFFFF];
+            }
+            set
+            {
+                if (y >= 0 && y < 256)
+                {
+                    if (!(Sections[y >> 4].Empty && value.GetBlock() == Blocks.Air))
+                    {
+                        ChunkSection chunksection = Sections[y >> 4];
+                        chunksection[x, y & 0xFFFF, z] = value;
+                    }
+                }
+                else
+                {
+                    throw new IndexOutOfRangeException("ChunkColumn.operator[]: position out of range.");
+                }
+            }
+        }
+    }
+}

+ 1 - 1
src/MineCase.Core/World/Chunk/ChunkPrimer.cs

@@ -17,7 +17,7 @@ namespace MineCase.World.Chunk
                 if ((y >= 0 && y < ChunkConstants.ChunkHeight))
                     throw new IndexOutOfRangeException("ChunkPrimer.operator[]: position out of range.");
                 if (chunksection.Empty)
-                    return Blocks.Air.GetDefaultState();
+                    return Blocks.Air.Default;
                 else
                     return chunksection[x & 0xFFFF, y & 0xFFFF, z & 0xFFFF];
             }

+ 5 - 0
src/MineCase.Core/World/Chunk/ChunkSection.cs

@@ -55,6 +55,11 @@ namespace MineCase.World.Chunk
             Data.Read(br);
         }
 
+        public int GetSerializedSize()
+        {
+            return 2 + Data.GetSerializedSize();
+        }
+
         private static int GetIndex(int x, int y, int z)
         {
             return y << 8 | z << 4 | x;

+ 5 - 5
src/MineCase.Gateway/Network/ClientSession.cs

@@ -5,13 +5,13 @@ using System.Net.Sockets;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks.Dataflow;
-using MineCase.Protocol.Protocol;
-using MineCase.Protocol.Protocol.Handshaking.Server;
-using MineCase.Protocol.Protocol.Login.Server;
-using MineCase.Protocol.Protocol.Status.Server;
+using MineCase.Protocol;
+using MineCase.Protocol.Handshaking.Server;
+using MineCase.Protocol.Login.Server;
+using MineCase.Protocol.Status.Server;
 using MineCase.Server.Network;
 using Orleans;
-using ProtocolType = MineCase.Protocol.Protocol.ProtocolType;
+using ProtocolType = MineCase.Protocol.ProtocolType;
 
 namespace MineCase.Gateway.Network
 {

+ 2 - 2
src/MineCase.Protocol/Protocol/Handshaking/Server/Handshake.cs

@@ -2,10 +2,10 @@
 using System.Collections.Generic;
 using System.IO;
 using System.Text;
-using MineCase.Protocol.Protocol;
+using MineCase.Protocol;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol.Handshaking.Server
+namespace MineCase.Protocol.Handshaking.Server
 {
     [Packet(0x00, ProtocolType.Handshake, PacketDirection.ServerBound)]
     public sealed class Handshake : ISerializablePacket

+ 1 - 1
src/MineCase.Protocol/Protocol/Login/Client/EncryptionRequest.cs

@@ -4,7 +4,7 @@ using System.IO;
 using System.Text;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol.Login.Client
+namespace MineCase.Protocol.Login.Client
 {
     [Packet(0x01, ProtocolType.Login, PacketDirection.ClientBound)]
     public sealed class EncryptionRequest : ISerializablePacket

+ 1 - 1
src/MineCase.Protocol/Protocol/Login/Client/LoginDisconnect.cs

@@ -4,7 +4,7 @@ using System.IO;
 using System.Text;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol.Login.Client
+namespace MineCase.Protocol.Login.Client
 {
     [Packet(0x00, ProtocolType.Login, PacketDirection.ClientBound)]
     public sealed class LoginDisconnect : ISerializablePacket

+ 1 - 1
src/MineCase.Protocol/Protocol/Login/Client/LoginPluginRequest.cs

@@ -3,7 +3,7 @@ using System.Collections.Generic;
 using System.IO;
 using System.Text;
 
-namespace MineCase.Protocol.Protocol.Login.Client
+namespace MineCase.Protocol.Login.Client
 {
     [Packet(0x04, ProtocolType.Login, PacketDirection.ClientBound)]
     public sealed class LoginPluginRequest : ISerializablePacket

+ 1 - 1
src/MineCase.Protocol/Protocol/Login/Client/LoginSuccess.cs

@@ -4,7 +4,7 @@ using System.IO;
 using System.Text;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol.Login.Client
+namespace MineCase.Protocol.Login.Client
 {
     [Packet(0x02, ProtocolType.Login, PacketDirection.ClientBound)]
     public sealed class LoginSuccess : ISerializablePacket

+ 1 - 1
src/MineCase.Protocol/Protocol/Login/Client/SetCompression.cs

@@ -4,7 +4,7 @@ using System.IO;
 using System.Text;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol.Login.Client
+namespace MineCase.Protocol.Login.Client
 {
     [Packet(0x03, ProtocolType.Login, PacketDirection.ClientBound)]
     public sealed class SetCompression : ISerializablePacket

+ 1 - 1
src/MineCase.Protocol/Protocol/Login/Server/EncryptionResponse.cs

@@ -4,7 +4,7 @@ using System.IO;
 using System.Text;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol.Login.Server
+namespace MineCase.Protocol.Login.Server
 {
     [Packet(0x02, ProtocolType.Login, PacketDirection.ServerBound)]
     public sealed class EncryptionResponse : ISerializablePacket

+ 1 - 1
src/MineCase.Protocol/Protocol/Login/Server/LoginPluginResponse.cs

@@ -4,7 +4,7 @@ using System.IO;
 using System.Text;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol.Login.Server
+namespace MineCase.Protocol.Login.Server
 {
     [Packet(0x01, ProtocolType.Login, PacketDirection.ServerBound)]
     public sealed class LoginPluginResponse : ISerializablePacket

+ 1 - 1
src/MineCase.Protocol/Protocol/Login/Server/LoginStart.cs

@@ -4,7 +4,7 @@ using System.IO;
 using System.Text;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol.Login.Server
+namespace MineCase.Protocol.Login.Server
 {
     [Packet(0x00, ProtocolType.Login, PacketDirection.ServerBound)]
     public sealed class LoginStart : ISerializablePacket

+ 1 - 1
src/MineCase.Protocol/Protocol/Packet.cs

@@ -5,7 +5,7 @@ using System.Text;
 using System.Threading.Tasks;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol
+namespace MineCase.Protocol
 {
     public class RawPacket
     {

+ 1 - 1
src/MineCase.Protocol/Protocol/PacketDecoder.cs

@@ -5,7 +5,7 @@ using System.Text;
 using System.Threading.Tasks;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol
+namespace MineCase.Protocol
 {
     public class PacketDecoder
     {

+ 1 - 1
src/MineCase.Protocol/Protocol/PacketDirection.cs

@@ -2,7 +2,7 @@
 using System.Collections.Generic;
 using System.Text;
 
-namespace MineCase.Protocol.Protocol
+namespace MineCase.Protocol
 {
     public enum PacketDirection
     {

+ 1 - 1
src/MineCase.Protocol/Protocol/PacketEncoder.cs

@@ -5,7 +5,7 @@ using System.Text;
 using System.Threading.Tasks;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol
+namespace MineCase.Protocol
 {
     public class PacketEncoder
     {

+ 1 - 1
src/MineCase.Protocol/Protocol/Play/Client/ChunkData.cs

@@ -6,7 +6,7 @@ using MineCase.Serialization;
 using MineCase.World.Biome;
 using MineCase.World.Chunk;
 
-namespace MineCase.Protocol.Protocol.Play.Client
+namespace MineCase.Protocol.Play.Client
 {
     [Packet(0x22, ProtocolType.Play, PacketDirection.ClientBound)]
     public sealed class ChunkData : ISerializablePacket

+ 30 - 0
src/MineCase.Protocol/Protocol/Play/Client/UnloadChunk.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using MineCase.Serialization;
+
+namespace MineCase.Protocol.Play.Client
+{
+    [Packet(0x1E, ProtocolType.Play, PacketDirection.ClientBound)]
+    public sealed class UnloadChunk : ISerializablePacket
+    {
+        [SerializeAs(DataType.Int)]
+        public int ChunkX;
+
+        [SerializeAs(DataType.Int)]
+        public int ChunkZ;
+
+        public void Deserialize(BinaryReader br)
+        {
+            ChunkX = br.ReadAsInt();
+            ChunkZ = br.ReadAsInt();
+        }
+
+        public void Serialize(BinaryWriter bw)
+        {
+            bw.WriteAsInt(ChunkX);
+            bw.WriteAsInt(ChunkZ);
+        }
+    }
+}

+ 1 - 1
src/MineCase.Protocol/Protocol/Protocol.cs

@@ -2,7 +2,7 @@
 using System.Collections.Generic;
 using System.Text;
 
-namespace MineCase.Protocol.Protocol
+namespace MineCase.Protocol
 {
     public static class Protocol
     {

+ 6 - 6
src/MineCase.Protocol/Protocol/ProtocolType.cs

@@ -3,13 +3,13 @@ using System.Collections.Generic;
 using System.IO;
 using System.Reflection;
 using System.Text;
-using MineCase.Protocol.Protocol.Handshaking.Server;
-using MineCase.Protocol.Protocol.Login.Client;
-using MineCase.Protocol.Protocol.Login.Server;
-using MineCase.Protocol.Protocol.Status.Client;
-using MineCase.Protocol.Protocol.Status.Server;
+using MineCase.Protocol.Handshaking.Server;
+using MineCase.Protocol.Login.Client;
+using MineCase.Protocol.Login.Server;
+using MineCase.Protocol.Status.Client;
+using MineCase.Protocol.Status.Server;
 
-namespace MineCase.Protocol.Protocol
+namespace MineCase.Protocol
 {
     public enum ProtocolType
     {

+ 1 - 1
src/MineCase.Protocol/Protocol/SessionState.cs

@@ -2,7 +2,7 @@
 using System.Collections.Generic;
 using System.Text;
 
-namespace MineCase.Protocol.Protocol
+namespace MineCase.Protocol
 {
     public enum SessionState
     {

+ 1 - 1
src/MineCase.Protocol/Protocol/Status/Client/Pong.cs

@@ -4,7 +4,7 @@ using System.IO;
 using System.Text;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol.Status.Client
+namespace MineCase.Protocol.Status.Client
 {
     [Packet(0x01, ProtocolType.Status, PacketDirection.ClientBound)]
     public sealed class Pong : ISerializablePacket

+ 1 - 1
src/MineCase.Protocol/Protocol/Status/Client/Response.cs

@@ -4,7 +4,7 @@ using System.IO;
 using System.Text;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol.Status.Client
+namespace MineCase.Protocol.Status.Client
 {
     [Packet(0x00, ProtocolType.Status, PacketDirection.ClientBound)]
     public sealed class Response : ISerializablePacket

+ 2 - 2
src/MineCase.Protocol/Protocol/Status/Server/Ping.cs

@@ -2,10 +2,10 @@
 using System.Collections.Generic;
 using System.IO;
 using System.Text;
-using MineCase.Protocol.Protocol;
+using MineCase.Protocol;
 using MineCase.Serialization;
 
-namespace MineCase.Protocol.Protocol.Status.Server
+namespace MineCase.Protocol.Status.Server
 {
     [Packet(0x01, ProtocolType.Status, PacketDirection.ServerBound)]
     public sealed class Ping : ISerializablePacket

+ 1 - 1
src/MineCase.Protocol/Protocol/Status/Server/Request.cs

@@ -3,7 +3,7 @@ using System.Collections.Generic;
 using System.IO;
 using System.Text;
 
-namespace MineCase.Protocol.Protocol.Status.Server
+namespace MineCase.Protocol.Status.Server
 {
     [Packet(0x00, ProtocolType.Status, PacketDirection.ServerBound)]
     public sealed class Request : ISerializablePacket

+ 11 - 0
src/MineCase.Server.Grains/Engine/BigWorldBaseApp.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Orleans;
+
+namespace MineCase.Server.Engine
+{
+    public class BigWorldBaseApp : Grain, IBigWorldBaseApp
+    {
+    }
+}

+ 21 - 0
src/MineCase.Server.Grains/Engine/BigWorldCellApp.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Orleans;
+
+namespace MineCase.Server.Engine
+{
+    public class BigWorldCellApp : Grain, IBigWorldCellApp
+    {
+        public Task Init()
+        {
+            return Task.CompletedTask;
+        }
+
+        public Task Destroy()
+        {
+            return Task.CompletedTask;
+        }
+    }
+}

+ 12 - 0
src/MineCase.Server.Grains/Engine/BigWorldClient.cs

@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Orleans;
+
+namespace MineCase.Server.Engine
+{
+    public class BigWorldClient : Grain, IBigWorldClient
+    {
+    }
+}

+ 53 - 0
src/MineCase.Server.Grains/Engine/BigWorldEntity.cs

@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MineCase.Server.Engine
+{
+    public struct BigWorldPosition
+    {
+        public float X { get; set; }
+
+        public float Y { get; set; }
+
+        public float Z { get; set; }
+
+        public BigWorldPosition(float x, float y, float z)
+        {
+            X = x;
+            Y = y;
+            Z = z;
+        }
+    }
+
+    public class BigWorldEntityRef
+    {
+        private Guid _id;
+        private Guid _spaceId;
+        private BigWorldPosition _position;
+        private bool _isDestroyed;
+    }
+
+    public enum BigWorldEntityLocation
+    {
+        Client,
+        Base,
+        Cell
+    }
+
+    public enum BigWorldEntityType
+    {
+        Real,
+        Ghost
+    }
+
+    public class BigWorldEntity
+    {
+        private Guid _id;
+        private Guid _spaceId;
+        private BigWorldEntityLocation _entityLocation;
+        private BigWorldEntityType _entityType;
+        private BigWorldPosition _position;
+        private bool _isDestroyed;
+    }
+}

+ 2 - 2
src/MineCase.Server.Grains/Entity/EntityAccesor.cs → src/MineCase.Server.Grains/Engine/BigWorldMethods.cs

@@ -2,9 +2,9 @@
 using System.Collections.Generic;
 using System.Text;
 
-namespace MineCase.Server.Entity
+namespace MineCase.Server.Engine
 {
-    public class EntityAccesor
+    public class BigWorldMethods
     {
     }
 }

+ 50 - 0
src/MineCase.Server.Grains/Engine/BigWorldObject.cs

@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text;
+
+namespace MineCase.Server.Engine
+{
+    public class BigWorldObject
+    {
+        public BigWorldProperty Properties { get; set; }
+
+        public Dictionary<string, MethodInfo> _methodTable;
+
+        public BigWorldObject()
+        {
+            Properties = new BigWorldProperty();
+            _methodTable = new Dictionary<string, MethodInfo>();
+            RegisterAllMethods();
+        }
+
+        public void RegisterAllMethods()
+        {
+            MethodInfo[] methods = GetType().GetMethods();
+            foreach (var eachMethod in methods)
+            {
+                _methodTable.Add(eachMethod.Name, eachMethod);
+            }
+        }
+
+        public T GetValue<T>(string name)
+        {
+            return Properties.GetValue<T>(name);
+        }
+
+        public T GetValue<T>(BigWorldPropertyEntry<T> prop)
+        {
+            return Properties.GetValue<T>(prop);
+        }
+
+        public void SetValue<T>(string name, T value)
+        {
+            Properties.SetValue(name, value);
+        }
+
+        public void SetValue<T>(BigWorldPropertyEntry<T> property, T value)
+        {
+            Properties.SetValue(property, value);
+        }
+    }
+}

+ 10 - 0
src/MineCase.Server.Grains/Engine/BigWorldObjectState.cs

@@ -0,0 +1,10 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MineCase.Server.Engine
+{
+    public class BigWorldObjectState
+    {
+    }
+}

+ 108 - 0
src/MineCase.Server.Grains/Engine/BigWorldProperty.cs

@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MineCase.Server.Engine
+{
+    public class BigWorldPropertyEntryBase
+    {
+        public Type ValueType { get; set; }
+
+        public bool HasDefault { get; set; }
+
+        public int Index { get; set; }
+    }
+
+    public class BigWorldPropertyEntry<T> : BigWorldPropertyEntryBase
+    {
+        public T DefaultValue { get; set; }
+    }
+
+    public class BigWorldProperty
+    {
+        private List<object> _values;
+        private Dictionary<string, BigWorldPropertyEntryBase> _info;
+
+        public BigWorldProperty()
+        {
+            _values = new List<object>();
+            _info = new Dictionary<string, BigWorldPropertyEntryBase>();
+        }
+
+        public BigWorldPropertyEntry<T> Register<T>(string name)
+        {
+            if (!_info.ContainsKey(name))
+            {
+                _info[name] = new BigWorldPropertyEntry<T>
+                {
+                    ValueType = typeof(T),
+                    HasDefault = false,
+                    Index = _values.Count
+                };
+                _values.Add(default(T));
+                return (BigWorldPropertyEntry<T>)_info[name];
+            }
+            else
+            {
+                throw new ArgumentException("This property is already existing。");
+            }
+        }
+
+        public BigWorldPropertyEntry<T> Register<T>(string name, T defaultValue)
+        {
+            if (!_info.ContainsKey(name))
+            {
+                _info[name] = new BigWorldPropertyEntry<T>
+                {
+                    ValueType = typeof(T),
+                    DefaultValue = defaultValue,
+                    HasDefault = true,
+                    Index = _values.Count
+                };
+                _values.Add(default(T));
+                return (BigWorldPropertyEntry<T>)_info[name];
+            }
+            else
+            {
+                throw new ArgumentException("This property is already existing。");
+            }
+        }
+
+        public T GetValue<T>(string name)
+        {
+            if (_info.ContainsKey(name))
+            {
+                var prop = _info[name];
+                return (T)_values[prop.Index];
+            }
+            else
+            {
+                throw new IndexOutOfRangeException("Property no found.");
+            }
+        }
+
+        public T GetValue<T>(BigWorldPropertyEntry<T> prop)
+        {
+            return (T)_values[prop.Index];
+        }
+
+        public void SetValue<T>(string name, T value)
+        {
+            if (_info.ContainsKey(name))
+            {
+                var prop = _info[name];
+                _values[prop.Index] = value;
+            }
+            else
+            {
+                throw new IndexOutOfRangeException("Property no found.");
+            }
+        }
+
+        public void SetValue<T>(BigWorldPropertyEntry<T> prop, T value)
+        {
+            _values[prop.Index] = value;
+        }
+    }
+}

+ 22 - 0
src/MineCase.Server.Grains/Engine/BigWorldPropertyMetadata.cs

@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MineCase.Server.Engine
+{
+    public class BigWorldPropertyMetadata<T>
+    {
+        private bool _defaultValueSet;
+        private T _defaultValue;
+
+        public bool HasDefaultValue => _defaultValueSet;
+
+        public T DefaultValue => _defaultValue;
+
+        public BigWorldPropertyMetadata(T defaultValue)
+        {
+            _defaultValue = defaultValue;
+            _defaultValueSet = true;
+        }
+    }
+}

+ 41 - 0
src/MineCase.Server.Grains/Engine/BigWorldSpace.cs

@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Orleans;
+
+namespace MineCase.Server.Engine
+{
+    public class BigWorldSpace : Grain, IBigWorldSpace
+    {
+        private Dictionary<Guid, IBigWorldCellApp> _cells = new Dictionary<Guid, IBigWorldCellApp>();
+
+        public override async Task OnActivateAsync()
+        {
+            await base.OnActivateAsync();
+        }
+
+        public Task<BigWorldEntityRef> CreateEntity()
+        {
+            return Task.CompletedTask;
+        }
+
+        protected Task<IBigWorldCellApp> CreateCell()
+        {
+            Guid cellId = Guid.NewGuid();
+            var cell = GrainFactory.GetGrain<IBigWorldCellApp>(cellId);
+            _cells.Add(cellId, cell);
+            cell.Init();
+            return Task.FromResult(cell);
+        }
+
+        protected async Task DestroyCell(Guid id)
+        {
+            if (_cells.ContainsKey(id))
+            {
+                await _cells[id].Destroy();
+                _cells.Remove(id);
+            }
+        }
+    }
+}

+ 15 - 0
src/MineCase.Server.Grains/Engine/BigWorldValue.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MineCase.Server.Engine
+{
+    public class IBigWorldValue
+    {
+    }
+
+    public class BigWorldValue<T> : IBigWorldValue
+    {
+        public T Value { get; set; }
+    }
+}

+ 34 - 0
src/MineCase.Server.Grains/Engine/Data/IBigWorldValue.cs

@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MineCase.Server.Engine.Data
+{
+    public interface IBigWorldValue
+    {
+    }
+
+    /// <summary>
+    /// BigWorldValue 接口.
+    /// </summary>
+    /// <typeparam name="T">值类型.</typeparam>
+    public interface IBigWorldValue<T> : IBigWorldValue
+    {
+        /// <summary>
+        /// 获取可否设置值.
+        /// </summary>
+        bool CanSetValue { get; }
+
+        /// <summary>
+        /// 获取值.
+        /// </summary>
+        T Value { get; }
+
+        /// <summary>
+        /// 设置值.
+        /// </summary>
+        /// <param name="value">值.</param>
+        void SetValue(T value);
+    }
+}

+ 23 - 0
src/MineCase.Server.Grains/Engine/EntityObjectTest.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using MineCase.Util.Math;
+
+namespace MineCase.Server.Engine
+{
+    public class EntityObjectTest : BigWorldObject
+    {
+        private BigWorldPropertyEntry<int> _viewDistance;
+
+        public EntityObjectTest()
+        {
+            _viewDistance = Properties.Register<int>("ViewDistance");
+        }
+
+        public Task<int> GetViewDistance()
+        {
+            return Task.FromResult(Properties.GetValue(_viewDistance));
+        }
+    }
+}

+ 7 - 4
src/MineCase.Server.Grains/Entity/Entity.cs

@@ -19,11 +19,14 @@ namespace MineCase.Server.Entity
 
         public EntityPos Position { get; set; }
 
-        protected IGrainFactory _grainFactory;
-
-        public Entity(IGrainFactory grainFactory)
+        // protected IGrainFactory _grainFactory;
+        public Entity(IGrainFactory grainFactory, IWorld world)
         {
-            _grainFactory = grainFactory;
+            PrimaryKey = Guid.NewGuid();
+            World = world;
+            Position = new EntityPos(0, 0, 0);
+
+            // _grainFactory = grainFactory;
         }
 
         public Task<Guid> GetID()

+ 5 - 0
src/MineCase.Server.Grains/Entity/EntityHolder.cs

@@ -18,6 +18,11 @@ namespace MineCase.Server.Entity
     {
         private IGameSession _gameSession;
 
+        public Task<bool> IsSpawned()
+        {
+            return Task.FromResult(State.Entity != null);
+        }
+
         public Task<bool> Lock(IGameSession gameSession)
         {
             if (_gameSession == null)

+ 3 - 2
src/MineCase.Server.Grains/Entity/LivingEntity.cs

@@ -1,14 +1,15 @@
 using System;
 using System.Collections.Generic;
 using System.Text;
+using MineCase.Server.World;
 using Orleans;
 
 namespace MineCase.Server.Entity
 {
     public abstract class LivingEntity : Entity
     {
-        public LivingEntity(IGrainFactory grainFactory)
-            : base(grainFactory)
+        public LivingEntity(IGrainFactory grainFactory, IWorld world)
+            : base(grainFactory, world)
         {
         }
     }

+ 4 - 2
src/MineCase.Server.Grains/Entity/Player/PlayerEntity.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
 using MineCase.Server.Network;
+using MineCase.Server.World;
 using MineCase.Util.Math;
 using MineCase.World;
 using Orleans;
@@ -15,9 +16,10 @@ namespace MineCase.Server.Entity.Player
 
         public int ViewDistance { get; set; }
 
-        public PlayerEntity(IGrainFactory grainFactory)
-            : base(grainFactory)
+        public PlayerEntity(IGrainFactory grainFactory, IWorld world)
+            : base(grainFactory, world)
         {
+            ViewDistance = 12;
         }
 
         public new Task OnGameTick(object sender, GameTickArgs tickArgs)

+ 24 - 4
src/MineCase.Server.Grains/Game/MinecraftServer.cs

@@ -4,6 +4,8 @@ using System.Text;
 using System.Threading.Tasks;
 using MineCase.Core.World.Dimension;
 using MineCase.Game.Server.MultiPlayer;
+using MineCase.Server.Entity;
+using MineCase.Server.Entity.Player;
 using MineCase.Server.World;
 using Orleans;
 using Orleans.Providers;
@@ -20,6 +22,17 @@ namespace MineCase.Game.Server
     {
         private readonly List<IUser> _users = new List<IUser>();
 
+        public override async Task OnActivateAsync()
+        {
+            await base.OnActivateAsync();
+
+            if (!State.Worlds.ContainsKey(DimensionType.Overworld))
+            {
+                var world = GrainFactory.GetGrain<IWorld>(DimensionType.Overworld.ToString());
+                State.Worlds[DimensionType.Overworld] = world;
+            }
+        }
+
         public Task<int> GetNetworkCompressionThreshold()
         {
             return Task.FromResult(-1);
@@ -30,15 +43,22 @@ namespace MineCase.Game.Server
             return Task.FromResult(false);
         }
 
-        public Task UserJoin(IUser user)
+        public async Task UserJoin(IUser user)
         {
             _users.Add(user);
-            user.SetServer(this);
+            await user.SetServer(this);
+
+            // Spawn Player Entity
+            var playerHolder = GrainFactory.GetGrain<IEntityHolder>(user.GetPrimaryKey());
+            if (!await playerHolder.IsSpawned())
+            {
+                PlayerEntity player = new PlayerEntity(GrainFactory, State.Worlds[DimensionType.Overworld]);
+                await playerHolder.Save(player);
+            }
 
             // Get main session and join in
             var mainSession = GrainFactory.GetGrain<IGameSession>(Guid.Empty);
-            mainSession.UserEnter(user);
-            return Task.CompletedTask;
+            await mainSession.UserEnter(user);
         }
 
         public Task UserLeave()

+ 13 - 4
src/MineCase.Server.Grains/Game/MultiPlayer/User.cs

@@ -2,9 +2,11 @@
 using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
+using MineCase.Protocol.Play.Client;
 using MineCase.Server.Network;
 using MineCase.Server.World;
 using MineCase.Util.Math;
+using MineCase.World.Chunk;
 using Orleans;
 using Orleans.Providers;
 
@@ -17,8 +19,6 @@ namespace MineCase.Game.Server.MultiPlayer
         public IWorld World { get; set; }
 
         public string Name { get; set; }
-
-        public Guid EntityKey { get; set; }
 }
 
     [StorageProvider(ProviderName = "MongoDBStore")]
@@ -26,10 +26,12 @@ namespace MineCase.Game.Server.MultiPlayer
     {
         private IPacketSink _packetSink;
         private IGameSession _gameSession;
+        private ClientPlayPacketGenerator _packetGenerator;
 
         public override async Task OnActivateAsync()
         {
             await base.OnActivateAsync();
+            _packetGenerator = new ClientPlayPacketGenerator(GrainFactory);
         }
 
         public override async Task OnDeactivateAsync()
@@ -84,7 +86,7 @@ namespace MineCase.Game.Server.MultiPlayer
 
         public Task<Guid> GetEntityId()
         {
-            return Task.FromResult(State.EntityKey);
+            return Task.FromResult(this.GetPrimaryKey());
         }
 
         public Task BindPacketSink(IPacketSink sink)
@@ -95,7 +97,14 @@ namespace MineCase.Game.Server.MultiPlayer
 
         public async Task SetPlayerPosition(EntityPos pos)
         {
-            await _gameSession.SetPlayerPosition(State.EntityKey, pos);
+            await _gameSession.SetPlayerPosition(this.GetPrimaryKey(), pos);
+        }
+
+        // Packets
+        public async Task SendChunkData(int chunkX, int chunkZ, ChunkColumn chunk)
+        {
+            var packet = await _packetGenerator.ChunkData(chunkX, chunkZ, chunk, 0xFFFF);
+            await _packetSink.SendPacket(packet);
         }
     }
 }

+ 78 - 0
src/MineCase.Server.Grains/Network/ClientPlayPacketGenerator.cs

@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using MineCase.Protocol.Play.Client;
+using MineCase.World.Chunk;
+using Orleans;
+
+namespace MineCase.Server.Network
+{
+    internal class ClientPlayPacketGenerator
+    {
+        private IGrainFactory _grainFactory;
+
+        public ClientPlayPacketGenerator(IGrainFactory grainFactory)
+        {
+            _grainFactory = grainFactory;
+        }
+
+        public async Task<ChunkData> ChunkData(int chunkX, int chunkZ, ChunkColumn chunk, int blockChangeMask)
+        {
+            bool fullChunk = blockChangeMask == 0xFFFF;
+            var chunkData = new ChunkData
+            {
+                ChunkX = chunkX,
+                ChunkZ = chunkZ,
+                FullChunk = fullChunk,
+                PrimaryBitMask = GetPrimaryBitMask(chunk, fullChunk, blockChangeMask),
+                Heightmaps = new Nbt.Tags.NbtCompound(),
+                Biomes = null,
+                Data = new byte[GetDataSize(chunk, fullChunk, blockChangeMask)],
+                NumberOfBlockEntities = 0,
+                BlockEntities = new List<Nbt.Tags.NbtCompound>(),
+            };
+
+            if (chunkData.FullChunk)
+            {
+                chunkData.Biomes = chunk.Biomes;
+            }
+
+            return chunkData;
+        }
+
+        protected int GetDataSize(ChunkColumn chunk, bool isFullChunk, int blockChangeMask)
+        {
+            int size = 0;
+            ChunkSection[] sections = chunk.Sections;
+
+            for (int i = 0; i < sections.Length; ++i)
+            {
+                ChunkSection chunksection = sections[i];
+                if (chunksection != ChunkColumn.EmptySection && (!isFullChunk || !chunksection.Empty) && (blockChangeMask & 1 << i) != 0)
+                {
+                    size += chunksection.GetSerializedSize();
+                }
+            }
+
+            return size;
+        }
+
+        public int GetPrimaryBitMask(ChunkColumn chunk, bool isFullChunk, int blockChangeMask)
+        {
+            int mask = 0;
+            ChunkSection[] sections = chunk.Sections;
+
+            for (int i = 0; i < sections.Length; ++i)
+            {
+                ChunkSection chunksection = sections[i];
+                if (chunksection != ChunkColumn.EmptySection && (!isFullChunk || !chunksection.Empty) && (blockChangeMask & 1 << i) != 0)
+                {
+                    mask |= 1 << i;
+                }
+            }
+
+            return mask;
+        }
+    }
+}

+ 1 - 1
src/MineCase.Server.Grains/Network/ClientboundPacketSink.cs

@@ -1,7 +1,7 @@
 using System;
 using System.IO;
 using System.Threading.Tasks;
-using MineCase.Protocol.Protocol;
+using MineCase.Protocol;
 using Orleans;
 using Orleans.Concurrency;
 

+ 1 - 1
src/MineCase.Server.Grains/Network/Handler/Handshaking/IHandshakeNetHandler.cs

@@ -2,7 +2,7 @@
 using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
-using MineCase.Protocol.Protocol.Handshaking.Server;
+using MineCase.Protocol.Handshaking.Server;
 
 namespace MineCase.Server.Network.Handler.Handshaking
 {

+ 4 - 4
src/MineCase.Server.Grains/Network/Handler/Handshaking/ServerHandshakeNetHandler.cs

@@ -2,8 +2,8 @@
 using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
-using MineCase.Protocol.Protocol;
-using MineCase.Protocol.Protocol.Handshaking.Server;
+using MineCase.Protocol;
+using MineCase.Protocol.Handshaking.Server;
 using Orleans;
 
 namespace MineCase.Server.Network.Handler.Handshaking
@@ -28,13 +28,13 @@ namespace MineCase.Server.Network.Handler.Handshaking
             if (packet.NextState == (int)SessionState.Login)
             {
                 await _clientSession.SetSessionState(SessionState.Login);
-                if (packet.ProtocolVersion > Protocol.Protocol.Protocol.Version)
+                if (packet.ProtocolVersion > Protocol.Protocol.Version)
                 {
                     // ITextComponent itextcomponent = new TranslationTextComponent("multiplayer.disconnect.outdated_server", SharedConstants.getVersion().getName());
                     // this.networkManager.sendPacket(new SDisconnectLoginPacket(itextcomponent));
                     await _packetSink.Close();
                 }
-                else if (packet.ProtocolVersion > Protocol.Protocol.Protocol.Version)
+                else if (packet.ProtocolVersion > Protocol.Protocol.Version)
                 {
                     // ITextComponent itextcomponent1 = new TranslationTextComponent("multiplayer.disconnect.outdated_client", SharedConstants.getVersion().getName());
                     // this.networkManager.sendPacket(new SDisconnectLoginPacket(itextcomponent1));

+ 1 - 1
src/MineCase.Server.Grains/Network/Handler/Login/IServerLoginNetHandler.cs

@@ -2,7 +2,7 @@
 using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
-using MineCase.Protocol.Protocol.Login.Server;
+using MineCase.Protocol.Login.Server;
 
 namespace MineCase.Server.Network.Handler.Login
 {

+ 3 - 3
src/MineCase.Server.Grains/Network/Handler/Login/ServerLoginNetHandler.cs

@@ -3,9 +3,9 @@ using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
 using MineCase.Game;
-using MineCase.Protocol.Protocol;
-using MineCase.Protocol.Protocol.Login.Client;
-using MineCase.Protocol.Protocol.Login.Server;
+using MineCase.Protocol;
+using MineCase.Protocol.Login.Client;
+using MineCase.Protocol.Login.Server;
 using MineCase.Game.Server;
 using MineCase.Game.Server.MultiPlayer;
 using Orleans;

+ 1 - 1
src/MineCase.Server.Grains/Network/Handler/Status/IServerStatusNetHandler.cs

@@ -2,7 +2,7 @@
 using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
-using MineCase.Protocol.Protocol.Status.Server;
+using MineCase.Protocol.Status.Server;
 
 namespace MineCase.Server.Network.Handler.Status
 {

+ 2 - 2
src/MineCase.Server.Grains/Network/Handler/Status/ServerStatusNetHandler.cs

@@ -2,8 +2,8 @@
 using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
-using MineCase.Protocol.Protocol.Status.Client;
-using MineCase.Protocol.Protocol.Status.Server;
+using MineCase.Protocol.Status.Client;
+using MineCase.Protocol.Status.Server;
 using Orleans;
 
 namespace MineCase.Server.Network.Handler.Status

+ 4 - 4
src/MineCase.Server.Grains/Network/PacketRouter.cs

@@ -3,10 +3,10 @@ using System.Collections.Generic;
 using System.IO;
 using System.Text;
 using System.Threading.Tasks;
-using MineCase.Protocol.Protocol;
-using MineCase.Protocol.Protocol.Handshaking.Server;
-using MineCase.Protocol.Protocol.Login.Server;
-using MineCase.Protocol.Protocol.Status.Server;
+using MineCase.Protocol;
+using MineCase.Protocol.Handshaking.Server;
+using MineCase.Protocol.Login.Server;
+using MineCase.Protocol.Status.Server;
 using MineCase.Server.Network.Handler;
 using MineCase.Server.Network.Handler.Handshaking;
 using MineCase.Server.Network.Handler.Login;

+ 8 - 0
src/MineCase.Server.Grains/World/Chunk/Chunk.cs

@@ -1,10 +1,18 @@
 using System;
 using System.Collections.Generic;
 using System.Text;
+using System.Threading.Tasks;
+using MineCase.World.Chunk;
 
 namespace MineCase.Server.World.Chunk
 {
     public class Chunk : IChunk
     {
+        private ChunkColumn _chunkColumn;
+
+        public Task<ChunkColumn> GetChunkColumn()
+        {
+            return Task.FromResult(_chunkColumn);
+        }
     }
 }

+ 4 - 4
src/MineCase.Server.Grains/World/Chunk/ChunkHolder.cs

@@ -44,14 +44,14 @@ namespace MineCase.Server.World.Chunk
             }
         }
 
-        public Task<Chunk> Load()
+        public Task<IChunk> Load()
         {
-            return Task.FromResult(State.Chunk);
+            return Task.FromResult((IChunk)State.Chunk);
         }
 
-        public Task Save(Chunk chunk)
+        public Task Save(IChunk chunk)
         {
-            State.Chunk = chunk;
+            State.Chunk = (Chunk)chunk;
             return Task.CompletedTask;
         }
     }

+ 26 - 3
src/MineCase.Server.Grains/World/Chunk/ChunkManager.cs

@@ -79,12 +79,28 @@ namespace MineCase.Server.World.Chunk
         private async Task UpdatePlayerPosition(PlayerEntity player)
         {
             // TODO: update tracking
+
+            // Unload chunks out of range and load new chunks
             var chunkPos = player.Position.ToChunkPos();
             var lastSectionPos = player.LastSectionPos;
             if (Math.Abs(lastSectionPos.X - chunkPos.X) <= _viewDistance * 2
                 && Math.Abs(lastSectionPos.Z - lastSectionPos.Z) <= _viewDistance * 2)
             {
-                // TODO
+                int xMin = Math.Min(chunkPos.X, lastSectionPos.X) - _viewDistance;
+                int zMin = Math.Min(chunkPos.Z, lastSectionPos.Z) - _viewDistance;
+                int xMax = Math.Max(chunkPos.X, lastSectionPos.X) + _viewDistance;
+                int zMax = Math.Max(chunkPos.Z, lastSectionPos.Z) + _viewDistance;
+
+                for (int x = xMin; x <= xMax; ++x)
+                {
+                    for (int z = zMin; z <= zMax; ++z)
+                    {
+                        ChunkPos eachChunkPos = new ChunkPos(x, z);
+                        bool isLoaded = GetChunkDistance(eachChunkPos, lastSectionPos.X, lastSectionPos.Z) <= _viewDistance;
+                        bool needLoad = GetChunkDistance(eachChunkPos, chunkPos.X, chunkPos.Z) <= _viewDistance;
+                        await SyncClientChunkState(player, eachChunkPos, isLoaded, needLoad);
+                    }
+                }
             }
             else
             {
@@ -120,14 +136,21 @@ namespace MineCase.Server.World.Chunk
                 if (needLoad && !isLoaded)
                 {
                     IChunk chunk = await GetChunk(chunkPos);
-                    user.SendChunkData(chunk);
+                    await user.SendChunkData(chunkPos.X, chunkPos.Z, await chunk.GetChunkColumn());
                 }
 
                 if (!needLoad && isLoaded)
                 {
-                    user.SendChunkUnload(chunkPos);
+                    // user.SendChunkUnload(chunkPos);
                 }
             }
         }
+
+        private static int GetChunkDistance(ChunkPos chunkPos, int x, int y)
+        {
+            int xDiff = chunkPos.X - x;
+            int zDiff = chunkPos.Z - y;
+            return Math.Max(Math.Abs(xDiff), Math.Abs(zDiff));
+        }
     }
 }

+ 11 - 0
src/MineCase.Server.Interfaces/Engine/IBigWorldBaseApp.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Orleans;
+
+namespace MineCase.Server.Engine
+{
+    public interface IBigWorldBaseApp : IGrainWithGuidKey
+    {
+    }
+}

+ 15 - 0
src/MineCase.Server.Interfaces/Engine/IBigWorldCellApp.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Orleans;
+
+namespace MineCase.Server.Engine
+{
+    public interface IBigWorldCellApp : IGrainWithGuidKey
+    {
+        Task Init();
+
+        Task Destroy();
+    }
+}

+ 13 - 0
src/MineCase.Server.Interfaces/Engine/IBigWorldClient.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading.Tasks;
+using Orleans;
+
+namespace MineCase.Server.Engine
+{
+    public interface IBigWorldClient : IGrainWithGuidKey
+    {
+
+    }
+}

+ 11 - 0
src/MineCase.Server.Interfaces/Engine/IBigWorldSpace.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Orleans;
+
+namespace MineCase.Server.Engine
+{
+    public interface IBigWorldSpace : IGrainWithGuidKey
+    {
+    }
+}

+ 46 - 0
src/MineCase.Server.Interfaces/Engine/IEntityMessage.cs

@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MineCase.Server.Engine
+{
+    /// <summary>
+    /// 是实体消息.
+    /// </summary>
+    public interface IEntityMessage
+    {
+    }
+
+    /// <summary>
+    /// 具有回复的实体消息.
+    /// </summary>
+    /// <typeparam name="TResponse">回复类型.</typeparam>
+    public interface IEntityMessage<TResponse>
+    {
+    }
+
+    public sealed class AskResult<TResponse>
+    {
+        /// <summary>
+        /// 询问失败.
+        /// </summary>
+        public static readonly AskResult<TResponse> Failed = new AskResult<TResponse> { Succeeded = false };
+
+        /// <summary>
+        /// 是否成功.
+        /// </summary>
+        public bool Succeeded;
+
+        /// <summary>
+        /// 回复.
+        /// </summary>
+        public TResponse Response;
+    }
+
+    /// <summary>
+    /// 找不到接收者异常.
+    /// </summary>
+    public class ReceiverNotFoundException : Exception
+    {
+    }
+}

+ 2 - 0
src/MineCase.Server.Interfaces/Entity/IEntityHolder.cs

@@ -9,6 +9,8 @@ namespace MineCase.Server.Entity
 {
     public interface IEntityHolder : IGrainWithGuidKey
     {
+        Task<bool> IsSpawned();
+
         Task<bool> Lock(IGameSession gameSession);
 
         Task<bool> UnLock(IGameSession gameSession);

+ 1 - 1
src/MineCase.Server.Interfaces/Network/IClientboundPacketObserver.cs

@@ -2,7 +2,7 @@
 using System.Collections.Generic;
 using System.Text;
 using MineCase.Protocol;
-using MineCase.Protocol.Protocol;
+using MineCase.Protocol;
 using Orleans;
 
 namespace MineCase.Server.Network

+ 1 - 1
src/MineCase.Server.Interfaces/Network/IPacketRouter.cs

@@ -2,8 +2,8 @@
 using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
-using MineCase.Protocol.Protocol;
 using MineCase.Game.Server.MultiPlayer;
+using MineCase.Protocol;
 using Orleans;
 
 namespace MineCase.Server.Network

+ 0 - 1
src/MineCase.Server.Interfaces/Network/IPacketSink.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.Text;
 using System.Threading.Tasks;
 using MineCase.Protocol;
-using MineCase.Protocol.Protocol;
 using Orleans.Concurrency;
 
 namespace MineCase.Server.Network

+ 3 - 0
src/MineCase.Server.Interfaces/Server/MultiPlayer/IUser.cs

@@ -5,6 +5,7 @@ using System.Threading.Tasks;
 using MineCase.Server.Network;
 using MineCase.Server.World;
 using MineCase.Util.Math;
+using MineCase.World.Chunk;
 using Orleans;
 
 namespace MineCase.Game.Server.MultiPlayer
@@ -32,5 +33,7 @@ namespace MineCase.Game.Server.MultiPlayer
         Task BindPacketSink(IPacketSink sink);
 
         Task SetPlayerPosition(EntityPos pos);
+
+        Task SendChunkData(int chunkX, int chunkZ, ChunkColumn chunk);
     }
 }

+ 3 - 0
src/MineCase.Server.Interfaces/World/Chunk/IChunk.cs

@@ -1,10 +1,13 @@
 using System;
 using System.Collections.Generic;
 using System.Text;
+using System.Threading.Tasks;
+using MineCase.World.Chunk;
 
 namespace MineCase.Server.World.Chunk
 {
     public interface IChunk
     {
+        Task<ChunkColumn> GetChunkColumn();
     }
 }

+ 16 - 0
tests/UnitTest/BigWorldEngineTest.cs

@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Xunit;
+
+namespace MineCase.UnitTest
+{
+    public class BigWorldEngineTest
+    {
+        [Fact]
+        public void Test1()
+        {
+
+        }
+    }
+}