Skip to content

Commit abf9d24

Browse files
committed
Make internal unique scene resource ID deterministic
Changes the Resource::generate_scene_unique_id() to be deterministic and seedable. Fixes godotengine#97110
1 parent d5aadc3 commit abf9d24

File tree

4 files changed

+27
-11
lines changed

4 files changed

+27
-11
lines changed

core/io/resource.cpp

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -99,31 +99,42 @@ void Resource::set_path_cache(const String &p_path) {
9999
GDVIRTUAL_CALL(_set_path_cache, p_path);
100100
}
101101

102+
static thread_local RandomPCG unique_id_gen(0, RandomPCG::DEFAULT_INC);
103+
104+
void Resource::seed_scene_unique_id(uint32_t p_seed) {
105+
unique_id_gen.seed(p_seed);
106+
}
107+
102108
String Resource::generate_scene_unique_id() {
103109
// Generate a unique enough hash, but still user-readable.
104110
// If it's not unique it does not matter because the saver will try again.
105-
OS::DateTime dt = OS::get_singleton()->get_datetime();
106-
uint32_t hash = hash_murmur3_one_32(OS::get_singleton()->get_ticks_usec());
107-
hash = hash_murmur3_one_32(dt.year, hash);
108-
hash = hash_murmur3_one_32(dt.month, hash);
109-
hash = hash_murmur3_one_32(dt.day, hash);
110-
hash = hash_murmur3_one_32(dt.hour, hash);
111-
hash = hash_murmur3_one_32(dt.minute, hash);
112-
hash = hash_murmur3_one_32(dt.second, hash);
113-
hash = hash_murmur3_one_32(Math::rand(), hash);
111+
if (unique_id_gen.get_seed() == 0) {
112+
OS::DateTime dt = OS::get_singleton()->get_datetime();
113+
uint32_t hash = hash_murmur3_one_32(OS::get_singleton()->get_ticks_usec());
114+
hash = hash_murmur3_one_32(dt.year, hash);
115+
hash = hash_murmur3_one_32(dt.month, hash);
116+
hash = hash_murmur3_one_32(dt.day, hash);
117+
hash = hash_murmur3_one_32(dt.hour, hash);
118+
hash = hash_murmur3_one_32(dt.minute, hash);
119+
hash = hash_murmur3_one_32(dt.second, hash);
120+
hash = hash_murmur3_one_32(Math::rand(), hash);
121+
unique_id_gen.seed(hash);
122+
}
123+
124+
uint32_t random_num = unique_id_gen.rand();
114125

115126
static constexpr uint32_t characters = 5;
116127
static constexpr uint32_t char_count = ('z' - 'a');
117128
static constexpr uint32_t base = char_count + ('9' - '0');
118129
String id;
119130
for (uint32_t i = 0; i < characters; i++) {
120-
uint32_t c = hash % base;
131+
uint32_t c = random_num % base;
121132
if (c < char_count) {
122133
id += String::chr('a' + c);
123134
} else {
124135
id += String::chr('0' + (c - char_count));
125136
}
126-
hash /= base;
137+
random_num /= base;
127138
}
128139

129140
return id;

core/io/resource.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ class Resource : public RefCounted {
114114
virtual void set_path_cache(const String &p_path); // Set raw path without involving resource cache.
115115
_FORCE_INLINE_ bool is_built_in() const { return path_cache.is_empty() || path_cache.contains("::") || path_cache.begins_with("local://"); }
116116

117+
static void seed_scene_unique_id(uint32_t p_seed);
117118
static String generate_scene_unique_id();
118119
void set_scene_unique_id(const String &p_id);
119120
String get_scene_unique_id() const;

core/io/resource_format_binary.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,6 +2136,8 @@ static String _resource_get_class(Ref<Resource> p_resource) {
21362136
}
21372137

21382138
Error ResourceFormatSaverBinaryInstance::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
2139+
Resource::seed_scene_unique_id(p_path.hash());
2140+
21392141
Error err;
21402142
Ref<FileAccess> f;
21412143
if (p_flags & ResourceSaver::FLAG_COMPRESS) {

scene/resources/resource_format_text.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,6 +1708,8 @@ static String _resource_get_class(Ref<Resource> p_resource) {
17081708
}
17091709

17101710
Error ResourceFormatSaverTextInstance::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
1711+
Resource::seed_scene_unique_id(p_path.hash()); // Seeding for save path should make it deterministic for importers.
1712+
17111713
if (p_path.ends_with(".tscn")) {
17121714
packed_scene = p_resource;
17131715
}

0 commit comments

Comments
 (0)