Skip to content

Support f32 directly in process and physics_process #1110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 30, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion godot-codegen/src/models/domain_mapping.rs
Original file line number Diff line number Diff line change
@@ -458,7 +458,6 @@ impl ClassMethod {
}

let is_private = special_cases::is_method_private(class_name, &method.name);

let godot_method_name = method.name.clone();

let qualifier = {
11 changes: 6 additions & 5 deletions godot-codegen/src/special_cases/special_cases.rs
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@

// NOTE: the methods are generally implemented on Godot types (e.g. AABB, not Aabb)

// This file is deliberately private -- all checks must go through `special_cases`.

#![allow(clippy::match_like_matches_macro)] // if there is only one rule

use crate::conv::to_enum_type_uncached;
@@ -29,7 +31,6 @@ use crate::models::json::{JsonBuiltinMethod, JsonClassMethod, JsonUtilityFunctio
use crate::special_cases::codegen_special_cases;
use crate::Context;
use proc_macro2::Ident;
// Deliberately private -- all checks must go through `special_cases`.

#[rustfmt::skip]
pub fn is_class_method_deleted(class_name: &TyName, method: &JsonClassMethod, ctx: &mut Context) -> bool {
@@ -62,7 +63,7 @@ pub fn is_class_method_deleted(class_name: &TyName, method: &JsonClassMethod, ct
| ("VisualShaderNodeComment", "set_description")
| ("VisualShaderNodeComment", "get_description")
=> true,

// Workaround for methods unexposed in Release mode, see https://github.com/godotengine/godot/pull/100317
// and https://github.com/godotengine/godot/pull/100328.
#[cfg(not(debug_assertions))]
@@ -840,9 +841,9 @@ pub fn is_enum_private(class_name: Option<&TyName>, enum_name: &str) -> bool {
}

/// Certain enums that are extremely unlikely to get new identifiers in the future.
///
///
/// `class_name` = None for global enums.
///
///
/// Very conservative, only includes a few enums. Even `VariantType` was extended over time.
/// Also does not work for any enums containing duplicate ordinals.
#[rustfmt::skip]
@@ -873,7 +874,7 @@ pub fn is_enum_bitfield(class_name: Option<&TyName>, enum_name: &str) -> Option<
match (class_name, enum_name) {
| (Some("Object"), "ConnectFlags")

=> Some(true),
=> Some(true),
_ => None
}
}
8 changes: 4 additions & 4 deletions godot-core/src/obj/traits.rs
Original file line number Diff line number Diff line change
@@ -293,7 +293,7 @@ pub trait WithBaseField: GodotClass + Bounds<Declarer = bounds::DeclUser> {
///
/// #[godot_api]
/// impl INode for MyClass {
/// fn process(&mut self, _delta: f64) {
/// fn process(&mut self, _delta: f32) {
/// let name = self.base().get_name();
/// godot_print!("name is {name}");
/// }
@@ -319,7 +319,7 @@ pub trait WithBaseField: GodotClass + Bounds<Declarer = bounds::DeclUser> {
///
/// #[godot_api]
/// impl INode for MyClass {
/// fn process(&mut self, _delta: f64) {
/// fn process(&mut self, _delta: f32) {
/// let node = Node::new_alloc();
/// // fails because `add_child` requires a mutable reference.
/// self.base().add_child(&node);
@@ -362,7 +362,7 @@ pub trait WithBaseField: GodotClass + Bounds<Declarer = bounds::DeclUser> {
///
/// #[godot_api]
/// impl INode for MyClass {
/// fn process(&mut self, _delta: f64) {
/// fn process(&mut self, _delta: f32) {
/// let node = Node::new_alloc();
/// self.base_mut().add_child(&node);
/// }
@@ -387,7 +387,7 @@ pub trait WithBaseField: GodotClass + Bounds<Declarer = bounds::DeclUser> {
///
/// #[godot_api]
/// impl INode for MyClass {
/// fn process(&mut self, _delta: f64) {
/// fn process(&mut self, _delta: f32) {
/// self.base_mut().call("other_method", &[]);
/// }
/// }
45 changes: 42 additions & 3 deletions godot-macros/src/class/data_models/func.rs
Original file line number Diff line number Diff line change
@@ -187,8 +187,14 @@ pub struct SignatureInfo {
pub method_name: Ident,
pub receiver_type: ReceiverType,
pub param_idents: Vec<Ident>,
/// Parameter types *without* receiver.
pub param_types: Vec<venial::TypeExpr>,
pub return_type: TokenStream,

/// `(original index, new type)` only for changed parameters; empty if no changes.
///
/// Index points into original venial tokens (i.e. takes into account potential receiver params).
pub modified_param_types: Vec<(usize, venial::TypeExpr)>,
}

impl SignatureInfo {
@@ -199,6 +205,7 @@ impl SignatureInfo {
param_idents: vec![],
param_types: vec![],
return_type: quote! { () },
modified_param_types: vec![],
}
}

@@ -359,7 +366,8 @@ pub(crate) fn into_signature_info(
};

let mut next_unnamed_index = 0;
for (arg, _) in signature.params.inner {
let mut modified_param_types = vec![];
for (index, (arg, _)) in signature.params.inner.into_iter().enumerate() {
match arg {
venial::FnParam::Receiver(recv) => {
if receiver_type == ReceiverType::GdSelf {
@@ -377,8 +385,17 @@ pub(crate) fn into_signature_info(
}
venial::FnParam::Typed(arg) => {
let ident = maybe_rename_parameter(arg.name, &mut next_unnamed_index);
let ty = venial::TypeExpr {
tokens: map_self_to_class_name(arg.ty.tokens, class_name),
let ty = match maybe_change_parameter_type(arg.ty, &method_name, index) {
// Parameter type was modified.
Ok(ty) => {
modified_param_types.push((index, ty.clone()));
ty
}

// Not an error, just unchanged.
Err(ty) => venial::TypeExpr {
tokens: map_self_to_class_name(ty.tokens, class_name),
},
};

param_types.push(ty);
@@ -393,6 +410,28 @@ pub(crate) fn into_signature_info(
param_idents,
param_types,
return_type: ret_type,
modified_param_types,
}
}

/// If `f32` is used for a delta parameter in a virtual process function, transparently use `f64` behind the scenes.
fn maybe_change_parameter_type(
param_ty: venial::TypeExpr,
method_name: &Ident,
param_index: usize,
) -> Result<venial::TypeExpr, venial::TypeExpr> {
// A bit hackish, but TokenStream APIs are also notoriously annoying to work with. Not even PartialEq...

if param_index == 1
&& (method_name == "process" || method_name == "physics_process")
&& param_ty.tokens.len() == 1
&& param_ty.tokens[0].to_string() == "f32"
{
Ok(venial::TypeExpr {
tokens: vec![TokenTree::Ident(ident("f64"))],
})
} else {
Err(param_ty)
}
}

Loading