Jelajahi Sumber

[iOS] update Swift inteface for more fine grained control(like external atlas loading) (#2772)

* update Swift inteface for more fine grained control

- move instance method to static method which does not require spine cpp pointer
- implement equality and hashing based on cpp pointer so that it can be stored in collection and compare it
- expose Atlas image count property so that the user can load the atlas resource lazily

- User can now Create Atlas by using Altas static function, and fetch whole resource path by iterating count of atlas page count

* [iOS] fix wrong y-axis alignment
Byeong Gwan 3 bulan lalu
induk
melakukan
6e5da45fa3

+ 34 - 0
spine-cpp/spine-cpp-lite/spine-cpp-lite-codegen.py

@@ -439,6 +439,7 @@ class SwiftFunctionWriter:
       if spine_params and spine_params[0].type == self.spine_object.name:
         spine_params_without_ivar = spine_params[1:] 
       else:
+        function_string = function_string.replace("public func ", "public static func ")
         spine_params_without_ivar = spine_params
 
       swift_params = [
@@ -501,6 +502,39 @@ class SwiftObjectWriter:
         object_string += "\n"
         object_string += "\n"
         
+        object_string += inset
+        object_string += "public override func isEqual(_ object: Any?) -> Bool"
+        object_string += " {"
+        object_string += "\n"
+        object_string += inset + inset
+        object_string += f"guard let other = object as? {class_name} else {{ return false }}"
+        object_string += "\n"
+        object_string += inset + inset
+        object_string += f"return self.{ivar_name} == other.{ivar_name}"
+        object_string += "\n"
+        object_string += inset
+        object_string += "}"
+        object_string += "\n"
+        object_string += "\n"
+        
+        object_string += inset
+        object_string += "public override var hash: Int"
+        object_string += " {"
+        object_string += "\n"
+        object_string += inset + inset
+        object_string += "var hasher = Hasher()"
+        object_string += "\n"
+        object_string += inset + inset
+        object_string += f"hasher.combine(self.{ivar_name})"
+        object_string += "\n"
+        object_string += inset + inset
+        object_string += "return hasher.finalize()"
+        object_string += "\n"
+        object_string += inset
+        object_string += "}"
+        object_string += "\n"
+        object_string += "\n"
+        
         filtered_spine_functions = [spine_function for spine_function in self.spine_object.functions if not "_get_num_" in spine_function.name]
 
         spine_functions_by_name = {}

+ 1 - 1
spine-ios/Sources/Spine/BoundsProvider.swift

@@ -151,7 +151,7 @@ public enum Alignment: Int {
         switch self {
         case .topLeft, .topCenter, .topRight: return -1.0
         case .centerLeft, .center, .centerRight: return 0.0
-        case .bottomLeft, .bottomCenter, .bottomRight: return -1.0
+        case .bottomLeft, .bottomCenter, .bottomRight: return 1.0
         }
     }
 }

+ 8 - 0
spine-ios/Sources/Spine/Spine.Generated+Extensions.swift

@@ -365,3 +365,11 @@ public extension SkeletonBounds {
         return SkeletonBounds(spine_skeleton_bounds_create())
     }
 }
+
+@objc public extension Atlas {
+    
+    var imagePathCount:Int32 {
+        spine_atlas_get_num_image_paths(wrappee)
+    }
+    
+}

+ 497 - 2
spine-ios/Sources/Spine/Spine.Generated.swift

