Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
marzvrover committed Dec 2, 2020
0 parents commit e26e33b
Show file tree
Hide file tree
Showing 15 changed files with 487 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.DS_Store
/.build
/Packages
/*.xcodeproj
xcuserdata/
/.swiftpm
34 changes: 34 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"object": {
"pins": [
{
"package": "Rainbow",
"repositoryURL": "https://github.com/onevcat/Rainbow",
"state": {
"branch": null,
"revision": "626c3d4b6b55354b4af3aa309f998fae9b31a3d9",
"version": "3.2.0"
}
},
{
"package": "swift-log",
"repositoryURL": "https://github.com/apple/swift-log.git",
"state": {
"branch": null,
"revision": "173f567a2dfec11d74588eea82cecea555bdc0bc",
"version": "1.4.0"
}
},
{
"package": "swift-nio",
"repositoryURL": "https://github.com/apple/swift-nio.git",
"state": {
"branch": null,
"revision": "c3e2359c55cd8b47207ab7363b77c9c398a95294",
"version": "2.23.0"
}
}
]
},
"version": 1
}
58 changes: 58 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "Swiftcraft",
platforms: [
.macOS(.v10_10),
],
products: [
.executable(name: "Swiftcraft", targets: ["Swiftcraft"]),
.library(name: "SwiftcraftLibrary", targets: ["SwiftcraftLibrary"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),

.package(url: "https://github.com/onevcat/Rainbow", from: "3.0.0"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.23.0"),
.package(url: "https://github.com/apple/swift-log.git", from: "1.4.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "Swiftcraft",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "NIO", package: "swift-nio"),
"Rainbow",
"SwiftcraftLibrary",
]
),
.target(
name: "SwiftcraftLibrary",
dependencies: [
.product(name: "Logging", package: "swift-log"),
.product(name: "NIO", package: "swift-nio"),
"Rainbow",
]
),
.testTarget(
name: "SwiftcraftLibraryTests",
dependencies: [
"SwiftcraftLibrary",
.product(name: "NIO", package: "swift-nio"),
]
),
.testTarget(
name: "SwiftcraftTests",
dependencies: [
"Swiftcraft",
.product(name: "NIO", package: "swift-nio"),
]
),
]
)
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Swiftcraft

Swiftcraft is a swift implementation of the Minecraft Server. The goal of this project is to provide a fast resource efficient Minecraft server.
**This is an active WIP.** Currently in the first steps of implementing the Minecraft Protocol.
You should expect massive amounts of refactoring.

## Protocol

This server is built from the ground up implementing [Minecraft's Protocol.](https://wiki.vg/Protocol)

## Credits

I would like to give a huge shoutout to #mcdevs for their working in maintaining [Wiki.vg](wiki.vg)
37 changes: 37 additions & 0 deletions Sources/Swiftcraft/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Foundation
import NIO
import SwiftcraftLibrary
import Rainbow

// seed linux random number
#if os(Linux)
srand(UInt(time(nil)))
#endif

signal(SIGINT) {_ in
if (server.isRunning == true) {
server.shutdown()
}
exit(0)
}

print("Welcome to Swiftcraft!".green)

let host = "127.0.0.1"
let port = 25564

var server = Server(host: host, port: port)

defer {
server.shutdown()
}

do {
try server.run()
} catch let error {
print(error)
print("Shutting down server due to fatal error")
server.shutdown()
}

print("Server closed")
94 changes: 94 additions & 0 deletions Sources/SwiftcraftLibrary/DataTypes.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//
// DataTypes.swift
// Swiftcraft
//
// Created by Marz Rover on 11/21/20.
//

import Foundation
import NIO

typealias Byte = UInt8
typealias ByteArray = [Byte]

enum VarIntError: Error {
case varIntIsTooBig
}

enum VarLongError: Error {
case varLongIsTooBig
}

extension Int32 {
init(buffer byteBuffer: inout ByteBuffer) throws {
self.init()
var result: Self = 0
var shift = 0
var input: Byte
repeat {
input = Byte(byteBuffer.readBytes(length: 1)![0])
result |= Self((input & Byte(0x7F)) << (shift * 7))
shift += 1
if (shift > 5) {
throw VarIntError.varIntIsTooBig
}
} while ((input & 0x80) != 0x80)
self = result
}

var varInt: ByteArray {
var out: ByteArray = []
var part: Byte
var value = self
repeat {
part = Byte(value & 0x7F)
value >>= 7
if (value != 0) {
part |= 0x80
}
out.append(part)
} while (value == 0)
return out
}
}

extension Int64 {
init(buffer byteBuffer: inout ByteBuffer) throws {
self.init()
var result: Self = 0
var shift = 0
var input: Byte
repeat {
input = Byte(byteBuffer.readBytes(length: 1)![0])
result |= Self((input & Byte(0x7F)) << (shift * 7))
shift += 1
if (shift > 10) {
throw VarLongError.varLongIsTooBig
}
} while ((input & 0x80) != 0x80)
self = result
}

var varLong: ByteArray {
var out: ByteArray = []
var part: Byte
var value = self
repeat {
part = Byte(value & 0x7F)
value >>= 7
if (value != 0) {
part |= 0x80
}
out.append(part)
} while (value == 0)
return out
}
}

extension String {
init(buffer: inout ByteBuffer) throws {
self.init()
let length = Int(try! Int32(buffer: &buffer))
self = buffer.readString(length: length)!
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import NIO

public final class HandshakeHandler: ChannelInboundHandler {
public typealias InboundIn = ByteBuffer
public typealias OutboundOut = ByteBuffer

public func channelActive(context: ChannelHandlerContext) {
debug("Active connection at \(context.remoteAddress!)")
}

public func channelInactive(context: ChannelHandlerContext) {
debug("Inactive connection at \(context.remoteAddress!)")
}

public func channelRegistered(context: ChannelHandlerContext) {
debug("Registered connection at \(context.remoteAddress!)")
}

public func channelUnregistered(context: ChannelHandlerContext) {
debug("Unregistered connection at \(context.remoteAddress!)")
}

public func channelRead(context: ChannelHandlerContext, data: NIOAny) {
// As we are not really interested getting notified on success or failure we just pass nil as promise to
// reduce allocations.
// context.write(data, promise: nil)
/// The last three bytes of the handshake buffer are used for an Unsigned Short and a VarInt [source](https://wiki.vg/Protocol#Handshake)
/// Up to 1023 bytes before the last three are used for String (255) preceded with a VarInt of how many bytes
/// The first set of bytes is a VarInt
var byteBuffer = self.unwrapInboundIn(data)
try! print(Int32(buffer: &byteBuffer))
try! print(String(buffer: &byteBuffer))

}

// Flush it out. This can make use of gathering writes if multiple buffers are pending
public func channelReadComplete(context: ChannelHandlerContext) {
context.flush()
}

public func channelWritabilityChanged(context: ChannelHandlerContext) {
debug("Writability changed at \(context.remoteAddress!)")
}

public func userInboundEventTriggered(context: ChannelHandlerContext, event: Any) {
debug("User \(context.remoteAddress!)")
debug("Event \(event)")
}

public func errorCaught(context: ChannelHandlerContext, error: Error) {
print("error: ", error)

// As we are not really interested getting notified on success or failure we just pass nil as promise to
// reduce allocations.
context.close(promise: nil)
}
}
66 changes: 66 additions & 0 deletions Sources/SwiftcraftLibrary/Networking/Server.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// Server.swift
// Swiftcraft
//
// Created by Marz Rover on 11/17/20.
//

import Foundation
import NIO

open class Server {
public var isRunning: Bool
public var host: String
public var port: Int
public var channel: Channel?

public let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)

public var bootstrap: ServerBootstrap {
ServerBootstrap(group: group)
// Specify backlog and enable SO_REUSEADDR for the server itself
.serverChannelOption(ChannelOptions.backlog, value: 256)
.serverChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)

// Set the handlers that are appled to the accepted Channels
.childChannelInitializer { channel in
// Ensure we don't read faster than we can write by adding the BackPressureHandler into the pipeline.
channel.pipeline.addHandler(BackPressureHandler()).flatMap { v in
channel.pipeline.addHandler(HandshakeHandler())
}
}

// Enable SO_REUSEADDR for the accepted Channels
.childChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
.childChannelOption(ChannelOptions.maxMessagesPerRead, value: 16)
.childChannelOption(ChannelOptions.recvAllocator, value: AdaptiveRecvByteBufferAllocator())
}

public init(host: String, port: Int) {
self.isRunning = true
self.host = host
self.port = port
}

public func run() throws {
self.channel = try { () -> Channel in
return try self.bootstrap.bind(host: self.host, port: self.port).wait()
}()

print("Server started and listening on \(channel!.localAddress!)")

// This will never unblock as we don't close the ServerChannel
try channel!.closeFuture.wait()
}

public func shutdown() {
do {
try self.group.syncShutdownGracefully()
} catch let error {
print(error)
print("Forcing exit")
exit(1)
}
print("Server Shutdown")
}
}
4 changes: 4 additions & 0 deletions Sources/SwiftcraftLibrary/SwiftcraftLibrary-Bridging-Header.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//

14 changes: 14 additions & 0 deletions Sources/SwiftcraftLibrary/SwiftcraftLibrary.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// SwiftcraftLibrary.swift
// Swiftcraft
//
// Created by Marz Rover on 12/2/20.
//

import Foundation

public func debug(_ object: Any) {
#if DEBUG
Swift.print(object)
#endif
}
Loading

0 comments on commit e26e33b

Please sign in to comment.