@@ -201,7 +201,12 @@ open class Wrapped: Equatable, Identifiable, Hashable {
201201 /// For example `Node.notificationProcess`
202202 open func _notification( code: Int , reversed: Bool ) {
203203 }
204-
204+
205+ /// Called whenever Godot retrieves value of property. Allows to customize existing properties.
206+ /// Return true if you made changes to the PropInfo value you got
207+ open func _validateProperty( _ property: inout PropInfo ) -> Bool {
208+ return false
209+ }
205210
206211 /// Checks if this object has a script with the given method.
207212 /// - Parameter method: StringName identifying the method.
@@ -352,6 +357,7 @@ func register<T:Wrapped> (type name: StringName, parent: StringName, type: T.Typ
352357 info. get_virtual_func = getVirtual
353358 info. notification_func = notificationFunc
354359 info. recreate_instance_func = recreateFunc
360+ info. validate_property_func = validatePropertyFunc
355361 info. is_exposed = 1
356362 userTypes [ name. description] = { ptr in
357363 return type. init ( nativeHandle: ptr)
@@ -547,6 +553,38 @@ func notificationFunc (ptr: UnsafeMutableRawPointer?, code: Int32, reversed: UIn
547553 original. _notification ( code: Int ( code) , reversed: reversed != 0 )
548554}
549555
556+ func validatePropertyFunc( ptr: UnsafeMutableRawPointer ? , _info: UnsafeMutablePointer < GDExtensionPropertyInfo > ? ) -> UInt8 {
557+ guard let ptr else { return 0 }
558+ let original = Unmanaged < Wrapped > . fromOpaque ( ptr) . takeUnretainedValue ( )
559+ guard var info = _info? . pointee else { return 0 }
560+ guard let namePtr = info. name,
561+ let classNamePtr = info. class_name,
562+ let infoHintPtr = info. hint_string else {
563+ return 0
564+ }
565+ guard let ptype = Variant . GType ( rawValue: Int64 ( info. type. rawValue) ) else { return 0 }
566+ let pname = StringName ( fromPtr: namePtr)
567+ let className = StringName ( fromPtr: classNamePtr)
568+ let hint = PropertyHint ( rawValue: Int64 ( info. hint) ) ?? . none
569+ let hintStr = GString ( content: infoHintPtr. load ( as: Int64 . self) )
570+ let usage = PropertyUsageFlags ( rawValue: Int ( info. usage) )
571+
572+ var pinfo = PropInfo ( propertyType: ptype, propertyName: pname, className: className, hint: hint, hintStr: hintStr, usage: usage)
573+ if original. _validateProperty ( & pinfo) {
574+ // The problem with the code below is that it does not make a copy of the StringName and String,
575+ // and passes a reference that we will destroy right away when `pinfo` goes out of scope.
576+ //
577+ // For now, we just update the usage, type and hint but we need to find a solution for those other fields
578+ let native = pinfo. makeNativeStruct ( )
579+ _info? . pointee. usage = UInt32 ( pinfo. usage. rawValue)
580+ _info? . pointee. hint = UInt32 ( pinfo. hint. rawValue)
581+ _info? . pointee. type = GDExtensionVariantType ( GDExtensionVariantType . RawValue ( pinfo. propertyType. rawValue) )
582+
583+ return 1
584+ }
585+ return 0
586+ }
587+
550588func userTypeBindingCreate ( _ token: UnsafeMutableRawPointer ? , _ instance: UnsafeMutableRawPointer ? ) -> UnsafeMutableRawPointer ? {
551589 // Godot-cpp does nothing for user types
552590 //print ("SWIFT: instanceBindingCreate")
0 commit comments