Merge pull request #28423 from neikeq/dont-forget-to-think-a-name-for-this-branch
C#: Deprecate accessor methods and generate correct int and float types
This commit is contained in:
commit
554c0ea90b
@ -9,6 +9,12 @@ public:
|
|||||||
$ifret R$ $ifnoret void$ (T::*method)($arg, P@$) $ifconst const$;
|
$ifret R$ $ifnoret void$ (T::*method)($arg, P@$) $ifconst const$;
|
||||||
#ifdef DEBUG_METHODS_ENABLED
|
#ifdef DEBUG_METHODS_ENABLED
|
||||||
virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
|
virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
|
||||||
|
virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
|
||||||
|
$ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$
|
||||||
|
$arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA;
|
||||||
|
$
|
||||||
|
return GodotTypeInfo::METADATA_NONE;
|
||||||
|
}
|
||||||
Variant::Type _get_argument_type(int p_argument) const {
|
Variant::Type _get_argument_type(int p_argument) const {
|
||||||
$ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
|
$ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
|
||||||
$arg if (p_argument==(@-1)) return (Variant::Type)GetTypeInfo<P@>::VARIANT_TYPE;
|
$arg if (p_argument==(@-1)) return (Variant::Type)GetTypeInfo<P@>::VARIANT_TYPE;
|
||||||
@ -94,6 +100,12 @@ public:
|
|||||||
|
|
||||||
#ifdef DEBUG_METHODS_ENABLED
|
#ifdef DEBUG_METHODS_ENABLED
|
||||||
virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
|
virtual Variant::Type _gen_argument_type(int p_arg) const { return _get_argument_type(p_arg); }
|
||||||
|
virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const {
|
||||||
|
$ifret if (p_arg==-1) return GetTypeInfo<R>::METADATA;$
|
||||||
|
$arg if (p_arg==(@-1)) return GetTypeInfo<P@>::METADATA;
|
||||||
|
$
|
||||||
|
return GodotTypeInfo::METADATA_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
Variant::Type _get_argument_type(int p_argument) const {
|
Variant::Type _get_argument_type(int p_argument) const {
|
||||||
$ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
|
$ifret if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;$
|
||||||
|
@ -273,6 +273,8 @@ public:
|
|||||||
void set_argument_names(const Vector<StringName> &p_names); //set by class, db, can't be inferred otherwise
|
void set_argument_names(const Vector<StringName> &p_names); //set by class, db, can't be inferred otherwise
|
||||||
Vector<StringName> get_argument_names() const;
|
Vector<StringName> get_argument_names() const;
|
||||||
|
|
||||||
|
virtual GodotTypeInfo::Metadata get_argument_meta(int p_arg) const = 0;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
void set_hint_flags(uint32_t p_hint) { hint_flags = p_hint; }
|
void set_hint_flags(uint32_t p_hint) { hint_flags = p_hint; }
|
||||||
uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0); }
|
uint32_t get_hint_flags() const { return hint_flags | (is_const() ? METHOD_FLAG_CONST : 0) | (is_vararg() ? METHOD_FLAG_VARARG : 0); }
|
||||||
@ -329,6 +331,10 @@ public:
|
|||||||
return _gen_argument_type_info(p_arg).type;
|
return _gen_argument_type_info(p_arg).type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual GodotTypeInfo::Metadata get_argument_meta(int) const {
|
||||||
|
return GodotTypeInfo::METADATA_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
virtual Variant::Type _gen_argument_type(int p_arg) const {
|
virtual Variant::Type _gen_argument_type(int p_arg) const {
|
||||||
|
@ -375,7 +375,8 @@ struct PtrToArg<const RefPtr &> {
|
|||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct GetTypeInfo<Ref<T> > {
|
struct GetTypeInfo<Ref<T> > {
|
||||||
enum { VARIANT_TYPE = Variant::OBJECT };
|
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||||
|
|
||||||
static inline PropertyInfo get_class_info() {
|
static inline PropertyInfo get_class_info() {
|
||||||
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
||||||
@ -384,7 +385,8 @@ struct GetTypeInfo<Ref<T> > {
|
|||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct GetTypeInfo<const Ref<T> &> {
|
struct GetTypeInfo<const Ref<T> &> {
|
||||||
enum { VARIANT_TYPE = Variant::OBJECT };
|
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||||
|
|
||||||
static inline PropertyInfo get_class_info() {
|
static inline PropertyInfo get_class_info() {
|
||||||
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, T::get_class_static());
|
||||||
|
@ -67,9 +67,26 @@ struct TypeInherits {
|
|||||||
!TypesAreSame<B volatile const, void volatile const>::value;
|
!TypesAreSame<B volatile const, void volatile const>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace GodotTypeInfo {
|
||||||
|
enum Metadata {
|
||||||
|
METADATA_NONE,
|
||||||
|
METADATA_INT_IS_INT8,
|
||||||
|
METADATA_INT_IS_INT16,
|
||||||
|
METADATA_INT_IS_INT32,
|
||||||
|
METADATA_INT_IS_INT64,
|
||||||
|
METADATA_INT_IS_UINT8,
|
||||||
|
METADATA_INT_IS_UINT16,
|
||||||
|
METADATA_INT_IS_UINT32,
|
||||||
|
METADATA_INT_IS_UINT64,
|
||||||
|
METADATA_REAL_IS_FLOAT,
|
||||||
|
METADATA_REAL_IS_DOUBLE
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
template <class T, typename = void>
|
template <class T, typename = void>
|
||||||
struct GetTypeInfo {
|
struct GetTypeInfo {
|
||||||
static const Variant::Type VARIANT_TYPE = Variant::NIL;
|
static const Variant::Type VARIANT_TYPE = Variant::NIL;
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||||
static inline PropertyInfo get_class_info() {
|
static inline PropertyInfo get_class_info() {
|
||||||
ERR_PRINT("GetTypeInfo fallback. Bug!");
|
ERR_PRINT("GetTypeInfo fallback. Bug!");
|
||||||
return PropertyInfo(); // Not "Nil", this is an error
|
return PropertyInfo(); // Not "Nil", this is an error
|
||||||
@ -80,6 +97,7 @@ struct GetTypeInfo {
|
|||||||
template <> \
|
template <> \
|
||||||
struct GetTypeInfo<m_type> { \
|
struct GetTypeInfo<m_type> { \
|
||||||
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
|
||||||
static inline PropertyInfo get_class_info() { \
|
static inline PropertyInfo get_class_info() { \
|
||||||
return PropertyInfo(VARIANT_TYPE, String()); \
|
return PropertyInfo(VARIANT_TYPE, String()); \
|
||||||
} \
|
} \
|
||||||
@ -87,23 +105,42 @@ struct GetTypeInfo {
|
|||||||
template <> \
|
template <> \
|
||||||
struct GetTypeInfo<const m_type &> { \
|
struct GetTypeInfo<const m_type &> { \
|
||||||
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
|
||||||
|
static inline PropertyInfo get_class_info() { \
|
||||||
|
return PropertyInfo(VARIANT_TYPE, String()); \
|
||||||
|
} \
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAKE_TYPE_INFO_WITH_META(m_type, m_var_type, m_metadata) \
|
||||||
|
template <> \
|
||||||
|
struct GetTypeInfo<m_type> { \
|
||||||
|
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = m_metadata; \
|
||||||
|
static inline PropertyInfo get_class_info() { \
|
||||||
|
return PropertyInfo(VARIANT_TYPE, String()); \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
template <> \
|
||||||
|
struct GetTypeInfo<const m_type &> { \
|
||||||
|
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = m_metadata; \
|
||||||
static inline PropertyInfo get_class_info() { \
|
static inline PropertyInfo get_class_info() { \
|
||||||
return PropertyInfo(VARIANT_TYPE, String()); \
|
return PropertyInfo(VARIANT_TYPE, String()); \
|
||||||
} \
|
} \
|
||||||
};
|
};
|
||||||
|
|
||||||
MAKE_TYPE_INFO(bool, Variant::BOOL)
|
MAKE_TYPE_INFO(bool, Variant::BOOL)
|
||||||
MAKE_TYPE_INFO(uint8_t, Variant::INT)
|
MAKE_TYPE_INFO_WITH_META(uint8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT8)
|
||||||
MAKE_TYPE_INFO(int8_t, Variant::INT)
|
MAKE_TYPE_INFO_WITH_META(int8_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT8)
|
||||||
MAKE_TYPE_INFO(uint16_t, Variant::INT)
|
MAKE_TYPE_INFO_WITH_META(uint16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT16)
|
||||||
MAKE_TYPE_INFO(int16_t, Variant::INT)
|
MAKE_TYPE_INFO_WITH_META(int16_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT16)
|
||||||
MAKE_TYPE_INFO(uint32_t, Variant::INT)
|
MAKE_TYPE_INFO_WITH_META(uint32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT32)
|
||||||
MAKE_TYPE_INFO(int32_t, Variant::INT)
|
MAKE_TYPE_INFO_WITH_META(int32_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT32)
|
||||||
MAKE_TYPE_INFO(int64_t, Variant::INT)
|
MAKE_TYPE_INFO_WITH_META(uint64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_UINT64)
|
||||||
MAKE_TYPE_INFO(uint64_t, Variant::INT)
|
MAKE_TYPE_INFO_WITH_META(int64_t, Variant::INT, GodotTypeInfo::METADATA_INT_IS_INT64)
|
||||||
MAKE_TYPE_INFO(wchar_t, Variant::INT)
|
MAKE_TYPE_INFO(wchar_t, Variant::INT)
|
||||||
MAKE_TYPE_INFO(float, Variant::REAL)
|
MAKE_TYPE_INFO_WITH_META(float, Variant::REAL, GodotTypeInfo::METADATA_REAL_IS_FLOAT)
|
||||||
MAKE_TYPE_INFO(double, Variant::REAL)
|
MAKE_TYPE_INFO_WITH_META(double, Variant::REAL, GodotTypeInfo::METADATA_REAL_IS_DOUBLE)
|
||||||
|
|
||||||
MAKE_TYPE_INFO(String, Variant::STRING)
|
MAKE_TYPE_INFO(String, Variant::STRING)
|
||||||
MAKE_TYPE_INFO(Vector2, Variant::VECTOR2)
|
MAKE_TYPE_INFO(Vector2, Variant::VECTOR2)
|
||||||
@ -138,6 +175,7 @@ MAKE_TYPE_INFO(BSP_Tree, Variant::DICTIONARY)
|
|||||||
template <>
|
template <>
|
||||||
struct GetTypeInfo<RefPtr> {
|
struct GetTypeInfo<RefPtr> {
|
||||||
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||||
static inline PropertyInfo get_class_info() {
|
static inline PropertyInfo get_class_info() {
|
||||||
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference");
|
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference");
|
||||||
}
|
}
|
||||||
@ -145,6 +183,7 @@ struct GetTypeInfo<RefPtr> {
|
|||||||
template <>
|
template <>
|
||||||
struct GetTypeInfo<const RefPtr &> {
|
struct GetTypeInfo<const RefPtr &> {
|
||||||
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||||
static inline PropertyInfo get_class_info() {
|
static inline PropertyInfo get_class_info() {
|
||||||
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference");
|
return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference");
|
||||||
}
|
}
|
||||||
@ -154,6 +193,7 @@ struct GetTypeInfo<const RefPtr &> {
|
|||||||
template <>
|
template <>
|
||||||
struct GetTypeInfo<Variant> {
|
struct GetTypeInfo<Variant> {
|
||||||
static const Variant::Type VARIANT_TYPE = Variant::NIL;
|
static const Variant::Type VARIANT_TYPE = Variant::NIL;
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||||
static inline PropertyInfo get_class_info() {
|
static inline PropertyInfo get_class_info() {
|
||||||
return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
|
return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
|
||||||
}
|
}
|
||||||
@ -162,6 +202,7 @@ struct GetTypeInfo<Variant> {
|
|||||||
template <>
|
template <>
|
||||||
struct GetTypeInfo<const Variant &> {
|
struct GetTypeInfo<const Variant &> {
|
||||||
static const Variant::Type VARIANT_TYPE = Variant::NIL;
|
static const Variant::Type VARIANT_TYPE = Variant::NIL;
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||||
static inline PropertyInfo get_class_info() {
|
static inline PropertyInfo get_class_info() {
|
||||||
return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
|
return PropertyInfo(Variant::NIL, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT);
|
||||||
}
|
}
|
||||||
@ -171,6 +212,7 @@ struct GetTypeInfo<const Variant &> {
|
|||||||
template <> \
|
template <> \
|
||||||
struct GetTypeInfo<m_template<m_type> > { \
|
struct GetTypeInfo<m_template<m_type> > { \
|
||||||
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
|
||||||
static inline PropertyInfo get_class_info() { \
|
static inline PropertyInfo get_class_info() { \
|
||||||
return PropertyInfo(VARIANT_TYPE, String()); \
|
return PropertyInfo(VARIANT_TYPE, String()); \
|
||||||
} \
|
} \
|
||||||
@ -178,6 +220,7 @@ struct GetTypeInfo<const Variant &> {
|
|||||||
template <> \
|
template <> \
|
||||||
struct GetTypeInfo<const m_template<m_type> &> { \
|
struct GetTypeInfo<const m_template<m_type> &> { \
|
||||||
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
static const Variant::Type VARIANT_TYPE = m_var_type; \
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
|
||||||
static inline PropertyInfo get_class_info() { \
|
static inline PropertyInfo get_class_info() { \
|
||||||
return PropertyInfo(VARIANT_TYPE, String()); \
|
return PropertyInfo(VARIANT_TYPE, String()); \
|
||||||
} \
|
} \
|
||||||
@ -202,6 +245,7 @@ MAKE_TEMPLATE_TYPE_INFO(PoolVector, Face3, Variant::POOL_VECTOR3_ARRAY)
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
|
struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
|
||||||
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||||
static inline PropertyInfo get_class_info() {
|
static inline PropertyInfo get_class_info() {
|
||||||
return PropertyInfo(StringName(T::get_class_static()));
|
return PropertyInfo(StringName(T::get_class_static()));
|
||||||
}
|
}
|
||||||
@ -210,6 +254,7 @@ struct GetTypeInfo<T *, typename EnableIf<TypeInherits<Object, T>::value>::type>
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
|
struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>::type> {
|
||||||
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
static const Variant::Type VARIANT_TYPE = Variant::OBJECT;
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE;
|
||||||
static inline PropertyInfo get_class_info() {
|
static inline PropertyInfo get_class_info() {
|
||||||
return PropertyInfo(StringName(T::get_class_static()));
|
return PropertyInfo(StringName(T::get_class_static()));
|
||||||
}
|
}
|
||||||
@ -219,6 +264,7 @@ struct GetTypeInfo<const T *, typename EnableIf<TypeInherits<Object, T>::value>:
|
|||||||
template <> \
|
template <> \
|
||||||
struct GetTypeInfo<m_impl> { \
|
struct GetTypeInfo<m_impl> { \
|
||||||
static const Variant::Type VARIANT_TYPE = Variant::INT; \
|
static const Variant::Type VARIANT_TYPE = Variant::INT; \
|
||||||
|
static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; \
|
||||||
static inline PropertyInfo get_class_info() { \
|
static inline PropertyInfo get_class_info() { \
|
||||||
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, String(#m_enum).replace("::", ".")); \
|
return PropertyInfo(Variant::INT, String(), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CLASS_IS_ENUM, String(#m_enum).replace("::", ".")); \
|
||||||
} \
|
} \
|
||||||
|
@ -131,14 +131,6 @@ void CSharpLanguage::finish() {
|
|||||||
|
|
||||||
finalizing = true;
|
finalizing = true;
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
|
||||||
// Must be here, to avoid StringName leaks
|
|
||||||
if (BindingsGenerator::singleton) {
|
|
||||||
memdelete(BindingsGenerator::singleton);
|
|
||||||
BindingsGenerator::singleton = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Make sure all script binding gchandles are released before finalizing GDMono
|
// Make sure all script binding gchandles are released before finalizing GDMono
|
||||||
for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) {
|
for (Map<Object *, CSharpScriptBinding>::Element *E = script_bindings.front(); E; E = E->next()) {
|
||||||
CSharpScriptBinding &script_binding = E->value();
|
CSharpScriptBinding &script_binding = E->value();
|
||||||
|
@ -97,14 +97,10 @@
|
|||||||
#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
|
#define C_METHOD_MONOARRAY_TO(m_type) C_NS_MONOMARSHAL "::mono_array_to_" #m_type
|
||||||
#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
|
#define C_METHOD_MONOARRAY_FROM(m_type) C_NS_MONOMARSHAL "::" #m_type "_to_mono_array"
|
||||||
|
|
||||||
#define BINDINGS_GENERATOR_VERSION UINT32_C(8)
|
#define BINDINGS_GENERATOR_VERSION UINT32_C(9)
|
||||||
|
|
||||||
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n");
|
const char *BindingsGenerator::TypeInterface::DEFAULT_VARARG_C_IN("\t%0 %1_in = %1;\n");
|
||||||
|
|
||||||
bool BindingsGenerator::verbose_output = false;
|
|
||||||
|
|
||||||
BindingsGenerator *BindingsGenerator::singleton = NULL;
|
|
||||||
|
|
||||||
static String fix_doc_description(const String &p_bbcode) {
|
static String fix_doc_description(const String &p_bbcode) {
|
||||||
|
|
||||||
// This seems to be the correct way to do this. It's the same EditorHelp does.
|
// This seems to be the correct way to do this. It's the same EditorHelp does.
|
||||||
@ -816,9 +812,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
|
|||||||
|
|
||||||
CRASH_COND(enum_class_name != "Variant"); // Hard-coded...
|
CRASH_COND(enum_class_name != "Variant"); // Hard-coded...
|
||||||
|
|
||||||
if (verbose_output) {
|
_log("Declaring global enum `%s` inside static class `%s`\n", enum_proxy_name.utf8().get_data(), enum_class_name.utf8().get_data());
|
||||||
WARN_PRINTS("Declaring global enum `" + enum_proxy_name + "` inside static class `" + enum_class_name + "`");
|
|
||||||
}
|
|
||||||
|
|
||||||
p_output.append("\n" INDENT1 "public static partial class ");
|
p_output.append("\n" INDENT1 "public static partial class ");
|
||||||
p_output.append(enum_class_name);
|
p_output.append(enum_class_name);
|
||||||
@ -867,9 +861,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
|
|||||||
p_output.append("\n#pragma warning restore CS1591\n");
|
p_output.append("\n#pragma warning restore CS1591\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) {
|
Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution) {
|
||||||
|
|
||||||
verbose_output = p_verbose_output;
|
|
||||||
|
|
||||||
String proj_dir = p_solution_dir.plus_file(CORE_API_ASSEMBLY_NAME);
|
String proj_dir = p_solution_dir.plus_file(CORE_API_ASSEMBLY_NAME);
|
||||||
|
|
||||||
@ -1001,15 +993,12 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir,
|
|||||||
|
|
||||||
r_solution.add_new_project(CORE_API_ASSEMBLY_NAME, proj_info);
|
r_solution.add_new_project(CORE_API_ASSEMBLY_NAME, proj_info);
|
||||||
|
|
||||||
if (verbose_output)
|
_log("The solution and C# project for the Core API was generated successfully\n");
|
||||||
OS::get_singleton()->print("The solution and C# project for the Core API was generated successfully\n");
|
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) {
|
Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution) {
|
||||||
|
|
||||||
verbose_output = p_verbose_output;
|
|
||||||
|
|
||||||
String proj_dir = p_solution_dir.plus_file(EDITOR_API_ASSEMBLY_NAME);
|
String proj_dir = p_solution_dir.plus_file(EDITOR_API_ASSEMBLY_NAME);
|
||||||
|
|
||||||
@ -1100,13 +1089,12 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_solution_dir
|
|||||||
|
|
||||||
r_solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, proj_info);
|
r_solution.add_new_project(EDITOR_API_ASSEMBLY_NAME, proj_info);
|
||||||
|
|
||||||
if (verbose_output)
|
_log("The solution and C# project for the Editor API was generated successfully\n");
|
||||||
OS::get_singleton()->print("The solution and C# project for the Editor API was generated successfully\n");
|
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BindingsGenerator::generate_cs_api(const String &p_output_dir, bool p_verbose_output) {
|
Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
|
||||||
|
|
||||||
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||||
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
|
ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
|
||||||
@ -1123,13 +1111,13 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir, bool p_verb
|
|||||||
|
|
||||||
Error proj_err;
|
Error proj_err;
|
||||||
|
|
||||||
proj_err = generate_cs_core_project(p_output_dir, solution, p_verbose_output);
|
proj_err = generate_cs_core_project(p_output_dir, solution);
|
||||||
if (proj_err != OK) {
|
if (proj_err != OK) {
|
||||||
ERR_PRINT("Generation of the Core API C# project failed");
|
ERR_PRINT("Generation of the Core API C# project failed");
|
||||||
return proj_err;
|
return proj_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
proj_err = generate_cs_editor_project(p_output_dir, solution, p_verbose_output);
|
proj_err = generate_cs_editor_project(p_output_dir, solution);
|
||||||
if (proj_err != OK) {
|
if (proj_err != OK) {
|
||||||
ERR_PRINT("Generation of the Editor API C# project failed");
|
ERR_PRINT("Generation of the Editor API C# project failed");
|
||||||
return proj_err;
|
return proj_err;
|
||||||
@ -1168,8 +1156,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||||||
|
|
||||||
List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
|
List<InternalCall> &custom_icalls = itype.api_type == ClassDB::API_EDITOR ? editor_custom_icalls : core_custom_icalls;
|
||||||
|
|
||||||
if (verbose_output)
|
_log("Generating %s.cs...\n", itype.proxy_name.utf8().get_data());
|
||||||
OS::get_singleton()->print("Generating %s.cs...\n", itype.proxy_name.utf8().get_data());
|
|
||||||
|
|
||||||
String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types
|
String ctor_method(ICALL_PREFIX + itype.proxy_name + "_Ctor"); // Used only for derived types
|
||||||
|
|
||||||
@ -1477,7 +1464,13 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
|
|||||||
p_output.append("\n" INDENT2 OPEN_BLOCK);
|
p_output.append("\n" INDENT2 OPEN_BLOCK);
|
||||||
|
|
||||||
if (getter) {
|
if (getter) {
|
||||||
p_output.append(INDENT3 "get\n" OPEN_BLOCK_L3);
|
p_output.append(INDENT3 "get\n"
|
||||||
|
|
||||||
|
// TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
|
||||||
|
"#pragma warning disable CS0618 // Disable warning about obsolete method\n"
|
||||||
|
|
||||||
|
OPEN_BLOCK_L3);
|
||||||
|
|
||||||
p_output.append("return ");
|
p_output.append("return ");
|
||||||
p_output.append(getter->proxy_name + "(");
|
p_output.append(getter->proxy_name + "(");
|
||||||
if (p_iprop.index != -1) {
|
if (p_iprop.index != -1) {
|
||||||
@ -1491,11 +1484,22 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
|
|||||||
p_output.append(itos(p_iprop.index));
|
p_output.append(itos(p_iprop.index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p_output.append(");\n" CLOSE_BLOCK_L3);
|
p_output.append(");\n"
|
||||||
|
|
||||||
|
CLOSE_BLOCK_L3
|
||||||
|
|
||||||
|
// TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
|
||||||
|
"#pragma warning restore CS0618\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setter) {
|
if (setter) {
|
||||||
p_output.append(INDENT3 "set\n" OPEN_BLOCK_L3);
|
p_output.append(INDENT3 "set\n"
|
||||||
|
|
||||||
|
// TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
|
||||||
|
"#pragma warning disable CS0618 // Disable warning about obsolete method\n"
|
||||||
|
|
||||||
|
OPEN_BLOCK_L3);
|
||||||
|
|
||||||
p_output.append(setter->proxy_name + "(");
|
p_output.append(setter->proxy_name + "(");
|
||||||
if (p_iprop.index != -1) {
|
if (p_iprop.index != -1) {
|
||||||
const ArgumentInterface &idx_arg = setter->arguments.front()->get();
|
const ArgumentInterface &idx_arg = setter->arguments.front()->get();
|
||||||
@ -1508,7 +1512,12 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
|
|||||||
p_output.append(itos(p_iprop.index) + ", ");
|
p_output.append(itos(p_iprop.index) + ", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
p_output.append("value);\n" CLOSE_BLOCK_L3);
|
p_output.append("value);\n"
|
||||||
|
|
||||||
|
CLOSE_BLOCK_L3
|
||||||
|
|
||||||
|
// TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
|
||||||
|
"#pragma warning restore CS0618\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
p_output.append(CLOSE_BLOCK_L2);
|
p_output.append(CLOSE_BLOCK_L2);
|
||||||
@ -1636,6 +1645,15 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
|
|||||||
p_output.append("\")]");
|
p_output.append("\")]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p_imethod.is_deprecated) {
|
||||||
|
if (p_imethod.deprecation_message.empty())
|
||||||
|
WARN_PRINTS("An empty deprecation message is discouraged. Method: " + p_imethod.proxy_name);
|
||||||
|
|
||||||
|
p_output.append(MEMBER_BEGIN "[Obsolete(\"");
|
||||||
|
p_output.append(p_imethod.deprecation_message);
|
||||||
|
p_output.append("\")]");
|
||||||
|
}
|
||||||
|
|
||||||
p_output.append(MEMBER_BEGIN);
|
p_output.append(MEMBER_BEGIN);
|
||||||
p_output.append(p_imethod.is_internal ? "internal " : "public ");
|
p_output.append(p_imethod.is_internal ? "internal " : "public ");
|
||||||
|
|
||||||
@ -1710,8 +1728,6 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
|
|||||||
|
|
||||||
Error BindingsGenerator::generate_glue(const String &p_output_dir) {
|
Error BindingsGenerator::generate_glue(const String &p_output_dir) {
|
||||||
|
|
||||||
verbose_output = true;
|
|
||||||
|
|
||||||
bool dir_exists = DirAccess::exists(p_output_dir);
|
bool dir_exists = DirAccess::exists(p_output_dir);
|
||||||
ERR_EXPLAIN("The output directory does not exist.");
|
ERR_EXPLAIN("The output directory does not exist.");
|
||||||
ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH);
|
ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH);
|
||||||
@ -2109,6 +2125,58 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placehol
|
|||||||
return &placeholder_types.insert(placeholder.cname, placeholder)->get();
|
return &placeholder_types.insert(placeholder.cname, placeholder)->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringName BindingsGenerator::_get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta) {
|
||||||
|
|
||||||
|
switch (p_meta) {
|
||||||
|
case GodotTypeInfo::METADATA_INT_IS_INT8:
|
||||||
|
return "sbyte";
|
||||||
|
break;
|
||||||
|
case GodotTypeInfo::METADATA_INT_IS_INT16:
|
||||||
|
return "short";
|
||||||
|
break;
|
||||||
|
case GodotTypeInfo::METADATA_INT_IS_INT32:
|
||||||
|
return "int";
|
||||||
|
break;
|
||||||
|
case GodotTypeInfo::METADATA_INT_IS_INT64:
|
||||||
|
return "long";
|
||||||
|
break;
|
||||||
|
case GodotTypeInfo::METADATA_INT_IS_UINT8:
|
||||||
|
return "byte";
|
||||||
|
break;
|
||||||
|
case GodotTypeInfo::METADATA_INT_IS_UINT16:
|
||||||
|
return "ushort";
|
||||||
|
break;
|
||||||
|
case GodotTypeInfo::METADATA_INT_IS_UINT32:
|
||||||
|
return "uint";
|
||||||
|
break;
|
||||||
|
case GodotTypeInfo::METADATA_INT_IS_UINT64:
|
||||||
|
return "ulong";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Assume INT32
|
||||||
|
return "int";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringName BindingsGenerator::_get_float_type_name_from_meta(GodotTypeInfo::Metadata p_meta) {
|
||||||
|
|
||||||
|
switch (p_meta) {
|
||||||
|
case GodotTypeInfo::METADATA_REAL_IS_FLOAT:
|
||||||
|
return "float";
|
||||||
|
break;
|
||||||
|
case GodotTypeInfo::METADATA_REAL_IS_DOUBLE:
|
||||||
|
return "double";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Assume real_t (float or double depending of REAL_T_IS_DOUBLE)
|
||||||
|
#ifdef REAL_T_IS_DOUBLE
|
||||||
|
return "double";
|
||||||
|
#else
|
||||||
|
return "float";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BindingsGenerator::_populate_object_type_interfaces() {
|
void BindingsGenerator::_populate_object_type_interfaces() {
|
||||||
|
|
||||||
obj_types.clear();
|
obj_types.clear();
|
||||||
@ -2128,15 +2196,13 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!ClassDB::is_class_exposed(type_cname)) {
|
if (!ClassDB::is_class_exposed(type_cname)) {
|
||||||
if (verbose_output)
|
_log("Ignoring type `%s` because it's not exposed\n", String(type_cname).utf8().get_data());
|
||||||
WARN_PRINTS("Ignoring type " + type_cname.operator String() + " because it's not exposed");
|
|
||||||
class_list.pop_front();
|
class_list.pop_front();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ClassDB::is_class_enabled(type_cname)) {
|
if (!ClassDB::is_class_enabled(type_cname)) {
|
||||||
if (verbose_output)
|
_log("Ignoring type `%s` because it's not enabled\n", String(type_cname).utf8().get_data());
|
||||||
WARN_PRINTS("Ignoring type " + type_cname.operator String() + " because it's not enabled");
|
|
||||||
class_list.pop_front();
|
class_list.pop_front();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2164,10 +2230,12 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
|||||||
itype.im_type_in = "IntPtr";
|
itype.im_type_in = "IntPtr";
|
||||||
itype.im_type_out = itype.proxy_name;
|
itype.im_type_out = itype.proxy_name;
|
||||||
|
|
||||||
|
// Populate properties
|
||||||
|
|
||||||
List<PropertyInfo> property_list;
|
List<PropertyInfo> property_list;
|
||||||
ClassDB::get_property_list(type_cname, &property_list, true);
|
ClassDB::get_property_list(type_cname, &property_list, true);
|
||||||
|
|
||||||
// Populate properties
|
Map<StringName, StringName> accessor_methods;
|
||||||
|
|
||||||
for (const List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
|
for (const List<PropertyInfo>::Element *E = property_list.front(); E; E = E->next()) {
|
||||||
const PropertyInfo &property = E->get();
|
const PropertyInfo &property = E->get();
|
||||||
@ -2180,18 +2248,21 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
|||||||
iprop.setter = ClassDB::get_property_setter(type_cname, iprop.cname);
|
iprop.setter = ClassDB::get_property_setter(type_cname, iprop.cname);
|
||||||
iprop.getter = ClassDB::get_property_getter(type_cname, iprop.cname);
|
iprop.getter = ClassDB::get_property_getter(type_cname, iprop.cname);
|
||||||
|
|
||||||
|
if (iprop.setter != StringName())
|
||||||
|
accessor_methods[iprop.setter] = iprop.cname;
|
||||||
|
if (iprop.getter != StringName())
|
||||||
|
accessor_methods[iprop.getter] = iprop.cname;
|
||||||
|
|
||||||
bool valid = false;
|
bool valid = false;
|
||||||
iprop.index = ClassDB::get_property_index(type_cname, iprop.cname, &valid);
|
iprop.index = ClassDB::get_property_index(type_cname, iprop.cname, &valid);
|
||||||
ERR_FAIL_COND(!valid);
|
ERR_FAIL_COND(!valid);
|
||||||
|
|
||||||
iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname));
|
iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname));
|
||||||
|
|
||||||
// Prevent property and enclosing type from sharing the same name
|
// Prevent the property and its enclosing type from sharing the same name
|
||||||
if (iprop.proxy_name == itype.proxy_name) {
|
if (iprop.proxy_name == itype.proxy_name) {
|
||||||
if (verbose_output) {
|
_log("Name of property `%s` is ambiguous with the name of its enclosing class `%s`. Renaming property to `%s_`\n",
|
||||||
WARN_PRINTS("Name of property `" + iprop.proxy_name + "` is ambiguous with the name of its class `" +
|
iprop.proxy_name.utf8().get_data(), itype.proxy_name.utf8().get_data(), iprop.proxy_name.utf8().get_data());
|
||||||
itype.proxy_name + "`. Renaming property to `" + iprop.proxy_name + "_`");
|
|
||||||
}
|
|
||||||
|
|
||||||
iprop.proxy_name += "_";
|
iprop.proxy_name += "_";
|
||||||
}
|
}
|
||||||
@ -2258,14 +2329,13 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
|||||||
// which could actually will return something different.
|
// which could actually will return something different.
|
||||||
// Let's put this to notify us if that ever happens.
|
// Let's put this to notify us if that ever happens.
|
||||||
if (itype.cname != name_cache.type_Object || imethod.name != "free") {
|
if (itype.cname != name_cache.type_Object || imethod.name != "free") {
|
||||||
if (verbose_output) {
|
ERR_PRINTS("Notification: New unexpected virtual non-overridable method found.\n"
|
||||||
WARN_PRINTS("Notification: New unexpected virtual non-overridable method found.\n"
|
|
||||||
"We only expected Object.free, but found " +
|
"We only expected Object.free, but found " +
|
||||||
itype.name + "." + imethod.name);
|
itype.name + "." + imethod.name);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ERR_PRINTS("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name);
|
ERR_EXPLAIN("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name);
|
||||||
|
ERR_FAIL();
|
||||||
}
|
}
|
||||||
} else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
|
} else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
|
||||||
imethod.return_type.cname = return_info.class_name;
|
imethod.return_type.cname = return_info.class_name;
|
||||||
@ -2278,9 +2348,15 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
|||||||
imethod.return_type.cname = name_cache.type_Variant;
|
imethod.return_type.cname = name_cache.type_Variant;
|
||||||
} else if (return_info.type == Variant::NIL) {
|
} else if (return_info.type == Variant::NIL) {
|
||||||
imethod.return_type.cname = name_cache.type_void;
|
imethod.return_type.cname = name_cache.type_void;
|
||||||
|
} else {
|
||||||
|
if (return_info.type == Variant::INT) {
|
||||||
|
imethod.return_type.cname = _get_int_type_name_from_meta(m ? m->get_argument_meta(-1) : GodotTypeInfo::METADATA_NONE);
|
||||||
|
} else if (return_info.type == Variant::REAL) {
|
||||||
|
imethod.return_type.cname = _get_float_type_name_from_meta(m ? m->get_argument_meta(-1) : GodotTypeInfo::METADATA_NONE);
|
||||||
} else {
|
} else {
|
||||||
imethod.return_type.cname = Variant::get_type_name(return_info.type);
|
imethod.return_type.cname = Variant::get_type_name(return_info.type);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
PropertyInfo arginfo = method_info.arguments[i];
|
PropertyInfo arginfo = method_info.arguments[i];
|
||||||
@ -2297,9 +2373,15 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
|||||||
iarg.type.cname = arginfo.hint_string;
|
iarg.type.cname = arginfo.hint_string;
|
||||||
} else if (arginfo.type == Variant::NIL) {
|
} else if (arginfo.type == Variant::NIL) {
|
||||||
iarg.type.cname = name_cache.type_Variant;
|
iarg.type.cname = name_cache.type_Variant;
|
||||||
|
} else {
|
||||||
|
if (arginfo.type == Variant::INT) {
|
||||||
|
iarg.type.cname = _get_int_type_name_from_meta(m ? m->get_argument_meta(i) : GodotTypeInfo::METADATA_NONE);
|
||||||
|
} else if (arginfo.type == Variant::REAL) {
|
||||||
|
iarg.type.cname = _get_float_type_name_from_meta(m ? m->get_argument_meta(i) : GodotTypeInfo::METADATA_NONE);
|
||||||
} else {
|
} else {
|
||||||
iarg.type.cname = Variant::get_type_name(arginfo.type);
|
iarg.type.cname = Variant::get_type_name(arginfo.type);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name));
|
iarg.name = escape_csharp_keyword(snake_to_camel_case(iarg.name));
|
||||||
|
|
||||||
@ -2319,16 +2401,24 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
|||||||
|
|
||||||
imethod.proxy_name = escape_csharp_keyword(snake_to_pascal_case(imethod.name));
|
imethod.proxy_name = escape_csharp_keyword(snake_to_pascal_case(imethod.name));
|
||||||
|
|
||||||
// Prevent naming the property and its enclosing type from sharing the same name
|
// Prevent the method and its enclosing type from sharing the same name
|
||||||
if (imethod.proxy_name == itype.proxy_name) {
|
if (imethod.proxy_name == itype.proxy_name) {
|
||||||
if (verbose_output) {
|
_log("Name of method `%s` is ambiguous with the name of its enclosing class `%s`. Renaming method to `%s_`\n",
|
||||||
WARN_PRINTS("Name of method `" + imethod.proxy_name + "` is ambiguous with the name of its class `" +
|
imethod.proxy_name.utf8().get_data(), itype.proxy_name.utf8().get_data(), imethod.proxy_name.utf8().get_data());
|
||||||
itype.proxy_name + "`. Renaming method to `" + imethod.proxy_name + "_`");
|
|
||||||
}
|
|
||||||
|
|
||||||
imethod.proxy_name += "_";
|
imethod.proxy_name += "_";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<StringName, StringName>::Element *accessor = accessor_methods.find(imethod.cname);
|
||||||
|
if (accessor) {
|
||||||
|
const PropertyInterface *accessor_property = itype.find_property_by_name(accessor->value());
|
||||||
|
|
||||||
|
// We only deprecate an accessor method if it's in the same class as the property. It's easier this way, but also
|
||||||
|
// we don't know if an accessor method in a different class could have other purposes, so better leave those untouched.
|
||||||
|
imethod.is_deprecated = true;
|
||||||
|
imethod.deprecation_message = imethod.proxy_name + " is deprecated. Use the " + accessor_property->proxy_name + " property instead.";
|
||||||
|
}
|
||||||
|
|
||||||
if (itype.class_doc) {
|
if (itype.class_doc) {
|
||||||
for (int i = 0; i < itype.class_doc->methods.size(); i++) {
|
for (int i = 0; i < itype.class_doc->methods.size(); i++) {
|
||||||
if (itype.class_doc->methods[i].name == imethod.name) {
|
if (itype.class_doc->methods[i].name == imethod.name) {
|
||||||
@ -2556,7 +2646,6 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
|
|||||||
|
|
||||||
// bool
|
// bool
|
||||||
itype = TypeInterface::create_value_type(String("bool"));
|
itype = TypeInterface::create_value_type(String("bool"));
|
||||||
|
|
||||||
{
|
{
|
||||||
// MonoBoolean <---> bool
|
// MonoBoolean <---> bool
|
||||||
itype.c_in = "\t%0 %1_in = (%0)%1;\n";
|
itype.c_in = "\t%0 %1_in = (%0)%1;\n";
|
||||||
@ -2570,39 +2659,52 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
|
|||||||
itype.im_type_out = itype.name;
|
itype.im_type_out = itype.name;
|
||||||
builtin_types.insert(itype.cname, itype);
|
builtin_types.insert(itype.cname, itype);
|
||||||
|
|
||||||
// int
|
// Integer types
|
||||||
// C interface is the same as that of enums. Remember to apply any
|
|
||||||
// changes done here to TypeInterface::postsetup_enum_type as well
|
|
||||||
itype = TypeInterface::create_value_type(String("int"));
|
|
||||||
itype.c_arg_in = "&%s_in";
|
|
||||||
{
|
{
|
||||||
// The expected types for parameters and return value in ptrcall are 'int64_t' or 'uint64_t'.
|
// C interface for 'uint32_t' is the same as that of enums. Remember to apply
|
||||||
itype.c_in = "\t%0 %1_in = (%0)%1;\n";
|
// any of the changes done here to 'TypeInterface::postsetup_enum_type' as well.
|
||||||
itype.c_out = "\treturn (%0)%1;\n";
|
#define INSERT_INT_TYPE(m_name, m_c_type_in_out, m_c_type) \
|
||||||
itype.c_type = "int64_t";
|
{ \
|
||||||
|
itype = TypeInterface::create_value_type(String(m_name)); \
|
||||||
|
{ \
|
||||||
|
itype.c_in = "\t%0 %1_in = (%0)%1;\n"; \
|
||||||
|
itype.c_out = "\treturn (%0)%1;\n"; \
|
||||||
|
itype.c_type = #m_c_type; \
|
||||||
|
itype.c_arg_in = "&%s_in"; \
|
||||||
|
} \
|
||||||
|
itype.c_type_in = #m_c_type_in_out; \
|
||||||
|
itype.c_type_out = itype.c_type_in; \
|
||||||
|
itype.im_type_in = itype.name; \
|
||||||
|
itype.im_type_out = itype.name; \
|
||||||
|
builtin_types.insert(itype.cname, itype); \
|
||||||
}
|
}
|
||||||
itype.c_type_in = "int32_t";
|
|
||||||
itype.c_type_out = itype.c_type_in;
|
|
||||||
itype.im_type_in = itype.name;
|
|
||||||
itype.im_type_out = itype.name;
|
|
||||||
builtin_types.insert(itype.cname, itype);
|
|
||||||
|
|
||||||
// real_t
|
// The expected type for all integers in ptrcall is 'int64_t', so that's what we use for 'c_type'
|
||||||
itype = TypeInterface();
|
|
||||||
itype.name = "float"; // The name is always "float" in Variant, even with REAL_T_IS_DOUBLE.
|
INSERT_INT_TYPE("sbyte", int8_t, int64_t);
|
||||||
itype.cname = itype.name;
|
INSERT_INT_TYPE("short", int16_t, int64_t);
|
||||||
#ifdef REAL_T_IS_DOUBLE
|
INSERT_INT_TYPE("int", int32_t, int64_t);
|
||||||
itype.proxy_name = "double";
|
INSERT_INT_TYPE("long", int64_t, int64_t);
|
||||||
#else
|
INSERT_INT_TYPE("byte", uint8_t, int64_t);
|
||||||
itype.proxy_name = "float";
|
INSERT_INT_TYPE("ushort", uint16_t, int64_t);
|
||||||
#endif
|
INSERT_INT_TYPE("uint", uint32_t, int64_t);
|
||||||
|
INSERT_INT_TYPE("ulong", uint64_t, int64_t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Floating point types
|
||||||
{
|
{
|
||||||
// The expected type for parameters and return value in ptrcall is 'double'.
|
// float
|
||||||
|
itype = TypeInterface();
|
||||||
|
itype.name = "float";
|
||||||
|
itype.cname = itype.name;
|
||||||
|
itype.proxy_name = "float";
|
||||||
|
{
|
||||||
|
// The expected type for 'float' in ptrcall is 'double'
|
||||||
itype.c_in = "\t%0 %1_in = (%0)%1;\n";
|
itype.c_in = "\t%0 %1_in = (%0)%1;\n";
|
||||||
itype.c_out = "\treturn (%0)%1;\n";
|
itype.c_out = "\treturn (%0)%1;\n";
|
||||||
itype.c_type = "double";
|
itype.c_type = "double";
|
||||||
itype.c_type_in = "real_t";
|
itype.c_type_in = "float";
|
||||||
itype.c_type_out = "real_t";
|
itype.c_type_out = "float";
|
||||||
itype.c_arg_in = "&%s_in";
|
itype.c_arg_in = "&%s_in";
|
||||||
}
|
}
|
||||||
itype.cs_type = itype.proxy_name;
|
itype.cs_type = itype.proxy_name;
|
||||||
@ -2610,6 +2712,21 @@ void BindingsGenerator::_populate_builtin_type_interfaces() {
|
|||||||
itype.im_type_out = itype.proxy_name;
|
itype.im_type_out = itype.proxy_name;
|
||||||
builtin_types.insert(itype.cname, itype);
|
builtin_types.insert(itype.cname, itype);
|
||||||
|
|
||||||
|
// double
|
||||||
|
itype = TypeInterface();
|
||||||
|
itype.name = "double";
|
||||||
|
itype.cname = itype.name;
|
||||||
|
itype.proxy_name = "double";
|
||||||
|
itype.c_type = "double";
|
||||||
|
itype.c_type_in = "double";
|
||||||
|
itype.c_type_out = "double";
|
||||||
|
itype.c_arg_in = "&%s";
|
||||||
|
itype.cs_type = itype.proxy_name;
|
||||||
|
itype.im_type_in = itype.proxy_name;
|
||||||
|
itype.im_type_out = itype.proxy_name;
|
||||||
|
builtin_types.insert(itype.cname, itype);
|
||||||
|
}
|
||||||
|
|
||||||
// String
|
// String
|
||||||
itype = TypeInterface();
|
itype = TypeInterface();
|
||||||
itype.name = "String";
|
itype.name = "String";
|
||||||
@ -2858,7 +2975,18 @@ void BindingsGenerator::_populate_global_constants() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BindingsGenerator::initialize() {
|
void BindingsGenerator::_log(const char *p_format, ...) {
|
||||||
|
|
||||||
|
if (log_print_enabled) {
|
||||||
|
va_list list;
|
||||||
|
|
||||||
|
va_start(list, p_format);
|
||||||
|
OS::get_singleton()->print("%s", str_format(p_format, list).utf8().get_data());
|
||||||
|
va_end(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsGenerator::_initialize() {
|
||||||
|
|
||||||
EditorHelp::generate_doc();
|
EditorHelp::generate_doc();
|
||||||
|
|
||||||
@ -2881,12 +3009,13 @@ void BindingsGenerator::initialize() {
|
|||||||
void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
|
void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args) {
|
||||||
|
|
||||||
const int NUM_OPTIONS = 2;
|
const int NUM_OPTIONS = 2;
|
||||||
int options_left = NUM_OPTIONS;
|
|
||||||
|
|
||||||
String mono_glue_option = "--generate-mono-glue";
|
String mono_glue_option = "--generate-mono-glue";
|
||||||
String cs_api_option = "--generate-cs-api";
|
String cs_api_option = "--generate-cs-api";
|
||||||
|
|
||||||
verbose_output = true;
|
String mono_glue_path;
|
||||||
|
String cs_api_path;
|
||||||
|
|
||||||
|
int options_left = NUM_OPTIONS;
|
||||||
|
|
||||||
const List<String>::Element *elem = p_cmdline_args.front();
|
const List<String>::Element *elem = p_cmdline_args.front();
|
||||||
|
|
||||||
@ -2895,8 +3024,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
|
|||||||
const List<String>::Element *path_elem = elem->next();
|
const List<String>::Element *path_elem = elem->next();
|
||||||
|
|
||||||
if (path_elem) {
|
if (path_elem) {
|
||||||
if (get_singleton()->generate_glue(path_elem->get()) != OK)
|
mono_glue_path = path_elem->get();
|
||||||
ERR_PRINTS(mono_glue_option + ": Failed to generate mono glue");
|
|
||||||
elem = elem->next();
|
elem = elem->next();
|
||||||
} else {
|
} else {
|
||||||
ERR_PRINTS(mono_glue_option + ": No output directory specified");
|
ERR_PRINTS(mono_glue_option + ": No output directory specified");
|
||||||
@ -2907,8 +3035,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
|
|||||||
const List<String>::Element *path_elem = elem->next();
|
const List<String>::Element *path_elem = elem->next();
|
||||||
|
|
||||||
if (path_elem) {
|
if (path_elem) {
|
||||||
if (get_singleton()->generate_cs_api(path_elem->get()) != OK)
|
cs_api_path = path_elem->get();
|
||||||
ERR_PRINTS(cs_api_option + ": Failed to generate the C# API");
|
|
||||||
elem = elem->next();
|
elem = elem->next();
|
||||||
} else {
|
} else {
|
||||||
ERR_PRINTS(cs_api_option + ": No output directory specified");
|
ERR_PRINTS(cs_api_option + ": No output directory specified");
|
||||||
@ -2920,10 +3047,23 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
|
|||||||
elem = elem->next();
|
elem = elem->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
verbose_output = false;
|
if (mono_glue_path.length() || cs_api_path.length()) {
|
||||||
|
BindingsGenerator bindings_generator;
|
||||||
|
bindings_generator.set_log_print_enabled(true);
|
||||||
|
|
||||||
if (options_left != NUM_OPTIONS)
|
if (mono_glue_path.length()) {
|
||||||
|
if (bindings_generator.generate_glue(mono_glue_path) != OK)
|
||||||
|
ERR_PRINTS(mono_glue_option + ": Failed to generate mono glue");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cs_api_path.length()) {
|
||||||
|
if (bindings_generator.generate_cs_api(cs_api_path) != OK)
|
||||||
|
ERR_PRINTS(cs_api_option + ": Failed to generate the C# API");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit once done
|
||||||
::exit(0);
|
::exit(0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -159,17 +159,20 @@ class BindingsGenerator {
|
|||||||
|
|
||||||
const DocData::MethodDoc *method_doc;
|
const DocData::MethodDoc *method_doc;
|
||||||
|
|
||||||
|
bool is_deprecated;
|
||||||
|
String deprecation_message;
|
||||||
|
|
||||||
void add_argument(const ArgumentInterface &argument) {
|
void add_argument(const ArgumentInterface &argument) {
|
||||||
arguments.push_back(argument);
|
arguments.push_back(argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodInterface() {
|
MethodInterface() {
|
||||||
return_type.cname = BindingsGenerator::get_singleton()->name_cache.type_void;
|
|
||||||
is_vararg = false;
|
is_vararg = false;
|
||||||
is_virtual = false;
|
is_virtual = false;
|
||||||
requires_object_call = false;
|
requires_object_call = false;
|
||||||
is_internal = false;
|
is_internal = false;
|
||||||
method_doc = NULL;
|
method_doc = NULL;
|
||||||
|
is_deprecated = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -400,8 +403,8 @@ class BindingsGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void postsetup_enum_type(TypeInterface &r_enum_itype) {
|
static void postsetup_enum_type(TypeInterface &r_enum_itype) {
|
||||||
// C interface is the same as that of 'int'. Remember to apply any
|
// C interface for enums is the same as that of 'uint32_t'. Remember to apply
|
||||||
// changes done here to the 'int' type interface as well
|
// any of the changes done here to the 'uint32_t' type interface as well.
|
||||||
|
|
||||||
r_enum_itype.c_arg_in = "&%s_in";
|
r_enum_itype.c_arg_in = "&%s_in";
|
||||||
{
|
{
|
||||||
@ -469,7 +472,7 @@ class BindingsGenerator {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool verbose_output;
|
bool log_print_enabled;
|
||||||
|
|
||||||
OrderedHashMap<StringName, TypeInterface> obj_types;
|
OrderedHashMap<StringName, TypeInterface> obj_types;
|
||||||
|
|
||||||
@ -490,7 +493,6 @@ class BindingsGenerator {
|
|||||||
|
|
||||||
struct NameCache {
|
struct NameCache {
|
||||||
StringName type_void;
|
StringName type_void;
|
||||||
StringName type_int;
|
|
||||||
StringName type_Array;
|
StringName type_Array;
|
||||||
StringName type_Dictionary;
|
StringName type_Dictionary;
|
||||||
StringName type_Variant;
|
StringName type_Variant;
|
||||||
@ -501,9 +503,19 @@ class BindingsGenerator {
|
|||||||
StringName type_at_GlobalScope;
|
StringName type_at_GlobalScope;
|
||||||
StringName enum_Error;
|
StringName enum_Error;
|
||||||
|
|
||||||
|
StringName type_sbyte;
|
||||||
|
StringName type_short;
|
||||||
|
StringName type_int;
|
||||||
|
StringName type_long;
|
||||||
|
StringName type_byte;
|
||||||
|
StringName type_ushort;
|
||||||
|
StringName type_uint;
|
||||||
|
StringName type_ulong;
|
||||||
|
StringName type_float;
|
||||||
|
StringName type_double;
|
||||||
|
|
||||||
NameCache() {
|
NameCache() {
|
||||||
type_void = StaticCString::create("void");
|
type_void = StaticCString::create("void");
|
||||||
type_int = StaticCString::create("int");
|
|
||||||
type_Array = StaticCString::create("Array");
|
type_Array = StaticCString::create("Array");
|
||||||
type_Dictionary = StaticCString::create("Dictionary");
|
type_Dictionary = StaticCString::create("Dictionary");
|
||||||
type_Variant = StaticCString::create("Variant");
|
type_Variant = StaticCString::create("Variant");
|
||||||
@ -513,8 +525,20 @@ class BindingsGenerator {
|
|||||||
type_String = StaticCString::create("String");
|
type_String = StaticCString::create("String");
|
||||||
type_at_GlobalScope = StaticCString::create("@GlobalScope");
|
type_at_GlobalScope = StaticCString::create("@GlobalScope");
|
||||||
enum_Error = StaticCString::create("Error");
|
enum_Error = StaticCString::create("Error");
|
||||||
|
|
||||||
|
type_sbyte = StaticCString::create("sbyte");
|
||||||
|
type_short = StaticCString::create("short");
|
||||||
|
type_int = StaticCString::create("int");
|
||||||
|
type_long = StaticCString::create("long");
|
||||||
|
type_byte = StaticCString::create("byte");
|
||||||
|
type_ushort = StaticCString::create("ushort");
|
||||||
|
type_uint = StaticCString::create("uint");
|
||||||
|
type_ulong = StaticCString::create("ulong");
|
||||||
|
type_float = StaticCString::create("float");
|
||||||
|
type_double = StaticCString::create("double");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
NameCache(const NameCache &);
|
NameCache(const NameCache &);
|
||||||
NameCache &operator=(const NameCache &);
|
NameCache &operator=(const NameCache &);
|
||||||
};
|
};
|
||||||
@ -560,6 +584,9 @@ class BindingsGenerator {
|
|||||||
const TypeInterface *_get_type_or_null(const TypeReference &p_typeref);
|
const TypeInterface *_get_type_or_null(const TypeReference &p_typeref);
|
||||||
const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref);
|
const TypeInterface *_get_type_or_placeholder(const TypeReference &p_typeref);
|
||||||
|
|
||||||
|
StringName _get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta);
|
||||||
|
StringName _get_float_type_name_from_meta(GodotTypeInfo::Metadata p_meta);
|
||||||
|
|
||||||
void _default_argument_from_variant(const Variant &p_val, ArgumentInterface &r_iarg);
|
void _default_argument_from_variant(const Variant &p_val, ArgumentInterface &r_iarg);
|
||||||
|
|
||||||
void _populate_object_type_interfaces();
|
void _populate_object_type_interfaces();
|
||||||
@ -578,33 +605,26 @@ class BindingsGenerator {
|
|||||||
|
|
||||||
Error _save_file(const String &p_path, const StringBuilder &p_content);
|
Error _save_file(const String &p_path, const StringBuilder &p_content);
|
||||||
|
|
||||||
BindingsGenerator() {}
|
void _log(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
|
||||||
|
|
||||||
BindingsGenerator(const BindingsGenerator &);
|
void _initialize();
|
||||||
BindingsGenerator &operator=(const BindingsGenerator &);
|
|
||||||
|
|
||||||
friend class CSharpLanguage;
|
|
||||||
static BindingsGenerator *singleton;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Error generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output = true);
|
Error generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution);
|
||||||
Error generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output = true);
|
Error generate_cs_editor_project(const String &p_solution_dir, DotNetSolution &r_solution);
|
||||||
Error generate_cs_api(const String &p_output_dir, bool p_verbose_output = true);
|
Error generate_cs_api(const String &p_output_dir);
|
||||||
Error generate_glue(const String &p_output_dir);
|
Error generate_glue(const String &p_output_dir);
|
||||||
|
|
||||||
|
void set_log_print_enabled(bool p_enabled) { log_print_enabled = p_enabled; }
|
||||||
|
|
||||||
static uint32_t get_version();
|
static uint32_t get_version();
|
||||||
|
|
||||||
void initialize();
|
|
||||||
|
|
||||||
_FORCE_INLINE_ static BindingsGenerator *get_singleton() {
|
|
||||||
if (!singleton) {
|
|
||||||
singleton = memnew(BindingsGenerator);
|
|
||||||
singleton->initialize();
|
|
||||||
}
|
|
||||||
return singleton;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_cmdline_args(const List<String> &p_cmdline_args);
|
static void handle_cmdline_args(const List<String> &p_cmdline_args);
|
||||||
|
|
||||||
|
BindingsGenerator() :
|
||||||
|
log_print_enabled(true) {
|
||||||
|
_initialize();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -323,10 +323,13 @@ bool GodotSharpBuilds::make_api_assembly(APIAssembly::Type p_api_type) {
|
|||||||
String api_sln_file = api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
|
String api_sln_file = api_sln_dir.plus_file(API_SOLUTION_NAME ".sln");
|
||||||
|
|
||||||
if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) {
|
if (!DirAccess::exists(api_sln_dir) || !FileAccess::exists(api_sln_file)) {
|
||||||
BindingsGenerator *gen = BindingsGenerator::get_singleton();
|
BindingsGenerator bindings_generator;
|
||||||
bool gen_verbose = OS::get_singleton()->is_stdout_verbose();
|
|
||||||
|
|
||||||
Error err = gen->generate_cs_api(api_sln_dir, gen_verbose);
|
if (!OS::get_singleton()->is_stdout_verbose()) {
|
||||||
|
bindings_generator.set_log_print_enabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error err = bindings_generator.generate_cs_api(api_sln_dir);
|
||||||
if (err != OK) {
|
if (err != OK) {
|
||||||
show_build_error_dialog("Failed to generate " API_SOLUTION_NAME " solution. Error: " + itos(err));
|
show_build_error_dialog("Failed to generate " API_SOLUTION_NAME " solution. Error: " + itos(err));
|
||||||
return false;
|
return false;
|
||||||
|
@ -111,7 +111,7 @@ namespace Godot
|
|||||||
godot_icall_GD_printt(Array.ConvertAll(what, x => x.ToString()));
|
godot_icall_GD_printt(Array.ConvertAll(what, x => x.ToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double Randf()
|
public static float Randf()
|
||||||
{
|
{
|
||||||
return godot_icall_GD_randf();
|
return godot_icall_GD_randf();
|
||||||
}
|
}
|
||||||
@ -224,7 +224,7 @@ namespace Godot
|
|||||||
internal extern static void godot_icall_GD_printt(object[] what);
|
internal extern static void godot_icall_GD_printt(object[] what);
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
internal extern static double godot_icall_GD_randf();
|
internal extern static float godot_icall_GD_randf();
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
internal extern static uint godot_icall_GD_randi();
|
internal extern static uint godot_icall_GD_randi();
|
||||||
@ -232,6 +232,7 @@ namespace Godot
|
|||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
internal extern static void godot_icall_GD_randomize();
|
internal extern static void godot_icall_GD_randomize();
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||||
internal extern static double godot_icall_GD_rand_range(double from, double to);
|
internal extern static double godot_icall_GD_rand_range(double from, double to);
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ void godot_icall_GD_printt(MonoArray *p_what) {
|
|||||||
print_line(str);
|
print_line(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
double godot_icall_GD_randf() {
|
float godot_icall_GD_randf() {
|
||||||
return Math::randf();
|
return Math::randf();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ void godot_icall_GD_prints(MonoArray *p_what);
|
|||||||
|
|
||||||
void godot_icall_GD_printt(MonoArray *p_what);
|
void godot_icall_GD_printt(MonoArray *p_what);
|
||||||
|
|
||||||
double godot_icall_GD_randf();
|
float godot_icall_GD_randf();
|
||||||
|
|
||||||
uint32_t godot_icall_GD_randi();
|
uint32_t godot_icall_GD_randi();
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "core/os/os.h"
|
#include "core/os/os.h"
|
||||||
|
|
||||||
#include "../godotsharp_dirs.h"
|
#include "../godotsharp_dirs.h"
|
||||||
|
#include "../utils/string_utils.h"
|
||||||
|
|
||||||
static int log_level_get_id(const char *p_log_level) {
|
static int log_level_get_id(const char *p_log_level) {
|
||||||
|
|
||||||
@ -125,27 +126,6 @@ void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
|
|||||||
da->list_dir_end();
|
da->list_dir_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
static String format(const char *p_fmt, ...) {
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, p_fmt);
|
|
||||||
int len = vsnprintf(NULL, 0, p_fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
len += 1; // for the trailing '/0'
|
|
||||||
|
|
||||||
char *buffer(memnew_arr(char, len));
|
|
||||||
|
|
||||||
va_start(args, p_fmt);
|
|
||||||
vsnprintf(buffer, len, p_fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
String res(buffer);
|
|
||||||
memdelete_arr(buffer);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GDMonoLog::initialize() {
|
void GDMonoLog::initialize() {
|
||||||
|
|
||||||
CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8();
|
CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8();
|
||||||
@ -172,7 +152,7 @@ void GDMonoLog::initialize() {
|
|||||||
OS::Time time_now = OS::get_singleton()->get_time();
|
OS::Time time_now = OS::get_singleton()->get_time();
|
||||||
int pid = OS::get_singleton()->get_process_id();
|
int pid = OS::get_singleton()->get_process_id();
|
||||||
|
|
||||||
String log_file_name = format("%d_%02d_%02d %02d.%02d.%02d (%d).txt",
|
String log_file_name = str_format("%d_%02d_%02d %02d.%02d.%02d (%d).txt",
|
||||||
date_now.year, date_now.month, date_now.day,
|
date_now.year, date_now.month, date_now.day,
|
||||||
time_now.hour, time_now.min, time_now.sec, pid);
|
time_now.hour, time_now.min, time_now.sec, pid);
|
||||||
|
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
|
|
||||||
#include "core/os/file_access.h"
|
#include "core/os/file_access.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
int sfind(const String &p_text, int p_from) {
|
int sfind(const String &p_text, int p_from) {
|
||||||
@ -184,3 +186,50 @@ Error read_all_file_utf8(const String &p_path, String &r_content) {
|
|||||||
r_content = source;
|
r_content = source;
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Move to variadic templates once we upgrade to C++11
|
||||||
|
|
||||||
|
String str_format(const char *p_format, ...) {
|
||||||
|
va_list list;
|
||||||
|
|
||||||
|
va_start(list, p_format);
|
||||||
|
String res = str_format(p_format, list);
|
||||||
|
va_end(list);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
// va_copy was defined in the C99, but not in C++ standards before C++11.
|
||||||
|
// When you compile C++ without --std=c++<XX> option, compilers still define
|
||||||
|
// va_copy, otherwise you have to use the internal version (__va_copy).
|
||||||
|
#if !defined(va_copy)
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define va_copy(d, s) __va_copy((d), (s))
|
||||||
|
#else
|
||||||
|
#define va_copy(d, s) ((d) = (s))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(MINGW_ENABLED) || defined(_MSC_VER)
|
||||||
|
#define vsnprintf vsnprintf_s
|
||||||
|
#endif
|
||||||
|
|
||||||
|
String str_format(const char *p_format, va_list p_list) {
|
||||||
|
va_list list;
|
||||||
|
|
||||||
|
va_copy(list, p_list);
|
||||||
|
int len = vsnprintf(NULL, 0, p_format, list);
|
||||||
|
va_end(list);
|
||||||
|
|
||||||
|
len += 1; // for the trailing '/0'
|
||||||
|
|
||||||
|
char *buffer(memnew_arr(char, len));
|
||||||
|
|
||||||
|
va_copy(list, p_list);
|
||||||
|
vsnprintf(buffer, len, p_format, list);
|
||||||
|
va_end(list);
|
||||||
|
|
||||||
|
String res(buffer);
|
||||||
|
memdelete_arr(buffer);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
#include "core/ustring.h"
|
#include "core/ustring.h"
|
||||||
#include "core/variant.h"
|
#include "core/variant.h"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
String sformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant());
|
String sformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant());
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
@ -44,4 +46,15 @@ String escape_csharp_keyword(const String &p_name);
|
|||||||
|
|
||||||
Error read_all_file_utf8(const String &p_path, String &r_content);
|
Error read_all_file_utf8(const String &p_path, String &r_content);
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define _PRINTF_FORMAT_ATTRIBUTE_1_0 __attribute__((format(printf, 1, 0)))
|
||||||
|
#define _PRINTF_FORMAT_ATTRIBUTE_1_2 __attribute__((format(printf, 1, 2)))
|
||||||
|
#else
|
||||||
|
#define _PRINTF_FORMAT_ATTRIBUTE_1_0
|
||||||
|
#define _PRINTF_FORMAT_ATTRIBUTE_1_2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
String str_format(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_1_2;
|
||||||
|
String str_format(const char *p_format, va_list p_list) _PRINTF_FORMAT_ATTRIBUTE_1_0;
|
||||||
|
|
||||||
#endif // STRING_FORMAT_H
|
#endif // STRING_FORMAT_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user