Skip to content

Commit

Permalink
Change Packet to a Class
Browse files Browse the repository at this point in the history
Packet is now a base class instead of a Protocol. This is so that it can conform to Equtable which is needed to be tested.
  • Loading branch information
marzvrover committed Dec 16, 2020
1 parent b837bdf commit 59a7848
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 38 deletions.
55 changes: 27 additions & 28 deletions Sources/SwiftcraftLibrary/Networking/Packet/Handshake.swift
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
//
// File.swift
//
//
// Created by Marz Rover on 12/3/20.
//

import Foundation
import NIO

/// The Minecraft Handshake `Packet`
struct Handshake: Packet {
/// The `Packet`.`id` for the Minecraft Handshake Packet is 0x00
var id: Int32 = 0x00
/// This is where the key=>value pairs from the packet are stored.
/// At first this field is an empty [:] while waiting for the decoder to decode values.
var data: [String : Any] = [:]
/// Defines how to decode the `Handshake` `Packet`
///
/// Field Name | Datatype | Decoder Arguments | Notes
/// -----------------|-------------------------------------------|-------------------|-------------------------------------------------
/// protocol_version | `PacketData`.`varInt` aka `Int32` | | The Minecraft Protocol version number.
/// server_address | `PacketData`.`varString` aka `String` | | The server address the client is connecting to.
/// server_port | `PacketData`.`unsignedShort` aka `UInt16` | | The server port the client is connecting to.
/// intention | `PacketData`.`varInt` aka `Int32` | | 1 for status, 2 for login
var definition: Definition = [
(name: "protocol_version", type: .varInt, args: nil),
(name: "server_address", type: .varString, args: nil),
(name: "server_port", type: .unsignedShort, args: nil),
(name: "intention", type: .varInt, args: nil),
]
/// # The Minecraft Handshake `Packet`
///
/// ## ID
/// The `Packet`.`id` for the Minecraft Handshake Packet is 0x00
///
/// ## Definition
///
/// Field Name | Datatype | Decoder Arguments | Notes
/// -----------------|-------------------------------------------|-------------------|-------------------------------------------------
/// protocol_version | `PacketData`.`varInt` aka `Int32` | | The Minecraft Protocol version number.
/// server_address | `PacketData`.`varString` aka `String` | | The server address the client is connecting to.
/// server_port | `PacketData`.`unsignedShort` aka `UInt16` | | The server port the client is connecting to.
/// intention | `PacketData`.`varInt` aka `Int32` | | 1 for status, 2 for login
class Handshake: Packet {
/// Handshake Initializer
init() {
super.init(
id: 0x00,
definition: [
(name: "protocol_version", type: .varInt, args: nil),
(name: "server_address", type: .varString, args: nil),
(name: "server_port", type: .unsignedShort, args: nil),
(name: "intention", type: .varInt, args: nil),
],
data: [:]
)
}
/// Getter and setter for `Handshake`.`data["protocol_version"]`.
var version: Int32 {
get {
Expand Down
87 changes: 77 additions & 10 deletions Sources/SwiftcraftLibrary/Networking/Packet/Packet.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
//
// Packet.swift
//
//
// Created by Marz Rover on 12/2/20.
//

import Foundation
import NIO

Expand Down Expand Up @@ -48,10 +41,84 @@ enum PacketData: String {
/// Minecraft `VarString` is a `String`
case varString = "String"
}
/// Packet class. This is the base class for all Packets.
class Packet: PacketProtocol & Equatable {
/// Conform to `Equatable` using `AnyHashable` to determine if values of type `Any` are equal.
///
/// - note: There has to be a better way to this.
/// But seeing as we shouldn't have to compare `Packet`s often besides in tests this will do for now.
static func == (lhs: Packet, rhs: Packet) -> Bool {
guard lhs.id == rhs.id else {
return false
}
guard lhs.definition.count == rhs.definition.count else {
return false
}
guard lhs.data.count == rhs.data.count else {
return false
}
for (key, value) in lhs.data {
guard rhs.data.keys.contains(key) else {
return false
}
guard value is AnyHashable else {
return false
}
let rvalue = rhs.data[key]
guard rvalue is AnyHashable else {
return false
}
guard value as! AnyHashable == rvalue as! AnyHashable else {
return false
}
}
for (index, (name, type, args)) in lhs.definition.enumerated() {
guard name == rhs.definition[index].name else {
return false
}
guard type == rhs.definition[index].type else {
return false
}
guard args != nil else {
if rhs.definition[index].args == nil {
continue
}
return false
}
for (key, value) in args! {
guard rhs.definition[index].args!.keys.contains(key) else {
return false
}
guard value is AnyHashable else {
return false
}
let rvalue = rhs.definition[index].args![key]
guard rvalue is AnyHashable else {
return false
}
guard (value as! AnyHashable) == (rvalue as! AnyHashable) else {
return false
}
}
}

return true
}

var data: [String : Any]
var definition: Definition
var id: Int32

internal init(id: Int32, definition: Definition, data: [String : Any]) {
self.id = id
self.definition = definition
self.data = data
}
}

/// A Packet must have these fields.
protocol Packet {
typealias Definition = [(name: String, type: PacketData, args: [String:Any]?)]
protocol PacketProtocol {
typealias Definition = [(name: String, type: PacketData, args: [String : Any]?)]
/// This is where the key=>value pairs from the packet are stored.
var data: [String:Any] { get set }
/// Defines how to decode the packet
Expand All @@ -61,7 +128,7 @@ protocol Packet {
}

/// Because of a definition field we can quickly and easily decode / encode packets
extension Packet {
extension PacketProtocol {
/// Decode the pack according to the `Packet`.`definition` field.
/// Load the results into the `Packet`.`data` field.
///
Expand Down

0 comments on commit 59a7848

Please sign in to comment.