Closed rrbox closed 8 months ago
open class SystemExecute {
public func execute(_ bufferRef: BufferRef) {
}
}
final public class SystemStorage {
final class SystemRegistry: WorldStorageElement {
var systems: [Schedule: [SystemExecute]] = [:]
}
func setUpSystemRegistry() {
self.buffer.map.push(SystemRegistry())
}
func registerSystemRegistry(schedule: Schedule) {
self.buffer.map.valueRef(ofType: SystemRegistry.self)!.body.systems[schedule] = []
}
public func systems(_ schedule: Schedule) -> [SystemExecute] {
self.buffer.map.valueRef(ofType: SystemRegistry.self)!.body.systems[schedule]!
}
func addSystem(_ schedule: Schedule, _ system: SystemExecute) {
self.buffer.map.valueRef(ofType: SystemRegistry.self)!.body.systems[schedule]!.append(system)
}
}
public extension WorldStorageRef {
var systemStorage: SystemStorage {
SystemStorage(buffer: self)
}
}
class System<P: SystemParameter>: SystemExecute {
let execute: (P) -> ()
init(_ execute: @escaping (P) -> ()) {
self.execute = execute
}
func execute(_ worldStorageRef: WorldStorageRef) {
self.execute(P.getParameter(from: worldStorageRef))
}
}
public extension World {
func addSystem<P: SystemParameter>(_ schedule: Schedule, _ system: @escaping (P) -> ()) {
self.worldStorage.systemStorage.addSystem(schedule, System<P>(system))
P.register(to: self.worldStorageRef)
}
}
class System2<P0: SystemParameter, P1: SystemParameter>: SystemExecute {
let execute: (P0, P1) -> ()
init(_ execute: @escaping (P0, P1) -> ()) {
self.execute = execute
}
func execute(_ worldStorageRef: WorldStorageRef) {
self.execute(P0.getParameter(from: worldStorageRef), P1.getParameter(from: worldStorageRef))
}
}
public extension World {
func addSystem<P0: SystemParameter, P1: SystemParameter>(_ schedule: Schedule, _ system: @escaping (P0, P1) -> ()) {
self.worldStorage.systemStorage.addSystem(schedule, System2<P0, P1>(system))
P0.register(to: self.worldStorageRef)
P1.register(to: self.worldStorageRef)
}
}
class System3<P0: SystemParameter, P1: SystemParameter, P2: SystemParameter>: SystemExecute {
let execute: (P0, P1, P2) -> ()
init(_ execute: @escaping (P0, P1, P2) -> ()) {
self.execute = execute
}
override func execute(worlfBuffer buffer: WorldBuffer) {
self.execute(P0.getParameter(from: buffer)!,
P1.getParameter(from: buffer)!,
P2.getParameter(from: buffer)!)
}
}
public extension World {
@discardableResult func addSystem<P0: SystemParameter, P1: SystemParameter, P2: SystemParameter>(
_ schedule: Schedule,
_ system: @escaping (P0, P1, P2) -> ()
) -> World {
self.worldStorage.systemStorage.addSystem(schedule, System3(system))
P0.register(to: buffer)
P1.register(to: buffer)
P2.register(to: buffer)
return self
}
}
class System4<P0: SystemParameter, P1: SystemParameter, P2: SystemParameter, P3: SystemParameter>: SystemExecute {
let execute: (P0, P1, P2, P3) -> ()
init(_ execute: @escaping (P0, P1, P2, P3) -> ()) {
self.execute = execute
}
override func execute(worlfBuffer buffer: WorldBuffer) {
self.execute(P0.getParameter(from: buffer)!,
P1.getParameter(from: buffer)!,
P2.getParameter(from: buffer)!,
P3.getParameter(from: buffer)!)
}
}
public extension World {
@discardableResult func addSystem<P0: SystemParameter, P1: SystemParameter, P2: SystemParameter, P3: SystemParameter>(
_ schedule: Schedule,
_ system: @escaping (P0, P1, P2, P3) -> ()
) -> World {
self.worldStorage.systemStorage.addSystem(schedule, System4(system))
P0.register(to: buffer)
P1.register(to: buffer)
P2.register(to: buffer)
P3.register(to: buffer)
return self
}
}
class System5<P0: SystemParameter, P1: SystemParameter, P2: SystemParameter, P3: SystemParameter, P4: SystemParameter>: SystemExecute {
let execute: (P0, P1, P2, P3, P4) -> ()
init(_ execute: @escaping (P0, P1, P2, P3, P4) -> ()) {
self.execute = execute
}
override func execute(worlfBuffer buffer: WorldBuffer) {
self.execute(P0.getParameter(from: buffer)!,
P1.getParameter(from: buffer)!,
P2.getParameter(from: buffer)!,
P3.getParameter(from: buffer)!,
P4.getParameter(from: buffer)!)
}
}
public extension World {
@discardableResult func addSystem<P0: SystemParameter, P1: SystemParameter, P2: SystemParameter, P3: SystemParameter, P4: SystemParameter>(
_ schedule: Schedule,
_ system: @escaping (P0, P1, P2, P3, P4) -> ()
) -> World {
self.worldStorage.systemStorage.addSystem(schedule, System5(system))
P0.register(to: buffer)
P1.register(to: buffer)
P2.register(to: buffer)
P3.register(to: buffer)
P4.register(to: buffer)
return self
}
}
上記の実装では、System 型が全て internal なので、ジェネリックなシステムを定義することが難しいです。
ジェネリックなシステムの例
struct Contaner<Value>: Component {
let value: Value
}
func genericSystem<Value>(query: Query<Container<Value>>) {
query.update { _, container in
print(container.value)
}
}
// 関数として定義はできるが、World に追加する方法がない。
let world = World()
.addSystem(.update, genericSystem(query:)) // コンパイルエラー!! 型パラメータが推論できない…
.addSystem(.update, genericSystem<String>(query:)) // コンパイルエラー!!Swift ではこの記述ができない…
これはクロージャにジェネリクスを適用できないこと、Swift では関数に型パラメータを記述できないこと (必ず引数を利用して明示する必要がある) ことが主な原因です。
現在の Swift の仕様(Swift 5.9)では ecs-swift 側からこの問題を解決する方法が考えられません。そこで、以下のようにしてジェネリックなシステムを定義してもらうように Wikis などで促すことにしましょう。
enum GenericSystem<Value> {
static func system(query: Query<Container<Value>>) {
query.update { _, container in
print(container.value)
}
}
}
現状、最も短いコードで system をジェネリックにすることができる方法だと思います。
// 追加も簡単寄り。
let world = World()
.addSystem(.update, GenericSystem<String>.system(query:)) // OK!
新しい System の実装です。
18 Schedule の登場により、これまでの Set up systems, Update systems, Event systems が 1 つに統合され、
Systems
というモジュールで実装されます。