diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/spacewar-swift.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/spacewar-swift.xcscheme deleted file mode 100644 index 5db4095..0000000 --- a/.swiftpm/xcode/xcshareddata/xcschemes/spacewar-swift.xcscheme +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Package.resolved b/Package.resolved index 18adcc0..e18ce03 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/johnfairh/steamworks-swift", "state" : { - "branch" : "main", - "revision" : "78fae74c61a7e91096b4beecb01a18e72b562a05" + "revision" : "d65d442139b042ce1172de95b915e9974c7d7fa7", + "version" : "0.3.0" } }, { @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-log.git", "state" : { - "revision" : "6fe203dc33195667ce1759bf0182975e4653ba1c", - "version" : "1.4.4" + "revision" : "32e8d724467f8fe623624570367e3d50c5638e46", + "version" : "1.5.2" } }, { @@ -23,8 +23,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/johnfairh/TMLEngines", "state" : { - "revision" : "81646b99277ce42ee5acc34577965cc292c2f587", - "version" : "1.2.4" + "revision" : "51a2ff3056ff60d3ebc6df1f3d8504d02b7c8ef3", + "version" : "1.3.0" } } ], diff --git a/Package.swift b/Package.swift index d5ae4a9..f972330 100644 --- a/Package.swift +++ b/Package.swift @@ -1,15 +1,15 @@ -// swift-tools-version: 5.7 +// swift-tools-version: 5.9 import PackageDescription let package = Package( name: "spacewar-swift", platforms: [ - .macOS("12.0"), + .macOS("13.0"), ], dependencies: [ .package(url: "https://github.com/johnfairh/steamworks-swift", - branch: "main"), + from: "0.3.0"), .package(url: "https://github.com/johnfairh/TMLEngines", from: "1.2.0") ], @@ -27,7 +27,8 @@ let package = Package( .process("Resources/steam_input_manifest.vdf"), .process("Resources/xbox_controller.vdf"), .process("Resources/ps5_controller.vdf") - ] + ], + swiftSettings: [.interoperabilityMode(.Cxx)] ), .systemLibrary(name: "CSpaceWar") ] diff --git a/README.md b/README.md index 4fc1a07..32c224e 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,7 @@ # spacewar-swift Educational port of Steamworks demo to Swift for macOS with Metal backend. + +Needs Xcode 15 / Swift 5.9 + +Needs Steam up and logged in; best run from CLI `swift run`. diff --git a/Sources/CSpaceWar/cspacewar.h b/Sources/CSpaceWar/cspacewar.h index 1040256..6c75125 100644 --- a/Sources/CSpaceWar/cspacewar.h +++ b/Sources/CSpaceWar/cspacewar.h @@ -1,5 +1,7 @@ #ifndef CSPACEWAR_H +extern "C" { + #include typedef short int16; @@ -8,7 +10,7 @@ typedef int int32; typedef unsigned int uint32; typedef long long int64; typedef unsigned long long uint64; -typedef unsigned char bool; +typedef unsigned char netbool; typedef unsigned char uint8; typedef uint32 netfloat; // network rep of single-prec floating-point @@ -20,7 +22,7 @@ typedef uint32 netfloat; // network rep of single-prec floating-point typedef struct { uint32 messageType; uint64 steamIDServer; - bool isVACSecure; + netbool isVACSecure; char serverName[128]; } MsgServerSendInfo_t; @@ -60,8 +62,14 @@ typedef struct { #define ARRAY_GETTER(TYPE,FIELD,FIELDTYPE) \ __attribute__((swift_name("getter:" #TYPE "." #FIELD "_ptr(self:)"))) \ +static inline const FIELDTYPE * _Nonnull TYPE ## _Get ## FIELD (const TYPE * _Nonnull t) { \ + return &t->FIELD[0]; \ +} + +#define ARRAY_MUTABLE_GETTER(TYPE,FIELD,FIELDTYPE) \ +__attribute__((swift_name("getter:" #TYPE "." #FIELD "_ptr(self:)"))) \ static inline FIELDTYPE * _Nonnull TYPE ## _Get ## FIELD (const TYPE * _Nonnull t) { \ - return t->FIELD; \ + return const_cast(&t->FIELD[0]); \ } ARRAY_GETTER(MsgClientBeginAuthentication_t, token, uint8) @@ -76,11 +84,11 @@ static inline void MsgClientBeginAuthentication_SetToken(MsgClientBeginAuthentic typedef struct { uint32 messageType; uint32 tokenLen; - char token[1024]; + uint8 token[1024]; uint64 steamID; } MsgP2PSendingTicket_t; -ARRAY_GETTER(MsgP2PSendingTicket_t, token, uint8) +ARRAY_MUTABLE_GETTER(MsgP2PSendingTicket_t, token, uint8) typedef struct { uint32 messageType; @@ -89,13 +97,13 @@ typedef struct { uint8 data[1024]; } MsgVoiceChatData_t; -ARRAY_GETTER(MsgVoiceChatData_t, data, uint8) +ARRAY_MUTABLE_GETTER(MsgVoiceChatData_t, data, uint8) // MARK: Game, Server -> Client typedef struct { // Does the photon beam exist right now? - bool isActive; + netbool isActive; // The current rotation netfloat currentRotation; @@ -132,14 +140,14 @@ typedef struct { netfloat yPosition; // Is the ship exploding? - bool exploding; + netbool exploding; // Is the ship disabled? - bool disabled; + netbool disabled; // Are the thrusters to be drawn? - bool forwardThrustersActive; - bool reverseThrustersActive; + netbool forwardThrustersActive; + netbool reverseThrustersActive; // Decoration for this ship int32 shipDecoration; @@ -173,7 +181,7 @@ typedef struct { uint32 playerWhoWonGame; // which player slots are in use - bool playersActive[MAX_PLAYERS_PER_SERVER]; + netbool playersActive[MAX_PLAYERS_PER_SERVER]; // what are the scores for each player? uint32 playerScores[MAX_PLAYERS_PER_SERVER]; @@ -185,7 +193,7 @@ typedef struct { uint64 playerSteamIDs[MAX_PLAYERS_PER_SERVER]; } ServerSpaceWarUpdateData_t; -ARRAY_GETTER(ServerSpaceWarUpdateData_t, playersActive, bool) +ARRAY_GETTER(ServerSpaceWarUpdateData_t, playersActive, netbool) ARRAY_GETTER(ServerSpaceWarUpdateData_t, playerScores, uint32) ARRAY_GETTER(ServerSpaceWarUpdateData_t, shipData, ServerShipUpdateData_t) ARRAY_GETTER(ServerSpaceWarUpdateData_t, playerSteamIDs, uint64) @@ -199,11 +207,11 @@ typedef struct { typedef struct { // Key's which are done - bool firePressed; - bool turnLeftPressed; - bool turnRightPressed; - bool forwardThrustersPressed; - bool reverseThrustersPressed; + netbool firePressed; + netbool turnLeftPressed; + netbool turnRightPressed; + netbool forwardThrustersPressed; + netbool reverseThrustersPressed; // Decoration for this ship int32 shipDecoration; @@ -240,4 +248,6 @@ typedef struct { #pragma pack( pop ) +} + #endif diff --git a/Sources/SpaceWar/Messages.swift b/Sources/SpaceWar/Messages.swift index 580ef0c..4a98d62 100644 --- a/Sources/SpaceWar/Messages.swift +++ b/Sources/SpaceWar/Messages.swift @@ -138,13 +138,13 @@ extension Bool { /// Fixed-size array tuple bullshit. holy fuck. extension Array { - static func four(_ p: UnsafeMutablePointer, map: (X) -> Element) -> Array{ - let bp = UnsafeMutableBufferPointer(start: p, count: 4) + static func four(_ p: UnsafePointer, map: (X) -> Element) -> Array{ + let bp = UnsafeBufferPointer(start: p, count: 4) return bp.map(map) } - static func seven(_ p: UnsafeMutablePointer, map: (X) -> Element) -> Array{ - let bp = UnsafeMutableBufferPointer(start: p, count: 7) + static func seven(_ p: UnsafePointer, map: (X) -> Element) -> Array{ + let bp = UnsafeBufferPointer(start: p, count: 7) return bp.map(map) } @@ -623,10 +623,10 @@ extension MsgP2PSendingTicket_t: ConstructableFrom { if let buf = from.buffer { precondition(buf.count <= 1024) self.tokenLen = UInt32(buf.count).bigEndian - self.token_ptr.assign(from: buf.baseAddress!, count: buf.count) + self.token_ptr.update(from: buf.baseAddress!, count: buf.count) } else { self.tokenLen = UInt32(from.token.count).bigEndian - self.token_ptr.assign(from: from.token, count: from.token.count) + self.token_ptr.update(from: from.token, count: from.token.count) } } } @@ -665,11 +665,11 @@ extension MsgVoiceChatData_t: ConstructableFrom { // got msg from a client, forwarding it... precondition(buf.count <= 1024) /* ahem */ self.dataLength = UInt32(buf.count).bigEndian - self.data_ptr.assign(from: buf.baseAddress!, count: buf.count) + self.data_ptr.update(from: buf.baseAddress!, count: buf.count) } else { // created msg here, converting from swift self.dataLength = UInt32(from.data.count).bigEndian - self.data_ptr.assign(from: from.data, count: from.data.count) + self.data_ptr.update(from: from.data, count: from.data.count) } } } diff --git a/Sources/SpaceWar/SpaceWarEntity.swift b/Sources/SpaceWar/SpaceWarEntity.swift index f614a93..f38ac65 100644 --- a/Sources/SpaceWar/SpaceWarEntity.swift +++ b/Sources/SpaceWar/SpaceWarEntity.swift @@ -23,13 +23,15 @@ class SpaceWarEntity: VectorEntity { // The suns gravity, compute that here, sun is always at the center of the screen [JF: !!!] let posSun = engine.viewportSize / 2 - // let distanceToSun = min(simd_distance(posSun, pos), 1) // JF: guard div0... - // let distancePower = pow(distanceToSun, 2) // gravity power falls off exponentially - let distancePower = max(simd_distance_squared(posSun, pos), 1) + #if true // XXX CxxInterop + let distancePower = max(my_distance_squared(posSun, pos), 1) + #else + let distancePower = max(simd_distance_squared(posSun, pos), 1) // gravity power falls off exponentially; guard div0 + #endif let factor = min(100000.0 / distancePower, SpaceWarEntity.MIN_GRAVITY) // arbitrary value for power of gravity - let direction = simd_normalize(pos - posSun) + let direction = my_normalize(pos - posSun) // XXX CxxInterop simd_normalize(pos - posSun) // Set updated acceleration acceleration -= factor * direction @@ -38,3 +40,23 @@ class SpaceWarEntity: VectorEntity { super.runFrame() } } + +// Swift C++ interop makes simd_vector_add() not link, which loads depends on ... baffling +func my_distance_squared(_ a: SIMD2, _ b: SIMD2) -> Float { + let xs = pow(a.x - b.x, 2) + let ys = pow(a.y - b.y, 2) + return xs + ys +} + +func my_distance(_ a: SIMD2, _ b: SIMD2) -> Float { + sqrt(my_distance_squared(a, b)) +} + +func my_length(_ v: SIMD2) -> Float { + sqrt(pow(v.x, 2) + pow(v.y, 2)) +} + +private func my_normalize(_ v: SIMD2) -> SIMD2 { + let len = my_length(v) + return [v.x / len, v.y / len] +} diff --git a/Sources/SpaceWar/VectorEntity.swift b/Sources/SpaceWar/VectorEntity.swift index 3e4d56f..023436c 100644 --- a/Sources/SpaceWar/VectorEntity.swift +++ b/Sources/SpaceWar/VectorEntity.swift @@ -31,7 +31,7 @@ class VectorEntity { /// The distance travelled since the last frame var distanceTraveledLastFrame: Float { - simd_distance(pos, posLastFrame) + my_distance(pos, posLastFrame) // XXX CxxInterop simd_distance(pos, posLastFrame) } /// Current velocity - normally computed from acceleration @@ -100,7 +100,7 @@ class VectorEntity { // Make sure velocity does not exceed maximum allowed - this scales it while // keeping the aspect ratio consistent - let linearVelocity = simd_length(velocity) + let linearVelocity = my_length(velocity) // XXX CxxInterop simd_length(velocity) if linearVelocity > maximumVelocity { let ratio = maximumVelocity / linearVelocity velocity *= ratio @@ -143,7 +143,8 @@ class VectorEntity { return false } - return simd_distance(pos, target.pos) < collisionRadius + target.collisionRadius +// return simd_distance(pos, target.pos) < collisionRadius + target.collisionRadius XXX CxxInterop + return my_distance(pos, target.pos) < collisionRadius + target.collisionRadius } }