fireblade-ecs/Sources/FirebladeECS/Nexus+Serialization.swift

128 lines
4.4 KiB
Swift

//
// Nexus+Serialization.swift
//
//
// Created by Christian Treffs on 26.06.20.
//
#if canImport(Foundation)
import struct Foundation.Data
extension Nexus {
final func serialize() throws -> SNexus {
var componentInstances: [ComponentIdentifier.StableId: SComponent<SNexus>] = [:]
var entityComponentsMap: [EntityIdentifier: Set<ComponentIdentifier.StableId>] = [:]
for entitId in componentIdsByEntity.keys {
entityComponentsMap[entitId] = []
let componentIds = self.get(components: entitId) ?? []
for componentId in componentIds {
let component = self.get(unsafe: componentId, for: entitId)
let componentStableInstanceHash = ComponentIdentifier.makeStableInstanceHash(component: component, entityId: entitId)
componentInstances[componentStableInstanceHash] = SComponent.component(component)
entityComponentsMap[entitId]?.insert(componentStableInstanceHash)
}
}
return SNexus(version: version,
entities: entityComponentsMap,
components: componentInstances)
}
final func deserialize(from sNexus: SNexus, into nexus: Nexus) throws {
for freeId in sNexus.entities.map(\.key).reversed() {
nexus.entityIdGenerator.markUnused(entityId: freeId)
}
for componentSet in sNexus.entities.values {
let entity = createEntity()
for sCompId in componentSet {
guard let sComp = sNexus.components[sCompId] else {
throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: [], debugDescription: "Could not find component instance for \(sCompId)."))
}
switch sComp {
case let .component(comp):
entity.assign(comp)
}
}
}
}
}
extension EntityIdentifier: Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(id)
}
}
extension EntityIdentifier: Decodable {
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let id = try container.decode(UInt32.self)
self.init(id)
}
}
struct SNexus {
let version: Version
let entities: [EntityIdentifier: Set<ComponentIdentifier.StableId>]
let components: [ComponentIdentifier.StableId: SComponent<SNexus>]
}
extension SNexus: Encodable {}
extension SNexus: Decodable {}
protocol ComponentEncoding {
static func encode(component: Component, to encoder: Encoder) throws
}
protocol ComponentDecoding {
static func decode(from decoder: Decoder) throws -> Component
}
typealias ComponentCodable = ComponentDecoding & ComponentEncoding
extension SNexus: ComponentEncoding {
static func encode(component: Component, to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
let bytes = withUnsafeBytes(of: component) {
Data(bytes: $0.baseAddress!, count: MemoryLayout.stride(ofValue: component))
}
try container.encode(bytes)
}
}
extension SNexus: ComponentDecoding {
static func decode(from decoder: Decoder) throws -> Component {
let container = try decoder.singleValueContainer()
let instanceData = try container.decode(Data.self)
return instanceData.withUnsafeBytes {
$0.baseAddress!.load(as: Component.self)
}
}
}
enum SComponent<CodingStrategy: ComponentCodable> {
case component(Component)
}
extension SComponent: Encodable {
public func encode(to encoder: Encoder) throws {
switch self {
case let .component(comp):
try CodingStrategy.encode(component: comp, to: encoder)
}
}
}
extension SComponent: Decodable {
public init(from decoder: Decoder) throws {
self = try .component(CodingStrategy.decode(from: decoder))
}
}
#endif