@@ -23,6 +23,17 @@ public final class TransformConstraintData: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? TransformConstraintData else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var bones: [BoneData] {
         let ptr = spine_transform_constraint_data_get_bones(wrappee)
         guard let validPtr = ptr else { return [] }
@@ -181,6 +192,17 @@ public final class BoundingBoxAttachment: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? BoundingBoxAttachment else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var color: Color {
         return .init(spine_bounding_box_attachment_get_color(wrappee))
     }
@@ -202,6 +224,17 @@ public final class PhysicsConstraintData: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? PhysicsConstraintData else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var bone: BoneData {
         get {
             return .init(spine_physics_constraint_data_get_bone(wrappee))
@@ -413,6 +446,17 @@ public final class AnimationStateEvents: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? AnimationStateEvents else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     @discardableResult
     public func getEventType(index: Int32) -> EventType {
         return spine_animation_state_events_get_event_type(wrappee, index)
@@ -445,6 +489,17 @@ public final class TransformConstraint: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? TransformConstraint else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var order: Int32 {
         return spine_transform_constraint_get_order(wrappee)
     }
@@ -552,6 +607,17 @@ public final class PathConstraintData: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? PathConstraintData else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var bones: [BoneData] {
         let ptr = spine_path_constraint_data_get_bones(wrappee)
         guard let validPtr = ptr else { return [] }
@@ -665,6 +731,17 @@ public final class AnimationStateData: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? AnimationStateData else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var skeletonData: SkeletonData {
         return .init(spine_animation_state_data_get_skeleton_data(wrappee))
     }
@@ -714,6 +791,17 @@ public final class SkeletonDataResult: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? SkeletonDataResult else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var error: String? {
         return spine_skeleton_data_result_get_error(wrappee).flatMap { String(cString: $0) }
     }
@@ -741,6 +829,17 @@ public final class ClippingAttachment: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? ClippingAttachment else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var color: Color {
         return .init(spine_clipping_attachment_get_color(wrappee))
     }
@@ -771,6 +870,17 @@ public final class IkConstraintData: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? IkConstraintData else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var bones: [BoneData] {
         let ptr = spine_ik_constraint_data_get_bones(wrappee)
         guard let validPtr = ptr else { return [] }
@@ -857,6 +967,17 @@ public final class PhysicsConstraint: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? PhysicsConstraint else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var bone: Bone {
         get {
             return .init(spine_physics_constraint_get_bone(wrappee))
@@ -1120,6 +1241,17 @@ public final class RegionAttachment: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? RegionAttachment else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var color: Color {
         return .init(spine_region_attachment_get_color(wrappee))
     }
@@ -1236,6 +1368,17 @@ public final class VertexAttachment: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? VertexAttachment else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var worldVerticesLength: Int32 {
         return spine_vertex_attachment_get_world_vertices_length(wrappee)
     }
@@ -1279,6 +1422,17 @@ public final class SkeletonDrawable: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? SkeletonDrawable else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var skeleton: Skeleton {
         return .init(spine_skeleton_drawable_get_skeleton(wrappee))
     }
@@ -1314,6 +1468,17 @@ public final class PointAttachment: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? PointAttachment else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var color: Color {
         return .init(spine_point_attachment_get_color(wrappee))
     }
@@ -1372,6 +1537,17 @@ public final class MeshAttachment: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? MeshAttachment else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var regionUvs: [Float?] {
         let ptr = spine_mesh_attachment_get_region_uvs(wrappee)
         guard let validPtr = ptr else { return [] }
@@ -1477,6 +1653,17 @@ public final class PathAttachment: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? PathAttachment else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var lengths: [Float?] {
         let ptr = spine_path_attachment_get_lengths(wrappee)
         guard let validPtr = ptr else { return [] }
@@ -1524,6 +1711,17 @@ public final class ConstraintData: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? ConstraintData else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var type: ConstraintType {
         return spine_constraint_data_get_type(wrappee)
     }
@@ -1563,6 +1761,17 @@ public final class PathConstraint: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? PathConstraint else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var order: Int32 {
         return spine_path_constraint_get_order(wrappee)
     }
@@ -1661,6 +1870,17 @@ public final class AnimationState: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? AnimationState else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var data: AnimationStateData {
         return .init(spine_animation_state_get_data(wrappee))
     }
@@ -1743,6 +1963,17 @@ public final class SkeletonBounds: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? SkeletonBounds else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var polygons: [Polygon] {
         let ptr = spine_skeleton_bounds_get_polygons(wrappee)
         guard let validPtr = ptr else { return [] }
@@ -1839,6 +2070,17 @@ public final class TextureRegion: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? TextureRegion else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var texture: UnsafeMutableRawPointer {
         get {
             return spine_texture_region_get_texture(wrappee)
@@ -1960,6 +2202,17 @@ public final class RenderCommand: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? RenderCommand else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var indices: [UInt16] {
         let ptr = spine_render_command_get_indices(wrappee)
         guard let validPtr = ptr else { return [] }
@@ -1994,6 +2247,17 @@ public final class SkeletonData: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? SkeletonData else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var name: String? {
         return spine_skeleton_data_get_name(wrappee).flatMap { String(cString: $0) }
     }
@@ -2217,6 +2481,17 @@ public final class IkConstraint: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? IkConstraint else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var order: Int32 {
         return spine_ik_constraint_get_order(wrappee)
     }
@@ -2316,6 +2591,17 @@ public final class SkinEntries: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? SkinEntries else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     @discardableResult
     public func getEntry(index: Int32) -> SkinEntry {
         return .init(spine_skin_entries_get_entry(wrappee, index))
@@ -2340,6 +2626,17 @@ public final class TrackEntry: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? TrackEntry else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var trackIndex: Int32 {
         return spine_track_entry_get_track_index(wrappee)
     }
@@ -2574,6 +2871,17 @@ public final class Attachment: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Attachment else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var name: String? {
         return spine_attachment_get_name(wrappee).flatMap { String(cString: $0) }
     }
@@ -2606,6 +2914,17 @@ public final class Constraint: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Constraint else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
 }
 
 @objc(SpineEventData)
@@ -2619,6 +2938,17 @@ public final class EventData: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? EventData else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var name: String? {
         return spine_event_data_get_name(wrappee).flatMap { String(cString: $0) }
     }
@@ -2685,6 +3015,17 @@ public final class SkinEntry: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? SkinEntry else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var slotIndex: Int32 {
         return spine_skin_entry_get_slot_index(wrappee)
     }
@@ -2710,6 +3051,17 @@ public final class BoneData: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? BoneData else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var index: Int32 {
         return spine_bone_data_get_index(wrappee)
     }
@@ -2842,6 +3194,17 @@ public final class SlotData: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? SlotData else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var index: Int32 {
         return spine_slot_data_get_index(wrappee)
     }
@@ -2919,6 +3282,17 @@ public final class Animation: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Animation else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var name: String? {
         return spine_animation_get_name(wrappee).flatMap { String(cString: $0) }
     }
@@ -2940,6 +3314,17 @@ public final class Skeleton: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Skeleton else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var bounds: Bounds {
         return .init(spine_skeleton_get_bounds(wrappee))
     }
@@ -3181,6 +3566,17 @@ public final class Sequence: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Sequence else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var regions: [TextureRegion] {
         let ptr = spine_sequence_get_regions(wrappee)
         guard let validPtr = ptr else { return [] }
@@ -3249,6 +3645,17 @@ public final class Polygon: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Polygon else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var vertices: [Float?] {
         let ptr = spine_polygon_get_vertices(wrappee)
         guard let validPtr = ptr else { return [] }
@@ -3270,6 +3677,17 @@ public final class Bounds: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Bounds else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var x: Float {
         return spine_bounds_get_x(wrappee)
     }
@@ -3299,6 +3717,17 @@ public final class Vector: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Vector else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var x: Float {
         return spine_vector_get_x(wrappee)
     }
@@ -3320,6 +3749,17 @@ public final class Event: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Event else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var data: EventData {
         return .init(spine_event_get_data(wrappee))
     }
@@ -3387,6 +3827,17 @@ public final class Atlas: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Atlas else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var isPma: Bool {
         return spine_atlas_is_pma(wrappee) != 0
     }
@@ -3396,7 +3847,7 @@ public final class Atlas: NSObject {
     }
 
     @discardableResult
-    public func load(atlasData: String?) -> Atlas {
+    public static func load(atlasData: String?) -> Atlas {
         return .init(spine_atlas_load(atlasData))
     }
 
@@ -3424,6 +3875,17 @@ public final class Color: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Color else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var r: Float {
         return spine_color_get_r(wrappee)
     }
@@ -3453,7 +3915,18 @@ public final class Bone: NSObject {
         super.init()
     }
 
-    public func setIsYDown(yDown: Bool) {
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Bone else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
+    public static func setIsYDown(yDown: Bool) {
         spine_bone_set_is_y_down(yDown ? -1 : 0)
     }
 
@@ -3772,6 +4245,17 @@ public final class Slot: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Slot else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var data: SlotData {
         return .init(spine_slot_get_data(wrappee))
     }
@@ -3841,6 +4325,17 @@ public final class Skin: NSObject {
         super.init()
     }
 
+    public override func isEqual(_ object: Any?) -> Bool {
+        guard let other = object as? Skin else { return false }
+        return self.wrappee == other.wrappee
+    }
+
+    public override var hash: Int {
+        var hasher = Hasher()
+        hasher.combine(self.wrappee)
+        return hasher.finalize()
+    }
+
     public var name: String? {
         return spine_skin_get_name(wrappee).flatMap { String(cString: $0) }
     }