├── .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_defaultsforblocks 4 Default 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 |
--------------------------------------------------------------------------------