2014-02-09 22:10:30 -03:00
/**************************************************************************/
/* resource_format_binary.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-09 22:10:30 -03:00
# include "resource_format_binary.h"
2017-08-26 17:46:49 +02:00
2020-11-07 19:33:38 -03:00
# include "core/config/project_settings.h"
2021-06-11 14:51:48 +02:00
# include "core/io/dir_access.h"
2017-08-26 17:46:49 +02:00
# include "core/io/file_access_compressed.h"
2020-11-07 19:33:38 -03:00
# include "core/io/image.h"
2017-08-26 17:46:49 +02:00
# include "core/io/marshalls.h"
2022-04-28 22:49:10 +02:00
# include "core/io/missing_resource.h"
2023-09-06 21:02:52 +02:00
# include "core/object/script_language.h"
2017-08-26 17:46:49 +02:00
# include "core/version.h"
2014-02-09 22:10:30 -03:00
//#define print_bl(m_what) print_line(m_what)
2017-09-02 22:32:31 +02:00
# define print_bl(m_what) (void)(m_what)
2014-02-09 22:10:30 -03:00
enum {
//numbering must be different from variant, in case new variant types are added (variant must be always contiguous for jumptable optimization)
VARIANT_NIL = 1 ,
VARIANT_BOOL = 2 ,
VARIANT_INT = 3 ,
2020-02-24 15:20:53 -03:00
VARIANT_FLOAT = 4 ,
2014-02-09 22:10:30 -03:00
VARIANT_STRING = 5 ,
VARIANT_VECTOR2 = 10 ,
VARIANT_RECT2 = 11 ,
VARIANT_VECTOR3 = 12 ,
VARIANT_PLANE = 13 ,
2021-01-20 07:02:02 +00:00
VARIANT_QUATERNION = 14 ,
2017-11-16 21:09:00 -05:00
VARIANT_AABB = 15 ,
2021-12-27 17:28:25 -08:00
VARIANT_BASIS = 16 ,
2021-12-24 18:44:08 +01:00
VARIANT_TRANSFORM3D = 17 ,
2021-12-27 17:28:25 -08:00
VARIANT_TRANSFORM2D = 18 ,
2014-02-09 22:10:30 -03:00
VARIANT_COLOR = 20 ,
VARIANT_NODE_PATH = 22 ,
VARIANT_RID = 23 ,
VARIANT_OBJECT = 24 ,
VARIANT_INPUT_EVENT = 25 ,
VARIANT_DICTIONARY = 26 ,
VARIANT_ARRAY = 30 ,
2021-12-24 18:44:08 +01:00
VARIANT_PACKED_BYTE_ARRAY = 31 ,
VARIANT_PACKED_INT32_ARRAY = 32 ,
VARIANT_PACKED_FLOAT32_ARRAY = 33 ,
VARIANT_PACKED_STRING_ARRAY = 34 ,
VARIANT_PACKED_VECTOR3_ARRAY = 35 ,
VARIANT_PACKED_COLOR_ARRAY = 36 ,
VARIANT_PACKED_VECTOR2_ARRAY = 37 ,
2017-01-08 20:58:39 -03:00
VARIANT_INT64 = 40 ,
VARIANT_DOUBLE = 41 ,
2020-02-19 16:27:19 -03:00
VARIANT_CALLABLE = 42 ,
VARIANT_SIGNAL = 43 ,
2020-02-20 18:58:05 -03:00
VARIANT_STRING_NAME = 44 ,
2020-02-22 00:26:41 -03:00
VARIANT_VECTOR2I = 45 ,
VARIANT_RECT2I = 46 ,
VARIANT_VECTOR3I = 47 ,
2021-12-24 18:44:08 +01:00
VARIANT_PACKED_INT64_ARRAY = 48 ,
VARIANT_PACKED_FLOAT64_ARRAY = 49 ,
2022-07-20 01:11:13 +02:00
VARIANT_VECTOR4 = 50 ,
VARIANT_VECTOR4I = 51 ,
VARIANT_PROJECTION = 52 ,
2024-04-08 07:51:34 -07:00
VARIANT_PACKED_VECTOR4_ARRAY = 53 ,
2014-02-09 22:10:30 -03:00
OBJECT_EMPTY = 0 ,
OBJECT_EXTERNAL_RESOURCE = 1 ,
OBJECT_INTERNAL_RESOURCE = 2 ,
2015-08-23 20:15:56 -03:00
OBJECT_EXTERNAL_RESOURCE_INDEX = 3 ,
2024-04-08 07:51:34 -07:00
// Version 2: Added 64-bit support for float and int.
// Version 3: Changed NodePath encoding.
// Version 4: New string ID for ext/subresources, breaks forward compat.
2023-01-19 19:12:25 +01:00
// Version 5: Ability to store script class in the header.
2024-04-08 07:51:34 -07:00
// Version 6: Added PackedVector4Array Variant type.
FORMAT_VERSION = 6 ,
2017-11-22 13:34:43 +02:00
FORMAT_VERSION_CAN_RENAME_DEPS = 1 ,
FORMAT_VERSION_NO_NODEPATH_PROPERTY = 3 ,
2014-02-09 22:10:30 -03:00
} ;
2020-02-28 08:27:04 -03:00
void ResourceLoaderBinary : : _advance_padding ( uint32_t p_len ) {
2014-02-09 22:10:30 -03:00
uint32_t extra = 4 - ( p_len % 4 ) ;
if ( extra < 4 ) {
2020-05-14 16:41:43 +02:00
for ( uint32_t i = 0 ; i < extra ; i + + ) {
2014-02-09 22:10:30 -03:00
f - > get_8 ( ) ; //pad to 32
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
}
2022-03-23 11:08:58 +02:00
static Error read_reals ( real_t * dst , Ref < FileAccess > & f , size_t count ) {
if ( f - > real_is_double ) {
2022-09-29 09:18:07 +03:00
if constexpr ( sizeof ( real_t ) = = 8 ) {
2022-03-19 16:56:45 +00:00
// Ideal case with double-precision
2022-03-23 11:08:58 +02:00
f - > get_buffer ( ( uint8_t * ) dst , count * sizeof ( double ) ) ;
2022-03-19 16:56:45 +00:00
# ifdef BIG_ENDIAN_ENABLED
{
uint64_t * dst = ( uint64_t * ) dst ;
for ( size_t i = 0 ; i < count ; i + + ) {
dst [ i ] = BSWAP64 ( dst [ i ] ) ;
}
}
# endif
2022-09-29 09:18:07 +03:00
} else if constexpr ( sizeof ( real_t ) = = 4 ) {
2022-03-19 16:56:45 +00:00
// May be slower, but this is for compatibility. Eventually the data should be converted.
for ( size_t i = 0 ; i < count ; + + i ) {
2022-03-23 11:08:58 +02:00
dst [ i ] = f - > get_double ( ) ;
2022-03-19 16:56:45 +00:00
}
} else {
ERR_FAIL_V_MSG ( ERR_UNAVAILABLE , " real_t size is neither 4 nor 8! " ) ;
}
} else {
2022-09-29 09:18:07 +03:00
if constexpr ( sizeof ( real_t ) = = 4 ) {
2022-03-19 16:56:45 +00:00
// Ideal case with float-precision
2022-03-23 11:08:58 +02:00
f - > get_buffer ( ( uint8_t * ) dst , count * sizeof ( float ) ) ;
2022-03-19 16:56:45 +00:00
# ifdef BIG_ENDIAN_ENABLED
{
uint32_t * dst = ( uint32_t * ) dst ;
for ( size_t i = 0 ; i < count ; i + + ) {
dst [ i ] = BSWAP32 ( dst [ i ] ) ;
}
}
# endif
2022-09-29 09:18:07 +03:00
} else if constexpr ( sizeof ( real_t ) = = 8 ) {
2022-03-19 16:56:45 +00:00
for ( size_t i = 0 ; i < count ; + + i ) {
2022-03-23 11:08:58 +02:00
dst [ i ] = f - > get_float ( ) ;
2022-03-19 16:56:45 +00:00
}
} else {
ERR_FAIL_V_MSG ( ERR_UNAVAILABLE , " real_t size is neither 4 nor 8! " ) ;
}
}
return OK ;
}
2020-02-28 08:27:04 -03:00
StringName ResourceLoaderBinary : : _get_string ( ) {
2017-02-15 08:29:46 -03:00
uint32_t id = f - > get_32 ( ) ;
if ( id & 0x80000000 ) {
2017-12-15 09:04:57 -03:00
uint32_t len = id & 0x7FFFFFFF ;
2019-02-21 20:57:39 +01:00
if ( ( int ) len > str_buf . size ( ) ) {
2017-02-15 08:29:46 -03:00
str_buf . resize ( len ) ;
}
2020-05-14 16:41:43 +02:00
if ( len = = 0 ) {
2017-02-15 08:29:46 -03:00
return StringName ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-02-15 08:29:46 -03:00
f - > get_buffer ( ( uint8_t * ) & str_buf [ 0 ] , len ) ;
String s ;
s . parse_utf8 ( & str_buf [ 0 ] ) ;
return s ;
}
return string_map [ id ] ;
}
2020-02-28 08:27:04 -03:00
Error ResourceLoaderBinary : : parse_variant ( Variant & r_v ) {
2022-09-29 12:53:28 +03:00
uint32_t prop_type = f - > get_32 ( ) ;
print_bl ( " find property of type: " + itos ( prop_type ) ) ;
2014-02-09 22:10:30 -03:00
2022-09-29 12:53:28 +03:00
switch ( prop_type ) {
2014-02-09 22:10:30 -03:00
case VARIANT_NIL : {
r_v = Variant ( ) ;
} break ;
case VARIANT_BOOL : {
r_v = bool ( f - > get_32 ( ) ) ;
} break ;
case VARIANT_INT : {
r_v = int ( f - > get_32 ( ) ) ;
} break ;
2017-01-08 20:58:39 -03:00
case VARIANT_INT64 : {
r_v = int64_t ( f - > get_64 ( ) ) ;
} break ;
2020-02-24 15:20:53 -03:00
case VARIANT_FLOAT : {
2014-02-09 22:10:30 -03:00
r_v = f - > get_real ( ) ;
} break ;
2017-01-08 20:58:39 -03:00
case VARIANT_DOUBLE : {
r_v = f - > get_double ( ) ;
} break ;
2014-02-09 22:10:30 -03:00
case VARIANT_STRING : {
r_v = get_unicode_string ( ) ;
} break ;
case VARIANT_VECTOR2 : {
Vector2 v ;
v . x = f - > get_real ( ) ;
v . y = f - > get_real ( ) ;
r_v = v ;
2020-02-22 00:26:41 -03:00
} break ;
case VARIANT_VECTOR2I : {
Vector2i v ;
v . x = f - > get_32 ( ) ;
v . y = f - > get_32 ( ) ;
r_v = v ;
2014-02-09 22:10:30 -03:00
} break ;
case VARIANT_RECT2 : {
Rect2 v ;
2017-06-04 00:25:13 +02:00
v . position . x = f - > get_real ( ) ;
v . position . y = f - > get_real ( ) ;
2014-02-09 22:10:30 -03:00
v . size . x = f - > get_real ( ) ;
v . size . y = f - > get_real ( ) ;
r_v = v ;
2020-02-22 00:26:41 -03:00
} break ;
case VARIANT_RECT2I : {
Rect2i v ;
v . position . x = f - > get_32 ( ) ;
v . position . y = f - > get_32 ( ) ;
v . size . x = f - > get_32 ( ) ;
v . size . y = f - > get_32 ( ) ;
r_v = v ;
2014-02-09 22:10:30 -03:00
} break ;
case VARIANT_VECTOR3 : {
Vector3 v ;
v . x = f - > get_real ( ) ;
v . y = f - > get_real ( ) ;
v . z = f - > get_real ( ) ;
r_v = v ;
} break ;
2020-02-22 00:26:41 -03:00
case VARIANT_VECTOR3I : {
Vector3i v ;
v . x = f - > get_32 ( ) ;
v . y = f - > get_32 ( ) ;
v . z = f - > get_32 ( ) ;
r_v = v ;
} break ;
2022-07-20 01:11:13 +02:00
case VARIANT_VECTOR4 : {
Vector4 v ;
v . x = f - > get_real ( ) ;
v . y = f - > get_real ( ) ;
v . z = f - > get_real ( ) ;
v . w = f - > get_real ( ) ;
r_v = v ;
} break ;
case VARIANT_VECTOR4I : {
Vector4i v ;
v . x = f - > get_32 ( ) ;
v . y = f - > get_32 ( ) ;
v . z = f - > get_32 ( ) ;
v . w = f - > get_32 ( ) ;
r_v = v ;
} break ;
2014-02-09 22:10:30 -03:00
case VARIANT_PLANE : {
Plane v ;
v . normal . x = f - > get_real ( ) ;
v . normal . y = f - > get_real ( ) ;
v . normal . z = f - > get_real ( ) ;
2020-05-10 16:47:11 +02:00
v . d = f - > get_real ( ) ;
2014-02-09 22:10:30 -03:00
r_v = v ;
} break ;
2021-01-20 07:02:02 +00:00
case VARIANT_QUATERNION : {
Quaternion v ;
2014-02-09 22:10:30 -03:00
v . x = f - > get_real ( ) ;
v . y = f - > get_real ( ) ;
v . z = f - > get_real ( ) ;
v . w = f - > get_real ( ) ;
r_v = v ;
} break ;
2017-11-16 21:09:00 -05:00
case VARIANT_AABB : {
AABB v ;
2017-06-06 20:33:51 +02:00
v . position . x = f - > get_real ( ) ;
v . position . y = f - > get_real ( ) ;
v . position . z = f - > get_real ( ) ;
2014-02-09 22:10:30 -03:00
v . size . x = f - > get_real ( ) ;
v . size . y = f - > get_real ( ) ;
v . size . z = f - > get_real ( ) ;
r_v = v ;
} break ;
2021-12-27 17:28:25 -08:00
case VARIANT_TRANSFORM2D : {
2017-01-11 00:52:51 -03:00
Transform2D v ;
2022-04-24 16:59:24 -05:00
v . columns [ 0 ] . x = f - > get_real ( ) ;
v . columns [ 0 ] . y = f - > get_real ( ) ;
v . columns [ 1 ] . x = f - > get_real ( ) ;
v . columns [ 1 ] . y = f - > get_real ( ) ;
v . columns [ 2 ] . x = f - > get_real ( ) ;
v . columns [ 2 ] . y = f - > get_real ( ) ;
2014-02-09 22:10:30 -03:00
r_v = v ;
} break ;
2021-12-27 17:28:25 -08:00
case VARIANT_BASIS : {
2017-01-11 00:52:51 -03:00
Basis v ;
2022-04-24 17:07:35 -05:00
v . rows [ 0 ] . x = f - > get_real ( ) ;
v . rows [ 0 ] . y = f - > get_real ( ) ;
v . rows [ 0 ] . z = f - > get_real ( ) ;
v . rows [ 1 ] . x = f - > get_real ( ) ;
v . rows [ 1 ] . y = f - > get_real ( ) ;
v . rows [ 1 ] . z = f - > get_real ( ) ;
v . rows [ 2 ] . x = f - > get_real ( ) ;
v . rows [ 2 ] . y = f - > get_real ( ) ;
v . rows [ 2 ] . z = f - > get_real ( ) ;
2014-02-09 22:10:30 -03:00
r_v = v ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_TRANSFORM3D : {
2020-10-17 01:08:21 -04:00
Transform3D v ;
2022-04-24 17:07:35 -05:00
v . basis . rows [ 0 ] . x = f - > get_real ( ) ;
v . basis . rows [ 0 ] . y = f - > get_real ( ) ;
v . basis . rows [ 0 ] . z = f - > get_real ( ) ;
v . basis . rows [ 1 ] . x = f - > get_real ( ) ;
v . basis . rows [ 1 ] . y = f - > get_real ( ) ;
v . basis . rows [ 1 ] . z = f - > get_real ( ) ;
v . basis . rows [ 2 ] . x = f - > get_real ( ) ;
v . basis . rows [ 2 ] . y = f - > get_real ( ) ;
v . basis . rows [ 2 ] . z = f - > get_real ( ) ;
2014-02-09 22:10:30 -03:00
v . origin . x = f - > get_real ( ) ;
v . origin . y = f - > get_real ( ) ;
v . origin . z = f - > get_real ( ) ;
r_v = v ;
} break ;
2022-07-20 01:11:13 +02:00
case VARIANT_PROJECTION : {
Projection v ;
2022-10-04 11:44:48 -05:00
v . columns [ 0 ] . x = f - > get_real ( ) ;
v . columns [ 0 ] . y = f - > get_real ( ) ;
v . columns [ 0 ] . z = f - > get_real ( ) ;
v . columns [ 0 ] . w = f - > get_real ( ) ;
v . columns [ 1 ] . x = f - > get_real ( ) ;
v . columns [ 1 ] . y = f - > get_real ( ) ;
v . columns [ 1 ] . z = f - > get_real ( ) ;
v . columns [ 1 ] . w = f - > get_real ( ) ;
v . columns [ 2 ] . x = f - > get_real ( ) ;
v . columns [ 2 ] . y = f - > get_real ( ) ;
v . columns [ 2 ] . z = f - > get_real ( ) ;
v . columns [ 2 ] . w = f - > get_real ( ) ;
v . columns [ 3 ] . x = f - > get_real ( ) ;
v . columns [ 3 ] . y = f - > get_real ( ) ;
v . columns [ 3 ] . z = f - > get_real ( ) ;
v . columns [ 3 ] . w = f - > get_real ( ) ;
2022-07-20 01:11:13 +02:00
r_v = v ;
} break ;
2014-02-09 22:10:30 -03:00
case VARIANT_COLOR : {
2021-01-25 14:46:35 -05:00
Color v ; // Colors should always be in single-precision.
v . r = f - > get_float ( ) ;
v . g = f - > get_float ( ) ;
v . b = f - > get_float ( ) ;
v . a = f - > get_float ( ) ;
2014-02-09 22:10:30 -03:00
r_v = v ;
} break ;
2020-02-20 18:58:05 -03:00
case VARIANT_STRING_NAME : {
r_v = StringName ( get_unicode_string ( ) ) ;
} break ;
2014-02-09 22:10:30 -03:00
case VARIANT_NODE_PATH : {
Vector < StringName > names ;
Vector < StringName > subnames ;
bool absolute ;
int name_count = f - > get_16 ( ) ;
uint32_t subname_count = f - > get_16 ( ) ;
absolute = subname_count & 0x8000 ;
subname_count & = 0x7FFF ;
2017-11-22 13:34:43 +02:00
if ( ver_format < FORMAT_VERSION_NO_NODEPATH_PROPERTY ) {
subname_count + = 1 ; // has a property field, so we should count it as well
}
2014-02-09 22:10:30 -03:00
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < name_count ; i + + ) {
2017-02-15 08:29:46 -03:00
names . push_back ( _get_string ( ) ) ;
2020-05-14 16:41:43 +02:00
}
for ( uint32_t i = 0 ; i < subname_count ; i + + ) {
2017-02-15 08:29:46 -03:00
subnames . push_back ( _get_string ( ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2017-05-30 23:20:15 +03:00
NodePath np = NodePath ( names , subnames , absolute ) ;
2014-02-09 22:10:30 -03:00
r_v = np ;
} break ;
case VARIANT_RID : {
r_v = f - > get_32 ( ) ;
} break ;
case VARIANT_OBJECT : {
2019-02-12 21:10:08 +01:00
uint32_t objtype = f - > get_32 ( ) ;
2014-02-09 22:10:30 -03:00
2019-02-12 21:10:08 +01:00
switch ( objtype ) {
2014-02-09 22:10:30 -03:00
case OBJECT_EMPTY : {
//do none
} break ;
case OBJECT_INTERNAL_RESOURCE : {
uint32_t index = f - > get_32 ( ) ;
2021-07-20 21:36:56 -03:00
String path ;
if ( using_named_scene_ids ) { // New format.
ERR_FAIL_INDEX_V ( ( int ) index , internal_resources . size ( ) , ERR_PARSE_ERROR ) ;
path = internal_resources [ index ] . path ;
} else {
path + = res_path + " :: " + itos ( index ) ;
}
2020-05-01 09:34:23 -03:00
2021-02-11 14:18:45 -03:00
//always use internal cache for loading internal resources
if ( ! internal_index_cache . has ( path ) ) {
WARN_PRINT ( String ( " Couldn't load resource (no cache): " + path ) . utf8 ( ) . get_data ( ) ) ;
r_v = Variant ( ) ;
2020-04-19 23:19:21 -03:00
} else {
2021-02-11 14:18:45 -03:00
r_v = internal_index_cache [ path ] ;
2014-02-09 22:10:30 -03:00
}
} break ;
case OBJECT_EXTERNAL_RESOURCE : {
2015-08-23 20:15:56 -03:00
//old file format, still around for compatibility
2014-02-09 22:10:30 -03:00
2019-02-12 21:10:08 +01:00
String exttype = get_unicode_string ( ) ;
2014-02-09 22:10:30 -03:00
String path = get_unicode_string ( ) ;
2022-02-03 21:48:38 +05:45
if ( ! path . contains ( " :// " ) & & path . is_relative_path ( ) ) {
2014-02-09 22:10:30 -03:00
// path is relative to file being loaded, so convert to a resource path
2022-08-29 19:34:01 -05:00
path = ProjectSettings : : get_singleton ( ) - > localize_path ( res_path . get_base_dir ( ) . path_join ( path ) ) ;
2014-02-09 22:10:30 -03:00
}
2015-08-23 20:15:56 -03:00
if ( remaps . find ( path ) ) {
path = remaps [ path ] ;
}
2024-02-22 12:53:19 +01:00
Ref < Resource > res = ResourceLoader : : load ( path , exttype , cache_mode_for_external ) ;
2014-02-09 22:10:30 -03:00
if ( res . is_null ( ) ) {
WARN_PRINT ( String ( " Couldn't load resource: " + path ) . utf8 ( ) . get_data ( ) ) ;
}
r_v = res ;
2015-08-23 20:15:56 -03:00
} break ;
case OBJECT_EXTERNAL_RESOURCE_INDEX : {
//new file format, just refers to an index in the external list
2017-08-31 23:30:35 +02:00
int erindex = f - > get_32 ( ) ;
2015-08-23 20:15:56 -03:00
2017-08-31 23:30:35 +02:00
if ( erindex < 0 | | erindex > = external_resources . size ( ) ) {
2019-01-26 22:35:31 +01:00
WARN_PRINT ( " Broken external resource! (index out of size) " ) ;
2015-08-23 20:15:56 -03:00
r_v = Variant ( ) ;
} else {
2023-03-05 01:09:18 +01:00
Ref < ResourceLoader : : LoadToken > & load_token = external_resources . write [ erindex ] . load_token ;
if ( load_token . is_valid ( ) ) { // If not valid, it's OK since then we know this load accepts broken dependencies.
Error err ;
Ref < Resource > res = ResourceLoader : : _load_complete ( * load_token . ptr ( ) , & err ) ;
if ( res . is_null ( ) ) {
if ( ! ResourceLoader : : is_cleaning_tasks ( ) ) {
2020-02-28 08:27:04 -03:00
if ( ! ResourceLoader : : get_abort_on_missing_resources ( ) ) {
ResourceLoader : : notify_dependency_error ( local_path , external_resources [ erindex ] . path , external_resources [ erindex ] . type ) ;
} else {
error = ERR_FILE_MISSING_DEPENDENCIES ;
ERR_FAIL_V_MSG ( error , " Can't load dependency: " + external_resources [ erindex ] . path + " . " ) ;
}
}
2023-03-05 01:09:18 +01:00
} else {
r_v = res ;
2020-02-28 08:27:04 -03:00
}
2015-08-23 20:15:56 -03:00
}
}
2014-02-09 22:10:30 -03:00
} break ;
default : {
ERR_FAIL_V ( ERR_FILE_CORRUPT ) ;
} break ;
}
} break ;
2020-02-19 16:27:19 -03:00
case VARIANT_CALLABLE : {
r_v = Callable ( ) ;
} break ;
case VARIANT_SIGNAL : {
r_v = Signal ( ) ;
} break ;
2014-02-09 22:10:30 -03:00
case VARIANT_DICTIONARY : {
2016-08-07 19:22:33 -03:00
uint32_t len = f - > get_32 ( ) ;
2017-01-11 08:53:31 -03:00
Dictionary d ; //last bit means shared
2016-08-07 19:22:33 -03:00
len & = 0x7FFFFFFF ;
for ( uint32_t i = 0 ; i < len ; i + + ) {
2014-02-09 22:10:30 -03:00
Variant key ;
Error err = parse_variant ( key ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err , ERR_FILE_CORRUPT , " Error when trying to parse Variant. " ) ;
2014-02-09 22:10:30 -03:00
Variant value ;
err = parse_variant ( value ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err , ERR_FILE_CORRUPT , " Error when trying to parse Variant. " ) ;
2014-02-09 22:10:30 -03:00
d [ key ] = value ;
}
r_v = d ;
} break ;
case VARIANT_ARRAY : {
2016-08-07 19:22:33 -03:00
uint32_t len = f - > get_32 ( ) ;
2017-01-11 08:53:31 -03:00
Array a ; //last bit means shared
2016-08-07 19:22:33 -03:00
len & = 0x7FFFFFFF ;
2014-02-09 22:10:30 -03:00
a . resize ( len ) ;
2016-08-07 19:22:33 -03:00
for ( uint32_t i = 0 ; i < len ; i + + ) {
2014-02-09 22:10:30 -03:00
Variant val ;
Error err = parse_variant ( val ) ;
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err , ERR_FILE_CORRUPT , " Error when trying to parse Variant. " ) ;
2014-02-09 22:10:30 -03:00
a [ i ] = val ;
}
r_v = a ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_BYTE_ARRAY : {
2014-02-09 22:10:30 -03:00
uint32_t len = f - > get_32 ( ) ;
2020-02-17 18:06:54 -03:00
Vector < uint8_t > array ;
2014-02-09 22:10:30 -03:00
array . resize ( len ) ;
2020-02-17 18:06:54 -03:00
uint8_t * w = array . ptrw ( ) ;
f - > get_buffer ( w , len ) ;
2014-02-09 22:10:30 -03:00
_advance_padding ( len ) ;
2020-02-17 18:06:54 -03:00
2014-02-09 22:10:30 -03:00
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_INT32_ARRAY : {
2014-02-09 22:10:30 -03:00
uint32_t len = f - > get_32 ( ) ;
2020-02-24 15:20:53 -03:00
Vector < int32_t > array ;
2014-02-09 22:10:30 -03:00
array . resize ( len ) ;
2020-02-24 15:20:53 -03:00
int32_t * w = array . ptrw ( ) ;
f - > get_buffer ( ( uint8_t * ) w , len * sizeof ( int32_t ) ) ;
2014-02-09 22:10:30 -03:00
# ifdef BIG_ENDIAN_ENABLED
{
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
}
}
# endif
2020-02-17 18:06:54 -03:00
2014-02-09 22:10:30 -03:00
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_INT64_ARRAY : {
2014-02-09 22:10:30 -03:00
uint32_t len = f - > get_32 ( ) ;
2020-02-24 15:20:53 -03:00
Vector < int64_t > array ;
2014-02-09 22:10:30 -03:00
array . resize ( len ) ;
2020-02-24 15:20:53 -03:00
int64_t * w = array . ptrw ( ) ;
f - > get_buffer ( ( uint8_t * ) w , len * sizeof ( int64_t ) ) ;
# ifdef BIG_ENDIAN_ENABLED
{
uint64_t * ptr = ( uint64_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
ptr [ i ] = BSWAP64 ( ptr [ i ] ) ;
}
}
# endif
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_FLOAT32_ARRAY : {
2020-02-24 15:20:53 -03:00
uint32_t len = f - > get_32 ( ) ;
Vector < float > array ;
array . resize ( len ) ;
float * w = array . ptrw ( ) ;
f - > get_buffer ( ( uint8_t * ) w , len * sizeof ( float ) ) ;
2014-02-09 22:10:30 -03:00
# ifdef BIG_ENDIAN_ENABLED
{
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
}
}
2020-02-24 15:20:53 -03:00
# endif
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_FLOAT64_ARRAY : {
2020-02-24 15:20:53 -03:00
uint32_t len = f - > get_32 ( ) ;
Vector < double > array ;
array . resize ( len ) ;
double * w = array . ptrw ( ) ;
f - > get_buffer ( ( uint8_t * ) w , len * sizeof ( double ) ) ;
# ifdef BIG_ENDIAN_ENABLED
{
uint64_t * ptr = ( uint64_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
ptr [ i ] = BSWAP64 ( ptr [ i ] ) ;
}
}
2014-02-09 22:10:30 -03:00
# endif
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_STRING_ARRAY : {
2014-02-09 22:10:30 -03:00
uint32_t len = f - > get_32 ( ) ;
2020-02-17 18:06:54 -03:00
Vector < String > array ;
2014-02-09 22:10:30 -03:00
array . resize ( len ) ;
2020-02-17 18:06:54 -03:00
String * w = array . ptrw ( ) ;
2020-05-14 16:41:43 +02:00
for ( uint32_t i = 0 ; i < len ; i + + ) {
2014-02-09 22:10:30 -03:00
w [ i ] = get_unicode_string ( ) ;
2020-05-14 16:41:43 +02:00
}
2020-02-17 18:06:54 -03:00
2014-02-09 22:10:30 -03:00
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_VECTOR2_ARRAY : {
2014-02-09 22:10:30 -03:00
uint32_t len = f - > get_32 ( ) ;
2020-02-17 18:06:54 -03:00
Vector < Vector2 > array ;
2014-02-09 22:10:30 -03:00
array . resize ( len ) ;
2020-02-17 18:06:54 -03:00
Vector2 * w = array . ptrw ( ) ;
2022-03-19 16:56:45 +00:00
static_assert ( sizeof ( Vector2 ) = = 2 * sizeof ( real_t ) ) ;
2022-03-23 11:08:58 +02:00
const Error err = read_reals ( reinterpret_cast < real_t * > ( w ) , f , len * 2 ) ;
2022-03-19 16:56:45 +00:00
ERR_FAIL_COND_V ( err ! = OK , err ) ;
2020-02-17 18:06:54 -03:00
2014-02-09 22:10:30 -03:00
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_VECTOR3_ARRAY : {
2014-02-09 22:10:30 -03:00
uint32_t len = f - > get_32 ( ) ;
2020-02-17 18:06:54 -03:00
Vector < Vector3 > array ;
2014-02-09 22:10:30 -03:00
array . resize ( len ) ;
2020-02-17 18:06:54 -03:00
Vector3 * w = array . ptrw ( ) ;
2022-03-19 16:56:45 +00:00
static_assert ( sizeof ( Vector3 ) = = 3 * sizeof ( real_t ) ) ;
2022-03-23 11:08:58 +02:00
const Error err = read_reals ( reinterpret_cast < real_t * > ( w ) , f , len * 3 ) ;
2022-03-19 16:56:45 +00:00
ERR_FAIL_COND_V ( err ! = OK , err ) ;
2020-02-17 18:06:54 -03:00
2014-02-09 22:10:30 -03:00
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_COLOR_ARRAY : {
2014-02-09 22:10:30 -03:00
uint32_t len = f - > get_32 ( ) ;
2020-02-17 18:06:54 -03:00
Vector < Color > array ;
2014-02-09 22:10:30 -03:00
array . resize ( len ) ;
2020-02-17 18:06:54 -03:00
Color * w = array . ptrw ( ) ;
2022-03-19 16:56:45 +00:00
// Colors always use `float` even with double-precision support enabled
static_assert ( sizeof ( Color ) = = 4 * sizeof ( float ) ) ;
f - > get_buffer ( ( uint8_t * ) w , len * sizeof ( float ) * 4 ) ;
2014-02-09 22:10:30 -03:00
# ifdef BIG_ENDIAN_ENABLED
2022-03-19 16:56:45 +00:00
{
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len * 4 ; i + + ) {
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
2014-02-09 22:10:30 -03:00
}
2022-03-19 16:56:45 +00:00
}
2014-02-09 22:10:30 -03:00
# endif
r_v = array ;
} break ;
2024-04-08 07:51:34 -07:00
case VARIANT_PACKED_VECTOR4_ARRAY : {
uint32_t len = f - > get_32 ( ) ;
Vector < Vector4 > array ;
array . resize ( len ) ;
Vector4 * w = array . ptrw ( ) ;
static_assert ( sizeof ( Vector4 ) = = 4 * sizeof ( real_t ) ) ;
const Error err = read_reals ( reinterpret_cast < real_t * > ( w ) , f , len * 4 ) ;
ERR_FAIL_COND_V ( err ! = OK , err ) ;
r_v = array ;
} break ;
2014-02-09 22:10:30 -03:00
default : {
ERR_FAIL_V ( ERR_FILE_CORRUPT ) ;
} break ;
}
return OK ; //never reach anyway
}
2020-02-28 08:27:04 -03:00
Ref < Resource > ResourceLoaderBinary : : get_resource ( ) {
2014-02-09 22:10:30 -03:00
return resource ;
}
2020-05-14 14:29:06 +02:00
2020-02-28 08:27:04 -03:00
Error ResourceLoaderBinary : : load ( ) {
2020-05-14 16:41:43 +02:00
if ( error ! = OK ) {
2014-02-09 22:10:30 -03:00
return error ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2020-02-28 08:27:04 -03:00
for ( int i = 0 ; i < external_resources . size ( ) ; i + + ) {
String path = external_resources [ i ] . path ;
2017-02-15 08:29:46 -03:00
2015-08-23 20:15:56 -03:00
if ( remaps . has ( path ) ) {
path = remaps [ path ] ;
}
2014-02-09 22:10:30 -03:00
2022-02-03 21:48:38 +05:45
if ( ! path . contains ( " :// " ) & & path . is_relative_path ( ) ) {
2020-02-28 08:27:04 -03:00
// path is relative to file being loaded, so convert to a resource path
2022-08-29 19:34:01 -05:00
path = ProjectSettings : : get_singleton ( ) - > localize_path ( path . get_base_dir ( ) . path_join ( external_resources [ i ] . path ) ) ;
2020-02-28 08:27:04 -03:00
}
2014-02-09 22:10:30 -03:00
2020-02-28 08:27:04 -03:00
external_resources . write [ i ] . path = path ; //remap happens here, not on load because on load it can actually be used for filesystem dock resource remap
2024-02-22 12:53:19 +01:00
external_resources . write [ i ] . load_token = ResourceLoader : : _load_start ( path , external_resources [ i ] . type , use_sub_threads ? ResourceLoader : : LOAD_THREAD_DISTRIBUTE : ResourceLoader : : LOAD_THREAD_FROM_CURRENT , cache_mode_for_external ) ;
2023-03-05 01:09:18 +01:00
if ( ! external_resources [ i ] . load_token . is_valid ( ) ) {
if ( ! ResourceLoader : : get_abort_on_missing_resources ( ) ) {
ResourceLoader : : notify_dependency_error ( local_path , path , external_resources [ i ] . type ) ;
} else {
error = ERR_FILE_MISSING_DEPENDENCIES ;
ERR_FAIL_V_MSG ( error , " Can't load dependency: " + path + " . " ) ;
2020-02-28 08:27:04 -03:00
}
2014-02-09 22:10:30 -03:00
}
}
2020-02-28 08:27:04 -03:00
for ( int i = 0 ; i < internal_resources . size ( ) ; i + + ) {
bool main = i = = ( internal_resources . size ( ) - 1 ) ;
2014-02-09 22:10:30 -03:00
2020-02-28 08:27:04 -03:00
//maybe it is loaded already
String path ;
2021-07-20 21:36:56 -03:00
String id ;
2014-02-09 22:10:30 -03:00
2020-02-28 08:27:04 -03:00
if ( ! main ) {
2020-05-01 09:34:23 -03:00
path = internal_resources [ i ] . path ;
if ( path . begins_with ( " local:// " ) ) {
path = path . replace_first ( " local:// " , " " ) ;
2021-07-20 21:36:56 -03:00
id = path ;
2020-05-01 09:34:23 -03:00
path = res_path + " :: " + path ;
2021-07-20 21:36:56 -03:00
internal_resources . write [ i ] . path = path ; // Update path.
2020-05-01 09:34:23 -03:00
}
2022-02-12 10:57:51 +01:00
if ( cache_mode = = ResourceFormatLoader : : CACHE_MODE_REUSE & & ResourceCache : : has ( path ) ) {
2022-06-22 13:46:46 +02:00
Ref < Resource > cached = ResourceCache : : get_ref ( path ) ;
2022-02-12 10:57:51 +01:00
if ( cached . is_valid ( ) ) {
2020-04-19 23:19:21 -03:00
//already loaded, don't do anything
error = OK ;
2022-02-12 10:57:51 +01:00
internal_index_cache [ path ] = cached ;
2020-04-19 23:19:21 -03:00
continue ;
}
2020-02-28 08:27:04 -03:00
}
} else {
2021-02-11 14:18:45 -03:00
if ( cache_mode ! = ResourceFormatLoader : : CACHE_MODE_IGNORE & & ! ResourceCache : : has ( res_path ) ) {
2020-02-28 08:27:04 -03:00
path = res_path ;
2020-05-14 16:41:43 +02:00
}
2015-06-22 00:03:19 -03:00
}
2014-02-09 22:10:30 -03:00
2020-02-28 08:27:04 -03:00
uint64_t offset = internal_resources [ i ] . offset ;
2014-02-09 22:10:30 -03:00
2020-02-28 08:27:04 -03:00
f - > seek ( offset ) ;
2014-02-09 22:10:30 -03:00
2020-02-28 08:27:04 -03:00
String t = get_unicode_string ( ) ;
2014-02-09 22:10:30 -03:00
2022-05-03 01:43:50 +02:00
Ref < Resource > res ;
2024-06-25 14:12:40 +02:00
Resource * r = nullptr ;
2014-02-09 22:10:30 -03:00
2022-04-28 22:49:10 +02:00
MissingResource * missing_resource = nullptr ;
2024-06-25 14:12:40 +02:00
if ( main ) {
res = ResourceLoader : : get_resource_ref_override ( local_path ) ;
r = res . ptr ( ) ;
}
if ( ! r ) {
if ( cache_mode = = ResourceFormatLoader : : CACHE_MODE_REPLACE & & ResourceCache : : has ( path ) ) {
//use the existing one
Ref < Resource > cached = ResourceCache : : get_ref ( path ) ;
if ( cached - > get_class ( ) = = t ) {
cached - > reset_state ( ) ;
res = cached ;
2022-04-28 22:49:10 +02:00
}
2021-02-11 14:18:45 -03:00
}
2014-02-09 22:10:30 -03:00
2024-06-25 14:12:40 +02:00
if ( res . is_null ( ) ) {
//did not replace
2021-02-11 14:18:45 -03:00
2024-06-25 14:12:40 +02:00
Object * obj = ClassDB : : instantiate ( t ) ;
if ( ! obj ) {
if ( ResourceLoader : : is_creating_missing_resources_if_class_unavailable_enabled ( ) ) {
//create a missing resource
missing_resource = memnew ( MissingResource ) ;
missing_resource - > set_original_class ( t ) ;
missing_resource - > set_recording_properties ( true ) ;
obj = missing_resource ;
} else {
error = ERR_FILE_CORRUPT ;
ERR_FAIL_V_MSG ( ERR_FILE_CORRUPT , local_path + " :Resource of unrecognized type in file: " + t + " . " ) ;
}
}
r = Object : : cast_to < Resource > ( obj ) ;
if ( ! r ) {
String obj_class = obj - > get_class ( ) ;
error = ERR_FILE_CORRUPT ;
memdelete ( obj ) ; //bye
ERR_FAIL_V_MSG ( ERR_FILE_CORRUPT , local_path + " :Resource type in resource field not a resource, type is: " + obj_class + " . " ) ;
}
res = Ref < Resource > ( r ) ;
}
}
if ( r ) {
2024-02-22 12:53:19 +01:00
if ( ! path . is_empty ( ) ) {
if ( cache_mode ! = ResourceFormatLoader : : CACHE_MODE_IGNORE ) {
r - > set_path ( path , cache_mode = = ResourceFormatLoader : : CACHE_MODE_REPLACE ) ; // If got here because the resource with same path has different type, replace it.
} else {
r - > set_path_cache ( path ) ;
}
2021-02-11 14:18:45 -03:00
}
2021-07-20 21:36:56 -03:00
r - > set_scene_unique_id ( id ) ;
2020-04-19 23:19:21 -03:00
}
2020-02-28 08:27:04 -03:00
2020-04-19 23:19:21 -03:00
if ( ! main ) {
2020-05-01 09:34:23 -03:00
internal_index_cache [ path ] = res ;
2020-04-19 23:19:21 -03:00
}
2020-02-28 08:27:04 -03:00
int pc = f - > get_32 ( ) ;
//set properties
2022-04-28 22:49:10 +02:00
Dictionary missing_resource_properties ;
2020-02-28 08:27:04 -03:00
for ( int j = 0 ; j < pc ; j + + ) {
StringName name = _get_string ( ) ;
if ( name = = StringName ( ) ) {
error = ERR_FILE_CORRUPT ;
ERR_FAIL_V ( ERR_FILE_CORRUPT ) ;
}
Variant value ;
error = parse_variant ( value ) ;
2020-05-14 16:41:43 +02:00
if ( error ) {
2020-02-28 08:27:04 -03:00
return error ;
2020-05-14 16:41:43 +02:00
}
2020-02-28 08:27:04 -03:00
2022-04-28 22:49:10 +02:00
bool set_valid = true ;
if ( value . get_type ( ) = = Variant : : OBJECT & & missing_resource ! = nullptr ) {
// If the property being set is a missing resource (and the parent is not),
// then setting it will most likely not work.
// Instead, save it as metadata.
Ref < MissingResource > mr = value ;
if ( mr . is_valid ( ) ) {
missing_resource_properties [ name ] = mr ;
set_valid = false ;
}
}
2024-10-04 19:09:53 +03:00
if ( value . get_type ( ) = = Variant : : ARRAY ) {
Array set_array = value ;
bool is_get_valid = false ;
Variant get_value = res - > get ( name , & is_get_valid ) ;
if ( is_get_valid & & get_value . get_type ( ) = = Variant : : ARRAY ) {
Array get_array = get_value ;
if ( ! set_array . is_same_typed ( get_array ) ) {
value = Array ( set_array , get_array . get_typed_builtin ( ) , get_array . get_typed_class_name ( ) , get_array . get_typed_script ( ) ) ;
2023-02-01 01:21:09 -05:00
}
}
2024-10-04 19:09:53 +03:00
}
2023-02-01 01:21:09 -05:00
2024-10-04 19:09:53 +03:00
if ( value . get_type ( ) = = Variant : : DICTIONARY ) {
Dictionary set_dict = value ;
bool is_get_valid = false ;
Variant get_value = res - > get ( name , & is_get_valid ) ;
if ( is_get_valid & & get_value . get_type ( ) = = Variant : : DICTIONARY ) {
Dictionary get_dict = get_value ;
if ( ! set_dict . is_same_typed ( get_dict ) ) {
value = Dictionary ( set_dict , get_dict . get_typed_key_builtin ( ) , get_dict . get_typed_key_class_name ( ) , get_dict . get_typed_key_script ( ) ,
get_dict . get_typed_value_builtin ( ) , get_dict . get_typed_value_class_name ( ) , get_dict . get_typed_value_script ( ) ) ;
2023-06-24 13:03:28 -05:00
}
}
}
2022-04-28 22:49:10 +02:00
if ( set_valid ) {
res - > set ( name , value ) ;
}
2020-02-28 08:27:04 -03:00
}
2022-04-28 22:49:10 +02:00
if ( missing_resource ) {
missing_resource - > set_recording_properties ( false ) ;
}
if ( ! missing_resource_properties . is_empty ( ) ) {
res - > set_meta ( META_MISSING_RESOURCES , missing_resource_properties ) ;
}
2014-02-09 22:10:30 -03:00
# ifdef TOOLS_ENABLED
2020-02-28 08:27:04 -03:00
res - > set_edited ( false ) ;
2014-02-09 22:10:30 -03:00
# endif
2020-02-28 08:27:04 -03:00
if ( progress ) {
* progress = ( i + 1 ) / float ( internal_resources . size ( ) ) ;
}
2014-02-09 22:10:30 -03:00
2020-02-28 08:27:04 -03:00
resource_cache . push_back ( res ) ;
2014-02-09 22:10:30 -03:00
2020-02-28 08:27:04 -03:00
if ( main ) {
2022-04-12 10:12:40 +03:00
f . unref ( ) ;
2020-02-28 08:27:04 -03:00
resource = res ;
resource - > set_as_translation_remapped ( translation_remapped ) ;
error = OK ;
return OK ;
}
2014-02-09 22:10:30 -03:00
}
2020-02-28 08:27:04 -03:00
return ERR_FILE_EOF ;
2014-02-09 22:10:30 -03:00
}
2020-02-28 08:27:04 -03:00
void ResourceLoaderBinary : : set_translation_remapped ( bool p_remapped ) {
2017-06-28 17:00:18 -03:00
translation_remapped = p_remapped ;
}
2022-03-23 11:08:58 +02:00
static void save_ustring ( Ref < FileAccess > f , const String & p_string ) {
2015-08-23 20:15:56 -03:00
CharString utf8 = p_string . utf8 ( ) ;
f - > store_32 ( utf8 . length ( ) + 1 ) ;
f - > store_buffer ( ( const uint8_t * ) utf8 . get_data ( ) , utf8 . length ( ) + 1 ) ;
}
2022-03-23 11:08:58 +02:00
static String get_ustring ( Ref < FileAccess > f ) {
2015-08-23 20:15:56 -03:00
int len = f - > get_32 ( ) ;
Vector < char > str_buf ;
str_buf . resize ( len ) ;
f - > get_buffer ( ( uint8_t * ) & str_buf [ 0 ] , len ) ;
String s ;
s . parse_utf8 ( & str_buf [ 0 ] ) ;
return s ;
}
2020-02-28 08:27:04 -03:00
String ResourceLoaderBinary : : get_unicode_string ( ) {
2014-02-09 22:10:30 -03:00
int len = f - > get_32 ( ) ;
if ( len > str_buf . size ( ) ) {
str_buf . resize ( len ) ;
}
2020-05-14 16:41:43 +02:00
if ( len = = 0 ) {
2015-12-09 09:08:41 -03:00
return String ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
f - > get_buffer ( ( uint8_t * ) & str_buf [ 0 ] , len ) ;
String s ;
s . parse_utf8 ( & str_buf [ 0 ] ) ;
return s ;
}
2022-07-14 14:18:18 +02:00
void ResourceLoaderBinary : : get_classes_used ( Ref < FileAccess > p_f , HashSet < StringName > * p_classes ) {
open ( p_f , false , true ) ;
if ( error ) {
return ;
}
for ( int i = 0 ; i < internal_resources . size ( ) ; i + + ) {
p_f - > seek ( internal_resources [ i ] . offset ) ;
String t = get_unicode_string ( ) ;
ERR_FAIL_COND ( p_f - > get_error ( ) ! = OK ) ;
if ( t ! = String ( ) ) {
p_classes - > insert ( t ) ;
}
}
}
2022-03-23 11:08:58 +02:00
void ResourceLoaderBinary : : get_dependencies ( Ref < FileAccess > p_f , List < String > * p_dependencies , bool p_add_types ) {
2021-07-23 16:01:18 -03:00
open ( p_f , false , true ) ;
2020-05-14 16:41:43 +02:00
if ( error ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
for ( int i = 0 ; i < external_resources . size ( ) ; i + + ) {
2021-07-23 16:01:18 -03:00
String dep ;
2023-06-16 13:40:10 +02:00
String fallback_path ;
2021-07-23 16:01:18 -03:00
if ( external_resources [ i ] . uid ! = ResourceUID : : INVALID_ID ) {
dep = ResourceUID : : get_singleton ( ) - > id_to_text ( external_resources [ i ] . uid ) ;
2023-06-16 13:40:10 +02:00
fallback_path = external_resources [ i ] . path ; // Used by Dependency Editor, in case uid path fails.
2021-07-23 16:01:18 -03:00
} else {
dep = external_resources [ i ] . path ;
}
2014-03-13 22:57:24 -03:00
2021-12-09 03:42:46 -06:00
if ( p_add_types & & ! external_resources [ i ] . type . is_empty ( ) ) {
2015-08-23 20:15:56 -03:00
dep + = " :: " + external_resources [ i ] . type ;
}
2023-06-16 13:40:10 +02:00
if ( ! fallback_path . is_empty ( ) ) {
if ( ! p_add_types ) {
dep + = " :: " ; // Ensure that path comes third, even if there is no type.
}
dep + = " :: " + fallback_path ;
}
2015-08-23 20:15:56 -03:00
2014-03-13 22:57:24 -03:00
p_dependencies - > push_back ( dep ) ;
2014-02-09 22:10:30 -03:00
}
}
2022-03-23 11:08:58 +02:00
void ResourceLoaderBinary : : open ( Ref < FileAccess > p_f , bool p_no_resources , bool p_keep_uuid_paths ) {
2017-03-05 16:44:50 +01:00
error = OK ;
2014-02-09 22:10:30 -03:00
f = p_f ;
uint8_t header [ 4 ] ;
f - > get_buffer ( header , 4 ) ;
if ( header [ 0 ] = = ' R ' & & header [ 1 ] = = ' S ' & & header [ 2 ] = = ' C ' & & header [ 3 ] = = ' C ' ) {
2020-02-11 11:39:20 +08:00
// Compressed.
2022-03-23 11:08:58 +02:00
Ref < FileAccessCompressed > fac ;
fac . instantiate ( ) ;
2020-02-11 11:39:20 +08:00
error = fac - > open_after_magic ( f ) ;
if ( error ! = OK ) {
2022-04-12 10:12:40 +03:00
f . unref ( ) ;
2020-02-11 11:39:20 +08:00
ERR_FAIL_MSG ( " Failed to open binary resource file: " + local_path + " . " ) ;
}
2014-02-09 22:10:30 -03:00
f = fac ;
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
2020-02-11 11:39:20 +08:00
// Not normal.
2014-02-09 22:10:30 -03:00
error = ERR_FILE_UNRECOGNIZED ;
2022-04-12 10:12:40 +03:00
f . unref ( ) ;
2019-08-14 20:57:49 -06:00
ERR_FAIL_MSG ( " Unrecognized binary resource file: " + local_path + " . " ) ;
2014-02-09 22:10:30 -03:00
}
bool big_endian = f - > get_32 ( ) ;
bool use_real64 = f - > get_32 ( ) ;
2021-05-20 14:58:03 +02:00
f - > set_big_endian ( big_endian ! = 0 ) ; //read big endian if saved as big endian
2014-02-09 22:10:30 -03:00
uint32_t ver_major = f - > get_32 ( ) ;
uint32_t ver_minor = f - > get_32 ( ) ;
2017-11-22 13:34:43 +02:00
ver_format = f - > get_32 ( ) ;
2014-02-09 22:10:30 -03:00
print_bl ( " big endian: " + itos ( big_endian ) ) ;
2017-09-02 22:32:31 +02:00
# ifdef BIG_ENDIAN_ENABLED
print_bl ( " endian swap: " + itos ( ! big_endian ) ) ;
# else
print_bl ( " endian swap: " + itos ( big_endian ) ) ;
# endif
2014-02-09 22:10:30 -03:00
print_bl ( " real64: " + itos ( use_real64 ) ) ;
print_bl ( " major: " + itos ( ver_major ) ) ;
print_bl ( " minor: " + itos ( ver_minor ) ) ;
print_bl ( " format: " + itos ( ver_format ) ) ;
2015-08-23 20:15:56 -03:00
if ( ver_format > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
2022-04-12 10:12:40 +03:00
f . unref ( ) ;
2020-10-05 13:52:34 +02:00
ERR_FAIL_MSG ( vformat ( " File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s). " ,
local_path , ver_format , ver_major , ver_minor , VERSION_BRANCH ) ) ;
2014-02-09 22:10:30 -03:00
}
type = get_unicode_string ( ) ;
print_bl ( " type: " + type ) ;
importmd_ofs = f - > get_64 ( ) ;
2021-07-20 21:36:56 -03:00
uint32_t flags = f - > get_32 ( ) ;
if ( flags & ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_NAMED_SCENE_IDS ) {
using_named_scene_ids = true ;
}
2021-07-23 16:01:18 -03:00
if ( flags & ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_UIDS ) {
using_uids = true ;
}
2022-02-16 00:55:13 +00:00
f - > real_is_double = ( flags & ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_REAL_T_IS_DOUBLE ) ! = 0 ;
2021-07-23 16:01:18 -03:00
if ( using_uids ) {
uid = f - > get_64 ( ) ;
} else {
2021-07-29 22:25:18 -07:00
f - > get_64 ( ) ; // skip over uid field
2021-07-23 16:01:18 -03:00
uid = ResourceUID : : INVALID_ID ;
}
2023-01-19 19:12:25 +01:00
if ( flags & ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_HAS_SCRIPT_CLASS ) {
script_class = get_unicode_string ( ) ;
}
2021-07-29 22:24:29 -07:00
for ( int i = 0 ; i < ResourceFormatSaverBinaryInstance : : RESERVED_FIELDS ; i + + ) {
2014-02-09 22:10:30 -03:00
f - > get_32 ( ) ; //skip a few reserved fields
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2021-07-23 16:01:18 -03:00
if ( p_no_resources ) {
return ;
}
2014-02-09 22:10:30 -03:00
uint32_t string_table_size = f - > get_32 ( ) ;
string_map . resize ( string_table_size ) ;
for ( uint32_t i = 0 ; i < string_table_size ; i + + ) {
StringName s = get_unicode_string ( ) ;
2018-07-25 03:11:03 +02:00
string_map . write [ i ] = s ;
2014-02-09 22:10:30 -03:00
}
print_bl ( " strings: " + itos ( string_table_size ) ) ;
uint32_t ext_resources_size = f - > get_32 ( ) ;
for ( uint32_t i = 0 ; i < ext_resources_size ; i + + ) {
2017-08-08 12:02:49 +07:00
ExtResource er ;
2014-02-09 22:10:30 -03:00
er . type = get_unicode_string ( ) ;
er . path = get_unicode_string ( ) ;
2021-07-23 16:01:18 -03:00
if ( using_uids ) {
er . uid = f - > get_64 ( ) ;
if ( ! p_keep_uuid_paths & & er . uid ! = ResourceUID : : INVALID_ID ) {
if ( ResourceUID : : get_singleton ( ) - > has_id ( er . uid ) ) {
// If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path.
er . path = ResourceUID : : get_singleton ( ) - > get_id_path ( er . uid ) ;
} else {
2022-10-09 13:52:04 +02:00
# ifdef TOOLS_ENABLED
// Silence a warning that can happen during the initial filesystem scan due to cache being regenerated.
if ( ResourceLoader : : get_resource_uid ( res_path ) ! = er . uid ) {
2022-12-05 19:01:59 +01:00
WARN_PRINT ( String ( res_path + " : In external resource # " + itos ( i ) + " , invalid UID: " + ResourceUID : : get_singleton ( ) - > id_to_text ( er . uid ) + " - using text path instead: " + er . path ) . utf8 ( ) . get_data ( ) ) ;
2022-10-09 13:52:04 +02:00
}
# else
2022-12-05 19:01:59 +01:00
WARN_PRINT ( String ( res_path + " : In external resource # " + itos ( i ) + " , invalid UID: " + ResourceUID : : get_singleton ( ) - > id_to_text ( er . uid ) + " - using text path instead: " + er . path ) . utf8 ( ) . get_data ( ) ) ;
2022-10-09 13:52:04 +02:00
# endif
2021-07-23 16:01:18 -03:00
}
}
}
2017-12-15 08:38:24 -03:00
2014-02-09 22:10:30 -03:00
external_resources . push_back ( er ) ;
}
print_bl ( " ext resources: " + itos ( ext_resources_size ) ) ;
uint32_t int_resources_size = f - > get_32 ( ) ;
for ( uint32_t i = 0 ; i < int_resources_size ; i + + ) {
2017-08-08 12:02:49 +07:00
IntResource ir ;
2014-02-09 22:10:30 -03:00
ir . path = get_unicode_string ( ) ;
ir . offset = f - > get_64 ( ) ;
internal_resources . push_back ( ir ) ;
}
print_bl ( " int resources: " + itos ( int_resources_size ) ) ;
if ( f - > eof_reached ( ) ) {
error = ERR_FILE_CORRUPT ;
2022-04-12 10:12:40 +03:00
f . unref ( ) ;
2019-08-14 20:57:49 -06:00
ERR_FAIL_MSG ( " Premature end of file (EOF): " + local_path + " . " ) ;
2014-02-09 22:10:30 -03:00
}
}
2022-03-23 11:08:58 +02:00
String ResourceLoaderBinary : : recognize ( Ref < FileAccess > p_f ) {
2014-02-09 22:10:30 -03:00
error = OK ;
f = p_f ;
uint8_t header [ 4 ] ;
f - > get_buffer ( header , 4 ) ;
if ( header [ 0 ] = = ' R ' & & header [ 1 ] = = ' S ' & & header [ 2 ] = = ' C ' & & header [ 3 ] = = ' C ' ) {
2020-02-11 11:39:20 +08:00
// Compressed.
2022-03-23 11:08:58 +02:00
Ref < FileAccessCompressed > fac ;
fac . instantiate ( ) ;
2020-02-11 11:39:20 +08:00
error = fac - > open_after_magic ( f ) ;
if ( error ! = OK ) {
2022-04-12 10:12:40 +03:00
f . unref ( ) ;
2020-02-11 11:39:20 +08:00
return " " ;
}
2014-02-09 22:10:30 -03:00
f = fac ;
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
2020-02-11 11:39:20 +08:00
// Not normal.
2014-04-05 12:39:30 -03:00
error = ERR_FILE_UNRECOGNIZED ;
2022-04-12 10:12:40 +03:00
f . unref ( ) ;
2014-02-09 22:10:30 -03:00
return " " ;
}
bool big_endian = f - > get_32 ( ) ;
2017-09-02 22:32:31 +02:00
f - > get_32 ( ) ; // use_real64
2014-02-09 22:10:30 -03:00
2021-05-20 14:58:03 +02:00
f - > set_big_endian ( big_endian ! = 0 ) ; //read big endian if saved as big endian
2014-02-09 22:10:30 -03:00
uint32_t ver_major = f - > get_32 ( ) ;
2017-09-02 22:32:31 +02:00
f - > get_32 ( ) ; // ver_minor
2022-09-29 12:53:28 +03:00
uint32_t ver_fmt = f - > get_32 ( ) ;
2014-02-09 22:10:30 -03:00
2022-09-29 12:53:28 +03:00
if ( ver_fmt > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
2022-04-12 10:12:40 +03:00
f . unref ( ) ;
2014-02-09 22:10:30 -03:00
return " " ;
}
2022-09-29 12:53:28 +03:00
return get_unicode_string ( ) ;
2014-02-09 22:10:30 -03:00
}
2023-01-19 19:12:25 +01:00
String ResourceLoaderBinary : : recognize_script_class ( Ref < FileAccess > p_f ) {
error = OK ;
f = p_f ;
uint8_t header [ 4 ] ;
f - > get_buffer ( header , 4 ) ;
if ( header [ 0 ] = = ' R ' & & header [ 1 ] = = ' S ' & & header [ 2 ] = = ' C ' & & header [ 3 ] = = ' C ' ) {
// Compressed.
Ref < FileAccessCompressed > fac ;
fac . instantiate ( ) ;
error = fac - > open_after_magic ( f ) ;
if ( error ! = OK ) {
f . unref ( ) ;
return " " ;
}
f = fac ;
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
// Not normal.
error = ERR_FILE_UNRECOGNIZED ;
f . unref ( ) ;
return " " ;
}
bool big_endian = f - > get_32 ( ) ;
f - > get_32 ( ) ; // use_real64
f - > set_big_endian ( big_endian ! = 0 ) ; //read big endian if saved as big endian
uint32_t ver_major = f - > get_32 ( ) ;
f - > get_32 ( ) ; // ver_minor
uint32_t ver_fmt = f - > get_32 ( ) ;
if ( ver_fmt > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
f . unref ( ) ;
return " " ;
}
get_unicode_string ( ) ; // type
f - > get_64 ( ) ; // Metadata offset
uint32_t flags = f - > get_32 ( ) ;
f - > get_64 ( ) ; // UID
if ( flags & ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_HAS_SCRIPT_CLASS ) {
return get_unicode_string ( ) ;
} else {
return String ( ) ;
}
}
2022-05-03 01:43:50 +02:00
Ref < Resource > ResourceFormatLoaderBinary : : load ( const String & p_path , const String & p_original_path , Error * r_error , bool p_use_sub_threads , float * r_progress , CacheMode p_cache_mode ) {
2020-05-14 16:41:43 +02:00
if ( r_error ) {
2015-08-23 20:15:56 -03:00
* r_error = ERR_FILE_CANT_OPEN ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
Error err ;
2022-03-23 11:08:58 +02:00
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ , & err ) ;
2014-02-09 22:10:30 -03:00
2022-05-03 01:43:50 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , Ref < Resource > ( ) , " Cannot open file ' " + p_path + " '. " ) ;
2014-02-09 22:10:30 -03:00
2020-02-28 08:27:04 -03:00
ResourceLoaderBinary loader ;
2024-02-22 12:53:19 +01:00
switch ( p_cache_mode ) {
case CACHE_MODE_IGNORE :
case CACHE_MODE_REUSE :
case CACHE_MODE_REPLACE :
loader . cache_mode = p_cache_mode ;
loader . cache_mode_for_external = CACHE_MODE_REUSE ;
break ;
case CACHE_MODE_IGNORE_DEEP :
loader . cache_mode = CACHE_MODE_IGNORE ;
loader . cache_mode_for_external = p_cache_mode ;
break ;
case CACHE_MODE_REPLACE_DEEP :
loader . cache_mode = CACHE_MODE_REPLACE ;
loader . cache_mode_for_external = p_cache_mode ;
break ;
}
2020-02-28 08:27:04 -03:00
loader . use_sub_threads = p_use_sub_threads ;
loader . progress = r_progress ;
2021-12-09 03:42:46 -06:00
String path = ! p_original_path . is_empty ( ) ? p_original_path : p_path ;
2020-02-28 08:27:04 -03:00
loader . local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( path ) ;
loader . res_path = loader . local_path ;
loader . open ( f ) ;
2014-02-09 22:10:30 -03:00
2020-02-28 08:27:04 -03:00
err = loader . load ( ) ;
if ( r_error ) {
* r_error = err ;
}
if ( err ) {
2022-05-03 01:43:50 +02:00
return Ref < Resource > ( ) ;
2020-02-28 08:27:04 -03:00
}
return loader . resource ;
2014-02-09 22:10:30 -03:00
}
void ResourceFormatLoaderBinary : : get_recognized_extensions_for_type ( const String & p_type , List < String > * p_extensions ) const {
2021-12-09 03:42:46 -06:00
if ( p_type . is_empty ( ) ) {
2014-02-09 22:10:30 -03:00
get_recognized_extensions ( p_extensions ) ;
return ;
}
2024-10-09 19:40:49 -04:00
// res files not supported for GDExtension.
if ( p_type = = " GDExtension " ) {
return ;
}
2014-02-09 22:10:30 -03:00
List < String > extensions ;
2017-01-02 23:03:46 -03:00
ClassDB : : get_extensions_for_type ( p_type , & extensions ) ;
2014-02-09 22:10:30 -03:00
extensions . sort ( ) ;
2021-07-24 15:46:25 +02:00
for ( const String & E : extensions ) {
2021-07-15 23:45:57 -04:00
String ext = E . to_lower ( ) ;
2014-02-09 22:10:30 -03:00
p_extensions - > push_back ( ext ) ;
}
}
2020-05-14 14:29:06 +02:00
2014-02-09 22:10:30 -03:00
void ResourceFormatLoaderBinary : : get_recognized_extensions ( List < String > * p_extensions ) const {
List < String > extensions ;
2017-01-02 23:03:46 -03:00
ClassDB : : get_resource_base_extensions ( & extensions ) ;
2014-02-09 22:10:30 -03:00
extensions . sort ( ) ;
2021-07-24 15:46:25 +02:00
for ( const String & E : extensions ) {
2021-07-15 23:45:57 -04:00
String ext = E . to_lower ( ) ;
2014-02-09 22:10:30 -03:00
p_extensions - > push_back ( ext ) ;
}
}
bool ResourceFormatLoaderBinary : : handles_type ( const String & p_type ) const {
return true ; //handles all
}
2015-08-23 20:15:56 -03:00
void ResourceFormatLoaderBinary : : get_dependencies ( const String & p_path , List < String > * p_dependencies , bool p_add_types ) {
2022-03-23 11:08:58 +02:00
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
ERR_FAIL_COND_MSG ( f . is_null ( ) , " Cannot open file ' " + p_path + " '. " ) ;
2014-02-09 22:10:30 -03:00
2020-02-28 08:27:04 -03:00
ResourceLoaderBinary loader ;
loader . local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
loader . res_path = loader . local_path ;
loader . get_dependencies ( f , p_dependencies , p_add_types ) ;
2015-08-23 20:15:56 -03:00
}
2022-05-13 15:04:37 +02:00
Error ResourceFormatLoaderBinary : : rename_dependencies ( const String & p_path , const HashMap < String , String > & p_map ) {
2022-03-23 11:08:58 +02:00
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
ERR_FAIL_COND_V_MSG ( f . is_null ( ) , ERR_CANT_OPEN , " Cannot open file ' " + p_path + " '. " ) ;
2015-08-23 20:15:56 -03:00
2022-03-23 11:08:58 +02:00
Ref < FileAccess > fw ;
2015-08-23 20:15:56 -03:00
String local_path = p_path . get_base_dir ( ) ;
uint8_t header [ 4 ] ;
f - > get_buffer ( header , 4 ) ;
if ( header [ 0 ] = = ' R ' & & header [ 1 ] = = ' S ' & & header [ 2 ] = = ' C ' & & header [ 3 ] = = ' C ' ) {
2020-02-11 11:39:20 +08:00
// Compressed.
2022-03-23 11:08:58 +02:00
Ref < FileAccessCompressed > fac ;
fac . instantiate ( ) ;
2020-02-11 11:39:20 +08:00
Error err = fac - > open_after_magic ( f ) ;
2022-03-23 11:08:58 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Cannot open file ' " + p_path + " '. " ) ;
2015-08-23 20:15:56 -03:00
f = fac ;
2022-03-23 11:08:58 +02:00
Ref < FileAccessCompressed > facw ;
facw . instantiate ( ) ;
2015-08-23 20:15:56 -03:00
facw - > configure ( " RSCC " ) ;
2022-09-05 13:01:31 +02:00
err = facw - > open_internal ( p_path + " .depren " , FileAccess : : WRITE ) ;
2022-03-23 11:08:58 +02:00
ERR_FAIL_COND_V_MSG ( err , ERR_FILE_CORRUPT , " Cannot create file ' " + p_path + " .depren'. " ) ;
2015-08-23 20:15:56 -03:00
fw = facw ;
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
2020-02-11 11:39:20 +08:00
// Not normal.
2019-09-25 10:28:50 +02:00
ERR_FAIL_V_MSG ( ERR_FILE_UNRECOGNIZED , " Unrecognized binary resource file ' " + local_path + " '. " ) ;
2015-08-23 20:15:56 -03:00
} else {
fw = FileAccess : : open ( p_path + " .depren " , FileAccess : : WRITE ) ;
2022-03-23 11:08:58 +02:00
ERR_FAIL_COND_V_MSG ( fw . is_null ( ) , ERR_CANT_CREATE , " Cannot create file ' " + p_path + " .depren'. " ) ;
2017-09-03 00:22:54 -03:00
uint8_t magic [ 4 ] = { ' R ' , ' S ' , ' R ' , ' C ' } ;
fw - > store_buffer ( magic , 4 ) ;
2015-08-23 20:15:56 -03:00
}
bool big_endian = f - > get_32 ( ) ;
bool use_real64 = f - > get_32 ( ) ;
2021-05-20 14:58:03 +02:00
f - > set_big_endian ( big_endian ! = 0 ) ; //read big endian if saved as big endian
2017-09-02 22:32:31 +02:00
# ifdef BIG_ENDIAN_ENABLED
fw - > store_32 ( ! big_endian ) ;
# else
fw - > store_32 ( big_endian ) ;
# endif
2021-05-20 14:58:03 +02:00
fw - > set_big_endian ( big_endian ! = 0 ) ;
2015-08-23 20:15:56 -03:00
fw - > store_32 ( use_real64 ) ; //use real64
uint32_t ver_major = f - > get_32 ( ) ;
uint32_t ver_minor = f - > get_32 ( ) ;
uint32_t ver_format = f - > get_32 ( ) ;
if ( ver_format < FORMAT_VERSION_CAN_RENAME_DEPS ) {
2022-04-22 18:15:31 +08:00
fw . unref ( ) ;
2022-03-10 15:27:09 +01:00
{
2022-03-23 11:08:58 +02:00
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
2022-03-10 15:27:09 +01:00
da - > remove ( p_path + " .depren " ) ;
}
// Use the old approach.
2015-08-23 20:15:56 -03:00
2019-11-07 09:44:15 +01:00
WARN_PRINT ( " This file is old, so it can't refactor dependencies, opening and resaving ' " + p_path + " '. " ) ;
2015-08-23 20:15:56 -03:00
Error err ;
f = FileAccess : : open ( p_path , FileAccess : : READ , & err ) ;
2019-06-20 16:59:48 +02:00
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , ERR_FILE_CANT_OPEN , " Cannot open file ' " + p_path + " '. " ) ;
2015-08-23 20:15:56 -03:00
2020-02-28 08:27:04 -03:00
ResourceLoaderBinary loader ;
loader . local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
loader . res_path = loader . local_path ;
loader . remaps = p_map ;
loader . open ( f ) ;
2015-08-23 20:15:56 -03:00
2020-02-28 08:27:04 -03:00
err = loader . load ( ) ;
2015-08-23 20:15:56 -03:00
ERR_FAIL_COND_V ( err ! = ERR_FILE_EOF , ERR_FILE_CORRUPT ) ;
2022-05-03 01:43:50 +02:00
Ref < Resource > res = loader . get_resource ( ) ;
2015-08-23 20:15:56 -03:00
ERR_FAIL_COND_V ( ! res . is_valid ( ) , ERR_FILE_CORRUPT ) ;
2022-06-03 01:33:42 +02:00
return ResourceFormatSaverBinary : : singleton - > save ( res , p_path ) ;
2015-08-23 20:15:56 -03:00
}
if ( ver_format > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
2020-10-05 13:52:34 +02:00
ERR_FAIL_V_MSG ( ERR_FILE_UNRECOGNIZED ,
vformat ( " File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s). " ,
local_path , ver_format , ver_major , ver_minor , VERSION_BRANCH ) ) ;
2015-08-23 20:15:56 -03:00
}
2018-03-19 16:37:57 +01:00
// Since we're not actually converting the file contents, leave the version
// numbers in the file untouched.
fw - > store_32 ( ver_major ) ;
fw - > store_32 ( ver_minor ) ;
fw - > store_32 ( ver_format ) ;
2015-08-23 20:15:56 -03:00
save_ustring ( fw , get_ustring ( f ) ) ; //type
2019-03-26 18:51:13 +01:00
uint64_t md_ofs = f - > get_position ( ) ;
uint64_t importmd_ofs = f - > get_64 ( ) ;
2015-08-23 20:15:56 -03:00
fw - > store_64 ( 0 ) ; //metadata offset
2021-07-23 16:01:18 -03:00
uint32_t flags = f - > get_32 ( ) ;
bool using_uids = ( flags & ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_UIDS ) ;
uint64_t uid_data = f - > get_64 ( ) ;
fw - > store_32 ( flags ) ;
fw - > store_64 ( uid_data ) ;
2023-01-19 19:12:25 +01:00
if ( flags & ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_HAS_SCRIPT_CLASS ) {
save_ustring ( fw , get_ustring ( f ) ) ;
}
2021-07-23 16:01:18 -03:00
2021-07-29 22:24:29 -07:00
for ( int i = 0 ; i < ResourceFormatSaverBinaryInstance : : RESERVED_FIELDS ; i + + ) {
2021-07-29 18:17:49 -07:00
fw - > store_32 ( 0 ) ; // reserved
2015-08-23 20:15:56 -03:00
f - > get_32 ( ) ;
}
//string table
uint32_t string_table_size = f - > get_32 ( ) ;
fw - > store_32 ( string_table_size ) ;
for ( uint32_t i = 0 ; i < string_table_size ; i + + ) {
String s = get_ustring ( f ) ;
save_ustring ( fw , s ) ;
}
//external resources
uint32_t ext_resources_size = f - > get_32 ( ) ;
fw - > store_32 ( ext_resources_size ) ;
for ( uint32_t i = 0 ; i < ext_resources_size ; i + + ) {
String type = get_ustring ( f ) ;
String path = get_ustring ( f ) ;
2021-07-23 16:01:18 -03:00
if ( using_uids ) {
ResourceUID : : ID uid = f - > get_64 ( ) ;
if ( uid ! = ResourceUID : : INVALID_ID ) {
if ( ResourceUID : : get_singleton ( ) - > has_id ( uid ) ) {
// If a UID is found and the path is valid, it will be used, otherwise, it falls back to the path.
path = ResourceUID : : get_singleton ( ) - > get_id_path ( uid ) ;
}
}
}
2015-08-23 20:15:56 -03:00
bool relative = false ;
if ( ! path . begins_with ( " res:// " ) ) {
2022-08-29 19:34:01 -05:00
path = local_path . path_join ( path ) . simplify_path ( ) ;
2015-08-23 20:15:56 -03:00
relative = true ;
}
if ( p_map . has ( path ) ) {
String np = p_map [ path ] ;
path = np ;
}
2021-07-23 16:01:18 -03:00
String full_path = path ;
2015-08-23 20:15:56 -03:00
if ( relative ) {
//restore relative
path = local_path . path_to_file ( path ) ;
}
save_ustring ( fw , type ) ;
save_ustring ( fw , path ) ;
2021-07-23 16:01:18 -03:00
if ( using_uids ) {
ResourceUID : : ID uid = ResourceSaver : : get_resource_id_for_path ( full_path ) ;
2021-07-29 18:17:49 -07:00
fw - > store_64 ( uid ) ;
2021-07-23 16:01:18 -03:00
}
2015-08-23 20:15:56 -03:00
}
2017-09-10 15:37:49 +02:00
int64_t size_diff = ( int64_t ) fw - > get_position ( ) - ( int64_t ) f - > get_position ( ) ;
2015-08-23 20:15:56 -03:00
//internal resources
uint32_t int_resources_size = f - > get_32 ( ) ;
fw - > store_32 ( int_resources_size ) ;
for ( uint32_t i = 0 ; i < int_resources_size ; i + + ) {
String path = get_ustring ( f ) ;
uint64_t offset = f - > get_64 ( ) ;
save_ustring ( fw , path ) ;
fw - > store_64 ( offset + size_diff ) ;
}
//rest of file
uint8_t b = f - > get_8 ( ) ;
while ( ! f - > eof_reached ( ) ) {
fw - > store_8 ( b ) ;
b = f - > get_8 ( ) ;
}
2022-05-02 16:37:50 +03:00
f . unref ( ) ;
2015-08-23 20:15:56 -03:00
bool all_ok = fw - > get_error ( ) = = OK ;
fw - > seek ( md_ofs ) ;
fw - > store_64 ( importmd_ofs + size_diff ) ;
if ( ! all_ok ) {
return ERR_CANT_CREATE ;
}
2022-04-22 18:15:31 +08:00
fw . unref ( ) ;
2022-03-23 11:08:58 +02:00
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
2023-12-14 22:28:48 +01:00
if ( da - > exists ( p_path + " .depren " ) ) {
da - > remove ( p_path ) ;
da - > rename ( p_path + " .depren " , p_path ) ;
}
2015-08-23 20:15:56 -03:00
return OK ;
2014-02-09 22:10:30 -03:00
}
2022-07-14 14:18:18 +02:00
void ResourceFormatLoaderBinary : : get_classes_used ( const String & p_path , HashSet < StringName > * r_classes ) {
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
ERR_FAIL_COND_MSG ( f . is_null ( ) , " Cannot open file ' " + p_path + " '. " ) ;
ResourceLoaderBinary loader ;
loader . local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
loader . res_path = loader . local_path ;
loader . get_classes_used ( f , r_classes ) ;
}
2014-02-09 22:10:30 -03:00
String ResourceFormatLoaderBinary : : get_resource_type ( const String & p_path ) const {
2022-03-23 11:08:58 +02:00
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
if ( f . is_null ( ) ) {
2021-03-12 19:05:16 +05:30
return " " ; //could not read
2014-02-09 22:10:30 -03:00
}
2020-02-28 08:27:04 -03:00
ResourceLoaderBinary loader ;
loader . local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
loader . res_path = loader . local_path ;
String r = loader . recognize ( f ) ;
2019-10-03 17:39:08 -03:00
return ClassDB : : get_compatibility_remapped_class ( r ) ;
2014-02-09 22:10:30 -03:00
}
2023-01-19 19:12:25 +01:00
String ResourceFormatLoaderBinary : : get_resource_script_class ( const String & p_path ) const {
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
if ( f . is_null ( ) ) {
return " " ; //could not read
}
ResourceLoaderBinary loader ;
loader . local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
loader . res_path = loader . local_path ;
return loader . recognize_script_class ( f ) ;
}
2021-07-23 16:01:18 -03:00
ResourceUID : : ID ResourceFormatLoaderBinary : : get_resource_uid ( const String & p_path ) const {
String ext = p_path . get_extension ( ) . to_lower ( ) ;
if ( ! ClassDB : : is_resource_extension ( ext ) ) {
return ResourceUID : : INVALID_ID ;
}
2022-03-23 11:08:58 +02:00
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
if ( f . is_null ( ) ) {
2021-07-23 16:01:18 -03:00
return ResourceUID : : INVALID_ID ; //could not read
}
ResourceLoaderBinary loader ;
loader . local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
loader . res_path = loader . local_path ;
loader . open ( f , true ) ;
if ( loader . error ! = OK ) {
return ResourceUID : : INVALID_ID ; //could not read
}
return loader . uid ;
}
2014-02-09 22:10:30 -03:00
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
2022-03-23 11:08:58 +02:00
void ResourceFormatSaverBinaryInstance : : _pad_buffer ( Ref < FileAccess > f , int p_bytes ) {
2014-02-09 22:10:30 -03:00
int extra = 4 - ( p_bytes % 4 ) ;
if ( extra < 4 ) {
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < extra ; i + + ) {
2014-02-09 22:10:30 -03:00
f - > store_8 ( 0 ) ; //pad to 32
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
}
2022-05-13 15:04:37 +02:00
void ResourceFormatSaverBinaryInstance : : write_variant ( Ref < FileAccess > f , const Variant & p_property , HashMap < Ref < Resource > , int > & resource_map , HashMap < Ref < Resource > , int > & external_resources , HashMap < StringName , int > & string_map , const PropertyInfo & p_hint ) {
2014-02-09 22:10:30 -03:00
switch ( p_property . get_type ( ) ) {
case Variant : : NIL : {
f - > store_32 ( VARIANT_NIL ) ;
// don't store anything
} break ;
case Variant : : BOOL : {
f - > store_32 ( VARIANT_BOOL ) ;
bool val = p_property ;
f - > store_32 ( val ) ;
} break ;
case Variant : : INT : {
2017-01-08 20:58:39 -03:00
int64_t val = p_property ;
2018-10-04 14:38:52 +01:00
if ( val > 0x7FFFFFFF | | val < - ( int64_t ) 0x80000000 ) {
2017-01-08 20:58:39 -03:00
f - > store_32 ( VARIANT_INT64 ) ;
f - > store_64 ( val ) ;
} else {
f - > store_32 ( VARIANT_INT ) ;
2019-02-12 21:10:08 +01:00
f - > store_32 ( int32_t ( p_property ) ) ;
2017-01-08 20:58:39 -03:00
}
2014-02-09 22:10:30 -03:00
} break ;
2020-02-24 15:20:53 -03:00
case Variant : : FLOAT : {
2017-01-08 20:58:39 -03:00
double d = p_property ;
float fl = d ;
if ( double ( fl ) ! = d ) {
f - > store_32 ( VARIANT_DOUBLE ) ;
f - > store_double ( d ) ;
} else {
2020-02-24 15:20:53 -03:00
f - > store_32 ( VARIANT_FLOAT ) ;
2017-01-08 20:58:39 -03:00
f - > store_real ( fl ) ;
}
2014-02-09 22:10:30 -03:00
} break ;
case Variant : : STRING : {
f - > store_32 ( VARIANT_STRING ) ;
String val = p_property ;
2017-12-15 08:38:24 -03:00
save_unicode_string ( f , val ) ;
2014-02-09 22:10:30 -03:00
} break ;
case Variant : : VECTOR2 : {
f - > store_32 ( VARIANT_VECTOR2 ) ;
Vector2 val = p_property ;
f - > store_real ( val . x ) ;
f - > store_real ( val . y ) ;
2020-02-22 00:26:41 -03:00
} break ;
case Variant : : VECTOR2I : {
f - > store_32 ( VARIANT_VECTOR2I ) ;
Vector2i val = p_property ;
f - > store_32 ( val . x ) ;
f - > store_32 ( val . y ) ;
2014-02-09 22:10:30 -03:00
} break ;
case Variant : : RECT2 : {
f - > store_32 ( VARIANT_RECT2 ) ;
Rect2 val = p_property ;
2017-06-04 00:25:13 +02:00
f - > store_real ( val . position . x ) ;
f - > store_real ( val . position . y ) ;
2014-02-09 22:10:30 -03:00
f - > store_real ( val . size . x ) ;
f - > store_real ( val . size . y ) ;
2020-02-22 00:26:41 -03:00
} break ;
case Variant : : RECT2I : {
f - > store_32 ( VARIANT_RECT2I ) ;
Rect2i val = p_property ;
f - > store_32 ( val . position . x ) ;
f - > store_32 ( val . position . y ) ;
f - > store_32 ( val . size . x ) ;
f - > store_32 ( val . size . y ) ;
2014-02-09 22:10:30 -03:00
} break ;
case Variant : : VECTOR3 : {
f - > store_32 ( VARIANT_VECTOR3 ) ;
Vector3 val = p_property ;
f - > store_real ( val . x ) ;
f - > store_real ( val . y ) ;
f - > store_real ( val . z ) ;
2020-02-22 00:26:41 -03:00
} break ;
case Variant : : VECTOR3I : {
f - > store_32 ( VARIANT_VECTOR3I ) ;
Vector3i val = p_property ;
f - > store_32 ( val . x ) ;
f - > store_32 ( val . y ) ;
f - > store_32 ( val . z ) ;
2022-07-20 01:11:13 +02:00
} break ;
case Variant : : VECTOR4 : {
f - > store_32 ( VARIANT_VECTOR4 ) ;
Vector4 val = p_property ;
f - > store_real ( val . x ) ;
f - > store_real ( val . y ) ;
f - > store_real ( val . z ) ;
f - > store_real ( val . w ) ;
} break ;
case Variant : : VECTOR4I : {
f - > store_32 ( VARIANT_VECTOR4I ) ;
Vector4i val = p_property ;
f - > store_32 ( val . x ) ;
f - > store_32 ( val . y ) ;
f - > store_32 ( val . z ) ;
f - > store_32 ( val . w ) ;
2014-02-09 22:10:30 -03:00
} break ;
case Variant : : PLANE : {
f - > store_32 ( VARIANT_PLANE ) ;
Plane val = p_property ;
f - > store_real ( val . normal . x ) ;
f - > store_real ( val . normal . y ) ;
f - > store_real ( val . normal . z ) ;
2020-05-10 16:47:11 +02:00
f - > store_real ( val . d ) ;
2014-02-09 22:10:30 -03:00
} break ;
2021-01-20 07:02:02 +00:00
case Variant : : QUATERNION : {
f - > store_32 ( VARIANT_QUATERNION ) ;
Quaternion val = p_property ;
2014-02-09 22:10:30 -03:00
f - > store_real ( val . x ) ;
f - > store_real ( val . y ) ;
f - > store_real ( val . z ) ;
f - > store_real ( val . w ) ;
} break ;
2017-11-16 21:09:00 -05:00
case Variant : : AABB : {
f - > store_32 ( VARIANT_AABB ) ;
AABB val = p_property ;
2017-06-06 20:33:51 +02:00
f - > store_real ( val . position . x ) ;
f - > store_real ( val . position . y ) ;
f - > store_real ( val . position . z ) ;
2014-02-09 22:10:30 -03:00
f - > store_real ( val . size . x ) ;
f - > store_real ( val . size . y ) ;
f - > store_real ( val . size . z ) ;
} break ;
2017-01-11 00:52:51 -03:00
case Variant : : TRANSFORM2D : {
2021-12-27 17:28:25 -08:00
f - > store_32 ( VARIANT_TRANSFORM2D ) ;
2017-01-11 00:52:51 -03:00
Transform2D val = p_property ;
2022-04-24 16:59:24 -05:00
f - > store_real ( val . columns [ 0 ] . x ) ;
f - > store_real ( val . columns [ 0 ] . y ) ;
f - > store_real ( val . columns [ 1 ] . x ) ;
f - > store_real ( val . columns [ 1 ] . y ) ;
f - > store_real ( val . columns [ 2 ] . x ) ;
f - > store_real ( val . columns [ 2 ] . y ) ;
2014-02-09 22:10:30 -03:00
} break ;
2017-01-11 00:52:51 -03:00
case Variant : : BASIS : {
2021-12-27 17:28:25 -08:00
f - > store_32 ( VARIANT_BASIS ) ;
2017-01-11 00:52:51 -03:00
Basis val = p_property ;
2022-04-24 17:07:35 -05:00
f - > store_real ( val . rows [ 0 ] . x ) ;
f - > store_real ( val . rows [ 0 ] . y ) ;
f - > store_real ( val . rows [ 0 ] . z ) ;
f - > store_real ( val . rows [ 1 ] . x ) ;
f - > store_real ( val . rows [ 1 ] . y ) ;
f - > store_real ( val . rows [ 1 ] . z ) ;
f - > store_real ( val . rows [ 2 ] . x ) ;
f - > store_real ( val . rows [ 2 ] . y ) ;
f - > store_real ( val . rows [ 2 ] . z ) ;
2014-02-09 22:10:30 -03:00
} break ;
2021-04-28 03:36:08 -04:00
case Variant : : TRANSFORM3D : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_TRANSFORM3D ) ;
2020-10-17 01:08:21 -04:00
Transform3D val = p_property ;
2022-04-24 17:07:35 -05:00
f - > store_real ( val . basis . rows [ 0 ] . x ) ;
f - > store_real ( val . basis . rows [ 0 ] . y ) ;
f - > store_real ( val . basis . rows [ 0 ] . z ) ;
f - > store_real ( val . basis . rows [ 1 ] . x ) ;
f - > store_real ( val . basis . rows [ 1 ] . y ) ;
f - > store_real ( val . basis . rows [ 1 ] . z ) ;
f - > store_real ( val . basis . rows [ 2 ] . x ) ;
f - > store_real ( val . basis . rows [ 2 ] . y ) ;
f - > store_real ( val . basis . rows [ 2 ] . z ) ;
2014-02-09 22:10:30 -03:00
f - > store_real ( val . origin . x ) ;
f - > store_real ( val . origin . y ) ;
f - > store_real ( val . origin . z ) ;
2022-07-20 01:11:13 +02:00
} break ;
case Variant : : PROJECTION : {
f - > store_32 ( VARIANT_PROJECTION ) ;
Projection val = p_property ;
2022-10-04 11:44:48 -05:00
f - > store_real ( val . columns [ 0 ] . x ) ;
f - > store_real ( val . columns [ 0 ] . y ) ;
f - > store_real ( val . columns [ 0 ] . z ) ;
f - > store_real ( val . columns [ 0 ] . w ) ;
f - > store_real ( val . columns [ 1 ] . x ) ;
f - > store_real ( val . columns [ 1 ] . y ) ;
f - > store_real ( val . columns [ 1 ] . z ) ;
f - > store_real ( val . columns [ 1 ] . w ) ;
f - > store_real ( val . columns [ 2 ] . x ) ;
f - > store_real ( val . columns [ 2 ] . y ) ;
f - > store_real ( val . columns [ 2 ] . z ) ;
f - > store_real ( val . columns [ 2 ] . w ) ;
f - > store_real ( val . columns [ 3 ] . x ) ;
f - > store_real ( val . columns [ 3 ] . y ) ;
f - > store_real ( val . columns [ 3 ] . z ) ;
f - > store_real ( val . columns [ 3 ] . w ) ;
2022-07-20 01:11:13 +02:00
2014-02-09 22:10:30 -03:00
} break ;
case Variant : : COLOR : {
f - > store_32 ( VARIANT_COLOR ) ;
Color val = p_property ;
2022-06-08 14:32:41 +02:00
// Color are always floats
f - > store_float ( val . r ) ;
f - > store_float ( val . g ) ;
f - > store_float ( val . b ) ;
f - > store_float ( val . a ) ;
2014-02-09 22:10:30 -03:00
2020-02-20 18:58:05 -03:00
} break ;
case Variant : : STRING_NAME : {
f - > store_32 ( VARIANT_STRING_NAME ) ;
String val = p_property ;
save_unicode_string ( f , val ) ;
2014-02-09 22:10:30 -03:00
} break ;
case Variant : : NODE_PATH : {
f - > store_32 ( VARIANT_NODE_PATH ) ;
NodePath np = p_property ;
f - > store_16 ( np . get_name_count ( ) ) ;
uint16_t snc = np . get_subname_count ( ) ;
2020-05-14 16:41:43 +02:00
if ( np . is_absolute ( ) ) {
2014-02-09 22:10:30 -03:00
snc | = 0x8000 ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
f - > store_16 ( snc ) ;
2017-12-15 08:38:24 -03:00
for ( int i = 0 ; i < np . get_name_count ( ) ; i + + ) {
if ( string_map . has ( np . get_name ( i ) ) ) {
f - > store_32 ( string_map [ np . get_name ( i ) ] ) ;
} else {
save_unicode_string ( f , np . get_name ( i ) , true ) ;
}
}
for ( int i = 0 ; i < np . get_subname_count ( ) ; i + + ) {
if ( string_map . has ( np . get_subname ( i ) ) ) {
f - > store_32 ( string_map [ np . get_subname ( i ) ] ) ;
} else {
save_unicode_string ( f , np . get_subname ( i ) , true ) ;
}
}
2014-02-09 22:10:30 -03:00
} break ;
2020-11-09 14:53:05 +01:00
case Variant : : RID : {
2014-02-09 22:10:30 -03:00
f - > store_32 ( VARIANT_RID ) ;
2019-08-14 20:57:49 -06:00
WARN_PRINT ( " Can't save RIDs. " ) ;
2014-02-09 22:10:30 -03:00
RID val = p_property ;
f - > store_32 ( val . get_id ( ) ) ;
} break ;
case Variant : : OBJECT : {
f - > store_32 ( VARIANT_OBJECT ) ;
2022-05-03 01:43:50 +02:00
Ref < Resource > res = p_property ;
2023-07-01 01:29:46 +02:00
if ( res . is_null ( ) | | res - > get_meta ( SNAME ( " _skip_save_ " ) , false ) ) {
2014-02-09 22:10:30 -03:00
f - > store_32 ( OBJECT_EMPTY ) ;
2023-07-01 01:29:46 +02:00
return ; // Don't save it.
2014-02-09 22:10:30 -03:00
}
2021-07-10 21:17:41 +02:00
if ( ! res - > is_built_in ( ) ) {
2015-08-23 20:15:56 -03:00
f - > store_32 ( OBJECT_EXTERNAL_RESOURCE_INDEX ) ;
f - > store_32 ( external_resources [ res ] ) ;
2014-02-09 22:10:30 -03:00
} else {
2021-07-20 21:36:56 -03:00
if ( ! resource_map . has ( res ) ) {
2014-02-09 22:10:30 -03:00
f - > store_32 ( OBJECT_EMPTY ) ;
2019-08-14 20:57:49 -06:00
ERR_FAIL_MSG ( " Resource was not pre cached for the resource section, most likely due to circular reference. " ) ;
2014-02-09 22:10:30 -03:00
}
f - > store_32 ( OBJECT_INTERNAL_RESOURCE ) ;
2021-07-20 21:36:56 -03:00
f - > store_32 ( resource_map [ res ] ) ;
2014-02-09 22:10:30 -03:00
//internal resource
}
} break ;
2020-02-19 16:27:19 -03:00
case Variant : : CALLABLE : {
f - > store_32 ( VARIANT_CALLABLE ) ;
WARN_PRINT ( " Can't save Callables. " ) ;
} break ;
case Variant : : SIGNAL : {
f - > store_32 ( VARIANT_SIGNAL ) ;
WARN_PRINT ( " Can't save Signals. " ) ;
} break ;
2014-02-09 22:10:30 -03:00
case Variant : : DICTIONARY : {
f - > store_32 ( VARIANT_DICTIONARY ) ;
Dictionary d = p_property ;
2017-01-11 08:53:31 -03:00
f - > store_32 ( uint32_t ( d . size ( ) ) ) ;
2014-02-09 22:10:30 -03:00
List < Variant > keys ;
d . get_key_list ( & keys ) ;
2021-07-24 15:46:25 +02:00
for ( const Variant & E : keys ) {
2021-07-15 23:45:57 -04:00
write_variant ( f , E , resource_map , external_resources , string_map ) ;
write_variant ( f , d [ E ] , resource_map , external_resources , string_map ) ;
2014-02-09 22:10:30 -03:00
}
} break ;
case Variant : : ARRAY : {
f - > store_32 ( VARIANT_ARRAY ) ;
Array a = p_property ;
2017-01-11 08:53:31 -03:00
f - > store_32 ( uint32_t ( a . size ( ) ) ) ;
2023-12-24 13:44:21 +01:00
for ( const Variant & var : a ) {
write_variant ( f , var , resource_map , external_resources , string_map ) ;
2014-02-09 22:10:30 -03:00
}
} break ;
2020-02-17 18:06:54 -03:00
case Variant : : PACKED_BYTE_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_BYTE_ARRAY ) ;
2020-02-17 18:06:54 -03:00
Vector < uint8_t > arr = p_property ;
2014-02-09 22:10:30 -03:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
2020-02-17 18:06:54 -03:00
const uint8_t * r = arr . ptr ( ) ;
f - > store_buffer ( r , len ) ;
2017-12-15 08:38:24 -03:00
_pad_buffer ( f , len ) ;
2014-02-09 22:10:30 -03:00
} break ;
2020-02-24 15:20:53 -03:00
case Variant : : PACKED_INT32_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_INT32_ARRAY ) ;
2020-02-24 15:20:53 -03:00
Vector < int32_t > arr = p_property ;
2014-02-09 22:10:30 -03:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
2020-02-24 15:20:53 -03:00
const int32_t * r = arr . ptr ( ) ;
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < len ; i + + ) {
2014-02-09 22:10:30 -03:00
f - > store_32 ( r [ i ] ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
} break ;
2020-02-24 15:20:53 -03:00
case Variant : : PACKED_INT64_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_INT64_ARRAY ) ;
2020-02-24 15:20:53 -03:00
Vector < int64_t > arr = p_property ;
2014-02-09 22:10:30 -03:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
2020-02-24 15:20:53 -03:00
const int64_t * r = arr . ptr ( ) ;
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < len ; i + + ) {
2020-02-24 15:20:53 -03:00
f - > store_64 ( r [ i ] ) ;
2020-05-14 16:41:43 +02:00
}
2020-02-24 15:20:53 -03:00
} break ;
case Variant : : PACKED_FLOAT32_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_FLOAT32_ARRAY ) ;
2020-02-24 15:20:53 -03:00
Vector < float > arr = p_property ;
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
const float * r = arr . ptr ( ) ;
2014-02-09 22:10:30 -03:00
for ( int i = 0 ; i < len ; i + + ) {
2022-06-08 14:32:41 +02:00
f - > store_float ( r [ i ] ) ;
2014-02-09 22:10:30 -03:00
}
2020-02-24 15:20:53 -03:00
} break ;
case Variant : : PACKED_FLOAT64_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_FLOAT64_ARRAY ) ;
2020-02-24 15:20:53 -03:00
Vector < double > arr = p_property ;
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
const double * r = arr . ptr ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
f - > store_double ( r [ i ] ) ;
}
2014-02-09 22:10:30 -03:00
} break ;
2020-02-17 18:06:54 -03:00
case Variant : : PACKED_STRING_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_STRING_ARRAY ) ;
2020-02-17 18:06:54 -03:00
Vector < String > arr = p_property ;
2014-02-09 22:10:30 -03:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
2020-02-17 18:06:54 -03:00
const String * r = arr . ptr ( ) ;
2014-02-09 22:10:30 -03:00
for ( int i = 0 ; i < len ; i + + ) {
2017-12-15 08:38:24 -03:00
save_unicode_string ( f , r [ i ] ) ;
2014-02-09 22:10:30 -03:00
}
} break ;
2024-04-08 07:51:34 -07:00
case Variant : : PACKED_VECTOR2_ARRAY : {
f - > store_32 ( VARIANT_PACKED_VECTOR2_ARRAY ) ;
Vector < Vector2 > arr = p_property ;
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
const Vector2 * r = arr . ptr ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
f - > store_real ( r [ i ] . x ) ;
f - > store_real ( r [ i ] . y ) ;
}
} break ;
2020-02-17 18:06:54 -03:00
case Variant : : PACKED_VECTOR3_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_VECTOR3_ARRAY ) ;
2020-02-17 18:06:54 -03:00
Vector < Vector3 > arr = p_property ;
2014-02-09 22:10:30 -03:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
2020-02-17 18:06:54 -03:00
const Vector3 * r = arr . ptr ( ) ;
2014-02-09 22:10:30 -03:00
for ( int i = 0 ; i < len ; i + + ) {
f - > store_real ( r [ i ] . x ) ;
f - > store_real ( r [ i ] . y ) ;
f - > store_real ( r [ i ] . z ) ;
}
} break ;
2020-02-17 18:06:54 -03:00
case Variant : : PACKED_COLOR_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_COLOR_ARRAY ) ;
2020-02-17 18:06:54 -03:00
Vector < Color > arr = p_property ;
2014-02-09 22:10:30 -03:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
2020-02-17 18:06:54 -03:00
const Color * r = arr . ptr ( ) ;
2014-02-09 22:10:30 -03:00
for ( int i = 0 ; i < len ; i + + ) {
2022-06-08 14:32:41 +02:00
f - > store_float ( r [ i ] . r ) ;
f - > store_float ( r [ i ] . g ) ;
f - > store_float ( r [ i ] . b ) ;
f - > store_float ( r [ i ] . a ) ;
2014-02-09 22:10:30 -03:00
}
2024-04-08 07:51:34 -07:00
} break ;
case Variant : : PACKED_VECTOR4_ARRAY : {
f - > store_32 ( VARIANT_PACKED_VECTOR4_ARRAY ) ;
Vector < Vector4 > arr = p_property ;
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
const Vector4 * r = arr . ptr ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
f - > store_real ( r [ i ] . x ) ;
f - > store_real ( r [ i ] . y ) ;
f - > store_real ( r [ i ] . z ) ;
f - > store_real ( r [ i ] . w ) ;
}
2014-02-09 22:10:30 -03:00
} break ;
default : {
2019-08-14 20:57:49 -06:00
ERR_FAIL_MSG ( " Invalid variant. " ) ;
2014-02-09 22:10:30 -03:00
}
}
}
void ResourceFormatSaverBinaryInstance : : _find_resources ( const Variant & p_variant , bool p_main ) {
switch ( p_variant . get_type ( ) ) {
case Variant : : OBJECT : {
2022-05-03 01:43:50 +02:00
Ref < Resource > res = p_variant ;
2014-02-09 22:10:30 -03:00
2023-07-01 01:29:46 +02:00
if ( res . is_null ( ) | | external_resources . has ( res ) | | res - > get_meta ( SNAME ( " _skip_save_ " ) , false ) ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2021-07-10 21:17:41 +02:00
if ( ! p_main & & ( ! bundle_resources ) & & ! res - > is_built_in ( ) ) {
2019-02-24 10:45:08 -03:00
if ( res - > get_path ( ) = = path ) {
2019-11-06 17:03:04 +01:00
ERR_PRINT ( " Circular reference to resource being saved found: ' " + local_path + " ' will be null next time it's loaded. " ) ;
2019-02-24 10:45:08 -03:00
return ;
}
2015-08-23 20:15:56 -03:00
int idx = external_resources . size ( ) ;
external_resources [ res ] = idx ;
2014-02-09 22:10:30 -03:00
return ;
}
2020-05-14 16:41:43 +02:00
if ( resource_set . has ( res ) ) {
2014-02-09 22:10:30 -03:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
2023-02-17 05:18:58 -05:00
resource_set . insert ( res ) ;
2014-02-09 22:10:30 -03:00
List < PropertyInfo > property_list ;
res - > get_property_list ( & property_list ) ;
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & E : property_list ) {
2021-07-15 23:45:57 -04:00
if ( E . usage & PROPERTY_USAGE_STORAGE ) {
Variant value = res - > get ( E . name ) ;
if ( E . usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT ) {
2022-12-17 22:20:27 +01:00
NonPersistentKey npk ;
npk . base = res ;
npk . property = E . name ;
non_persistent_map [ npk ] = value ;
2022-05-03 01:43:50 +02:00
Ref < Resource > sres = value ;
2019-02-21 20:49:42 -03:00
if ( sres . is_valid ( ) ) {
resource_set . insert ( sres ) ;
saved_resources . push_back ( sres ) ;
2022-12-17 22:20:27 +01:00
} else {
_find_resources ( value ) ;
2019-02-21 20:49:42 -03:00
}
} else {
_find_resources ( value ) ;
}
2014-02-09 22:10:30 -03:00
}
}
saved_resources . push_back ( res ) ;
} break ;
case Variant : : ARRAY : {
Array varray = p_variant ;
2023-11-17 19:27:42 +02:00
_find_resources ( varray . get_typed_script ( ) ) ;
2023-12-24 13:44:21 +01:00
for ( const Variant & v : varray ) {
2014-02-09 22:10:30 -03:00
_find_resources ( v ) ;
}
} break ;
case Variant : : DICTIONARY : {
Dictionary d = p_variant ;
2023-06-24 13:03:28 -05:00
_find_resources ( d . get_typed_key_script ( ) ) ;
_find_resources ( d . get_typed_value_script ( ) ) ;
2014-02-09 22:10:30 -03:00
List < Variant > keys ;
d . get_key_list ( & keys ) ;
2021-07-24 15:46:25 +02:00
for ( const Variant & E : keys ) {
2021-07-15 23:45:57 -04:00
_find_resources ( E ) ;
Variant v = d [ E ] ;
2014-02-09 22:10:30 -03:00
_find_resources ( v ) ;
}
} break ;
case Variant : : NODE_PATH : {
//take the chance and save node path strings
NodePath np = p_variant ;
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < np . get_name_count ( ) ; i + + ) {
2014-02-09 22:10:30 -03:00
get_string_index ( np . get_name ( i ) ) ;
2020-05-14 16:41:43 +02:00
}
for ( int i = 0 ; i < np . get_subname_count ( ) ; i + + ) {
2014-02-09 22:10:30 -03:00
get_string_index ( np . get_subname ( i ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2014-02-09 22:10:30 -03:00
}
}
2022-03-23 11:08:58 +02:00
void ResourceFormatSaverBinaryInstance : : save_unicode_string ( Ref < FileAccess > p_f , const String & p_string , bool p_bit_on_len ) {
2014-02-09 22:10:30 -03:00
CharString utf8 = p_string . utf8 ( ) ;
2017-12-15 08:38:24 -03:00
if ( p_bit_on_len ) {
2022-03-23 11:08:58 +02:00
p_f - > store_32 ( ( utf8 . length ( ) + 1 ) | 0x80000000 ) ;
2017-12-15 08:38:24 -03:00
} else {
2022-03-23 11:08:58 +02:00
p_f - > store_32 ( utf8 . length ( ) + 1 ) ;
2017-12-15 08:38:24 -03:00
}
2022-03-23 11:08:58 +02:00
p_f - > store_buffer ( ( const uint8_t * ) utf8 . get_data ( ) , utf8 . length ( ) + 1 ) ;
2014-02-09 22:10:30 -03:00
}
int ResourceFormatSaverBinaryInstance : : get_string_index ( const String & p_string ) {
StringName s = p_string ;
2020-05-14 16:41:43 +02:00
if ( string_map . has ( s ) ) {
2014-02-09 22:10:30 -03:00
return string_map [ s ] ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
string_map [ s ] = strings . size ( ) ;
strings . push_back ( s ) ;
return strings . size ( ) - 1 ;
}
2022-04-28 22:49:10 +02:00
static String _resource_get_class ( Ref < Resource > p_resource ) {
Ref < MissingResource > missing_resource = p_resource ;
if ( missing_resource . is_valid ( ) ) {
return missing_resource - > get_original_class ( ) ;
} else {
return p_resource - > get_class ( ) ;
}
}
2022-05-03 01:43:50 +02:00
Error ResourceFormatSaverBinaryInstance : : save ( const String & p_path , const Ref < Resource > & p_resource , uint32_t p_flags ) {
2024-09-23 15:07:00 +02:00
Resource : : seed_scene_unique_id ( p_path . hash ( ) ) ;
2014-02-09 22:10:30 -03:00
Error err ;
2022-03-23 11:08:58 +02:00
Ref < FileAccess > f ;
2014-02-09 22:10:30 -03:00
if ( p_flags & ResourceSaver : : FLAG_COMPRESS ) {
2022-03-23 11:08:58 +02:00
Ref < FileAccessCompressed > fac ;
fac . instantiate ( ) ;
2014-02-09 22:10:30 -03:00
fac - > configure ( " RSCC " ) ;
f = fac ;
2022-09-05 13:01:31 +02:00
err = fac - > open_internal ( p_path , FileAccess : : WRITE ) ;
2014-02-09 22:10:30 -03:00
} else {
f = FileAccess : : open ( p_path , FileAccess : : WRITE , & err ) ;
}
2019-09-25 10:28:50 +02:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Cannot create file ' " + p_path + " '. " ) ;
2014-02-09 22:10:30 -03:00
relative_paths = p_flags & ResourceSaver : : FLAG_RELATIVE_PATHS ;
skip_editor = p_flags & ResourceSaver : : FLAG_OMIT_EDITOR_PROPERTIES ;
bundle_resources = p_flags & ResourceSaver : : FLAG_BUNDLE_RESOURCES ;
big_endian = p_flags & ResourceSaver : : FLAG_SAVE_BIG_ENDIAN ;
2014-06-27 23:21:45 -03:00
takeover_paths = p_flags & ResourceSaver : : FLAG_REPLACE_SUBRESOURCE_PATHS ;
2014-03-13 22:57:24 -03:00
2020-05-14 16:41:43 +02:00
if ( ! p_path . begins_with ( " res:// " ) ) {
2014-06-27 23:21:45 -03:00
takeover_paths = false ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
local_path = p_path . get_base_dir ( ) ;
2019-02-24 10:45:08 -03:00
path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
2014-02-09 22:10:30 -03:00
_find_resources ( p_resource , true ) ;
if ( ! ( p_flags & ResourceSaver : : FLAG_COMPRESS ) ) {
//save header compressed
static const uint8_t header [ 4 ] = { ' R ' , ' S ' , ' R ' , ' C ' } ;
f - > store_buffer ( header , 4 ) ;
}
if ( big_endian ) {
f - > store_32 ( 1 ) ;
2021-05-20 14:58:03 +02:00
f - > set_big_endian ( true ) ;
2020-05-14 16:41:43 +02:00
} else {
2014-02-09 22:10:30 -03:00
f - > store_32 ( 0 ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
f - > store_32 ( 0 ) ; //64 bits file, false for now
f - > store_32 ( VERSION_MAJOR ) ;
f - > store_32 ( VERSION_MINOR ) ;
f - > store_32 ( FORMAT_VERSION ) ;
2015-03-02 00:54:10 -03:00
if ( f - > get_error ( ) ! = OK & & f - > get_error ( ) ! = ERR_FILE_EOF ) {
return ERR_CANT_CREATE ;
}
2022-04-28 22:49:10 +02:00
save_unicode_string ( f , _resource_get_class ( p_resource ) ) ;
2017-09-02 22:32:31 +02:00
f - > store_64 ( 0 ) ; //offset to import metadata
2023-01-19 19:12:25 +01:00
String script_class ;
2022-02-16 00:55:13 +00:00
{
uint32_t format_flags = FORMAT_FLAG_NAMED_SCENE_IDS | FORMAT_FLAG_UIDS ;
# ifdef REAL_T_IS_DOUBLE
format_flags | = FORMAT_FLAG_REAL_T_IS_DOUBLE ;
# endif
2023-01-19 19:12:25 +01:00
if ( ! p_resource - > is_class ( " PackedScene " ) ) {
Ref < Script > s = p_resource - > get_script ( ) ;
if ( s . is_valid ( ) ) {
script_class = s - > get_global_name ( ) ;
if ( ! script_class . is_empty ( ) ) {
format_flags | = ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_HAS_SCRIPT_CLASS ;
}
}
}
2022-02-16 00:55:13 +00:00
f - > store_32 ( format_flags ) ;
}
2021-07-23 16:01:18 -03:00
ResourceUID : : ID uid = ResourceSaver : : get_resource_id_for_path ( p_path , true ) ;
f - > store_64 ( uid ) ;
2023-01-19 19:12:25 +01:00
if ( ! script_class . is_empty ( ) ) {
save_unicode_string ( f , script_class ) ;
}
2021-07-29 22:24:29 -07:00
for ( int i = 0 ; i < ResourceFormatSaverBinaryInstance : : RESERVED_FIELDS ; i + + ) {
2014-02-09 22:10:30 -03:00
f - > store_32 ( 0 ) ; // reserved
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
List < ResourceData > resources ;
2022-04-28 22:49:10 +02:00
Dictionary missing_resource_properties = p_resource - > get_meta ( META_MISSING_RESOURCES , Dictionary ( ) ) ;
2014-02-09 22:10:30 -03:00
{
2022-05-03 01:43:50 +02:00
for ( const Ref < Resource > & E : saved_resources ) {
2014-02-09 22:10:30 -03:00
ResourceData & rd = resources . push_back ( ResourceData ( ) ) - > get ( ) ;
2022-04-28 22:49:10 +02:00
rd . type = _resource_get_class ( E ) ;
2014-02-09 22:10:30 -03:00
List < PropertyInfo > property_list ;
2021-07-15 23:45:57 -04:00
E - > get_property_list ( & property_list ) ;
2014-02-09 22:10:30 -03:00
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & F : property_list ) {
2021-07-15 23:45:57 -04:00
if ( skip_editor & & F . name . begins_with ( " __editor " ) ) {
2014-02-09 22:10:30 -03:00
continue ;
2020-05-14 16:41:43 +02:00
}
2022-04-28 22:49:10 +02:00
if ( F . name = = META_PROPERTY_MISSING_RESOURCES ) {
continue ;
}
2021-07-15 23:45:57 -04:00
if ( ( F . usage & PROPERTY_USAGE_STORAGE ) ) {
2014-02-09 22:10:30 -03:00
Property p ;
2021-07-15 23:45:57 -04:00
p . name_idx = get_string_index ( F . name ) ;
2019-02-21 20:49:42 -03:00
2021-07-15 23:45:57 -04:00
if ( F . usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT ) {
2019-02-21 20:49:42 -03:00
NonPersistentKey npk ;
2021-07-15 23:45:57 -04:00
npk . base = E ;
npk . property = F . name ;
2019-02-21 20:49:42 -03:00
if ( non_persistent_map . has ( npk ) ) {
p . value = non_persistent_map [ npk ] ;
}
} else {
2021-07-15 23:45:57 -04:00
p . value = E - > get ( F . name ) ;
2019-02-21 20:49:42 -03:00
}
2018-11-08 11:30:02 -03:00
2022-04-28 22:49:10 +02:00
if ( p . pi . type = = Variant : : OBJECT & & missing_resource_properties . has ( F . name ) ) {
2022-05-23 21:32:19 +02:00
// Was this missing resource overridden? If so do not save the old value.
2022-04-28 22:49:10 +02:00
Ref < Resource > res = p . value ;
if ( res . is_null ( ) ) {
p . value = missing_resource_properties [ F . name ] ;
}
}
2021-07-15 23:45:57 -04:00
Variant default_value = ClassDB : : class_get_default_property_value ( E - > get_class ( ) , F . name ) ;
2018-11-08 11:30:02 -03:00
if ( default_value . get_type ( ) ! = Variant : : NIL & & bool ( Variant : : evaluate ( Variant : : OP_EQUAL , p . value , default_value ) ) ) {
2014-02-09 22:10:30 -03:00
continue ;
2018-11-08 11:30:02 -03:00
}
2021-07-15 23:45:57 -04:00
p . pi = F ;
2014-02-09 22:10:30 -03:00
rd . properties . push_back ( p ) ;
}
}
}
}
f - > store_32 ( strings . size ( ) ) ; //string table size
for ( int i = 0 ; i < strings . size ( ) ; i + + ) {
2017-12-15 08:38:24 -03:00
save_unicode_string ( f , strings [ i ] ) ;
2014-02-09 22:10:30 -03:00
}
// save external resource table
f - > store_32 ( external_resources . size ( ) ) ; //amount of external resources
2022-05-03 01:43:50 +02:00
Vector < Ref < Resource > > save_order ;
2015-08-23 20:15:56 -03:00
save_order . resize ( external_resources . size ( ) ) ;
2014-02-09 22:10:30 -03:00
2022-05-03 01:43:50 +02:00
for ( const KeyValue < Ref < Resource > , int > & E : external_resources ) {
2021-08-09 14:13:42 -06:00
save_order . write [ E . value ] = E . key ;
2015-08-23 20:15:56 -03:00
}
for ( int i = 0 ; i < save_order . size ( ) ; i + + ) {
2017-12-15 08:38:24 -03:00
save_unicode_string ( f , save_order [ i ] - > get_save_class ( ) ) ;
2022-09-29 12:53:28 +03:00
String res_path = save_order [ i ] - > get_path ( ) ;
res_path = relative_paths ? local_path . path_to_file ( res_path ) : res_path ;
save_unicode_string ( f , res_path ) ;
2021-07-23 16:01:18 -03:00
ResourceUID : : ID ruid = ResourceSaver : : get_resource_id_for_path ( save_order [ i ] - > get_path ( ) , false ) ;
f - > store_64 ( ruid ) ;
2014-02-09 22:10:30 -03:00
}
// save internal resource table
f - > store_32 ( saved_resources . size ( ) ) ; //amount of internal resources
Vector < uint64_t > ofs_pos ;
2022-05-19 17:00:06 +02:00
HashSet < String > used_unique_ids ;
2015-06-22 00:03:19 -03:00
2022-05-03 01:43:50 +02:00
for ( Ref < Resource > & r : saved_resources ) {
2021-07-10 21:17:41 +02:00
if ( r - > is_built_in ( ) ) {
2021-12-09 03:42:46 -06:00
if ( ! r - > get_scene_unique_id ( ) . is_empty ( ) ) {
2021-07-20 21:36:56 -03:00
if ( used_unique_ids . has ( r - > get_scene_unique_id ( ) ) ) {
r - > set_scene_unique_id ( " " ) ;
2015-06-22 00:03:19 -03:00
} else {
2021-07-20 21:36:56 -03:00
used_unique_ids . insert ( r - > get_scene_unique_id ( ) ) ;
2015-06-22 00:03:19 -03:00
}
}
}
}
2022-05-13 15:04:37 +02:00
HashMap < Ref < Resource > , int > resource_map ;
2021-07-20 21:36:56 -03:00
int res_index = 0 ;
2022-05-03 01:43:50 +02:00
for ( Ref < Resource > & r : saved_resources ) {
2021-07-10 21:17:41 +02:00
if ( r - > is_built_in ( ) ) {
2021-12-09 03:42:46 -06:00
if ( r - > get_scene_unique_id ( ) . is_empty ( ) ) {
2021-07-20 21:36:56 -03:00
String new_id ;
while ( true ) {
2022-04-28 22:49:10 +02:00
new_id = _resource_get_class ( r ) + " _ " + Resource : : generate_scene_unique_id ( ) ;
2021-07-20 21:36:56 -03:00
if ( ! used_unique_ids . has ( new_id ) ) {
break ;
}
2015-06-22 00:03:19 -03:00
}
2021-07-20 21:36:56 -03:00
r - > set_scene_unique_id ( new_id ) ;
used_unique_ids . insert ( new_id ) ;
2015-06-22 00:03:19 -03:00
}
2021-07-20 21:36:56 -03:00
save_unicode_string ( f , " local:// " + r - > get_scene_unique_id ( ) ) ;
2014-06-27 23:21:45 -03:00
if ( takeover_paths ) {
2021-07-20 21:36:56 -03:00
r - > set_path ( p_path + " :: " + r - > get_scene_unique_id ( ) , true ) ;
2014-06-27 23:21:45 -03:00
}
2016-08-31 17:58:51 -03:00
# ifdef TOOLS_ENABLED
r - > set_edited ( false ) ;
# endif
2015-10-21 23:57:43 -03:00
} else {
2017-12-15 08:38:24 -03:00
save_unicode_string ( f , r - > get_path ( ) ) ; //actual external
2015-10-21 23:57:43 -03:00
}
2017-09-10 15:37:49 +02:00
ofs_pos . push_back ( f - > get_position ( ) ) ;
2014-02-09 22:10:30 -03:00
f - > store_64 ( 0 ) ; //offset in 64 bits
2021-07-20 21:36:56 -03:00
resource_map [ r ] = res_index + + ;
2014-02-09 22:10:30 -03:00
}
Vector < uint64_t > ofs_table ;
2017-08-26 17:46:49 +02:00
//now actually save the resources
2021-07-24 15:46:25 +02:00
for ( const ResourceData & rd : resources ) {
2017-09-10 15:37:49 +02:00
ofs_table . push_back ( f - > get_position ( ) ) ;
2017-12-15 08:38:24 -03:00
save_unicode_string ( f , rd . type ) ;
2014-02-09 22:10:30 -03:00
f - > store_32 ( rd . properties . size ( ) ) ;
2021-07-24 15:46:25 +02:00
for ( const Property & p : rd . properties ) {
2014-02-09 22:10:30 -03:00
f - > store_32 ( p . name_idx ) ;
2021-07-24 15:46:25 +02:00
write_variant ( f , p . value , resource_map , external_resources , string_map , p . pi ) ;
2014-02-09 22:10:30 -03:00
}
}
for ( int i = 0 ; i < ofs_table . size ( ) ; i + + ) {
f - > seek ( ofs_pos [ i ] ) ;
f - > store_64 ( ofs_table [ i ] ) ;
}
f - > seek_end ( ) ;
f - > store_buffer ( ( const uint8_t * ) " RSRC " , 4 ) ; //magic at end
2015-03-02 00:54:10 -03:00
if ( f - > get_error ( ) ! = OK & & f - > get_error ( ) ! = ERR_FILE_EOF ) {
return ERR_CANT_CREATE ;
}
2014-02-09 22:10:30 -03:00
return OK ;
}
2022-12-05 19:01:59 +01:00
Error ResourceFormatSaverBinaryInstance : : set_uid ( const String & p_path , ResourceUID : : ID p_uid ) {
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
ERR_FAIL_COND_V_MSG ( f . is_null ( ) , ERR_CANT_OPEN , " Cannot open file ' " + p_path + " '. " ) ;
Ref < FileAccess > fw ;
local_path = p_path . get_base_dir ( ) ;
uint8_t header [ 4 ] ;
f - > get_buffer ( header , 4 ) ;
if ( header [ 0 ] = = ' R ' & & header [ 1 ] = = ' S ' & & header [ 2 ] = = ' C ' & & header [ 3 ] = = ' C ' ) {
// Compressed.
Ref < FileAccessCompressed > fac ;
fac . instantiate ( ) ;
Error err = fac - > open_after_magic ( f ) ;
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Cannot open file ' " + p_path + " '. " ) ;
f = fac ;
Ref < FileAccessCompressed > facw ;
facw . instantiate ( ) ;
facw - > configure ( " RSCC " ) ;
err = facw - > open_internal ( p_path + " .uidren " , FileAccess : : WRITE ) ;
ERR_FAIL_COND_V_MSG ( err , ERR_FILE_CORRUPT , " Cannot create file ' " + p_path + " .uidren'. " ) ;
fw = facw ;
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
// Not a binary resource.
return ERR_FILE_UNRECOGNIZED ;
} else {
fw = FileAccess : : open ( p_path + " .uidren " , FileAccess : : WRITE ) ;
ERR_FAIL_COND_V_MSG ( fw . is_null ( ) , ERR_CANT_CREATE , " Cannot create file ' " + p_path + " .uidren'. " ) ;
uint8_t magich [ 4 ] = { ' R ' , ' S ' , ' R ' , ' C ' } ;
fw - > store_buffer ( magich , 4 ) ;
}
big_endian = f - > get_32 ( ) ;
bool use_real64 = f - > get_32 ( ) ;
f - > set_big_endian ( big_endian ! = 0 ) ; //read big endian if saved as big endian
# ifdef BIG_ENDIAN_ENABLED
fw - > store_32 ( ! big_endian ) ;
# else
fw - > store_32 ( big_endian ) ;
# endif
fw - > set_big_endian ( big_endian ! = 0 ) ;
fw - > store_32 ( use_real64 ) ; //use real64
uint32_t ver_major = f - > get_32 ( ) ;
uint32_t ver_minor = f - > get_32 ( ) ;
uint32_t ver_format = f - > get_32 ( ) ;
if ( ver_format < FORMAT_VERSION_CAN_RENAME_DEPS ) {
fw . unref ( ) ;
{
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
da - > remove ( p_path + " .uidren " ) ;
}
// Use the old approach.
WARN_PRINT ( " This file is old, so it does not support UIDs, opening and resaving ' " + p_path + " '. " ) ;
return ERR_UNAVAILABLE ;
}
if ( ver_format > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
ERR_FAIL_V_MSG ( ERR_FILE_UNRECOGNIZED ,
vformat ( " File '%s' can't be loaded, as it uses a format version (%d) or engine version (%d.%d) which are not supported by your engine version (%s). " ,
local_path , ver_format , ver_major , ver_minor , VERSION_BRANCH ) ) ;
}
// Since we're not actually converting the file contents, leave the version
// numbers in the file untouched.
fw - > store_32 ( ver_major ) ;
fw - > store_32 ( ver_minor ) ;
fw - > store_32 ( ver_format ) ;
save_ustring ( fw , get_ustring ( f ) ) ; //type
fw - > store_64 ( f - > get_64 ( ) ) ; //metadata offset
uint32_t flags = f - > get_32 ( ) ;
flags | = ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_UIDS ;
f - > get_64 ( ) ; // Skip previous UID
fw - > store_32 ( flags ) ;
fw - > store_64 ( p_uid ) ;
2023-01-19 19:12:25 +01:00
if ( flags & ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_HAS_SCRIPT_CLASS ) {
save_ustring ( fw , get_ustring ( f ) ) ;
}
2022-12-05 19:01:59 +01:00
//rest of file
uint8_t b = f - > get_8 ( ) ;
while ( ! f - > eof_reached ( ) ) {
fw - > store_8 ( b ) ;
b = f - > get_8 ( ) ;
}
f . unref ( ) ;
bool all_ok = fw - > get_error ( ) = = OK ;
if ( ! all_ok ) {
return ERR_CANT_CREATE ;
}
fw . unref ( ) ;
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
da - > remove ( p_path ) ;
da - > rename ( p_path + " .uidren " , p_path ) ;
return OK ;
}
2022-06-03 01:33:42 +02:00
Error ResourceFormatSaverBinary : : save ( const Ref < Resource > & p_resource , const String & p_path , uint32_t p_flags ) {
2017-07-19 17:00:46 -03:00
String local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
2014-02-09 22:10:30 -03:00
ResourceFormatSaverBinaryInstance saver ;
return saver . save ( local_path , p_resource , p_flags ) ;
}
2022-12-05 19:01:59 +01:00
Error ResourceFormatSaverBinary : : set_uid ( const String & p_path , ResourceUID : : ID p_uid ) {
String local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
ResourceFormatSaverBinaryInstance saver ;
return saver . set_uid ( local_path , p_uid ) ;
}
2022-05-03 01:43:50 +02:00
bool ResourceFormatSaverBinary : : recognize ( const Ref < Resource > & p_resource ) const {
2014-02-09 22:10:30 -03:00
return true ; //all recognized
}
2022-05-03 01:43:50 +02:00
void ResourceFormatSaverBinary : : get_recognized_extensions ( const Ref < Resource > & p_resource , List < String > * p_extensions ) const {
2014-02-09 22:10:30 -03:00
String base = p_resource - > get_base_extension ( ) . to_lower ( ) ;
2016-06-28 18:58:40 +02:00
p_extensions - > push_back ( base ) ;
2020-05-14 16:41:43 +02:00
if ( base ! = " res " ) {
2017-02-15 08:29:46 -03:00
p_extensions - > push_back ( " res " ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-09 22:10:30 -03:00
}
2020-04-02 01:20:12 +02:00
ResourceFormatSaverBinary * ResourceFormatSaverBinary : : singleton = nullptr ;
2015-08-23 20:15:56 -03:00
ResourceFormatSaverBinary : : ResourceFormatSaverBinary ( ) {
singleton = this ;
}