Skip to content

Commit

Permalink
Merge pull request #931 from Spartan322/4.3.1-cherry-pick/bugs-core
Browse files Browse the repository at this point in the history
[4.3] Cherry-picks for the 4.3 (4.3.1) branch - 1st core bugs batch
  • Loading branch information
Spartan322 authored Jan 18, 2025
2 parents 66372fa + 2f0f68c commit 859eefd
Show file tree
Hide file tree
Showing 51 changed files with 700 additions and 423 deletions.
33 changes: 22 additions & 11 deletions core/io/resource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,31 +100,42 @@ void Resource::set_path_cache(const String &p_path) {
path_cache = p_path;
}

static thread_local RandomPCG unique_id_gen(0, RandomPCG::DEFAULT_INC);

void Resource::seed_scene_unique_id(uint32_t p_seed) {
unique_id_gen.seed(p_seed);
}

String Resource::generate_scene_unique_id() {
// Generate a unique enough hash, but still user-readable.
// If it's not unique it does not matter because the saver will try again.
OS::DateTime dt = OS::get_singleton()->get_datetime();
uint32_t hash = hash_murmur3_one_32(OS::get_singleton()->get_ticks_usec());
hash = hash_murmur3_one_32(dt.year, hash);
hash = hash_murmur3_one_32(dt.month, hash);
hash = hash_murmur3_one_32(dt.day, hash);
hash = hash_murmur3_one_32(dt.hour, hash);
hash = hash_murmur3_one_32(dt.minute, hash);
hash = hash_murmur3_one_32(dt.second, hash);
hash = hash_murmur3_one_32(Math::rand(), hash);
if (unique_id_gen.get_seed() == 0) {
OS::DateTime dt = OS::get_singleton()->get_datetime();
uint32_t hash = hash_murmur3_one_32(OS::get_singleton()->get_ticks_usec());
hash = hash_murmur3_one_32(dt.year, hash);
hash = hash_murmur3_one_32(dt.month, hash);
hash = hash_murmur3_one_32(dt.day, hash);
hash = hash_murmur3_one_32(dt.hour, hash);
hash = hash_murmur3_one_32(dt.minute, hash);
hash = hash_murmur3_one_32(dt.second, hash);
hash = hash_murmur3_one_32(Math::rand(), hash);
unique_id_gen.seed(hash);
}

uint32_t random_num = unique_id_gen.rand();

static constexpr uint32_t characters = 5;
static constexpr uint32_t char_count = ('z' - 'a');
static constexpr uint32_t base = char_count + ('9' - '0');
String id;
for (uint32_t i = 0; i < characters; i++) {
uint32_t c = hash % base;
uint32_t c = random_num % base;
if (c < char_count) {
id += String::chr('a' + c);
} else {
id += String::chr('0' + (c - char_count));
}
hash /= base;
random_num /= base;
}

return id;
Expand Down
1 change: 1 addition & 0 deletions core/io/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ class Resource : public RefCounted {
virtual void set_path_cache(const String &p_path); // Set raw path without involving resource cache.
_FORCE_INLINE_ bool is_built_in() const { return path_cache.is_empty() || path_cache.contains("::") || path_cache.begins_with("local://"); }

static void seed_scene_unique_id(uint32_t p_seed);
static String generate_scene_unique_id();
void set_scene_unique_id(const String &p_id);
String get_scene_unique_id() const;
Expand Down
2 changes: 2 additions & 0 deletions core/io/resource_format_binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2121,6 +2121,8 @@ static String _resource_get_class(Ref<Resource> p_resource) {
}

Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
Resource::seed_scene_unique_id(p_path.hash());

Error err;
Ref<FileAccess> f;
if (p_flags & ResourceSaver::FLAG_COMPRESS) {
Expand Down
22 changes: 21 additions & 1 deletion core/io/resource_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,14 +307,34 @@ Ref<Resource> ResourceLoader::_load(const String &p_path, const String &p_origin
return res;
}

#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
if (ResourceFormatImporter::get_singleton()->get_importer_by_extension(p_path.get_extension()).is_valid()) {
// The format is known to the editor, but the file hasn't been imported
// (otherwise, ResourceFormatImporter would have been found as a suitable loader).
found = true;
if (r_error) {
*r_error = ERR_FILE_NOT_FOUND;
}
}
}
#endif
ERR_FAIL_COND_V_MSG(found, Ref<Resource>(),
vformat("Failed loading resource: %s. Make sure resources have been imported by opening the project in the editor at least once.", p_path));

#ifdef TOOLS_ENABLED
Ref<FileAccess> file_check = FileAccess::create(FileAccess::ACCESS_RESOURCES);
ERR_FAIL_COND_V_MSG(!file_check->file_exists(p_path), Ref<Resource>(), vformat("Resource file not found: %s (expected type: %s)", p_path, p_type_hint));
if (!file_check->file_exists(p_path)) {
if (r_error) {
*r_error = ERR_FILE_NOT_FOUND;
}
ERR_FAIL_V_MSG(Ref<Resource>(), vformat("Resource file not found: %s (expected type: %s)", p_path, p_type_hint));
}
#endif

if (r_error) {
*r_error = ERR_FILE_UNRECOGNIZED;
}
ERR_FAIL_V_MSG(Ref<Resource>(), vformat("No loader found for resource: %s (expected type: %s)", p_path, p_type_hint));
}

Expand Down
137 changes: 48 additions & 89 deletions core/object/callable_method_pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
#include "core/variant/binder_common.h"
#include "core/variant/callable.h"

#include <type_traits>

class CallableCustomMethodPointerBase : public CallableCustom {
uint32_t *comp_ptr = nullptr;
uint32_t comp_size;
Expand Down Expand Up @@ -79,12 +81,13 @@ class CallableCustomMethodPointerBase : public CallableCustom {
virtual uint32_t hash() const;
};

template <typename T, typename... P>
template <typename T, typename R, typename... P>
class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
uint64_t object_id;
void (T::*method)(P...);
R(T::*method)
(P...);
} data;

public:
Expand All @@ -102,10 +105,14 @@ class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {

virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
if constexpr (std::is_same<R, void>::value) {
call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
} else {
call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
}

CallableCustomMethodPointer(T *p_instance, void (T::*p_method)(P...)) {
CallableCustomMethodPointer(T *p_instance, R (T::*p_method)(P...)) {
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance;
data.object_id = p_instance->get_instance_id();
Expand All @@ -120,70 +127,32 @@ Callable create_custom_callable_function_pointer(T *p_instance,
const char *p_func_text,
#endif
void (T::*p_method)(P...)) {
typedef CallableCustomMethodPointer<T, P...> CCMP; // Messes with memnew otherwise.
typedef CallableCustomMethodPointer<T, void, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
#ifdef DEBUG_METHODS_ENABLED
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
#endif
return Callable(ccmp);
}

// VERSION WITH RETURN

template <typename T, typename R, typename... P>
class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
uint64_t object_id;
R(T::*method)
(P...);
} data;

public:
virtual ObjectID get_object() const {
if (ObjectDB::get_instance(ObjectID(data.object_id)) == nullptr) {
return ObjectID();
}
return data.instance->get_instance_id();
}

virtual int get_argument_count(bool &r_is_valid) const {
r_is_valid = true;
return sizeof...(P);
}

virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}

CallableCustomMethodPointerRet(T *p_instance, R (T::*p_method)(P...)) {
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance;
data.object_id = p_instance->get_instance_id();
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};

template <typename T, typename R, typename... P>
Callable create_custom_callable_function_pointer(T *p_instance,
#ifdef DEBUG_METHODS_ENABLED
const char *p_func_text,
#endif
R (T::*p_method)(P...)) {
typedef CallableCustomMethodPointerRet<T, R, P...> CCMP; // Messes with memnew otherwise.
typedef CallableCustomMethodPointer<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
#ifdef DEBUG_METHODS_ENABLED
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
#endif
return Callable(ccmp);
}

// CONST VERSION WITH RETURN
// CONST VERSION

template <typename T, typename R, typename... P>
class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
class CallableCustomMethodPointerC : public CallableCustomMethodPointerBase {
struct Data {
T *instance;
uint64_t object_id;
Expand All @@ -206,10 +175,14 @@ class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {

virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
if constexpr (std::is_same<R, void>::value) {
call_with_variant_argsc(data.instance, data.method, p_arguments, p_argcount, r_call_error);
} else {
call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
}

CallableCustomMethodPointerRetC(T *p_instance, R (T::*p_method)(P...) const) {
CallableCustomMethodPointerC(T *p_instance, R (T::*p_method)(P...) const) {
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.instance = p_instance;
data.object_id = p_instance->get_instance_id();
Expand All @@ -218,13 +191,27 @@ class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
}
};

template <typename T, typename... P>
Callable create_custom_callable_function_pointer(T *p_instance,
#ifdef DEBUG_METHODS_ENABLED
const char *p_func_text,
#endif
void (T::*p_method)(P...) const) {
typedef CallableCustomMethodPointerC<T, void, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
#ifdef DEBUG_METHODS_ENABLED
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
#endif
return Callable(ccmp);
}

template <typename T, typename R, typename... P>
Callable create_custom_callable_function_pointer(T *p_instance,
#ifdef DEBUG_METHODS_ENABLED
const char *p_func_text,
#endif
R (T::*p_method)(P...) const) {
typedef CallableCustomMethodPointerRetC<T, R, P...> CCMP; // Messes with memnew otherwise.
typedef CallableCustomMethodPointerC<T, R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_instance, p_method));
#ifdef DEBUG_METHODS_ENABLED
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
Expand All @@ -240,10 +227,11 @@ Callable create_custom_callable_function_pointer(T *p_instance,

// STATIC VERSIONS

template <typename... P>
template <typename R, typename... P>
class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase {
struct Data {
void (*method)(P...);
R(*method)
(P...);
} data;

public:
Expand All @@ -261,70 +249,41 @@ class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase
}

virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
r_return_value = Variant();
if constexpr (std::is_same<R, void>::value) {
call_with_variant_args_static(data.method, p_arguments, p_argcount, r_call_error);
} else {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}
}

CallableCustomStaticMethodPointer(void (*p_method)(P...)) {
CallableCustomStaticMethodPointer(R (*p_method)(P...)) {
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};

template <typename T, typename... P>
template <typename... P>
Callable create_custom_callable_static_function_pointer(
#ifdef DEBUG_METHODS_ENABLED
const char *p_func_text,
#endif
void (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointer<P...> CCMP; // Messes with memnew otherwise.
typedef CallableCustomStaticMethodPointer<void, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_method));
#ifdef DEBUG_METHODS_ENABLED
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
#endif
return Callable(ccmp);
}

template <typename R, typename... P>
class CallableCustomStaticMethodPointerRet : public CallableCustomMethodPointerBase {
struct Data {
R(*method)
(P...);
} data;

public:
virtual bool is_valid() const override {
return true;
}

virtual ObjectID get_object() const override {
return ObjectID();
}

virtual int get_argument_count(bool &r_is_valid) const override {
r_is_valid = true;
return sizeof...(P);
}

virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
}

CallableCustomStaticMethodPointerRet(R (*p_method)(P...)) {
memset(&data, 0, sizeof(Data)); // Clear beforehand, may have padding bytes.
data.method = p_method;
_setup((uint32_t *)&data, sizeof(Data));
}
};

template <typename R, typename... P>
Callable create_custom_callable_static_function_pointer(
#ifdef DEBUG_METHODS_ENABLED
const char *p_func_text,
#endif
R (*p_method)(P...)) {
typedef CallableCustomStaticMethodPointerRet<R, P...> CCMP; // Messes with memnew otherwise.
typedef CallableCustomStaticMethodPointer<R, P...> CCMP; // Messes with memnew otherwise.
CCMP *ccmp = memnew(CCMP(p_method));
#ifdef DEBUG_METHODS_ENABLED
ccmp->set_text(p_func_text + 1); // Try to get rid of the ampersand.
Expand Down
Loading

0 comments on commit 859eefd

Please sign in to comment.