Skip to content

Commit

Permalink
Swift 5.10 updates
Browse files Browse the repository at this point in the history
  • Loading branch information
johnfairh committed May 2, 2024
1 parent 45014fa commit eecb601
Show file tree
Hide file tree
Showing 21 changed files with 84 additions and 60 deletions.
15 changes: 8 additions & 7 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
{
"originHash" : "0e835b31f6c99de6fcc976f46a22a3f635ba60b860700b86b6104956fd572882",
"pins" : [
{
"identity" : "steamworks-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/johnfairh/steamworks-swift",
"state" : {
"revision" : "56ef22fc7c1cd98fc2e04acf4d45bcb4bc9db389",
"version" : "0.5.1"
"revision" : "a55227dc4f155977147d7cb66c0d164c6139a870",
"version" : "0.5.2"
}
},
{
"identity" : "swift-log",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-log.git",
"state" : {
"revision" : "532d8b529501fb73a2455b179e0bbb6d49b652ed",
"version" : "1.5.3"
"revision" : "e97a6fcb1ab07462881ac165fdbb37f067e205d5",
"version" : "1.5.4"
}
},
{
"identity" : "tmlengines",
"kind" : "remoteSourceControl",
"location" : "https://github.com/johnfairh/TMLEngines",
"state" : {
"revision" : "6ba327419697ce9e150f6c782a59fa7b4ea89124",
"version" : "1.3.1"
"revision" : "3a728fea123425746bea5ec0b07ee6c80eb6c53d",
"version" : "1.3.3"
}
}
],
"version" : 2
"version" : 3
}
13 changes: 8 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
// swift-tools-version: 5.9
// swift-tools-version: 5.10

import PackageDescription

let package = Package(
name: "spacewar-swift",
platforms: [
.macOS("13.0"),
.macOS("14.0"),
],
dependencies: [
.package(url: "https://github.com/johnfairh/steamworks-swift",
from: "0.5.1"),
from: "0.5.2"),
.package(url: "https://github.com/johnfairh/TMLEngines",
from: "1.2.0")
from: "1.3.3")
],
targets: [
.executableTarget(
Expand All @@ -28,7 +28,10 @@ let package = Package(
.process("Resources/xbox_controller.vdf"),
.process("Resources/ps5_controller.vdf")
],
swiftSettings: [.interoperabilityMode(.Cxx)]
swiftSettings: [
.interoperabilityMode(.Cxx),
.enableExperimentalFeature("StrictConcurrency")
]
),
.systemLibrary(name: "CSpaceWar")
]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

Educational port of Steamworks demo to Swift for macOS with Metal backend.

Needs Xcode 15 / Swift 5.9
Needs Xcode 15.3 / Swift 5.10

