├── .gitignore ├── .travis.yml ├── DOCUMENTATION.md ├── LICENSE ├── Package.swift ├── README.md ├── Sources ├── SwiftMC │ ├── Blocks │ │ ├── Material.swift │ │ └── MaterialData.swift │ ├── Chat │ │ ├── ChatColor.swift │ │ ├── ChatMessage.swift │ │ ├── ChatProgressBar.swift │ │ └── CommandSender.swift │ ├── Commands │ │ ├── ChatCommand.swift │ │ ├── Command.swift │ │ ├── GamemodeCommand.swift │ │ ├── HelpCommand.swift │ │ ├── StopCommand.swift │ │ └── WorldCommand.swift │ ├── Configuration │ │ ├── Configuration.swift │ │ ├── GameMode.swift │ │ └── ServerInfo.swift │ ├── Encryption │ │ ├── AuthentificationMode.swift │ │ └── EncryptionManager.swift │ ├── Entities │ │ ├── Entity.swift │ │ └── Player.swift │ ├── Events │ │ ├── Event.swift │ │ ├── EventListener.swift │ │ ├── PlayerChatEvent.swift │ │ ├── PlayerConnectEvent.swift │ │ ├── PlayerDisconnectEvent.swift │ │ ├── PlayerJoinEvent.swift │ │ ├── PlayerMoveEvent.swift │ │ └── PlayerQuitEvent.swift │ ├── Extensions │ │ ├── ByteBufferExtension.swift │ │ ├── DataExtension.swift │ │ ├── FileHandleExtension.swift │ │ ├── StringExtension.swift │ │ └── SystemExtension.swift │ ├── HTTP │ │ ├── BStatsSubmitData.swift │ │ ├── MojangHasJoined.swift │ │ └── MojangJoin.swift │ ├── Handlers │ │ ├── ChannelHandler.swift │ │ ├── ClientHandler.swift │ │ ├── GameHandler.swift │ │ ├── InitialHandler.swift │ │ ├── MinecraftDecoder.swift │ │ ├── MinecraftEncoder.swift │ │ └── PacketHandler.swift │ ├── Inventory │ │ └── Slot.swift │ ├── NBT │ │ ├── NBTByte.swift │ │ ├── NBTByteArray.swift │ │ ├── NBTCompound.swift │ │ ├── NBTDouble.swift │ │ ├── NBTEnd.swift │ │ ├── NBTFloat.swift │ │ ├── NBTInt.swift │ │ ├── NBTIntArray.swift │ │ ├── NBTList.swift │ │ ├── NBTLong.swift │ │ ├── NBTLongArray.swift │ │ ├── NBTRegistry.swift │ │ ├── NBTShort.swift │ │ ├── NBTString.swift │ │ └── NBTTag.swift │ ├── Packets │ │ ├── BlockPlace.swift │ │ ├── Chat.swift │ │ ├── EncryptionRequest.swift │ │ ├── EncryptionResponse.swift │ │ ├── GameState.swift │ │ ├── Handshake.swift │ │ ├── KeepAlive.swift │ │ ├── Kick.swift │ │ ├── LegacyHandshake.swift │ │ ├── LegacyPing.swift │ │ ├── Login.swift │ │ ├── LoginRequest.swift │ │ ├── LoginSuccess.swift │ │ ├── MapChunk.swift │ │ ├── Packet.swift │ │ ├── PingPacket.swift │ │ ├── PlayerInfo.swift │ │ ├── PlayerListHeaderFooter.swift │ │ ├── PlayerLook.swift │ │ ├── PlayerPosition.swift │ │ ├── PlayerPositionLook.swift │ │ ├── PluginMessage.swift │ │ ├── Position.swift │ │ ├── Respawn.swift │ │ ├── SetCompression.swift │ │ ├── StatusRequest.swift │ │ ├── StatusResponse.swift │ │ └── UnknownPacket.swift │ ├── Protocols │ │ ├── DirectionData.swift │ │ ├── Protocol.swift │ │ ├── ProtocolConstants.swift │ │ ├── ProtocolData.swift │ │ └── ProtocolMapping.swift │ ├── Random │ │ ├── PerlinGenerator.swift │ │ └── Random.swift │ ├── SwiftMC.swift │ ├── Worlds │ │ ├── Biome.swift │ │ ├── LocalWorld.swift │ │ ├── Location.swift │ │ ├── NibbleArray.swift │ │ ├── OverworldGenerator.swift │ │ ├── PlayerData.swift │ │ ├── RemoteWorld.swift │ │ ├── SuperflatGenerator.swift │ │ ├── VariableValueArray.swift │ │ ├── WorldChunk.swift │ │ ├── WorldChunkData.swift │ │ ├── WorldChunkSection.swift │ │ ├── WorldConfiguration.swift │ │ ├── WorldGenerator.swift │ │ ├── WorldProtocol.swift │ │ ├── WorldRegion.swift │ │ └── WorldType.swift │ └── Wrappers │ │ └── ChannelWrapper.swift └── SwiftMCRun │ └── main.swift └── Tests ├── LinuxMain.swift └── SwiftMCTests ├── SwiftMCTests.swift └── XCTestManifests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | .swiftpm/ 6 | Package.resolved 7 | xcuserdata/ 8 | world/ 9 | swiftmc.json 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Only create a build job IF the branch is 'master' 2 | branches: 3 | only: 4 | - master 5 | # Set environment variables for the build job 6 | env: 7 | global: 8 | - SWIFT_BRANCH=swift-5.2.3-release 9 | - SWIFT_VERSION=swift-5.2.3-RELEASE 10 | jobs: 11 | include: 12 | # The first stage will run all unit tests using Ubuntu 13 | - stage: Linux test 14 | os: linux 15 | language: generic 16 | dist: trusty 17 | sudo: required 18 | install: 19 | - sudo apt-get install clang libicu-dev 20 | - mkdir swift 21 | - curl https://swift.org/builds/$SWIFT_BRANCH/ubuntu1804/$SWIFT_VERSION/$SWIFT_VERSION-ubuntu18.04.tar.gz 22 | -s | tar xz -C swift &> /dev/null 23 | - export PATH="$(pwd)/swift/$SWIFT_VERSION-ubuntu18.04/usr/bin:$PATH" 24 | script: 25 | - swift package update 26 | - swift test 27 | # The second stage will run all tests on macOS 28 | - stage: OSX test 29 | os: osx 30 | osx_image: xcode11.4.1 31 | language: swift 32 | sudo: required 33 | install: 34 | - wget https://swift.org/builds/$SWIFT_BRANCH/xcode/$SWIFT_VERSION/$SWIFT_VERSION-osx.pkg 35 | - sudo installer -pkg $SWIFT_VERSION-osx.pkg -target / 36 | - export PATH="/Library/Developer/Toolchains/$SWIFT_VERSION.xctoolchain/usr/bin:$PATH" 37 | script: 38 | - swift package update 39 | - swift test 40 | -------------------------------------------------------------------------------- /DOCUMENTATION.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | ## Load a world 4 | 5 | The first thing to know is that there are two types of worlds: `local` and `remote`. Local worlds are running locally on the server, while remote worlds are connected to a remote server (it can be a spigot server for example). 6 | 7 | ```swift 8 | // Load a local world 9 | server.registerLocalWorld(name: "world") 10 | 11 | // Load a remote world 12 | server.registerRemoteWorld(host: "123.123.123.123", port: 25565) 13 | ``` 14 | 15 | Note: The local world will create a folder at your SwiftMC server root. 16 | 17 | ## Register a custom command 18 | 19 | For each command you want to register, you need to create a class conforming to `Command`: 20 | 21 | ```swift 22 | public class MyCommand: Command { 23 | 24 | public func execute(server: SwiftMC, sender: CommandSender, args: [String]) { 25 | // Run your command here 26 | 27 | } 28 | 29 | public func description() -> String { 30 | // Give a description of your command, shown in the /help 31 | return "A custom command" 32 | } 33 | 34 | } 35 | ``` 36 | 37 | Then, you need to register you command just before starting your server: 38 | 39 | ```swift 40 | // Register your command as /mycommand 41 | server.registerCommand("mycommand", command: MyCommand()) 42 | ``` 43 | 44 | ## Listen for events 45 | 46 | ```swift 47 | // TODO 48 | ``` 49 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.2 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "SwiftMC", 8 | products: [ 9 | // Products define the executables and libraries produced by a package, and make them visible to other packages. 10 | .library( 11 | name: "SwiftMC", 12 | targets: ["SwiftMC"] 13 | ), 14 | .executable( 15 | name: "SwiftMCRun", 16 | targets: ["SwiftMCRun"] 17 | ) 18 | ], 19 | dependencies: [ 20 | // Dependencies declare other packages that this package depends on. 21 | .package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0"), 22 | .package(url: "https://github.com/adam-fowler/compress-nio.git", from: "0.0.1"), 23 | .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.0.0"), 24 | .package(url: "https://github.com/krzyzanowskim/CryptoSwift.git", from: "1.0.0") 25 | ], 26 | targets: [ 27 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 28 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 29 | .target( 30 | name: "SwiftMC", 31 | dependencies: [ 32 | .product(name: "NIO", package: "swift-nio"), 33 | .product(name: "CompressNIO", package: "compress-nio"), 34 | .product(name: "AsyncHTTPClient", package: "async-http-client"), 35 | .product(name: "CryptoSwift", package: "CryptoSwift") 36 | ] 37 | ), 38 | .target( 39 | name: "SwiftMCRun", 40 | dependencies: ["SwiftMC"] 41 | ), 42 | .testTarget( 43 | name: "SwiftMCTests", 44 | dependencies: ["SwiftMC"] 45 | ) 46 | ] 47 | ) 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SwiftMC 2 | 3 | [![Build Status](https://travis-ci.com/GroupeMINASTE/SwiftMC.svg?token=oK8ceAyYNdbxPjHsz2xq&branch=master)](https://travis-ci.com/GroupeMINASTE/SwiftMC) 4 | [![License](https://img.shields.io/github/license/GroupeMINASTE/SwiftMC)](LICENSE) 5 | [![Issues](https://img.shields.io/github/issues/GroupeMINASTE/SwiftMC)]() 6 | [![Pull Requests](https://img.shields.io/github/issues-pr/GroupeMINASTE/SwiftMC)]() 7 | [![Code Size](https://img.shields.io/github/languages/code-size/GroupeMINASTE/SwiftMC)]() 8 | [![CodeFactor](https://www.codefactor.io/repository/github/groupeminaste/swiftmc/badge)](https://www.codefactor.io/repository/github/groupeminaste/swiftmc) 9 | [![Open Source Helpers](https://www.codetriage.com/groupeminaste/swiftmc/badges/users.svg)](https://www.codetriage.com/groupeminaste/swiftmc) 10 | 11 | A Minecraft server and proxy written from scratch in Swift. 12 | 13 | > **NOTICE**: This swift package is in active development, so the code may build with warnings or errors 14 | 15 | ## Installation (run a server) 16 | 17 | Clone the repository and start the server 18 | 19 | ```bash 20 | git clone https://github.com/GroupeMINASTE/SwiftMC.git 21 | cd SwiftMC 22 | swift run -c release 23 | ``` 24 | WARNING: You must use a MacOS system with Xcode installed to compile this ! 25 | 26 | 27 | ## Create a custom server 28 | 29 | Add SwiftMC to the dependencies of your swift executable package: 30 | 31 | ```swift 32 | .package(url: "https://github.com/GroupeMINASTE/SwiftMC.git", from: "0.0.1") 33 | ``` 34 | 35 | Create a server: 36 | 37 | ```swift 38 | import SwiftMC 39 | 40 | // Initialize a server 41 | let server = SwiftMC() 42 | 43 | // And start it 44 | DispatchQueue.global().async { 45 | server.start() 46 | } 47 | 48 | // Read commands from console 49 | while let input = readLine(strippingNewline: true) { 50 | server.dispatchCommand(command: input) 51 | } 52 | ``` 53 | 54 | See [DOCUMENTATION.md](DOCUMENTATION.md) for a full documentation of all available features to customize your server. 55 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Blocks/Material.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class Material: Equatable { 23 | 24 | // Constants 25 | public static let air = Material(id: 0, stack: 0, transparent: true) 26 | public static let stone = Material(id: 1, solid: true, occluding: true) 27 | public static let grass = Material(id: 2, solid: true, occluding: true) 28 | public static let dirt = Material(id: 3, solid: true, occluding: true) 29 | public static let cobblestone = Material(id: 4, solid: true, occluding: true) 30 | public static let wood = Material(id: 5, solid: true, flammable: true, burnable: true, occluding: true) 31 | public static let sapling = Material(id: 6, transparent: true) 32 | public static let bedrock = Material(id: 7, solid: true, occluding: true) 33 | 34 | // List of all values 35 | public static let values = [ 36 | air, 37 | stone, 38 | grass, 39 | dirt, 40 | cobblestone, 41 | wood, 42 | sapling, 43 | bedrock 44 | ] 45 | 46 | // Get a material by id 47 | public static func get(id: UInt16) -> Material? { 48 | return values.first(where: { $0.id == id }) 49 | } 50 | 51 | // Properties 52 | public let id: UInt16 53 | public let stack: UInt8 54 | public let durability: UInt16 55 | public let data: MaterialData.Type 56 | public let edible: Bool 57 | public let solid: Bool 58 | public let transparent: Bool 59 | public let flammable: Bool 60 | public let burnable: Bool 61 | public let occluding: Bool 62 | public let gravity: Bool 63 | 64 | // Initializer 65 | internal init(id: UInt16, stack: UInt8 = 64, durability: UInt16 = 0, data: MaterialData.Type = MaterialData.self, edible: Bool = false, solid: Bool = false, transparent: Bool = false, flammable: Bool = false, burnable: Bool = false, occluding: Bool = false, gravity: Bool = false) { 66 | self.id = id 67 | self.stack = stack 68 | self.durability = durability 69 | self.data = data 70 | self.edible = edible 71 | self.solid = solid 72 | self.transparent = transparent 73 | self.flammable = flammable 74 | self.burnable = burnable 75 | self.occluding = occluding 76 | self.gravity = gravity 77 | } 78 | 79 | // Equatable 80 | public static func == (lhs: Material, rhs: Material) -> Bool { 81 | return lhs.id == rhs.id 82 | } 83 | 84 | // Create a data object 85 | public func getNewData(raw: UInt8) -> MaterialData { 86 | return data.init(id: id, data: raw) 87 | } 88 | 89 | // Checks if material is a block 90 | public func isBlock() -> Bool { 91 | return id < 256 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Blocks/MaterialData.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class MaterialData { 23 | 24 | // Properties 25 | public let id: UInt16 26 | public var data: UInt8 27 | 28 | // Initializer 29 | public required init(id: UInt16, data: UInt8) { 30 | self.id = id 31 | self.data = data 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Chat/ChatColor.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class ChatColor: CustomStringConvertible, Equatable { 23 | 24 | public static let black = ChatColor("0", id: "black", ansi: 30) 25 | public static let dark_blue = ChatColor("1", id: "dark_blue", ansi: 34) 26 | public static let dark_green = ChatColor("2", id: "dark_green", ansi: 32) 27 | public static let dark_aqua = ChatColor("3", id: "dark_aqua", ansi: 36) 28 | public static let dark_red = ChatColor("4", id: "dark_red", ansi: 31) 29 | public static let dark_purple = ChatColor("5", id: "dark_purple", ansi: 35) 30 | public static let gold = ChatColor("6", id: "gold", ansi: 33) 31 | public static let gray = ChatColor("7", id: "gray", ansi: 37) 32 | public static let dark_gray = ChatColor("8", id: "dark_gray", ansi: 90) 33 | public static let blue = ChatColor("9", id: "blue", ansi: 94) 34 | public static let green = ChatColor("a", id: "green", ansi: 92) 35 | public static let aqua = ChatColor("b", id: "aqua", ansi: 96) 36 | public static let red = ChatColor("c", id: "red", ansi: 91) 37 | public static let light_purple = ChatColor("d", id: "light_purple", ansi: 95) 38 | public static let yellow = ChatColor("e", id: "yellow", ansi: 93) 39 | public static let white = ChatColor("f", id: "white", ansi: 97) 40 | public static let magic = ChatColor("k", id: "obfuscated", ansi: 5) 41 | public static let bold = ChatColor("l", id: "bold", ansi: 1) 42 | public static let strikethrough = ChatColor("m", id: "strikethrough", ansi: 9) 43 | public static let underline = ChatColor("n", id: "underline", ansi: 4) 44 | public static let italic = ChatColor("o", id: "italic", ansi: 3) 45 | public static let reset = ChatColor("r", id: "reset", ansi: 0) 46 | 47 | public static let colors: [ChatColor] = [ 48 | .black, .dark_blue, .dark_green, .dark_aqua, .dark_red, .dark_purple, .gold, .gray, 49 | .dark_gray, .blue, .green, .aqua, .red, .light_purple, .yellow, .white, .reset 50 | ] 51 | 52 | public static let all: [ChatColor] = colors + [ 53 | .magic, .bold, .strikethrough, .underline, .italic, .reset 54 | ] 55 | 56 | public static let color_char: Character = "§" 57 | 58 | public static func + (lhs: ChatColor, rhs: ChatColor) -> String { 59 | return lhs.description + rhs.description 60 | } 61 | 62 | public let char: Character 63 | public let id: String 64 | public let ansi: Int 65 | 66 | internal init(_ char: Character, id: String, ansi: Int) { 67 | self.char = char 68 | self.id = id 69 | self.ansi = ansi 70 | } 71 | 72 | public var description: String { 73 | return "\(ChatColor.color_char)\(char)" 74 | } 75 | 76 | public func toAnsi() -> String { 77 | return "\u{001B}[\(ansi)m" 78 | } 79 | 80 | public static func == (lhs: ChatColor, rhs: ChatColor) -> Bool { 81 | return lhs.id == rhs.id 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Chat/ChatProgressBar.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class ChatProgressBar: ChatMessage { 23 | 24 | private let dispatchQueue: DispatchQueue 25 | private let total: Int 26 | private let width: Int 27 | private var count: Int 28 | private var first: Bool 29 | private var logger: (ChatMessage) -> () 30 | private var done: () -> () 31 | 32 | public init(total: Int, width: Int, logger: @escaping (ChatMessage) -> (), done: @escaping () -> ()) { 33 | self.dispatchQueue = DispatchQueue(label: "progressBar") 34 | self.total = total 35 | self.width = width 36 | self.logger = logger 37 | self.done = done 38 | self.count = 0 39 | self.first = true 40 | super.init(text: "") 41 | self.logger(self) 42 | } 43 | 44 | required init(from decoder: Decoder) throws { 45 | fatalError("init(from:) has not been implemented") 46 | } 47 | 48 | public func increment() { 49 | dispatchQueue.sync { 50 | if count < total { 51 | count += 1 52 | } 53 | self.logger(self) 54 | if count >= total { 55 | done() 56 | } 57 | } 58 | } 59 | 60 | public override func toString(useAnsi: Bool = false) -> String { 61 | // Init string 62 | var string = "" 63 | 64 | // Replace last line 65 | if !first && useAnsi { 66 | string += "\u{001B}[2K\u{001B}[A" 67 | } 68 | self.first = false 69 | 70 | // Create bar 71 | let n = (count * width) / total 72 | let bar = "[\(String(repeating: "#", count: n))\(String(repeating: " ", count: width - n))]" 73 | let p = " \((count * 100) / total)% " 74 | let s = (bar.count / 2) - p.count + 1 75 | string += bar.replacingCharacters(in: bar.index(bar.startIndex, offsetBy: s) ..< bar.index(bar.startIndex, offsetBy: s + p.count), with: p) 76 | 77 | // Return the result 78 | return string 79 | } 80 | 81 | public func getFirstAndSet() -> Bool { 82 | let old = first 83 | self.first = false 84 | return old 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Chat/CommandSender.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public protocol CommandSender { 24 | 25 | func getName() -> String 26 | 27 | func sendMessage(message: ChatMessage) 28 | 29 | } 30 | 31 | extension CommandSender { 32 | 33 | public func sendMessage(message: String) { 34 | self.sendMessage(message: ChatMessage(text: message)) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Commands/ChatCommand.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class ChatCommand: Command { 23 | 24 | public func execute(server: SwiftMC, sender: CommandSender, args: [String]) { 25 | // Get the message 26 | let message = args.joined(separator: " ") 27 | 28 | // Check sender 29 | if let player = sender as? Player { 30 | // Fire PlayerChatEvent 31 | let event = PlayerChatEvent(player: player, message: message, format: "\(ChatColor.aqua)[%@] \(ChatColor.reset)%@") 32 | server.fireListeners(for: event) 33 | server.broadcast(packet: Chat(message: ChatMessage(text: String(format: event.format, sender.getName(), event.message)))) 34 | } else { 35 | // Send server chat 36 | server.broadcast(packet: Chat(message: ChatMessage(text: String(format: "\(ChatColor.red)[%@] \(ChatColor.reset)%@", sender.getName(), message)))) 37 | } 38 | } 39 | 40 | public func description() -> String { 41 | return "Send a message to the global chat" 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Commands/Command.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public protocol Command { 23 | 24 | func execute(server: SwiftMC, sender: CommandSender, args: [String]) 25 | 26 | func description() -> String 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Commands/GamemodeCommand.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class GamemodeCommand: Command { 23 | 24 | public func execute(server: SwiftMC, sender: CommandSender, args: [String]) { 25 | // Check sender 26 | if let player = sender as? Player { 27 | if args.count == 1 || args.count == 2 { 28 | // Get gamemode 29 | var gamemode: GameMode? 30 | if args[0] == "survival" || args[0] == "0" { 31 | gamemode = .survival 32 | } else if args[0] == "creative" || args[0] == "1" { 33 | gamemode = .creative 34 | } else if args[0] == "adventure" || args[0] == "2" { 35 | gamemode = .adventure 36 | } else if args[0] == "spectator" || args[0] == "3" { 37 | gamemode = .spectator 38 | } 39 | 40 | // Check gamemode 41 | if let gamemode = gamemode { 42 | // Check player 43 | var target = player 44 | if args.count == 2 { 45 | guard let newTarget = server.getPlayer(name: args[1]) else { 46 | // Error message 47 | sender.sendMessage(message: ChatColor.red + "Unable to find player \(args[1])!") 48 | return 49 | } 50 | target = newTarget 51 | } 52 | 53 | // Change gamemode 54 | target.setGameMode(to: gamemode) 55 | sender.sendMessage(message: ChatColor.yellow + "\(target.getName() == player.getName() ? "Your" : player.getName()+"'s") gamemode was changed to \(gamemode)!") 56 | } else { 57 | // Error message 58 | sender.sendMessage(message: ChatColor.red + "Usage: /gamemode [player]") 59 | } 60 | } else { 61 | // Error message 62 | sender.sendMessage(message: ChatColor.red + "Usage: /gamemode [player]") 63 | } 64 | } else { 65 | // Error message 66 | sender.sendMessage(message: ChatColor.red + "Only players can use this command!") 67 | } 68 | } 69 | 70 | public func description() -> String { 71 | return "Change a player gamemode" 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Commands/HelpCommand.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class HelpCommand: Command { 23 | 24 | public func execute(server: SwiftMC, sender: CommandSender, args: [String]) { 25 | // Init base message 26 | var message = ChatColor.aqua + "SwiftMC Server - Developed by Nathan Fallet at Groupe MINASTE" 27 | 28 | // Iterate commands 29 | for (name, command) in server.commands { 30 | message.append("\n\(ChatColor.gold)/\(name): \(ChatColor.yellow)\(command.description())") 31 | } 32 | 33 | // Print help 34 | sender.sendMessage(message: ChatMessage(text: message)) 35 | } 36 | 37 | public func description() -> String { 38 | return "Print this help command" 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Commands/StopCommand.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class StopCommand: Command { 23 | 24 | public func execute(server: SwiftMC, sender: CommandSender, args: [String]) { 25 | // Stop the server 26 | server.stop() 27 | } 28 | 29 | public func description() -> String { 30 | return "Stop the server" 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Commands/WorldCommand.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class WorldCommand: Command { 23 | 24 | public func execute(server: SwiftMC, sender: CommandSender, args: [String]) { 25 | if let player = sender as? Player { 26 | if args.count == 2 { 27 | // Get world type 28 | var type: WorldType? 29 | if args[0].lowercased() == WorldType.local.rawValue { 30 | type = .local 31 | } else if args[0].lowercased() == WorldType.remote.rawValue { 32 | type = .remote 33 | } 34 | if let type = type { 35 | // Get world by name 36 | if let world = server.worlds.first(where: { $0.getType() == type && $0.getName().lowercased() == args[1].lowercased() }) { 37 | // Go to this world 38 | player.goTo(world: world) 39 | } else { 40 | // Error message 41 | sender.sendMessage(message: ChatColor.red + "This world doesn't exist!") 42 | } 43 | } else { 44 | // Error message 45 | sender.sendMessage(message: ChatColor.red + "\"\(args[0])\" is not a correct world type! Try local or remote.") 46 | } 47 | } else { 48 | // Error message 49 | sender.sendMessage(message: ChatColor.red + "Usage: /world ") 50 | } 51 | } else { 52 | // Error message 53 | sender.sendMessage(message: ChatColor.red + "Only players can use this command!") 54 | } 55 | } 56 | 57 | public func description() -> String { 58 | return "Switch world" 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Configuration/GameMode.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public typealias GameMode = Int32 23 | 24 | public extension Int32 { 25 | 26 | static let survival: Int32 = 0 27 | static let creative: Int32 = 1 28 | static let adventure: Int32 = 2 29 | static let spectator: Int32 = 3 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Configuration/ServerInfo.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public struct ServerInfo: Codable { 23 | 24 | // MARK: - JSON Encoding/Decoding 25 | 26 | public static func decode(from json: String) -> ServerInfo? { 27 | if let data = json.data(using: .utf8), let object = try? JSONDecoder().decode(ServerInfo.self, from: data) { 28 | return object 29 | } 30 | return nil 31 | } 32 | 33 | public func toJSON() -> String? { 34 | if let json = try? JSONEncoder().encode(self), let string = String(bytes: json, encoding: .utf8) { 35 | return string 36 | } 37 | return nil 38 | } 39 | 40 | // MARK: - Server info content 41 | 42 | public var version: ServerVersion? 43 | public var players: ServerPlayers? 44 | public var description: ChatMessage? 45 | public var favicon: String? 46 | 47 | // MARK: - Server version 48 | 49 | public struct ServerVersion: Codable { 50 | enum CodingKeys: String, CodingKey { 51 | case name = "name", protocolVersion = "protocol" 52 | } 53 | var name: String? 54 | var protocolVersion: Int32? 55 | } 56 | 57 | // MARK: - Player list 58 | 59 | public struct ServerPlayers: Codable { 60 | var max: Int? 61 | var online: Int? 62 | var sample: [ServerPlayer]? 63 | } 64 | 65 | public struct ServerPlayer: Codable { 66 | var name: String? 67 | var id: String? 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Encryption/AuthentificationMode.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public enum AuthentificationMode { 23 | 24 | case online, offline, auto 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Entities/Entity.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public protocol Entity { 24 | 25 | func getID() -> Int32 26 | 27 | func getUUID() -> String 28 | 29 | func getLocation() -> Location 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Entities/Player.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public protocol Player: CommandSender, Entity { 24 | 25 | func goTo(world: WorldProtocol) 26 | 27 | func kick(reason: String) 28 | 29 | func isOnlineMode() -> Bool 30 | 31 | func hasSwiftMCPremium() -> Bool 32 | 33 | func setTabListMessage(header: ChatMessage, footer: ChatMessage) 34 | 35 | func getGameMode() -> GameMode 36 | 37 | func setGameMode(to gamemode: GameMode) 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Events/Event.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public protocol Event { 23 | 24 | func call(listener: EventListener) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Events/EventListener.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | open class EventListener { 23 | 24 | public init() {} 25 | 26 | open func onPlayerConnect(event: PlayerConnectEvent) {} 27 | open func onPlayerDisconnect(event: PlayerDisconnectEvent) {} 28 | open func onPlayerJoin(event: PlayerJoinEvent) {} 29 | open func onPlayerQuit(event: PlayerQuitEvent) {} 30 | open func onPlayerChat(event: PlayerChatEvent) {} 31 | open func onPlayerMove(event: PlayerMoveEvent) {} 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Events/PlayerChatEvent.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class PlayerChatEvent: Event { 23 | 24 | public let player: Player 25 | public var message: String 26 | public var format: String 27 | 28 | init(player: Player, message: String, format: String) { 29 | self.player = player 30 | self.message = message 31 | self.format = format 32 | } 33 | 34 | public func call(listener: EventListener) { 35 | listener.onPlayerChat(event: self) 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Events/PlayerConnectEvent.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class PlayerConnectEvent: Event { 23 | 24 | public let player: Player 25 | public var world: WorldProtocol? 26 | 27 | init(player: Player, world: WorldProtocol?) { 28 | self.player = player 29 | self.world = world 30 | } 31 | 32 | public func call(listener: EventListener) { 33 | listener.onPlayerConnect(event: self) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Events/PlayerDisconnectEvent.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class PlayerDisconnectEvent: Event { 23 | 24 | public let player: Player 25 | 26 | init(player: Player) { 27 | self.player = player 28 | } 29 | 30 | public func call(listener: EventListener) { 31 | listener.onPlayerDisconnect(event: self) 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Events/PlayerJoinEvent.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class PlayerJoinEvent: Event { 23 | 24 | public let player: Player 25 | public var message: String 26 | 27 | init(player: Player, message: String) { 28 | self.player = player 29 | self.message = message 30 | } 31 | 32 | public func call(listener: EventListener) { 33 | listener.onPlayerJoin(event: self) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Events/PlayerMoveEvent.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class PlayerMoveEvent: Event { 23 | 24 | public let player: Player 25 | public let from: Location 26 | public let to: Location 27 | public var cancel: Bool 28 | 29 | init(player: Player, location: Location) { 30 | self.player = player 31 | self.from = player.getLocation() 32 | self.to = location 33 | self.cancel = false 34 | } 35 | 36 | public func call(listener: EventListener) { 37 | listener.onPlayerMove(event: self) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Events/PlayerQuitEvent.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class PlayerQuitEvent: Event { 23 | 24 | public let player: Player 25 | public var message: String 26 | 27 | init(player: Player, message: String) { 28 | self.player = player 29 | self.message = message 30 | } 31 | 32 | public func call(listener: EventListener) { 33 | listener.onPlayerQuit(event: self) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Extensions/DataExtension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | extension Data { 23 | 24 | public func bin2hex() -> String { 25 | var string = "" 26 | for byte in [UInt8](self) { 27 | string += String(format: "%02hhx", byte) 28 | } 29 | return string 30 | } 31 | 32 | public func toSignedHexString() -> String { 33 | // Create an empty string 34 | var result = "" 35 | var first: Int8 = 0 36 | 37 | // Iterate bytes 38 | var bytes = map { byte in 39 | // Convert to Int8 40 | return Int8(bitPattern: byte) 41 | } 42 | while !bytes.isEmpty { 43 | // Get and remove the first byte 44 | let byte = bytes.removeFirst() 45 | 46 | // Check if this byte is the first byte 47 | if result.isEmpty && first == 0 { 48 | // Save the first byte 49 | first = byte 50 | } else if result.isEmpty && first != 0 { 51 | // Convert two first bytes to hex 52 | result.append(String(Int32(first + (byte < 0 ? 1 : 0)) * 256 + Int32(byte) + (first < 0 ? 1 : 0), radix: 16, uppercase: false)) 53 | } else { 54 | // Convert it to hex 55 | result.append(String(format: "%02hhx", first < 0 ? (Int32(bytes.isEmpty ? 256 : 255) - Int32(byte)) % 256 : byte)) 56 | } 57 | } 58 | 59 | // Return the final result 60 | return result 61 | } 62 | 63 | init(from value: T) where T: FixedWidthInteger { 64 | self = Swift.withUnsafeBytes(of: value.bigEndian) { Data($0) } 65 | } 66 | 67 | func to(type: T.Type) -> T? where T: FixedWidthInteger { 68 | var value: T = 0 69 | guard count >= MemoryLayout.size(ofValue: value) else { return nil } 70 | _ = Swift.withUnsafeMutableBytes(of: &value, { copyBytes(to: $0)} ) 71 | return value.bigEndian 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Extensions/FileHandleExtension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | extension FileHandle { 23 | 24 | public func seek(to offset: UInt64) { 25 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) { 26 | try? seek(toOffset: offset) 27 | } else { 28 | seek(toFileOffset: offset) 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Extensions/StringExtension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import CryptoSwift 22 | 23 | extension String { 24 | 25 | public func hex2bin() -> [UInt8] { 26 | var hex = self 27 | var array = [UInt8]() 28 | while hex.count >= 2 { 29 | let chars = String([hex.removeFirst(), hex.removeFirst()]) 30 | array.append(UInt8(chars, radix: 16) ?? 0) 31 | } 32 | return array 33 | } 34 | 35 | public func getUUID() -> String? { 36 | if let data = "OfflinePlayer:\(self)".data(using: .utf8) { 37 | var bytes = [UInt8](data.md5()) 38 | bytes[6] = bytes[6] & 0x0F | 0x30 39 | bytes[8] = bytes[8] & 0x3F | 0x80 40 | return Data(bytes).bin2hex().addSeparatorUUID() 41 | } 42 | return nil 43 | } 44 | 45 | public func addSeparatorUUID() -> String { 46 | var components = [String]() 47 | components.append(String(self[startIndex ..< index(startIndex, offsetBy: 8)])) 48 | components.append(String(self[index(startIndex, offsetBy: 8) ..< index(startIndex, offsetBy: 12)])) 49 | components.append(String(self[index(startIndex, offsetBy: 12) ..< index(startIndex, offsetBy: 16)])) 50 | components.append(String(self[index(startIndex, offsetBy: 16) ..< index(startIndex, offsetBy: 20)])) 51 | components.append(String(self[index(startIndex, offsetBy: 20) ..< endIndex])) 52 | return components.joined(separator: "-") 53 | } 54 | 55 | public func indent() -> String { 56 | split(separator: "\n").map({ "\t" + $0 }).joined(separator: "\n") 57 | } 58 | 59 | public static func + (lhs: String, rhs: ChatColor) -> String { 60 | return lhs + rhs.description 61 | } 62 | 63 | public static func + (lhs: ChatColor, rhs: String) -> String { 64 | return lhs.description + rhs 65 | } 66 | 67 | public static func += (lhs: inout String, rhs: ChatColor) { 68 | lhs += rhs.description 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Extensions/SystemExtension.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | extension System { 24 | 25 | // Operating system name 26 | static var name: String { 27 | #if os(Android) 28 | return "Android" 29 | #elseif os(Linux) 30 | return "Linux" 31 | #elseif os(macOS) 32 | return "Mac OS X" 33 | #elseif os(iOS) 34 | return "iOS" 35 | #elseif os(watchOS) 36 | return "watchOS" 37 | #elseif os(tvOS) 38 | return "tvOS" 39 | #elseif os(Windows) 40 | return "Windows" 41 | #else 42 | return "Other" 43 | #endif 44 | } 45 | 46 | // Operating system arch 47 | static var arch: String { 48 | #if arch(i386) 49 | return "i386" 50 | #elseif arch(x86_64) 51 | return "x86_64" 52 | #elseif arch(arm) 53 | return "arm" 54 | #elseif arch(arm64) 55 | return "arm64" 56 | #else 57 | return "Other" 58 | #endif 59 | } 60 | 61 | // Operating system version 62 | static var version: String { 63 | let version = ProcessInfo.processInfo.operatingSystemVersion 64 | return "\(version.majorVersion).\(version.minorVersion).\(version.patchVersion)" 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /Sources/SwiftMC/HTTP/BStatsSubmitData.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | import AsyncHTTPClient 23 | 24 | public class BStatsSubmitData { 25 | 26 | let server: SwiftMC 27 | 28 | public init(server: SwiftMC) { 29 | self.server = server 30 | } 31 | 32 | public func fetch(in eventLoopGroup: EventLoopGroup) { 33 | let client = HTTPClient(eventLoopGroupProvider: .shared(eventLoopGroup)) 34 | 35 | var urlComponents = URLComponents() 36 | urlComponents.scheme = "https" 37 | urlComponents.host = "bstats.org" 38 | urlComponents.path = "/submitData/server-implementation" 39 | 40 | guard let url = urlComponents.url else { 41 | return 42 | } 43 | 44 | guard let body = try? JSONSerialization.data(withJSONObject: [ 45 | // Server data 46 | "serverUUID": server.configuration.bstats["server-uuid"] ?? UUID().uuidString, 47 | "osName": System.name, 48 | "osArch": System.arch, 49 | "osVersion": System.version, 50 | "coreCount": System.coreCount, 51 | 52 | // Plugin data 53 | "plugins": [ 54 | [ 55 | "pluginName": "SwiftMC", 56 | "customCharts": [ 57 | // Players 58 | [ 59 | "chartId": "players", 60 | "data": [ 61 | "value": server.players.count 62 | ] 63 | ], 64 | // Mode 65 | [ 66 | "chartId": "mode", 67 | "data": [ 68 | "value": "\(server.configuration.mode)" 69 | ] 70 | ], 71 | ] 72 | ] 73 | ] 74 | ], options: []) else { 75 | return 76 | } 77 | 78 | if var request = try? HTTPClient.Request(url: url.absoluteString, method: .POST) { 79 | request.headers.add(name: "Accept", value: "application/json") 80 | request.headers.add(name: "Content-Type", value: "application/json") 81 | request.headers.add(name: "User-Agent", value: "MC-Server/1") 82 | request.body = .data(body) 83 | 84 | client.execute(request: request).whenComplete { _ in 85 | try? client.syncShutdown() 86 | } 87 | } 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /Sources/SwiftMC/HTTP/MojangHasJoined.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | import AsyncHTTPClient 23 | 24 | public class MojangHasJoined { 25 | 26 | let username: String 27 | let serverId: String 28 | 29 | public init(username: String, serverId: String) { 30 | self.username = username 31 | self.serverId = serverId 32 | } 33 | 34 | public func fetch(in eventLoopGroup: EventLoopGroup, completionHandler: @escaping ([String: Any]?) -> ()) { 35 | let client = HTTPClient(eventLoopGroupProvider: .shared(eventLoopGroup)) 36 | 37 | var urlComponents = URLComponents() 38 | urlComponents.scheme = "https" 39 | urlComponents.host = "sessionserver.mojang.com" 40 | urlComponents.path = "/session/minecraft/hasJoined" 41 | urlComponents.queryItems = [ 42 | URLQueryItem(name: "username", value: username), 43 | URLQueryItem(name: "serverId", value: serverId) 44 | ] 45 | 46 | guard let url = urlComponents.url else { 47 | completionHandler(nil) 48 | return 49 | } 50 | 51 | client.get(url: url.absoluteString).whenComplete { result in 52 | switch result { 53 | case.failure(_): 54 | completionHandler(nil) 55 | case .success(let response): 56 | if response.status == .ok, let body = response.body, let json = try?JSONSerialization.jsonObject(with: Data(buffer: body), options: []) as? [String: Any] { 57 | completionHandler(json) 58 | } else { 59 | completionHandler(nil) 60 | } 61 | } 62 | try? client.syncShutdown() 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /Sources/SwiftMC/HTTP/MojangJoin.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | import AsyncHTTPClient 23 | 24 | public class MojangJoin { 25 | 26 | let accessToken: String 27 | let selectedProfile: String 28 | let serverId: String 29 | 30 | public init(accessToken: String, selectedProfile: String, serverId: String) { 31 | self.accessToken = accessToken 32 | self.selectedProfile = selectedProfile 33 | self.serverId = serverId 34 | } 35 | 36 | public func fetch(in eventLoopGroup: EventLoopGroup, completionHandler: @escaping (Bool) -> ()) { 37 | let client = HTTPClient(eventLoopGroupProvider: .shared(eventLoopGroup)) 38 | 39 | var urlComponents = URLComponents() 40 | urlComponents.scheme = "https" 41 | urlComponents.host = "sessionserver.mojang.com" 42 | urlComponents.path = "/session/minecraft/join" 43 | 44 | guard let url = urlComponents.url else { 45 | completionHandler(false) 46 | return 47 | } 48 | 49 | guard let body = try? JSONSerialization.data(withJSONObject: [ 50 | "accessToken": accessToken, 51 | "selectedProfile": selectedProfile, 52 | "serverId": serverId 53 | ], options: []) else { 54 | completionHandler(false) 55 | return 56 | } 57 | 58 | client.post(url: url.absoluteString, body: .data(body)).whenComplete { result in 59 | switch result { 60 | case.failure(_): 61 | completionHandler(false) 62 | case .success(let response): 63 | if response.status == .noContent { 64 | completionHandler(true) 65 | } else { 66 | completionHandler(false) 67 | } 68 | } 69 | try? client.syncShutdown() 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Handlers/ChannelHandler.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | protocol ChannelHandler { 24 | 25 | var handler: PacketHandler? { get set } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Handlers/ClientHandler.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public final class ClientHandler: ChannelInboundHandler, ChannelHandler { 24 | 25 | // Requirements 26 | public typealias InboundIn = Packet 27 | public typealias OutboundOut = Packet 28 | 29 | // Variables 30 | let channelWrapper: ChannelWrapper 31 | var handler: PacketHandler? 32 | 33 | // Initializer 34 | init(channelWrapper: ChannelWrapper) { 35 | self.channelWrapper = channelWrapper 36 | self.channelWrapper.handler = self 37 | self.channelWrapper.setHandler(handler: InitialHandler()) 38 | } 39 | 40 | public func channelRead(context: ChannelHandlerContext, data: NIOAny) { 41 | // Close if server is not ready 42 | if !channelWrapper.server.ready { 43 | channelWrapper.close() 44 | return 45 | } 46 | 47 | // Read wrapper 48 | let packet = unwrapInboundIn(data) 49 | 50 | // Check for debug 51 | if channelWrapper.server.configuration.debug { 52 | channelWrapper.server.log("CLIENT -> SERVER: \(packet.toString())") 53 | } 54 | 55 | // Handle packet 56 | if let handler = handler { 57 | let sendPacket = handler.shouldHandle(packet: packet) 58 | if sendPacket { 59 | handler.handle(packet: packet) 60 | } 61 | } 62 | } 63 | 64 | // This method is called if the socket is closed in a clean way. 65 | public func channelInactive(context: ChannelHandlerContext) { 66 | // Mark as closed 67 | channelWrapper.close() 68 | } 69 | 70 | // Called if an error happens. Log and close the socket. 71 | public func errorCaught(context: ChannelHandlerContext, error: Error) { 72 | // Mark as closed 73 | channelWrapper.close() 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Handlers/GameHandler.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | class GameHandler: PacketHandler { 24 | 25 | var channel: ChannelWrapper? 26 | 27 | func connected(channel: ChannelWrapper) { 28 | // Save channel 29 | self.channel = channel 30 | 31 | // Fire PlayerConnectEvent 32 | let event = PlayerConnectEvent(player: channel, world: channel.server.worlds.first) 33 | channel.server.fireListeners(for: event) 34 | 35 | // Login to the selected world 36 | if let world = event.world { 37 | channel.goTo(world: world) 38 | } else { 39 | disconnect(reason: "No world found on this server!") 40 | return 41 | } 42 | } 43 | 44 | func disconnected(channel: ChannelWrapper) { 45 | // Remove channel 46 | self.channel = nil 47 | 48 | // Foward to remote world 49 | if let world = channel.world { 50 | world.disconnect(client: channel) 51 | } 52 | } 53 | 54 | func shouldHandle(packet: Packet) -> Bool { 55 | return !(channel?.closing ?? true) 56 | } 57 | 58 | func handle(packet: Packet) { 59 | // Check packet type 60 | if let pluginMessage = packet as? PluginMessage { 61 | self.handle(pluginMessage: pluginMessage) 62 | } 63 | if let chat = packet as? Chat { 64 | if self.handle(chat: chat) { 65 | return 66 | } 67 | } 68 | 69 | // Foward packets to world 70 | if let channel = channel, let world = channel.world { 71 | world.handle(packet: packet, for: channel) 72 | } 73 | } 74 | 75 | func handle(pluginMessage: PluginMessage) { 76 | // Get channel 77 | if let channel = channel { 78 | // Check for a register 79 | if (pluginMessage.tag == "minecraft:register" || pluginMessage.tag == "REGISTER"), let string = String(bytes: Data(pluginMessage.data), encoding: .utf8) { 80 | // Iterate registered channels 81 | for pluginChannel in string.split(separator: "\0") { 82 | // Save the registered channels 83 | channel.pluginMessageChannels.append(String(pluginChannel)) 84 | 85 | // If the channel is a SwiftMC channel 86 | if pluginChannel.starts(with: "swiftmc:") { 87 | // Log it 88 | channel.server.log(ChatMessage(text: "\(channel.getName()) registered plugin message channel \(pluginChannel)")) 89 | 90 | // Check for SwiftMC:Premium channel 91 | if pluginChannel == "swiftmc:premium" { 92 | // Send message to ask for the access token 93 | channel.send(packet: PluginMessage(tag: "swiftmc:premium", data: [0x01])) 94 | } 95 | } 96 | } 97 | } 98 | 99 | // Check for a SwiftMC:Premium message 100 | var buffer = ByteBuffer(ByteBufferView(pluginMessage.data)) 101 | if pluginMessage.tag == "swiftmc:premium" && buffer.readableBytes >= 2 && buffer.readBytes(length: 1)?.first == 0x02 { 102 | // Read the token 103 | channel.accessToken = buffer.readVarString() 104 | } 105 | } 106 | } 107 | 108 | func handle(chat: Chat) -> Bool { 109 | if let channel = channel { 110 | // Check for a command 111 | if chat.message.starts(with: "/") { 112 | // Handle the command 113 | let follow = channel.world as? RemoteWorld != nil 114 | if channel.server.dispatchCommand(sender: channel, command: String(chat.message.suffix(chat.message.count - 1)), showError: !follow) { 115 | return true 116 | } 117 | return !follow 118 | } 119 | } 120 | return false 121 | } 122 | 123 | func disconnect(reason: String) { 124 | channel?.kick(reason: reason) 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Handlers/MinecraftEncoder.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | import CompressNIO 23 | 24 | class MinecraftEncoder: MessageToByteEncoder { 25 | 26 | // Input alias 27 | typealias OutboundIn = Packet 28 | 29 | // Configuration for encoding 30 | var channel: ChannelWrapper? 31 | var server: Bool 32 | var iv: [UInt8] 33 | 34 | // Initializer 35 | init(server: Bool) { 36 | self.server = server 37 | self.iv = [] 38 | } 39 | 40 | func encode(data: Packet, out: inout ByteBuffer) throws { 41 | // Init a temporary buffer 42 | var buffer1 = ByteBufferAllocator().buffer(capacity: 1024*1024) 43 | var buffer2 = ByteBufferAllocator().buffer(capacity: 1024*1024) 44 | var buffer3 = ByteBufferAllocator().buffer(capacity: 1024*1024) 45 | 46 | // Packet encoder 47 | try packetEncoder(data: data, out: &buffer1) 48 | 49 | // Threshold encoder 50 | try thresholdEncoder(from: &buffer1, out: &buffer2) 51 | 52 | // Frame encoder 53 | try frameEncoder(from: &buffer2, out: &buffer3) 54 | 55 | // Encryption encoder 56 | try encryptionEncoder(from: &buffer3, out: &out) 57 | } 58 | 59 | // Threshold 60 | func thresholdEncoder(from: inout ByteBuffer, out: inout ByteBuffer) throws { 61 | // Check for compression 62 | if let threshold = channel?.threshold, threshold != -1 { 63 | // Check for size 64 | let fromSize = Int32(from.readableBytes) 65 | if fromSize < threshold { 66 | out.writeVarInt(value: 0) 67 | out.writeBuffer(&from) 68 | } else { 69 | out.writeVarInt(value: fromSize) 70 | try from.compress(to: &out, with: .deflate) 71 | } 72 | } else { 73 | // Just send data 74 | out.writeBuffer(&from) 75 | } 76 | } 77 | 78 | // Frame encoder 79 | func frameEncoder(from: inout ByteBuffer, out: inout ByteBuffer) throws { 80 | out.writeVarInt(value: Int32(from.readableBytes)) 81 | out.writeBuffer(&from) 82 | } 83 | 84 | // Encryption encoder 85 | func encryptionEncoder(from: inout ByteBuffer, out: inout ByteBuffer) throws { 86 | if from.readableBytes > 0 { 87 | // AES(key: sharedKey, blockMode: CFB(iv: iv), padding: .noPadding).encrypt(bytes) 88 | if let sharedKey = channel?.sharedKey, let encrypted = EncryptionManager.crypt(.encrypt, data: Data(buffer: from), key: Data(sharedKey), iv: Data(iv)) { 89 | // Encrypt data with given key 90 | out.writeBytes([UInt8](encrypted)) 91 | 92 | // Update IV 93 | self.iv = iv + encrypted 94 | self.iv.removeFirst(encrypted.count) 95 | } else { 96 | // Just send data 97 | out.writeBuffer(&from) 98 | } 99 | } 100 | } 101 | 102 | // Packet encoder 103 | func packetEncoder(data: Packet, out: inout ByteBuffer) throws { 104 | // Get direction 105 | if let channel = channel, let direction = server ? channel.prot.to_client : channel.prot.to_server { 106 | // Get packet id 107 | if let id = direction.getId(for: type(of: data), version: channel.protocolVersion) { 108 | // Write packet id 109 | out.writeVarInt(value: id) 110 | } else if let unknownPacket = data as? UnknownPacket { 111 | // Write packet id 112 | out.writeVarInt(value: unknownPacket.packetId) 113 | } 114 | 115 | // And write packet content 116 | data.writePacket(to: &out, direction: direction, protocolVersion: channel.protocolVersion) 117 | } 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Handlers/PacketHandler.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | protocol PacketHandler { 24 | 25 | func connected(channel: ChannelWrapper) 26 | 27 | func disconnected(channel: ChannelWrapper) 28 | 29 | func shouldHandle(packet: Packet) -> Bool 30 | 31 | func handle(packet: Packet) 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Inventory/Slot.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public struct Slot { 23 | 24 | // Properties 25 | public var present: Bool 26 | public var id: Int32? 27 | public var count: UInt8? 28 | public var tag: NBTTag? 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTByte.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTByte: NBTTag { 24 | 25 | public var name: String? 26 | public var value: Int8 27 | 28 | public required init() { 29 | value = 0 30 | } 31 | 32 | public init(name: String?, value: Int8) { 33 | self.name = name 34 | self.value = value 35 | } 36 | 37 | public func readTag(from buffer: inout ByteBuffer) { 38 | self.value = buffer.readInteger(as: Int8.self) ?? value 39 | } 40 | 41 | public func writeTag(to buffer: inout ByteBuffer) { 42 | buffer.writeInteger(value) 43 | } 44 | 45 | public func toString() -> String { 46 | return "NBTByte(name: \(name ?? "NONE"), value: \(value))" 47 | } 48 | 49 | public func contentSize() -> Int { 50 | return 1 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTByteArray.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTByteArray: NBTTag { 24 | 25 | public var name: String? 26 | public var values: [Int8] 27 | 28 | public required init() { 29 | values = [] 30 | } 31 | 32 | public init(name: String?, values: [Int8]) { 33 | self.name = name 34 | self.values = values 35 | } 36 | 37 | public func readTag(from buffer: inout ByteBuffer) { 38 | let count = Int(buffer.readInteger(as: Int32.self) ?? 0) 39 | values = buffer.readBytes(length: count)?.map({ Int8(bitPattern: $0) }) ?? [] 40 | } 41 | 42 | public func writeTag(to buffer: inout ByteBuffer) { 43 | buffer.writeInteger(Int32(values.count), as: Int32.self) 44 | buffer.writeBytes(values.map({ UInt8(bitPattern: $0) })) 45 | } 46 | 47 | public func toString() -> String { 48 | return "NBTByteArray(name: \(name ?? "NONE"), values: \(values))" 49 | } 50 | 51 | public func contentSize() -> Int { 52 | return 4 + values.count 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTCompound.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTCompound: NBTTag { 24 | 25 | public var name: String? 26 | public var values: [NBTTag] 27 | 28 | public required init() { 29 | values = [] 30 | } 31 | 32 | public init(name: String?, values: [NBTTag]) { 33 | self.name = name 34 | self.values = values 35 | } 36 | 37 | public func readTag(from buffer: inout ByteBuffer) { 38 | repeat { 39 | values.append(NBTRegistry.readTag(in: &buffer)) 40 | } while !(values.last is NBTEnd) 41 | values.removeLast() 42 | } 43 | 44 | public func writeTag(to buffer: inout ByteBuffer) { 45 | for value in values { 46 | NBTRegistry.writeTag(tag: value, to: &buffer) 47 | } 48 | NBTRegistry.writeTag(tag: NBTEnd(), to: &buffer) 49 | } 50 | 51 | public func toString() -> String { 52 | return "NBTCompound(name: \(name ?? "NONE"), values:\n\(values.map({ $0.toString() }).joined(separator: "\n").indent())\n)" 53 | } 54 | 55 | public func contentSize() -> Int { 56 | return values.map({ $0.fullSize() }).reduce(1, { $0 + $1 }) 57 | } 58 | 59 | public subscript(name: String) -> NBTTag? { 60 | get { 61 | return values.first(where: { $0.name == name }) 62 | } 63 | set { 64 | values.removeAll(where: { $0.name == name }) 65 | if var newValue = newValue { 66 | newValue.name = name 67 | values.append(newValue) 68 | } 69 | } 70 | } 71 | 72 | public func put(_ newElement: NBTTag) { 73 | if let name = newElement.name { 74 | self[name] = newElement 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTDouble.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTDouble: NBTTag { 24 | 25 | public var name: String? 26 | public var value: Double 27 | 28 | public required init() { 29 | value = 0 30 | } 31 | 32 | public init(name: String?, value: Double) { 33 | self.name = name 34 | self.value = value 35 | } 36 | 37 | public func readTag(from buffer: inout ByteBuffer) { 38 | self.value = buffer.readDouble() ?? value 39 | } 40 | 41 | public func writeTag(to buffer: inout ByteBuffer) { 42 | buffer.writeDouble(value: value) 43 | } 44 | 45 | public func toString() -> String { 46 | return "NBTDouble(name: \(name ?? "NONE"), value: \(value))" 47 | } 48 | 49 | public func contentSize() -> Int { 50 | return 8 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTEnd.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTEnd: NBTTag { 24 | 25 | public var name: String? 26 | 27 | public required init() {} 28 | 29 | public func readTag(from buffer: inout ByteBuffer) {} 30 | 31 | public func writeTag(to buffer: inout ByteBuffer) {} 32 | 33 | public func toString() -> String { 34 | return "NBTEnd()" 35 | } 36 | 37 | public func contentSize() -> Int { 38 | return 0 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTFloat.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTFloat: NBTTag { 24 | 25 | public var name: String? 26 | public var value: Float32 27 | 28 | public required init() { 29 | value = 0 30 | } 31 | 32 | public init(name: String?, value: Float32) { 33 | self.name = name 34 | self.value = value 35 | } 36 | 37 | public func readTag(from buffer: inout ByteBuffer) { 38 | self.value = buffer.readFloat() ?? value 39 | } 40 | 41 | public func writeTag(to buffer: inout ByteBuffer) { 42 | buffer.writeFloat(value: value) 43 | } 44 | 45 | public func toString() -> String { 46 | return "NBTFloat(name: \(name ?? "NONE"), value: \(value))" 47 | } 48 | 49 | public func contentSize() -> Int { 50 | return 4 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTInt.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTInt: NBTTag { 24 | 25 | public var name: String? 26 | public var value: Int32 27 | 28 | public required init() { 29 | value = 0 30 | } 31 | 32 | public init(name: String?, value: Int32) { 33 | self.name = name 34 | self.value = value 35 | } 36 | 37 | public func readTag(from buffer: inout ByteBuffer) { 38 | self.value = buffer.readInteger(as: Int32.self) ?? value 39 | } 40 | 41 | public func writeTag(to buffer: inout ByteBuffer) { 42 | buffer.writeInteger(value) 43 | } 44 | 45 | public func toString() -> String { 46 | return "NBTInt(name: \(name ?? "NONE"), value: \(value))" 47 | } 48 | 49 | public func contentSize() -> Int { 50 | return 4 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTIntArray.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTIntArray: NBTTag { 24 | 25 | public var name: String? 26 | public var values: [Int32] 27 | 28 | public required init() { 29 | values = [] 30 | } 31 | 32 | public init(name: String?, values: [Int32]) { 33 | self.name = name 34 | self.values = values 35 | } 36 | 37 | public func readTag(from buffer: inout ByteBuffer) { 38 | let count = Int(buffer.readInteger(as: Int32.self) ?? 0) 39 | for _ in 0 ..< count { 40 | values.append(buffer.readInteger(as: Int32.self) ?? 0) 41 | } 42 | } 43 | 44 | public func writeTag(to buffer: inout ByteBuffer) { 45 | buffer.writeInteger(Int32(values.count), as: Int32.self) 46 | for value in values { 47 | buffer.writeInteger(value) 48 | } 49 | } 50 | 51 | public func toString() -> String { 52 | return "NBTIntArray(name: \(name ?? "NONE"), values: \(values))" 53 | } 54 | 55 | public func contentSize() -> Int { 56 | return 4 + (values.count * 4) 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTList.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTList: NBTTag { 24 | 25 | public var name: String? 26 | public var values: [NBTTag] 27 | 28 | public required init() { 29 | values = [] 30 | } 31 | 32 | public init(name: String?, values: [NBTTag]) { 33 | self.name = name 34 | self.values = values 35 | } 36 | 37 | public func readTag(from buffer: inout ByteBuffer) { 38 | let id = buffer.readBytes(length: 1)?.first ?? 0 39 | let count = Int(buffer.readInteger(as: Int32.self) ?? 0) 40 | for _ in 0 ..< count { 41 | let tag = NBTRegistry.createTag(id: id) 42 | tag.readTag(from: &buffer) 43 | values.append(tag) 44 | } 45 | } 46 | 47 | public func writeTag(to buffer: inout ByteBuffer) { 48 | buffer.writeBytes([NBTRegistry.getId(for: type(of: values.first ?? NBTEnd())) ?? 0]) 49 | buffer.writeInteger(Int32(values.count), as: Int32.self) 50 | for value in values { 51 | value.writeTag(to: &buffer) 52 | } 53 | } 54 | 55 | public func toString() -> String { 56 | return "NBTList(name: \(name ?? "NONE"), values:\n\(values.map({ $0.toString() }).joined(separator: "\n").indent())\n)" 57 | } 58 | 59 | public func contentSize() -> Int { 60 | return values.map({ $0.contentSize() }).reduce(5, { $0 + $1 }) 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTLong.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTLong: NBTTag { 24 | 25 | public var name: String? 26 | public var value: Int64 27 | 28 | public required init() { 29 | value = 0 30 | } 31 | 32 | public init(name: String?, value: Int64) { 33 | self.name = name 34 | self.value = value 35 | } 36 | 37 | public func readTag(from buffer: inout ByteBuffer) { 38 | self.value = buffer.readInteger(as: Int64.self) ?? value 39 | } 40 | 41 | public func writeTag(to buffer: inout ByteBuffer) { 42 | buffer.writeInteger(value) 43 | } 44 | 45 | public func toString() -> String { 46 | return "NBTLong(name: \(name ?? "NONE"), value: \(value))" 47 | } 48 | 49 | public func contentSize() -> Int { 50 | return 8 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTLongArray.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTLongArray: NBTTag { 24 | 25 | public var name: String? 26 | public var values: [Int64] 27 | 28 | public required init() { 29 | values = [] 30 | } 31 | 32 | public init(name: String?, values: [Int64]) { 33 | self.name = name 34 | self.values = values 35 | } 36 | 37 | public func readTag(from buffer: inout ByteBuffer) { 38 | let count = Int(buffer.readInteger(as: Int32.self) ?? 0) 39 | for _ in 0 ..< count { 40 | values.append(buffer.readInteger(as: Int64.self) ?? 0) 41 | } 42 | } 43 | 44 | public func writeTag(to buffer: inout ByteBuffer) { 45 | buffer.writeInteger(Int32(values.count), as: Int32.self) 46 | for value in values { 47 | buffer.writeInteger(value) 48 | } 49 | } 50 | 51 | public func toString() -> String { 52 | return "NBTLongArray(name: \(name ?? "NONE"), values: \(values))" 53 | } 54 | 55 | public func contentSize() -> Int { 56 | return 4 + (values.count * 8) 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTRegistry.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | class NBTRegistry { 24 | 25 | // Map of ID <=> Tag 26 | private static var nbtMap = [ 27 | // End tag 28 | 0: NBTEnd.self, 29 | 30 | // Byte 31 | 1: NBTByte.self, 32 | 33 | // Integers 34 | 2: NBTShort.self, 35 | 3: NBTInt.self, 36 | 4: NBTLong.self, 37 | 38 | // Floating numbers 39 | 5: NBTFloat.self, 40 | 6: NBTDouble.self, 41 | 42 | // Byte array 43 | 7: NBTByteArray.self, 44 | 45 | // String 46 | 8: NBTString.self, 47 | 48 | // Lists 49 | 9: NBTList.self, 50 | 10: NBTCompound.self, 51 | 52 | // Integer arrays 53 | 11: NBTIntArray.self, 54 | 12: NBTLongArray.self 55 | ] as [UInt8: NBTTag.Type] 56 | 57 | // Create a tag from id 58 | public static func createTag(id: UInt8, name: String? = nil) -> NBTTag { 59 | if let tag = nbtMap[id]?.init(name: name) { 60 | return tag 61 | } 62 | return NBTEnd() 63 | } 64 | 65 | // Get id from a tag 66 | public static func getId(for tag: NBTTag.Type) -> UInt8? { 67 | return nbtMap.first { item in 68 | return item.value == tag 69 | }?.key 70 | } 71 | 72 | // Read a tag 73 | public static func readTag(in buffer: inout ByteBuffer) -> NBTTag { 74 | // Get tag id 75 | let id = buffer.readBytes(length: 1)?.first ?? 0 76 | 77 | // Return if it is an end tag 78 | if id == 0 { 79 | return NBTEnd() 80 | } 81 | 82 | // Read the tag name 83 | let name = buffer.readShortPrefixedString() 84 | 85 | // Create a tag 86 | let tag = createTag(id: id, name: name) 87 | 88 | // Read the tag 89 | tag.readTag(from: &buffer) 90 | 91 | // And return it 92 | return tag 93 | } 94 | 95 | // Write a tag 96 | public static func writeTag(tag: NBTTag, to buffer: inout ByteBuffer) { 97 | // Get tag id 98 | let id = getId(for: type(of: tag)) ?? 0 99 | 100 | // Write the tag id 101 | buffer.writeBytes([id]) 102 | 103 | // Return if it is an end tag 104 | if id == 0 { 105 | return 106 | } 107 | 108 | // Write the tag name 109 | buffer.writeShortPrefixedString(string: tag.name ?? "") 110 | 111 | // Write the tag content 112 | tag.writeTag(to: &buffer) 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTShort.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTShort: NBTTag { 24 | 25 | public var name: String? 26 | public var value: Int16 27 | 28 | public required init() { 29 | value = 0 30 | } 31 | 32 | public init(name: String?, value: Int16) { 33 | self.name = name 34 | self.value = value 35 | } 36 | 37 | public func readTag(from buffer: inout ByteBuffer) { 38 | self.value = buffer.readInteger(as: Int16.self) ?? value 39 | } 40 | 41 | public func writeTag(to buffer: inout ByteBuffer) { 42 | buffer.writeInteger(value) 43 | } 44 | 45 | public func toString() -> String { 46 | return "NBTShort(name: \(name ?? "NONE"), value: \(value))" 47 | } 48 | 49 | public func contentSize() -> Int { 50 | return 2 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTString.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class NBTString: NBTTag { 24 | 25 | public var name: String? 26 | public var value: String 27 | 28 | public required init() { 29 | value = "" 30 | } 31 | 32 | public init(name: String?, value: String) { 33 | self.name = name 34 | self.value = value 35 | } 36 | 37 | public func readTag(from buffer: inout ByteBuffer) { 38 | self.value = buffer.readShortPrefixedString() ?? value 39 | } 40 | 41 | public func writeTag(to buffer: inout ByteBuffer) { 42 | buffer.writeShortPrefixedString(string: value) 43 | } 44 | 45 | public func toString() -> String { 46 | return "NBTString(name: \(name ?? "NONE"), value: \(value))" 47 | } 48 | 49 | public func contentSize() -> Int { 50 | return 2 + value.count 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Sources/SwiftMC/NBT/NBTTag.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public protocol NBTTag { 24 | 25 | init() 26 | 27 | var name: String? { get set } 28 | 29 | func readTag(from buffer: inout ByteBuffer) 30 | 31 | func writeTag(to buffer: inout ByteBuffer) 32 | 33 | func toString() -> String 34 | 35 | func contentSize() -> Int 36 | 37 | } 38 | 39 | extension NBTTag { 40 | 41 | public init(name: String? = nil) { 42 | self.init() 43 | self.name = name 44 | } 45 | 46 | public func fullSize() -> Int { 47 | if let name = name { 48 | return 3 + name.count + contentSize() 49 | } 50 | return 1 + contentSize() 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/BlockPlace.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class BlockPlace: Packet { 24 | 25 | public var position: UInt64 26 | public var direction: Int8 27 | 28 | public required init() { 29 | position = 0 30 | direction = 0 31 | } 32 | 33 | public init(position: UInt64, direction: Int8) { 34 | self.position = position 35 | self.direction = 0 36 | } 37 | 38 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 39 | self.position = buffer.readInteger(as: UInt64.self) ?? self.position 40 | self.direction = buffer.readInteger(as: Int8.self) ?? self.direction 41 | } 42 | 43 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 44 | buffer.writeInteger(self.position, as: UInt64.self) 45 | buffer.writeInteger(self.direction, as: Int8.self) 46 | } 47 | 48 | public func toString() -> String { 49 | return "BlockPlace(x: \(position >> 38), y: \(position & 0xFFF), z: \((position << 26) >> 38), direction: \(direction))" 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/Chat.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class Chat: Packet { 24 | 25 | public var message: String 26 | public var position: UInt8 27 | 28 | public required init() { 29 | message = "" 30 | position = 0 31 | } 32 | 33 | public init(message: String) { 34 | self.message = message 35 | self.position = 0 36 | } 37 | 38 | public init(message: ChatMessage) { 39 | self.message = message.toJSON() ?? "{}" 40 | self.position = 0 41 | } 42 | 43 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 44 | message = buffer.readVarString() ?? message 45 | if direction.direction == .to_client { 46 | position = buffer.readBytes(length: 1)?.first ?? position 47 | } 48 | } 49 | 50 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 51 | buffer.writeVarString(string: message) 52 | if direction.direction == .to_client { 53 | buffer.writeBytes([position]) 54 | } 55 | } 56 | 57 | public func toString() -> String { 58 | return "Chat(message: \(message), position: \(position))" 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/EncryptionRequest.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class EncryptionRequest: Packet { 24 | 25 | public var serverId: String 26 | public var publicKey: [UInt8] 27 | public var verifyToken: [UInt8] 28 | 29 | public required init() { 30 | serverId = "" 31 | publicKey = [] 32 | verifyToken = [] 33 | } 34 | 35 | public init(serverId: String, publicKey: [UInt8], verifyToken: [UInt8]) { 36 | self.serverId = serverId 37 | self.publicKey = publicKey 38 | self.verifyToken = verifyToken 39 | } 40 | 41 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 42 | serverId = buffer.readVarString() ?? serverId 43 | publicKey = buffer.readArray() ?? publicKey 44 | verifyToken = buffer.readArray() ?? verifyToken 45 | } 46 | 47 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 48 | buffer.writeVarString(string: serverId) 49 | buffer.writeArray(value: publicKey) 50 | buffer.writeArray(value: verifyToken) 51 | } 52 | 53 | public func toString() -> String { 54 | return "EncryptionRequest(serverId: \(serverId), publicKey: \(publicKey), verifyToken: \(verifyToken))" 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/EncryptionResponse.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class EncryptionResponse: Packet { 24 | 25 | public var sharedSecret: [UInt8] 26 | public var verifyToken: [UInt8] 27 | 28 | public required init() { 29 | sharedSecret = [] 30 | verifyToken = [] 31 | } 32 | 33 | public init(sharedSecret: [UInt8], verifyToken: [UInt8]) { 34 | self.sharedSecret = sharedSecret 35 | self.verifyToken = verifyToken 36 | } 37 | 38 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 39 | sharedSecret = buffer.readArray() ?? sharedSecret 40 | verifyToken = buffer.readArray() ?? verifyToken 41 | } 42 | 43 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 44 | buffer.writeArray(value: sharedSecret) 45 | buffer.writeArray(value: verifyToken) 46 | } 47 | 48 | public func toString() -> String { 49 | return "EncryptionResponse(sharedSecret: \(sharedSecret), verifyToken: \(verifyToken))" 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/GameState.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class GameState: Packet { 24 | 25 | public static let change_gamemode: UInt8 = 3 26 | public static let immediate_respawn: UInt8 = 11 27 | 28 | public var reason: UInt8 29 | public var value: Float32 30 | 31 | public required init() { 32 | reason = 0 33 | value = 0 34 | } 35 | 36 | public init(reason: UInt8, value: Float32) { 37 | self.reason = reason 38 | self.value = value 39 | } 40 | 41 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 42 | self.reason = buffer.readBytes(length: 1)?.first ?? reason 43 | self.value = buffer.readFloat() ?? value 44 | } 45 | 46 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 47 | buffer.writeBytes([reason]) 48 | buffer.writeFloat(value: value) 49 | } 50 | 51 | public func toString() -> String { 52 | return "GameState(reason: \(reason), value: \(value))" 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/Handshake.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class Handshake: Packet { 24 | 25 | public var protocolVersion: Int32 26 | public var host: String 27 | public var port: Int16 28 | public var requestedProtocol: Int32 29 | 30 | public required init() { 31 | protocolVersion = -1 32 | host = "" 33 | port = -1 34 | requestedProtocol = -1 35 | } 36 | 37 | public init(protocolVersion: Int32, host: String, port: Int16, requestedProtocol: Int32) { 38 | self.protocolVersion = protocolVersion 39 | self.host = host 40 | self.port = port 41 | self.requestedProtocol = requestedProtocol 42 | } 43 | 44 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 45 | self.protocolVersion = buffer.readVarInt() ?? self.protocolVersion 46 | self.host = buffer.readVarString() ?? self.host 47 | self.port = buffer.readInteger(as: Int16.self) ?? self.port 48 | self.requestedProtocol = buffer.readVarInt() ?? self.requestedProtocol 49 | } 50 | 51 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 52 | buffer.writeVarInt(value: protocolVersion) 53 | buffer.writeVarString(string: host) 54 | buffer.writeInteger(port) 55 | buffer.writeVarInt(value: requestedProtocol) 56 | } 57 | 58 | public func toString() -> String { 59 | return "Handshake(protocolVersion: \(protocolVersion), host: \(host), port: \(port), requestedProtocol: \(requestedProtocol))" 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/KeepAlive.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class KeepAlive: Packet { 24 | 25 | public var randomId: Int64 26 | 27 | public required init() { 28 | randomId = 0 29 | } 30 | 31 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 32 | randomId = protocolVersion >= ProtocolConstants.minecraft_1_12_2 ? 33 | buffer.readInteger(as: Int64.self) ?? randomId : 34 | Int64(buffer.readVarInt() ?? Int32(randomId)) 35 | } 36 | 37 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 38 | if protocolVersion >= ProtocolConstants.minecraft_1_12_2 { 39 | buffer.writeInteger(randomId) 40 | } else { 41 | buffer.writeVarInt(value: Int32(randomId)) 42 | } 43 | } 44 | 45 | public func toString() -> String { 46 | return "KeepAlive(randomId: \(randomId))" 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/Kick.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class Kick: Packet { 24 | 25 | public var message: String 26 | 27 | public required init() { 28 | message = "" 29 | } 30 | 31 | public init(message: String) { 32 | self.message = message 33 | } 34 | 35 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 36 | message = buffer.readVarString() ?? message 37 | } 38 | 39 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 40 | buffer.writeVarString(string: message) 41 | } 42 | 43 | public func toString() -> String { 44 | return "Kick(message: \(message))" 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/LegacyHandshake.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class LegacyHandshake: Packet { 24 | 25 | public required init() {} 26 | 27 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 28 | // ??? 29 | } 30 | 31 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 32 | // ??? 33 | } 34 | 35 | public func toString() -> String { 36 | return "LegacyHandshake()" 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/LegacyPing.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class LegacyPing: Packet { 24 | 25 | public var v1_5: Bool 26 | 27 | public required init() { 28 | self.v1_5 = false 29 | } 30 | 31 | public init(v1_5: Bool) { 32 | self.v1_5 = v1_5 33 | } 34 | 35 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 36 | // ??? 37 | } 38 | 39 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 40 | // ??? 41 | } 42 | 43 | public func toString() -> String { 44 | return "LegacyPing(v1_5: \(v1_5))" 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/Login.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class Login: Packet { 24 | 25 | public var entityId: Int32 26 | public var gameMode: UInt8 27 | public var dimension: Int32 28 | public var seed: Int64 29 | public var difficulty: UInt8 30 | public var maxPlayers: UInt8 31 | public var levelType: String 32 | public var viewDistance: Int32 33 | public var reducedDebugInfo: Bool 34 | public var normalRespawn: Bool 35 | 36 | public required init() { 37 | entityId = 0 38 | gameMode = 0 39 | dimension = 0 40 | seed = 0 41 | difficulty = 0 42 | maxPlayers = 0 43 | levelType = "" 44 | viewDistance = 0 45 | reducedDebugInfo = false 46 | normalRespawn = true 47 | } 48 | 49 | public init(entityId: Int32, gameMode: UInt8, dimension: Int32, seed: Int64, difficulty: UInt8, maxPlayers: UInt8, levelType: String, viewDistance: Int32, reducedDebugInfo: Bool, normalRespawn: Bool) { 50 | self.entityId = entityId 51 | self.gameMode = gameMode 52 | self.dimension = dimension 53 | self.seed = seed 54 | self.difficulty = difficulty 55 | self.maxPlayers = maxPlayers 56 | self.levelType = levelType 57 | self.viewDistance = viewDistance 58 | self.reducedDebugInfo = reducedDebugInfo 59 | self.normalRespawn = normalRespawn 60 | } 61 | 62 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 63 | entityId = buffer.readInteger(as: Int32.self) ?? entityId 64 | gameMode = buffer.readBytes(length: 1)?.first ?? gameMode 65 | if protocolVersion > ProtocolConstants.minecraft_1_9 { 66 | dimension = buffer.readInteger(as: Int32.self) ?? dimension 67 | } else { 68 | dimension = Int32(buffer.readBytes(length: 1)?.first ?? 0) 69 | } 70 | if protocolVersion >= ProtocolConstants.minecraft_1_15 { 71 | seed = buffer.readInteger(as: Int64.self) ?? seed 72 | } 73 | if protocolVersion < ProtocolConstants.minecraft_1_14 { 74 | difficulty = buffer.readBytes(length: 1)?.first ?? difficulty 75 | } 76 | maxPlayers = buffer.readBytes(length: 1)?.first ?? maxPlayers 77 | levelType = buffer.readVarString() ?? levelType 78 | if protocolVersion >= ProtocolConstants.minecraft_1_14 { 79 | viewDistance = buffer.readVarInt() ?? viewDistance 80 | } 81 | if protocolVersion >= 29 { 82 | reducedDebugInfo = buffer.readBool() ?? reducedDebugInfo 83 | } 84 | if protocolVersion >= ProtocolConstants.minecraft_1_15 { 85 | normalRespawn = buffer.readBool() ?? normalRespawn 86 | } 87 | } 88 | 89 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 90 | buffer.writeInteger(entityId) 91 | buffer.writeBytes([gameMode]) 92 | if protocolVersion > ProtocolConstants.minecraft_1_9 { 93 | buffer.writeInteger(dimension) 94 | } else { 95 | buffer.writeBytes([UInt8(dimension)]) 96 | } 97 | if protocolVersion >= ProtocolConstants.minecraft_1_15 { 98 | buffer.writeInteger(seed) 99 | } 100 | if protocolVersion < ProtocolConstants.minecraft_1_14 { 101 | buffer.writeBytes([difficulty]) 102 | } 103 | buffer.writeBytes([maxPlayers]) 104 | buffer.writeVarString(string: levelType) 105 | if protocolVersion >= ProtocolConstants.minecraft_1_14 { 106 | buffer.writeVarInt(value: viewDistance) 107 | } 108 | if protocolVersion >= 29 { 109 | buffer.writeBool(value: reducedDebugInfo) 110 | } 111 | if protocolVersion >= ProtocolConstants.minecraft_1_15 { 112 | buffer.writeBool(value: normalRespawn) 113 | } 114 | } 115 | 116 | public func toString() -> String { 117 | return "Login(entityId: \(entityId), gameMode: \(gameMode), dimension: \(dimension), seed: \(seed), difficulty: \(difficulty), maxPlayers: \(maxPlayers), levelType: \(levelType), viewDistance: \(viewDistance), reducedDebugInfo: \(reducedDebugInfo), normalRespawn: \(normalRespawn))" 118 | } 119 | 120 | } 121 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/LoginRequest.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class LoginRequest: Packet { 24 | 25 | public var data: String 26 | 27 | public required init() { 28 | data = "" 29 | } 30 | 31 | public init(data: String) { 32 | self.data = data 33 | } 34 | 35 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 36 | data = buffer.readVarString() ?? data 37 | } 38 | 39 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 40 | buffer.writeVarString(string: data) 41 | } 42 | 43 | public func toString() -> String { 44 | return "LoginRequest(data: \(data))" 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/LoginSuccess.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class LoginSuccess: Packet { 24 | 25 | public var uuid: String 26 | public var username: String 27 | 28 | public required init() { 29 | uuid = "" 30 | username = "" 31 | } 32 | 33 | public init(uuid: String, username: String) { 34 | self.uuid = uuid 35 | self.username = username 36 | } 37 | 38 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 39 | uuid = buffer.readVarString() ?? uuid 40 | username = buffer.readVarString() ?? username 41 | } 42 | 43 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 44 | buffer.writeVarString(string: uuid) 45 | buffer.writeVarString(string: username) 46 | } 47 | 48 | public func toString() -> String { 49 | return "LoginSuccess(uuid: \(uuid), username: \(username))" 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/MapChunk.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class MapChunk: Packet { 24 | 25 | public var x: Int32 26 | public var z: Int32 27 | public var groundUp: Bool 28 | public var bitMap: Int32 29 | public var heightmaps: NBTTag 30 | public var biomes: [Int32] 31 | public var chunkData: [UInt8] 32 | public var blockEntities: [NBTTag] 33 | 34 | public required init() { 35 | x = 0 36 | z = 0 37 | groundUp = false 38 | bitMap = 0 39 | heightmaps = NBTCompound(name: "") 40 | biomes = [] 41 | chunkData = [] 42 | blockEntities = [] 43 | } 44 | 45 | public init(x: Int32, z: Int32, groundUp: Bool, bitMap: Int32, heightmaps: NBTCompound, biomes: [Int32], chunkData: [UInt8], blockEntities: [NBTTag]) { 46 | self.x = x 47 | self.z = z 48 | self.groundUp = groundUp 49 | self.bitMap = bitMap 50 | self.heightmaps = heightmaps 51 | self.biomes = biomes 52 | self.chunkData = chunkData 53 | self.blockEntities = blockEntities 54 | } 55 | 56 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 57 | self.x = buffer.readInteger(as: Int32.self) ?? x 58 | self.z = buffer.readInteger(as: Int32.self) ?? z 59 | self.groundUp = buffer.readBool() ?? groundUp 60 | if protocolVersion >= ProtocolConstants.minecraft_1_9 { 61 | self.bitMap = buffer.readVarInt() ?? bitMap 62 | } else { 63 | self.bitMap = Int32(buffer.readInteger(as: UInt16.self) ?? 0) 64 | } 65 | if protocolVersion >= ProtocolConstants.minecraft_1_14 { 66 | self.heightmaps = buffer.readNBT() 67 | } 68 | if protocolVersion >= ProtocolConstants.minecraft_1_15 && groundUp { 69 | for _ in 0 ..< 1024 { 70 | self.biomes.append(buffer.readInteger(as: Int32.self) ?? 0) 71 | } 72 | } 73 | self.chunkData = buffer.readBytes(length: Int(buffer.readVarInt() ?? 0)) ?? chunkData 74 | if protocolVersion >= ProtocolConstants.minecraft_1_9_4 { 75 | let count = Int(buffer.readVarInt() ?? 0) 76 | for _ in 0 ..< count { 77 | blockEntities.append(buffer.readNBT()) 78 | } 79 | } 80 | } 81 | 82 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 83 | buffer.writeInteger(x) 84 | buffer.writeInteger(z) 85 | buffer.writeBool(value: groundUp) 86 | if protocolVersion >= ProtocolConstants.minecraft_1_9 { 87 | buffer.writeVarInt(value: bitMap) 88 | } else { 89 | buffer.writeInteger(UInt16(bitMap), as: UInt16.self) 90 | } 91 | if protocolVersion >= ProtocolConstants.minecraft_1_14 { 92 | buffer.writeNBT(tag: heightmaps) 93 | } 94 | if protocolVersion >= ProtocolConstants.minecraft_1_15 && groundUp { 95 | for i in 0 ..< 1024 { 96 | if biomes.count > i { 97 | buffer.writeInteger(biomes[i], as: Int32.self) 98 | } else { 99 | buffer.writeInteger(127, as: Int32.self) 100 | } 101 | } 102 | } 103 | buffer.writeVarInt(value: Int32(chunkData.count)) 104 | buffer.writeBytes(chunkData) 105 | if protocolVersion >= ProtocolConstants.minecraft_1_9_4 { 106 | buffer.writeVarInt(value: Int32(blockEntities.count)) 107 | for blockEntity in blockEntities { 108 | buffer.writeNBT(tag: blockEntity) 109 | } 110 | } 111 | } 112 | 113 | public func toString() -> String { 114 | return "MapChunk()" 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/Packet.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public protocol Packet { 24 | 25 | init() 26 | 27 | func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) 28 | 29 | func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) 30 | 31 | func toString() -> String 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/PingPacket.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class PingPacket: Packet { 24 | 25 | public var time: Int64 26 | 27 | public required init() { 28 | time = 0 29 | } 30 | 31 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 32 | self.time = buffer.readInteger(as: Int64.self) ?? self.time 33 | } 34 | 35 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 36 | buffer.writeInteger(time) 37 | } 38 | 39 | public func toString() -> String { 40 | return "PingPacket(time: \(time))" 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/PlayerListHeaderFooter.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class PlayerListHeaderFooter: Packet { 24 | 25 | public var header: String 26 | public var footer: String 27 | 28 | public required init() { 29 | header = "" 30 | footer = "" 31 | } 32 | 33 | public init(header: String, footer: String) { 34 | self.header = header 35 | self.footer = footer 36 | } 37 | 38 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 39 | header = buffer.readVarString() ?? header 40 | footer = buffer.readVarString() ?? footer 41 | } 42 | 43 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 44 | buffer.writeVarString(string: header) 45 | buffer.writeVarString(string: footer) 46 | } 47 | 48 | public func toString() -> String { 49 | return "PlayerListHeaderFooter(header: \(header), footer: \(footer))" 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/PlayerLook.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class PlayerLook: Packet { 24 | 25 | public var yaw: Float 26 | public var pitch: Float 27 | public var onGround: Bool 28 | 29 | public required init() { 30 | yaw = 0 31 | pitch = 0 32 | onGround = true 33 | } 34 | 35 | public init(yaw: Float = 0, pitch: Float = 0, onGround: Bool = true) { 36 | self.yaw = yaw 37 | self.pitch = pitch 38 | self.onGround = onGround 39 | } 40 | 41 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 42 | yaw = buffer.readFloat() ?? yaw 43 | pitch = buffer.readFloat() ?? pitch 44 | onGround = buffer.readBool() ?? onGround 45 | } 46 | 47 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 48 | buffer.writeFloat(value: yaw) 49 | buffer.writeFloat(value: pitch) 50 | buffer.writeBool(value: onGround) 51 | } 52 | 53 | public func toString() -> String { 54 | return "PlayerLook(yaw: \(yaw), pitch: \(pitch), onGround: \(onGround))" 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/PlayerPosition.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class PlayerPosition: Packet { 24 | 25 | public var x: Double 26 | public var y: Double 27 | public var z: Double 28 | public var onGround: Bool 29 | 30 | public required init() { 31 | x = 0 32 | y = 0 33 | z = 0 34 | onGround = true 35 | } 36 | 37 | public init(x: Double, y: Double, z: Double, onGround: Bool = true) { 38 | self.x = x 39 | self.y = y 40 | self.z = z 41 | self.onGround = onGround 42 | } 43 | 44 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 45 | x = buffer.readDouble() ?? x 46 | y = buffer.readDouble() ?? y 47 | z = buffer.readDouble() ?? z 48 | onGround = buffer.readBool() ?? onGround 49 | } 50 | 51 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 52 | buffer.writeDouble(value: x) 53 | buffer.writeDouble(value: y) 54 | buffer.writeDouble(value: z) 55 | buffer.writeBool(value: onGround) 56 | } 57 | 58 | public func toString() -> String { 59 | return "PlayerPosition(x: \(x), y: \(y), z: \(z), onGround: \(onGround))" 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/PlayerPositionLook.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class PlayerPositionLook: Packet { 24 | 25 | public var x: Double 26 | public var y: Double 27 | public var z: Double 28 | public var yaw: Float 29 | public var pitch: Float 30 | public var onGround: Bool 31 | 32 | public required init() { 33 | x = 0 34 | y = 0 35 | z = 0 36 | yaw = 0 37 | pitch = 0 38 | onGround = true 39 | } 40 | 41 | public init(x: Double, y: Double, z: Double, yaw: Float = 0, pitch: Float = 0, onGround: Bool = true) { 42 | self.x = x 43 | self.y = y 44 | self.z = z 45 | self.yaw = yaw 46 | self.pitch = pitch 47 | self.onGround = onGround 48 | } 49 | 50 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 51 | x = buffer.readDouble() ?? x 52 | y = buffer.readDouble() ?? y 53 | z = buffer.readDouble() ?? z 54 | yaw = buffer.readFloat() ?? yaw 55 | pitch = buffer.readFloat() ?? pitch 56 | onGround = buffer.readBool() ?? onGround 57 | } 58 | 59 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 60 | buffer.writeDouble(value: x) 61 | buffer.writeDouble(value: y) 62 | buffer.writeDouble(value: z) 63 | buffer.writeFloat(value: yaw) 64 | buffer.writeFloat(value: pitch) 65 | buffer.writeBool(value: onGround) 66 | } 67 | 68 | public func toString() -> String { 69 | return "PlayerPositionLook(x: \(x), y: \(y), z: \(z), yaw: \(yaw), pitch: \(pitch), onGround: \(onGround))" 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/PluginMessage.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class PluginMessage: Packet { 24 | 25 | public var tag: String 26 | public var data: [UInt8] 27 | 28 | public required init() { 29 | tag = "" 30 | data = [] 31 | } 32 | 33 | public init(tag: String, data: [UInt8]) { 34 | self.tag = tag 35 | self.data = data 36 | } 37 | 38 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 39 | tag = buffer.readVarString() ?? tag 40 | data = buffer.readBytes(length: buffer.readableBytes) ?? data 41 | } 42 | 43 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 44 | buffer.writeVarString(string: tag) 45 | buffer.writeBytes(data) 46 | } 47 | 48 | public func toString() -> String { 49 | return "PluginMessage(tag: \(tag), data: \(data))" 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/Position.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class Position: Packet { 24 | 25 | public var x: Double 26 | public var y: Double 27 | public var z: Double 28 | public var yaw: Float 29 | public var pitch: Float 30 | public var flags: UInt8 31 | public var teleportId: Int32 32 | 33 | public required init() { 34 | x = 0 35 | y = 0 36 | z = 0 37 | yaw = 0 38 | pitch = 0 39 | flags = 0 40 | teleportId = 0 41 | } 42 | 43 | public init(x: Double, y: Double, z: Double, yaw: Float = 0, pitch: Float = 0, flags: UInt8 = 0, teleportId: Int32) { 44 | self.x = x 45 | self.y = y 46 | self.z = z 47 | self.yaw = yaw 48 | self.pitch = pitch 49 | self.flags = flags 50 | self.teleportId = teleportId 51 | } 52 | 53 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 54 | x = buffer.readDouble() ?? x 55 | y = buffer.readDouble() ?? y 56 | z = buffer.readDouble() ?? z 57 | yaw = buffer.readFloat() ?? yaw 58 | pitch = buffer.readFloat() ?? pitch 59 | flags = buffer.readBytes(length: 1)?.first ?? flags 60 | if protocolVersion >= ProtocolConstants.minecraft_1_9 { 61 | teleportId = buffer.readVarInt() ?? teleportId 62 | } 63 | } 64 | 65 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 66 | buffer.writeDouble(value: x) 67 | buffer.writeDouble(value: y) 68 | buffer.writeDouble(value: z) 69 | buffer.writeFloat(value: yaw) 70 | buffer.writeFloat(value: pitch) 71 | buffer.writeBytes([flags]) 72 | if protocolVersion >= ProtocolConstants.minecraft_1_9 { 73 | buffer.writeVarInt(value: teleportId) 74 | } 75 | } 76 | 77 | public func toString() -> String { 78 | return "Position(x: \(x), y: \(y), z: \(z), yaw: \(yaw), pitch: \(pitch), teleportId: \(teleportId))" 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/Respawn.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class Respawn: Packet { 24 | 25 | public var dimension: Int32 26 | public var hashedSeed: Int64 27 | public var difficulty: UInt8 28 | public var gameMode: UInt8 29 | public var levelType: String 30 | 31 | public required init() { 32 | dimension = 0 33 | hashedSeed = 0 34 | difficulty = 0 35 | gameMode = 0 36 | levelType = "" 37 | } 38 | 39 | public init(dimension: Int32, hashedSeed: Int64, difficulty: UInt8, gameMode: UInt8, levelType: String) { 40 | self.dimension = dimension 41 | self.hashedSeed = hashedSeed 42 | self.difficulty = difficulty 43 | self.gameMode = gameMode 44 | self.levelType = levelType 45 | } 46 | 47 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 48 | dimension = buffer.readInteger(as: Int32.self) ?? dimension 49 | if protocolVersion >= ProtocolConstants.minecraft_1_15 { 50 | hashedSeed = buffer.readInteger(as: Int64.self) ?? hashedSeed 51 | } 52 | if protocolVersion < ProtocolConstants.minecraft_1_14 { 53 | difficulty = buffer.readBytes(length: 1)?.first ?? difficulty 54 | } 55 | gameMode = buffer.readBytes(length: 1)?.first ?? gameMode 56 | levelType = buffer.readVarString() ?? levelType 57 | } 58 | 59 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 60 | buffer.writeInteger(dimension) 61 | if protocolVersion >= ProtocolConstants.minecraft_1_15 { 62 | buffer.writeInteger(hashedSeed) 63 | } 64 | if protocolVersion < ProtocolConstants.minecraft_1_14 { 65 | buffer.writeBytes([difficulty]) 66 | } 67 | buffer.writeBytes([gameMode]) 68 | buffer.writeVarString(string: levelType) 69 | } 70 | 71 | public func toString() -> String { 72 | return "Respawn(dimension: \(dimension), hashedSeed: \(hashedSeed), difficulty: \(difficulty), gameMode: \(gameMode), levelType: \(levelType))" 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/SetCompression.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class SetCompression: Packet { 24 | 25 | public var threshold: Int32 26 | 27 | public required init() { 28 | threshold = 0 29 | } 30 | 31 | public init(threshold: Int32) { 32 | self.threshold = threshold 33 | } 34 | 35 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 36 | self.threshold = buffer.readVarInt() ?? self.threshold 37 | } 38 | 39 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 40 | buffer.writeVarInt(value: threshold) 41 | } 42 | 43 | public func toString() -> String { 44 | return "SetCompression(threshold: \(threshold))" 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/StatusRequest.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class StatusRequest: Packet { 24 | 25 | public required init() {} 26 | 27 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) {} 28 | 29 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) {} 30 | 31 | public func toString() -> String { 32 | return "StatusRequest()" 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/StatusResponse.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class StatusResponse: Packet { 24 | 25 | public var response: String 26 | 27 | public required init() { 28 | response = "" 29 | } 30 | 31 | public init(response: String) { 32 | self.response = response 33 | } 34 | 35 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 36 | response = buffer.readVarString() ?? response 37 | } 38 | 39 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 40 | buffer.writeVarString(string: response) 41 | } 42 | 43 | public func toString() -> String { 44 | return "StatusResponse(response: \(response))" 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Packets/UnknownPacket.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class UnknownPacket: Packet { 24 | 25 | public var packetId: Int32 26 | public var bytes: [UInt8] 27 | 28 | public required init() { 29 | packetId = 0 30 | bytes = [] 31 | } 32 | 33 | public func readPacket(from buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 34 | self.bytes = buffer.readBytes(length: buffer.readableBytes) ?? bytes 35 | } 36 | 37 | public func writePacket(to buffer: inout ByteBuffer, direction: DirectionData, protocolVersion: Int32) { 38 | buffer.writeBytes(bytes) 39 | } 40 | 41 | public func toString() -> String { 42 | return "UnknownPacket(packetId: \(packetId), size: \(bytes.count) bytes)" 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Protocols/DirectionData.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class DirectionData { 23 | 24 | // Variables 25 | var prot: Prot 26 | var direction: Direction 27 | var protocols = [Int32: ProtocolData]() 28 | 29 | init(prot: Prot, direction: Direction) { 30 | // Save properties 31 | self.prot = prot 32 | self.direction = direction 33 | 34 | // And init protocols data 35 | for current in ProtocolConstants.supported_versions_ids { 36 | protocols[current] = ProtocolData(protocolVersion: current) 37 | } 38 | } 39 | 40 | // Get protocol data 41 | func getProtocolData(version: Int32) -> ProtocolData? { 42 | if let current = protocols[version] { 43 | return current 44 | } else if let first = protocols.values.first, prot.name != "GAME" { 45 | return first 46 | } 47 | return nil 48 | } 49 | 50 | // Register a packet 51 | func registerPacket(packetClass: Packet.Type, mappings: [ProtocolMapping]) { 52 | var mappingIndex = 0 53 | var mapping = mappings[0] 54 | for current in ProtocolConstants.supported_versions_ids { 55 | // Checks 56 | if current < mapping.protocolVersion { 57 | // New packet, skip till reach next protocol 58 | continue 59 | } 60 | if mapping.protocolVersion < current && mappingIndex + 1 < mappings.count { 61 | // Go to next 62 | let nextMapping = mappings[mappingIndex + 1] 63 | if nextMapping.protocolVersion == current { 64 | if nextMapping.packetID != mapping.packetID { 65 | mapping = nextMapping 66 | mappingIndex += 1 67 | } 68 | } 69 | } 70 | 71 | // Save 72 | let data = protocols[current] 73 | data?.packetMap[mapping.packetID] = packetClass 74 | } 75 | } 76 | 77 | // Create a packet from id 78 | func createPacket(id: Int32, version: Int32) -> Packet { 79 | if let protocolData = getProtocolData(version: version), id <= Prot.max_packet_id, let packet = protocolData.packetMap[id]?.init() { 80 | return packet 81 | } 82 | return UnknownPacket() 83 | } 84 | 85 | // Get id from a packet 86 | func getId(for packet: Packet.Type, version: Int32) -> Int32? { 87 | guard let protocolData = getProtocolData(version: version) else { 88 | return nil 89 | } 90 | return protocolData.packetMap.first { item in 91 | return item.value == packet 92 | }?.key 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Protocols/ProtocolConstants.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class ProtocolConstants { 23 | 24 | // Version constants 25 | public static var minecraft_1_8: Int32 = 47 26 | public static var minecraft_1_9: Int32 = 107 27 | public static var minecraft_1_9_1: Int32 = 108 28 | public static var minecraft_1_9_2: Int32 = 109 29 | public static var minecraft_1_9_4: Int32 = 110 30 | public static var minecraft_1_10: Int32 = 210 31 | public static var minecraft_1_11: Int32 = 315 32 | public static var minecraft_1_12: Int32 = 335 33 | public static var minecraft_1_12_1: Int32 = 338 34 | public static var minecraft_1_12_2: Int32 = 340 35 | public static var minecraft_1_13: Int32 = 393 36 | public static var minecraft_1_13_1: Int32 = 401 37 | public static var minecraft_1_13_2: Int32 = 404 38 | public static var minecraft_1_14: Int32 = 477 39 | public static var minecraft_1_14_1: Int32 = 480 40 | public static var minecraft_1_14_2: Int32 = 485 41 | public static var minecraft_1_14_3: Int32 = 490 42 | public static var minecraft_1_14_4: Int32 = 498 43 | public static var minecraft_1_15: Int32 = 573 44 | public static var minecraft_1_15_1: Int32 = 575 45 | public static var minecraft_1_15_2: Int32 = 578 46 | 47 | public static var supported_versions = [ 48 | "1.8.x", 49 | "1.9.x", 50 | "1.10.x", 51 | "1.11.x", 52 | "1.12.x", 53 | "1.13.x", 54 | "1.14.x", 55 | "1.15.x" 56 | ] 57 | 58 | public static var supported_versions_ids = [ 59 | minecraft_1_8, 60 | minecraft_1_9, 61 | minecraft_1_9_1, 62 | minecraft_1_9_2, 63 | minecraft_1_9_4, 64 | minecraft_1_10, 65 | minecraft_1_11, 66 | minecraft_1_12, 67 | minecraft_1_12_1, 68 | minecraft_1_12_2, 69 | minecraft_1_13, 70 | minecraft_1_13_1, 71 | minecraft_1_13_2, 72 | minecraft_1_14, 73 | minecraft_1_14_1, 74 | minecraft_1_14_2, 75 | minecraft_1_14_3, 76 | minecraft_1_14_4, 77 | minecraft_1_15, 78 | minecraft_1_15_1, 79 | minecraft_1_15_2 80 | ] 81 | 82 | } 83 | 84 | enum Direction { 85 | 86 | case to_client, to_server 87 | 88 | } 89 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Protocols/ProtocolData.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | class ProtocolData { 23 | 24 | var protocolVersion: Int32 25 | var packetMap = [Int32: Packet.Type]() 26 | 27 | init(protocolVersion: Int32) { 28 | self.protocolVersion = protocolVersion 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Protocols/ProtocolMapping.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | struct ProtocolMapping { 23 | 24 | var protocolVersion: Int32 25 | var packetID: Int32 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Random/PerlinGenerator.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class PerlinGenerator { 23 | 24 | var permutation = [Int]() 25 | 26 | public init(random: Random) { 27 | permutation = (0 ..< 512).map({ _ in Int(random.nextInt32(bound: 255)) }) 28 | } 29 | 30 | func lerp(a: Float, b: Float, x: Float) -> Float { 31 | return a + x * (b - a) // This interpolates between two points with a weight x 32 | } 33 | 34 | func fade(t: Float) -> Float { 35 | return t * t * t * (t * (t * 6 - 15) + 10) // This is the smoothing function for Perlin noise 36 | } 37 | 38 | func grad(hash: Int, x: Float, y: Float) -> Float { 39 | // This takes a hash (a number from 0 - 5) generated from the random permutations and returns a random operation for the node to offset 40 | switch hash & 3 { 41 | case 0: 42 | return x + y 43 | case 1: 44 | return -x + y 45 | case 2: 46 | return x - y 47 | case 3: 48 | return -x - y 49 | default: 50 | return 0 51 | } 52 | } 53 | 54 | func fastfloor(x: Float) -> Int { 55 | return x > 0 ? Int(x) : Int(x-1) 56 | } 57 | 58 | public func noise(x: Float, y: Float) -> Float { 59 | // Find the unit grid cell containing the point 60 | var xi = fastfloor(x: x) 61 | var yi = fastfloor(x: y) 62 | 63 | // This is the other bound of the unit square 64 | let xf = x - Float(xi) 65 | let yf = y - Float(yi) 66 | 67 | // Wrap the ints around 255 68 | xi = xi & 255 69 | yi = yi & 255 70 | 71 | // These are offset values for interpolation 72 | let u = fade(t: xf) 73 | let v = fade(t: yf) 74 | 75 | // These are the 4 possible permutations so we get the perm value for each 76 | let aa = permutation[permutation[xi] + yi] 77 | let ab = permutation[permutation[xi] + yi + 1] 78 | let ba = permutation[permutation[xi + 1] + yi] 79 | let bb = permutation[permutation[xi + 1] + yi + 1] 80 | 81 | // We pair aa and ba, and ab and bb and lerp the gradient of the two, using the offset values 82 | // We take 1 off the value which we added one to for the perms 83 | let x1 = lerp(a: grad(hash: aa, x: xf, y: yf), b: grad(hash: ba, x: xf - 1, y: yf), x: u) 84 | let x2 = lerp(a: grad(hash: ab, x: xf, y: yf - 1), b: grad(hash: bb, x: xf - 1, y: yf - 1), x: u) 85 | let y1 = lerp(a: x1, b: x2, x: v) 86 | 87 | // We return the value + 1 / 2 to remove any negatives. 88 | return (y1 + 1) / 2 89 | } 90 | 91 | public func octaveNoise(x: Float, y: Float, octaves: Int, persistence: Float) -> Float { 92 | // This takes several perlin readings (n octaves) and merges them into one map 93 | var total: Float = 0 94 | var frequency: Float = 1 95 | var amplitude: Float = 1 96 | var maxValue: Float = 0 97 | 98 | // We sum the total and divide by the max at the end to normalise 99 | for _ in 0 ..< octaves { 100 | total += noise(x: x * frequency, y: y * frequency) * amplitude 101 | maxValue += amplitude 102 | 103 | // This is taken from recomendations on values 104 | amplitude *= persistence 105 | frequency *= 2 106 | } 107 | 108 | return total/maxValue 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Random/Random.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class Random { 23 | 24 | // Store the random seed 25 | private var seed: Int64 26 | 27 | // Initializer 28 | public init(seed: Int64 = Int64.random(in: Int64.min ..< Int64.max)) { 29 | self.seed = (seed ^ 0x5DEECE66D) & ((1 << 48) - 1) 30 | } 31 | 32 | // Set the seed 33 | public func setSeed(to seed: Int64) { 34 | self.seed = (seed ^ 0x5DEECE66D) & ((1 << 48) - 1) 35 | } 36 | 37 | // Get the seed 38 | public func getSeed() -> Int64 { 39 | return seed 40 | } 41 | 42 | // Next element bits 43 | private func next(bits: Int) -> Int64 { 44 | self.seed = (seed &* 0x5DEECE66D &+ 0xB) & ((1 << 48) - 1) 45 | return Int64(bitPattern: UInt64(bitPattern: seed) >> (48 - bits)) 46 | } 47 | 48 | // Random Int32 49 | public func nextInt32() -> Int32 { 50 | return Int32(next(bits: 31)) 51 | } 52 | 53 | // Random Int32 with bounds 54 | public func nextInt32(bound: Int32) -> Int32 { 55 | if bound <= 0 { return 0 } 56 | 57 | if (bound & -bound) == bound { 58 | return Int32((Int64(bound) * next(bits: 31)) >> 31) 59 | } 60 | 61 | var bits: Int32, val: Int32 62 | repeat { 63 | bits = Int32(next(bits: 31)) 64 | val = bits % bound 65 | } while bits - val + (bound-1) < 0 66 | return val 67 | } 68 | 69 | // Random Int64 70 | public func nextInt64() -> Int64 { 71 | return (next(bits: 32) << 32) + next(bits: 32) 72 | } 73 | 74 | // Random Bool 75 | public func nextBool() -> Bool { 76 | return next(bits: 1) != 0 77 | } 78 | 79 | // Random Float 80 | public func nextFloat() -> Float { 81 | return Float(next(bits: 24)) / Float(1 << 24) 82 | } 83 | 84 | // Random Double 85 | public func nextDouble() -> Double { 86 | return Double((next(bits: 26) << 27) + next(bits: 27)) / Double(1 << 53) 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Worlds/Biome.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public enum Biome: Int8 { 23 | 24 | case ocean = 0 25 | case plains = 1 26 | case desert = 2 27 | case extreme_hills = 3 28 | case forest = 4 29 | case taiga = 5 30 | case swampland = 6 31 | case river = 7 32 | case hell = 8 33 | case sky = 9 34 | case frozen_ocean = 10 35 | case frozen_river = 11 36 | case ice_plains = 12 37 | case ice_mountains = 13 38 | case mushroom_island = 14 39 | case mushroom_insland_shore = 15 40 | case beach = 16 41 | case desert_hills = 17 42 | case forest_hills = 18 43 | case taiga_hills = 19 44 | case extreme_hills_edge = 20 45 | case jungle = 21 46 | case jungle_hills = 22 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Worlds/Location.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public struct Location { 24 | 25 | // Variables 26 | public var world: WorldProtocol 27 | public var x: Double 28 | public var y: Double 29 | public var z: Double 30 | public var yaw: Float 31 | public var pitch: Float 32 | 33 | // Computed properties 34 | public var blockX: Int32 { return Int32(x) } 35 | public var blockY: Int32 { return Int32(y) } 36 | public var blockZ: Int32 { return Int32(z) } 37 | 38 | // Get chunk for this location 39 | public func getChunk() -> WorldChunk { 40 | return world.getChunk(x: Int32(Int64(x) >> 4), z: Int32(Int64(z) >> 4)) 41 | } 42 | 43 | // Convert to position packet 44 | public func toPositionServerPacket() -> Position { 45 | return Position(x: x, y: y, z: z, yaw: yaw, pitch: pitch, flags: 0, teleportId: 0) 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Worlds/NibbleArray.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class NibbleArray { 23 | 24 | // Storage 25 | internal var rawData: [Int8] 26 | 27 | // Initializer 28 | public init(size: Int, value: Int8 = 0) { 29 | let size = size % 2 == 0 ? size : size + 1 30 | if value != 0 { 31 | let value = value & 0x0F 32 | self.rawData = [Int8](repeating: value << 4 | value, count: size / 2) 33 | } else { 34 | self.rawData = [Int8](repeating: 0, count: size / 2) 35 | } 36 | } 37 | 38 | // Init from existing data 39 | public init(rawData: [Int8]) { 40 | self.rawData = rawData 41 | } 42 | 43 | // Get size 44 | public func count() -> Int { 45 | return 2 * rawData.count 46 | } 47 | 48 | // Get size in bytes 49 | public func byteCount() -> Int { 50 | return rawData.count 51 | } 52 | 53 | // Get and set a value 54 | public subscript(index: Int) -> Int8 { 55 | get { 56 | let val = UInt8(bitPattern: rawData[index / 2]) 57 | if index % 2 == 0 { 58 | return Int8(bitPattern: val & 0x0F) 59 | } else { 60 | return Int8(bitPattern: (val & 0x0F) >> 4) 61 | } 62 | } 63 | set { 64 | let value = UInt8(bitPattern: newValue & 0x0F) 65 | let half = index / 2 66 | let previous = UInt8(bitPattern: rawData[half]) 67 | if index % 2 == 0 { 68 | rawData[half] = Int8(bitPattern: previous & 0xF0 | value) 69 | } else { 70 | rawData[half] = Int8(bitPattern: previous & 0x0F | value << 4) 71 | } 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Worlds/OverworldGenerator.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class OverworldGenerator: WorldGenerator { 23 | 24 | public func generateBiomes(world: LocalWorld, random: Random, chunkX: Int32, chunkZ: Int32) -> [Int8] { 25 | let perlin = PerlinGenerator(random: random) 26 | var biomes = [Int8]() 27 | 28 | for z: Int32 in 0 ..< 16 { 29 | for x: Int32 in 0 ..< 16 { 30 | biomes.append(Int8(perlin.octaveNoise(x: Float(chunkX * 16 + x) / 500, y: Float(chunkZ * 16 + z) / 500, octaves: 1, persistence: 0.5) * 22)) 31 | } 32 | } 33 | 34 | return biomes 35 | } 36 | 37 | public func generateChunkData(world: LocalWorld, random: Random, chunkX: Int32, chunkZ: Int32, biomes: [Int8]) -> WorldChunkData { 38 | var chunkData = WorldChunkData(world: world) 39 | let perlin = PerlinGenerator(random: random) 40 | 41 | for x: Int32 in 0 ..< 16 { 42 | for z: Int32 in 0 ..< 16 { 43 | generateColumn(in: &chunkData, with: perlin, x: x, chunkX: chunkX, z: z, chunkZ: chunkZ, biome: biomes[Int(x | z << 4)]) 44 | } 45 | } 46 | 47 | return chunkData 48 | } 49 | 50 | public func getName() -> String { 51 | return "overworld" 52 | } 53 | 54 | public func generateColumn(in chunkData: inout WorldChunkData, with perlin: PerlinGenerator, x: Int32, chunkX: Int32, z: Int32, chunkZ: Int32, biome: Int8) { 55 | let h = Int32(perlin.octaveNoise(x: Float(chunkX * 16 + x) / 100, y: Float(chunkZ * 16 + z) / 100, octaves: 3, persistence: 0.5) * 30 + 50) 56 | for y: Int32 in 0 ..< max(h, 63) { 57 | if y < 4 { 58 | // Always bedrock 59 | chunkData.setBlock(x: x, y: y, z: z, material: .bedrock) 60 | } else if y < h - 10 || h > 70 { 61 | // Stone until a change 62 | chunkData.setBlock(x: x, y: y, z: z, material: .stone) 63 | } else if y < h - 1 { 64 | // Check if we are under a lake 65 | if h < 63 { 66 | // Sandstone 67 | chunkData.setBlock(x: x, y: y, z: z, blockId: 24) 68 | } else { 69 | // Some dirt 70 | chunkData.setBlock(x: x, y: y, z: z, material: .dirt) 71 | } 72 | } else if y < h { 73 | // Check if we are under a lake 74 | if h < 63 { 75 | // Sandstone 76 | chunkData.setBlock(x: x, y: y, z: z, blockId: 12) 77 | } else { 78 | // And grass 79 | chunkData.setBlock(x: x, y: y, z: z, material: .grass) 80 | } 81 | } else { 82 | // Fill missing blocks with water 83 | chunkData.setBlock(x: x, y: y, z: z, blockId: 8) 84 | } 85 | } 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Worlds/SuperflatGenerator.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class SuperflatGenerator: WorldGenerator { 23 | 24 | public func generateBiomes(world: LocalWorld, random: Random, chunkX: Int32, chunkZ: Int32) -> [Int8] { 25 | return [Int8](repeating: 1, count: 256) 26 | } 27 | 28 | public func generateChunkData(world: LocalWorld, random: Random, chunkX: Int32, chunkZ: Int32, biomes: [Int8]) -> WorldChunkData { 29 | let chunkData = WorldChunkData(world: world) 30 | 31 | for x: Int32 in 0 ..< 16 { 32 | for z: Int32 in 0 ..< 16 { 33 | for y: Int32 in 0 ..< 64 { 34 | if y < 4 { 35 | chunkData.setBlock(x: x, y: y, z: z, material: .bedrock) 36 | } else if y < 60 { 37 | chunkData.setBlock(x: x, y: y, z: z, material: .stone) 38 | } else if y < 63 { 39 | chunkData.setBlock(x: x, y: y, z: z, material: .dirt) 40 | } else if y < 64 { 41 | chunkData.setBlock(x: x, y: y, z: z, material: .grass) 42 | } 43 | } 44 | } 45 | } 46 | 47 | return chunkData 48 | } 49 | 50 | public func getName() -> String { 51 | return "superflat" 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Worlds/VariableValueArray.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class VariableValueArray { 23 | 24 | // Calculation 25 | public static func neededBits(for number: Int) -> Int { 26 | var number = number 27 | var count = 0 28 | repeat { 29 | count += 1 30 | number = number >> 1 31 | } while number != 0 32 | return count 33 | } 34 | 35 | // Storage 36 | internal var backing: [Int64] 37 | internal let capacity: Int 38 | internal let bitsPerValue: Int 39 | internal let valueMask: Int64 40 | 41 | // Initializer 42 | public init(bitsPerValue: Int, capacity: Int) { 43 | self.backing = [Int64](repeating: 0, count: Int(ceil(Double(bitsPerValue * capacity) / 64.0))) 44 | self.bitsPerValue = bitsPerValue 45 | self.valueMask = (1 << bitsPerValue) - 1 46 | self.capacity = capacity 47 | } 48 | 49 | // Largest possible value 50 | public func largestPossibleValue() -> Int64 { 51 | return valueMask 52 | } 53 | 54 | // Get and set a value 55 | public subscript(index: Int) -> Int32 { 56 | get { 57 | let index = index * bitsPerValue 58 | let i0 = index >> 6 59 | let i1 = index & 0x3F 60 | let i2 = i1 + bitsPerValue 61 | 62 | var value = Int64(bitPattern: UInt64(bitPattern: backing[i0]) >> UInt64(bitPattern: Int64(i1))) 63 | 64 | if i2 > 64 { 65 | value |= backing[i0 + 1] << Int64(64 - i1) 66 | } 67 | 68 | return Int32(value & valueMask) 69 | } 70 | set { 71 | let value = Int64(newValue) 72 | let index = index * bitsPerValue 73 | var i0 = index >> 6 74 | let i1 = index & 0x3F 75 | let i2 = i1 + bitsPerValue 76 | 77 | let p1 = backing[i0] & ~(valueMask << i1) 78 | let p2 = (value & valueMask) << i1 79 | backing[i0] = p1 | p2 80 | 81 | if i2 > 64 { 82 | i0 += 1 83 | let p3 = ~((1 << i2 - 64) - 1) 84 | let p4 = value >> Int64(64 - i1) 85 | backing[i0] = backing[i0] & Int64(p3) | p4 86 | } 87 | } 88 | } 89 | 90 | // Increase the bits per value 91 | public func increaseBitsPerValue(to newBitsPerValue: Int) -> VariableValueArray { 92 | let returned = VariableValueArray(bitsPerValue: newBitsPerValue, capacity: capacity) 93 | for i in 0 ..< capacity { 94 | returned[i] = self[i] 95 | } 96 | return returned 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Worlds/WorldChunk.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class WorldChunk { 24 | 25 | // Static constants 26 | public static let width = 16 27 | public static let height = 16 28 | public static let depth = 256 29 | public static let section_depth = 16 30 | public static let section_count = depth / section_depth 31 | 32 | // Chunk coordinates 33 | public let x: Int32 34 | public let z: Int32 35 | 36 | // Chunk sections 37 | internal var sections: [Int8: WorldChunkSection] 38 | internal var biomes: [Int8] 39 | public internal(set) var loaded: Bool 40 | 41 | // Initializer 42 | internal init(x: Int32, z: Int32) { 43 | self.x = x 44 | self.z = z 45 | self.sections = [:] 46 | self.biomes = [] 47 | self.loaded = false 48 | } 49 | 50 | // Convert to MapChunk packet 51 | public func toMapChunkPacket(protocolVersion: Int32, skylight: Bool = true, entireChunk: Bool = true) -> MapChunk { 52 | // Calculate bitMap 53 | let maxY = (sections.map({ $0.key }).max() ?? 0) + 1 54 | let maxBitMap = (1 << maxY) - 1 55 | var bitMap = entireChunk ? maxBitMap : 0 & maxBitMap 56 | for y in 0 ..< maxY { 57 | if sections[y]?.isEmpty() ?? true { 58 | bitMap = bitMap & ~(1 << y) 59 | } 60 | } 61 | 62 | // Write sections 63 | var buffer = ByteBufferAllocator().buffer(capacity: 1024*1024) 64 | if protocolVersion >= ProtocolConstants.minecraft_1_9 { 65 | for y in 0 ..< maxY { 66 | if (bitMap & 1 << y) != 0 { 67 | sections[y]?.writeBlocks(to: &buffer) 68 | sections[y]?.writeBlockLight(to: &buffer) 69 | if skylight { 70 | sections[y]?.writeSkyLight(to: &buffer) 71 | } 72 | } 73 | } 74 | } else { 75 | var secs = [WorldChunkSection]() 76 | for y in 0 ..< maxY { 77 | if (bitMap & 1 << y) != 0 { 78 | if let sec = sections[y] { 79 | sec.writeBlocksOld(to: &buffer) 80 | secs.append(sec) 81 | } 82 | } 83 | } 84 | for sec in secs { sec.writeBlockLight(to: &buffer) } 85 | if skylight { for sec in secs { sec.writeSkyLight(to: &buffer) } } 86 | } 87 | 88 | // Write biomes 89 | if protocolVersion < ProtocolConstants.minecraft_1_15 && entireChunk { 90 | buffer.writeBytes(biomes.map({ UInt8(bitPattern: $0) })) 91 | } 92 | 93 | // Extract chunk data 94 | let data = buffer.readBytes(length: buffer.readableBytes) ?? [] 95 | 96 | // Create the packet 97 | return MapChunk(x: x, z: z, groundUp: true, bitMap: Int32(bitMap), heightmaps: NBTCompound(), biomes: [], chunkData: data, blockEntities: []) 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Worlds/WorldChunkData.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public class WorldChunkData { 23 | 24 | private let maxHeight: Int32 25 | private var sections: [[UInt16]] 26 | 27 | public init(world: LocalWorld) { 28 | self.maxHeight = 128 // TODO: Make a parameter to change this value 29 | self.sections = [[UInt16]](repeating: [], count: WorldChunk.section_count) 30 | } 31 | 32 | public func index(x: Int32, y: Int32, z: Int32) -> Int { 33 | return Int((y & 0xF) << 8 | z << 4 | x) 34 | } 35 | 36 | public func getData(x: Int32, y: Int32, z: Int32) -> UInt8 { 37 | if x < 0 || y < 0 || z < 0 || x >= WorldChunk.height || y >= WorldChunk.depth || z >= WorldChunk.width { 38 | return 0 39 | } 40 | if sections[Int(y >> 4)].isEmpty { 41 | return 0 42 | } 43 | return UInt8(sections[Int(y >> 4)][index(x: x, y: y, z: z)] & 0xF) 44 | } 45 | 46 | public func getType(x: Int32, y: Int32, z: Int32) -> Material? { 47 | return Material.get(id: UInt16(getTypeId(x: x, y: y, z: z))) 48 | } 49 | 50 | public func getTypeAndData(x: Int32, y: Int32, z: Int32) -> MaterialData? { 51 | return getType(x: x, y: y, z: z)?.getNewData(raw: getData(x: x, y: y, z: z)) 52 | } 53 | 54 | public func getTypeId(x: Int32, y: Int32, z: Int32) -> UInt8 { 55 | if x < 0 || y < 0 || z < 0 || x >= WorldChunk.height || y >= WorldChunk.depth || z >= WorldChunk.width { 56 | return 0 57 | } 58 | if sections[Int(y >> 4)].isEmpty { 59 | return 0 60 | } 61 | return UInt8(sections[Int(y >> 4)][index(x: x, y: y, z: z)] >> 4) 62 | } 63 | 64 | public func setBlock(x: Int32, y: Int32, z: Int32, material: Material) { 65 | if material.isBlock() { 66 | setBlock(x: x, y: y, z: z, blockId: UInt8(material.id)) 67 | } 68 | } 69 | 70 | public func setBlock(x: Int32, y: Int32, z: Int32, materialData: MaterialData) { 71 | if materialData.id < 256 { 72 | setBlock(x: x, y: y, z: z, blockId: UInt8(materialData.id), data: materialData.data) 73 | } 74 | } 75 | 76 | public func setBlock(x: Int32, y: Int32, z: Int32, blockId: UInt8, data: UInt8 = 0) { 77 | if x < 0 || y < 0 || z < 0 || x >= WorldChunk.height || y >= WorldChunk.depth || z >= WorldChunk.width { 78 | return 79 | } 80 | if sections[Int(y >> 4)].isEmpty { 81 | sections[Int(y >> 4)] = [UInt16](repeating: 0, count: 4096) 82 | } 83 | sections[Int(y >> 4)][index(x: x, y: y, z: z)] = (UInt16(blockId) << 4) | UInt16(data) 84 | } 85 | 86 | internal func getSections() -> [[UInt16]] { 87 | return sections 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Worlds/WorldConfiguration.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import NIO 22 | 23 | public class WorldConfiguration { 24 | 25 | // Internal storage 26 | private var root: NBTCompound? 27 | private var data: NBTCompound? { 28 | return root?["Data"] as? NBTCompound 29 | } 30 | 31 | // Variables 32 | var difficulty: Int8 { 33 | get { return (data?["Difficulty"] as? NBTByte)?.value ?? 2 } 34 | set { data?.put(NBTByte(name: "Difficulty", value: newValue)) } 35 | } 36 | var dayTime: Int64 { 37 | get { return (data?["DayTime"] as? NBTLong)?.value ?? 0 } 38 | set { data?.put(NBTLong(name: "DayTime", value: newValue)) } 39 | } 40 | var gameType: GameMode { 41 | get { return (data?["GameType"] as? NBTInt)?.value ?? 0 } 42 | set { data?.put(NBTInt(name: "GameType", value: newValue)) } 43 | } 44 | var initialized: Bool { 45 | get { return (data?["initialized"] as? NBTByte)?.value == 1 } 46 | set { data?.put(NBTByte(name: "initialized", value: newValue ? 1 : 0)) } 47 | } 48 | var levelName: String { 49 | get { return (data?["LevelName"] as? NBTString)?.value ?? "" } 50 | set { data?.put(NBTString(name: "LevelName", value: newValue)) } 51 | } 52 | var randomSeed: Int64 { 53 | get { return (data?["RandomSeed"] as? NBTLong)?.value ?? 0 } 54 | set { data?.put(NBTLong(name: "RandomSeed", value: newValue)) } 55 | } 56 | var spawnX: Int32 { 57 | get { return (data?["SpawnX"] as? NBTInt)?.value ?? 0 } 58 | set { data?.put(NBTInt(name: "SpawnX", value: newValue)) } 59 | } 60 | var spawnY: Int32 { 61 | get { return (data?["SpawnY"] as? NBTInt)?.value ?? 64 } 62 | set { data?.put(NBTInt(name: "SpawnY", value: newValue)) } 63 | } 64 | var spawnZ: Int32 { 65 | get { return (data?["SpawnZ"] as? NBTInt)?.value ?? 0 } 66 | set { data?.put(NBTInt(name: "SpawnZ", value: newValue)) } 67 | } 68 | 69 | // Read from file 70 | public func read(from file: URL) throws { 71 | // Check if the configuration exists 72 | if FileManager.default.fileExists(atPath: file.path), let content = FileManager.default.contents(atPath: file.path) { 73 | // Try to load configuration 74 | var buffer = ByteBufferAllocator().buffer(capacity: content.count) 75 | buffer.writeBytes(content) 76 | buffer = try buffer.decompress(with: .gzip) 77 | self.root = buffer.readNBT() as? NBTCompound 78 | } 79 | 80 | // If the root is nil, generate a new configuration 81 | if self.root == nil { 82 | // Compounds creation 83 | self.root = NBTCompound(name: "", values: [NBTCompound(name: "Data")]) 84 | 85 | // Fill data 86 | self.difficulty = 2 87 | self.dayTime = 0 88 | self.gameType = 0 89 | self.initialized = false 90 | self.levelName = file.lastPathComponent 91 | self.randomSeed = Int64.random(in: Int64.min ... Int64.max) 92 | } 93 | } 94 | 95 | // Save to file 96 | public func save(to file: URL) throws { 97 | // Get the content 98 | guard let root = root else { return } 99 | 100 | // Put the content in a buffer 101 | var level_content = ByteBufferAllocator().buffer(capacity: root.fullSize()) 102 | level_content.writeNBT(tag: root) 103 | level_content = try level_content.compress(with: .gzip) 104 | 105 | // Save to disk 106 | FileManager.default.createFile(atPath: file.path, contents: level_content.readData(length: level_content.readableBytes), attributes: nil) 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Worlds/WorldGenerator.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public protocol WorldGenerator { 23 | 24 | func generateBiomes(world: LocalWorld, random: Random, chunkX: Int32, chunkZ: Int32) -> [Int8] 25 | 26 | func generateChunkData(world: LocalWorld, random: Random, chunkX: Int32, chunkZ: Int32, biomes: [Int8]) -> WorldChunkData 27 | 28 | func getName() -> String 29 | 30 | } 31 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Worlds/WorldProtocol.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public protocol WorldProtocol { 23 | 24 | func connect(client: ChannelWrapper) 25 | 26 | func disconnect(client: ChannelWrapper) 27 | 28 | func handle(packet: Packet, for client: ChannelWrapper) 29 | 30 | func pingWorld(from client: ChannelWrapper, completionHandler: @escaping (ServerInfo?) -> ()) 31 | 32 | func getName() -> String 33 | 34 | func getType() -> WorldType 35 | 36 | func getPlayers() -> [Player] 37 | 38 | func load() 39 | 40 | func save() 41 | 42 | func getChunk(x: Int32, z: Int32) -> WorldChunk 43 | 44 | } 45 | 46 | extension WorldProtocol { 47 | 48 | public func getPlayer(uuid: String) -> Player? { 49 | return getPlayers().first(where: { player in 50 | return player.getUUID() == uuid 51 | }) 52 | } 53 | 54 | public func getPlayer(name: String) -> Player? { 55 | return getPlayers().first(where: { player in 56 | return player.getName() == name 57 | }) 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Sources/SwiftMC/Worlds/WorldType.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | 22 | public enum WorldType: String { 23 | 24 | case local, remote 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Sources/SwiftMCRun/main.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 Groupe MINASTE 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License along 15 | * with this program; if not, write to the Free Software Foundation, Inc., 16 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * 18 | */ 19 | 20 | import Foundation 21 | import SwiftMC 22 | 23 | // Initialize a server 24 | let server = SwiftMC() 25 | 26 | // And start it 27 | DispatchQueue.global().async { 28 | server.start() 29 | exit(0) 30 | } 31 | 32 | // Read commands from console 33 | while let input = readLine(strippingNewline: true) { 34 | server.dispatchCommand(command: input) 35 | } 36 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import SwiftMCTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += SwiftMCTests.allTests() 7 | XCTMain(tests) 8 | -------------------------------------------------------------------------------- /Tests/SwiftMCTests/SwiftMCTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import SwiftMC 3 | 4 | final class SwiftMCTests: XCTestCase { 5 | func testExample() { 6 | // This is an example of a functional test case. 7 | // Use XCTAssert and related functions to verify your tests produce the correct 8 | // results. 9 | //XCTAssertEqual(SwiftMC().text, "Hello, World!") 10 | } 11 | 12 | static var allTests = [ 13 | ("testExample", testExample), 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /Tests/SwiftMCTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !canImport(ObjectiveC) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(SwiftMCTests.allTests), 7 | ] 8 | } 9 | #endif 10 | --------------------------------------------------------------------------------