kitgit

tirbofish/dropbear · diff

0911f33 · Thribhu K

fix: fix up native since i remove collidercollisionsarray.

Unverified

diff --git a/crates/goanna-gen/src/lib.rs b/crates/goanna-gen/src/lib.rs
index 0fff27c..fe594e6 100644
--- a/crates/goanna-gen/src/lib.rs
+++ b/crates/goanna-gen/src/lib.rs
@@ -14,10 +14,28 @@ pub fn generate_c_header() -> anyhow::Result<()> {
     let mut functions = Vec::new();
     let mut structs = std::collections::HashMap::new();
     let mut enums = Vec::new();
+
+    seed_well_known_extern_types(&mut structs);
+
+    // Scan sibling crates for additional type definitions (not function exports)
+    let crates_dir = workspace_root.join("crates");
+    if let Ok(entries) = std::fs::read_dir(&crates_dir) {
+        let mut sorted: Vec<_> = entries.filter_map(Result::ok).collect();
+        sorted.sort_by_key(|e| e.path());
+        for entry in sorted {
+            let crate_src = entry.path().join("src");
+            // Only scan other crates, not the current one
+            if crate_src.exists() && crate_src != src_dir {
+                let _ = collect_type_definitions_only(&crate_src, &mut structs, &mut enums);
+            }
+        }
+    }
+
     collect_exported_functions(&src_dir, &mut functions, &mut structs, &mut enums)?;
 
     functions.sort_by(|a, b| a.name.cmp(&b.name));
     enums.sort_by(|a, b| a.name.cmp(&b.name));
+    enums.dedup_by(|a, b| a.name == b.name);
 
     let header = render_header(&functions, &structs, &enums);
     if let Ok(existing) = std::fs::read_to_string(&output_path) {
@@ -31,6 +49,66 @@ pub fn generate_c_header() -> anyhow::Result<()> {
     Ok(())
 }
 
+fn seed_well_known_extern_types(structs: &mut std::collections::HashMap<String, StructDef>) {
+    // glam::Vec3 - #[repr(C)] with f32 x/y/z fields
+    structs.entry("Vec3".to_string()).or_insert(StructDef {
+        name: "Vec3".to_string(),
+        fields: vec![
+            ExportParam { name: "x".to_string(), ty: "float".to_string() },
+            ExportParam { name: "y".to_string(), ty: "float".to_string() },
+            ExportParam { name: "z".to_string(), ty: "float".to_string() },
+        ],
+        is_repr_c: true,
+    });
+    // glam::Vec4 - #[repr(C)] with f32 x/y/z/w fields
+    structs.entry("Vec4".to_string()).or_insert(StructDef {
+        name: "Vec4".to_string(),
+        fields: vec![
+            ExportParam { name: "x".to_string(), ty: "float".to_string() },
+            ExportParam { name: "y".to_string(), ty: "float".to_string() },
+            ExportParam { name: "z".to_string(), ty: "float".to_string() },
+            ExportParam { name: "w".to_string(), ty: "float".to_string() },
+        ],
+        is_repr_c: true,
+    });
+    // glam::Vec2 - #[repr(C)] with f32 x/y fields
+    structs.entry("Vec2".to_string()).or_insert(StructDef {
+        name: "Vec2".to_string(),
+        fields: vec![
+            ExportParam { name: "x".to_string(), ty: "float".to_string() },
+            ExportParam { name: "y".to_string(), ty: "float".to_string() },
+        ],
+        is_repr_c: true,
+    });
+}
+
+fn collect_type_definitions_only(
+    dir: &std::path::Path,
+    structs: &mut std::collections::HashMap<String, StructDef>,
+    enums: &mut Vec<EnumDef>,
+) -> anyhow::Result<()> {
+    if dir.is_dir() {
+        let mut entries = std::fs::read_dir(dir)?
+            .filter_map(Result::ok)
+            .collect::<Vec<_>>();
+        entries.sort_by_key(|entry| entry.path());
+
+        for entry in entries {
+            let path = entry.path();
+            if path.is_dir() {
+                collect_type_definitions_only(&path, structs, enums)?;
+            } else if path.extension().and_then(|s| s.to_str()) == Some("rs") {
+                let content = std::fs::read_to_string(&path)?;
+                if let Ok(file) = syn::parse_file(&content) {
+                    extract_structs_from_file(&file, structs)?;
+                    extract_repr_c_enums_from_file(&file, enums)?;
+                }
+            }
+        }
+    }
+    Ok(())
+}
+
 #[derive(Debug)]
 struct ExportedFunction {
     name: String,
@@ -80,66 +158,89 @@ fn extract_exports_from_file(
     _structs: &mut std::collections::HashMap<String, StructDef>,
 ) -> anyhow::Result<()> {
     let module_path = module_path_from_file(file_path, src_root);
-    for item in &file.items {
-        if let syn::Item::Fn(func) = item {
-            if let Some(export) = parse_export_attr(&func.attrs)? {
-                if export.c.is_none() {
-                    continue;
-                }
+    extract_exports_from_items(&file.items, module_path.as_deref(), out)?;
+    Ok(())
+}
 
-                let c_name = export.c.and_then(|c| c.name).unwrap_or_else(|| {
-                    if let Some(path) = module_path.as_deref() {
-                        if !path.is_empty() {
-                            return format!("dropbear_{}_{}", path, func.sig.ident);
-                        }
+fn extract_exports_from_items(
+    items: &[syn::Item],
+    module_path: Option<&str>,
+    out: &mut Vec<ExportedFunction>,
+) -> anyhow::Result<()> {
+    for item in items {
+        match item {
+            syn::Item::Fn(func) => {
+                if let Some(export) = parse_export_attr(&func.attrs)? {
+                    if export.c.is_none() {
+                        continue;
                     }
-                    format!("dropbear_{}", func.sig.ident)
-                });
 
-                let (out_type, out_is_optional) = extract_result_type(&func.sig.output)?;
-                let mut params = Vec::new();
-                for input in &func.sig.inputs {
-                    if let syn::FnArg::Typed(pat_ty) = input {
-                        let (define_ty, is_entity) = extract_arg_markers(&pat_ty.attrs);
-                        let name = match &*pat_ty.pat {
-                            syn::Pat::Ident(ident) => ident.ident.to_string(),
-                            _ => continue,
-                        };
-
-                        let ty = if is_entity {
-                            "uint64_t".to_string()
-                        } else if let Some(define_ty) = define_ty {
-                            type_to_c(&define_ty, true)
-                        } else if is_object_input(&pat_ty.ty) {
-                            object_input_to_c(&pat_ty.ty)
-                        } else {
-                            type_to_c(&pat_ty.ty, false)
-                        };
-
-                        params.push(ExportParam { name, ty });
+                    let c_name = export.c.and_then(|c| c.name).unwrap_or_else(|| {
+                        if let Some(path) = module_path {
+                            if !path.is_empty() {
+                                return format!("dropbear_{}_{}", path, func.sig.ident);
+                            }
+                        }
+                        format!("dropbear_{}", func.sig.ident)
+                    });
+
+                    let (out_type, out_is_optional) = extract_result_type(&func.sig.output)?;
+                    let mut params = Vec::new();
+                    for input in &func.sig.inputs {
+                        if let syn::FnArg::Typed(pat_ty) = input {
+                            let (define_ty, is_entity) = extract_arg_markers(&pat_ty.attrs);
+                            let name = match &*pat_ty.pat {
+                                syn::Pat::Ident(ident) => ident.ident.to_string(),
+                                _ => continue,
+                            };
+
+                            let ty = if is_entity {
+                                "uint64_t".to_string()
+                            } else if let Some(define_ty) = define_ty {
+                                type_to_c(&define_ty, true)
+                            } else if is_object_input(&pat_ty.ty) {
+                                object_input_to_c(&pat_ty.ty)
+                            } else {
+                                type_to_c(&pat_ty.ty, false)
+                            };
+
+                            params.push(ExportParam { name, ty });
+                        }
                     }
-                }
 
-                if out_type.is_some() {
-                    let out_ty = out_type.clone().unwrap();
-                    params.push(ExportParam {
-                        name: "out0".to_string(),
-                        ty: format!("{}*", out_ty),
-                    });
-                    if out_is_optional {
+                    if out_type.is_some() {
+                        let out_ty = out_type.clone().unwrap();
                         params.push(ExportParam {
-                            name: "out0_present".to_string(),
-                            ty: "bool*".to_string(),
+                            name: "out0".to_string(),
+                            ty: format!("{}*", out_ty),
                         });
+                        if out_is_optional {
+                            params.push(ExportParam {
+                                name: "out0_present".to_string(),
+                                ty: "bool*".to_string(),
+                            });
+                        }
                     }
-                }
 
-                out.push(ExportedFunction {
-                    name: c_name,
-                    params,
-                    out_type,
-                });
+                    out.push(ExportedFunction {
+                        name: c_name,
+                        params,
+                        out_type,
+                    });
+                }
             }
+            syn::Item::Mod(mod_item) => {
+                // Recurse into inline module blocks (e.g. `mod group { ... }`)
+                if let Some((_, mod_items)) = &mod_item.content {
+                    let mod_name = mod_item.ident.to_string();
+                    let child_path = match module_path {
+                        Some(p) if !p.is_empty() => format!("{}_{}", p, mod_name),
+                        _ => mod_name,
+                    };
+                    extract_exports_from_items(mod_items, Some(&child_path), out)?;
+                }
+            }
+            _ => {}
         }
     }
     Ok(())
@@ -478,6 +579,13 @@ fn type_to_c(ty: &syn::Type, for_output: bool) -> String {
         return format!("{}{}*", mutability, inner);
     }
     if let Some(inner) = extract_option_inner(ty) {
+        // Option<&T> / Option<&mut T> is a nullable pointer — don't add an
+        // extra pointer level; the inner reference already contributes one.
+        if let syn::Type::Reference(ref_ty) = &inner {
+            let inner_c = type_to_c(&ref_ty.elem, for_output);
+            let mutability = if ref_ty.mutability.is_some() { "" } else { "const " };
+            return format!("{}{}*", mutability, inner_c);
+        }
         let inner_c = type_to_c(&inner, true);
         let mutability = if for_output { "" } else { "const " };
         return format!("{}{}*", mutability, inner_c);
@@ -642,6 +750,24 @@ fn emit_repr_c_enum(
     let data_name = format!("{}Data", enm.name);
     let ffi_name = format!("{}Ffi", enm.name);
 
+    // When every variant carries no fields the tag value alone is sufficient.
+    // Emitting a plain C enum avoids empty-struct extensions that are not
+    // standard C and keeps the ABI identical (both representations are the
+    // size of a u32).
+    let all_unit = enm.variants.iter().all(|v| v.fields.is_empty());
+    if all_unit {
+        out.push_str(&format!("typedef enum {} {{\n", tag_name));
+        for (idx, var) in enm.variants.iter().enumerate() {
+            out.push_str(&format!("    {}_{} = {},\n", tag_name, var.name, idx));
+        }
+        out.push_str(&format!("}} {};\n\n", tag_name));
+        out.push_str(&format!("typedef {} {};\n\n", tag_name, enm.name));
+        emitted.insert(tag_name);
+        emitted.insert(ffi_name);
+        emitted.insert(enm.name.clone());
+        return;
+    }
+
     for var in &enm.variants {
         for field in &var.fields {
             emit_field_type_deps(&field.ty, structs, emitted, out);
diff --git a/include/dropbear.h b/include/dropbear.h
index 1b85def..6cbf417 100644
--- a/include/dropbear.h
+++ b/include/dropbear.h
@@ -16,35 +16,71 @@ typedef enum AssetKind {
     AssetKind_Model = 1,
 } AssetKind;
 
+typedef struct Vec3 {
+    float x;
+    float y;
+    float z;
+} Vec3;
+
+typedef enum ColliderShapeTag {
+    ColliderShapeTag_Box = 0,
+    ColliderShapeTag_Sphere = 1,
+    ColliderShapeTag_Capsule = 2,
+    ColliderShapeTag_Cylinder = 3,
+    ColliderShapeTag_Cone = 4,
+} ColliderShapeTag;
+
+typedef struct ColliderShapeBox {
+    Vec3 half_extents;
+} ColliderShapeBox;
+
+typedef struct ColliderShapeSphere {
+    float radius;
+} ColliderShapeSphere;
+
+typedef struct ColliderShapeCapsule {
+    float half_height;
+    float radius;
+} ColliderShapeCapsule;
+
+typedef struct ColliderShapeCylinder {
+    float half_height;
+    float radius;
+} ColliderShapeCylinder;
+
+typedef struct ColliderShapeCone {
+    float half_height;
+    float radius;
+} ColliderShapeCone;
+
+typedef union ColliderShapeData {
+    ColliderShapeBox Box;
+    ColliderShapeSphere Sphere;
+    ColliderShapeCapsule Capsule;
+    ColliderShapeCylinder Cylinder;
+    ColliderShapeCone Cone;
+} ColliderShapeData;
+
+typedef struct ColliderShapeFfi {
+    ColliderShapeTag tag;
+    ColliderShapeData data;
+} ColliderShapeFfi;
+
+typedef ColliderShapeFfi ColliderShape;
+
 typedef enum NAnimationInterpolationTag {
     NAnimationInterpolationTag_Linear = 0,
     NAnimationInterpolationTag_Step = 1,
     NAnimationInterpolationTag_CubicSpline = 2,
 } NAnimationInterpolationTag;
 
-typedef struct NAnimationInterpolationLinear {
-} NAnimationInterpolationLinear;
-
-typedef struct NAnimationInterpolationStep {
-} NAnimationInterpolationStep;
-
-typedef struct NAnimationInterpolationCubicSpline {
-} NAnimationInterpolationCubicSpline;
-
-typedef union NAnimationInterpolationData {
-    NAnimationInterpolationLinear Linear;
-    NAnimationInterpolationStep Step;
-    NAnimationInterpolationCubicSpline CubicSpline;
-} NAnimationInterpolationData;
-
-typedef struct NAnimationInterpolationFfi {
-    NAnimationInterpolationTag tag;
-    NAnimationInterpolationData data;
-} NAnimationInterpolationFfi;
+typedef NAnimationInterpolationTag NAnimationInterpolation;
 
-typedef NAnimationInterpolationFfi NAnimationInterpolation;
-
-typedef struct NVector3 NVector3;// opaque
+typedef struct NVector3 {
+    double x;
+    double y;
+    double z;
+} NVector3;
 
 typedef struct NVector3Array {
     NVector3* values;
@@ -52,7 +88,12 @@ typedef struct NVector3Array {
     size_t capacity;
 } NVector3Array;
 
-typedef struct NQuaternion NQuaternion;// opaque
+typedef struct NQuaternion {
+    double x;
+    double y;
+    double z;
+    double w;
+} NQuaternion;
 
 typedef struct NQuaternionArray {
     NQuaternion* values;
@@ -103,11 +144,27 @@ typedef struct NChannelValuesFfi {
 
 typedef NChannelValuesFfi NChannelValues;
 
+typedef enum NShapeCastStatusTag {
+    NShapeCastStatusTag_OutOfIterations = 0,
+    NShapeCastStatusTag_Converged = 1,
+    NShapeCastStatusTag_Failed = 2,
+    NShapeCastStatusTag_PenetratingOrWithinTargetDist = 3,
+} NShapeCastStatusTag;
+
+typedef NShapeCastStatusTag NShapeCastStatus;
+
 typedef void* AssetRegistryPtr;
 
-typedef struct AxisLock AxisLock;// opaque
+typedef struct AxisLock {
+    bool x;
+    bool y;
+    bool z;
+} AxisLock;
 
-typedef struct IndexNative IndexNative;// opaque
+typedef struct IndexNative {
+    uint32_t index;
+    uint32_t generation;
+} IndexNative;
 
 typedef struct IndexNativeArray {
     IndexNative* values;
@@ -121,9 +178,11 @@ typedef struct CharacterCollisionArray {
     IndexNativeArray collisions;
 } CharacterCollisionArray;
 
-typedef struct CharacterMovementResult CharacterMovementResult;// opaque
-
-typedef struct ColliderShape ColliderShape;// opaque
+typedef struct CharacterMovementResult {
+    Vec3 translation;
+    bool grounded;
+    bool is_sliding_down_slope;
+} CharacterMovementResult;
 
 typedef void* CommandBufferPtr;
 
@@ -168,7 +227,11 @@ typedef struct NAttenuation {
     float quadratic;
 } NAttenuation;
 
-typedef struct NCollider NCollider;// opaque
+typedef struct NCollider {
+    IndexNative index;
+    uint64_t entity_id;
+    uint32_t id;
+} NCollider;
 
 typedef struct NColliderArray {
     NCollider* values;
@@ -176,11 +239,24 @@ typedef struct NColliderArray {
     size_t capacity;
 } NColliderArray;
 
-typedef struct NColour NColour;// opaque
-
-typedef struct NVector4 NVector4;// opaque
-
-typedef struct NVector2 NVector2;// opaque
+typedef struct NColour {
+    uint8_t r;
+    uint8_t g;
+    uint8_t b;
+    uint8_t a;
+} NColour;
+
+typedef struct NVector4 {
+    double x;
+    double y;
+    double z;
+    double w;
+} NVector4;
+
+typedef struct NVector2 {
+    double x;
+    double y;
+} NVector2;
 
 typedef struct NMaterial {
     const char* name;
@@ -265,9 +341,15 @@ typedef struct NRange {
     float end;
 } NRange;
 
-typedef struct NShapeCastHit NShapeCastHit;// opaque
-
-typedef struct NShapeCastStatus NShapeCastStatus;// opaque
+typedef struct NShapeCastHit {
+    NCollider collider;
+    double distance;
+    NVector3 witness1;
+    NVector3 witness2;
+    NVector3 normal1;
+    NVector3 normal2;
+    NShapeCastStatus status;
+} NShapeCastHit;
 
 typedef struct NSkin {
     const char* name;
@@ -282,15 +364,29 @@ typedef struct NSkinArray {
     size_t capacity;
 } NSkinArray;
 
-typedef struct NTransform NTransform;// opaque
+typedef struct NTransform {
+    NVector3 position;
+    NQuaternion rotation;
+    NVector3 scale;
+} NTransform;
 
 typedef void* PhysicsStatePtr;
 
-typedef struct Progress Progress;// opaque
+typedef struct Progress {
+    size_t current;
+    size_t total;
+    const char* message;
+} Progress;
 
-typedef struct RayHit RayHit;// opaque
+typedef struct RayHit {
+    NCollider collider;
+    double distance;
+} RayHit;
 
-typedef struct RigidBodyContext RigidBodyContext;// opaque
+typedef struct RigidBodyContext {
+    IndexNative index;
+    uint64_t entity_id;
+} RigidBodyContext;
 
 typedef void* SceneLoaderPtr;
 
@@ -362,6 +458,8 @@ int32_t dropbear_collider_get_collider_restitution(PhysicsStatePtr physics, cons
 int32_t dropbear_collider_get_collider_rotation(PhysicsStatePtr physics, const NCollider* collider, NVector3* out0);
 int32_t dropbear_collider_get_collider_shape(PhysicsStatePtr physics, const NCollider* collider, ColliderShape* out0);
 int32_t dropbear_collider_get_collider_translation(PhysicsStatePtr physics, const NCollider* collider, NVector3* out0);
+int32_t dropbear_collider_group_exists_for_entity(WorldPtr world, uint64_t entity, bool* out0);
+int32_t dropbear_collider_group_get_colliders(WorldPtr world, PhysicsStatePtr physics, uint64_t entity, NColliderArray* out0);
 int32_t dropbear_collider_set_collider_density(PhysicsStatePtr physics, const NCollider* collider, double density);
 int32_t dropbear_collider_set_collider_friction(PhysicsStatePtr physics, const NCollider* collider, double friction);
 int32_t dropbear_collider_set_collider_is_sensor(PhysicsStatePtr physics, const NCollider* collider, bool is_sensor);
diff --git a/scripting/nativeMain/kotlin/com/dropbear/ffi/generated/FfiConverters.kt b/scripting/nativeMain/kotlin/com/dropbear/ffi/generated/FfiConverters.kt
index 952a520..ac20a74 100644
--- a/scripting/nativeMain/kotlin/com/dropbear/ffi/generated/FfiConverters.kt
+++ b/scripting/nativeMain/kotlin/com/dropbear/ffi/generated/FfiConverters.kt
@@ -86,7 +86,7 @@ internal fun MemScope.allocColour(c: Colour): NColour {
 }
 
 
-internal fun readShapeCastStatus(s: NShapeCastStatus): ShapeCastStatus = when (s.tag) {
+internal fun readShapeCastStatus(s: UInt): ShapeCastStatus = when (s) {
     NShapeCastStatusTag_OutOfIterations -> ShapeCastStatus.OutOfIterations
     NShapeCastStatusTag_Converged -> ShapeCastStatus.Converged
     NShapeCastStatusTag_Failed -> ShapeCastStatus.Failed
@@ -96,7 +96,7 @@ internal fun readShapeCastStatus(s: NShapeCastStatus): ShapeCastStatus = when (s
 
 internal fun readColliderShape(ffi: ColliderShapeFfi): ColliderShape = when (ffi.tag) {
     ColliderShapeTag_Box -> ColliderShape.Box(
-        Vector3d(ffi.data.Box.half_extents.x, ffi.data.Box.half_extents.y, ffi.data.Box.half_extents.z)
+        Vector3d(ffi.data.Box.half_extents.x.toDouble(), ffi.data.Box.half_extents.y.toDouble(), ffi.data.Box.half_extents.z.toDouble())
     )
     ColliderShapeTag_Sphere -> ColliderShape.Sphere(ffi.data.Sphere.radius)
     ColliderShapeTag_Capsule -> ColliderShape.Capsule(ffi.data.Capsule.half_height, ffi.data.Capsule.radius)
@@ -110,9 +110,9 @@ internal fun MemScope.allocColliderShape(shape: ColliderShape): ColliderShapeFfi
     when (shape) {
         is ColliderShape.Box -> {
             ffi.tag = ColliderShapeTag_Box
-            ffi.data.Box.half_extents.x = shape.halfExtents.x
-            ffi.data.Box.half_extents.y = shape.halfExtents.y
-            ffi.data.Box.half_extents.z = shape.halfExtents.z
+            ffi.data.Box.half_extents.x = shape.halfExtents.x.toFloat()
+            ffi.data.Box.half_extents.y = shape.halfExtents.y.toFloat()
+            ffi.data.Box.half_extents.z = shape.halfExtents.z.toFloat()
         }
         is ColliderShape.Sphere -> {
             ffi.tag = ColliderShapeTag_Sphere
diff --git a/scripting/nativeMain/kotlin/com/dropbear/input/Gamepad.native.kt b/scripting/nativeMain/kotlin/com/dropbear/input/Gamepad.native.kt
index 37fb8c9..45f61fd 100644
--- a/scripting/nativeMain/kotlin/com/dropbear/input/Gamepad.native.kt
+++ b/scripting/nativeMain/kotlin/com/dropbear/input/Gamepad.native.kt
@@ -11,20 +11,20 @@ import kotlinx.cinterop.*
 internal actual fun Gamepad.isGamepadButtonPressed(button: GamepadButton): Boolean = memScoped {
     val input = DropbearEngine.native.inputHandle ?: return@memScoped false
     val out = alloc<BooleanVar>()
-    dropbear_gamepad_is_button_pressed(input, id.toULong(), button.ordinal, out.ptr)
+    dropbear_input_is_button_pressed(input, id.toULong(), button.ordinal, out.ptr)
     out.value
 }
 
 internal actual fun Gamepad.getLeftStickPosition(): Vector2d = memScoped {
     val input = DropbearEngine.native.inputHandle ?: return@memScoped Vector2d(0.0, 0.0)
     val out = alloc<NVector2>()
-    dropbear_gamepad_get_left_stick_position(input, id.toULong(), out.ptr)
+    dropbear_input_get_left_stick_position(input, id.toULong(), out.ptr)
     Vector2d(out.x, out.y)
 }
 
 internal actual fun Gamepad.getRightStickPosition(): Vector2d = memScoped {
     val input = DropbearEngine.native.inputHandle ?: return@memScoped Vector2d(0.0, 0.0)
     val out = alloc<NVector2>()
-    dropbear_gamepad_get_right_stick_position(input, id.toULong(), out.ptr)
+    dropbear_input_get_right_stick_position(input, id.toULong(), out.ptr)
     Vector2d(out.x, out.y)
 }
diff --git a/scripting/nativeMain/kotlin/com/dropbear/input/InputState.native.kt b/scripting/nativeMain/kotlin/com/dropbear/input/InputState.native.kt
index 54f2ee2..7d63e7b 100644
--- a/scripting/nativeMain/kotlin/com/dropbear/input/InputState.native.kt
+++ b/scripting/nativeMain/kotlin/com/dropbear/input/InputState.native.kt
@@ -77,11 +77,11 @@ actual class InputState actual constructor() {
 
     actual fun getConnectedGamepads(): List<Gamepad> = memScoped {
         val input = DropbearEngine.native.inputHandle ?: return@memScoped emptyList()
-        val out = alloc<ConnectedGamepadIds>()
+        val out = alloc<u64Array>()
         val rc = dropbear_input_get_connected_gamepads(input, out.ptr)
         if (rc != 0) return@memScoped emptyList()
-        val ptr = out.ids.values ?: return@memScoped emptyList()
-        val len = out.ids.length.toInt()
+        val ptr = out.values ?: return@memScoped emptyList()
+        val len = out.length.toInt()
         (0 until len).map { i -> Gamepad(ptr[i].toLong()) }
     }
 }
\ No newline at end of file
diff --git a/scripting/nativeMain/kotlin/com/dropbear/physics/CharacterCollision.native.kt b/scripting/nativeMain/kotlin/com/dropbear/physics/CharacterCollision.native.kt
index dee9baf..690247e 100644
--- a/scripting/nativeMain/kotlin/com/dropbear/physics/CharacterCollision.native.kt
+++ b/scripting/nativeMain/kotlin/com/dropbear/physics/CharacterCollision.native.kt
@@ -4,20 +4,19 @@ package com.dropbear.physics
 
 import com.dropbear.DropbearEngine
 import com.dropbear.ffi.generated.NCollider
-import com.dropbear.ffi.generated.NShapeCastStatus
 import com.dropbear.ffi.generated.NTransform
 import com.dropbear.ffi.generated.NVector3
 import com.dropbear.ffi.generated.allocIndexNative
-import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_collider
-import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_normal1
-import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_normal2
-import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_position
-import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_status
-import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_time_of_impact
-import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_translation_applied
-import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_translation_remaining
-import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_witness1
-import com.dropbear.ffi.generated.dropbear_character_collision_get_character_collision_witness2
+import com.dropbear.ffi.generated.dropbear_kcc_get_character_collision_collider
+import com.dropbear.ffi.generated.dropbear_kcc_get_character_collision_normal1
+import com.dropbear.ffi.generated.dropbear_kcc_get_character_collision_normal2
+import com.dropbear.ffi.generated.dropbear_kcc_get_character_collision_position
+import com.dropbear.ffi.generated.dropbear_kcc_get_character_collision_status
+import com.dropbear.ffi.generated.dropbear_kcc_get_character_collision_time_of_impact
+import com.dropbear.ffi.generated.dropbear_kcc_get_character_collision_translation_applied
+import com.dropbear.ffi.generated.dropbear_kcc_get_character_collision_translation_remaining
+import com.dropbear.ffi.generated.dropbear_kcc_get_character_collision_witness1
+import com.dropbear.ffi.generated.dropbear_kcc_get_character_collision_witness2
 import com.dropbear.ffi.generated.readCollider
 import com.dropbear.ffi.generated.readShapeCastStatus
 import com.dropbear.ffi.generated.readTransform
@@ -29,7 +28,7 @@ internal actual fun CharacterCollision.getCollider(): Collider = memScoped {
     val world = DropbearEngine.native.worldHandle ?: return@memScoped Collider(Index(0u, 0u), entity, 0u)
     val ni = allocIndexNative(collisionHandle)
     val out = alloc<NCollider>()
-    dropbear_character_collision_get_character_collision_collider(world, entity.raw.toULong(), ni.ptr, out.ptr)
+    dropbear_kcc_get_character_collision_collider(world, entity.raw.toULong(), ni.ptr, out.ptr)
     readCollider(out)
 }
 
@@ -37,7 +36,7 @@ internal actual fun CharacterCollision.getCharacterPosition(): Transform = memSc
     val world = DropbearEngine.native.worldHandle ?: return@memScoped Transform.identity()
     val ni = allocIndexNative(collisionHandle)
     val out = alloc<NTransform>()
-    dropbear_character_collision_get_character_collision_position(world, entity.raw.toULong(), ni.ptr, out.ptr)
+    dropbear_kcc_get_character_collision_position(world, entity.raw.toULong(), ni.ptr, out.ptr)
     readTransform(out)
 }
 
@@ -45,7 +44,7 @@ internal actual fun CharacterCollision.getTranslationApplied(): Vector3d = memSc
     val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero()
     val ni = allocIndexNative(collisionHandle)
     val out = alloc<NVector3>()
-    dropbear_character_collision_get_character_collision_translation_applied(world, entity.raw.toULong(), ni.ptr, out.ptr)
+    dropbear_kcc_get_character_collision_translation_applied(world, entity.raw.toULong(), ni.ptr, out.ptr)
     Vector3d(out.x, out.y, out.z)
 }
 
@@ -53,7 +52,7 @@ internal actual fun CharacterCollision.getTranslationRemaining(): Vector3d = mem
     val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero()
     val ni = allocIndexNative(collisionHandle)
     val out = alloc<NVector3>()
-    dropbear_character_collision_get_character_collision_translation_remaining(world, entity.raw.toULong(), ni.ptr, out.ptr)
+    dropbear_kcc_get_character_collision_translation_remaining(world, entity.raw.toULong(), ni.ptr, out.ptr)
     Vector3d(out.x, out.y, out.z)
 }
 
@@ -61,7 +60,7 @@ internal actual fun CharacterCollision.getTimeOfImpact(): Double = memScoped {
     val world = DropbearEngine.native.worldHandle ?: return@memScoped 0.0
     val ni = allocIndexNative(collisionHandle)
     val out = alloc<DoubleVar>()
-    dropbear_character_collision_get_character_collision_time_of_impact(world, entity.raw.toULong(), ni.ptr, out.ptr)
+    dropbear_kcc_get_character_collision_time_of_impact(world, entity.raw.toULong(), ni.ptr, out.ptr)
     out.value
 }
 
@@ -69,7 +68,7 @@ internal actual fun CharacterCollision.getWitness1(): Vector3d = memScoped {
     val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero()
     val ni = allocIndexNative(collisionHandle)
     val out = alloc<NVector3>()
-    dropbear_character_collision_get_character_collision_witness1(world, entity.raw.toULong(), ni.ptr, out.ptr)
+    dropbear_kcc_get_character_collision_witness1(world, entity.raw.toULong(), ni.ptr, out.ptr)
     Vector3d(out.x, out.y, out.z)
 }
 
@@ -77,7 +76,7 @@ internal actual fun CharacterCollision.getWitness2(): Vector3d = memScoped {
     val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero()
     val ni = allocIndexNative(collisionHandle)
     val out = alloc<NVector3>()
-    dropbear_character_collision_get_character_collision_witness2(world, entity.raw.toULong(), ni.ptr, out.ptr)
+    dropbear_kcc_get_character_collision_witness2(world, entity.raw.toULong(), ni.ptr, out.ptr)
     Vector3d(out.x, out.y, out.z)
 }
 
@@ -85,7 +84,7 @@ internal actual fun CharacterCollision.getNormal1(): Vector3d = memScoped {
     val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero()
     val ni = allocIndexNative(collisionHandle)
     val out = alloc<NVector3>()
-    dropbear_character_collision_get_character_collision_normal1(world, entity.raw.toULong(), ni.ptr, out.ptr)
+    dropbear_kcc_get_character_collision_normal1(world, entity.raw.toULong(), ni.ptr, out.ptr)
     Vector3d(out.x, out.y, out.z)
 }
 
@@ -93,14 +92,14 @@ internal actual fun CharacterCollision.getNormal2(): Vector3d = memScoped {
     val world = DropbearEngine.native.worldHandle ?: return@memScoped Vector3d.zero()
     val ni = allocIndexNative(collisionHandle)
     val out = alloc<NVector3>()
-    dropbear_character_collision_get_character_collision_normal2(world, entity.raw.toULong(), ni.ptr, out.ptr)
+    dropbear_kcc_get_character_collision_normal2(world, entity.raw.toULong(), ni.ptr, out.ptr)
     Vector3d(out.x, out.y, out.z)
 }
 
 internal actual fun CharacterCollision.getStatus(): ShapeCastStatus = memScoped {
     val world = DropbearEngine.native.worldHandle ?: return@memScoped ShapeCastStatus.Failed
     val ni = allocIndexNative(collisionHandle)
-    val out = alloc<NShapeCastStatus>()
-    dropbear_character_collision_get_character_collision_status(world, entity.raw.toULong(), ni.ptr, out.ptr)
-    readShapeCastStatus(out)
+    val out = alloc<UIntVar>()
+    dropbear_kcc_get_character_collision_status(world, entity.raw.toULong(), ni.ptr, out.ptr.reinterpret())
+    readShapeCastStatus(out.value)
 }
\ No newline at end of file
diff --git a/scripting/nativeMain/kotlin/com/dropbear/physics/KinematicCharacterController.native.kt b/scripting/nativeMain/kotlin/com/dropbear/physics/KinematicCharacterController.native.kt
index 7f7594e..768d591 100644
--- a/scripting/nativeMain/kotlin/com/dropbear/physics/KinematicCharacterController.native.kt
+++ b/scripting/nativeMain/kotlin/com/dropbear/physics/KinematicCharacterController.native.kt
@@ -59,7 +59,7 @@ internal actual fun KinematicCharacterController.getMovementResult(): CharacterM
     val present = alloc<BooleanVar>()
     val rc = dropbear_kcc_get_movement_result(world, entity.raw.toULong(), out.ptr, present.ptr)
     if (rc != 0 || !present.value) null else CharacterMovementResult(
-        Vector3d(out.translation.x, out.translation.y, out.translation.z),
+        Vector3d(out.translation.x.toDouble(), out.translation.y.toDouble(), out.translation.z.toDouble()),
         out.grounded,
         out.is_sliding_down_slope,
     )
diff --git a/scripting/nativeMain/kotlin/com/dropbear/scene/SceneLoadHandle.native.kt b/scripting/nativeMain/kotlin/com/dropbear/scene/SceneLoadHandle.native.kt
index a88836b..866f80f 100644
--- a/scripting/nativeMain/kotlin/com/dropbear/scene/SceneLoadHandle.native.kt
+++ b/scripting/nativeMain/kotlin/com/dropbear/scene/SceneLoadHandle.native.kt
@@ -11,13 +11,13 @@ import kotlinx.cinterop.*
 internal actual fun SceneLoadHandle.switchToSceneAsync() {
     val cmd = DropbearEngine.native.commandBufferHandle ?: return
     val sceneLoader = DropbearEngine.native.sceneLoaderHandle ?: return
-    memScoped { dropbear_scripting_switch_to_scene_async(cmd, sceneLoader, id.toULong()) }
+    memScoped { dropbear_scene_switch_to_scene_async(cmd, sceneLoader, id.toULong()) }
 }
 
 internal actual fun SceneLoadHandle.getSceneLoadProgress(): Progress = memScoped {
     val sceneLoader = DropbearEngine.native.sceneLoaderHandle ?: return@memScoped Progress.nothing()
     val out = alloc<com.dropbear.ffi.generated.Progress>()
-    val rc = dropbear_scripting_get_scene_load_progress(sceneLoader, id.toULong(), out.ptr)
+    val rc = dropbear_scene_get_scene_load_progress(sceneLoader, id.toULong(), out.ptr)
     if (rc != 0) Progress.nothing() else Progress(
         out.current.toDouble(),
         out.total.toDouble(),
@@ -28,7 +28,7 @@ internal actual fun SceneLoadHandle.getSceneLoadProgress(): Progress = memScoped
 internal actual fun SceneLoadHandle.getSceneLoadStatus(): SceneLoadStatus = memScoped {
     val sceneLoader = DropbearEngine.native.sceneLoaderHandle ?: return@memScoped SceneLoadStatus.FAILED
     val out = alloc<UIntVar>()
-    val rc = dropbear_scripting_get_scene_load_status(sceneLoader, id.toULong(), out.ptr)
+    val rc = dropbear_scene_get_scene_load_status(sceneLoader, id.toULong(), out.ptr)
     if (rc != 0) SceneLoadStatus.FAILED else when (out.value.toInt()) {
         0 -> SceneLoadStatus.PENDING
         1 -> SceneLoadStatus.READY
@@ -39,6 +39,6 @@ internal actual fun SceneLoadHandle.getSceneLoadStatus(): SceneLoadStatus = memS
 internal actual fun SceneLoadHandle.getSceneLoadHandleSceneName(id: Long): String = memScoped {
     val sceneLoader = DropbearEngine.native.sceneLoaderHandle ?: return@memScoped ""
     val out = alloc<CPointerVar<ByteVar>>()
-    val rc = dropbear_scripting_get_scene_load_handle_scene_name(sceneLoader, id.toULong(), out.ptr)
+    val rc = dropbear_scene_get_scene_load_handle_scene_name(sceneLoader, id.toULong(), out.ptr)
     if (rc != 0) "" else out.value?.toKString() ?: ""
 }
\ No newline at end of file
diff --git a/scripting/nativeMain/kotlin/com/dropbear/scene/SceneManager.native.kt b/scripting/nativeMain/kotlin/com/dropbear/scene/SceneManager.native.kt
index 476fb09..287c4d7 100644
--- a/scripting/nativeMain/kotlin/com/dropbear/scene/SceneManager.native.kt
+++ b/scripting/nativeMain/kotlin/com/dropbear/scene/SceneManager.native.kt
@@ -11,7 +11,7 @@ internal actual fun SceneManager.loadSceneAsyncNative(sceneName: String): SceneL
     val cmd = DropbearEngine.native.commandBufferHandle ?: return@memScoped null
     val sceneLoader = DropbearEngine.native.sceneLoaderHandle ?: return@memScoped null
     val out = alloc<ULongVar>()
-    val rc = dropbear_scripting_load_scene_async(cmd, sceneLoader, sceneName, out.ptr)
+    val rc = dropbear_scene_load_scene_async(cmd, sceneLoader, sceneName, out.ptr)
     if (rc != 0) null else SceneLoadHandle(out.value.toLong())
 }
 
@@ -19,13 +19,13 @@ internal actual fun SceneManager.loadSceneAsyncNative(sceneName: String, loading
     val cmd = DropbearEngine.native.commandBufferHandle ?: return@memScoped null
     val sceneLoader = DropbearEngine.native.sceneLoaderHandle ?: return@memScoped null
     val out = alloc<ULongVar>()
-    val rc = dropbear_scripting_load_scene_async_with_loading(cmd, sceneLoader, sceneName, loadingScene, out.ptr)
+    val rc = dropbear_scene_load_scene_async_with_loading(cmd, sceneLoader, sceneName, loadingScene, out.ptr)
     if (rc != 0) null else SceneLoadHandle(out.value.toLong())
 }
 
 internal actual fun SceneManager.switchToSceneImmediateNative(sceneName: String) {
     val cmd = DropbearEngine.native.commandBufferHandle ?: return
-    memScoped { dropbear_scripting_switch_to_scene_immediate(cmd, sceneName) }
+    memScoped { dropbear_scene_switch_to_scene_immediate(cmd, sceneName) }
 }
 
 internal actual fun SceneManager.getSceneMetadataNative(sceneName: String): SceneMetadata? {