Needs Steam up and logged in; best run from CLI `swift run` - see CI for
pre-reqs.
16 changes: 11 additions & 5 deletions Sources/SpaceWar/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Dispatch
/// Don't actually create the client or set up Steam until the engine starts up and gives
/// us a context to create objects and hang stuff on.
@main
@MainActor
struct SpaceWarApp: App {
init() {
// Some nonsense to simulate a library that probably doesn't exist
Expand Down Expand Up @@ -53,12 +54,13 @@ struct SpaceWarApp: App {
}

/// Might need to reach around here from random places, not sure
@MainActor
static private(set) var instance: SpaceWarMain?

/// Steam API initialization dance
private func initSteam() -> (SteamAPI, Controller) {
// Set our log handler before SteamAPI creates a logger
SWLogHandler.setup()
SWLogHandler.setup(level: .trace)
LoggingSystem.bootstrap(SWLogHandler.init)

guard let steam = SteamAPI(appID: .spaceWar, fakeAppIdTxtFile: true) else {
Expand All @@ -69,7 +71,6 @@ struct SpaceWarApp: App {
// Debug handlers
steam.useLoggerForSteamworksWarnings()
steam.networkingUtils.useLoggerForDebug(detailLevel: .everything)
SteamAPI.logger.logLevel = .debug

// Ensure that the user has logged into Steam. This will always return true if the game is launched
// from Steam, but if Steam is at the login prompt when you run your game from the debugger, it
Expand Down Expand Up @@ -122,8 +123,9 @@ struct SpaceWarApp: App {
}

/// Top-level debug logging
let logger = Logger(label: "SpaceWar")
func OutputDebugString(_ msg: String) {
SteamAPI.logger.debug(.init(stringLiteral: msg))
logger.debug(.init(stringLiteral: msg))
}

/// CEG -- don't think this exists on macOS, we don't have it at any rate
Expand All @@ -137,20 +139,24 @@ import Logging
/// A `LogHandler` which logs to stdout and a file -- big hack yikes need to find a proper logger
struct SWLogHandler: LogHandler {

static func setup() {
static func setup(level: Logger.Level = .info) {
unlink(Self.LOGFILE)
defaultLevel = level
}

private nonisolated(unsafe) static var defaultLevel: Logger.Level = .info

static let LOGFILE = "/Users/johnf/project/swift-spacewar/latest-log"

/// Create a `SyslogLogHandler`.
public init(label: String) {
self.label = label
self.logLevel = SWLogHandler.defaultLevel
}

public let label: String

public var logLevel: Logger.Level = .info
public var logLevel: Logger.Level

public func log(level: Logger.Level,
message: Logger.Message,
Expand Down
2 changes: 2 additions & 0 deletions Sources/SpaceWar/BaseMenu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import MetalEngine

/// Shared things and constants
@MainActor
private enum Menu {
static var font: Font2D!

Expand All @@ -18,6 +19,7 @@ private enum Menu {
}

/// General menu class that can draw itself, scroll, and report selection to a callback
@MainActor
class BaseMenu<ItemData: Equatable & MenuItemNamed> {
private let engine: Engine2D
private let controller: Controller
Expand Down
2 changes: 1 addition & 1 deletion Sources/SpaceWar/Controller.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import struct MetalEngine.Color2D

// The platform-independent part of 'engine' to do with wrangling SteamInput

final class Controller {
final class Controller: @unchecked Sendable {
let steam: SteamAPI

// MARK: Button bindings
Expand Down
4 changes: 4 additions & 0 deletions Sources/SpaceWar/FakeNet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ final class FakeMsgEndpoint: CustomStringConvertible {
}
}

@MainActor
class FakeNet {
@MainActor
private static var endpoints: [SteamID : FakeMsgEndpoint] = [:]

static var enableReporting = 0
Expand Down Expand Up @@ -171,6 +173,7 @@ extension SteamNetworkingMessage : SteamMsgProtocol {
/// Versions of send/receive that are `FAKE_NET` aware
extension SteamNetworkingSockets {
/// `FAKE_NET_USE`-aware send-msg function
@MainActor
func sendMessageToConnection(conn: HSteamNetConnection?, from: SteamID, to: SteamID, data: UnsafeRawPointer, dataSize: Int, sendFlags: SteamNetworkingSendFlags) -> (rc: Result, messageNumber: Int) {
if FAKE_NET_USE {
FakeNet.send(from: from, to: to, data: data, size: dataSize)
Expand All @@ -184,6 +187,7 @@ extension SteamNetworkingSockets {
}

/// `FAKE_NET_USE`-aware recv-msgs function
@MainActor
func receiveMessagesOnConnection(conn: HSteamNetConnection?, steamID: SteamID, maxMessages: Int) -> (rc: Int, messages: [SteamMsgProtocol]) {
if FAKE_NET_USE {
var msgs = [FakeClientMsg]()
Expand Down
1 change: 1 addition & 0 deletions Sources/SpaceWar/Inventory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ final class SpaceWarLocalInventory {

/// This gets accessed from all over the place so we mimic the global getter
extension SpaceWarLocalInventory {
@MainActor
static var instance: SpaceWarLocalInventory {
SpaceWarApp.instance!.inventory
}
Expand Down
1 change: 1 addition & 0 deletions Sources/SpaceWar/Lobby.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import MetalEngine
/// 1) Create Lobby -> start server locally and join it
/// 2) Browse for existing lobby -> join it -> join server remotely
///
@MainActor
class Lobbies {
private let steam: SteamAPI
private let engine: Engine2D
Expand Down
1 change: 1 addition & 0 deletions Sources/SpaceWar/Misc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ struct Debounced {
/// Record time of state change
/// Provide call to execute code first time made in new state
/// Provide setter to nop if already there and execute code if not
@MainActor
final class MonitoredState<ActualState: Equatable> {
let tickSource: TickSource
let name: String
Expand Down
7 changes: 5 additions & 2 deletions Sources/SpaceWar/SpaceWarClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Foundation
///
/// SpaceWarMain is in charge of this, initializes it and passes it the baton of
/// running a game, with either a local server or connecting to one.
@MainActor
final class SpaceWarClient {
private let steam: SteamAPI
private let engine: Engine2D
Expand Down Expand Up @@ -102,8 +103,10 @@ final class SpaceWarClient {
}

deinit {
clientConnection.disconnect(reason: "Client object deletion")
disconnect()
MainActor.assumeIsolated { // sure...
clientConnection.disconnect(reason: "Client object deletion")
disconnect()
}
}

// MARK: Kick-off entrypoints
Expand Down
7 changes: 5 additions & 2 deletions Sources/SpaceWar/SpaceWarClientConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import MetalEngine
/// notice, its watchdog at the top of `runFrame()` will trigger.
///
/// Factored out of SpaceWarClient to save my sanity.
@MainActor
final class SpaceWarClientConnection {
let steam: SteamAPI
let tickSource: TickSource
Expand Down Expand Up @@ -422,7 +423,7 @@ final class SpaceWarClientConnection {
// MARK: ServerPing

/// Helper to ping/query a server from an IP address
private final class ServerPing: SteamMatchmakingPingResponse {
private final class ServerPing: SteamMatchmakingPingResponse, @unchecked Sendable {
private let steam: SteamAPI
private weak var connection: SpaceWarClientConnection?
private var serverQuery: HServerQuery?
Expand All @@ -441,7 +442,9 @@ private final class ServerPing: SteamMatchmakingPingResponse {
func serverResponded(server: GameServerItem) {
if let connection {
OutputDebugString("ClientConnection ping response, connecting to Steam ID")
connection.connect(steamID: server.steamID)
MainActor.assumeIsolated {
connection.connect(steamID: server.steamID)
}
}
}

Expand Down
1 change: 1 addition & 0 deletions Sources/SpaceWar/SpaceWarClientLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Steamworks
import MetalEngine

/// Routines from spacewarclient to do with drawing graphics on screen
@MainActor
final class SpaceWarClientLayout {
let steam: SteamAPI
let controller: Controller
Expand Down
29 changes: 3 additions & 26 deletions Sources/SpaceWar/SpaceWarEntity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import simd

/// A `SpaceWarEntity` is just like a `VectorEntity`, except it knows how
/// to apply gravity from the SpaceWar Sun
@MainActor
class SpaceWarEntity: VectorEntity {
private let affectedByGravity: Bool

Expand All @@ -16,22 +17,18 @@ class SpaceWarEntity: VectorEntity {
super.init(engine: engine, collisionRadius: collisionRadius, maximumVelocity: maximumVelocity)
}

static let MIN_GRAVITY = Float(15) // pixels per second per second
static nonisolated let MIN_GRAVITY = Float(15) // pixels per second per second

override func runFrame() {
if affectedByGravity {
// The suns gravity, compute that here, sun is always at the center of the screen [JF: !!!]
let posSun = engine.viewportSize / 2

#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 = my_normalize(pos - posSun) // XXX CxxInterop simd_normalize(pos - posSun)
let direction = simd_normalize(pos - posSun)

// Set updated acceleration
acceleration -= factor * direction
Expand All @@ -40,23 +37,3 @@ 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<Float>, _ b: SIMD2<Float>) -> 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<Float>, _ b: SIMD2<Float>) -> Float {
sqrt(my_distance_squared(a, b))
}

func my_length(_ v: SIMD2<Float>) -> Float {
sqrt(pow(v.x, 2) + pow(v.y, 2))
}

private func my_normalize(_ v: SIMD2<Float>) -> SIMD2<Float> {
let len = my_length(v)
return [v.x / len, v.y / len]
}
15 changes: 13 additions & 2 deletions Sources/SpaceWar/SpaceWarMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Foundation
/// Though I have modularized slightly rather than having one massive state enum.
///
/// No PS3 accommodations.
@MainActor
final class SpaceWarMain {
private let engine: Engine2D
private let steam: SteamAPI
Expand Down Expand Up @@ -47,6 +48,7 @@ final class SpaceWarMain {
private(set) var gameState: MonitoredState<State>
private var cancelInput: Debounced
private var infrequent: Debounced
private var networkRcvTask: Task<Void, Never>?

init(engine: Engine2D, steam: SteamAPI, controller: Controller) {
self.engine = engine
Expand Down Expand Up @@ -105,14 +107,23 @@ final class SpaceWarMain {
steam.networkingUtils.initRelayNetworkAccess()
}

Timer.scheduledTimer(withTimeInterval: 0.005, repeats: true) { [weak self] _ in
self?.receiveNetworkData()
networkRcvTask = Task { [weak self] in
MainActor.assertIsolated() // does isolation inheritance work?
while !Task.isCancelled {
try? await Task.sleep(for: .milliseconds(5))
self?.receiveNetworkData()
}
OutputDebugString("NetworkRcvTask exitting")
}

initSteamNotifications()
initCommandLine()
}

deinit {
networkRcvTask?.cancel()
}

// MARK: General Steam Infrastructure Interlocks

/// Connect to general Steam notifications, roughly all lifecycle-related
Expand Down
Loading

0 comments on commit eecb601

Please sign in to comment.