├── .gitignore ├── PixelWorldsServer.Server ├── Data │ ├── blocks-config.csv │ ├── tutorial-world.bin │ └── default-blocks-config.csv ├── appsettings.json ├── Event │ ├── EventAttribute.cs │ └── EventManager.cs ├── Players │ ├── PlayerManager.cs │ └── Player.cs ├── log4net.config ├── Program.cs ├── ServerHostedService.cs ├── PixelWorldsServer.Server.csproj ├── Network │ └── TcpServer.cs └── Worlds │ ├── World.cs │ └── WorldManager.cs ├── PixelWorldsServer.Protocol ├── Constants │ ├── Gender.cs │ ├── GravityMode.cs │ ├── PlayerCostumeType.cs │ ├── GemType.cs │ ├── LayerType.cs │ ├── AdminStatus.cs │ ├── CameraZoomLevel.cs │ ├── BasicWorldBiome.cs │ ├── LightingType.cs │ ├── StatusIconType.cs │ ├── BlockDirection.cs │ ├── Direction.cs │ ├── TutorialState.cs │ ├── LayerBackgroundType.cs │ ├── InventoryItemType.cs │ ├── WeatherType.cs │ ├── BlockClass.cs │ ├── InstructionEventsCompleted.cs │ ├── WorldJoinResult.cs │ ├── AnimationHotSpots.cs │ ├── WorldLayoutType.cs │ ├── StatisticsKey.cs │ ├── Achievement.cs │ ├── AnimationNames.cs │ └── CountryCodes.cs ├── Packet │ ├── PacketBase.cs │ ├── Request │ │ ├── SyncTimeRequest.cs │ │ ├── BuyItemPackRequest.cs │ │ ├── CollectRequest.cs │ │ ├── WorldChatMessageRequest.cs │ │ ├── ChangeCameraZoomValueRequest.cs │ │ ├── MenuWorldLoadInfoRequest.cs │ │ ├── RenamePlayerRequest.cs │ │ ├── PlayerStatusIconUpdateRequest.cs │ │ ├── WearableOrWeaponChangeRequest.cs │ │ ├── HitBlockRequest.cs │ │ ├── TutorialStateRequest.cs │ │ ├── ChangeCameraZoomLevelRequest.cs │ │ ├── VersionCheckRequest.cs │ │ ├── SetSeedRequest.cs │ │ ├── SetBlockRequest.cs │ │ ├── GetPlayerDataRequest.cs │ │ ├── CharacterCreatedRequest.cs │ │ ├── TryToJoinWorldRequest.cs │ │ ├── GetWorldRequest.cs │ │ └── MyPosRequest.cs │ └── Response │ │ ├── RemoveCollectResponse.cs │ │ ├── PlayerLeftResponse.cs │ │ ├── VersionCheckResponse.cs │ │ ├── GetWorldCompressedResponse.cs │ │ ├── LoginTokenUpdateResponse.cs │ │ ├── SyncTimeResponse.cs │ │ ├── RenamePlayerResponse.cs │ │ ├── PlayerStatusIconUpdateResponse.cs │ │ ├── WearableOrWeaponChangeResponse.cs │ │ ├── MenuWorldLoadInfoResponse.cs │ │ ├── TryToJoinWorldResponse.cs │ │ ├── HitBlockResponse.cs │ │ ├── SetBlockResponse.cs │ │ ├── DestroyBlockResponse.cs │ │ ├── MyPosResponse.cs │ │ ├── BuyItemPackResponse.cs │ │ ├── WorldChatMessageResponse.cs │ │ ├── CollectResponse.cs │ │ ├── GetPlayerDataResponse.cs │ │ ├── SetSeedResponse.cs │ │ ├── AddNetworkPlayerResponse.cs │ │ ├── PlayerDataResponse.cs │ │ └── GetWorldResponse.cs ├── Worlds │ ├── LockAccess.cs │ ├── StereosData.cs │ ├── ScifiArrowData.cs │ ├── LabLightRedData.cs │ ├── LanternBlueData.cs │ ├── ScifiLightsData.cs │ ├── LabHoseLargeData.cs │ ├── ScifiComputerData.cs │ ├── EntrancePortalData.cs │ ├── SewerPipeBlackData.cs │ ├── LabElectricWireRedData.cs │ ├── LabElectricWireBlueData.cs │ ├── ScifiDoorData.cs │ ├── BattleBarrierLabData.cs │ ├── LayerBlockBackground.cs │ ├── LayerBlock.cs │ ├── LayerWiring.cs │ ├── TutorialSleepPodData.cs │ ├── TutorialCablePortalData.cs │ ├── PortalData.cs │ ├── WorldItemBase.cs │ ├── CollectableData.cs │ ├── SeedData.cs │ └── LockSmallData.cs ├── PixelWorldsServer.Protocol.csproj ├── Players │ └── InventoryItemBase.cs └── Utils │ ├── BlockTuple.cs │ ├── ShuffleBag.cs │ ├── Math.cs │ ├── LZMATools.cs │ ├── PositionConversions.cs │ ├── Seeds.cs │ ├── DataFactory.cs │ ├── RollDrops.cs │ └── NetStrings.cs ├── PixelWorldsServer.DataAccess ├── DatabaseSettings.cs ├── PixelWorldsServer.DataAccess.csproj ├── Database.cs └── Models │ ├── WorldModel.cs │ └── PlayerModel.cs ├── Dockerfile ├── README.md └── PixelWorldsServer.sln /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | obj/ 3 | .vs/ 4 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/Data/blocks-config.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zKevz/Pixel-Worlds-Server/HEAD/PixelWorldsServer.Server/Data/blocks-config.csv -------------------------------------------------------------------------------- /PixelWorldsServer.Server/Data/tutorial-world.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zKevz/Pixel-Worlds-Server/HEAD/PixelWorldsServer.Server/Data/tutorial-world.bin -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/Gender.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum Gender 4 | { 5 | Male, 6 | Female, 7 | } 8 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/GravityMode.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum GravityMode 4 | { 5 | Normal, 6 | Low, 7 | High, 8 | } 9 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/PlayerCostumeType.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum PlayerCostumeType 4 | { 5 | None, 6 | Werewolf 7 | } 8 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/PacketBase.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Packet; 2 | 3 | public class PacketBase 4 | { 5 | public string ID { get; set; } = string.Empty; 6 | } 7 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/GemType.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum GemType 4 | { 5 | Gem1, 6 | Gem2, 7 | Gem3, 8 | Gem4, 9 | Gem5, 10 | } 11 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/LayerType.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum LayerType 4 | { 5 | Block, 6 | Background, 7 | Water, 8 | Wiring 9 | } 10 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/AdminStatus.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum AdminStatus 4 | { 5 | None, 6 | Moderator, 7 | Admin, 8 | Influencer, 9 | } 10 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/CameraZoomLevel.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum CameraZoomLevel 4 | { 5 | ExtraFar, 6 | Far, 7 | Normal, 8 | Near, 9 | } 10 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/BasicWorldBiome.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum BasicWorldBiome 4 | { 5 | Forest, 6 | Empty, 7 | Winter, 8 | Desert, 9 | Alien 10 | } 11 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/LightingType.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum LightingType 4 | { 5 | None, 6 | Dark, 7 | Mining, 8 | LesserDark, 9 | GreatDark, 10 | } 11 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/StatusIconType.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum StatusIconType 4 | { 5 | None, 6 | InMenus, 7 | Typing, 8 | Trading, 9 | CardGame 10 | } 11 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/BlockDirection.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum BlockDirection 4 | { 5 | None, 6 | Center, 7 | Up, 8 | Right, 9 | Down, 10 | Left, 11 | } 12 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/LockAccess.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Worlds; 2 | 3 | public class LockAccess 4 | { 5 | public string Id { get; set; } = string.Empty; 6 | public string Name { get; set; } = string.Empty; 7 | } 8 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Database": { 3 | "ConnectionString": "mongodb://localhost:27017", 4 | "DatabaseName": "PixelWorlds", 5 | "PlayersCollectionName": "Players", 6 | "WorldsCollectionName": "Worlds" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/Direction.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum Direction 4 | { 5 | Center, 6 | Up, 7 | UpRight, 8 | Right, 9 | DownRight, 10 | Down, 11 | DownLeft, 12 | Left, 13 | UpLeft, 14 | LeftMinor, 15 | UpUpLeft, 16 | UpUpRight 17 | } 18 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/TutorialState.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum TutorialState 4 | { 5 | NotStarted, 6 | CharacterCreation, 7 | TutorialWorld, 8 | TutorialCompleted, 9 | TutorialPhase1, 10 | TutorialPhase2, 11 | TutorialPhase3, 12 | TutorialPhase4, 13 | } 14 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/LayerBackgroundType.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum LayerBackgroundType 4 | { 5 | ForestBackground, 6 | NightBackground, 7 | SpaceBackground, 8 | DesertBackground, 9 | IceBackground, 10 | StarBackground, 11 | CandyBackground, 12 | TODOBackground, 13 | } 14 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/Event/EventAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Server.Event; 2 | 3 | [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)] 4 | public sealed class EventAttribute : Attribute 5 | { 6 | public string Id { get; set; } 7 | 8 | public EventAttribute(string id) 9 | { 10 | Id = id; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/InventoryItemType.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum InventoryItemType 4 | { 5 | Block, 6 | BlockBackground, 7 | Seed, 8 | BlockWater, 9 | WearableItem, 10 | Weapon, 11 | Throwable, 12 | Consumable, 13 | Shard, 14 | Blueprint, 15 | Familiar, 16 | FAMFood, 17 | } 18 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/SyncTimeRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Request; 6 | 7 | public class SyncTimeRequest : PacketBase 8 | { 9 | [BsonElement(NetStrings.TIME_KEY)] 10 | public long Time { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/RemoveCollectResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Utils; 3 | 4 | namespace PixelWorldsServer.Protocol.Packet.Response; 5 | 6 | public class RemoveCollectResponse : PacketBase 7 | { 8 | [BsonElement(NetStrings.COLLECTABLE_ID_KEY)] 9 | public int CollectableId { get; set; } 10 | } 11 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/StereosData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Worlds; 4 | 5 | public class StereosData : WorldItemBase 6 | { 7 | public StereosData() : base(0, BlockType.Stereos) 8 | { 9 | } 10 | 11 | public StereosData(int itemId) : base(itemId, BlockType.Stereos) 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/Data/default-blocks-config.csv: -------------------------------------------------------------------------------- 1 | ocsvcache_defaultsforblocks4Default value,,,,,,0,15,0,0,,0,0,1,0,1000,0,1-8,0-2,20,10,0-0,0,0,0,0,0,-1,0,0,0,12.0,1.00,1.0,1.0,5.0,0.37,0.3456310,0,0,0,0,0,0.0000000,0,1,4294967295,188846180,188846180,1,yes,0,0,30,1,0,0,0,0,0,1,-0.04 0.04,-0.04 0.04,0,0,0,0,0,2,0,0,0,0,0,1.0 0 1.0,3,0,0,0,-1,0,0,0,0,0,0,0,0,0,0,0,0,-1,1,0,0,0,-1,0,0,0 -------------------------------------------------------------------------------- /PixelWorldsServer.DataAccess/DatabaseSettings.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.DataAccess; 2 | 3 | public class DatabaseSettings 4 | { 5 | public string ConnectionString { get; set; } = null!; 6 | public string DatabaseName { get; set; } = null!; 7 | public string PlayersCollectionName { get; set; } = null!; 8 | public string WorldsCollectionName { get; set; } = null!; 9 | } 10 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/PlayerLeftResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Utils; 3 | 4 | namespace PixelWorldsServer.Protocol.Packet.Response; 5 | 6 | public class PlayerLeftResponse : PacketBase 7 | { 8 | [BsonElement(NetStrings.PLAYER_ID_KEY)] 9 | public string PlayerId { get; set; } = string.Empty; 10 | } 11 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/BuyItemPackRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Utils; 3 | 4 | namespace PixelWorldsServer.Protocol.Packet.Request; 5 | 6 | public class BuyItemPackRequest : PacketBase 7 | { 8 | [BsonElement(NetStrings.ITEM_PACK_ID_KEY)] 9 | public string ItemPackId { get; set; } = string.Empty; 10 | } 11 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/CollectRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Request; 6 | 7 | public class CollectRequest : PacketBase 8 | { 9 | [BsonElement(NetStrings.COLLECTABLE_ID_KEY)] 10 | public int CollectableId { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/WorldChatMessageRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Utils; 3 | 4 | namespace PixelWorldsServer.Protocol.Packet.Request; 5 | 6 | public class WorldChatMessageRequest : PacketBase 7 | { 8 | [BsonElement(NetStrings.MESSAGE_KEY)] 9 | public string Message { get; set; } = string.Empty; 10 | } 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Application builder 2 | FROM mcr.microsoft.com/dotnet/sdk:6.0 AS builder 3 | 4 | WORKDIR /app 5 | 6 | COPY . . 7 | 8 | RUN dotnet restore 9 | 10 | RUN dotnet publish -c Release -o out 11 | 12 | # Runtime image 13 | FROM mcr.microsoft.com/dotnet/aspnet:6.0 14 | 15 | WORKDIR /app 16 | 17 | COPY --from=builder /app/out . 18 | 19 | ENTRYPOINT ["dotnet", "PixelWorldsServer.Server.dll"] 20 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/ScifiArrowData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Worlds; 4 | 5 | public class ScifiArrowData : WorldItemBase 6 | { 7 | public ScifiArrowData() : base(0, BlockType.ScifiArrow) 8 | { 9 | } 10 | 11 | public ScifiArrowData(int itemId) : base(itemId, BlockType.ScifiArrow) 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/VersionCheckResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Response; 6 | 7 | public class VersionCheckResponse : PacketBase 8 | { 9 | [BsonElement(NetStrings.VERSION_NUMBER_KEY)] 10 | public int VersionNumber { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/LabLightRedData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Worlds; 4 | 5 | public class LabLightRedData : WorldItemBase 6 | { 7 | public LabLightRedData() : base(0, BlockType.LabLightRed) 8 | { 9 | } 10 | 11 | public LabLightRedData(int itemId) : base(itemId, BlockType.LabLightRed) 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/LanternBlueData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Worlds; 4 | 5 | public class LanternBlueData : WorldItemBase 6 | { 7 | public LanternBlueData() : base(0, BlockType.LanternBlue) 8 | { 9 | } 10 | 11 | public LanternBlueData(int itemId) : base(itemId, BlockType.LanternBlue) 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/ScifiLightsData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Worlds; 4 | 5 | public class ScifiLightsData : WorldItemBase 6 | { 7 | public ScifiLightsData() : base(0, BlockType.ScifiLights) 8 | { 9 | } 10 | 11 | public ScifiLightsData(int itemId) : base(itemId, BlockType.ScifiLights) 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/LabHoseLargeData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Worlds; 4 | 5 | public class LabHoseLargeData : WorldItemBase 6 | { 7 | public LabHoseLargeData() : base(0, BlockType.LabHoseLarge) 8 | { 9 | } 10 | 11 | public LabHoseLargeData(int itemId) : base(itemId, BlockType.LabHoseLarge) 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/WeatherType.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum WeatherType 4 | { 5 | None, 6 | HeavyRain, 7 | PixelTrail, 8 | SandStorm, 9 | LightRain, 10 | LightSnow, 11 | SnowStorm, 12 | DeepNether, 13 | Halloween, 14 | HalloweenTower, 15 | Hearts, 16 | Mining, 17 | AuroraBorealis, 18 | Armageddon, 19 | } 20 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/ChangeCameraZoomValueRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Request; 6 | 7 | public class ChangeCameraZoomValueRequest : PacketBase 8 | { 9 | [BsonElement(NetStrings.AMOUNT_KEY)] 10 | public float CameraZoomValue { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/GetWorldCompressedResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Response; 6 | 7 | public class GetWorldCompressedResponse : PacketBase 8 | { 9 | [BsonElement(NetStrings.WORLD_KEY)] 10 | public byte[] WorldData { get; set; } = null!; 11 | } 12 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/LoginTokenUpdateResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Response; 6 | 7 | public class LoginTokenUpdateResponse : PacketBase 8 | { 9 | [BsonElement(NetStrings.TOKEN_KEY)] 10 | public string Token { get; set; } = string.Empty; 11 | } 12 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/MenuWorldLoadInfoRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Request; 6 | 7 | public class MenuWorldLoadInfoRequest : PacketBase 8 | { 9 | [BsonElement(NetStrings.WORLD_NAME_KEY)] 10 | public string WorldName { get; set; } = string.Empty; 11 | } 12 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/RenamePlayerRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Request; 6 | 7 | public class RenamePlayerRequest : PacketBase 8 | { 9 | [BsonElement(NetStrings.PLAYER_USERNAME_KEY)] 10 | public string PlayerName { get; set; } = string.Empty; 11 | } 12 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/ScifiComputerData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Worlds; 4 | 5 | public class ScifiComputerData : WorldItemBase 6 | { 7 | public ScifiComputerData() : base(0, BlockType.ScifiComputer) 8 | { 9 | } 10 | 11 | public ScifiComputerData(int itemId) : base(itemId, BlockType.ScifiComputer) 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/EntrancePortalData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Worlds; 4 | 5 | public class EntrancePortalData : WorldItemBase 6 | { 7 | public EntrancePortalData() : base(0, BlockType.EntrancePortal) 8 | { 9 | } 10 | 11 | public EntrancePortalData(int itemId) : base(itemId, BlockType.EntrancePortal) 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/SewerPipeBlackData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Worlds; 4 | 5 | public class SewerPipeBlackData : WorldItemBase 6 | { 7 | public SewerPipeBlackData() : base(0, BlockType.SewerPipeBlack) 8 | { 9 | } 10 | 11 | public SewerPipeBlackData(int itemId) : base(itemId, BlockType.SewerPipeBlack) 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/BlockClass.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum BlockClass 4 | { 5 | GroundGeneric, 6 | GroundSoft, 7 | GroundHard, 8 | GroundVegetation, 9 | GroundIndestructible, 10 | WeaponGeneric, 11 | WeaponBlade, 12 | WeaponPickaxe, 13 | WeaponGun, 14 | WeaponPickaxePoor, 15 | WeaponPickaxeGood, 16 | WeaponPickaxeEpic 17 | } 18 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/LabElectricWireRedData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Worlds; 4 | 5 | public class LabElectricWireRedData : WorldItemBase 6 | { 7 | public LabElectricWireRedData() : base(0, BlockType.LabElectricWireRed) 8 | { 9 | } 10 | 11 | public LabElectricWireRedData(int itemId) : base(itemId, BlockType.LabElectricWireRed) 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/PlayerStatusIconUpdateRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Constants; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Request; 6 | 7 | public class PlayerStatusIconUpdateRequest : PacketBase 8 | { 9 | [BsonElement(NetStrings.STATUS_ICON_FIELD_KEY)] 10 | public StatusIconType StatusIcon { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/LabElectricWireBlueData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Worlds; 4 | 5 | public class LabElectricWireBlueData : WorldItemBase 6 | { 7 | public LabElectricWireBlueData() : base(0, BlockType.LabElectricWireBlue) 8 | { 9 | } 10 | 11 | public LabElectricWireBlueData(int itemId) : base(itemId, BlockType.LabElectricWireBlue) 12 | { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/WearableOrWeaponChangeRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Constants; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Request; 6 | 7 | public class WearableOrWeaponChangeRequest : PacketBase 8 | { 9 | [BsonElement(NetStrings.HOTSPOT_BLOCK_TYPE_KEY)] 10 | public BlockType HotspotBlockType { get; set; } 11 | } 12 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/HitBlockRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Request; 6 | 7 | public class HitBlockRequest : PacketBase 8 | { 9 | [BsonElement(NetStrings.POSITION_X_KEY)] 10 | public int X { get; set; } 11 | 12 | [BsonElement(NetStrings.POSITION_Y_KEY)] 13 | public int Y { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/TutorialStateRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Request; 7 | 8 | public class TutorialStateRequest : PacketBase 9 | { 10 | [BsonElement(NetStrings.TUTORIAL_STATE_UPDATE_FIELD_KEY)] 11 | public TutorialState TutorialState { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/ChangeCameraZoomLevelRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Request; 7 | 8 | public class ChangeCameraZoomLevelRequest : PacketBase 9 | { 10 | [BsonElement(NetStrings.CAMERA_ZOOM_LEVEL_UPDATE_FIELD_KEY)] 11 | public CameraZoomLevel CameraZoomLevel { get; set; } 12 | } 13 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/SyncTimeResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Response; 6 | 7 | public class SyncTimeResponse : PacketBase 8 | { 9 | [BsonElement(NetStrings.SYNC_TIME_FIELD_KEY)] 10 | public long SyncTime { get; set; } 11 | 12 | [BsonElement(NetStrings.SYNC_TIME_SERVER_SLEEP_KEY)] 13 | public int ServerSleep { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/InstructionEventsCompleted.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum InstructionEventsCompleted 4 | { 5 | GotCrossBreedSeeds, 6 | SelectedFirstWrenchItem, 7 | VisitedMainMenuThrice, 8 | InventoryFullForFirstTime, 9 | FirstTimeInMainMenu, 10 | FishingRodEquipped, 11 | SelectedFirstLure, 12 | WonFirstFishingMinigame, 13 | SelectedFirstLock, 14 | ClaimedFirstWelcomeGift, 15 | InstructionEventVariables_Count 16 | } 17 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/VersionCheckRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Request; 6 | 7 | public class VersionCheckRequest : PacketBase 8 | { 9 | [BsonElement(NetStrings.OPERATING_SYSTEM_KEY)] 10 | public string OS { get; set; } = string.Empty; 11 | 12 | [BsonElement(NetStrings.OPERATING_SYSTEM_TYPE_KEY)] 13 | public int OsType { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/RenamePlayerResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Response; 6 | 7 | public class RenamePlayerResponse : PacketBase 8 | { 9 | [BsonElement(NetStrings.SUCCESS_KEY)] 10 | public bool IsSuccess { get; set; } 11 | 12 | [BsonElement(NetStrings.ERROR_KEY)] 13 | [BsonIgnoreIfDefault] 14 | public int ErrorState { get; set; } 15 | } 16 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/WorldJoinResult.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum WorldJoinResult : byte 4 | { 5 | Ok, 6 | TooManyPlayersInServer, 7 | TooManyPlayersInWorld, 8 | MaintenanceStarting, 9 | NotValidWorldName, 10 | UserIsBanned, 11 | AdminLockedWorld, 12 | UserHasWarning, 13 | WorldUnavailable, 14 | ServerTimeOut, 15 | IncorrectServerAddress, 16 | ServerException, 17 | CustomJoinFail, 18 | AlreadyHere, 19 | NotAllowed 20 | } 21 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/PixelWorldsServer.Protocol.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/ScifiDoorData.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | 5 | namespace PixelWorldsServer.Protocol.Worlds; 6 | 7 | public class ScifiDoorData : WorldItemBase 8 | { 9 | [BsonElement("isLocked")] 10 | public bool IsLocked { get; set; } 11 | 12 | public ScifiDoorData() : base(0, BlockType.ScifiDoor) 13 | { 14 | } 15 | 16 | public ScifiDoorData(int itemId) : base(itemId, BlockType.ScifiDoor) 17 | { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/PlayerStatusIconUpdateResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Constants; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Request; 6 | 7 | public class PlayerStatusIconUpdateResponse : PacketBase 8 | { 9 | [BsonElement(NetStrings.PLAYER_ID_KEY)] 10 | public string PlayerId { get; set; } = string.Empty; 11 | 12 | [BsonElement(NetStrings.STATUS_ICON_FIELD_KEY)] 13 | public StatusIconType StatusIcon { get; set; } 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/WearableOrWeaponChangeResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Constants; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Request; 6 | 7 | public class WearableOrWeaponChangeResponse : PacketBase 8 | { 9 | [BsonElement(NetStrings.HOTSPOT_BLOCK_TYPE_KEY)] 10 | public BlockType HotspotBlockType { get; set; } 11 | 12 | [BsonElement(NetStrings.PLAYER_ID_KEY)] 13 | public string PlayerId { get; set; } = string.Empty; 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/BattleBarrierLabData.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | 5 | namespace PixelWorldsServer.Protocol.Worlds; 6 | 7 | public class BattleBarrierLabData : WorldItemBase 8 | { 9 | [BsonElement("isOpen")] 10 | public bool IsOpen { get; set; } 11 | 12 | public BattleBarrierLabData() : base(0, BlockType.BattleBarrierLab) 13 | { 14 | } 15 | 16 | public BattleBarrierLabData(int itemId) : base(itemId, BlockType.BattleBarrierLab) 17 | { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/MenuWorldLoadInfoResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Response; 6 | 7 | public class MenuWorldLoadInfoResponse : PacketBase 8 | { 9 | [BsonElement(NetStrings.WORLD_NAME_KEY)] 10 | public string WorldName { get; set; } = string.Empty; 11 | 12 | [BsonElement(NetStrings.COUNT_KEY)] 13 | public int Count { get; set; } // if it is exist return the players count in that world, or else return negative 14 | } 15 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/LayerBlockBackground.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Constants; 3 | 4 | namespace PixelWorldsServer.Protocol.Worlds; 5 | 6 | public class LayerBlockBackground 7 | { 8 | public BlockType BlockType { get; set; } = BlockType.None; 9 | public int HitsRequired { get; set; } 10 | public int HitBuffer { get; set; } 11 | public int WaitingBlockIndex { get; set; } 12 | public bool IsWaitingForBlock { get; set; } 13 | 14 | [BsonIgnore] 15 | public DateTime LastHitTime { get; set; } = DateTime.Now; 16 | } 17 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/SetSeedRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Request; 7 | 8 | public class SetSeedRequest : PacketBase 9 | { 10 | [BsonElement(NetStrings.POSITION_X_KEY)] 11 | public int X { get; set; } 12 | 13 | [BsonElement(NetStrings.POSITION_Y_KEY)] 14 | public int Y { get; set; } 15 | 16 | [BsonElement(NetStrings.BLOCK_TYPE_KEY)] 17 | public BlockType BlockType { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/SetBlockRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Request; 7 | 8 | public class SetBlockRequest : PacketBase 9 | { 10 | [BsonElement(NetStrings.POSITION_X_KEY)] 11 | public int X { get; set; } 12 | 13 | [BsonElement(NetStrings.POSITION_Y_KEY)] 14 | public int Y { get; set; } 15 | 16 | [BsonElement(NetStrings.BLOCK_TYPE_KEY)] 17 | public BlockType BlockType { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/GetPlayerDataRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Request; 6 | 7 | public class GetPlayerDataRequest : PacketBase 8 | { 9 | [BsonElement(NetStrings.TOKEN_KEY)] 10 | public string Token { get; set; } = string.Empty; 11 | 12 | [BsonElement(NetStrings.COGNITO_ID_KEY)] 13 | public string CognitoId { get; set; } = string.Empty; 14 | 15 | [BsonElement("cgy")] // no idea what the fuck is this 16 | public int CGY { get; set; } 17 | } 18 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/LayerBlock.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Constants; 3 | 4 | namespace PixelWorldsServer.Protocol.Worlds; 5 | 6 | public class LayerBlock 7 | { 8 | public BlockType BlockType { get; set; } = BlockType.None; 9 | public int HitsRequired { get; set; } 10 | public int HitBuffer { get; set; } 11 | public int WaitingBlockIndex { get; set; } 12 | public bool IsWaitingForBlock { get; set; } 13 | public bool IsWaitingForBlockTree { get; set; } 14 | 15 | [BsonIgnore] 16 | public DateTime LastHitTime { get; set; } = DateTime.Now; 17 | } 18 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/CharacterCreatedRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Request; 7 | 8 | public class CharacterCreatedRequest : PacketBase 9 | { 10 | [BsonElement(NetStrings.GENDER_KEY)] 11 | public Gender Gender { get; set; } 12 | 13 | [BsonElement(NetStrings.COUNTRY_KEY)] 14 | public int CountryCode { get; set; } 15 | 16 | [BsonElement(NetStrings.SKIN_COLOR_INDEX_KEY)] 17 | public int SkinColorIndex { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/TryToJoinWorldRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Request; 7 | 8 | public class TryToJoinWorldRequest : PacketBase 9 | { 10 | [BsonElement(NetStrings.WORLD_KEY)] 11 | public string World { get; set; } = string.Empty; 12 | 13 | [BsonElement(NetStrings.AMOUNT_KEY)] 14 | public int ServerConnectAttempts { get; set; } 15 | 16 | [BsonElement(NetStrings.WORLD_BIOME_KEY)] 17 | public BasicWorldBiome Biome { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/GetWorldRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Request; 7 | 8 | public class GetWorldRequest : PacketBase 9 | { 10 | [BsonElement(NetStrings.ENTRANCE_PORTAL_ID_KEY)] 11 | public string EntrancePortalId { get; set; } = string.Empty; 12 | 13 | [BsonElement(NetStrings.WORLD_KEY)] 14 | public string World { get; set; } = string.Empty; 15 | 16 | [BsonElement(NetStrings.WORLD_BIOME_KEY)] 17 | public BasicWorldBiome Biome { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Players/InventoryItemBase.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | 5 | namespace PixelWorldsServer.Protocol.Players; 6 | 7 | public abstract class InventoryItemBase 8 | { 9 | [BsonElement("inventoryClass")] 10 | public string InventoryClass { get; set; } = string.Empty; 11 | 12 | [BsonElement("blockType")] 13 | public BlockType BlockType { get; set; } 14 | 15 | public BsonDocument Serialize() 16 | { 17 | var document = this.ToBsonDocument(); 18 | document.Add("class", GetType().Name); 19 | return document; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/TryToJoinWorldResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Response; 7 | 8 | public class TryToJoinWorldResponse : PacketBase 9 | { 10 | [BsonElement(NetStrings.WORLD_NAME_KEY)] 11 | public string WorldName { get; set; } = string.Empty; 12 | 13 | [BsonElement(NetStrings.JOIN_RESULT_KEY)] 14 | public WorldJoinResult JoinResult { get; set; } 15 | 16 | [BsonElement(NetStrings.WORLD_BIOME_KEY)] 17 | public BasicWorldBiome Biome { get; set; } 18 | } 19 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/LayerWiring.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Constants; 3 | 4 | namespace PixelWorldsServer.Protocol.Worlds; 5 | 6 | // literally the same as LayerBlockBackground but i dont have any idea why pw separates them 7 | public class LayerWiring 8 | { 9 | public BlockType BlockType { get; set; } = BlockType.None; 10 | public int HitsRequired { get; set; } 11 | public int HitBuffer { get; set; } 12 | public int WaitingBlockIndex { get; set; } 13 | public bool IsWaitingForBlock { get; set; } 14 | 15 | [BsonIgnore] 16 | public DateTime LastHitTime { get; set; } = DateTime.Now; 17 | } 18 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/HitBlockResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Constants; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Response; 6 | 7 | public class HitBlockResponse : PacketBase 8 | { 9 | [BsonElement(NetStrings.POSITION_X_KEY)] 10 | public int X { get; set; } 11 | 12 | [BsonElement(NetStrings.POSITION_Y_KEY)] 13 | public int Y { get; set; } 14 | 15 | [BsonElement(NetStrings.TOP_ARM_BLOCK_TYPE_KEY)] 16 | public BlockType TopArmBlockType { get; set; } 17 | 18 | [BsonElement(NetStrings.PLAYER_ID_KEY)] 19 | public string PlayerId { get; set; } = string.Empty; 20 | } 21 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/SetBlockResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Response; 7 | 8 | public class SetBlockResponse : PacketBase 9 | { 10 | [BsonElement(NetStrings.POSITION_X_KEY)] 11 | public int X { get; set; } 12 | 13 | [BsonElement(NetStrings.POSITION_Y_KEY)] 14 | public int Y { get; set; } 15 | 16 | [BsonElement(NetStrings.BLOCK_TYPE_KEY)] 17 | public BlockType BlockType { get; set; } 18 | 19 | [BsonElement(NetStrings.PLAYER_ID_KEY)] 20 | public string PlayerId { get; set; } = string.Empty; 21 | } 22 | -------------------------------------------------------------------------------- /PixelWorldsServer.DataAccess/PixelWorldsServer.DataAccess.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/DestroyBlockResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Response; 7 | 8 | public class DestroyBlockResponse : PacketBase 9 | { 10 | [BsonElement(NetStrings.POSITION_X_KEY)] 11 | public int X { get; set; } 12 | 13 | [BsonElement(NetStrings.POSITION_Y_KEY)] 14 | public int Y { get; set; } 15 | 16 | [BsonElement(NetStrings.DESTROYED_BLOCK_TYPE_KEY)] 17 | [BsonIgnoreIfDefault] 18 | public BlockType BlockDestroyedBlockType { get; set; } 19 | 20 | [BsonElement(NetStrings.PLAYER_ID_KEY)] 21 | public string PlayerId { get; set; } = string.Empty; 22 | } 23 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/AnimationHotSpots.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum AnimationHotSpots 4 | { 5 | None, 6 | Face, 7 | Eyebrows, 8 | Eyeballs, 9 | PupilLeft, 10 | Mouth, 11 | Torso, 12 | TopArm, 13 | BottomArm, 14 | Legs, 15 | Hat, 16 | Hair, 17 | Glasses, 18 | ContactLensLeft, 19 | TopEarRing, 20 | Magic, 21 | Beard, 22 | Mask, 23 | Pants, 24 | Shoes, 25 | Neck, 26 | Shirt, 27 | TopArmSleeve, 28 | TopArmGlove, 29 | TopArmItem, 30 | BottomArmSleeve, 31 | BottomArmGlove, 32 | BottomArmItem, 33 | Back, 34 | PupilRight, 35 | ContactLensRight, 36 | Eyelashes, 37 | Tights, 38 | Tail, 39 | Mount, 40 | END_OF_THE_ENUM 41 | } 42 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/MyPosResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Constants; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Response; 6 | 7 | public class MyPosResponse : PacketBase 8 | { 9 | [BsonElement(NetStrings.POSITION_X_KEY)] 10 | public float X { get; set; } 11 | 12 | [BsonElement(NetStrings.POSITION_Y_KEY)] 13 | public float Y { get; set; } 14 | 15 | [BsonElement(NetStrings.ANIMATION_KEY)] 16 | public AnimationNames Animation { get; set; } 17 | 18 | [BsonElement(NetStrings.DIRECTION_KEY)] 19 | public Direction Direction { get; set; } 20 | 21 | [BsonElement(NetStrings.TELEPORT_KEY)] 22 | public bool Teleport { get; set; } 23 | 24 | [BsonElement(NetStrings.PLAYER_ID_KEY)] 25 | public string PlayerId { get; set; } = string.Empty; 26 | } 27 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Request/MyPosRequest.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Request; 7 | 8 | public class MyPosRequest : PacketBase 9 | { 10 | [BsonElement(NetStrings.TIMESTAMP_KEY)] 11 | public long Timestamp { get; set; } 12 | 13 | [BsonElement(NetStrings.POSITION_X_KEY)] 14 | public float X { get; set; } 15 | 16 | [BsonElement(NetStrings.POSITION_Y_KEY)] 17 | public float Y { get; set; } 18 | 19 | [BsonElement(NetStrings.ANIMATION_KEY)] 20 | public AnimationNames Animation { get; set; } 21 | 22 | [BsonElement(NetStrings.DIRECTION_KEY)] 23 | public Direction Direction { get; set; } 24 | 25 | [BsonElement(NetStrings.TELEPORT_KEY)] 26 | public bool Teleport { get; set; } 27 | } 28 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/BuyItemPackResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Utils; 3 | 4 | namespace PixelWorldsServer.Protocol.Packet.Response; 5 | 6 | public class BuyItemPackResponse : PacketBase 7 | { 8 | [BsonElement(NetStrings.ITEM_PACK_ID_KEY)] 9 | public string ItemPackId { get; set; } = string.Empty; 10 | 11 | [BsonElement(NetStrings.ITEM_PACK_ROLLS_KEY)] 12 | public int[] ItemPackRolls { get; set; } = Array.Empty(); 13 | 14 | [BsonElement(NetStrings.ITEM_PACK_ROLLS2_KEY)] 15 | public int[] ItemPackRolls2 { get; set; } = Array.Empty(); 16 | 17 | [BsonElement(NetStrings.SUCCESS_KEY)] 18 | [BsonIgnoreIfNull] 19 | public string Success { get; set; } = null!; 20 | 21 | [BsonElement(NetStrings.ERROR_KEY)] 22 | [BsonIgnoreIfNull] 23 | public string ErrorReason { get; set; } = null!; 24 | } 25 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/WorldLayoutType.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum WorldLayoutType 4 | { 5 | Basic, 6 | BasicWithBots, 7 | PerformanceTestFull, 8 | PerformanceTestFullWithoutBots, 9 | PerformanceTestFullWithoutCollectables, 10 | PerformanceTestFullWithoutBotsAndCollectables, 11 | EmptyWhenIniting, 12 | PerformanceTestMedium, 13 | BasicWithCollectables, 14 | PerformanceTestFullWithoutBotsAndCollectablesAndTrees, 15 | PerformanceTestFullWithoutTrees, 16 | PerformanceTestMediumWithoutBots, 17 | PerformanceTestMediumWithoutCollectables, 18 | PerformanceTestMediumWithoutBotsAndCollectables, 19 | PerformanceTestMediumWithoutBotsAndCollectablesAndTrees, 20 | PerformanceTestMediumWithoutTrees, 21 | HalloweenTower, 22 | NetherWorld, 23 | DeepNether, 24 | SecretBaseLaboratory, 25 | HomeWorld, 26 | GeneratedMine, 27 | JetRace 28 | } 29 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/TutorialSleepPodData.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | 5 | namespace PixelWorldsServer.Protocol.Worlds; 6 | 7 | public class TutorialSleepPodData : WorldItemBase 8 | { 9 | [BsonElement("targetWorldID")] 10 | public string TargetWorldId { get; set; } = string.Empty; 11 | 12 | [BsonElement("targetEntryPointID")] 13 | public string TargetEntryPointId { get; set; } = string.Empty; 14 | 15 | [BsonElement("name")] 16 | public string Name { get; set; } = string.Empty; 17 | 18 | [BsonElement("entryPointID")] 19 | public string EntryPointId { get; set; } = string.Empty; 20 | 21 | [BsonElement("isLocked")] 22 | public bool IsLocked { get; set; } 23 | 24 | 25 | public TutorialSleepPodData() : base(0, BlockType.TutorialSleepPod) 26 | { 27 | } 28 | 29 | public TutorialSleepPodData(int itemId) : base(itemId, BlockType.TutorialSleepPod) 30 | { 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/TutorialCablePortalData.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | 5 | namespace PixelWorldsServer.Protocol.Worlds; 6 | 7 | public class TutorialCablePortalData : WorldItemBase 8 | { 9 | [BsonElement("targetWorldID")] 10 | public string TargetWorldId { get; set; } = string.Empty; 11 | 12 | [BsonElement("targetEntryPointID")] 13 | public string TargetEntryPointId { get; set; } = string.Empty; 14 | 15 | [BsonElement("name")] 16 | public string Name { get; set; } = string.Empty; 17 | 18 | [BsonElement("entryPointID")] 19 | public string EntryPointId { get; set; } = string.Empty; 20 | 21 | [BsonElement("isLocked")] 22 | public bool IsLocked { get; set; } 23 | 24 | 25 | public TutorialCablePortalData() : base(0, BlockType.TutorialCablePortal) 26 | { 27 | } 28 | 29 | public TutorialCablePortalData(int itemId) : base(itemId, BlockType.TutorialCablePortal) 30 | { 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/PortalData.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | 5 | namespace PixelWorldsServer.Protocol.Worlds; 6 | 7 | public class PortalData : WorldItemBase 8 | { 9 | [BsonElement("targetWorldID")] 10 | public string TargetWorldId { get; set; } = string.Empty; 11 | 12 | [BsonElement("targetEntryPointID")] 13 | public string TargetEntryPointId { get; set; } = string.Empty; 14 | 15 | [BsonElement("name")] 16 | public string Name { get; set; } = string.Empty; 17 | 18 | [BsonElement("entryPointID")] 19 | public string EntryPointId { get; set; } = string.Empty; 20 | 21 | [BsonElement("isLocked")] 22 | public bool IsLocked { get; set; } 23 | 24 | [BsonElement("password")] 25 | public string Password { get; set; } = string.Empty; 26 | 27 | public PortalData() : base(0, BlockType.Portal) 28 | { 29 | } 30 | 31 | public PortalData(int itemId) : base(itemId, BlockType.Portal) 32 | { 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/StatisticsKey.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum StatisticsKey 4 | { 5 | Blocks_Destroyed, 6 | Gems_Collected, 7 | Blocks_Placed, 8 | Items_Trashed, 9 | Trees_Harvested, 10 | Gems_Spent_In_Shop, 11 | ItemsCrafted, 12 | ShardsConverted, 13 | WorldsRated, 14 | QuestsCompleted, 15 | FAMFoodsCrafted, 16 | FamiliarsEvolved, 17 | BattleKills, 18 | BattleDeaths, 19 | FossilsAssembled, 20 | NetherWorldsFinished, 21 | AIEnemiesKilled, 22 | UniqueItemsCrossBred, 23 | DecayedSmallLocksDestroyed, 24 | DecayedWorldLocksDestroyed, 25 | ButterfliesCollected, 26 | GraffitiAssembled, 27 | LabSpeedrunsFinished, 28 | BestLabSpeedrunTime, 29 | PotionsCreated, 30 | FishCaught, 31 | PWEBuyByteCoins, 32 | PWESellByteCoins, 33 | BattleFactionKills, 34 | PWEFulfilledOrders, 35 | PetLevelReached, 36 | PetMinutesOnAdventure, 37 | MinesFinished, 38 | JetRacesFinished, 39 | CardsCollected, 40 | LAST_VALUE 41 | } 42 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Utils/BlockTuple.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Utils; 4 | 5 | public class BlockTuple 6 | { 7 | public BlockType First; 8 | 9 | public BlockType Second; 10 | 11 | public BlockTuple(BlockType newFirst, BlockType newSecond) 12 | { 13 | if (newFirst > newSecond) 14 | { 15 | First = newFirst; 16 | Second = newSecond; 17 | } 18 | else 19 | { 20 | First = newSecond; 21 | Second = newFirst; 22 | } 23 | } 24 | 25 | public override bool Equals(object? obj) 26 | { 27 | if (obj is null) 28 | { 29 | return false; 30 | } 31 | 32 | if (obj is not BlockTuple blockTuple) 33 | { 34 | return false; 35 | } 36 | 37 | return First == blockTuple.First && Second == blockTuple.Second; 38 | } 39 | 40 | public override int GetHashCode() 41 | { 42 | return (int)First << (int)(16 + Second); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Utils/ShuffleBag.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Utils; 2 | 3 | public class ShuffleBag 4 | { 5 | private int m_Cursor = -1; 6 | private readonly List m_Data = new(100); 7 | private readonly Random m_Random = new(); 8 | 9 | public void Add(T item, int count) 10 | { 11 | while (count-- > 0) 12 | { 13 | m_Data.Add(item); 14 | } 15 | m_Cursor = m_Data.Count - 1; 16 | } 17 | 18 | public T? Next() 19 | { 20 | if (m_Data.Count == 0) 21 | { 22 | return default; 23 | } 24 | 25 | if (m_Cursor < 1) 26 | { 27 | m_Cursor = m_Data.Count - 1; 28 | return m_Data[0]; 29 | } 30 | 31 | int index = m_Random.Next(0, m_Cursor + 1); 32 | 33 | T value = m_Data[index]; 34 | m_Data[index] = m_Data[m_Cursor]; 35 | m_Data[m_Cursor] = value; 36 | m_Cursor--; 37 | 38 | return value; 39 | } 40 | 41 | public void Clear() 42 | { 43 | m_Data.Clear(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/WorldChatMessageResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Utils; 3 | 4 | namespace PixelWorldsServer.Protocol.Packet.Response; 5 | 6 | public class ChatMessageBinary 7 | { 8 | [BsonElement(NetStrings.NICK_KEY)] 9 | public string Nick { get; set; } = string.Empty; 10 | 11 | [BsonElement(NetStrings.USER_ID_KEY)] 12 | public string UserId { get; set; } = string.Empty; 13 | 14 | [BsonElement(NetStrings.CHANNEL_KEY)] 15 | public string Channel { get; set; } = string.Empty; 16 | 17 | [BsonElement(NetStrings.CHANNEL_INDEX_KEY)] 18 | public int ChannelIndex { get; set; } 19 | 20 | [BsonElement(NetStrings.MESSAGE_CHAT_KEY)] 21 | public string MessageChat { get; set; } = string.Empty; 22 | 23 | [BsonElement(NetStrings.CHAT_TIME_KEY)] 24 | public DateTime Time { get; set; } 25 | } 26 | 27 | public class WorldChatMessageResponse : PacketBase 28 | { 29 | [BsonElement(NetStrings.CHAT_MESSAGE_BINARY)] 30 | public ChatMessageBinary MessageBinary { get; set; } = null!; 31 | } 32 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/Achievement.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum Achievement 4 | { 5 | Total, 6 | Smasher, 7 | Hoarder, 8 | MyWorld, 9 | GemFarmer, 10 | WellConnected, 11 | Fashionista, 12 | TrustedFriend, 13 | Instagram, 14 | Youtube, 15 | Secret1, 16 | ConvertShards, 17 | CraftItems, 18 | Critic, 19 | ShoppingSpree, 20 | Conqueror, 21 | QuestsKing, 22 | SteamLogin, 23 | FAMCook, 24 | FAMEvolver, 25 | Secret2, 26 | Archaeologist, 27 | Harvester, 28 | Trasher, 29 | Veteran, 30 | Nether, 31 | Slayer, 32 | Untouchable, 33 | Crossbreeder, 34 | Butterflies, 35 | Pacifist, 36 | StreetArtist, 37 | LabSpeedRun, 38 | LabSoloRun, 39 | Alchemist, 40 | Fisherman, 41 | Rodder, 42 | CatchAFish, 43 | PWEBuy, 44 | PWESell, 45 | PWEOrders, 46 | WraithBoss, 47 | GoodBoy, 48 | WanderingCompanion, 49 | MineExit, 50 | PickaxeUpgrade, 51 | JetRaceFinish, 52 | GottaGetEmAll, 53 | Achievement_Count 54 | } 55 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Utils/Math.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | 3 | namespace PixelWorldsServer.Protocol.Utils; 4 | 5 | public class Vector2 6 | { 7 | [BsonElement("x")] 8 | public float X { get; set; } 9 | 10 | [BsonElement("y")] 11 | public float Y { get; set; } 12 | 13 | public Vector2() 14 | { 15 | X = 0; 16 | Y = 0; 17 | } 18 | 19 | public Vector2(float mx, float my) 20 | { 21 | X = mx; 22 | Y = my; 23 | } 24 | 25 | public Vector2(int mx, int my) 26 | { 27 | X = mx; 28 | Y = my; 29 | } 30 | } 31 | 32 | public class Vector2i 33 | { 34 | [BsonElement("x")] 35 | public int X { get; set; } 36 | 37 | [BsonElement("y")] 38 | public int Y { get; set; } 39 | 40 | public Vector2i() 41 | { 42 | X = 0; 43 | Y = 0; 44 | } 45 | 46 | public Vector2i(float mx, float my) 47 | { 48 | X = (int)mx; 49 | Y = (int)my; 50 | } 51 | 52 | public Vector2i(int mx, int my) 53 | { 54 | X = mx; 55 | Y = my; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/CollectResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Response; 7 | 8 | public class CollectResponse : PacketBase 9 | { 10 | [BsonElement(NetStrings.COLLECTABLE_ID_KEY)] 11 | public int CollectableId { get; set; } 12 | 13 | [BsonElement(NetStrings.BLOCK_TYPE_KEY)] 14 | public BlockType BlockType { get; set; } 15 | 16 | [BsonElement(NetStrings.COLLECT_AMOUNT_KEY)] 17 | public int Amount { get; set; } 18 | 19 | [BsonElement(NetStrings.INVENTORY_TYPE_KEY)] 20 | public InventoryItemType InventoryType { get; set; } 21 | 22 | [BsonElement(NetStrings.POSITION_X_FLOAT_KEY)] 23 | public float PositionX { get; set; } 24 | 25 | [BsonElement(NetStrings.POSITION_Y_FLOAT_KEY)] 26 | public float PositionY { get; set; } 27 | 28 | [BsonElement(NetStrings.IS_GEM_KEY)] 29 | public bool IsGem { get; set; } 30 | 31 | [BsonElement(NetStrings.GEM_TYPE_KEY)] 32 | public GemType GemType { get; set; } 33 | } 34 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Utils/LZMATools.cs: -------------------------------------------------------------------------------- 1 | using SevenZip.Compression.LZMA; 2 | 3 | namespace PixelWorldsServer.Protocol; 4 | 5 | public static class LZMATools 6 | { 7 | public static byte[] Compress(byte[] data) 8 | { 9 | using var stream = new MemoryStream(data); 10 | return Compress(stream); 11 | } 12 | 13 | public static byte[] Compress(Stream stream) 14 | { 15 | using var ms = new MemoryStream(); 16 | using var bw = new BinaryWriter(ms); 17 | 18 | var ec = new Encoder(); 19 | ec.WriteCoderProperties(ms); 20 | bw.Write(stream.Length); 21 | ec.Code(stream, ms, stream.Length, -1, null); 22 | bw.Flush(); 23 | 24 | return ms.ToArray(); 25 | } 26 | 27 | public static byte[] Decompress(Stream stream) 28 | { 29 | using var br = new BinaryReader(stream); 30 | using var ms = new MemoryStream(); 31 | 32 | var properties = br.ReadBytes(5); 33 | var outSize = br.ReadInt64(); 34 | 35 | var dc = new Decoder(); 36 | dc.SetDecoderProperties(properties); 37 | dc.Code(stream, ms, stream.Length, outSize, null); 38 | ms.Flush(); 39 | 40 | return ms.ToArray(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/Players/PlayerManager.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.DataAccess; 2 | using PixelWorldsServer.DataAccess.Models; 3 | using System.Collections.Concurrent; 4 | using System.Net; 5 | 6 | namespace PixelWorldsServer.Server.Players; 7 | 8 | public class PlayerManager 9 | { 10 | private readonly Database m_Database; 11 | private readonly ConcurrentDictionary m_Players = new(); 12 | 13 | public PlayerManager(Database database) 14 | { 15 | m_Database = database; 16 | } 17 | 18 | public Player AddOrReplacePlayer(IPEndPoint iPEndPoint) 19 | { 20 | var player = new Player(iPEndPoint.Address); 21 | return m_Players.AddOrUpdate(iPEndPoint, player, (x, y) => 22 | { 23 | y.Disconnect(); 24 | return player; 25 | }); 26 | } 27 | 28 | public bool RemovePlayer(IPEndPoint iPEndPoint) 29 | { 30 | return m_Players.TryRemove(iPEndPoint, out _); 31 | } 32 | 33 | public async Task SaveAllPlayersAsync() 34 | { 35 | var tasks = new List(); 36 | 37 | foreach (var (_, player) in m_Players) 38 | { 39 | tasks.Add(m_Database.SavePlayerAsync(PlayerModel.CreateCopy(player))); 40 | } 41 | 42 | await Task.WhenAll(tasks).ConfigureAwait(false); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/WorldItemBase.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | 5 | namespace PixelWorldsServer.Protocol.Worlds; 6 | 7 | public abstract class WorldItemBase 8 | { 9 | [BsonElement("itemId")] 10 | public int ItemId { get; set; } 11 | 12 | [BsonElement("blockType")] 13 | public BlockType BlockType { get; set; } 14 | 15 | [BsonElement("direction")] 16 | public BlockDirection BlockDirection { get; set; } 17 | 18 | [BsonElement("animOn")] 19 | public bool IsAnimationOn { get; set; } 20 | 21 | [BsonElement("anotherSprite")] 22 | public bool UseAnotherSprite { get; set; } 23 | 24 | [BsonElement("damageNow")] 25 | public bool DoDamageNow { get; set; } 26 | 27 | public WorldItemBase() 28 | { 29 | } 30 | 31 | public WorldItemBase(int itemId, BlockType blockType) 32 | { 33 | ItemId = itemId; 34 | BlockType = blockType; 35 | } 36 | 37 | public static BlockType GetBlockTypeViaClassName(string className) 38 | { 39 | return Enum.Parse(className.Remove(className.Length - 4), true); 40 | } 41 | 42 | public BsonDocument Serialize() 43 | { 44 | var document = this.ToBsonDocument(); 45 | document.Add("class", GetType().Name); 46 | return document; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/log4net.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/GetPlayerDataResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Response; 6 | 7 | public class GetPlayerDataResponse : PacketBase 8 | { 9 | [BsonElement(NetStrings.PLAYER_ID_KEY)] 10 | public string PlayerId { get; set; } = string.Empty; 11 | 12 | [BsonElement(NetStrings.PLAYER_USERNAME_KEY)] 13 | public string PlayerUsername { get; set; } = string.Empty; 14 | 15 | [BsonElement(NetStrings.REAL_USERNAME_KEY)] 16 | public string RealUsername { get; set; } = string.Empty; 17 | 18 | [BsonElement(NetStrings.PLAYER_DATA_KEY)] 19 | public byte[] PlayerData { get; set; } = null!; 20 | 21 | [BsonElement(NetStrings.EMAIL_KEY)] 22 | public string Email { get; set; } = string.Empty; 23 | 24 | [BsonElement(NetStrings.EMAIL_VERIFIED_KEY)] 25 | public bool EmailVerified { get; set; } 26 | 27 | [BsonElement(NetStrings.WORLD_NAME_KEY)] 28 | public string[] WorldNames { get; set; } = null!; 29 | 30 | [BsonElement(NetStrings.BAN_PLAYER_KEY)] 31 | public int BanState { get; set; } 32 | 33 | [BsonElement(NetStrings.NEWS_VERSION_KEY)] 34 | public int NewsVersion { get; set; } 35 | 36 | [BsonElement(NetStrings.WOTW_VERSION_KEY)] 37 | public int WOTWVersion { get; set; } 38 | 39 | [BsonElement(NetStrings.WOTW_KEY)] 40 | public string WOTW { get; set; } = string.Empty; 41 | } 42 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Utils/PositionConversions.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Utils; 2 | 3 | public static class PositionConversions 4 | { 5 | public static Vector2 ConvertPlayerMapPointToWorldPoint(int x, int y) 6 | { 7 | return new(x * ConfigData.TileSizeX, y * ConfigData.TileSizeY - ConfigData.TileSizeY * 0.5f); 8 | } 9 | public static Vector2i ConvertWorldPointToMapPoint(float x, float y) 10 | { 11 | return new Vector2i((int)((x + ConfigData.TileSizeX * 0.5f) / ConfigData.TileSizeX), (int)((y + ConfigData.TileSizeY * 0.5f) / ConfigData.TileSizeY)); 12 | } 13 | 14 | public static void ConvertWorldPointToMapPoint(float x, float y, Vector2i mapPoint) 15 | { 16 | mapPoint.X = (int)((x + ConfigData.TileSizeX * 0.5f) / ConfigData.TileSizeX); 17 | mapPoint.Y = (int)((y + ConfigData.TileSizeY * 0.5f) / ConfigData.TileSizeY); 18 | } 19 | 20 | public static Vector2i ConvertPlayersWorldPointToMapPoint(float x, float y) 21 | { 22 | y += ConfigData.TileSizeY * 0.5f; 23 | return ConvertWorldPointToMapPoint(x, y); 24 | } 25 | 26 | public static Vector2i ConvertPlayersWorldPointToMapPointFromFeet(float x, float y) 27 | { 28 | y += ConfigData.TileSizeY * 0.01f; 29 | return ConvertWorldPointToMapPoint(x, y); 30 | } 31 | 32 | public static Vector2i ConvertCollectablePosToMapPoint(float x, float y) 33 | { 34 | return ConvertWorldPointToMapPoint(x * ConfigData.TileSizeX, y * ConfigData.TileSizeY); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/SetSeedResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Response; 7 | 8 | public class SetSeedResponse : PacketBase 9 | { 10 | [BsonElement(NetStrings.POSITION_X_KEY)] 11 | public int X { get; set; } 12 | 13 | [BsonElement(NetStrings.POSITION_Y_KEY)] 14 | public int Y { get; set; } 15 | 16 | [BsonElement(NetStrings.PLAYER_ID_KEY)] 17 | public string PlayerId { get; set; } = string.Empty; 18 | 19 | [BsonElement(NetStrings.BLOCK_TYPE_KEY)] 20 | public BlockType BlockType { get; set; } 21 | 22 | [BsonElement(NetStrings.GROWTH_DURATION_KEY)] 23 | public int GrowthDurationInSeconds { get; set; } 24 | 25 | [BsonElement(NetStrings.GROWTH_END_TIME_KEY)] 26 | public long GrowthEndTime { get; set; } 27 | 28 | [BsonElement(NetStrings.IS_MIXED_KEY)] 29 | public bool IsMixed { get; set; } 30 | 31 | [BsonElement(NetStrings.HARVEST_SEEDS_KEY)] 32 | public int HarvestSeeds { get; set; } 33 | 34 | [BsonElement(NetStrings.HARVEST_BLOCKS_KEY)] 35 | public int HarvestBlocks { get; set; } 36 | 37 | [BsonElement(NetStrings.HARVEST_GEMS_KEY)] 38 | public int HarvestGems { get; set; } 39 | 40 | [BsonElement(NetStrings.HARVEST_EXTRA_BLOCKS_KEY)] 41 | public int HarvestExtraBlocks { get; set; } 42 | 43 | [BsonElement(NetStrings.SET_FERTILIZER_KEY)] 44 | public bool SetFertilizer { get; set; } 45 | } 46 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/CollectableData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | using PixelWorldsServer.Protocol.Players; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Worlds; 6 | 7 | public class CollectableData 8 | { 9 | public int Id { get; set; } 10 | 11 | public BlockType BlockType { get; set; } 12 | public InventoryItemType InventoryItemType { get; set; } 13 | 14 | public InventoryItemBase InventoryData { get; set; } = null!; 15 | public Vector2 Pos { get; set; } = new(); 16 | public Vector2i MapPoint { get; set; } = new(); 17 | 18 | public short Amount { get; set; } 19 | public bool IsGem { get; set; } 20 | public GemType GemType { get; set; } 21 | 22 | public CollectableData(int id, BlockType newType, short amount, InventoryItemType inventoryItemType, float posX, float posY, InventoryItemBase inventoryData) 23 | { 24 | Id = id; 25 | Pos.X = posX; 26 | IsGem = false; 27 | Pos.Y = posY; 28 | Amount = amount; 29 | MapPoint = PositionConversions.ConvertCollectablePosToMapPoint(Pos.X, Pos.Y); 30 | BlockType = newType; 31 | InventoryData = inventoryData; 32 | InventoryItemType = inventoryItemType; 33 | } 34 | 35 | public CollectableData(BlockType newType, short amount, InventoryItemType inventoryItemType, InventoryItemBase inventoryData) 36 | : this(0, newType, amount, inventoryItemType, 0f, 0f, inventoryData) 37 | { 38 | } 39 | 40 | public CollectableData(int id, short amount, float posX, float posY, GemType gemType) 41 | : this(id, BlockType.None, amount, InventoryItemType.Block, posX, posY, null!) 42 | { 43 | IsGem = true; 44 | GemType = gemType; 45 | } 46 | 47 | public CollectableData() 48 | { 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Utils/Seeds.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | using PixelWorldsServer.Protocol.Worlds; 3 | 4 | namespace PixelWorldsServer.Protocol.Utils; 5 | 6 | public static class Seeds 7 | { 8 | private static BlockType m_TempHolder; 9 | private static readonly Dictionary m_CrossBreedings = new(); 10 | 11 | public static void Clear() 12 | { 13 | m_CrossBreedings.Clear(); 14 | } 15 | 16 | public static void SetFirstCrossBreedingPart(string firstPart, int _) 17 | { 18 | m_TempHolder = (BlockType)int.Parse(firstPart); 19 | } 20 | 21 | public static void AddCrossBreeding(string secondPart, int index) 22 | { 23 | var newSecond = (BlockType)int.Parse(secondPart); 24 | var blockTuple = new BlockTuple(m_TempHolder, newSecond); 25 | m_CrossBreedings[blockTuple] = (BlockType)index; 26 | } 27 | 28 | public static BlockType GetCrossBreedingResult(BlockTuple query) 29 | { 30 | if (m_CrossBreedings.ContainsKey(query)) 31 | { 32 | return m_CrossBreedings[query]; 33 | } 34 | return BlockType.None; 35 | } 36 | 37 | public static SeedData GenerateSeedData(BlockType typeOfSeed, Vector2i pos, bool isMixed = false) 38 | { 39 | int blockComplexity = ConfigData.BlockComplexity[(int)typeOfSeed]; 40 | int growthDurationSeconds = SeedData.CalculateGrowthTimeInSeconds(blockComplexity); 41 | int growthTimeInSeconds = ConfigData.GrowthTimeInSeconds[(int)typeOfSeed]; 42 | if (growthTimeInSeconds != ConfigData.DefaultGrowthTimeInSeconds) 43 | { 44 | growthDurationSeconds = growthTimeInSeconds; 45 | } 46 | 47 | return new SeedData(typeOfSeed, pos, growthDurationSeconds, isMixed); 48 | } 49 | 50 | public static BlockTuple? GetBlockTuple(BlockType blockType) 51 | { 52 | foreach (var (key, value) in m_CrossBreedings) 53 | { 54 | if (value == blockType) 55 | { 56 | return key; 57 | } 58 | } 59 | 60 | return null; 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pixel Worlds Server 2 | The first ever open-sourced Pixel Worlds Server, made in C# 6.0, provides the basic features of the game in well-structured, organized, reliable, and fast code. 3 | 4 | ## Dependencies 5 | The server uses [MongoDB](https://www.mongodb.com/) as its database, dependency injection code design, [log4net](https://logging.apache.org/log4net/) as its logging, and [7zip](https://github.com/adoconnection/SevenZipExtractor) for [lzma](https://7-zip.org/sdk.html) compression. 6 | 7 | ## Building The Project (Docker) 8 | ```console 9 | $ git clone https://github.com/zKevz/Pixel-Worlds-Server 10 | $ docker build -t pixel-worlds-server -f Dockerfile . 11 | $ docker run pixel-worlds-server 12 | ``` 13 | 14 | ## Building The Project (Manual) 15 | 1. Make sure to have [.NET 6.0](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) and [MongoDB](https://www.mongodb.com/docs/manual/installation/) installed 16 | 2. Compile the project 17 | 3. If you are compiling from the command line, you need to copy the `PixelWorldsServerPixelWorldsServer.Server\Data` directory into the executable directory. If you are using an IDE such as Visual Studio, those files will be automatically copied to the executable directory, so you don't need to do it manually. 18 | 19 | ## Game Features 20 | - Basic account with name aswell 21 | - Tutorial 22 | - Worlds 23 | - Putting blocks/backgrounds 24 | - Breaking blocks/backgrounds 25 | - Multiplayer 26 | - Collectables 27 | - Randomized collectables that is 1:1 in the real server 28 | - Seeds 29 | - Splicing seeds 30 | - World chat message 31 | - Equip / unequip clothes 32 | 33 | ## Contributors 34 | [I](https://github.com/zKevz) am the only one who contributes to this project currently. If you want to contribute, feel free to make pull request or issues. Any help is appreciated. 35 | 36 | ## Notable People 37 | These people below are the ones who are helping me discover things. Shoutout: 38 | - [Dark](https://github.com/NotDark) 39 | - [iProgramInCpp](https://github.com/iProgramMC) 40 | 41 | ## License 42 | The server uses [GPL3](https://www.gnu.org/licenses/gpl-3.0.html) as its license. 43 | 44 | ## Help 45 | If you encounter an issue and is seeking for help, please join this discord server with the link below: 46 | https://discord.gg/J4qbskMfM3 47 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/SeedData.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | using PixelWorldsServer.Protocol.Utils; 3 | 4 | namespace PixelWorldsServer.Protocol.Worlds; 5 | 6 | public class SeedData 7 | { 8 | private static readonly int m_GrowthTimeInSecondsForZeroOrLessComplexity = 8640000; 9 | private static readonly int m_MinGrowthTimeInSeconds = 30; 10 | private static readonly int m_MaxGrowthTimeInSeconds = 31536000; 11 | 12 | public BlockType BlockType { get; set; } 13 | public DateTime GrowthEndTime { get; set; } 14 | public int GrowthDurationInSeconds { get; set; } 15 | public bool IsAlreadyCrossBred { get; set; } 16 | public Vector2i Position { get; set; } = new(); 17 | public short HarvestSeeds { get; set; } 18 | public short HarvestBlocks { get; set; } 19 | public short HarvestGems { get; set; } 20 | public short HarvestExtraBlocks { get; set; } 21 | 22 | public SeedData(BlockType blockType, Vector2i position, int growthDurationSeconds, bool isMixed = false) 23 | { 24 | BlockType = blockType; 25 | Position = position; 26 | GrowthEndTime = DateTime.UtcNow.AddSeconds(growthDurationSeconds); 27 | GrowthDurationInSeconds = growthDurationSeconds; 28 | IsAlreadyCrossBred = isMixed; 29 | HarvestSeeds = (short)(RollDrops.DoesTreeDropSeed(blockType) ? 1 : 0); 30 | HarvestBlocks = RollDrops.TreeDropsBlocks(blockType); 31 | HarvestGems = RollDrops.TreeDropsGems(blockType); 32 | HarvestExtraBlocks = (short)(RollDrops.DoesTreeDropExtraBlock(blockType) ? 1 : 0); 33 | } 34 | 35 | public static int CalculateGrowthTimeInSeconds(int blockComplexity) 36 | { 37 | if (blockComplexity <= 0) 38 | { 39 | return m_GrowthTimeInSecondsForZeroOrLessComplexity; 40 | } 41 | 42 | double growthTime = Math.Floor(Math.Pow(blockComplexity, 3.2) + 30.0 * Math.Pow(blockComplexity, 1.4)); 43 | 44 | if (growthTime < m_MinGrowthTimeInSeconds) 45 | { 46 | growthTime = m_MinGrowthTimeInSeconds; 47 | } 48 | else if (growthTime > m_MaxGrowthTimeInSeconds) 49 | { 50 | growthTime = m_MaxGrowthTimeInSeconds; 51 | } 52 | 53 | return (int)growthTime; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /PixelWorldsServer.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.32112.339 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PixelWorldsServer.Server", "PixelWorldsServer.Server\PixelWorldsServer.Server.csproj", "{7EEABD8C-7120-4BDA-B15A-C68977C6CF44}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PixelWorldsServer.DataAccess", "PixelWorldsServer.DataAccess\PixelWorldsServer.DataAccess.csproj", "{763A5B89-6D05-4C6C-80D4-DC5FE2665794}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PixelWorldsServer.Protocol", "PixelWorldsServer.Protocol\PixelWorldsServer.Protocol.csproj", "{AA59E2D2-3ABB-4CAD-8AC2-412460EFF3BC}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {7EEABD8C-7120-4BDA-B15A-C68977C6CF44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {7EEABD8C-7120-4BDA-B15A-C68977C6CF44}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {7EEABD8C-7120-4BDA-B15A-C68977C6CF44}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {7EEABD8C-7120-4BDA-B15A-C68977C6CF44}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {763A5B89-6D05-4C6C-80D4-DC5FE2665794}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {763A5B89-6D05-4C6C-80D4-DC5FE2665794}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {763A5B89-6D05-4C6C-80D4-DC5FE2665794}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {763A5B89-6D05-4C6C-80D4-DC5FE2665794}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {AA59E2D2-3ABB-4CAD-8AC2-412460EFF3BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {AA59E2D2-3ABB-4CAD-8AC2-412460EFF3BC}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {AA59E2D2-3ABB-4CAD-8AC2-412460EFF3BC}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {AA59E2D2-3ABB-4CAD-8AC2-412460EFF3BC}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {6826E903-7BE0-48CE-B6DC-87B8DFDEBC26} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Hosting; 3 | using Microsoft.Extensions.Logging; 4 | using MongoDB.Bson.Serialization; 5 | using PixelWorldsServer.DataAccess; 6 | using PixelWorldsServer.DataAccess.Models; 7 | using PixelWorldsServer.Protocol.Packet.Response; 8 | using PixelWorldsServer.Protocol.Utils; 9 | using PixelWorldsServer.Server; 10 | using PixelWorldsServer.Server.Event; 11 | using PixelWorldsServer.Server.Network; 12 | using PixelWorldsServer.Server.Players; 13 | using PixelWorldsServer.Server.Worlds; 14 | using EventHandler = PixelWorldsServer.Server.Event.EventHandler; 15 | 16 | static bool Init(ILogger logger) 17 | { 18 | BsonSerializer.RegisterSerializationProvider(new WorldItemDataSerializationProvider()); 19 | BsonSerializer.RegisterSerializationProvider(new GetWorldResponseSerializationProvider()); 20 | 21 | logger.LogInformation("Loading blocks config..."); 22 | 23 | var start = DateTime.Now; 24 | if (!ConfigData.Init()) 25 | { 26 | logger.LogError("Failed to load blocks config!"); 27 | return false; 28 | } 29 | 30 | logger.LogInformation("Blocks config successfully loaded in {} milliseconds", (DateTime.Now - start).TotalMilliseconds); 31 | return true; 32 | } 33 | 34 | using var host = Host.CreateDefaultBuilder(args) 35 | .ConfigureServices((hostContext, services) => 36 | { 37 | services 38 | .AddLogging(logger => 39 | { 40 | logger.ClearProviders(); 41 | logger.SetMinimumLevel(LogLevel.Debug); 42 | logger.AddLog4Net("log4net.config"); 43 | }) 44 | .Configure(hostContext.Configuration.GetSection("Database")) 45 | .AddSingleton() 46 | .AddSingleton() 47 | .AddSingleton() 48 | .AddSingleton() 49 | .AddSingleton() 50 | .AddSingleton() 51 | .AddHostedService(); 52 | }) 53 | .Build(); 54 | 55 | var logger = host.Services.GetService>()!; 56 | logger.LogInformation("Pixel Worlds Server v0.0.1"); 57 | logger.LogInformation("Project created by kevz#2211"); 58 | 59 | if (!Init(logger)) 60 | { 61 | return; 62 | } 63 | 64 | await host.RunAsync().ConfigureAwait(false); 65 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Worlds/LockSmallData.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Worlds; 7 | 8 | public class LockSmallData : WorldItemBase 9 | { 10 | [BsonElement("playerWhoOwnsLockId")] 11 | public string PlayerWhoOwnsLockId { get; set; } = string.Empty; 12 | 13 | [BsonElement("playerWhoOwnsLockName")] 14 | public string PlayerWhoOwnsLockName { get; set; } = string.Empty; 15 | 16 | [BsonIgnore] 17 | public List PlayersWhoHaveAccessToLock { get; set; } = new(); 18 | 19 | [BsonElement("playersWhoHaveAccessToLock")] 20 | public string[] PlayersWhoHaveAccessToLockString => SerializeAccess(PlayersWhoHaveAccessToLock); 21 | 22 | [BsonIgnore] 23 | public List PlayersWhoHaveMinorAccessToLock { get; set; } = new(); 24 | 25 | [BsonElement("playersWhoHaveMinorAccessToLock")] 26 | public string[] PlayersWhoHaveMinorAccessToLockString => SerializeAccess(PlayersWhoHaveMinorAccessToLock); 27 | 28 | [BsonElement("isOpen")] 29 | public bool IsOpen { get; set; } 30 | 31 | [BsonElement("ignoreEmptyArea")] 32 | public bool IgnoreEmptyArea { get; set; } 33 | 34 | [BsonIgnore] 35 | public List LockMapPoints { get; set; } = new(); 36 | 37 | [BsonElement("lockMapPoints")] 38 | public byte[] LockMapPointsBinary => SerializeLockMapPoints(); 39 | 40 | [BsonElement("creationTime")] 41 | public DateTime CreationTime { get; set; } 42 | 43 | [BsonElement("lastActivatedTime")] 44 | public DateTime LastActivatedTime { get; set; } 45 | 46 | [BsonElement("isBattleOn")] 47 | public bool IsBattleOn { get; set; } 48 | 49 | public LockSmallData() : base(0, BlockType.LockSmall) 50 | { 51 | } 52 | 53 | public LockSmallData(int itemId) : base(itemId, BlockType.LockSmall) 54 | { 55 | } 56 | 57 | private static string[] SerializeAccess(List access) 58 | { 59 | return access.Select(x => $"{x.Id}|{x.Name}").ToArray(); 60 | } 61 | 62 | private byte[] SerializeLockMapPoints() 63 | { 64 | using var ms = new MemoryStream(LockMapPoints.Count * (sizeof(int) + sizeof(int))); 65 | using var bw = new BinaryWriter(ms); 66 | 67 | foreach (var position in LockMapPoints) 68 | { 69 | bw.Write(position.X); 70 | bw.Write(position.Y); 71 | } 72 | 73 | return ms.ToArray(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/AddNetworkPlayerResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization.Attributes; 2 | using PixelWorldsServer.Protocol.Constants; 3 | using PixelWorldsServer.Protocol.Utils; 4 | 5 | namespace PixelWorldsServer.Protocol.Packet.Response; 6 | 7 | public class AddNetworkPlayerResponse : PacketBase 8 | { 9 | [BsonElement(NetStrings.POSITION_X_KEY)] 10 | public float X { get; set; } 11 | 12 | [BsonElement(NetStrings.POSITION_Y_KEY)] 13 | public float Y { get; set; } 14 | 15 | [BsonElement(NetStrings.TIMESTAMP_KEY)] 16 | public long Timestamp { get; set; } 17 | 18 | [BsonElement(NetStrings.ANIMATION_KEY)] 19 | public AnimationNames Animation { get; set; } 20 | 21 | [BsonElement(NetStrings.DIRECTION_KEY)] 22 | public Direction Direction { get; set; } 23 | 24 | [BsonElement(NetStrings.PLAYER_ID_KEY)] 25 | public string PlayerId { get; set; } = string.Empty; 26 | 27 | [BsonElement(NetStrings.PLAYER_USERNAME_KEY)] 28 | public string PlayerUsername { get; set; } = string.Empty; 29 | 30 | [BsonElement("D")] // idk what the fuck is this 31 | public int D { get; set; } 32 | 33 | [BsonElement(NetStrings.SPOTS_FIELD_KEY)] 34 | public BlockType[] Spots { get; set; } = null!; 35 | 36 | [BsonElement(NetStrings.FAMILIAR_BLOCK_TYPE_PLAYER_KEY)] 37 | public BlockType Familiar { get; set; } 38 | 39 | [BsonElement(NetStrings.FAMILIAR_NAME_PLAYER_KEY)] 40 | public string FamiliarName { get; set; } = string.Empty; 41 | 42 | [BsonElement(NetStrings.IS_FAMILIAR_MAX_LVL_PLAYER_KEY)] 43 | public bool IsFamiliarMaxLvl { get; set; } 44 | 45 | [BsonElement(NetStrings.IS_VIP_FIELD_KEY)] 46 | public bool IsVIP { get; set; } 47 | 48 | [BsonElement(NetStrings.VIP_END_TIME_AGE_FIELD_KEY)] 49 | public long VIPEndTimeAge { get; set; } 50 | 51 | [BsonElement(NetStrings.COUNTRY_KEY)] 52 | public int Country { get; set; } 53 | 54 | [BsonElement(NetStrings.AGE_FIELD_KEY)] 55 | public long Age { get; set; } 56 | 57 | [BsonElement(NetStrings.LEVEL_FIELD_KEY)] 58 | public int Level { get; set; } 59 | 60 | [BsonElement(NetStrings.XP_LEVEL_FIELD_KEY)] 61 | public int XPLevel { get; set; } 62 | 63 | [BsonElement(NetStrings.GEMS_AMOUNT_FIELD_KEY)] 64 | public int GemsAmount { get; set; } 65 | 66 | [BsonElement(NetStrings.GENDER_KEY)] 67 | public Gender Gender { get; set; } 68 | 69 | [BsonElement(NetStrings.SKIN_INDEX_FIELD_KEY)] 70 | public int SkinIndex { get; set; } 71 | 72 | [BsonElement(NetStrings.FACE_ANIM_FIELD_KEY)] 73 | public int FaceAnimIndex { get; set; } 74 | 75 | [BsonElement(NetStrings.IN_PORTAL_FIELD_KEY)] 76 | public bool CameFromPortal { get; set; } 77 | 78 | [BsonElement(NetStrings.STATUS_ICON_FIELD_KEY)] 79 | public StatusIconType StatusIcon { get; set; } 80 | } 81 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/ServerHostedService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Options; 4 | using PixelWorldsServer.DataAccess; 5 | using PixelWorldsServer.Server.Event; 6 | using PixelWorldsServer.Server.Network; 7 | using PixelWorldsServer.Server.Players; 8 | using PixelWorldsServer.Server.Worlds; 9 | 10 | namespace PixelWorldsServer.Server; 11 | 12 | public class ServerHostedService : IHostedService 13 | { 14 | private readonly TcpServer m_TcpServer; 15 | private readonly WorldManager m_WorldManager; 16 | private readonly EventManager m_EventManager; 17 | private readonly PlayerManager m_PlayerManager; 18 | 19 | private readonly ILogger m_Logger; 20 | private readonly IOptions m_DatabaseSettings; 21 | 22 | public ServerHostedService(TcpServer tcpServer, WorldManager worldManager, EventManager eventManager, PlayerManager playerManager, ILogger logger, IOptions databaseSettings) 23 | { 24 | m_Logger = logger; 25 | m_TcpServer = tcpServer; 26 | m_EventManager = eventManager; 27 | m_WorldManager = worldManager; 28 | m_PlayerManager = playerManager; 29 | m_DatabaseSettings = databaseSettings; 30 | } 31 | 32 | public async Task StartAsync(CancellationToken cancellationToken) 33 | { 34 | if (m_DatabaseSettings.Value.ConnectionString is null) 35 | { 36 | m_Logger.LogError("Connection string is null! Did you set it in appsettings.json?"); 37 | return; 38 | } 39 | 40 | m_Logger.LogInformation("Loading important worlds.."); 41 | 42 | for (int i = 1; i <= 12; ++i) 43 | { 44 | // I could just copy existing world instead of loading it every fucking time but idc 45 | await m_WorldManager 46 | .LoadWorldFromBinaryAsync($"TUTORIAL{i}", "Data/tutorial-world.bin") 47 | .ConfigureAwait(false); 48 | } 49 | 50 | m_Logger.LogInformation("Loaded {} worlds", m_WorldManager.GetWorldsCount()); 51 | 52 | var eventTask = m_EventManager.StartAsync(cancellationToken); 53 | var serverTask = m_TcpServer.StartAsync(cancellationToken); 54 | await Task.WhenAll(eventTask, serverTask).ConfigureAwait(false); // I think i should use WhenAny instead of waiting for both tasks? 55 | } 56 | 57 | public async Task StopAsync(CancellationToken _) 58 | { 59 | m_TcpServer.Stop(); 60 | m_Logger.LogInformation("Saving all players and worlds..."); 61 | 62 | var tasks = new Task[] 63 | { 64 | m_WorldManager.SaveAllWorldsAsync(), 65 | m_PlayerManager.SaveAllPlayersAsync() 66 | }; 67 | 68 | await Task.WhenAll(tasks).ConfigureAwait(false); 69 | 70 | m_Logger.LogInformation("All players and worlds are saved!"); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Utils/DataFactory.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | using PixelWorldsServer.Protocol.Worlds; 3 | 4 | namespace PixelWorldsServer.Protocol.Utils; 5 | 6 | public static class DataFactory 7 | { 8 | public static Type GetDataTypeForEnum(BlockType bt) 9 | { 10 | return bt switch 11 | { 12 | BlockType.LockSmall => typeof(LockSmallData), 13 | BlockType.EntrancePortal => typeof(EntrancePortalData), 14 | BlockType.LanternBlue => typeof(LanternBlueData), 15 | BlockType.LabHoseLarge => typeof(LabHoseLargeData), 16 | BlockType.LabLightRed => typeof(LabLightRedData), 17 | BlockType.SewerPipeBlack => typeof(SewerPipeBlackData), 18 | BlockType.TutorialSleepPod => typeof(TutorialSleepPodData), 19 | BlockType.TutorialCablePortal => typeof(TutorialCablePortalData), 20 | BlockType.Stereos => typeof(StereosData), 21 | BlockType.ScifiArrow => typeof(ScifiArrowData), 22 | BlockType.Portal => typeof(PortalData), 23 | BlockType.BattleBarrierLab => typeof(BattleBarrierLabData), 24 | BlockType.ScifiLights => typeof(ScifiLightsData), 25 | BlockType.ScifiDoor => typeof(ScifiDoorData), 26 | BlockType.LabElectricWireBlue => typeof(LabElectricWireBlueData), 27 | BlockType.ScifiComputer => typeof(ScifiComputerData), 28 | BlockType.LabElectricWireRed => typeof(LabElectricWireRedData), 29 | 30 | _ => throw new InvalidDataException($"Unrecognized data {Enum.GetName(bt)}") 31 | }; 32 | } 33 | 34 | public static WorldItemBase SpawnDataClassForEnum(BlockType bt) 35 | { 36 | return SpawnDataClassForEnum(bt, 0); 37 | } 38 | 39 | public static WorldItemBase SpawnDataClassForEnum(BlockType bt, int itemId = 0) 40 | { 41 | return bt switch 42 | { 43 | BlockType.LockSmall => new LockSmallData(itemId), 44 | BlockType.EntrancePortal => new EntrancePortalData(itemId), 45 | BlockType.LanternBlue => new LanternBlueData(itemId), 46 | BlockType.LabHoseLarge => new LabHoseLargeData(itemId), 47 | BlockType.LabLightRed => new LabLightRedData(itemId), 48 | BlockType.SewerPipeBlack => new SewerPipeBlackData(itemId), 49 | BlockType.TutorialSleepPod => new TutorialSleepPodData(itemId), 50 | BlockType.TutorialCablePortal => new TutorialCablePortalData(itemId), 51 | BlockType.Stereos => new StereosData(itemId), 52 | BlockType.ScifiArrow => new ScifiArrowData(itemId), 53 | BlockType.Portal => new PortalData(itemId), 54 | BlockType.BattleBarrierLab => new BattleBarrierLabData(itemId), 55 | BlockType.ScifiLights => new ScifiLightsData(itemId), 56 | BlockType.ScifiDoor => new ScifiDoorData(itemId), 57 | BlockType.LabElectricWireBlue => new LabElectricWireBlueData(itemId), 58 | BlockType.ScifiComputer => new ScifiComputerData(itemId), 59 | BlockType.LabElectricWireRed => new LabElectricWireRedData(itemId), 60 | 61 | _ => throw new InvalidDataException($"Unrecognized data {Enum.GetName(bt)}") 62 | }; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /PixelWorldsServer.DataAccess/Database.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Microsoft.Extensions.Options; 3 | using MongoDB.Driver; 4 | using PixelWorldsServer.DataAccess.Models; 5 | 6 | namespace PixelWorldsServer.DataAccess; 7 | 8 | public class Database 9 | { 10 | private readonly ILogger m_Logger; 11 | private readonly IMongoClient m_MongoClient; 12 | private readonly IMongoDatabase m_MongoDatabase; 13 | private readonly IMongoCollection m_WorldsCollection; 14 | private readonly IMongoCollection m_PlayersCollection; 15 | private readonly IOptions m_DatabaseSettings; 16 | 17 | public Database(ILogger logger, IOptions databaseSettings) 18 | { 19 | m_Logger = logger; 20 | m_Logger.LogInformation("Connecting to MongoDB..."); 21 | m_DatabaseSettings = databaseSettings; 22 | 23 | m_MongoClient = new MongoClient(m_DatabaseSettings.Value.ConnectionString); 24 | m_MongoDatabase = m_MongoClient.GetDatabase(m_DatabaseSettings.Value.DatabaseName); 25 | m_WorldsCollection = m_MongoDatabase.GetCollection(m_DatabaseSettings.Value.WorldsCollectionName); 26 | m_PlayersCollection = m_MongoDatabase.GetCollection(m_DatabaseSettings.Value.PlayersCollectionName); 27 | m_Logger.LogInformation("Successfully connected to MongoDB!"); 28 | } 29 | 30 | public async Task GetPlayerByIdAsync(string id) 31 | { 32 | var players = await m_PlayersCollection.FindAsync(x => x.Id == id).ConfigureAwait(false); 33 | return await players.FirstOrDefaultAsync().ConfigureAwait(false); 34 | } 35 | 36 | public async Task GetPlayerByNameAsync(string name) 37 | { 38 | var players = await m_PlayersCollection.FindAsync(x => x.Name == name).ConfigureAwait(false); 39 | return await players.FirstOrDefaultAsync().ConfigureAwait(false); 40 | } 41 | 42 | public async Task CreatePlayerAsync(string ip, string os) 43 | { 44 | PlayerModel playerModel = new() 45 | { 46 | IP = ip, 47 | OS = os, 48 | Skin = 7, 49 | Gems = 250, 50 | Level = 1, 51 | Slots = 20, 52 | CountryCode = 999, 53 | CameraZoomValue = 0.25f 54 | }; 55 | 56 | await m_PlayersCollection.InsertOneAsync(playerModel).ConfigureAwait(false); 57 | playerModel.Name = $"SUBJECT_{playerModel.Id.ToUpper()}"; 58 | 59 | await UpdatePlayerNameAsync(playerModel.Id, playerModel.Name).ConfigureAwait(false); 60 | return playerModel; 61 | } 62 | 63 | public async Task UpdatePlayerNameAsync(string id, string name) 64 | { 65 | var update = Builders.Update.Set(x => x.Name, name); 66 | await m_PlayersCollection.UpdateOneAsync(x => x.Id == id, update).ConfigureAwait(false); 67 | } 68 | 69 | public async Task SavePlayerAsync(PlayerModel playerModel) 70 | { 71 | await m_PlayersCollection.ReplaceOneAsync(x => x.Id == playerModel.Id, playerModel).ConfigureAwait(false); 72 | } 73 | 74 | public async Task GetWorldByNameAsync(string name) 75 | { 76 | var worlds = await m_WorldsCollection.FindAsync(x => x.Name == name).ConfigureAwait(false); 77 | return await worlds.FirstOrDefaultAsync().ConfigureAwait(false); 78 | } 79 | 80 | public async Task InsertWorldAsync(WorldModel worldModel) 81 | { 82 | await m_WorldsCollection.InsertOneAsync(worldModel).ConfigureAwait(false); 83 | return worldModel.Id; 84 | } 85 | 86 | public async Task SaveWorldAsync(WorldModel worldModel) 87 | { 88 | await m_WorldsCollection.ReplaceOneAsync(x => x.Id == worldModel.Id, worldModel).ConfigureAwait(false); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/PixelWorldsServer.Server.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | Always 26 | 27 | 28 | Always 29 | 30 | 31 | Always 32 | 33 | 34 | Always 35 | 36 | 37 | Always 38 | 39 | 40 | Always 41 | 42 | 43 | Always 44 | 45 | 46 | Always 47 | 48 | 49 | Always 50 | 51 | 52 | Always 53 | 54 | 55 | Always 56 | 57 | 58 | Always 59 | 60 | 61 | Always 62 | 63 | 64 | Always 65 | 66 | 67 | Always 68 | 69 | 70 | Always 71 | 72 | 73 | Always 74 | 75 | 76 | Always 77 | 78 | 79 | Always 80 | 81 | 82 | Always 83 | 84 | 85 | Always 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/AnimationNames.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Constants; 2 | 3 | public enum AnimationNames 4 | { 5 | None, 6 | Idle, 7 | Move, 8 | Jump, 9 | StartFall, 10 | Fall, 11 | Hit, 12 | HitMove, 13 | Swim, 14 | FaceContent, 15 | FaceHappy, 16 | FaceSurprised, 17 | FaceDevastated, 18 | FaceTired, 19 | FaceHoldBreath, 20 | FaceFurious, 21 | FaceAngry, 22 | FaceAngryMutru, 23 | FaceDying, 24 | FaceSad, 25 | FaceLaugh, 26 | FaceWink, 27 | FaceGrin, 28 | FaceSuspicious, 29 | FaceGoofySmile, 30 | FaceJump1, 31 | FaceJump2, 32 | FaceJoyfull, 33 | FaceSleep1, 34 | FaceSleep2, 35 | FaceSerious, 36 | FaceVicious, 37 | FaceContentTalk, 38 | FaceHappyTalk, 39 | FaceSurprisedTalk, 40 | FaceTiredTalk, 41 | FaceHoldBreathTalk, 42 | FaceAngryTalk, 43 | FaceAngryMutruTalk, 44 | FaceSadTalk, 45 | FaceSuspiciousTalk, 46 | FaceSeriousTalk, 47 | FaceViciousTalk, 48 | HoldGun, 49 | Shoot, 50 | ShootMove, 51 | Dying, 52 | RockRock, 53 | Surprised, 54 | Dunno, 55 | Furious, 56 | PointForward, 57 | ThumbsUp, 58 | JollyArms, 59 | Depressed, 60 | DepressedLoop, 61 | Honk, 62 | Applause, 63 | Wave, 64 | Waveone, 65 | Wink, 66 | Tired, 67 | Sleep, 68 | JumpWings, 69 | Sit, 70 | SitDown, 71 | GetUp, 72 | TakeHit, 73 | ThrowBlock, 74 | Invisible, 75 | SleepInBed, 76 | SitInBath, 77 | FallParachute, 78 | Dabb, 79 | FaceDabbNFPalm, 80 | WoopWoop, 81 | ThisWay, 82 | Love, 83 | FUUU, 84 | Cheer, 85 | FPalm, 86 | Dance, 87 | LOL, 88 | Cuteness, 89 | Troll, 90 | FaceWoopWoop, 91 | FaceLove1, 92 | FaceLove2, 93 | FaceFUUU, 94 | FaceDance1, 95 | FaceDance2, 96 | FaceCuteness, 97 | FaceTroll1, 98 | FaceTroll2, 99 | MeGusta, 100 | FaceMeGusta, 101 | FaceHappyC, 102 | FaceHappyE, 103 | FaceHappyF, 104 | FaceHappyK, 105 | FaceHappyL, 106 | FaceHappyM, 107 | FaceMutruA, 108 | FaceMutruB, 109 | FaceGrinA, 110 | FaceGrinC, 111 | FaceGrinE, 112 | FaceGrinF, 113 | FaceGrinK, 114 | FaceGrinL, 115 | FaceGrinM, 116 | FaceLaughC, 117 | FaceLaughE, 118 | FaceLaughF, 119 | FaceLaughK, 120 | FaceLaughL, 121 | FaceSadL, 122 | FaceSuspiciousA, 123 | FaceSuspiciousF, 124 | FaceSuspiciousM, 125 | FaceSeriousC, 126 | FaceHappyCTalk, 127 | FaceHappyETalk, 128 | FaceHappyFTalk, 129 | FaceHappyKTalk, 130 | FaceHappyLTalk, 131 | FaceHappyMTalk, 132 | FaceMutruATalk, 133 | FaceMutruBTalk, 134 | FaceGrinATalk, 135 | FaceGrinCTalk, 136 | FaceGrinETalk, 137 | FaceGrinFTalk, 138 | FaceGrinKTalk, 139 | FaceGrinLTalk, 140 | FaceGrinMTalk, 141 | FaceLaughCTalk, 142 | FaceLaughETalk, 143 | FaceLaughFTalk, 144 | FaceLaughKTalk, 145 | FaceLaughLTalk, 146 | FaceSadLTalk, 147 | FaceSuspiciousATalk, 148 | FaceSuspiciousFTalk, 149 | FaceSuspiciousMTalk, 150 | FaceSeriousCTalk, 151 | UseRocket, 152 | FaceFPalm, 153 | WerewolfExpression, 154 | FaceWerewolfExpression1, 155 | FaceWerewolfExpression2, 156 | FaceWerewolfExpression3, 157 | FaceWerewolfExpression4, 158 | FaceWerewolfExpression5, 159 | FaceWerewolfDying1, 160 | FaceWerewolfDying2, 161 | FaceWerewolfDying3, 162 | FacePacifier, 163 | FishStrikes, 164 | HookFish, 165 | FightWithFish, 166 | FishCaught, 167 | FishingIdle, 168 | IdleReset, 169 | PetsTrain, 170 | PetsClean, 171 | PetsPet, 172 | MountFlyingIdle, 173 | MountFlying, 174 | MountFlyingTakeHit, 175 | MountFlyingWithInput, 176 | MountFlyingSleep, 177 | HoldMeleeHeavy, 178 | HoldMeleeArcane, 179 | IdleCamouflage, 180 | END_OF_THE_ENUM 181 | } 182 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/Players/Player.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using PixelWorldsServer.DataAccess.Models; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | using PixelWorldsServer.Server.Worlds; 6 | using System.Net; 7 | 8 | namespace PixelWorldsServer.Server.Players; 9 | 10 | public class Player : PlayerModel 11 | { 12 | private bool m_ShouldDisconnect = false; 13 | private readonly object m_DocumentsLocker = new(); 14 | private readonly object m_DisconnectLocker = new(); 15 | private readonly List m_Documents = new(); 16 | 17 | public int TutorialHitCount { get; set; } 18 | public bool Teleport { get; set; } 19 | 20 | public Direction Direction { get; set; } = Direction.Left; 21 | public AnimationNames Animation { get; set; } = AnimationNames.Idle; 22 | public StatusIconType StatusIcon { get; set; } 23 | 24 | public World? World { get; set; } 25 | public Vector2 Position { get; set; } = new(); 26 | public IPAddress Address { get; private set; } 27 | 28 | public Player(IPAddress address) 29 | { 30 | IP = address.ToString(); 31 | Address = address; 32 | } 33 | 34 | public void SendPacket(T data) 35 | { 36 | var document = data.ToBsonDocument(); 37 | lock (m_DocumentsLocker) 38 | { 39 | m_Documents.Add(document); 40 | } 41 | } 42 | 43 | public void Disconnect() 44 | { 45 | lock (m_DisconnectLocker) 46 | { 47 | m_ShouldDisconnect = true; 48 | } 49 | } 50 | 51 | public bool IsDisconnected() 52 | { 53 | lock (m_DisconnectLocker) 54 | { 55 | return m_ShouldDisconnect; 56 | } 57 | } 58 | 59 | public BsonDocument ConsumePackets() 60 | { 61 | lock (m_DocumentsLocker) 62 | { 63 | BsonDocument document = new(); 64 | for (int i = 0; i < m_Documents.Count; ++i) 65 | { 66 | document.Add($"m{i}", m_Documents[i]); 67 | } 68 | 69 | document.Add("mc", m_Documents.Count); 70 | m_Documents.Clear(); 71 | 72 | return document; 73 | } 74 | } 75 | 76 | public byte[] PackInventory() 77 | { 78 | using var ms = new MemoryStream(Inventory.Count * (sizeof(int) + sizeof(short))); 79 | using var bw = new BinaryWriter(ms); 80 | 81 | foreach (var (id, amount) in Inventory) 82 | { 83 | bw.Write((int)id); 84 | bw.Write(amount); 85 | } 86 | 87 | return ms.ToArray(); 88 | } 89 | 90 | public static int BlockTypeAndInventoryItemTypeToInt(BlockType blockType, InventoryItemType inventoryItemType) 91 | { 92 | return (int)((uint)inventoryItemType << 24) | (int)blockType; 93 | } 94 | 95 | public bool CanFitItem(BlockType blockType, InventoryItemType inventoryItemType, short amount) 96 | { 97 | var key = BlockTypeAndInventoryItemTypeToInt(blockType, inventoryItemType); 98 | if (Inventory.TryGetValue(key, out var currentAmount)) 99 | { 100 | if (amount + currentAmount > 999) 101 | { 102 | return false; 103 | } 104 | 105 | Inventory[key] += currentAmount; 106 | } 107 | else if (Inventory.Count >= Slots) 108 | { 109 | return false; 110 | } 111 | 112 | return true; 113 | } 114 | 115 | public bool HasItem(BlockType blockType, InventoryItemType inventoryItemType) 116 | { 117 | int key = BlockTypeAndInventoryItemTypeToInt(blockType, inventoryItemType); 118 | return Inventory.ContainsKey(key); 119 | } 120 | 121 | public void AddItem(BlockType blockType, InventoryItemType inventoryItemType, short amount) 122 | { 123 | int key = BlockTypeAndInventoryItemTypeToInt(blockType, inventoryItemType); 124 | if (Inventory.ContainsKey(key)) 125 | { 126 | Inventory[key] += amount; 127 | } 128 | else 129 | { 130 | Inventory.Add(key, amount); 131 | } 132 | } 133 | 134 | public void RemoveItem(BlockType blockType, InventoryItemType inventoryItemType, short amount) 135 | { 136 | int key = BlockTypeAndInventoryItemTypeToInt(blockType, inventoryItemType); 137 | 138 | Inventory[key] -= amount; 139 | 140 | if (Inventory[key] <= 0) 141 | { 142 | Inventory.Remove(key); 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Utils/RollDrops.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.Protocol.Constants; 2 | 3 | namespace PixelWorldsServer.Protocol.Utils; 4 | 5 | public static class RollDrops 6 | { 7 | public struct RollChances 8 | { 9 | private readonly short[] m_AmountArray = new short[100]; 10 | 11 | public RollChances(short[] chances, short[] amounts) 12 | { 13 | int counter = 0; 14 | for (int i = 0; i < chances.Length; i++) 15 | { 16 | for (int j = 0; j < chances[i]; j++) 17 | { 18 | m_AmountArray[counter++] = amounts[i]; 19 | } 20 | } 21 | } 22 | 23 | public short GetRolledAmount(int roll) 24 | { 25 | return m_AmountArray[roll]; 26 | } 27 | } 28 | 29 | public static bool DoesTreeDropSeed(BlockType blockType) 30 | { 31 | return RollD100() < ConfigData.TreeDropSeedPercentage[(int)blockType]; 32 | } 33 | 34 | public static bool DoesBlockDropSeed(BlockType blockType) 35 | { 36 | return RollD100() < ConfigData.BlockDropSeedPercentage[(int)blockType]; 37 | } 38 | 39 | public static bool DoesBlockDropBlock(BlockType blockType) 40 | { 41 | return RollD100() < ConfigData.BlockDropBlockPercentage[(int)blockType]; 42 | } 43 | 44 | public static bool DoesTreeDropExtraBlock(BlockType blockType) 45 | { 46 | int treeExtraDropChance = ConfigData.TreeExtraDropChance[(int)blockType]; 47 | if (treeExtraDropChance == 0) 48 | { 49 | return false; 50 | } 51 | return 0 == GenericRoll(0, treeExtraDropChance); 52 | } 53 | 54 | public static bool DoesBlockDropExtraBlock(BlockType blockType) 55 | { 56 | int blockExtraDropChance = ConfigData.BlockExtraDropChance[(int)blockType]; 57 | if (blockExtraDropChance == 0) 58 | { 59 | return false; 60 | } 61 | return 0 == GenericRoll(0, blockExtraDropChance); 62 | } 63 | 64 | public static short TreeDropsBlocks(BlockType blockType) 65 | { 66 | short treeDropBlockRangeMax = ConfigData.TreeDropBlockRangeMax[(int)blockType]; 67 | if (treeDropBlockRangeMax == 0) 68 | { 69 | return 0; 70 | } 71 | short treeDropBlockRangeMin = ConfigData.TreeDropBlockRangeMin[(int)blockType]; 72 | return GenericRoll(treeDropBlockRangeMin, (short)(treeDropBlockRangeMax + 1)); 73 | } 74 | 75 | public static short TreeDropsGems(BlockType blockType) 76 | { 77 | short treeDropGemRangeMax = ConfigData.TreeDropGemRangeMax[(int)blockType]; 78 | if (treeDropGemRangeMax == 0) 79 | { 80 | return 0; 81 | } 82 | short treeDropGemRangeMin = ConfigData.TreeDropGemRangeMin[(int)blockType]; 83 | return GenericRoll(treeDropGemRangeMin, (short)(treeDropGemRangeMax + 1)); 84 | } 85 | 86 | public static short BlockDropsGems(BlockType blockType) 87 | { 88 | short blockDropGemRangeMax = ConfigData.BlockDropGemRangeMax[(int)blockType]; 89 | if (ConfigData.BlockDropGemPercentageOn[(int)blockType]) 90 | { 91 | if (RollD100() < blockDropGemRangeMax) 92 | { 93 | return 1; 94 | } 95 | return 0; 96 | } 97 | if (blockDropGemRangeMax == 0) 98 | { 99 | return 0; 100 | } 101 | short blockDropGemRangeMin = ConfigData.BlockDropGemRangeMin[(int)blockType]; 102 | return GenericRoll(blockDropGemRangeMin, (short)(blockDropGemRangeMax + 1)); 103 | } 104 | 105 | private static byte RollD100() 106 | { 107 | return (byte)GenericRoll(0, 100); 108 | } 109 | 110 | private static short GenericRoll(short minInclusive, short maxExclusive) 111 | { 112 | return (short)GenericRoll((int)minInclusive, (int)maxExclusive); 113 | } 114 | 115 | public static int GenericRoll(int minInclusive, int maxExclusive) 116 | { 117 | return new Random().Next(minInclusive, maxExclusive); 118 | } 119 | 120 | public static int RollPosition(int min, int max) 121 | { 122 | return new Random().Next(min, max); 123 | } 124 | 125 | public static void Shuffle(T[] array) 126 | { 127 | var length = array.Length; 128 | var random = new Random(); 129 | while (length > 1) 130 | { 131 | int index = random.Next(length--); 132 | 133 | T val = array[length]; 134 | array[length] = array[index]; 135 | array[index] = val; 136 | } 137 | } 138 | } 139 | 140 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/Event/EventManager.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using MongoDB.Bson; 3 | using MongoDB.Bson.Serialization; 4 | using PixelWorldsServer.Server.Players; 5 | using PixelWorldsServer.Server.Worlds; 6 | using System.Collections.Concurrent; 7 | using System.Reflection; 8 | 9 | namespace PixelWorldsServer.Server.Event; 10 | 11 | public class EventContext 12 | { 13 | public World? World { get; set; } 14 | public Player Player { get; set; } = null!; 15 | } 16 | 17 | public class IncomingPacket 18 | { 19 | public Player Player { get; set; } = null!; 20 | public BsonDocument Document { get; set; } = null!; 21 | public AutoResetEvent AutoResetEvent { get; set; } = null!; 22 | } 23 | 24 | public class EventManager 25 | { 26 | private readonly ILogger m_Logger; 27 | private readonly EventHandler m_EventHandler; 28 | private readonly ConcurrentQueue m_PacketQueue = new(); 29 | private readonly Dictionary m_RegisteredEvents = new(); 30 | 31 | public EventManager(ILogger logger, EventHandler eventHandler) 32 | { 33 | m_Logger = logger; 34 | m_EventHandler = eventHandler; 35 | 36 | Initialize(); 37 | } 38 | 39 | private void Initialize() 40 | { 41 | m_Logger.LogInformation("Registering events..."); 42 | 43 | foreach (var method in m_EventHandler.GetType().GetMethods()) 44 | { 45 | var attributes = method.GetCustomAttributes(); 46 | foreach (var attribute in attributes) 47 | { 48 | m_RegisteredEvents.Add(attribute.Id, method); 49 | } 50 | } 51 | 52 | m_Logger.LogInformation("Registered {} events", m_RegisteredEvents.Count); 53 | } 54 | 55 | public void QueuePacket(BsonDocument document, Player player, AutoResetEvent autoResetEvent) 56 | { 57 | m_PacketQueue.Enqueue(new IncomingPacket() 58 | { 59 | Player = player, 60 | Document = document, 61 | AutoResetEvent = autoResetEvent 62 | }); 63 | } 64 | 65 | public async Task StartAsync(CancellationToken cancellationToken) 66 | { 67 | await Task.Yield(); 68 | 69 | m_Logger.LogInformation("Event manager is running!"); 70 | while (!cancellationToken.IsCancellationRequested) 71 | { 72 | if (!m_PacketQueue.TryDequeue(out var incomingPacket)) 73 | { 74 | Thread.Sleep(1); 75 | continue; 76 | } 77 | 78 | try 79 | { 80 | var realTask = InvokeAsync(incomingPacket.Document, incomingPacket.Player); 81 | var delayTask = Task.Delay(TimeSpan.FromSeconds(10), cancellationToken); 82 | 83 | var task = await Task.WhenAny(realTask, delayTask); 84 | if (task == delayTask) 85 | { 86 | m_Logger.LogCritical("Event takes more than 10 seconds!!!"); 87 | } 88 | } 89 | catch (Exception exception) 90 | { 91 | m_Logger.LogError("Exception: {}", exception); 92 | } 93 | finally 94 | { 95 | incomingPacket.AutoResetEvent.Set(); 96 | } 97 | } 98 | } 99 | 100 | private async Task InvokeAsync(BsonDocument document, Player player) 101 | { 102 | string id = document["ID"].AsString; 103 | if (!m_RegisteredEvents.TryGetValue(id, out var method)) 104 | { 105 | m_Logger.LogWarning("Unhandled packet {}", document.ToString()); 106 | return; 107 | } 108 | 109 | var context = new EventContext() 110 | { 111 | World = player.World, 112 | Player = player 113 | }; 114 | 115 | var methodParameters = method.GetParameters(); 116 | object[] parameters; 117 | if (methodParameters.Length > 1) 118 | { 119 | var parameter = methodParameters[1]; 120 | var serialized = BsonSerializer.Deserialize(document, parameter.ParameterType); 121 | parameters = new[] { context, serialized }; 122 | } 123 | else 124 | { 125 | parameters = new[] { context }; 126 | } 127 | 128 | try 129 | { 130 | var task = (Task)method.Invoke(m_EventHandler, parameters)!; 131 | await task.ConfigureAwait(false); 132 | } 133 | catch (Exception exception) 134 | { 135 | m_Logger.LogError("Exception: {}", exception); 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /PixelWorldsServer.DataAccess/Models/WorldModel.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization; 3 | using MongoDB.Bson.Serialization.Attributes; 4 | using MongoDB.Bson.Serialization.Serializers; 5 | using PixelWorldsServer.Protocol.Constants; 6 | using PixelWorldsServer.Protocol.Utils; 7 | using PixelWorldsServer.Protocol.Worlds; 8 | 9 | namespace PixelWorldsServer.DataAccess.Models; 10 | 11 | public class WorldModel 12 | { 13 | [BsonId] 14 | [BsonRepresentation(BsonType.ObjectId)] 15 | public string Id { get; set; } = null!; 16 | public string Name { get; set; } = string.Empty; 17 | 18 | public int ItemId { get; set; } = 1;// WorldItem last id 19 | public int MusicIndex { get; set; } 20 | public int InventoryId { get; set; } = 1;// Collectables last id 21 | 22 | public Vector2i Size { get; set; } = new(); 23 | public Vector2i StartingPoint { get; set; } = new(); 24 | 25 | public WeatherType WeatherType { get; set; } = WeatherType.None; 26 | public GravityMode GravityMode { get; set; } = GravityMode.Normal; 27 | public LightingType LightingType { get; set; } = LightingType.None; 28 | public WorldLayoutType LayoutType { get; set; } = WorldLayoutType.Basic; 29 | public LayerBackgroundType LayerBackgroundType { get; set; } = LayerBackgroundType.ForestBackground; 30 | 31 | public List BlockLayer { get; set; } = new(); 32 | public List PlantedSeeds { get; set; } = new(); 33 | public List ItemDatas { get; set; } = new(); 34 | public List BlockWaterLayer { get; set; } = new(); 35 | public List BlockWiringLayer { get; set; } = new(); 36 | public List Collectables { get; set; } = new(); 37 | public List BlockBackgroundLayer { get; set; } = new(); 38 | 39 | public void LoadCopy(WorldModel worldModel) 40 | { 41 | Id = worldModel.Id; 42 | Name = worldModel.Name; 43 | 44 | ItemId = worldModel.ItemId; 45 | MusicIndex = worldModel.MusicIndex; 46 | InventoryId = worldModel.InventoryId; 47 | 48 | Size = worldModel.Size; 49 | StartingPoint = worldModel.StartingPoint; 50 | 51 | WeatherType = worldModel.WeatherType; 52 | GravityMode = worldModel.GravityMode; 53 | LightingType = worldModel.LightingType; 54 | LayoutType = worldModel.LayoutType; 55 | LayerBackgroundType = worldModel.LayerBackgroundType; 56 | 57 | BlockLayer = worldModel.BlockLayer; 58 | PlantedSeeds = worldModel.PlantedSeeds; 59 | ItemDatas = worldModel.ItemDatas; 60 | BlockWaterLayer = worldModel.BlockWaterLayer; 61 | BlockWiringLayer = worldModel.BlockWiringLayer; 62 | BlockBackgroundLayer = worldModel.BlockBackgroundLayer; 63 | } 64 | 65 | public static WorldModel CreateCopy(WorldModel worldModel) 66 | { 67 | WorldModel result = new(); 68 | result.LoadCopy(worldModel); 69 | return result; 70 | } 71 | } 72 | 73 | public class WorldItemDataSerializer : SerializerBase> 74 | { 75 | public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, List value) 76 | { 77 | context.Writer.WriteStartDocument(); 78 | context.Writer.WriteName("Count"); 79 | context.Writer.WriteInt32(value.Count); 80 | context.Writer.WriteName("Values"); 81 | context.Writer.WriteStartArray(); 82 | 83 | foreach (var item in value) 84 | { 85 | if (item is null) 86 | { 87 | context.Writer.WriteStartDocument(); 88 | context.Writer.WriteName("class"); 89 | context.Writer.WriteString("null"); 90 | context.Writer.WriteEndDocument(); 91 | } 92 | else 93 | { 94 | BsonDocumentSerializer.Instance.Serialize(context, item.Serialize()); 95 | } 96 | } 97 | 98 | context.Writer.WriteEndArray(); 99 | context.Writer.WriteEndDocument(); 100 | } 101 | 102 | public override List Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) 103 | { 104 | context.Reader.ReadStartDocument(); 105 | var count = context.Reader.ReadInt32(); 106 | var list = new List(count); 107 | context.Reader.ReadStartArray(); 108 | 109 | for (int i = 0; i < count; ++i) 110 | { 111 | var childDocument = BsonDocumentSerializer.Instance.Deserialize(context); 112 | var className = childDocument["class"].AsString; 113 | if (className != "null") 114 | { 115 | childDocument.Remove("class"); 116 | 117 | var blockType = WorldItemBase.GetBlockTypeViaClassName(className); 118 | var worldItemType = DataFactory.GetDataTypeForEnum(blockType); 119 | var worldItemBase = (WorldItemBase)BsonSerializer.Deserialize(childDocument, worldItemType); 120 | list.Add(worldItemBase); 121 | } 122 | else 123 | { 124 | list.Add(null); 125 | } 126 | } 127 | 128 | context.Reader.ReadEndArray(); 129 | context.Reader.ReadEndDocument(); 130 | 131 | return list; 132 | } 133 | } 134 | 135 | public class WorldItemDataSerializationProvider : IBsonSerializationProvider 136 | { 137 | public IBsonSerializer GetSerializer(Type type) 138 | { 139 | if (type == typeof(List)) 140 | { 141 | return new WorldItemDataSerializer(); 142 | } 143 | return null!; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/Network/TcpServer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using MongoDB.Bson; 3 | using MongoDB.Bson.Serialization; 4 | using PixelWorldsServer.DataAccess; 5 | using PixelWorldsServer.DataAccess.Models; 6 | using PixelWorldsServer.Protocol.Packet; 7 | using PixelWorldsServer.Protocol.Utils; 8 | using PixelWorldsServer.Server.Event; 9 | using PixelWorldsServer.Server.Players; 10 | using System.Net; 11 | using System.Net.Sockets; 12 | 13 | namespace PixelWorldsServer.Server.Network; 14 | 15 | public class TcpServer 16 | { 17 | private readonly ILogger m_Logger; 18 | private readonly Database m_Database; 19 | private readonly TcpListener m_TcpListener; 20 | private readonly EventManager m_EventManager; 21 | private readonly PlayerManager m_PlayerManager; 22 | 23 | public TcpServer(ILogger logger, EventManager eventManager, Database database, PlayerManager playerManager) 24 | { 25 | m_Logger = logger; 26 | m_Database = database; 27 | m_TcpListener = new TcpListener(new IPEndPoint(IPAddress.Any, 10001)); 28 | m_TcpListener.Server.ReceiveTimeout = 1000; 29 | m_EventManager = eventManager; 30 | m_PlayerManager = playerManager; 31 | } 32 | 33 | public async Task HandleConnectionAsync(TcpClient client, Player player, CancellationToken token) 34 | { 35 | var stream = client.GetStream(); 36 | var autoResetEvent = new AutoResetEvent(false); 37 | 38 | int packetDataLength = 0; 39 | byte[]? packetData = null; 40 | byte[] buffer = new byte[1024]; 41 | 42 | while (!token.IsCancellationRequested) 43 | { 44 | try 45 | { 46 | int bytesRead = await stream.ReadAsync(buffer, token).ConfigureAwait(false); 47 | if (bytesRead == 0) 48 | { 49 | return; 50 | } 51 | 52 | // If packet data is null 53 | if (packetData is null) 54 | { 55 | if (bytesRead < sizeof(int)) 56 | { 57 | m_Logger.LogWarning("Client sends packet less than 4 bytes long"); 58 | return; // Too less packet 59 | } 60 | 61 | packetDataLength = BitConverter.ToInt32(buffer); 62 | if (packetDataLength > 1024 * 64) // 64 KB 63 | { 64 | m_Logger.LogWarning("Client sends packet more than 64KB long"); 65 | return; // Too long packet 66 | } 67 | 68 | packetData = new byte[bytesRead - sizeof(int)]; // skip the length 69 | packetDataLength -= 4; 70 | Array.Copy(buffer, 4, packetData, 0, packetData.Length); 71 | } 72 | else 73 | { 74 | int offset = packetData.Length; 75 | Array.Resize(ref packetData, packetData.Length + buffer.Length); 76 | Array.Copy(buffer, 0, packetData, offset, buffer.Length); 77 | } 78 | 79 | if (packetData.Length < packetDataLength) 80 | { 81 | continue; // Waiting for more data.. 82 | } 83 | 84 | var document = BsonSerializer.Deserialize(packetData); 85 | var messageCount = document["mc"].AsInt32; 86 | if (messageCount == 1 && document[NetStrings.FIRST_MESSAGE_KEY][NetStrings.ID_KEY].AsString == NetStrings.PING_KEY) 87 | { 88 | player.SendPacket(new PacketBase() 89 | { 90 | ID = NetStrings.PING_KEY 91 | }); 92 | } 93 | else 94 | { 95 | for (int i = 0; i < messageCount; ++i) 96 | { 97 | var message = document[$"m{i}"].AsBsonDocument; 98 | m_EventManager.QueuePacket(message, player, autoResetEvent); 99 | } 100 | 101 | if (messageCount > 0) 102 | { 103 | // If the handler takes more than 100 ms then just send 104 | // the client empty message so that the client doesn't die 105 | if (!autoResetEvent.WaitOne(TimeSpan.FromMilliseconds(100))) 106 | { 107 | m_Logger.LogWarning("Event takes more than 100 milliseconds: {}", document); 108 | } 109 | } 110 | } 111 | 112 | if (player.IsDisconnected()) 113 | { 114 | return; 115 | } 116 | 117 | await SendRespondAsync(player, stream, token).ConfigureAwait(false); 118 | 119 | packetData = null; 120 | packetDataLength = 0; 121 | } 122 | catch (Exception exception) 123 | { 124 | m_Logger.LogError("Exception occured: {}", exception); 125 | return; 126 | } 127 | } 128 | } 129 | 130 | private static async Task SendRespondAsync(Player player, NetworkStream stream, CancellationToken token) 131 | { 132 | var responseDocument = player.ConsumePackets(); 133 | var responseBytes = responseDocument.ToBson(); 134 | 135 | /*if (responseDocument["mc"] > 0) 136 | { 137 | m_Logger.LogInformation("Sending packet: {}", responseDocument); 138 | }*/ 139 | 140 | using var ms = new MemoryStream(); 141 | using var bw = new BinaryWriter(ms); 142 | bw.Write(responseBytes.Length + sizeof(int)); 143 | bw.Write(responseBytes); 144 | 145 | await stream.WriteAsync(ms.ToArray(), token).ConfigureAwait(false); 146 | await stream.FlushAsync(token).ConfigureAwait(false); 147 | } 148 | 149 | public async Task StartAsync(CancellationToken cancellationToken) 150 | { 151 | m_TcpListener.Start(); 152 | m_Logger.LogInformation("Server is running!"); 153 | 154 | while (!cancellationToken.IsCancellationRequested) 155 | { 156 | try 157 | { 158 | var client = await m_TcpListener.AcceptTcpClientAsync(cancellationToken).ConfigureAwait(false); 159 | var endPoint = client.Client.LocalEndPoint; 160 | if (endPoint is null) 161 | { 162 | client.Close(); 163 | continue; 164 | } 165 | 166 | if (endPoint is not IPEndPoint iPEndPoint) 167 | { 168 | client.Close(); 169 | continue; 170 | } 171 | 172 | m_Logger.LogInformation("Client {} connected", endPoint); 173 | 174 | var player = m_PlayerManager.AddOrReplacePlayer(iPEndPoint); 175 | var _ = HandleConnectionAsync(client, player, cancellationToken).ContinueWith(async x => 176 | { 177 | if (!m_PlayerManager.RemovePlayer(iPEndPoint)) 178 | { 179 | m_Logger.LogWarning("Failed to remove player with address: {}", iPEndPoint); 180 | } 181 | 182 | m_Logger.LogInformation("Client {} disconnected", endPoint); 183 | 184 | if (player.World is not null && !player.World.RemovePlayer(player)) 185 | { 186 | m_Logger.LogWarning("Failed to remove player with address: {} from world", iPEndPoint); 187 | } 188 | 189 | await m_Database.SavePlayerAsync(PlayerModel.CreateCopy(player)).ConfigureAwait(false); 190 | 191 | client.Close(); 192 | client.Dispose(); 193 | }, cancellationToken); 194 | } 195 | catch (Exception) when (cancellationToken.IsCancellationRequested) 196 | { 197 | } 198 | catch (Exception ex) 199 | { 200 | m_Logger.LogError("Server crashed, exception: {}", ex); 201 | } 202 | } 203 | } 204 | 205 | public void Stop() 206 | { 207 | m_Logger.LogInformation("Stopping server.."); 208 | m_TcpListener.Stop(); 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Constants/CountryCodes.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol; 2 | 3 | public static class CountryCodes 4 | { 5 | public static readonly Dictionary Map = new() 6 | { 7 | { 4, "Afghanistan AFG" }, 8 | { 248, "Åland Islands ALA" }, 9 | { 8, "Albania ALB" }, 10 | { 12, "Algeria DZA" }, 11 | { 16, "American Samoa ASM" }, 12 | { 20, "Andorra AND" }, 13 | { 24, "Angola AGO" }, 14 | { 660, "Anguilla AIA" }, 15 | { 10, "Antarctica ATA" }, 16 | { 28, "Antigua and Barbuda ATG" }, 17 | { 32, "Argentina ARG" }, 18 | { 51, "Armenia ARM" }, 19 | { 533, "Aruba ABW" }, 20 | { 36, "Australia AUS" }, 21 | { 40, "Austria AUT" }, 22 | { 31, "Azerbaijan AZE" }, 23 | { 44, "Bahamas BHS" }, 24 | { 48, "Bahrain BHR" }, 25 | { 50, "Bangladesh BGD" }, 26 | { 52, "Barbados BRB" }, 27 | { 112, "Belarus BLR" }, 28 | { 56, "Belgium BEL" }, 29 | { 84, "Belize BLZ" }, 30 | { 204, "Benin BEN" }, 31 | { 60, "Bermuda BMU" }, 32 | { 64, "Bhutan BTN" }, 33 | { 68, "Bolivia (Plurinational State of) BOL" }, 34 | { 535, "Bonaire, Sint Eustatius and Saba BES" }, 35 | { 70, "Bosnia and Herzegovina BIH" }, 36 | { 72, "Botswana BWA" }, 37 | { 74, "Bouvet Island BVT" }, 38 | { 76, "Brazil BRA" }, 39 | { 86, "British Indian Ocean Territory IOT" }, 40 | { 96, "Brunei Darussalam BRN" }, 41 | { 100, "Bulgaria BGR" }, 42 | { 854, "Burkina Faso BFA" }, 43 | { 108, "Burundi BDI" }, 44 | { 116, "Cambodia KHM" }, 45 | { 120, "Cameroon CMR" }, 46 | { 124, "Canada CAN" }, 47 | { 132, "Cabo Verde CPV" }, 48 | { 136, "Cayman Islands CYM" }, 49 | { 140, "Central African Republic CAF" }, 50 | { 148, "Chad TCD" }, 51 | { 152, "Chile CHL" }, 52 | { 156, "China CHN" }, 53 | { 162, "Christmas Island CXR" }, 54 | { 166, "Cocos (Keeling) Islands CCK" }, 55 | { 170, "Colombia COL" }, 56 | { 174, "Comoros COM" }, 57 | { 178, "Congo COG" }, 58 | { 180, "Congo (Democratic Republic of the) COD" }, 59 | { 184, "Cook Islands COK" }, 60 | { 188, "Costa Rica CRI" }, 61 | { 384, "Côte d'Ivoire CIV" }, 62 | { 191, "Croatia HRV" }, 63 | { 192, "Cuba CUB" }, 64 | { 531, "Curaçao CUW" }, 65 | { 196, "Cyprus CYP" }, 66 | { 203, "Czech Republic CZE" }, 67 | { 208, "Denmark DNK" }, 68 | { 262, "Djibouti DJI" }, 69 | { 212, "Dominica DMA" }, 70 | { 214, "Dominican Republic DOM" }, 71 | { 218, "Ecuador ECU" }, 72 | { 818, "Egypt EGY" }, 73 | { 222, "El Salvador SLV" }, 74 | { 226, "Equatorial Guinea GNQ" }, 75 | { 232, "Eritrea ERI" }, 76 | { 233, "Estonia EST" }, 77 | { 231, "Ethiopia ETH" }, 78 | { 238, "Falkland Islands (Malvinas) FLK" }, 79 | { 234, "Faroe Islands FRO" }, 80 | { 242, "Fiji FJI" }, 81 | { 246, "Finland FIN" }, 82 | { 250, "France FRA" }, 83 | { 254, "French Guiana GUF" }, 84 | { 258, "French Polynesia PYF" }, 85 | { 260, "French Southern Territories ATF" }, 86 | { 266, "Gabon GAB" }, 87 | { 270, "Gambia GMB" }, 88 | { 268, "Georgia GEO" }, 89 | { 276, "Germany DEU" }, 90 | { 288, "Ghana GHA" }, 91 | { 292, "Gibraltar GIB" }, 92 | { 300, "Greece GRC" }, 93 | { 304, "Greenland GRL" }, 94 | { 308, "Grenada GRD" }, 95 | { 312, "Guadeloupe GLP" }, 96 | { 316, "Guam GUM" }, 97 | { 320, "Guatemala GTM" }, 98 | { 831, "Guernsey GGY" }, 99 | { 324, "Guinea GIN" }, 100 | { 624, "Guinea-Bissau GNB" }, 101 | { 328, "Guyana GUY" }, 102 | { 332, "Haiti HTI" }, 103 | { 334, "Heard Island and McDonald Islands HMD" }, 104 | { 336, "Holy See VAT" }, 105 | { 340, "Honduras HND" }, 106 | { 344, "Hong Kong HKG" }, 107 | { 348, "Hungary HUN" }, 108 | { 352, "Iceland ISL" }, 109 | { 356, "India IND" }, 110 | { 360, "Indonesia IDN" }, // indog woof woof 111 | { 364, "Iran (Islamic Republic of) IRN" }, 112 | { 368, "Iraq IRQ" }, 113 | { 372, "Ireland IRL" }, 114 | { 833, "Isle of Man IMN" }, 115 | { 376, "Israel ISR" }, 116 | { 380, "Italy ITA" }, 117 | { 388, "Jamaica JAM" }, 118 | { 392, "Japan JPN" }, 119 | { 832, "Jersey JEY" }, 120 | { 400, "Jordan JOR" }, 121 | { 398, "Kazakhstan KAZ" }, 122 | { 404, "Kenya KEN" }, 123 | { 296, "Kiribati KIR" }, 124 | { 408, "Korea (Democratic People's Republic of) PRK" }, 125 | { 410, "Korea (Republic of) KOR" }, 126 | { 414, "Kuwait KWT" }, 127 | { 417, "Kyrgyzstan KGZ" }, 128 | { 418, "Lao People's Democratic Republic LAO" }, 129 | { 428, "Latvia LVA" }, 130 | { 422, "Lebanon LBN" }, 131 | { 426, "Lesotho LSO" }, 132 | { 430, "Liberia LBR" }, 133 | { 434, "Libya LBY" }, 134 | { 438, "Liechtenstein LIE" }, 135 | { 440, "Lithuania LTU" }, 136 | { 442, "Luxembourg LUX" }, 137 | { 446, "Macao MAC" }, 138 | { 807, "Macedonia (the former Yugoslav Republic of) MKD" }, 139 | { 450, "Madagascar MDG" }, 140 | { 454, "Malawi MWI" }, 141 | { 458, "Malaysia MYS" }, 142 | { 462, "Maldives MDV" }, 143 | { 466, "Mali MLI" }, 144 | { 470, "Malta MLT" }, 145 | { 584, "Marshall Islands MHL" }, 146 | { 474, "Martinique MTQ" }, 147 | { 478, "Mauritania MRT" }, 148 | { 480, "Mauritius MUS" }, 149 | { 175, "Mayotte MYT" }, 150 | { 484, "Mexico MEX" }, 151 | { 583, "Micronesia (Federated States of) FSM" }, 152 | { 498, "Moldova (Republic of) MDA" }, 153 | { 492, "Monaco MCO" }, 154 | { 496, "Mongolia MNG" }, 155 | { 499, "Montenegro MNE" }, 156 | { 500, "Montserrat MSR" }, 157 | { 504, "Morocco MAR" }, 158 | { 508, "Mozambique MOZ" }, 159 | { 104, "Myanmar MMR" }, 160 | { 516, "Namibia NAM" }, 161 | { 520, "Nauru NRU" }, 162 | { 524, "Nepal NPL" }, 163 | { 999, "Neutral" }, 164 | { 528, "Netherlands NLD" }, 165 | { 540, "New Caledonia NCL" }, 166 | { 554, "New Zealand NZL" }, 167 | { 558, "Nicaragua NIC" }, 168 | { 562, "Niger NER" }, 169 | { 566, "Nigeria NGA" }, 170 | { 570, "Niue NIU" }, 171 | { 574, "Norfolk Island NFK" }, 172 | { 580, "Northern Mariana Islands MNP" }, 173 | { 578, "Norway NOR" }, 174 | { 512, "Oman OMN" }, 175 | { 586, "Pakistan PAK" }, 176 | { 585, "Palau PLW" }, 177 | { 275, "Palestine, State of PSE" }, 178 | { 591, "Panama PAN" }, 179 | { 598, "Papua New Guinea PNG" }, 180 | { 600, "Paraguay PRY" }, 181 | { 604, "Peru PER" }, 182 | { 608, "Philippines PHL" }, 183 | { 612, "Pitcairn PCN" }, 184 | { 616, "Poland POL" }, 185 | { 620, "Portugal PRT" }, 186 | { 630, "Puerto Rico PRI" }, 187 | { 634, "Qatar QAT" }, 188 | { 638, "Réunion REU" }, 189 | { 642, "Romania ROU" }, 190 | { 643, "Russian Federation RUS" }, 191 | { 646, "Rwanda RWA" }, 192 | { 652, "Saint Barthélemy BLM" }, 193 | { 654, "Saint Helena, Ascension and Tristan da Cunha SHN" }, 194 | { 659, "Saint Kitts and Nevis KNA" }, 195 | { 662, "Saint Lucia LCA" }, 196 | { 663, "Saint Martin (French part) MAF" }, 197 | { 666, "Saint Pierre and Miquelon SPM" }, 198 | { 670, "Saint Vincent and the Grenadines VCT" }, 199 | { 882, "Samoa WSM" }, 200 | { 674, "San Marino SMR" }, 201 | { 678, "Sao Tome and Principe STP" }, 202 | { 682, "Saudi Arabia SAU" }, 203 | { 686, "Senegal SEN" }, 204 | { 688, "Serbia SRB" }, 205 | { 690, "Seychelles SYC" }, 206 | { 694, "Sierra Leone SLE" }, 207 | { 702, "Singapore SGP" }, 208 | { 534, "Sint Maarten (Dutch part) SXM" }, 209 | { 703, "Slovakia SVK" }, 210 | { 705, "Slovenia SVN" }, 211 | { 90, "Solomon Islands SLB" }, 212 | { 706, "Somalia SOM" }, 213 | { 710, "South Africa ZAF" }, 214 | { 239, "South Georgia and the South Sandwich Islands SGS" }, 215 | { 728, "South Sudan SSD" }, 216 | { 724, "Spain ESP" }, 217 | { 144, "Sri Lanka LKA" }, 218 | { 729, "Sudan SDN" }, 219 | { 740, "Suriname SUR" }, 220 | { 744, "Svalbard and Jan Mayen SJM" }, 221 | { 748, "Swaziland SWZ" }, 222 | { 752, "Sweden SWE" }, 223 | { 756, "Switzerland CHE" }, 224 | { 760, "Syrian Arab Republic SYR" }, 225 | { 158, "Taiwan, Province of China TWN" }, 226 | { 762, "Tajikistan TJK" }, 227 | { 834, "Tanzania, United Republic of TZA" }, 228 | { 764, "Thailand THA" }, 229 | { 626, "Timor-Leste TLS" }, 230 | { 768, "Togo TGO" }, 231 | { 772, "Tokelau TKL" }, 232 | { 776, "Tonga TON" }, 233 | { 780, "Trinidad and Tobago TTO" }, 234 | { 788, "Tunisia TUN" }, 235 | { 792, "Turkey TUR" }, 236 | { 795, "Turkmenistan TKM" }, 237 | { 796, "Turks and Caicos Islands TCA" }, 238 | { 798, "Tuvalu TUV" }, 239 | { 800, "Uganda UGA" }, 240 | { 804, "Ukraine UKR" }, 241 | { 784, "United Arab Emirates ARE" }, 242 | { 826, "United Kingdom of Great Britain and Northern Ireland GBR" }, 243 | { 840, "United States of America USA" }, 244 | { 581, "United States Minor Outlying Islands UMI" }, 245 | { 858, "Uruguay URY" }, 246 | { 860, "Uzbekistan UZB" }, 247 | { 548, "Vanuatu VUT" }, 248 | { 862, "Venezuela (Bolivarian Republic of) VEN" }, 249 | { 704, "Viet Nam VNM" }, 250 | { 92, "Virgin Islands (British) VGB" }, 251 | { 850, "Virgin Islands (U.S.) VIR" }, 252 | { 876, "Wallis and Futuna WLF" }, 253 | { 732, "Western Sahara ESH" }, 254 | { 887, "Yemen YEM" }, 255 | { 894, "Zambia ZMB" }, 256 | { 716, "Zimbabwe ZWE" } 257 | }; 258 | } 259 | -------------------------------------------------------------------------------- /PixelWorldsServer.DataAccess/Models/PlayerModel.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using MongoDB.Bson.Serialization.Options; 4 | using PixelWorldsServer.Protocol.Constants; 5 | using PixelWorldsServer.Protocol.Players; 6 | 7 | namespace PixelWorldsServer.DataAccess.Models; 8 | 9 | public class PlayerModel 10 | { 11 | [BsonId] 12 | [BsonRepresentation(BsonType.ObjectId)] 13 | public string Id { get; set; } = null!; 14 | 15 | public int XP { get; set; } 16 | public int Skin { get; set; } 17 | public int Gems { get; set; } 18 | public int Level { get; set; } 19 | public int Slots { get; set; } 20 | public int OSType { get; set; } 21 | public int ByteCoins { get; set; } 22 | public int Belt1Item { get; set; } 23 | public int CountryCode { get; set; } 24 | public int QuestListCount { get; set; } 25 | public int PassiveEffects { get; set; } 26 | public int ExperienceAmount { get; set; } 27 | public int WelcomeGiftIndex { get; set; } 28 | public int NameChangeCounter { get; set; } 29 | public int DefaultFaceAnimationIndex { get; set; } 30 | public int SkinColorIndexBeforeOverride { get; set; } 31 | 32 | public bool IsStarter { get; set; } 33 | public bool ShowLocation { get; set; } 34 | public bool ShowOnlineStatus { get; set; } 35 | public bool IsFamiliarMaxLvl { get; set; } 36 | public bool TutorialQuestCompleteState { get; set; } 37 | public bool CardGameFaceExpressionsEnabled { get; set; } 38 | public bool CardGameBodyExpressionsEnabled { get; set; } 39 | public bool HasClaimedAdditionalAdBasedDailyBonus { get; set; } 40 | 41 | public float CameraZoomValue { get; set; } 42 | 43 | public string IP { get; set; } = string.Empty; 44 | public string OS { get; set; } = string.Empty; 45 | public string Name { get; set; } = string.Empty; 46 | public string FamiliarName { get; set; } = string.Empty; 47 | 48 | public Gender Gender { get; set; } 49 | public AdminStatus AdminStatus { get; set; } 50 | public PlayerCostumeType Costume { get; set; } 51 | public BlockType FamiliarBlockType { get; set; } 52 | public TutorialState TutorialState { get; set; } 53 | public CameraZoomLevel CameraZoomLevel { get; set; } = CameraZoomLevel.Normal; 54 | 55 | public DateTime VIPEndTime { get; set; } = DateTime.MinValue; 56 | public DateTime DateCreated { get; set; } = DateTime.Now; 57 | public DateTime CostumeEndTime { get; set; } = DateTime.MinValue; 58 | public DateTime LastVIPClaimTime { get; set; } = DateTime.MinValue; 59 | public DateTime LastNormalClaimTime { get; set; } = DateTime.MinValue; 60 | public DateTime NextDailyBonusGiveAway { get; set; } = DateTime.MinValue; 61 | public DateTime LastFreePrizeClaimTime { get; set; } = DateTime.MinValue; 62 | public DateTime NextVIPDailyBonusClaim { get; set; } = DateTime.MinValue; 63 | public DateTime NextDailyAdsRefreshTime { get; set; } = DateTime.MinValue; 64 | public DateTime NextWelcomeGiftClaimTime { get; set; } = DateTime.MinValue; 65 | public DateTime NextNormalDailyBonusClaim { get; set; } = DateTime.MinValue; 66 | public DateTime NextDailyPvpRewardsRefreshTime { get; set; } = DateTime.MinValue; 67 | 68 | public int[] Statistics { get; set; } = null!; 69 | public BlockType[] Spots { get; set; } = null!; 70 | public int[] QuestCurrentPhase { get; set; } = null!; 71 | public string[] QuestCurrentID { get; set; } = null!; 72 | public byte[] InstructionStates { get; set; } = null!; 73 | public long[] DailyQuestNextAvailList { get; set; } = null!; 74 | public int[] InstructionStatesAmounts { get; set; } = null!; 75 | public int[] AchievementCurrentValues { get; set; } = null!; 76 | public byte[] AchievementRewardsClaimed { get; set; } = null!; 77 | public byte[] AchievementsCompletedStates { get; set; } = null!; 78 | public string[] AlreadyBoughtOneTimeItems { get; set; } = null!; 79 | public string[] PreviousThreeDailyQuestIds { get; set; } = null!; 80 | public AnimationNames[] FaceExpressionListId { get; set; } = null!; 81 | public AnimationNames[] BoughtExpressionsList { get; set; } = null!; 82 | 83 | [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] 84 | public Dictionary Inventory { get; set; } = new(); 85 | 86 | [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] 87 | public Dictionary InventoryItemData { get; set; } = new(); 88 | 89 | public PlayerModel() 90 | { 91 | Statistics = Enumerable.Repeat(0, (int)StatisticsKey.LAST_VALUE).ToArray(); 92 | Spots = new BlockType[(int)AnimationHotSpots.END_OF_THE_ENUM] // DefaultMaleHotSpotsBlockTypes 93 | { 94 | BlockType.None, 95 | BlockType.BasicFace, 96 | BlockType.BasicEyebrows, 97 | BlockType.BasicEyeballs, 98 | BlockType.None, 99 | BlockType.BasicMouth, 100 | BlockType.BasicTorso, 101 | BlockType.BasicTopArm, 102 | BlockType.BasicBottomArm, 103 | BlockType.BasicLegs, 104 | BlockType.None, 105 | BlockType.None, 106 | BlockType.None, 107 | BlockType.None, 108 | BlockType.None, 109 | BlockType.None, 110 | BlockType.None, 111 | BlockType.None, 112 | BlockType.None, 113 | BlockType.None, 114 | BlockType.None, 115 | BlockType.Underwear, 116 | BlockType.None, 117 | BlockType.None, 118 | BlockType.None, 119 | BlockType.None, 120 | BlockType.None, 121 | BlockType.None, 122 | BlockType.None, 123 | BlockType.None, 124 | BlockType.None, 125 | BlockType.BasicEyelashes, 126 | BlockType.Underwear, 127 | BlockType.None, 128 | BlockType.None, 129 | }; 130 | QuestCurrentID = Array.Empty(); 131 | QuestCurrentPhase = Array.Empty(); 132 | InstructionStates = new byte[(int)InstructionEventsCompleted.InstructionEventVariables_Count]; 133 | FaceExpressionListId = new AnimationNames[] 134 | { 135 | AnimationNames.FaceContent, 136 | AnimationNames.FaceLaugh, 137 | AnimationNames.FaceAngryMutru, 138 | AnimationNames.FaceSad, 139 | AnimationNames.FaceSuspicious, 140 | AnimationNames.RockRock, 141 | AnimationNames.Applause, 142 | AnimationNames.ThumbsUp, 143 | AnimationNames.Wink, 144 | AnimationNames.Waveone 145 | }; 146 | BoughtExpressionsList = Array.Empty(); 147 | DailyQuestNextAvailList = new long[] { 0, 0, 0 }; 148 | InstructionStatesAmounts = new int[] { 0 }; // only 0? idk 149 | AchievementCurrentValues = new int[(int)Achievement.Achievement_Count]; 150 | AlreadyBoughtOneTimeItems = Array.Empty(); 151 | AchievementRewardsClaimed = new byte[(int)Achievement.Achievement_Count]; 152 | PreviousThreeDailyQuestIds = Array.Empty(); 153 | AchievementsCompletedStates = new byte[(int)Achievement.Achievement_Count]; 154 | } 155 | 156 | public void LoadCopy(PlayerModel playerModel) 157 | { 158 | Id = playerModel.Id; 159 | 160 | XP = playerModel.XP; 161 | Skin = playerModel.Skin; 162 | Gems = playerModel.Gems; 163 | Level = playerModel.Level; 164 | Slots = playerModel.Slots; 165 | OSType = playerModel.OSType; 166 | ByteCoins = playerModel.ByteCoins; 167 | Belt1Item = playerModel.Belt1Item; 168 | CountryCode = playerModel.CountryCode; 169 | QuestListCount = playerModel.QuestListCount; 170 | PassiveEffects = playerModel.PassiveEffects; 171 | ExperienceAmount = playerModel.ExperienceAmount; 172 | WelcomeGiftIndex = playerModel.WelcomeGiftIndex; 173 | NameChangeCounter = playerModel.NameChangeCounter; 174 | DefaultFaceAnimationIndex = playerModel.DefaultFaceAnimationIndex; 175 | SkinColorIndexBeforeOverride = playerModel.SkinColorIndexBeforeOverride; 176 | 177 | IsStarter = playerModel.IsStarter; 178 | ShowLocation = playerModel.ShowLocation; 179 | ShowOnlineStatus = playerModel.ShowOnlineStatus; 180 | IsFamiliarMaxLvl = playerModel.IsFamiliarMaxLvl; 181 | TutorialQuestCompleteState = playerModel.TutorialQuestCompleteState; 182 | CardGameBodyExpressionsEnabled = playerModel.CardGameBodyExpressionsEnabled; 183 | CardGameFaceExpressionsEnabled = playerModel.CardGameFaceExpressionsEnabled; 184 | HasClaimedAdditionalAdBasedDailyBonus = playerModel.HasClaimedAdditionalAdBasedDailyBonus; 185 | 186 | CameraZoomValue = playerModel.CameraZoomValue; 187 | 188 | IP = playerModel.IP; 189 | OS = playerModel.OS; 190 | Name = playerModel.Name; 191 | FamiliarName = playerModel.FamiliarName; 192 | 193 | Gender = playerModel.Gender; 194 | AdminStatus = playerModel.AdminStatus; 195 | Costume = playerModel.Costume; 196 | FamiliarBlockType = playerModel.FamiliarBlockType; 197 | TutorialState = playerModel.TutorialState; 198 | CameraZoomLevel = playerModel.CameraZoomLevel; 199 | 200 | VIPEndTime = playerModel.VIPEndTime; 201 | DateCreated = playerModel.DateCreated; 202 | CostumeEndTime = playerModel.CostumeEndTime; 203 | LastVIPClaimTime = playerModel.LastVIPClaimTime; 204 | LastNormalClaimTime = playerModel.LastNormalClaimTime; 205 | NextDailyBonusGiveAway = playerModel.NextDailyBonusGiveAway; 206 | LastFreePrizeClaimTime = playerModel.LastFreePrizeClaimTime; 207 | NextVIPDailyBonusClaim = playerModel.NextVIPDailyBonusClaim; 208 | NextDailyAdsRefreshTime = playerModel.NextDailyAdsRefreshTime; 209 | NextWelcomeGiftClaimTime = playerModel.NextWelcomeGiftClaimTime; 210 | NextNormalDailyBonusClaim = playerModel.NextNormalDailyBonusClaim; 211 | NextDailyPvpRewardsRefreshTime = playerModel.NextDailyPvpRewardsRefreshTime; 212 | 213 | Statistics = playerModel.Statistics; 214 | Spots = playerModel.Spots; 215 | QuestCurrentPhase = playerModel.QuestCurrentPhase; 216 | QuestCurrentID = playerModel.QuestCurrentID; 217 | InstructionStates = playerModel.InstructionStates; 218 | DailyQuestNextAvailList = playerModel.DailyQuestNextAvailList; 219 | InstructionStatesAmounts = playerModel.InstructionStatesAmounts; 220 | AchievementCurrentValues = playerModel.AchievementCurrentValues; 221 | AchievementRewardsClaimed = playerModel.AchievementRewardsClaimed; 222 | AchievementsCompletedStates = playerModel.AchievementsCompletedStates; 223 | AlreadyBoughtOneTimeItems = playerModel.AlreadyBoughtOneTimeItems; 224 | PreviousThreeDailyQuestIds = playerModel.PreviousThreeDailyQuestIds; 225 | FaceExpressionListId = playerModel.FaceExpressionListId; 226 | BoughtExpressionsList = playerModel.BoughtExpressionsList; 227 | 228 | Inventory = playerModel.Inventory; 229 | InventoryItemData = playerModel.InventoryItemData; 230 | } 231 | 232 | public static PlayerModel CreateCopy(PlayerModel playerModel) 233 | { 234 | PlayerModel result = new(); 235 | result.LoadCopy(playerModel); 236 | return result; 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/PlayerDataResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson; 2 | using MongoDB.Bson.Serialization.Attributes; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | 6 | namespace PixelWorldsServer.Protocol.Packet.Response; 7 | 8 | public class PlayerDataResponse 9 | { 10 | [BsonElement(NetStrings.PLAYER_USERNAME_KEY)] 11 | public string Username { get; set; } = string.Empty; 12 | 13 | [BsonElement(NetStrings.TUTORIAL_STATE_FIELD_KEY)] 14 | public int TutorialState { get; set; } 15 | 16 | [BsonElement(NetStrings.CAMERA_ZOOM_LEVEL_FIELD_KEY)] 17 | public int CameraZoomLevel { get; set; } 18 | 19 | [BsonElement(NetStrings.CAMERA_ZOOM_VALUE_FIELD_KEY)] 20 | public float CameraZoomValue { get; set; } 21 | 22 | [BsonElement(NetStrings.GEMS_FIELD_KEY)] 23 | public int Gems { get; set; } 24 | 25 | [BsonElement(NetStrings.BYTE_COINS_FIELD_KEY)] 26 | public int ByteCoins { get; set; } 27 | 28 | [BsonElement(NetStrings.SLOTS_FIELD_KEY)] 29 | public int Slots { get; set; } 30 | 31 | [BsonElement(NetStrings.INVENTORY_FIELD_KEY)] 32 | public byte[] Inventory { get; set; } = null!; 33 | 34 | [BsonElement(NetStrings.INVENTORY_DATA_FIELD_KEY)] 35 | public BsonDocument InventoryData { get; set; } = new(); 36 | 37 | [BsonElement(NetStrings.BELT1_FIELD_KEY)] 38 | public int Belt1Item { get; set; } 39 | 40 | [BsonElement(NetStrings.SPOTS_FIELD_KEY)] 41 | public BlockType[] Spots { get; set; } = null!; 42 | 43 | [BsonElement(NetStrings.FAMILIAR_BLOCK_TYPE_FIELD_KEY)] 44 | public BlockType FamiliarBlockType { get; set; } 45 | 46 | [BsonElement(NetStrings.PLAYER_COSTUME_FIELD_KEY)] 47 | public PlayerCostumeType PlayerCostume { get; set; } 48 | 49 | [BsonElement(NetStrings.PLAYER_COSTUME_END_TIME_FIELD_KEY)] 50 | public long PlayerCostumeEndTime { get; set; } 51 | 52 | [BsonElement(NetStrings.FAMILIAR_NAME_FIELD_KEY)] 53 | public string FamiliarName { get; set; } = string.Empty; 54 | 55 | [BsonElement(NetStrings.IS_FAMILIAR_MAX_LVL_FIELD_KEY)] 56 | public bool IsFamiliarMaxLvl { get; set; } 57 | 58 | [BsonElement(NetStrings.FACE_ANIM_FIELD_KEY)] 59 | public int DefaultFaceAnimationIndex { get; set; } 60 | 61 | [BsonElement(NetStrings.SKIN_INDEX_FIELD_KEY)] 62 | public int SkinColorIndex { get; set; } 63 | 64 | [BsonElement(NetStrings.GENDER_FIELD_KEY)] 65 | public Gender Gender { get; set; } 66 | 67 | [BsonElement(NetStrings.NORMAL_CLAIM_TIME_FIELD_KEY)] 68 | public long LastNormalClaimTime { get; set; } 69 | 70 | [BsonElement(NetStrings.VIP_CLAIM_TIME_FIELD_KEY)] 71 | public long LastVIPClaimTime { get; set; } 72 | 73 | [BsonElement(NetStrings.HAS_CLAIMED_ADDITIONAL_FIELD_KEY)] 74 | public bool HasClaimedAdditionalAdBasedDailyBonus { get; set; } 75 | 76 | [BsonElement(NetStrings.STATISTICS_FIELD_KEY)] 77 | public int[] Statistics { get; set; } = null!; 78 | 79 | [BsonElement(NetStrings.ACCOUNT_AGE_FIELD_KEY)] 80 | public long AccountAge { get; set; } 81 | 82 | [BsonElement(NetStrings.COUNTRY_CODE_FIELD_KEY)] 83 | public int CountryCode { get; set; } 84 | 85 | [BsonElement(NetStrings.VIP_END_TIME_FIELD_KEY)] 86 | public long VIPEndTime { get; set; } 87 | 88 | [BsonElement(NetStrings.NAME_CHANGE_COUNTER_FIELD_KEY)] 89 | public int NameChangeCounter { get; set; } 90 | 91 | [BsonElement(NetStrings.EXPERIENCE_AMOUNT_FIELD_KEY)] 92 | public int ExperienceAmount { get; set; } 93 | 94 | [BsonElement(NetStrings.XP_AMOUNT_FIELD_KEY)] 95 | public int XPAmount { get; set; } 96 | 97 | [BsonElement(NetStrings.NEXT_DAILY_BONUS_GIVEAWAY_FIELD_KEY)] 98 | public long NextDailyBonusGiveAway { get; set; } 99 | 100 | [BsonElement(NetStrings.NEXT_NORMAL_DAILY_BONUS_CLAIM_FIELD_KEY)] 101 | public long NextNormalDailyBonusClaim { get; set; } 102 | 103 | [BsonElement(NetStrings.NEXT_VIP_DAILY_BONUS_CLAIM_FIELD_KEY)] 104 | public long NextVIPDailyBonusClaim { get; set; } 105 | 106 | [BsonElement(NetStrings.NEXT_DAILY_ADS_REFRESH_TIME_FIELD_KEY)] 107 | public long NextDailyAdsRefreshTime { get; set; } 108 | 109 | [BsonElement(NetStrings.NEXT_DAILY_PVP_REWARDS_REFRESH_TIME_FIELD_KEY)] 110 | public long NextDailyPvpRewardsRefreshTime { get; set; } 111 | 112 | [BsonElement(NetStrings.LAST_FREE_PRIZE_CLAIM_TIME_FIELD_KEY)] 113 | public long LastFreePrizeClaimTime { get; set; } 114 | 115 | [BsonElement(NetStrings.NEXT_WELCOME_GIFT_CLAIM_TIME_FIELD_KEY)] 116 | public long NextWelcomeGiftClaimTime { get; set; } 117 | 118 | [BsonElement(NetStrings.WELCOME_GIFT_INDEX_FIELD_KEY)] 119 | public int WelcomeGiftIndex { get; set; } 120 | 121 | [BsonElement(NetStrings.PLAYER_ADMIN_STATUS_FIELD_KEY)] 122 | public int AdminStatus { get; set; } 123 | 124 | [BsonElement(NetStrings.SHOW_LOCATION_FIELD_KEY)] 125 | public bool ShowLocation { get; set; } 126 | 127 | [BsonElement(NetStrings.SHOW_ONLINE_STATUS_FIELD_KEY)] 128 | public bool ShowOnlineStatus { get; set; } 129 | 130 | [BsonElement(NetStrings.GENERIC_VERSIONING_FIELD_KEY)] 131 | public int[] GenericVersioning { get; set; } = null!; 132 | 133 | [BsonElement(NetStrings.PASSIVE_EFFECTS_FIELD_KEY)] 134 | public int PassiveEffects { get; set; } 135 | 136 | [BsonElement(NetStrings.INSTRUCTION_STATES_AMOUNTS_FIELD_KEY)] 137 | public int[] InstructionStatesAmounts { get; set; } = null!; 138 | 139 | [BsonElement(NetStrings.INSTRUCTION_STATES_FIELD_KEY)] 140 | public byte[] InstructionStates { get; set; } = null!; 141 | 142 | [BsonElement(NetStrings.ACHIEVEMENT_CURRENT_VALUES_FIELD_KEY)] 143 | public int[] AchievementCurrentValues { get; set; } = null!; 144 | 145 | [BsonElement(NetStrings.ACHIEVEMENT_COMPLETED_STATES_FIELD_KEY)] 146 | public byte[] AchievementsCompletedStates { get; set; } = null!; 147 | 148 | [BsonElement(NetStrings.ACHIEVEMENT_REWARDS_CLAIMED_FIELD_KEY)] 149 | public byte[] AchievementRewardsClaimed { get; set; } = null!; 150 | 151 | [BsonElement(NetStrings.QUEST_LIST_COUNT_FIELD_KEY)] 152 | public int QuestListCount { get; set; } 153 | 154 | [BsonElement(NetStrings.QUEST_CURRENT_ID_FIELD_KEY)] 155 | public string[] QuestCurrentID { get; set; } = null!; 156 | 157 | [BsonElement(NetStrings.QUEST_CURRENT_PHASE_FIELD_KEY)] 158 | public int[] QuestCurrentPhase { get; set; } = null!; 159 | 160 | [BsonElement(NetStrings.FACE_EXPRESSION_LIST_ID_FIELD_KEY)] 161 | public AnimationNames[] FaceExpressionListID { get; set; } = null!; 162 | 163 | [BsonElement(NetStrings.BOUGHT_EXPRESSIONS_LIST_FIELD_KEY)] 164 | public AnimationNames[] BoughtExpressionsList { get; set; } = null!; 165 | 166 | [BsonElement(NetStrings.ALREADY_BOUGHT_ONE_TIME_ITEMS_FIELD_KEY)] 167 | public string[] AlreadyBoughtOneTimeItems { get; set; } = null!; 168 | 169 | [BsonElement(NetStrings.DAILY_QUEST_NEXT_AVAILABLE_LIST_FIELD_KEY)] 170 | public long[] DailyQuestNextAvailList { get; set; } = null!; 171 | 172 | [BsonElement(NetStrings.PREVIOUS_THREE_DAILY_QUEST_IDS_FIELD_KEY)] 173 | public string[] PreviousThreeDailyQuestIds { get; set; } = null!; 174 | 175 | [BsonElement(NetStrings.TUTORIAL_1_CURRENT_STEP_FIELD_KEY)] 176 | public int Tutorial1CurrentStep { get; set; } 177 | 178 | [BsonElement(NetStrings.TUTORIAL_1_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY)] 179 | public int[] Tutorial1TrackQuestStepProgress { get; set; } = null!; 180 | 181 | [BsonElement(NetStrings.TUTORIAL_2_CURRENT_STEP_FIELD_KEY)] 182 | public int Tutorial2CurrentStep { get; set; } 183 | 184 | [BsonElement(NetStrings.TUTORIAL_2_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY)] 185 | public int[] Tutorial2TrackQuestStepProgress { get; set; } = null!; 186 | 187 | [BsonElement(NetStrings.TUTORIAL_3_CURRENT_STEP_FIELD_KEY)] 188 | public int Tutorial3CurrentStep { get; set; } 189 | 190 | [BsonElement(NetStrings.TUTORIAL_3_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY)] 191 | public int[] Tutorial3TrackQuestStepProgress { get; set; } = null!; 192 | 193 | [BsonElement(NetStrings.TUTORIAL_4_CURRENT_STEP_FIELD_KEY)] 194 | public int Tutorial4CurrentStep { get; set; } 195 | 196 | [BsonElement(NetStrings.TUTORIAL_4_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY)] 197 | public int[] Tutorial4TrackQuestStepProgress { get; set; } = null!; 198 | 199 | [BsonElement(NetStrings.TUTORIAL_5_CURRENT_STEP_FIELD_KEY)] 200 | public int Tutorial5CurrentStep { get; set; } 201 | 202 | [BsonElement(NetStrings.TUTORIAL_5_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY)] 203 | public int[] Tutorial5TrackQuestStepProgress { get; set; } = null!; 204 | 205 | [BsonElement(NetStrings.TUTORIAL_5_INVENTORY_SIZE_KEY)] 206 | public int Tutorial5InventorySize { get; set; } 207 | 208 | [BsonElement(NetStrings.TUTORIAL_6_CURRENT_STEP_FIELD_KEY)] 209 | public int Tutorial6CurrentStep { get; set; } 210 | 211 | [BsonElement(NetStrings.TUTORIAL_6_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY)] 212 | public int[] Tutorial6TrackQuestStepProgress { get; set; } = null!; 213 | 214 | [BsonElement(NetStrings.TUTORIAL_7_CURRENT_STEP_FIELD_KEY)] 215 | public int Tutorial7CurrentStep { get; set; } 216 | 217 | [BsonElement(NetStrings.TUTORIAL_7_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY)] 218 | public int[] Tutorial7TrackQuestStepProgress { get; set; } = null!; 219 | 220 | [BsonElement(NetStrings.TUTORIAL_8_CURRENT_STEP_FIELD_KEY)] 221 | public int Tutorial8CurrentStep { get; set; } 222 | 223 | [BsonElement(NetStrings.TUTORIAL_8_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY)] 224 | public int[] Tutorial8TrackQuestStepProgress { get; set; } = null!; 225 | 226 | [BsonElement(NetStrings.TUTORIAL_8_QUEST_VISITED_WORLDS_LIST_FIELD_KEY)] 227 | public int[] Tutorial8QuestVisitedWorldsList { get; set; } = null!; 228 | 229 | [BsonElement(NetStrings.TUTORIAL_9_CURRENT_STEP_FIELD_KEY)] 230 | public int Tutorial9CurrentStep { get; set; } 231 | 232 | [BsonElement(NetStrings.TUTORIAL_9_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY)] 233 | public int[] Tutorial9TrackQuestStepProgress { get; set; } = null!; 234 | 235 | [BsonElement(NetStrings.TUTORIAL_9_QUEST_VISITED_WORLDS_LIST_FIELD_KEY)] 236 | public int[] Tutorial9QuestVisitedWorldsList { get; set; } = null!; 237 | 238 | [BsonElement(NetStrings.TUTORIAL_10_CURRENT_STEP_FIELD_KEY)] 239 | public int Tutorial10CurrentStep { get; set; } 240 | 241 | [BsonElement(NetStrings.TUTORIAL_10_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY)] 242 | public int[] Tutorial10TrackQuestStepProgress { get; set; } = null!; 243 | 244 | [BsonElement(NetStrings.TUTORIAL_11_CURRENT_STEP_FIELD_KEY)] 245 | public int Tutorial11CurrentStep { get; set; } 246 | 247 | [BsonElement(NetStrings.TUTORIAL_11_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY)] 248 | public int[] Tutorial11TrackQuestStepProgress { get; set; } = null!; 249 | 250 | [BsonElement(NetStrings.TUTORIAL_ID_LIST_FIELD_KEY)] 251 | public string[] TutorialIDList { get; set; } = null!; 252 | 253 | [BsonElement(NetStrings.TUTORIAL_QUEST_COMPLETE_STATE_FIELD_KEY)] 254 | public bool TutorialQuestCompleteState { get; set; } 255 | 256 | [BsonElement(NetStrings.LIMITED_OFFERS_FIELD_KEY)] 257 | public BsonDocument LimitedOffers { get; set; } = null!; 258 | 259 | [BsonElement(NetStrings.LIMITED_OFFERS_USED_FIELD_KEY)] 260 | public BsonDocument LimitedOffersUsed { get; set; } = null!; 261 | 262 | [BsonElement(NetStrings.IS_STARTER_FIELD_KEY)] 263 | public bool IsStarter { get; set; } 264 | 265 | [BsonElement(NetStrings.CARD_GAME_FACE_EXPRESSIONS_ENABLED_FIELD_KEY)] 266 | public bool CardGameFaceExpressionsEnabled { get; set; } 267 | 268 | [BsonElement(NetStrings.CARD_GAME_BODY_EXPRESSIONS_ENABLED_FIELD_KEY)] 269 | public bool CardGameBodyExpressionsEnabled { get; set; } 270 | 271 | [BsonElement(NetStrings.FTUE_SOLD_ITEM_IDS_FIELD_KEY)] 272 | public BsonDocument FTUESoldItemIDs { get; set; } = null!; 273 | 274 | [BsonElement(NetStrings.SKIN_COLOR_INDEX_BEFORE_OVERRIDE_FIELD_KEY)] 275 | public int SkinColorIndexBeforeOverride { get; set; } 276 | } 277 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/Worlds/World.cs: -------------------------------------------------------------------------------- 1 | using PixelWorldsServer.DataAccess.Models; 2 | using PixelWorldsServer.Protocol.Constants; 3 | using PixelWorldsServer.Protocol.Packet.Response; 4 | using PixelWorldsServer.Protocol.Players; 5 | using PixelWorldsServer.Protocol.Utils; 6 | using PixelWorldsServer.Protocol.Worlds; 7 | using PixelWorldsServer.Server.Players; 8 | using System.Collections.Concurrent; 9 | 10 | namespace PixelWorldsServer.Server.Worlds; 11 | 12 | public class World : WorldModel 13 | { 14 | private int m_BedrockRows; 15 | 16 | public ConcurrentDictionary Players { get; set; } = new(); 17 | 18 | public bool AddPlayer(Player player) 19 | { 20 | player.World = this; 21 | return Players.TryAdd(player.Id, player); 22 | } 23 | 24 | public bool RemovePlayer(Player player) 25 | { 26 | player.World = null; 27 | 28 | if (Players.TryRemove(player.Id, out _)) 29 | { 30 | if (!Players.IsEmpty) 31 | { 32 | var notification = new PlayerLeftResponse() 33 | { 34 | ID = NetStrings.PLAYER_LEFT_KEY, 35 | PlayerId = player.Id 36 | }; 37 | 38 | foreach (var (_, otherPlayer) in Players) 39 | { 40 | otherPlayer.SendPacket(notification); 41 | } 42 | } 43 | 44 | return true; 45 | } 46 | 47 | return false; 48 | } 49 | 50 | public void ResetCollectables() 51 | { 52 | InventoryId = 0; 53 | Collectables.Clear(); 54 | } 55 | 56 | 57 | private void SetDefaultWorldSize() 58 | { 59 | Size.X = 80; 60 | Size.Y = 60; 61 | } 62 | 63 | private void SetDefaultBedrockRows() 64 | { 65 | m_BedrockRows = 3; 66 | } 67 | 68 | public LayerBlock GetBlock(int index) 69 | { 70 | return BlockLayer[index]; 71 | } 72 | 73 | public LayerBlock GetBlock(int x, int y) 74 | { 75 | return GetBlock(x + y * Size.X); 76 | } 77 | 78 | public SeedData? GetSeed(int index) 79 | { 80 | return PlantedSeeds[index]; 81 | } 82 | 83 | public SeedData? GetSeed(int x, int y) 84 | { 85 | return GetSeed(x + y * Size.X); 86 | } 87 | 88 | public LayerBlockBackground GetBackground(int index) 89 | { 90 | return BlockBackgroundLayer[index]; 91 | } 92 | 93 | public LayerBlockBackground GetBackground(int x, int y) 94 | { 95 | return GetBackground(x + y * Size.X); 96 | } 97 | 98 | public void SetSeed(int index, SeedData seed) 99 | { 100 | PlantedSeeds[index] = seed; 101 | } 102 | 103 | public void SetSeed(int x, int y, SeedData seed) 104 | { 105 | SetSeed(x + y * Size.X, seed); 106 | } 107 | 108 | public void SetBlock(int index, BlockType blockType) 109 | { 110 | BlockLayer[index].BlockType = blockType; 111 | BlockLayer[index].LastHitTime = DateTime.UtcNow; 112 | BlockLayer[index].HitsRequired = ConfigData.BlockHitPoints[(int)blockType]; 113 | } 114 | 115 | public void SetBlock(int x, int y, BlockType blockType) 116 | { 117 | SetBlock(x + y * Size.X, blockType); 118 | } 119 | 120 | public void SetBlockBackground(int index, BlockType blockType) 121 | { 122 | BlockBackgroundLayer[index].BlockType = blockType; 123 | BlockBackgroundLayer[index].LastHitTime = DateTime.UtcNow; 124 | BlockBackgroundLayer[index].HitsRequired = ConfigData.BlockHitPoints[(int)blockType]; 125 | } 126 | 127 | public void SetBlockBackground(int x, int y, BlockType blockType) 128 | { 129 | SetBlockBackground(x + y * Size.X, blockType); 130 | } 131 | 132 | public void InitBlocks() 133 | { 134 | int size = Size.X * Size.Y; 135 | for (int i = 0; i < size; ++i) 136 | { 137 | ItemDatas.Add(null); 138 | BlockLayer.Add(new LayerBlock()); 139 | PlantedSeeds.Add(null); 140 | BlockWaterLayer.Add(new LayerBlock()); 141 | BlockWiringLayer.Add(new LayerWiring()); 142 | BlockBackgroundLayer.Add(new LayerBlockBackground()); 143 | } 144 | } 145 | 146 | 147 | public void Init(string name, WorldLayoutType worldLayoutType) 148 | { 149 | Name = name; 150 | 151 | switch (worldLayoutType) 152 | { 153 | case WorldLayoutType.Basic: 154 | case WorldLayoutType.BasicWithBots: 155 | case WorldLayoutType.BasicWithCollectables: 156 | { 157 | LayerBackgroundType = LayerBackgroundType.ForestBackground; 158 | SetDefaultWorldSize(); 159 | SetDefaultBedrockRows(); 160 | InitBlocks(); 161 | 162 | int bottomLayerHeight = 10; 163 | int middleLayerHeight = 16; 164 | int topLayerHeight = 1; 165 | 166 | ShuffleBag bottomLayerShuffleBag = new(); 167 | ShuffleBag middleLayerShuffleBag = new(); 168 | ShuffleBag topLayerShuffleBag = new(); 169 | 170 | { 171 | int obsidianCount = 7; 172 | int marbleCount = 7; 173 | int lavaCount = 25; 174 | int graniteCount = 20; 175 | int soilBlockCount = bottomLayerHeight * Size.X - lavaCount - graniteCount - obsidianCount - marbleCount; 176 | 177 | bottomLayerShuffleBag.Add(BlockType.SoilBlock, soilBlockCount); 178 | bottomLayerShuffleBag.Add(BlockType.Lava, lavaCount); 179 | bottomLayerShuffleBag.Add(BlockType.Granite, graniteCount); 180 | bottomLayerShuffleBag.Add(BlockType.Obsidian, obsidianCount); 181 | bottomLayerShuffleBag.Add(BlockType.Marble, marbleCount); 182 | } 183 | 184 | { 185 | 186 | int graniteCount = 40; 187 | int soilBlockCount = middleLayerHeight * Size.X - graniteCount; 188 | 189 | middleLayerShuffleBag.Add(BlockType.SoilBlock, soilBlockCount); 190 | middleLayerShuffleBag.Add(BlockType.Granite, graniteCount); 191 | } 192 | 193 | { 194 | int soilBlockCount = topLayerHeight * Size.X; 195 | 196 | topLayerShuffleBag.Add(BlockType.SoilBlock, soilBlockCount); 197 | } 198 | 199 | for (int i = 0; i < Size.X; i++) 200 | { 201 | for (int j = 0; j < m_BedrockRows + bottomLayerHeight + middleLayerHeight + topLayerHeight; j++) 202 | { 203 | var position = new Vector2i(i, j); 204 | 205 | if (j < m_BedrockRows) 206 | { 207 | if (j < m_BedrockRows - 2) 208 | { 209 | SetBlock(i, j, BlockType.EndLava); 210 | } 211 | else if (j < m_BedrockRows - 1) 212 | { 213 | SetBlock(i, j, BlockType.EndLavaRock); 214 | } 215 | else 216 | { 217 | SetBlock(i, j, BlockType.Bedrock); 218 | } 219 | 220 | continue; 221 | } 222 | 223 | SetBlockBackground(position.X, position.Y, BlockType.CaveWall); 224 | 225 | if (j < m_BedrockRows + bottomLayerHeight) 226 | { 227 | SetBlock(position.X, position.Y, bottomLayerShuffleBag.Next()); 228 | } 229 | else if (j >= m_BedrockRows + bottomLayerHeight + middleLayerHeight) 230 | { 231 | SetBlock(position.X, position.Y, topLayerShuffleBag.Next()); 232 | } 233 | else 234 | { 235 | SetBlock(position.X, position.Y, middleLayerShuffleBag.Next()); 236 | } 237 | } 238 | } 239 | 240 | StartingPoint = new Vector2i(Size.X / 2, Size.Y / 2); 241 | SetBlock(StartingPoint.X, StartingPoint.Y, BlockType.EntrancePortal); 242 | break; 243 | } 244 | 245 | default: 246 | { 247 | throw new Exception("Invalid world layout type"); 248 | } 249 | } 250 | } 251 | 252 | public CollectableData AddCollectable(BlockType blockType, short amount, InventoryItemType inventoryItemType, Vector2i mapPoint, InventoryItemBase inventoryData) 253 | { 254 | var newInventoryId = InventoryId++; 255 | var posX = mapPoint.X + RollDrops.RollPosition(ConfigData.RollCollectableXMin, ConfigData.RollCollectableXMax) * 0.01f; 256 | var posY = mapPoint.Y + RollDrops.RollPosition(ConfigData.RollCollectableYMin, ConfigData.RollCollectableYMax) * 0.01f; 257 | var collectableData = new CollectableData(newInventoryId, blockType, amount, inventoryItemType, posX, posY, inventoryData); 258 | Collectables.Add(collectableData); 259 | return collectableData; 260 | } 261 | 262 | public CollectableData AddCollectable(BlockType blockType, short amount, InventoryItemType inventoryItemType, float x, float y) 263 | { 264 | var newInventoryId = InventoryId++; 265 | var collectableData = new CollectableData(newInventoryId, blockType, amount, inventoryItemType, x, y, null!); 266 | Collectables.Add(collectableData); 267 | return collectableData; 268 | } 269 | 270 | public CollectableData[] AddCollectableGems(short gemAmount, Vector2i mapPoint) 271 | { 272 | var list = new List(); 273 | var array = ConfigData.SplitGemValueToGems(gemAmount); 274 | 275 | for (int i = 0; i < array.Length; i++) 276 | { 277 | int num = array[i]; 278 | for (int j = 0; j < num; j++) 279 | { 280 | int newInventoryId = InventoryId++; 281 | var posX = mapPoint.X + RollDrops.RollPosition(ConfigData.RollCollectableXMin, ConfigData.RollCollectableXMax) * 0.01f; 282 | var posY = mapPoint.Y + RollDrops.RollPosition(ConfigData.RollCollectableYMin, ConfigData.RollCollectableYMax) * 0.01f; 283 | 284 | var item = new CollectableData(newInventoryId, 1, posX, posY, (GemType)i); 285 | Collectables.Add(item); 286 | list.Add(item); 287 | } 288 | } 289 | 290 | return list.ToArray(); 291 | } 292 | 293 | public List? RandomizeCollectablesForDestroyedBlock(Vector2i mapPoint, BlockType blockType) 294 | { 295 | var list = new List(); 296 | 297 | short seedsCount; 298 | short blocksCount; 299 | short gemsCount; 300 | short extraBlocksCount; 301 | BlockType extraBlock; 302 | if (blockType == BlockType.Tree) 303 | { 304 | var seedDataAt = PlantedSeeds[mapPoint.X + mapPoint.Y * Size.X]; 305 | if (seedDataAt is null || seedDataAt.GrowthEndTime > DateTime.Now) 306 | { 307 | return null; 308 | } 309 | 310 | gemsCount = seedDataAt.HarvestGems; 311 | blockType = seedDataAt.BlockType; 312 | seedsCount = seedDataAt.HarvestSeeds; 313 | blocksCount = seedDataAt.HarvestBlocks; 314 | extraBlocksCount = seedDataAt.HarvestExtraBlocks; 315 | extraBlock = ConfigData.TreeExtraDropBlock[(int)blockType]; 316 | } 317 | else 318 | { 319 | seedsCount = (short)(RollDrops.DoesBlockDropSeed(blockType) ? 1 : 0); 320 | blocksCount = (short)(RollDrops.DoesBlockDropBlock(blockType) ? 1 : 0); 321 | gemsCount = RollDrops.BlockDropsGems(blockType); 322 | extraBlocksCount = (short)(RollDrops.DoesBlockDropExtraBlock(blockType) ? 1 : 0); 323 | extraBlock = ConfigData.BlockExtraDropBlock[(int)blockType]; 324 | } 325 | 326 | if (seedsCount > 0) 327 | { 328 | list.Add(AddCollectable(blockType, seedsCount, InventoryItemType.Seed, mapPoint, null!)); 329 | } 330 | 331 | if (blocksCount > 0) 332 | { 333 | // (!InventoryDataFactory.DoesEnumNeedDataClass(blockType)) ? null : InventoryDataFactory.SpawnDataClassForEnum(blockType) 334 | list.Add(AddCollectable(blockType, blocksCount, ConfigData.BlockInventoryItemType[(int)blockType], mapPoint, null!)); 335 | } 336 | 337 | if (gemsCount > 0) 338 | { 339 | list.AddRange(AddCollectableGems(gemsCount, mapPoint)); 340 | } 341 | 342 | if (extraBlocksCount > 0) 343 | { 344 | // (!InventoryDataFactory.DoesEnumNeedDataClass(blockType2)) ? null : InventoryDataFactory.SpawnDataClassForEnum(blockType2) 345 | list.Add(AddCollectable(extraBlock, extraBlocksCount, ConfigData.BlockInventoryItemType[(int)extraBlock], mapPoint, null!)); 346 | } 347 | 348 | return list; 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /PixelWorldsServer.Server/Worlds/WorldManager.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using MongoDB.Bson; 3 | using MongoDB.Bson.Serialization; 4 | using PixelWorldsServer.DataAccess; 5 | using PixelWorldsServer.DataAccess.Models; 6 | using PixelWorldsServer.Protocol; 7 | using PixelWorldsServer.Protocol.Constants; 8 | using PixelWorldsServer.Protocol.Utils; 9 | using PixelWorldsServer.Protocol.Worlds; 10 | 11 | namespace PixelWorldsServer.Server.Worlds; 12 | 13 | public class WorldManager 14 | { 15 | private readonly ILogger m_Logger; 16 | private readonly Database m_Database; 17 | private readonly Dictionary m_Worlds = new(); 18 | 19 | public WorldManager(ILogger logger, Database database) 20 | { 21 | m_Logger = logger; 22 | m_Database = database; 23 | } 24 | 25 | public int GetWorldsCount() 26 | { 27 | return m_Worlds.Count; 28 | } 29 | 30 | public async Task GetWorldAsync(string name, WorldLayoutType worldLayoutType = WorldLayoutType.Basic) 31 | { 32 | if (m_Worlds.TryGetValue(name, out World? world)) 33 | { 34 | return world; 35 | } 36 | 37 | var worldModel = await m_Database.GetWorldByNameAsync(name).ConfigureAwait(false); 38 | if (worldModel is not null) 39 | { 40 | world = new World(); 41 | world.LoadCopy(worldModel); 42 | 43 | m_Worlds.Add(name, world); 44 | 45 | return world; 46 | } 47 | 48 | return await GenerateWorldAsync(name, worldLayoutType).ConfigureAwait(false); 49 | } 50 | 51 | public async Task GenerateWorldAsync(string name, WorldLayoutType worldLayoutType) 52 | { 53 | var world = new World(); 54 | world.Init(name, worldLayoutType); 55 | world.Id = await m_Database.InsertWorldAsync(WorldModel.CreateCopy(world)).ConfigureAwait(false); 56 | return world; 57 | } 58 | 59 | public World? CopyTutorialWorld(string name) 60 | { 61 | if (!m_Worlds.TryGetValue(name, out World? world)) 62 | { 63 | return null; 64 | } 65 | 66 | return new() 67 | { 68 | Id = $"DYNAMIC_WORLD_{world.Id}", 69 | Name = $"DYNAMIC_WORLD_{name}", 70 | 71 | ItemId = world.ItemId, 72 | MusicIndex = world.MusicIndex, 73 | InventoryId = world.InventoryId, 74 | 75 | Size = world.Size, 76 | StartingPoint = world.StartingPoint, 77 | 78 | WeatherType = world.WeatherType, 79 | GravityMode = world.GravityMode, 80 | LightingType = world.LightingType, 81 | LayoutType = world.LayoutType, 82 | LayerBackgroundType = world.LayerBackgroundType, 83 | 84 | BlockLayer = new(world.BlockLayer), 85 | PlantedSeeds = new(world.PlantedSeeds), 86 | ItemDatas = new(world.ItemDatas), 87 | BlockWaterLayer = new(world.BlockWaterLayer), 88 | BlockWiringLayer = new(world.BlockWiringLayer), 89 | Collectables = new(world.Collectables), 90 | BlockBackgroundLayer = new(world.BlockBackgroundLayer), 91 | }; 92 | } 93 | 94 | public async Task GetExistingWorldAsync(string name) 95 | { 96 | if (m_Worlds.TryGetValue(name, out World? world)) 97 | { 98 | return world; 99 | } 100 | 101 | var worldModel = await m_Database.GetWorldByNameAsync(name).ConfigureAwait(false); 102 | if (worldModel is not null) 103 | { 104 | world = new World(); 105 | world.LoadCopy(worldModel); 106 | 107 | m_Worlds.Add(name, world); 108 | 109 | return world; 110 | } 111 | 112 | return null; 113 | } 114 | private static void GenerateLayerFromByteArray(WorldModel worldModel, byte[] data, LayerType layerType) 115 | { 116 | short[] array = new short[data.Length / 2]; 117 | Buffer.BlockCopy(data, 0, array, 0, data.Length); 118 | 119 | for (int i = 0; i < worldModel.Size.X; ++i) 120 | { 121 | for (int j = 0; j < worldModel.Size.Y; ++j) 122 | { 123 | var index = i + j * worldModel.Size.X; 124 | var blockType = (BlockType)array[index]; 125 | 126 | switch (layerType) 127 | { 128 | case LayerType.Block: 129 | { 130 | worldModel.BlockLayer[index].BlockType = blockType; 131 | break; 132 | } 133 | 134 | case LayerType.Water: 135 | { 136 | worldModel.BlockWaterLayer[index].BlockType = blockType; 137 | break; 138 | } 139 | 140 | case LayerType.Background: 141 | { 142 | worldModel.BlockBackgroundLayer[index].BlockType = blockType; 143 | break; 144 | } 145 | 146 | case LayerType.Wiring: 147 | { 148 | worldModel.BlockWiringLayer[index].BlockType = blockType; 149 | break; 150 | } 151 | } 152 | } 153 | } 154 | } 155 | 156 | private static void GenerateLayerHitsFromByteIntList(WorldModel worldModel, BsonArray array, LayerType layerType) 157 | { 158 | for (int i = 0; i < worldModel.Size.X; ++i) 159 | { 160 | for (int j = 0; j < worldModel.Size.Y; ++j) 161 | { 162 | var index = i + j * worldModel.Size.X; 163 | var hitsRequired = array[index].AsInt32; 164 | 165 | switch (layerType) 166 | { 167 | case LayerType.Block: 168 | { 169 | worldModel.BlockLayer[index].HitsRequired = hitsRequired; 170 | break; 171 | } 172 | 173 | case LayerType.Water: 174 | { 175 | worldModel.BlockWaterLayer[index].HitsRequired = hitsRequired; 176 | break; 177 | } 178 | 179 | case LayerType.Background: 180 | { 181 | worldModel.BlockBackgroundLayer[index].HitsRequired = hitsRequired; 182 | break; 183 | } 184 | 185 | case LayerType.Wiring: 186 | { 187 | worldModel.BlockWiringLayer[index].HitsRequired = hitsRequired; 188 | break; 189 | } 190 | } 191 | } 192 | } 193 | } 194 | 195 | private static void GenerateLayerHitBuffersFromByteIntList(WorldModel worldModel, BsonArray array, LayerType layerType) 196 | { 197 | for (int i = 0; i < worldModel.Size.X; ++i) 198 | { 199 | for (int j = 0; j < worldModel.Size.Y; ++j) 200 | { 201 | var index = i + j * worldModel.Size.X; 202 | var hitsRequired = array[index].AsInt32; 203 | 204 | switch (layerType) 205 | { 206 | case LayerType.Block: 207 | { 208 | worldModel.BlockLayer[index].HitBuffer = hitsRequired; 209 | break; 210 | } 211 | 212 | case LayerType.Water: 213 | { 214 | worldModel.BlockWaterLayer[index].HitBuffer = hitsRequired; 215 | break; 216 | } 217 | 218 | case LayerType.Background: 219 | { 220 | worldModel.BlockBackgroundLayer[index].HitBuffer = hitsRequired; 221 | break; 222 | } 223 | 224 | case LayerType.Wiring: 225 | { 226 | worldModel.BlockWiringLayer[index].HitBuffer = hitsRequired; 227 | break; 228 | } 229 | } 230 | } 231 | } 232 | } 233 | 234 | public async Task LoadWorldFromBinaryAsync(string name, string path) 235 | { 236 | m_Logger.LogInformation("Loading world {}..", name); 237 | 238 | if (!File.Exists(path)) 239 | { 240 | m_Logger.LogWarning("Skipping world {} because path {} doesn't exist", name, path); 241 | return null; 242 | } 243 | 244 | var world = new World(); 245 | 246 | { 247 | var worldModelDb = await m_Database.GetWorldByNameAsync(name).ConfigureAwait(false); 248 | if (worldModelDb is not null) 249 | { 250 | world.LoadCopy(worldModelDb); 251 | 252 | m_Worlds.Add(name, world); 253 | return world; 254 | } 255 | } 256 | 257 | using var fs = File.OpenRead(path); 258 | var data = LZMATools.Decompress(fs); 259 | var document = BsonSerializer.Deserialize(data); 260 | var worldModel = new WorldModel() 261 | { 262 | Name = name, 263 | ItemId = document["WorldItemId"].AsInt32, 264 | MusicIndex = document["WorldMusicIndex"]["Count"].AsInt32, 265 | InventoryId = document["InventoryId"].AsInt32, 266 | Size = new Vector2i() 267 | { 268 | X = document["WorldSizeSettingsType"]["WorldSizeX"].AsInt32, 269 | Y = document["WorldSizeSettingsType"]["WorldSizeY"].AsInt32 270 | }, 271 | StartingPoint = new Vector2i() 272 | { 273 | X = document["WorldStartPoint"]["x"].AsInt32, 274 | Y = document["WorldStartPoint"]["y"].AsInt32 275 | }, 276 | LayoutType = (WorldLayoutType)document["WorldLayoutType"]["Count"].AsInt32, 277 | GravityMode = (GravityMode)document["WorldGravityMode"]["GM"].AsInt32, 278 | WeatherType = (WeatherType)document["WorldWeatherType"]["Count"].AsInt32, 279 | LightingType = (LightingType)document["WorldLightingType"]["Count"].AsInt32, 280 | LayerBackgroundType = (LayerBackgroundType)document["WorldBackgroundType"]["Count"].AsInt32, 281 | }; 282 | 283 | int size = worldModel.Size.X * worldModel.Size.Y; 284 | for (int i = 0; i < size; ++i) 285 | { 286 | worldModel.ItemDatas.Add(null); 287 | worldModel.BlockLayer.Add(new LayerBlock()); 288 | worldModel.PlantedSeeds.Add(null); 289 | worldModel.BlockWaterLayer.Add(new LayerBlock()); 290 | worldModel.BlockWiringLayer.Add(new LayerWiring()); 291 | worldModel.BlockBackgroundLayer.Add(new LayerBlockBackground()); 292 | } 293 | 294 | foreach (var element in document["WorldItems"].AsBsonDocument) 295 | { 296 | string[] arrays = element.Name.Split(' '); 297 | var x = int.Parse(arrays[1]); 298 | var y = int.Parse(arrays[2]); 299 | 300 | var childDocument = element.Value.AsBsonDocument; 301 | var className = childDocument["class"].AsString; 302 | childDocument.Remove("class"); 303 | 304 | var blockType = WorldItemBase.GetBlockTypeViaClassName(className); 305 | var worldItemType = DataFactory.GetDataTypeForEnum(blockType); 306 | var worldItemBase = (WorldItemBase)BsonSerializer.Deserialize(childDocument, worldItemType); 307 | worldModel.ItemDatas[x + y * worldModel.Size.X] = worldItemBase; 308 | } 309 | 310 | GenerateLayerFromByteArray(worldModel, document["BlockLayer"].AsByteArray, LayerType.Block); 311 | GenerateLayerFromByteArray(worldModel, document["BackgroundLayer"].AsByteArray, LayerType.Background); 312 | GenerateLayerFromByteArray(worldModel, document["WaterLayer"].AsByteArray, LayerType.Water); 313 | GenerateLayerFromByteArray(worldModel, document["WiringLayer"].AsByteArray, LayerType.Wiring); 314 | 315 | GenerateLayerHitsFromByteIntList(worldModel, document["BlockLayerHits"].AsBsonArray, LayerType.Block); 316 | GenerateLayerHitsFromByteIntList(worldModel, document["BackgroundLayerHits"].AsBsonArray, LayerType.Background); 317 | GenerateLayerHitsFromByteIntList(worldModel, document["WaterLayerHits"].AsBsonArray, LayerType.Water); 318 | GenerateLayerHitsFromByteIntList(worldModel, document["WiringLayerHits"].AsBsonArray, LayerType.Wiring); 319 | 320 | GenerateLayerHitBuffersFromByteIntList(worldModel, document["BlockLayerHitBuffers"].AsBsonArray, LayerType.Block); 321 | GenerateLayerHitBuffersFromByteIntList(worldModel, document["BackgroundLayerHitBuffers"].AsBsonArray, LayerType.Background); 322 | GenerateLayerHitBuffersFromByteIntList(worldModel, document["WaterLayerHitBuffers"].AsBsonArray, LayerType.Water); 323 | GenerateLayerHitBuffersFromByteIntList(worldModel, document["WiringLayerHitBuffers"].AsBsonArray, LayerType.Wiring); 324 | 325 | world.LoadCopy(worldModel); 326 | m_Worlds.Add(name, world); 327 | 328 | await m_Database.InsertWorldAsync(worldModel).ConfigureAwait(false); 329 | 330 | return world; 331 | } 332 | 333 | public async Task SaveAllWorldsAsync() 334 | { 335 | var tasks = new List(); 336 | 337 | foreach (var (_, world) in m_Worlds) 338 | { 339 | // to boost the performance! 340 | tasks.Add(m_Database.SaveWorldAsync(WorldModel.CreateCopy(world))); 341 | } 342 | 343 | await Task.WhenAll(tasks).ConfigureAwait(false); 344 | } 345 | } 346 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Utils/NetStrings.cs: -------------------------------------------------------------------------------- 1 | namespace PixelWorldsServer.Protocol.Utils; 2 | 3 | public static class NetStrings 4 | { 5 | public const string ID_KEY = "ID"; 6 | public const string PING_KEY = "p"; 7 | public const string SYNC_TIME_KEY = "ST"; 8 | public const string VERSION_CHECK_KEY = "VChk"; 9 | public const string OPERATING_SYSTEM_KEY = "OS"; 10 | public const string OPERATING_SYSTEM_TYPE_KEY = "OSt"; 11 | public const string VERSION_NUMBER_KEY = "VN"; 12 | public const string TIME_KEY = "T"; 13 | public const string SYNC_TIME_FIELD_KEY = "STime"; 14 | public const string SYNC_TIME_SERVER_SLEEP_KEY = "SSlp"; 15 | public const string GET_PLAYER_DATA_KEY = "GPd"; 16 | public const string TOKEN_KEY = "Tk"; 17 | public const string COGNITO_ID_KEY = "CoID"; 18 | public const string PLAYER_ID_KEY = "U"; 19 | public const string PLAYER_USERNAME_KEY = "UN"; 20 | public const string PLAYER_DATA_KEY = "pD"; 21 | public const string EMAIL_KEY = "Email"; 22 | public const string EMAIL_VERIFIED_KEY = "EmailVerified"; 23 | public const string RENAME_PLAYER_KEY = "RenamePlayer"; 24 | public const string SUCCESS_KEY = "S"; 25 | public const string ERROR_KEY = "ER"; 26 | public const string MENU_WORLD_LOAD_INFO_KEY = "MWli"; 27 | public const string WORLD_NAME_KEY = "WN"; 28 | public const string COUNT_KEY = "Ct"; 29 | public const string LOGIN_TOKEN_UPDATE_KEY = "LoginTokenUpdate"; 30 | public const string GET_LIVE_STREAM_INFO_KEY = "gLSI"; 31 | public const string UPDATE_LOCATION_STATUS_KEY = "ULS"; 32 | public const string INSTRUCTION_EVENT_COMPLETED_KEY = "iEC"; 33 | public const string TRY_TO_JOIN_WORLD_KEY = "TTjW"; 34 | public const string WORLD_KEY = "W"; 35 | public const string AMOUNT_KEY = "Amt"; 36 | public const string REAL_USERNAME_KEY = "rUN"; 37 | public const string BAN_PLAYER_KEY = "BPl"; 38 | public const string NEWS_VERSION_KEY = "NV"; 39 | public const string WOTW_KEY = "Wo"; 40 | public const string WOTW_VERSION_KEY = "WV"; 41 | public const string WORLD_BIOME_KEY = "WB"; 42 | public const string JOIN_RESULT_KEY = "JR"; 43 | public const string GET_WORLD_KEY = "Gw"; 44 | public const string GET_WORLD_COMPRESSED_KEY = "GWC"; 45 | public const string ENTRANCE_PORTAL_ID_KEY = "eID"; 46 | public const string ACHIEVEMENT_KEY = "A"; 47 | public const string CAMERA_ZOOM_LEVEL_UPDATE_KEY = "cZL"; 48 | public const string CAMERA_ZOOM_LEVEL_UPDATE_FIELD_KEY = "CZL"; 49 | public const string CAMERA_ZOOM_VALUE_UPDATE_KEY = "cZva"; 50 | public const string REQUEST_OTHER_PLAYER_KEY = "rOP"; 51 | public const string REQUEST_AI_ENEMY_KEY = "rAI"; 52 | public const string REQUEST_AI_PETS_KEY = "rAIp"; 53 | public const string GET_FRIEND_LIST_KEY = "GFLi"; 54 | public const string GET_SCOREBOARD_DATA_KEY = "GSb"; 55 | public const string WORLD_RANDOM_EVENT_UPDATE_KEY = "WREU"; 56 | public const string WORLD_RANDOM_EVENT_GET_ALL_ACTIVE_KEY = "WREgA"; 57 | public const string ADD_NETWORK_PLAYER_KEY = "AnP"; 58 | public const string TIMESTAMP_KEY = "t"; 59 | public const string POSITION_X_KEY = "x"; 60 | public const string POSITION_Y_KEY = "y"; 61 | public const string POSITION_X_FLOAT_KEY = "PosX"; 62 | public const string POSITION_Y_FLOAT_KEY = "PosY"; 63 | public const string ANIMATION_KEY = "a"; 64 | public const string DIRECTION_KEY = "d"; 65 | public const string TELEPORT_KEY = "tp"; 66 | public const string MY_POSITION_KEY = "mP"; 67 | public const string READY_TO_PLAY_KEY = "RtP"; 68 | public const string FIRST_MESSAGE_KEY = "m0"; 69 | public const string TUTORIAL_STATE_UPDATE_KEY = "TState"; 70 | public const string TUTORIAL_STATE_UPDATE_FIELD_KEY = "Tstate"; 71 | public const string CHARACTER_CREATED_KEY = "CharC"; 72 | public const string GENDER_KEY = "Gnd"; 73 | public const string COUNTRY_KEY = "Ctry"; 74 | public const string SKIN_COLOR_INDEX_KEY = "SCI"; 75 | public const string BLOCK_TYPE_KEY = "BlockType"; 76 | public const string SET_SEED_KEY = "SS"; 77 | public const string SET_BLOCK_KEY = "SB"; 78 | public const string SET_BLOCK_BACKGROUND_KEY = "SBB"; 79 | public const string HIT_BLOCK_KEY = "HB"; 80 | public const string HIT_BLOCK_BACKGROUND_KEY = "HBB"; 81 | public const string DESTROY_BLOCK_KEY = "DB"; 82 | public const string DESTROYED_BLOCK_TYPE_KEY = "DBBT"; 83 | public const string DESTROYED_SEED_TYPE_KEY = "DSBT"; 84 | public const string GROWTH_DURATION_KEY = "GrowthDuration"; 85 | public const string GROWTH_END_TIME_KEY = "GrowthEndTime"; 86 | public const string IS_MIXED_KEY = "Mixed"; 87 | public const string HARVEST_SEEDS_KEY = "HarvestSeeds"; 88 | public const string HARVEST_BLOCKS_KEY = "HarvestBlocks"; 89 | public const string HARVEST_GEMS_KEY = "HarvestGems"; 90 | public const string HARVEST_EXTRA_BLOCKS_KEY = "HarvestExtraBlocks"; 91 | public const string SET_FERTILIZER_KEY = "SFe"; 92 | public const string COLLECT_KEY = "C"; 93 | public const string REMOVE_COLLECT_KEY = "RC"; 94 | public const string COLLECTABLE_ID_KEY = "CollectableID"; 95 | public const string COLLECT_AMOUNT_KEY = "Amount"; 96 | public const string INVENTORY_TYPE_KEY = "InventoryType"; 97 | public const string INVENTORY_DATA_KEY = "InventoryData"; 98 | public const string IS_GEM_KEY = "IsGem"; 99 | public const string GEM_TYPE_KEY = "GemType"; 100 | public const string NEW_COLLECTABLE_KEY = "nCo"; 101 | public const string BUY_ITEM_PACK_KEY = "BIPack"; 102 | public const string ITEM_PACK_ID_KEY = "IPId"; 103 | public const string ITEM_PACK_ROLLS_KEY = "IPRs"; 104 | public const string ITEM_PACK_ROLLS2_KEY = "IPRs2"; 105 | public const string LEAVE_WORLD_KEY = "LW"; 106 | public const string TUTORIAL_STATE_FIELD_KEY = "tutorialState"; 107 | public const string CAMERA_ZOOM_LEVEL_FIELD_KEY = "cameraZoomLevel"; 108 | public const string CAMERA_ZOOM_UPDATE_FIELD_KEY = "cZv"; 109 | public const string CAMERA_ZOOM_VALUE_FIELD_KEY = "cZv"; 110 | public const string GEMS_FIELD_KEY = "gems"; 111 | public const string GEMS_AMOUNT_FIELD_KEY = "GAmt"; 112 | public const string BYTE_COINS_FIELD_KEY = "bcs"; 113 | public const string SLOTS_FIELD_KEY = "slots"; 114 | public const string INVENTORY_FIELD_KEY = "inv"; 115 | public const string INVENTORY_DATA_FIELD_KEY = "invData"; 116 | public const string BELT1_FIELD_KEY = "belt1"; 117 | public const string SPOTS_FIELD_KEY = "spots"; 118 | public const string FAMILIAR_BLOCK_TYPE_FIELD_KEY = "fam"; 119 | public const string FAMILIAR_BLOCK_TYPE_PLAYER_KEY = "familiar"; 120 | public const string PLAYER_COSTUME_FIELD_KEY = "pCosT"; 121 | public const string PLAYER_COSTUME_END_TIME_FIELD_KEY = "pCosET"; 122 | public const string FAMILIAR_NAME_FIELD_KEY = "famName"; 123 | public const string FAMILIAR_NAME_PLAYER_KEY = "familiarName"; 124 | public const string IS_FAMILIAR_MAX_LVL_FIELD_KEY = "isFamMaxLvl"; 125 | public const string IS_FAMILIAR_MAX_LVL_PLAYER_KEY = "isFamiliarMaxLevel"; 126 | public const string FACE_ANIM_FIELD_KEY = "faceAnim"; 127 | public const string SKIN_INDEX_FIELD_KEY = "skin"; 128 | public const string GENDER_FIELD_KEY = "gender"; 129 | public const string NORMAL_CLAIM_TIME_FIELD_KEY = "normalClaimTime"; 130 | public const string VIP_CLAIM_TIME_FIELD_KEY = "vipClaimTime"; 131 | public const string HAS_CLAIMED_ADDITIONAL_FIELD_KEY = "hasClaimedAdditional"; 132 | public const string STATISTICS_FIELD_KEY = "statistics"; 133 | public const string AGE_FIELD_KEY = "Age"; 134 | public const string LEVEL_FIELD_KEY = "LvL"; 135 | public const string XP_LEVEL_FIELD_KEY = "xpLvL"; 136 | public const string ACCOUNT_AGE_FIELD_KEY = "accountAge"; 137 | public const string COUNTRY_CODE_FIELD_KEY = "countryCode"; 138 | public const string VIP_END_TIME_FIELD_KEY = "VIPendTime"; 139 | public const string VIP_END_TIME_AGE_FIELD_KEY = "VIPEndTimeAge"; 140 | public const string NAME_CHANGE_COUNTER_FIELD_KEY = "nameChangeCounter"; 141 | public const string EXPERIENCE_AMOUNT_FIELD_KEY = "experienceAmount"; 142 | public const string XP_AMOUNT_FIELD_KEY = "xpAmount"; 143 | public const string NEXT_DAILY_BONUS_GIVEAWAY_FIELD_KEY = "nextdailyBonusGiveAwayKey"; 144 | public const string NEXT_NORMAL_DAILY_BONUS_CLAIM_FIELD_KEY = "nextNormalDailyBonusClaimKey"; 145 | public const string NEXT_VIP_DAILY_BONUS_CLAIM_FIELD_KEY = "nextVIPDailyBonusClaimKey"; 146 | public const string NEXT_DAILY_ADS_REFRESH_TIME_FIELD_KEY = "nextDailyAdsRefreshTimeKey"; 147 | public const string NEXT_DAILY_PVP_REWARDS_REFRESH_TIME_FIELD_KEY = "nextDailyPvpRewardsRefreshTimeKey"; 148 | public const string LAST_FREE_PRIZE_CLAIM_TIME_FIELD_KEY = "FPCKey"; 149 | public const string NEXT_WELCOME_GIFT_CLAIM_TIME_FIELD_KEY = "WGtKey"; 150 | public const string WELCOME_GIFT_INDEX_FIELD_KEY = "WGiKey"; 151 | public const string PLAYER_ADMIN_STATUS_FIELD_KEY = "playerAdminStatusKey"; 152 | public const string SHOW_LOCATION_FIELD_KEY = "showLocation"; 153 | public const string SHOW_ONLINE_STATUS_FIELD_KEY = "showOnlineStatus"; 154 | public const string GENERIC_VERSIONING_FIELD_KEY = "gV"; 155 | public const string PASSIVE_EFFECTS_FIELD_KEY = "pEffs"; 156 | public const string INSTRUCTION_STATES_AMOUNTS_FIELD_KEY = "playerAmounts"; 157 | public const string INSTRUCTION_STATES_FIELD_KEY = "instructionStates"; 158 | public const string ACHIEVEMENT_CURRENT_VALUES_FIELD_KEY = "achievementCurrentValues"; 159 | public const string ACHIEVEMENT_COMPLETED_STATES_FIELD_KEY = "achievementsCompletedStates"; 160 | public const string ACHIEVEMENT_REWARDS_CLAIMED_FIELD_KEY = "achievementRewardsClaimed"; 161 | public const string QUEST_LIST_COUNT_FIELD_KEY = "questListCountKey"; 162 | public const string QUEST_CURRENT_ID_FIELD_KEY = "questCurrentIDKey"; 163 | public const string QUEST_CURRENT_PHASE_FIELD_KEY = "questCurrentPhaseKey"; 164 | public const string FACE_EXPRESSION_LIST_ID_FIELD_KEY = "faceExpressionListIDKey"; 165 | public const string BOUGHT_EXPRESSIONS_LIST_FIELD_KEY = "boughtExpressionsListKey"; 166 | public const string ALREADY_BOUGHT_ONE_TIME_ITEMS_FIELD_KEY = "alreadyBoughtOneTimeItems"; 167 | public const string DAILY_QUEST_NEXT_AVAILABLE_LIST_FIELD_KEY = "dailyQuestNextAvailListKey"; 168 | public const string PREVIOUS_THREE_DAILY_QUEST_IDS_FIELD_KEY = "previousThreeDailyQuestIdsKey"; 169 | public const string TUTORIAL_1_CURRENT_STEP_FIELD_KEY = "Tutorial1currentStep"; 170 | public const string TUTORIAL_1_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY = "Tutorial1trackQuestStepProgress"; 171 | public const string TUTORIAL_2_CURRENT_STEP_FIELD_KEY = "Tutorial2currentStep"; 172 | public const string TUTORIAL_2_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY = "Tutorial2trackQuestStepProgress"; 173 | public const string TUTORIAL_3_CURRENT_STEP_FIELD_KEY = "Tutorial3currentStep"; 174 | public const string TUTORIAL_3_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY = "Tutorial3trackQuestStepProgress"; 175 | public const string TUTORIAL_4_CURRENT_STEP_FIELD_KEY = "Tutorial4currentStep"; 176 | public const string TUTORIAL_4_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY = "Tutorial4trackQuestStepProgress"; 177 | public const string TUTORIAL_5_CURRENT_STEP_FIELD_KEY = "Tutorial5currentStep"; 178 | public const string TUTORIAL_5_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY = "Tutorial5trackQuestStepProgress"; 179 | public const string TUTORIAL_5_INVENTORY_SIZE_KEY = "Tutorial5InventorySizeKey"; 180 | public const string TUTORIAL_6_CURRENT_STEP_FIELD_KEY = "Tutorial6currentStep"; 181 | public const string TUTORIAL_6_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY = "Tutorial6trackQuestStepProgress"; 182 | public const string TUTORIAL_7_CURRENT_STEP_FIELD_KEY = "Tutorial7currentStep"; 183 | public const string TUTORIAL_7_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY = "Tutorial7trackQuestStepProgress"; 184 | public const string TUTORIAL_8_CURRENT_STEP_FIELD_KEY = "Tutorial8currentStep"; 185 | public const string TUTORIAL_8_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY = "Tutorial8trackQuestStepProgress"; 186 | public const string TUTORIAL_8_QUEST_VISITED_WORLDS_LIST_FIELD_KEY = "Tutorial8questVisitedWorldsListKey"; 187 | public const string TUTORIAL_9_CURRENT_STEP_FIELD_KEY = "Tutorial9currentStep"; 188 | public const string TUTORIAL_9_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY = "Tutorial9trackQuestStepProgress"; 189 | public const string TUTORIAL_9_QUEST_VISITED_WORLDS_LIST_FIELD_KEY = "Tutorial9questVisitedWorldsListKey"; 190 | public const string TUTORIAL_10_CURRENT_STEP_FIELD_KEY = "Tutorial10currentStep"; 191 | public const string TUTORIAL_10_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY = "Tutorial10trackQuestStepProgress"; 192 | public const string TUTORIAL_11_CURRENT_STEP_FIELD_KEY = "Tutorial11currentStep"; 193 | public const string TUTORIAL_11_TRACK_QUEST_STEP_PROGRESS_FIELD_KEY = "Tutorial11trackQuestStepProgress"; 194 | public const string TUTORIAL_ID_LIST_FIELD_KEY = "tutorialIDListKey"; 195 | public const string TUTORIAL_QUEST_COMPLETE_STATE_FIELD_KEY = "tutorialQuestCompleteState"; 196 | public const string LIMITED_OFFERS_FIELD_KEY = "limitedOffersKey"; 197 | public const string LIMITED_OFFERS_USED_FIELD_KEY = "limitedOffersUsedKey"; 198 | public const string IS_STARTER_FIELD_KEY = "starter"; 199 | public const string CARD_GAME_FACE_EXPRESSIONS_ENABLED_FIELD_KEY = "cGFee"; 200 | public const string CARD_GAME_BODY_EXPRESSIONS_ENABLED_FIELD_KEY = "cGBee"; 201 | public const string FTUE_SOLD_ITEM_IDS_FIELD_KEY = "ftueSoldItemIDsKey"; 202 | public const string SKIN_COLOR_INDEX_BEFORE_OVERRIDE_FIELD_KEY = "skinBO"; 203 | public const string IS_VIP_FIELD_KEY = "IsVIP"; 204 | public const string IN_PORTAL_FIELD_KEY = "inPortal"; 205 | public const string STATUS_ICON_FIELD_KEY = "SIc"; 206 | public const string WEARABLE_OR_WEAPON_CHANGE_KEY = "WeOwC"; 207 | public const string WEARABLE_OR_WEAPON_UNDRESS_KEY = "WeOwU"; 208 | public const string HOTSPOT_BLOCK_TYPE_KEY = "hBlock"; 209 | public const string TOP_ARM_BLOCK_TYPE_KEY = "TT"; 210 | public const string PLAYER_STATUS_ICON_UPDATE = "PSicU"; 211 | public const string PLAYER_LEFT_KEY = "PL"; 212 | public const string WORLD_CHAT_MESSAGE_KEY = "WCM"; 213 | public const string MESSAGE_KEY = "msg"; 214 | public const string NICK_KEY = "nick"; 215 | public const string CHAT_MESSAGE_BINARY = "CmB"; 216 | public const string USER_ID_KEY = "userID"; 217 | public const string CHANNEL_KEY = "channel"; 218 | public const string CHANNEL_INDEX_KEY = "channelIndex"; 219 | public const string MESSAGE_CHAT_KEY = "message"; 220 | public const string CHAT_TIME_KEY = "time"; 221 | } 222 | -------------------------------------------------------------------------------- /PixelWorldsServer.Protocol/Packet/Response/GetWorldResponse.cs: -------------------------------------------------------------------------------- 1 | using MongoDB.Bson.Serialization; 2 | using MongoDB.Bson.Serialization.Serializers; 3 | using PixelWorldsServer.Protocol.Constants; 4 | using PixelWorldsServer.Protocol.Utils; 5 | using PixelWorldsServer.Protocol.Worlds; 6 | 7 | namespace PixelWorldsServer.Protocol.Packet.Response; 8 | 9 | public class GetWorldResponse : PacketBase 10 | { 11 | public string WorldId { get; set; } = string.Empty; 12 | 13 | public int ItemId { get; set; } // WorldItem last id 14 | public int MusicIndex { get; set; } 15 | public int InventoryId { get; set; } // Collectables last id 16 | 17 | public Vector2i Size { get; set; } = new(); 18 | public Vector2i StartingPoint { get; set; } = new(); 19 | 20 | public WeatherType WeatherType { get; set; } = WeatherType.None; 21 | public GravityMode GravityMode { get; set; } = GravityMode.Normal; 22 | public LightingType LightingType { get; set; } = LightingType.None; 23 | public WorldLayoutType LayoutType { get; set; } = WorldLayoutType.Basic; 24 | public LayerBackgroundType LayerBackgroundType { get; set; } = LayerBackgroundType.ForestBackground; 25 | 26 | public List BlockLayer { get; set; } = new(); 27 | public List PlantedSeeds { get; set; } = new(); 28 | public List ItemDatas { get; set; } = new(); 29 | public List BlockWaterLayer { get; set; } = new(); 30 | public List BlockWiringLayer { get; set; } = new(); 31 | public List Collectables { get; set; } = new(); 32 | public List BlockBackgroundLayer { get; set; } = new(); 33 | } 34 | 35 | public class GetWorldResponseSerializer : SerializerBase 36 | { 37 | public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, GetWorldResponse value) 38 | { 39 | context.Writer.WriteStartDocument(); 40 | context.Writer.WriteName("ID"); 41 | context.Writer.WriteString(value.ID); 42 | context.Writer.WriteName("World"); 43 | context.Writer.WriteString(value.WorldId); 44 | 45 | { 46 | context.Writer.WriteName("WorldLayoutType"); 47 | context.Writer.WriteStartDocument(); 48 | context.Writer.WriteName("Count"); 49 | context.Writer.WriteInt32((int)value.LayoutType); 50 | context.Writer.WriteEndDocument(); 51 | } 52 | 53 | { 54 | context.Writer.WriteName("WorldBackgroundType"); 55 | context.Writer.WriteStartDocument(); 56 | context.Writer.WriteName("Count"); 57 | context.Writer.WriteInt32((int)value.LayerBackgroundType); 58 | context.Writer.WriteEndDocument(); 59 | } 60 | 61 | { 62 | context.Writer.WriteName("WorldWeatherType"); 63 | context.Writer.WriteStartDocument(); 64 | context.Writer.WriteName("Count"); 65 | context.Writer.WriteInt32((int)value.WeatherType); 66 | context.Writer.WriteEndDocument(); 67 | } 68 | 69 | { 70 | context.Writer.WriteName("WorldLightingType"); 71 | context.Writer.WriteStartDocument(); 72 | context.Writer.WriteName("Count"); 73 | context.Writer.WriteInt32((int)value.LightingType); 74 | context.Writer.WriteEndDocument(); 75 | } 76 | 77 | { 78 | context.Writer.WriteName("WorldMusicIndex"); 79 | context.Writer.WriteStartDocument(); 80 | context.Writer.WriteName("Count"); 81 | context.Writer.WriteInt32(value.MusicIndex); 82 | context.Writer.WriteEndDocument(); 83 | } 84 | 85 | { 86 | context.Writer.WriteName("WorldGravityMode"); 87 | context.Writer.WriteStartDocument(); 88 | context.Writer.WriteName("GM"); 89 | context.Writer.WriteInt32((int)value.GravityMode); 90 | context.Writer.WriteEndDocument(); 91 | } 92 | 93 | { 94 | context.Writer.WriteName("WorldStartPoint"); 95 | context.Writer.WriteStartDocument(); 96 | context.Writer.WriteName("x"); 97 | context.Writer.WriteInt32(value.StartingPoint.X); 98 | context.Writer.WriteName("y"); 99 | context.Writer.WriteInt32(value.StartingPoint.Y); 100 | context.Writer.WriteEndDocument(); 101 | } 102 | 103 | { 104 | context.Writer.WriteName("WorldSizeSettingsType"); 105 | context.Writer.WriteStartDocument(); 106 | context.Writer.WriteName("WorldSizeX"); 107 | context.Writer.WriteInt32(value.Size.X); 108 | context.Writer.WriteName("WorldSizeY"); 109 | context.Writer.WriteInt32(value.Size.Y); 110 | context.Writer.WriteEndDocument(); 111 | } 112 | 113 | var size = value.Size.X * value.Size.Y; 114 | var blockLayerData = new byte[size * sizeof(short)]; 115 | var backgroundLayerData = new byte[size * sizeof(short)]; 116 | var waterLayerData = new byte[size * sizeof(short)]; 117 | var wiringLayerData = new byte[size * sizeof(short)]; 118 | 119 | for (int i = 0; i < size; ++i) 120 | { 121 | Buffer.BlockCopy(BitConverter.GetBytes((short)value.BlockLayer[i].BlockType), 0, blockLayerData, i * 2, sizeof(short)); 122 | Buffer.BlockCopy(BitConverter.GetBytes((short)value.BlockBackgroundLayer[i].BlockType), 0, backgroundLayerData, i * 2, sizeof(short)); 123 | Buffer.BlockCopy(BitConverter.GetBytes((short)value.BlockWaterLayer[i].BlockType), 0, waterLayerData, i * 2, sizeof(short)); 124 | Buffer.BlockCopy(BitConverter.GetBytes((short)value.BlockWiringLayer[i].BlockType), 0, wiringLayerData, i * 2, sizeof(short)); 125 | } 126 | 127 | context.Writer.WriteName("BlockLayer"); 128 | context.Writer.WriteBytes(blockLayerData); 129 | context.Writer.WriteName("BackgroundLayer"); 130 | context.Writer.WriteBytes(backgroundLayerData); 131 | context.Writer.WriteName("WaterLayer"); 132 | context.Writer.WriteBytes(waterLayerData); 133 | context.Writer.WriteName("WiringLayer"); 134 | context.Writer.WriteBytes(wiringLayerData); 135 | 136 | void WriteLayerHits(string name, LayerType layerType) 137 | { 138 | context.Writer.WriteName(name); 139 | context.Writer.WriteStartArray(); 140 | 141 | for (int i = 0; i < size; ++i) 142 | { 143 | switch (layerType) 144 | { 145 | case LayerType.Block: 146 | { 147 | context.Writer.WriteInt32(value.BlockLayer[i].HitsRequired); 148 | break; 149 | } 150 | 151 | case LayerType.Background: 152 | { 153 | context.Writer.WriteInt32(value.BlockBackgroundLayer[i].HitsRequired); 154 | break; 155 | } 156 | 157 | case LayerType.Water: 158 | { 159 | context.Writer.WriteInt32(value.BlockWaterLayer[i].HitsRequired); 160 | break; 161 | } 162 | 163 | case LayerType.Wiring: 164 | { 165 | context.Writer.WriteInt32(value.BlockWiringLayer[i].HitsRequired); 166 | break; 167 | } 168 | } 169 | } 170 | 171 | context.Writer.WriteEndArray(); 172 | } 173 | 174 | void WriteLayerHitBuffers(string name, LayerType layerType) 175 | { 176 | context.Writer.WriteName(name); 177 | context.Writer.WriteStartArray(); 178 | 179 | for (int i = 0; i < size; ++i) 180 | { 181 | switch (layerType) 182 | { 183 | case LayerType.Block: 184 | { 185 | context.Writer.WriteInt32(value.BlockLayer[i].HitBuffer); 186 | break; 187 | } 188 | 189 | case LayerType.Background: 190 | { 191 | context.Writer.WriteInt32(value.BlockBackgroundLayer[i].HitBuffer); 192 | break; 193 | } 194 | 195 | case LayerType.Water: 196 | { 197 | context.Writer.WriteInt32(value.BlockWaterLayer[i].HitBuffer); 198 | break; 199 | } 200 | 201 | case LayerType.Wiring: 202 | { 203 | context.Writer.WriteInt32(value.BlockWiringLayer[i].HitBuffer); 204 | break; 205 | } 206 | } 207 | } 208 | 209 | context.Writer.WriteEndArray(); 210 | } 211 | 212 | // So fucking inefficient, but there is no other way apparently. 213 | // I can use context.Writer.WriteRawBsonArray, loops once and cache everything 214 | // but it takes an IByteBuffer which is what the fuck. 215 | // There is no actual clear documentation about this so i have no idea. 216 | WriteLayerHits("BlockLayerHits", LayerType.Block); 217 | WriteLayerHits("BackgroundLayerHits", LayerType.Background); 218 | WriteLayerHits("WaterLayerHits", LayerType.Water); 219 | WriteLayerHits("WiringLayerHits", LayerType.Wiring); 220 | 221 | WriteLayerHitBuffers("BlockLayerHitBuffers", LayerType.Block); 222 | WriteLayerHitBuffers("BackgroundLayerHitBuffers", LayerType.Background); 223 | WriteLayerHitBuffers("WaterLayerHitBuffers", LayerType.Water); 224 | WriteLayerHitBuffers("WiringLayerHitBuffers", LayerType.Wiring); 225 | 226 | var seeds = new List<(SeedData, int, int)>(); 227 | var itemDatas = new List<(WorldItemBase, int, int)>(); 228 | for (int x = 0; x < value.Size.X; ++x) 229 | { 230 | for (int y = 0; y < value.Size.Y; ++y) 231 | { 232 | var index = x + y * value.Size.X; 233 | 234 | var seed = value.PlantedSeeds[index]; 235 | if (seed is not null) 236 | { 237 | seeds.Add((seed, x, y)); 238 | } 239 | 240 | var itemData = value.ItemDatas[index]; 241 | if (itemData is not null) 242 | { 243 | itemDatas.Add((itemData, x, y)); 244 | } 245 | } 246 | } 247 | 248 | { 249 | context.Writer.WriteName("Collectables"); 250 | context.Writer.WriteStartDocument(); 251 | context.Writer.WriteName("Count"); 252 | context.Writer.WriteInt32(value.Collectables.Count); 253 | 254 | foreach (var collectable in value.Collectables) 255 | { 256 | context.Writer.WriteName($"C{collectable.Id}"); 257 | context.Writer.WriteStartDocument(); 258 | 259 | context.Writer.WriteName(NetStrings.COLLECTABLE_ID_KEY); 260 | context.Writer.WriteInt32(collectable.Id); 261 | 262 | context.Writer.WriteName(NetStrings.BLOCK_TYPE_KEY); 263 | context.Writer.WriteInt32((int)collectable.BlockType); 264 | 265 | context.Writer.WriteName(NetStrings.COLLECT_AMOUNT_KEY); 266 | context.Writer.WriteInt32(collectable.Amount); 267 | 268 | context.Writer.WriteName(NetStrings.INVENTORY_TYPE_KEY); 269 | context.Writer.WriteInt32((int)collectable.InventoryItemType); 270 | 271 | context.Writer.WriteName(NetStrings.POSITION_X_FLOAT_KEY); 272 | context.Writer.WriteDouble(collectable.Pos.X); 273 | 274 | context.Writer.WriteName(NetStrings.POSITION_Y_FLOAT_KEY); 275 | context.Writer.WriteDouble(collectable.Pos.Y); 276 | 277 | context.Writer.WriteName(NetStrings.IS_GEM_KEY); 278 | context.Writer.WriteBoolean(collectable.IsGem); 279 | 280 | context.Writer.WriteName(NetStrings.GEM_TYPE_KEY); 281 | context.Writer.WriteInt32((int)collectable.GemType); 282 | 283 | if (collectable.InventoryData is not null) 284 | { 285 | context.Writer.WriteName(NetStrings.INVENTORY_DATA_KEY); 286 | BsonDocumentSerializer.Instance.Serialize(context, collectable.InventoryData.Serialize()); 287 | } 288 | 289 | context.Writer.WriteEndDocument(); 290 | } 291 | 292 | context.Writer.WriteEndDocument(); 293 | } 294 | 295 | { 296 | // TODO: WorldRandomEvents 297 | context.Writer.WriteName("WorldRandomEvents"); 298 | context.Writer.WriteStartDocument(); 299 | context.Writer.WriteName("Count"); 300 | //context.Writer.WriteInt32(value.RandomEvents.Count); 301 | context.Writer.WriteInt32(0); 302 | context.Writer.WriteEndDocument(); 303 | } 304 | 305 | { 306 | context.Writer.WriteName("PlantedSeeds"); 307 | context.Writer.WriteStartDocument(); 308 | 309 | foreach (var (seed, x, y) in seeds) 310 | { 311 | context.Writer.WriteName($"W {x} {y}"); 312 | context.Writer.WriteStartDocument(); 313 | 314 | context.Writer.WriteName(NetStrings.POSITION_X_KEY); 315 | context.Writer.WriteInt32(seed.Position.X); 316 | 317 | context.Writer.WriteName(NetStrings.POSITION_Y_KEY); 318 | context.Writer.WriteInt32(seed.Position.Y); 319 | 320 | context.Writer.WriteName(NetStrings.BLOCK_TYPE_KEY); 321 | context.Writer.WriteInt32((int)seed.BlockType); 322 | 323 | context.Writer.WriteName(NetStrings.GROWTH_DURATION_KEY); 324 | context.Writer.WriteInt32(seed.GrowthDurationInSeconds); 325 | 326 | context.Writer.WriteName(NetStrings.GROWTH_END_TIME_KEY); 327 | context.Writer.WriteInt64(seed.GrowthEndTime.Ticks); 328 | 329 | context.Writer.WriteName(NetStrings.IS_MIXED_KEY); 330 | context.Writer.WriteBoolean(seed.IsAlreadyCrossBred); 331 | 332 | context.Writer.WriteName(NetStrings.HARVEST_SEEDS_KEY); 333 | context.Writer.WriteInt32(seed.HarvestSeeds); 334 | 335 | context.Writer.WriteName(NetStrings.HARVEST_BLOCKS_KEY); 336 | context.Writer.WriteInt32(seed.HarvestBlocks); 337 | 338 | context.Writer.WriteName(NetStrings.HARVEST_GEMS_KEY); 339 | context.Writer.WriteInt32(seed.HarvestGems); 340 | 341 | context.Writer.WriteName(NetStrings.HARVEST_EXTRA_BLOCKS_KEY); 342 | context.Writer.WriteInt32(seed.HarvestExtraBlocks); 343 | 344 | context.Writer.WriteEndDocument(); 345 | } 346 | 347 | context.Writer.WriteEndDocument(); 348 | } 349 | 350 | { 351 | context.Writer.WriteName("WorldItems"); 352 | context.Writer.WriteStartDocument(); 353 | 354 | foreach (var (itemData, x, y) in itemDatas) 355 | { 356 | context.Writer.WriteName($"W {x} {y}"); 357 | BsonDocumentSerializer.Instance.Serialize(context, itemData.Serialize()); 358 | } 359 | 360 | context.Writer.WriteEndDocument(); 361 | } 362 | 363 | context.Writer.WriteName("InventoryId"); 364 | context.Writer.WriteInt32(value.InventoryId); 365 | context.Writer.WriteName("WorldItemId"); 366 | context.Writer.WriteInt32(value.ItemId); 367 | 368 | context.Writer.WriteEndDocument(); 369 | } 370 | } 371 | 372 | public class GetWorldResponseSerializationProvider : IBsonSerializationProvider 373 | { 374 | public IBsonSerializer GetSerializer(Type type) 375 | { 376 | if (type == typeof(GetWorldResponse)) 377 | { 378 | return new GetWorldResponseSerializer(); 379 | } 380 | return null!; 381 | } 382 | } 383 | --------------------------------------------------------------------------------