2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
# include "resource_format_binary.h"
2017-08-26 17:46:49 +02:00
2020-11-07 23:33:38 +01: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 23:33:38 +01: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-10 02:10:30 +01: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-10 02:10:30 +01: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 ,
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
VARIANT_FLOAT = 4 ,
2014-02-10 02:10:30 +01:00
VARIANT_STRING = 5 ,
VARIANT_VECTOR2 = 10 ,
VARIANT_RECT2 = 11 ,
VARIANT_VECTOR3 = 12 ,
VARIANT_PLANE = 13 ,
2021-01-20 08:02:02 +01:00
VARIANT_QUATERNION = 14 ,
2017-11-17 03:09:00 +01:00
VARIANT_AABB = 15 ,
2021-12-28 02:28:25 +01:00
VARIANT_BASIS = 16 ,
2021-12-24 18:44:08 +01:00
VARIANT_TRANSFORM3D = 17 ,
2021-12-28 02:28:25 +01:00
VARIANT_TRANSFORM2D = 18 ,
2014-02-10 02:10:30 +01: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-09 00:58:39 +01:00
VARIANT_INT64 = 40 ,
VARIANT_DOUBLE = 41 ,
2020-02-19 20:27:19 +01:00
VARIANT_CALLABLE = 42 ,
VARIANT_SIGNAL = 43 ,
2020-02-20 22:58:05 +01:00
VARIANT_STRING_NAME = 44 ,
2020-02-22 04:26:41 +01: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 ,
Implement Vector4, Vector4i, Projection
Implement built-in classes Vector4, Vector4i and Projection.
* Two versions of Vector4 (float and integer).
* A Projection class, which is a 4x4 matrix specialized in projection types.
These types have been requested for a long time, but given they were very corner case they were not added before.
Because in Godot 4, reimplementing parts of the rendering engine is now possible, access to these types (heavily used by the rendering code) becomes a necessity.
**Q**: Why Projection and not Matrix4?
**A**: Godot does not use Matrix2, Matrix3, Matrix4x3, etc. naming convention because, within the engine, these types always have a *purpose*. As such, Godot names them: Transform2D, Transform3D or Basis. In this case, this 4x4 matrix is _always_ used as a _Projection_, hence the naming.
2022-07-20 01:11:13 +02:00
VARIANT_VECTOR4 = 50 ,
VARIANT_VECTOR4I = 51 ,
VARIANT_PROJECTION = 52 ,
2024-04-08 16:51:34 +02:00
VARIANT_PACKED_VECTOR4_ARRAY = 53 ,
2014-02-10 02:10:30 +01:00
OBJECT_EMPTY = 0 ,
OBJECT_EXTERNAL_RESOURCE = 1 ,
OBJECT_INTERNAL_RESOURCE = 2 ,
2015-08-24 01:15:56 +02:00
OBJECT_EXTERNAL_RESOURCE_INDEX = 3 ,
2024-04-08 16:51:34 +02: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 16:51:34 +02:00
// Version 6: Added PackedVector4Array Variant type.
FORMAT_VERSION = 6 ,
2017-11-22 12:34:43 +01:00
FORMAT_VERSION_CAN_RENAME_DEPS = 1 ,
FORMAT_VERSION_NO_NODEPATH_PROPERTY = 3 ,
2014-02-10 02:10:30 +01:00
} ;
2020-02-28 12:27:04 +01:00
void ResourceLoaderBinary : : _advance_padding ( uint32_t p_len ) {
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
f - > get_8 ( ) ; //pad to 32
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
}
2022-03-23 10:08:58 +01:00
static Error read_reals ( real_t * dst , Ref < FileAccess > & f , size_t count ) {
if ( f - > real_is_double ) {
2022-09-29 08:18:07 +02:00
if constexpr ( sizeof ( real_t ) = = 8 ) {
2022-03-19 17:56:45 +01:00
// Ideal case with double-precision
2022-03-23 10:08:58 +01:00
f - > get_buffer ( ( uint8_t * ) dst , count * sizeof ( double ) ) ;
2022-03-19 17:56:45 +01: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 08:18:07 +02:00
} else if constexpr ( sizeof ( real_t ) = = 4 ) {
2022-03-19 17:56:45 +01: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 10:08:58 +01:00
dst [ i ] = f - > get_double ( ) ;
2022-03-19 17:56:45 +01:00
}
} else {
ERR_FAIL_V_MSG ( ERR_UNAVAILABLE , " real_t size is neither 4 nor 8! " ) ;
}
} else {
2022-09-29 08:18:07 +02:00
if constexpr ( sizeof ( real_t ) = = 4 ) {
2022-03-19 17:56:45 +01:00
// Ideal case with float-precision
2022-03-23 10:08:58 +01:00
f - > get_buffer ( ( uint8_t * ) dst , count * sizeof ( float ) ) ;
2022-03-19 17:56:45 +01: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 08:18:07 +02:00
} else if constexpr ( sizeof ( real_t ) = = 8 ) {
2022-03-19 17:56:45 +01:00
for ( size_t i = 0 ; i < count ; + + i ) {
2022-03-23 10:08:58 +01:00
dst [ i ] = f - > get_float ( ) ;
2022-03-19 17:56:45 +01:00
}
} else {
ERR_FAIL_V_MSG ( ERR_UNAVAILABLE , " real_t size is neither 4 nor 8! " ) ;
}
}
return OK ;
}
2020-02-28 12:27:04 +01:00
StringName ResourceLoaderBinary : : _get_string ( ) {
2017-02-15 12:29:46 +01:00
uint32_t id = f - > get_32 ( ) ;
if ( id & 0x80000000 ) {
2017-12-15 13:04:57 +01:00
uint32_t len = id & 0x7FFFFFFF ;
2019-02-21 20:57:39 +01:00
if ( ( int ) len > str_buf . size ( ) ) {
2017-02-15 12:29:46 +01:00
str_buf . resize ( len ) ;
}
2020-05-14 16:41:43 +02:00
if ( len = = 0 ) {
2017-02-15 12:29:46 +01:00
return StringName ( ) ;
2020-05-14 16:41:43 +02:00
}
2017-02-15 12:29:46 +01: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 12:27:04 +01:00
Error ResourceLoaderBinary : : parse_variant ( Variant & r_v ) {
2022-09-29 11:53:28 +02:00
uint32_t prop_type = f - > get_32 ( ) ;
print_bl ( " find property of type: " + itos ( prop_type ) ) ;
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
switch ( prop_type ) {
2014-02-10 02:10:30 +01: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-09 00:58:39 +01:00
case VARIANT_INT64 : {
r_v = int64_t ( f - > get_64 ( ) ) ;
} break ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
case VARIANT_FLOAT : {
2014-02-10 02:10:30 +01:00
r_v = f - > get_real ( ) ;
} break ;
2017-01-09 00:58:39 +01:00
case VARIANT_DOUBLE : {
r_v = f - > get_double ( ) ;
} break ;
2014-02-10 02:10:30 +01: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 04:26:41 +01:00
} break ;
case VARIANT_VECTOR2I : {
Vector2i v ;
v . x = f - > get_32 ( ) ;
v . y = f - > get_32 ( ) ;
r_v = v ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
v . size . x = f - > get_real ( ) ;
v . size . y = f - > get_real ( ) ;
r_v = v ;
2020-02-22 04:26:41 +01: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-10 02:10:30 +01: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 04:26:41 +01: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 ;
Implement Vector4, Vector4i, Projection
Implement built-in classes Vector4, Vector4i and Projection.
* Two versions of Vector4 (float and integer).
* A Projection class, which is a 4x4 matrix specialized in projection types.
These types have been requested for a long time, but given they were very corner case they were not added before.
Because in Godot 4, reimplementing parts of the rendering engine is now possible, access to these types (heavily used by the rendering code) becomes a necessity.
**Q**: Why Projection and not Matrix4?
**A**: Godot does not use Matrix2, Matrix3, Matrix4x3, etc. naming convention because, within the engine, these types always have a *purpose*. As such, Godot names them: Transform2D, Transform3D or Basis. In this case, this 4x4 matrix is _always_ used as a _Projection_, hence the naming.
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-10 02:10:30 +01: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-10 02:10:30 +01:00
r_v = v ;
} break ;
2021-01-20 08:02:02 +01:00
case VARIANT_QUATERNION : {
Quaternion v ;
2014-02-10 02:10:30 +01: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-17 03:09:00 +01: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-10 02:10:30 +01: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-28 02:28:25 +01:00
case VARIANT_TRANSFORM2D : {
2017-01-11 04:52:51 +01:00
Transform2D v ;
2022-04-24 23:59:24 +02: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-10 02:10:30 +01:00
r_v = v ;
} break ;
2021-12-28 02:28:25 +01:00
case VARIANT_BASIS : {
2017-01-11 04:52:51 +01:00
Basis v ;
2022-04-25 00:07:35 +02: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-10 02:10:30 +01:00
r_v = v ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_TRANSFORM3D : {
2020-10-17 07:08:21 +02:00
Transform3D v ;
2022-04-25 00:07:35 +02: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-10 02:10:30 +01:00
v . origin . x = f - > get_real ( ) ;
v . origin . y = f - > get_real ( ) ;
v . origin . z = f - > get_real ( ) ;
r_v = v ;
} break ;
Implement Vector4, Vector4i, Projection
Implement built-in classes Vector4, Vector4i and Projection.
* Two versions of Vector4 (float and integer).
* A Projection class, which is a 4x4 matrix specialized in projection types.
These types have been requested for a long time, but given they were very corner case they were not added before.
Because in Godot 4, reimplementing parts of the rendering engine is now possible, access to these types (heavily used by the rendering code) becomes a necessity.
**Q**: Why Projection and not Matrix4?
**A**: Godot does not use Matrix2, Matrix3, Matrix4x3, etc. naming convention because, within the engine, these types always have a *purpose*. As such, Godot names them: Transform2D, Transform3D or Basis. In this case, this 4x4 matrix is _always_ used as a _Projection_, hence the naming.
2022-07-20 01:11:13 +02:00
case VARIANT_PROJECTION : {
Projection v ;
2022-10-04 18:44:48 +02: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 ( ) ;
Implement Vector4, Vector4i, Projection
Implement built-in classes Vector4, Vector4i and Projection.
* Two versions of Vector4 (float and integer).
* A Projection class, which is a 4x4 matrix specialized in projection types.
These types have been requested for a long time, but given they were very corner case they were not added before.
Because in Godot 4, reimplementing parts of the rendering engine is now possible, access to these types (heavily used by the rendering code) becomes a necessity.
**Q**: Why Projection and not Matrix4?
**A**: Godot does not use Matrix2, Matrix3, Matrix4x3, etc. naming convention because, within the engine, these types always have a *purpose*. As such, Godot names them: Transform2D, Transform3D or Basis. In this case, this 4x4 matrix is _always_ used as a _Projection_, hence the naming.
2022-07-20 01:11:13 +02:00
r_v = v ;
} break ;
2014-02-10 02:10:30 +01:00
case VARIANT_COLOR : {
2021-01-25 20:46:35 +01: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-10 02:10:30 +01:00
r_v = v ;
} break ;
2020-02-20 22:58:05 +01:00
case VARIANT_STRING_NAME : {
r_v = StringName ( get_unicode_string ( ) ) ;
} break ;
2014-02-10 02:10:30 +01: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 12:34:43 +01: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-10 02:10:30 +01:00
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < name_count ; i + + ) {
2017-02-15 12:29:46 +01: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 12:29:46 +01:00
subnames . push_back ( _get_string ( ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2017-05-30 22:20:15 +02:00
NodePath np = NodePath ( names , subnames , absolute ) ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
2019-02-12 21:10:08 +01:00
switch ( objtype ) {
2014-02-10 02:10:30 +01:00
case OBJECT_EMPTY : {
//do none
} break ;
case OBJECT_INTERNAL_RESOURCE : {
uint32_t index = f - > get_32 ( ) ;
2021-07-21 02:36:56 +02: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 14:34:23 +02:00
2021-02-11 18:18:45 +01: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-20 04:19:21 +02:00
} else {
2021-02-11 18:18:45 +01:00
r_v = internal_index_cache [ path ] ;
2014-02-10 02:10:30 +01:00
}
} break ;
case OBJECT_EXTERNAL_RESOURCE : {
2015-08-24 01:15:56 +02:00
//old file format, still around for compatibility
2014-02-10 02:10:30 +01:00
2019-02-12 21:10:08 +01:00
String exttype = get_unicode_string ( ) ;
2014-02-10 02:10:30 +01:00
String path = get_unicode_string ( ) ;
2022-02-03 17:03:38 +01:00
if ( ! path . contains ( " :// " ) & & path . is_relative_path ( ) ) {
2014-02-10 02:10:30 +01:00
// path is relative to file being loaded, so convert to a resource path
2022-08-30 02:34:01 +02:00
path = ProjectSettings : : get_singleton ( ) - > localize_path ( res_path . get_base_dir ( ) . path_join ( path ) ) ;
2014-02-10 02:10:30 +01:00
}
2015-08-24 01:15:56 +02: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-10 02:10:30 +01:00
if ( res . is_null ( ) ) {
WARN_PRINT ( String ( " Couldn't load resource: " + path ) . utf8 ( ) . get_data ( ) ) ;
}
r_v = res ;
2015-08-24 01:15:56 +02: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-24 01:15:56 +02: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-24 01:15:56 +02: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 12:27:04 +01: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 12:27:04 +01:00
}
2015-08-24 01:15:56 +02:00
}
}
2014-02-10 02:10:30 +01:00
} break ;
default : {
ERR_FAIL_V ( ERR_FILE_CORRUPT ) ;
} break ;
}
} break ;
2020-02-19 20:27:19 +01:00
case VARIANT_CALLABLE : {
r_v = Callable ( ) ;
} break ;
case VARIANT_SIGNAL : {
r_v = Signal ( ) ;
} break ;
2014-02-10 02:10:30 +01:00
case VARIANT_DICTIONARY : {
2016-08-08 00:22:33 +02:00
uint32_t len = f - > get_32 ( ) ;
2017-01-11 12:53:31 +01:00
Dictionary d ; //last bit means shared
2016-08-08 00:22:33 +02:00
len & = 0x7FFFFFFF ;
for ( uint32_t i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01: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-10 02:10:30 +01: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-10 02:10:30 +01:00
d [ key ] = value ;
}
r_v = d ;
} break ;
case VARIANT_ARRAY : {
2016-08-08 00:22:33 +02:00
uint32_t len = f - > get_32 ( ) ;
2017-01-11 12:53:31 +01:00
Array a ; //last bit means shared
2016-08-08 00:22:33 +02:00
len & = 0x7FFFFFFF ;
2014-02-10 02:10:30 +01:00
a . resize ( len ) ;
2016-08-08 00:22:33 +02:00
for ( uint32_t i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
a [ i ] = val ;
}
r_v = a ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_BYTE_ARRAY : {
2014-02-10 02:10:30 +01:00
uint32_t len = f - > get_32 ( ) ;
2020-02-17 22:06:54 +01:00
Vector < uint8_t > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
2020-02-17 22:06:54 +01:00
uint8_t * w = array . ptrw ( ) ;
f - > get_buffer ( w , len ) ;
2014-02-10 02:10:30 +01:00
_advance_padding ( len ) ;
2020-02-17 22:06:54 +01:00
2014-02-10 02:10:30 +01:00
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_INT32_ARRAY : {
2014-02-10 02:10:30 +01:00
uint32_t len = f - > get_32 ( ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
Vector < int32_t > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
int32_t * w = array . ptrw ( ) ;
f - > get_buffer ( ( uint8_t * ) w , len * sizeof ( int32_t ) ) ;
2014-02-10 02:10:30 +01: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 22:06:54 +01:00
2014-02-10 02:10:30 +01:00
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_INT64_ARRAY : {
2014-02-10 02:10:30 +01:00
uint32_t len = f - > get_32 ( ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
Vector < int64_t > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01: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 : {
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01: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-10 02:10:30 +01:00
# ifdef BIG_ENDIAN_ENABLED
{
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len ; i + + ) {
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
}
}
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
# endif
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_FLOAT64_ARRAY : {
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01: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-10 02:10:30 +01:00
# endif
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_STRING_ARRAY : {
2014-02-10 02:10:30 +01:00
uint32_t len = f - > get_32 ( ) ;
2020-02-17 22:06:54 +01:00
Vector < String > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
2020-02-17 22:06:54 +01:00
String * w = array . ptrw ( ) ;
2020-05-14 16:41:43 +02:00
for ( uint32_t i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01:00
w [ i ] = get_unicode_string ( ) ;
2020-05-14 16:41:43 +02:00
}
2020-02-17 22:06:54 +01:00
2014-02-10 02:10:30 +01:00
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_VECTOR2_ARRAY : {
2014-02-10 02:10:30 +01:00
uint32_t len = f - > get_32 ( ) ;
2020-02-17 22:06:54 +01:00
Vector < Vector2 > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
2020-02-17 22:06:54 +01:00
Vector2 * w = array . ptrw ( ) ;
2022-03-19 17:56:45 +01:00
static_assert ( sizeof ( Vector2 ) = = 2 * sizeof ( real_t ) ) ;
2022-03-23 10:08:58 +01:00
const Error err = read_reals ( reinterpret_cast < real_t * > ( w ) , f , len * 2 ) ;
2022-03-19 17:56:45 +01:00
ERR_FAIL_COND_V ( err ! = OK , err ) ;
2020-02-17 22:06:54 +01:00
2014-02-10 02:10:30 +01:00
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_VECTOR3_ARRAY : {
2014-02-10 02:10:30 +01:00
uint32_t len = f - > get_32 ( ) ;
2020-02-17 22:06:54 +01:00
Vector < Vector3 > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
2020-02-17 22:06:54 +01:00
Vector3 * w = array . ptrw ( ) ;
2022-03-19 17:56:45 +01:00
static_assert ( sizeof ( Vector3 ) = = 3 * sizeof ( real_t ) ) ;
2022-03-23 10:08:58 +01:00
const Error err = read_reals ( reinterpret_cast < real_t * > ( w ) , f , len * 3 ) ;
2022-03-19 17:56:45 +01:00
ERR_FAIL_COND_V ( err ! = OK , err ) ;
2020-02-17 22:06:54 +01:00
2014-02-10 02:10:30 +01:00
r_v = array ;
} break ;
2021-12-24 18:44:08 +01:00
case VARIANT_PACKED_COLOR_ARRAY : {
2014-02-10 02:10:30 +01:00
uint32_t len = f - > get_32 ( ) ;
2020-02-17 22:06:54 +01:00
Vector < Color > array ;
2014-02-10 02:10:30 +01:00
array . resize ( len ) ;
2020-02-17 22:06:54 +01:00
Color * w = array . ptrw ( ) ;
2022-03-19 17:56:45 +01: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-10 02:10:30 +01:00
# ifdef BIG_ENDIAN_ENABLED
2022-03-19 17:56:45 +01:00
{
uint32_t * ptr = ( uint32_t * ) w . ptr ( ) ;
for ( int i = 0 ; i < len * 4 ; i + + ) {
ptr [ i ] = BSWAP32 ( ptr [ i ] ) ;
2014-02-10 02:10:30 +01:00
}
2022-03-19 17:56:45 +01:00
}
2014-02-10 02:10:30 +01:00
# endif
r_v = array ;
} break ;
2024-04-08 16:51:34 +02: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-10 02:10:30 +01:00
default : {
ERR_FAIL_V ( ERR_FILE_CORRUPT ) ;
} break ;
}
return OK ; //never reach anyway
}
2020-02-28 12:27:04 +01:00
Ref < Resource > ResourceLoaderBinary : : get_resource ( ) {
2014-02-10 02:10:30 +01:00
return resource ;
}
2020-05-14 14:29:06 +02:00
2020-02-28 12:27:04 +01:00
Error ResourceLoaderBinary : : load ( ) {
2020-05-14 16:41:43 +02:00
if ( error ! = OK ) {
2014-02-10 02:10:30 +01:00
return error ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2020-02-28 12:27:04 +01:00
for ( int i = 0 ; i < external_resources . size ( ) ; i + + ) {
String path = external_resources [ i ] . path ;
2017-02-15 12:29:46 +01:00
2015-08-24 01:15:56 +02:00
if ( remaps . has ( path ) ) {
path = remaps [ path ] ;
}
2014-02-10 02:10:30 +01:00
2022-02-03 17:03:38 +01:00
if ( ! path . contains ( " :// " ) & & path . is_relative_path ( ) ) {
2020-02-28 12:27:04 +01:00
// path is relative to file being loaded, so convert to a resource path
2022-08-30 02:34:01 +02:00
path = ProjectSettings : : get_singleton ( ) - > localize_path ( path . get_base_dir ( ) . path_join ( external_resources [ i ] . path ) ) ;
2020-02-28 12:27:04 +01: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 12:27:04 +01:00
}
2014-02-10 02:10:30 +01:00
}
}
2020-02-28 12:27:04 +01:00
for ( int i = 0 ; i < internal_resources . size ( ) ; i + + ) {
bool main = i = = ( internal_resources . size ( ) - 1 ) ;
2014-02-10 02:10:30 +01:00
2020-02-28 12:27:04 +01:00
//maybe it is loaded already
String path ;
2021-07-21 02:36:56 +02:00
String id ;
2014-02-10 02:10:30 +01:00
2020-02-28 12:27:04 +01:00
if ( ! main ) {
2020-05-01 14:34:23 +02:00
path = internal_resources [ i ] . path ;
if ( path . begins_with ( " local:// " ) ) {
path = path . replace_first ( " local:// " , " " ) ;
2021-07-21 02:36:56 +02:00
id = path ;
2020-05-01 14:34:23 +02:00
path = res_path + " :: " + path ;
2021-07-21 02:36:56 +02:00
internal_resources . write [ i ] . path = path ; // Update path.
2020-05-01 14:34:23 +02: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-20 04:19:21 +02:00
//already loaded, don't do anything
error = OK ;
2022-02-12 10:57:51 +01:00
internal_index_cache [ path ] = cached ;
2020-04-20 04:19:21 +02:00
continue ;
}
2020-02-28 12:27:04 +01:00
}
} else {
2021-02-11 18:18:45 +01:00
if ( cache_mode ! = ResourceFormatLoader : : CACHE_MODE_IGNORE & & ! ResourceCache : : has ( res_path ) ) {
2020-02-28 12:27:04 +01:00
path = res_path ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2020-02-28 12:27:04 +01:00
uint64_t offset = internal_resources [ i ] . offset ;
2014-02-10 02:10:30 +01:00
2020-02-28 12:27:04 +01:00
f - > seek ( offset ) ;
2014-02-10 02:10:30 +01:00
2020-02-28 12:27:04 +01:00
String t = get_unicode_string ( ) ;
2014-02-10 02:10:30 +01:00
2022-05-03 01:43:50 +02:00
Ref < Resource > res ;
2014-02-10 02:10:30 +01:00
2021-02-11 18:18:45 +01:00
if ( cache_mode = = ResourceFormatLoader : : CACHE_MODE_REPLACE & & ResourceCache : : has ( path ) ) {
//use the existing one
2022-06-22 13:46:46 +02:00
Ref < Resource > cached = ResourceCache : : get_ref ( path ) ;
if ( cached - > get_class ( ) = = t ) {
cached - > reset_state ( ) ;
res = cached ;
2021-02-11 18:18:45 +01:00
}
2020-02-28 12:27:04 +01:00
}
2014-02-10 02:10:30 +01:00
2022-04-28 22:49:10 +02:00
MissingResource * missing_resource = nullptr ;
2021-02-11 18:18:45 +01:00
if ( res . is_null ( ) ) {
//did not replace
2014-02-10 02:10:30 +01:00
2021-06-18 00:03:09 +02:00
Object * obj = ClassDB : : instantiate ( t ) ;
2021-02-11 18:18:45 +01:00
if ( ! obj ) {
2022-04-28 22:49:10 +02:00
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 + " . " ) ;
}
2021-02-11 18:18:45 +01:00
}
Resource * 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 + " . " ) ;
}
2022-05-03 01:43:50 +02:00
res = Ref < Resource > ( 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 18:18:45 +01:00
}
2021-07-21 02:36:56 +02:00
r - > set_scene_unique_id ( id ) ;
2020-04-20 04:19:21 +02:00
}
2014-02-10 02:10:30 +01:00
2020-04-20 04:19:21 +02:00
if ( ! main ) {
2020-05-01 14:34:23 +02:00
internal_index_cache [ path ] = res ;
2020-04-20 04:19:21 +02:00
}
2020-02-28 12:27:04 +01:00
int pc = f - > get_32 ( ) ;
2014-02-10 02:10:30 +01:00
2020-02-28 12:27:04 +01:00
//set properties
2014-02-10 02:10:30 +01:00
2022-04-28 22:49:10 +02:00
Dictionary missing_resource_properties ;
2020-02-28 12:27:04 +01:00
for ( int j = 0 ; j < pc ; j + + ) {
StringName name = _get_string ( ) ;
2017-12-15 12:38:24 +01:00
2020-02-28 12:27:04 +01:00
if ( name = = StringName ( ) ) {
error = ERR_FILE_CORRUPT ;
ERR_FAIL_V ( ERR_FILE_CORRUPT ) ;
}
2014-02-10 02:10:30 +01:00
2020-02-28 12:27:04 +01:00
Variant value ;
2014-02-10 02:10:30 +01:00
2020-02-28 12:27:04 +01:00
error = parse_variant ( value ) ;
2020-05-14 16:41:43 +02:00
if ( error ) {
2020-02-28 12:27:04 +01:00
return error ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01: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 ;
}
}
2023-02-01 07:21:09 +01: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 ( ) ) ;
}
}
}
2022-04-28 22:49:10 +02:00
if ( set_valid ) {
res - > set ( name , value ) ;
}
}
if ( missing_resource ) {
missing_resource - > set_recording_properties ( false ) ;
}
if ( ! missing_resource_properties . is_empty ( ) ) {
res - > set_meta ( META_MISSING_RESOURCES , missing_resource_properties ) ;
2020-02-28 12:27:04 +01:00
}
2022-04-28 22:49:10 +02:00
2014-02-10 02:10:30 +01:00
# ifdef TOOLS_ENABLED
2020-02-28 12:27:04 +01:00
res - > set_edited ( false ) ;
2014-02-10 02:10:30 +01:00
# endif
2020-02-28 12:27:04 +01:00
if ( progress ) {
* progress = ( i + 1 ) / float ( internal_resources . size ( ) ) ;
}
2014-02-10 02:10:30 +01:00
2020-02-28 12:27:04 +01:00
resource_cache . push_back ( res ) ;
2014-02-10 02:10:30 +01:00
2020-02-28 12:27:04 +01:00
if ( main ) {
2022-04-12 09:12:40 +02:00
f . unref ( ) ;
2020-02-28 12:27:04 +01:00
resource = res ;
resource - > set_as_translation_remapped ( translation_remapped ) ;
error = OK ;
return OK ;
}
2014-02-10 02:10:30 +01:00
}
2020-02-28 12:27:04 +01:00
return ERR_FILE_EOF ;
2014-02-10 02:10:30 +01:00
}
2020-02-28 12:27:04 +01:00
void ResourceLoaderBinary : : set_translation_remapped ( bool p_remapped ) {
2017-06-28 22:00:18 +02:00
translation_remapped = p_remapped ;
}
2022-03-23 10:08:58 +01:00
static void save_ustring ( Ref < FileAccess > f , const String & p_string ) {
2015-08-24 01:15:56 +02: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 10:08:58 +01:00
static String get_ustring ( Ref < FileAccess > f ) {
2015-08-24 01:15:56 +02: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 12:27:04 +01:00
String ResourceLoaderBinary : : get_unicode_string ( ) {
2014-02-10 02:10:30 +01: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 13:08:41 +01:00
return String ( ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01: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 10:08:58 +01:00
void ResourceLoaderBinary : : get_dependencies ( Ref < FileAccess > p_f , List < String > * p_dependencies , bool p_add_types ) {
2021-07-23 21:01:18 +02:00
open ( p_f , false , true ) ;
2020-05-14 16:41:43 +02:00
if ( error ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < external_resources . size ( ) ; i + + ) {
2021-07-23 21:01:18 +02:00
String dep ;
2023-06-16 13:40:10 +02:00
String fallback_path ;
2021-07-23 21:01:18 +02: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 21:01:18 +02:00
} else {
dep = external_resources [ i ] . path ;
}
2014-03-14 02:57:24 +01:00
2021-12-09 10:42:46 +01:00
if ( p_add_types & & ! external_resources [ i ] . type . is_empty ( ) ) {
2015-08-24 01:15:56 +02: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-24 01:15:56 +02:00
2014-03-14 02:57:24 +01:00
p_dependencies - > push_back ( dep ) ;
2014-02-10 02:10:30 +01:00
}
}
2022-03-23 10:08:58 +01: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-10 02:10:30 +01: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 04:39:20 +01:00
// Compressed.
2022-03-23 10:08:58 +01:00
Ref < FileAccessCompressed > fac ;
fac . instantiate ( ) ;
2020-02-11 04:39:20 +01:00
error = fac - > open_after_magic ( f ) ;
if ( error ! = OK ) {
2022-04-12 09:12:40 +02:00
f . unref ( ) ;
2020-02-11 04:39:20 +01:00
ERR_FAIL_MSG ( " Failed to open binary resource file: " + local_path + " . " ) ;
}
2014-02-10 02:10:30 +01:00
f = fac ;
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
2020-02-11 04:39:20 +01:00
// Not normal.
2014-02-10 02:10:30 +01:00
error = ERR_FILE_UNRECOGNIZED ;
2022-04-12 09:12:40 +02:00
f . unref ( ) ;
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " Unrecognized binary resource file: " + local_path + " . " ) ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
uint32_t ver_major = f - > get_32 ( ) ;
uint32_t ver_minor = f - > get_32 ( ) ;
2017-11-22 12:34:43 +01:00
ver_format = f - > get_32 ( ) ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01: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-24 01:15:56 +02:00
if ( ver_format > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
2022-04-12 09:12:40 +02: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-10 02:10:30 +01:00
}
type = get_unicode_string ( ) ;
print_bl ( " type: " + type ) ;
importmd_ofs = f - > get_64 ( ) ;
2021-07-21 02:36:56 +02:00
uint32_t flags = f - > get_32 ( ) ;
if ( flags & ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_NAMED_SCENE_IDS ) {
using_named_scene_ids = true ;
}
2021-07-23 21:01:18 +02:00
if ( flags & ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_UIDS ) {
using_uids = true ;
}
2022-02-16 01:55:13 +01:00
f - > real_is_double = ( flags & ResourceFormatSaverBinaryInstance : : FORMAT_FLAG_REAL_T_IS_DOUBLE ) ! = 0 ;
2021-07-23 21:01:18 +02:00
if ( using_uids ) {
uid = f - > get_64 ( ) ;
} else {
2021-07-30 07:25:18 +02:00
f - > get_64 ( ) ; // skip over uid field
2021-07-23 21:01:18 +02: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-30 07:24:29 +02:00
for ( int i = 0 ; i < ResourceFormatSaverBinaryInstance : : RESERVED_FIELDS ; i + + ) {
2014-02-10 02:10:30 +01:00
f - > get_32 ( ) ; //skip a few reserved fields
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2021-07-23 21:01:18 +02:00
if ( p_no_resources ) {
return ;
}
2014-02-10 02:10:30 +01: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-10 02:10:30 +01: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 07:02:49 +02:00
ExtResource er ;
2014-02-10 02:10:30 +01:00
er . type = get_unicode_string ( ) ;
er . path = get_unicode_string ( ) ;
2021-07-23 21:01:18 +02: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 21:01:18 +02:00
}
}
}
2017-12-15 12:38:24 +01:00
2014-02-10 02:10:30 +01: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 07:02:49 +02:00
IntResource ir ;
2014-02-10 02:10:30 +01: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 09:12:40 +02:00
f . unref ( ) ;
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " Premature end of file (EOF): " + local_path + " . " ) ;
2014-02-10 02:10:30 +01:00
}
}
2022-03-23 10:08:58 +01:00
String ResourceLoaderBinary : : recognize ( Ref < FileAccess > p_f ) {
2014-02-10 02:10:30 +01: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 04:39:20 +01:00
// Compressed.
2022-03-23 10:08:58 +01:00
Ref < FileAccessCompressed > fac ;
fac . instantiate ( ) ;
2020-02-11 04:39:20 +01:00
error = fac - > open_after_magic ( f ) ;
if ( error ! = OK ) {
2022-04-12 09:12:40 +02:00
f . unref ( ) ;
2020-02-11 04:39:20 +01:00
return " " ;
}
2014-02-10 02:10:30 +01:00
f = fac ;
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
2020-02-11 04:39:20 +01:00
// Not normal.
2014-04-05 17:39:30 +02:00
error = ERR_FILE_UNRECOGNIZED ;
2022-04-12 09:12:40 +02:00
f . unref ( ) ;
2014-02-10 02:10:30 +01:00
return " " ;
}
bool big_endian = f - > get_32 ( ) ;
2017-09-02 22:32:31 +02:00
f - > get_32 ( ) ; // use_real64
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
uint32_t ver_major = f - > get_32 ( ) ;
2017-09-02 22:32:31 +02:00
f - > get_32 ( ) ; // ver_minor
2022-09-29 11:53:28 +02:00
uint32_t ver_fmt = f - > get_32 ( ) ;
2014-02-10 02:10:30 +01:00
2022-09-29 11:53:28 +02:00
if ( ver_fmt > FORMAT_VERSION | | ver_major > VERSION_MAJOR ) {
2022-04-12 09:12:40 +02:00
f . unref ( ) ;
2014-02-10 02:10:30 +01:00
return " " ;
}
2022-09-29 11:53:28 +02:00
return get_unicode_string ( ) ;
2014-02-10 02:10:30 +01: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-24 01:15:56 +02:00
* r_error = ERR_FILE_CANT_OPEN ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
Error err ;
2022-03-23 10:08:58 +01:00
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ , & err ) ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
2020-02-28 12:27:04 +01: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 12:27:04 +01:00
loader . use_sub_threads = p_use_sub_threads ;
loader . progress = r_progress ;
2021-12-09 10:42:46 +01:00
String path = ! p_original_path . is_empty ( ) ? p_original_path : p_path ;
2020-02-28 12:27:04 +01:00
loader . local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( path ) ;
loader . res_path = loader . local_path ;
loader . open ( f ) ;
err = loader . load ( ) ;
if ( r_error ) {
* r_error = err ;
}
2014-02-10 02:10:30 +01:00
2020-02-28 12:27:04 +01:00
if ( err ) {
2022-05-03 01:43:50 +02:00
return Ref < Resource > ( ) ;
2020-02-28 12:27:04 +01:00
}
return loader . resource ;
2014-02-10 02:10:30 +01:00
}
void ResourceFormatLoaderBinary : : get_recognized_extensions_for_type ( const String & p_type , List < String > * p_extensions ) const {
2021-12-09 10:42:46 +01:00
if ( p_type . is_empty ( ) ) {
2014-02-10 02:10:30 +01:00
get_recognized_extensions ( p_extensions ) ;
return ;
}
List < String > extensions ;
2017-01-03 03:03:46 +01:00
ClassDB : : get_extensions_for_type ( p_type , & extensions ) ;
2014-02-10 02:10:30 +01:00
extensions . sort ( ) ;
2021-07-24 15:46:25 +02:00
for ( const String & E : extensions ) {
2021-07-16 05:45:57 +02:00
String ext = E . to_lower ( ) ;
2014-02-10 02:10:30 +01:00
p_extensions - > push_back ( ext ) ;
}
}
2020-05-14 14:29:06 +02:00
2014-02-10 02:10:30 +01:00
void ResourceFormatLoaderBinary : : get_recognized_extensions ( List < String > * p_extensions ) const {
List < String > extensions ;
2017-01-03 03:03:46 +01:00
ClassDB : : get_resource_base_extensions ( & extensions ) ;
2014-02-10 02:10:30 +01:00
extensions . sort ( ) ;
2021-07-24 15:46:25 +02:00
for ( const String & E : extensions ) {
2021-07-16 05:45:57 +02:00
String ext = E . to_lower ( ) ;
2014-02-10 02:10:30 +01:00
p_extensions - > push_back ( ext ) ;
}
}
bool ResourceFormatLoaderBinary : : handles_type ( const String & p_type ) const {
return true ; //handles all
}
2015-08-24 01:15:56 +02:00
void ResourceFormatLoaderBinary : : get_dependencies ( const String & p_path , List < String > * p_dependencies , bool p_add_types ) {
2022-03-23 10:08:58 +01:00
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
ERR_FAIL_COND_MSG ( f . is_null ( ) , " Cannot open file ' " + p_path + " '. " ) ;
2014-02-10 02:10:30 +01:00
2020-02-28 12:27:04 +01: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-24 01:15:56 +02: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 10:08:58 +01: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-24 01:15:56 +02:00
2022-03-23 10:08:58 +01:00
Ref < FileAccess > fw ;
2015-08-24 01:15:56 +02: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 04:39:20 +01:00
// Compressed.
2022-03-23 10:08:58 +01:00
Ref < FileAccessCompressed > fac ;
fac . instantiate ( ) ;
2020-02-11 04:39:20 +01:00
Error err = fac - > open_after_magic ( f ) ;
2022-03-23 10:08:58 +01:00
ERR_FAIL_COND_V_MSG ( err ! = OK , err , " Cannot open file ' " + p_path + " '. " ) ;
2015-08-24 01:15:56 +02:00
f = fac ;
2022-03-23 10:08:58 +01:00
Ref < FileAccessCompressed > facw ;
facw . instantiate ( ) ;
2015-08-24 01:15:56 +02:00
facw - > configure ( " RSCC " ) ;
2022-09-05 13:01:31 +02:00
err = facw - > open_internal ( p_path + " .depren " , FileAccess : : WRITE ) ;
2022-03-23 10:08:58 +01:00
ERR_FAIL_COND_V_MSG ( err , ERR_FILE_CORRUPT , " Cannot create file ' " + p_path + " .depren'. " ) ;
2015-08-24 01:15:56 +02:00
fw = facw ;
} else if ( header [ 0 ] ! = ' R ' | | header [ 1 ] ! = ' S ' | | header [ 2 ] ! = ' R ' | | header [ 3 ] ! = ' C ' ) {
2020-02-11 04:39:20 +01: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-24 01:15:56 +02:00
} else {
fw = FileAccess : : open ( p_path + " .depren " , FileAccess : : WRITE ) ;
2022-03-23 10:08:58 +01:00
ERR_FAIL_COND_V_MSG ( fw . is_null ( ) , ERR_CANT_CREATE , " Cannot create file ' " + p_path + " .depren'. " ) ;
2017-09-03 05:22:54 +02:00
uint8_t magic [ 4 ] = { ' R ' , ' S ' , ' R ' , ' C ' } ;
fw - > store_buffer ( magic , 4 ) ;
2015-08-24 01:15:56 +02: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-24 01:15:56 +02: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 12:15:31 +02:00
fw . unref ( ) ;
2022-03-10 15:27:09 +01:00
{
2022-03-23 10:08:58 +01: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-24 01:15:56 +02: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-24 01:15:56 +02: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-24 01:15:56 +02:00
2020-02-28 12:27:04 +01: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-24 01:15:56 +02:00
2020-02-28 12:27:04 +01:00
err = loader . load ( ) ;
2015-08-24 01:15:56 +02: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-24 01:15:56 +02: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-24 01:15:56 +02: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-24 01:15:56 +02: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-24 01:15:56 +02: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-24 01:15:56 +02:00
fw - > store_64 ( 0 ) ; //metadata offset
2021-07-23 21:01:18 +02: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 21:01:18 +02:00
2021-07-30 07:24:29 +02:00
for ( int i = 0 ; i < ResourceFormatSaverBinaryInstance : : RESERVED_FIELDS ; i + + ) {
2021-07-30 03:17:49 +02:00
fw - > store_32 ( 0 ) ; // reserved
2015-08-24 01:15:56 +02: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 21:01:18 +02: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-24 01:15:56 +02:00
bool relative = false ;
if ( ! path . begins_with ( " res:// " ) ) {
2022-08-30 02:34:01 +02:00
path = local_path . path_join ( path ) . simplify_path ( ) ;
2015-08-24 01:15:56 +02:00
relative = true ;
}
if ( p_map . has ( path ) ) {
String np = p_map [ path ] ;
path = np ;
}
2021-07-23 21:01:18 +02:00
String full_path = path ;
2015-08-24 01:15:56 +02:00
if ( relative ) {
//restore relative
path = local_path . path_to_file ( path ) ;
}
save_ustring ( fw , type ) ;
save_ustring ( fw , path ) ;
2021-07-23 21:01:18 +02:00
if ( using_uids ) {
ResourceUID : : ID uid = ResourceSaver : : get_resource_id_for_path ( full_path ) ;
2021-07-30 03:17:49 +02:00
fw - > store_64 ( uid ) ;
2021-07-23 21:01:18 +02:00
}
2015-08-24 01:15:56 +02: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-24 01:15:56 +02: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 15:37:50 +02:00
f . unref ( ) ;
2015-08-24 01:15:56 +02: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 12:15:31 +02:00
fw . unref ( ) ;
2022-03-23 10:08:58 +01: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-24 01:15:56 +02:00
return OK ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
String ResourceFormatLoaderBinary : : get_resource_type ( const String & p_path ) const {
2022-03-23 10:08:58 +01:00
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
if ( f . is_null ( ) ) {
2021-03-12 14:35:16 +01:00
return " " ; //could not read
2014-02-10 02:10:30 +01:00
}
2020-02-28 12:27:04 +01: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 22:39:08 +02:00
return ClassDB : : get_compatibility_remapped_class ( r ) ;
2014-02-10 02:10:30 +01: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 21:01:18 +02: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 10:08:58 +01:00
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : READ ) ;
if ( f . is_null ( ) ) {
2021-07-23 21:01:18 +02: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-10 02:10:30 +01:00
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
2022-03-23 10:08:58 +01:00
void ResourceFormatSaverBinaryInstance : : _pad_buffer ( Ref < FileAccess > f , int p_bytes ) {
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
f - > store_8 ( 0 ) ; //pad to 32
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01: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-10 02:10:30 +01: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-09 00:58:39 +01:00
int64_t val = p_property ;
2018-10-04 15:38:52 +02:00
if ( val > 0x7FFFFFFF | | val < - ( int64_t ) 0x80000000 ) {
2017-01-09 00:58:39 +01: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-09 00:58:39 +01:00
}
2014-02-10 02:10:30 +01:00
} break ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
case Variant : : FLOAT : {
2017-01-09 00:58:39 +01:00
double d = p_property ;
float fl = d ;
if ( double ( fl ) ! = d ) {
f - > store_32 ( VARIANT_DOUBLE ) ;
f - > store_double ( d ) ;
} else {
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
f - > store_32 ( VARIANT_FLOAT ) ;
2017-01-09 00:58:39 +01:00
f - > store_real ( fl ) ;
}
2014-02-10 02:10:30 +01:00
} break ;
case Variant : : STRING : {
f - > store_32 ( VARIANT_STRING ) ;
String val = p_property ;
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , val ) ;
2014-02-10 02:10:30 +01: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 04:26:41 +01: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-10 02:10:30 +01: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-10 02:10:30 +01:00
f - > store_real ( val . size . x ) ;
f - > store_real ( val . size . y ) ;
2020-02-22 04:26:41 +01: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-10 02:10:30 +01: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 04:26:41 +01: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 ) ;
Implement Vector4, Vector4i, Projection
Implement built-in classes Vector4, Vector4i and Projection.
* Two versions of Vector4 (float and integer).
* A Projection class, which is a 4x4 matrix specialized in projection types.
These types have been requested for a long time, but given they were very corner case they were not added before.
Because in Godot 4, reimplementing parts of the rendering engine is now possible, access to these types (heavily used by the rendering code) becomes a necessity.
**Q**: Why Projection and not Matrix4?
**A**: Godot does not use Matrix2, Matrix3, Matrix4x3, etc. naming convention because, within the engine, these types always have a *purpose*. As such, Godot names them: Transform2D, Transform3D or Basis. In this case, this 4x4 matrix is _always_ used as a _Projection_, hence the naming.
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-10 02:10:30 +01: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-10 02:10:30 +01:00
} break ;
2021-01-20 08:02:02 +01:00
case Variant : : QUATERNION : {
f - > store_32 ( VARIANT_QUATERNION ) ;
Quaternion val = p_property ;
2014-02-10 02:10:30 +01:00
f - > store_real ( val . x ) ;
f - > store_real ( val . y ) ;
f - > store_real ( val . z ) ;
f - > store_real ( val . w ) ;
} break ;
2017-11-17 03:09:00 +01: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-10 02:10:30 +01:00
f - > store_real ( val . size . x ) ;
f - > store_real ( val . size . y ) ;
f - > store_real ( val . size . z ) ;
} break ;
2017-01-11 04:52:51 +01:00
case Variant : : TRANSFORM2D : {
2021-12-28 02:28:25 +01:00
f - > store_32 ( VARIANT_TRANSFORM2D ) ;
2017-01-11 04:52:51 +01:00
Transform2D val = p_property ;
2022-04-24 23:59:24 +02: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-10 02:10:30 +01:00
} break ;
2017-01-11 04:52:51 +01:00
case Variant : : BASIS : {
2021-12-28 02:28:25 +01:00
f - > store_32 ( VARIANT_BASIS ) ;
2017-01-11 04:52:51 +01:00
Basis val = p_property ;
2022-04-25 00:07:35 +02: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-10 02:10:30 +01:00
} break ;
2021-04-28 09:36:08 +02:00
case Variant : : TRANSFORM3D : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_TRANSFORM3D ) ;
2020-10-17 07:08:21 +02:00
Transform3D val = p_property ;
2022-04-25 00:07:35 +02: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-10 02:10:30 +01:00
f - > store_real ( val . origin . x ) ;
f - > store_real ( val . origin . y ) ;
f - > store_real ( val . origin . z ) ;
Implement Vector4, Vector4i, Projection
Implement built-in classes Vector4, Vector4i and Projection.
* Two versions of Vector4 (float and integer).
* A Projection class, which is a 4x4 matrix specialized in projection types.
These types have been requested for a long time, but given they were very corner case they were not added before.
Because in Godot 4, reimplementing parts of the rendering engine is now possible, access to these types (heavily used by the rendering code) becomes a necessity.
**Q**: Why Projection and not Matrix4?
**A**: Godot does not use Matrix2, Matrix3, Matrix4x3, etc. naming convention because, within the engine, these types always have a *purpose*. As such, Godot names them: Transform2D, Transform3D or Basis. In this case, this 4x4 matrix is _always_ used as a _Projection_, hence the naming.
2022-07-20 01:11:13 +02:00
} break ;
case Variant : : PROJECTION : {
f - > store_32 ( VARIANT_PROJECTION ) ;
Projection val = p_property ;
2022-10-04 18:44:48 +02: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 ) ;
Implement Vector4, Vector4i, Projection
Implement built-in classes Vector4, Vector4i and Projection.
* Two versions of Vector4 (float and integer).
* A Projection class, which is a 4x4 matrix specialized in projection types.
These types have been requested for a long time, but given they were very corner case they were not added before.
Because in Godot 4, reimplementing parts of the rendering engine is now possible, access to these types (heavily used by the rendering code) becomes a necessity.
**Q**: Why Projection and not Matrix4?
**A**: Godot does not use Matrix2, Matrix3, Matrix4x3, etc. naming convention because, within the engine, these types always have a *purpose*. As such, Godot names them: Transform2D, Transform3D or Basis. In this case, this 4x4 matrix is _always_ used as a _Projection_, hence the naming.
2022-07-20 01:11:13 +02:00
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
2020-02-20 22:58:05 +01:00
} break ;
case Variant : : STRING_NAME : {
f - > store_32 ( VARIANT_STRING_NAME ) ;
String val = p_property ;
save_unicode_string ( f , val ) ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
snc | = 0x8000 ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
f - > store_16 ( snc ) ;
2017-12-15 12:38:24 +01: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-10 02:10:30 +01:00
} break ;
2020-11-09 14:53:05 +01:00
case Variant : : RID : {
2014-02-10 02:10:30 +01:00
f - > store_32 ( VARIANT_RID ) ;
2019-08-15 04:57:49 +02:00
WARN_PRINT ( " Can't save RIDs. " ) ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
f - > store_32 ( OBJECT_EMPTY ) ;
2023-07-01 01:29:46 +02:00
return ; // Don't save it.
2014-02-10 02:10:30 +01:00
}
2021-07-10 21:17:41 +02:00
if ( ! res - > is_built_in ( ) ) {
2015-08-24 01:15:56 +02:00
f - > store_32 ( OBJECT_EXTERNAL_RESOURCE_INDEX ) ;
f - > store_32 ( external_resources [ res ] ) ;
2014-02-10 02:10:30 +01:00
} else {
2021-07-21 02:36:56 +02:00
if ( ! resource_map . has ( res ) ) {
2014-02-10 02:10:30 +01:00
f - > store_32 ( OBJECT_EMPTY ) ;
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " Resource was not pre cached for the resource section, most likely due to circular reference. " ) ;
2014-02-10 02:10:30 +01:00
}
f - > store_32 ( OBJECT_INTERNAL_RESOURCE ) ;
2021-07-21 02:36:56 +02:00
f - > store_32 ( resource_map [ res ] ) ;
2014-02-10 02:10:30 +01:00
//internal resource
}
} break ;
2020-02-19 20:27:19 +01: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-10 02:10:30 +01:00
case Variant : : DICTIONARY : {
f - > store_32 ( VARIANT_DICTIONARY ) ;
Dictionary d = p_property ;
2017-01-11 12:53:31 +01:00
f - > store_32 ( uint32_t ( d . size ( ) ) ) ;
2014-02-10 02:10:30 +01:00
List < Variant > keys ;
d . get_key_list ( & keys ) ;
2021-07-24 15:46:25 +02:00
for ( const Variant & E : keys ) {
2021-07-16 05:45:57 +02:00
write_variant ( f , E , resource_map , external_resources , string_map ) ;
write_variant ( f , d [ E ] , resource_map , external_resources , string_map ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
case Variant : : ARRAY : {
f - > store_32 ( VARIANT_ARRAY ) ;
Array a = p_property ;
2017-01-11 12:53:31 +01: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-10 02:10:30 +01:00
}
} break ;
2020-02-17 22:06:54 +01:00
case Variant : : PACKED_BYTE_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_BYTE_ARRAY ) ;
2020-02-17 22:06:54 +01:00
Vector < uint8_t > arr = p_property ;
2014-02-10 02:10:30 +01:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
2020-02-17 22:06:54 +01:00
const uint8_t * r = arr . ptr ( ) ;
f - > store_buffer ( r , len ) ;
2017-12-15 12:38:24 +01:00
_pad_buffer ( f , len ) ;
2014-02-10 02:10:30 +01:00
} break ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
case Variant : : PACKED_INT32_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_INT32_ARRAY ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
Vector < int32_t > arr = p_property ;
2014-02-10 02:10:30 +01:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
const int32_t * r = arr . ptr ( ) ;
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < len ; i + + ) {
2014-02-10 02:10:30 +01:00
f - > store_32 ( r [ i ] ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
} break ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
case Variant : : PACKED_INT64_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_INT64_ARRAY ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
Vector < int64_t > arr = p_property ;
2014-02-10 02:10:30 +01:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
const int64_t * r = arr . ptr ( ) ;
2020-05-14 16:41:43 +02:00
for ( int i = 0 ; i < len ; i + + ) {
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
f - > store_64 ( r [ i ] ) ;
2020-05-14 16:41:43 +02:00
}
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
} break ;
case Variant : : PACKED_FLOAT32_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_FLOAT32_ARRAY ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
Vector < float > arr = p_property ;
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
const float * r = arr . ptr ( ) ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < len ; i + + ) {
2022-06-08 14:32:41 +02:00
f - > store_float ( r [ i ] ) ;
2014-02-10 02:10:30 +01:00
}
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01:00
} break ;
case Variant : : PACKED_FLOAT64_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_FLOAT64_ARRAY ) ;
Variant: Added 64-bit packed arrays, renamed Variant::REAL to FLOAT.
- Renames PackedIntArray to PackedInt32Array.
- Renames PackedFloatArray to PackedFloat32Array.
- Adds PackedInt64Array and PackedFloat64Array.
- Renames Variant::REAL to Variant::FLOAT for consistency.
Packed arrays are for storing large amount of data and creating stuff like
meshes, buffers. textures, etc. Forcing them to be 64 is a huge waste of
memory. That said, many users requested the ability to have 64 bits packed
arrays for their games, so this is just an optional added type.
For Variant, the float datatype is always 64 bits, and exposed as `float`.
We still have `real_t` which is the datatype that can change from 32 to 64
bits depending on a compile flag (not entirely working right now, but that's
the idea). It affects math related datatypes and code only.
Neither Variant nor PackedArray make use of real_t, which is only intended
for math precision, so the term is removed from there to keep only float.
2020-02-24 19:20:53 +01: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-10 02:10:30 +01:00
} break ;
2020-02-17 22:06:54 +01:00
case Variant : : PACKED_STRING_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_STRING_ARRAY ) ;
2020-02-17 22:06:54 +01:00
Vector < String > arr = p_property ;
2014-02-10 02:10:30 +01:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
2020-02-17 22:06:54 +01:00
const String * r = arr . ptr ( ) ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < len ; i + + ) {
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , r [ i ] ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
2024-04-08 16:51:34 +02:00
case Variant : : PACKED_VECTOR2_ARRAY : {
f - > store_32 ( VARIANT_PACKED_VECTOR2_ARRAY ) ;
Vector < Vector2 > arr = p_property ;
2014-02-10 02:10:30 +01:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
2024-04-08 16:51:34 +02:00
const Vector2 * r = arr . ptr ( ) ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < len ; i + + ) {
f - > store_real ( r [ i ] . x ) ;
f - > store_real ( r [ i ] . y ) ;
}
} break ;
2024-04-08 16:51:34 +02:00
case Variant : : PACKED_VECTOR3_ARRAY : {
f - > store_32 ( VARIANT_PACKED_VECTOR3_ARRAY ) ;
Vector < Vector3 > arr = p_property ;
2014-02-10 02:10:30 +01:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
2024-04-08 16:51:34 +02:00
const Vector3 * r = arr . ptr ( ) ;
2014-02-10 02:10:30 +01:00
for ( int i = 0 ; i < len ; i + + ) {
f - > store_real ( r [ i ] . x ) ;
f - > store_real ( r [ i ] . y ) ;
2024-04-08 16:51:34 +02:00
f - > store_real ( r [ i ] . z ) ;
2014-02-10 02:10:30 +01:00
}
} break ;
2024-04-08 16:51:34 +02:00
2020-02-17 22:06:54 +01:00
case Variant : : PACKED_COLOR_ARRAY : {
2021-12-24 18:44:08 +01:00
f - > store_32 ( VARIANT_PACKED_COLOR_ARRAY ) ;
2020-02-17 22:06:54 +01:00
Vector < Color > arr = p_property ;
2014-02-10 02:10:30 +01:00
int len = arr . size ( ) ;
f - > store_32 ( len ) ;
2020-02-17 22:06:54 +01:00
const Color * r = arr . ptr ( ) ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
}
2024-04-08 16:51:34 +02: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-10 02:10:30 +01:00
} break ;
default : {
2019-08-15 04:57:49 +02:00
ERR_FAIL_MSG ( " Invalid variant. " ) ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01: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-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2021-07-10 21:17:41 +02:00
if ( ! p_main & & ( ! bundle_resources ) & & ! res - > is_built_in ( ) ) {
2019-02-24 14:45:08 +01: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 14:45:08 +01:00
return ;
}
2015-08-24 01:15:56 +02:00
int idx = external_resources . size ( ) ;
external_resources [ res ] = idx ;
2014-02-10 02:10:30 +01:00
return ;
}
2020-05-14 16:41:43 +02:00
if ( resource_set . has ( res ) ) {
2014-02-10 02:10:30 +01:00
return ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
2023-02-17 11:18:58 +01:00
resource_set . insert ( res ) ;
2014-02-10 02:10:30 +01: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-16 05:45:57 +02: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-22 00:49:42 +01: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-22 00:49:42 +01:00
}
} else {
_find_resources ( value ) ;
}
2014-02-10 02:10:30 +01:00
}
}
saved_resources . push_back ( res ) ;
} break ;
case Variant : : ARRAY : {
Array varray = p_variant ;
2023-11-17 18:27:42 +01:00
_find_resources ( varray . get_typed_script ( ) ) ;
2023-12-24 13:44:21 +01:00
for ( const Variant & v : varray ) {
2014-02-10 02:10:30 +01:00
_find_resources ( v ) ;
}
} break ;
case Variant : : DICTIONARY : {
Dictionary d = p_variant ;
List < Variant > keys ;
d . get_key_list ( & keys ) ;
2021-07-24 15:46:25 +02:00
for ( const Variant & E : keys ) {
2021-07-16 05:45:57 +02:00
_find_resources ( E ) ;
Variant v = d [ E ] ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01: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-10 02:10:30 +01:00
get_string_index ( np . get_subname ( i ) ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
} break ;
2019-04-09 17:08:36 +02:00
default : {
}
2014-02-10 02:10:30 +01:00
}
}
2022-03-23 10:08:58 +01:00
void ResourceFormatSaverBinaryInstance : : save_unicode_string ( Ref < FileAccess > p_f , const String & p_string , bool p_bit_on_len ) {
2014-02-10 02:10:30 +01:00
CharString utf8 = p_string . utf8 ( ) ;
2017-12-15 12:38:24 +01:00
if ( p_bit_on_len ) {
2022-03-23 10:08:58 +01:00
p_f - > store_32 ( ( utf8 . length ( ) + 1 ) | 0x80000000 ) ;
2017-12-15 12:38:24 +01:00
} else {
2022-03-23 10:08:58 +01:00
p_f - > store_32 ( utf8 . length ( ) + 1 ) ;
2017-12-15 12:38:24 +01:00
}
2022-03-23 10:08:58 +01:00
p_f - > store_buffer ( ( const uint8_t * ) utf8 . get_data ( ) , utf8 . length ( ) + 1 ) ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
return string_map [ s ] ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01: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 ) {
2014-02-10 02:10:30 +01:00
Error err ;
2022-03-23 10:08:58 +01:00
Ref < FileAccess > f ;
2014-02-10 02:10:30 +01:00
if ( p_flags & ResourceSaver : : FLAG_COMPRESS ) {
2022-03-23 10:08:58 +01:00
Ref < FileAccessCompressed > fac ;
fac . instantiate ( ) ;
2014-02-10 02:10:30 +01:00
fac - > configure ( " RSCC " ) ;
f = fac ;
2022-09-05 13:01:31 +02:00
err = fac - > open_internal ( p_path , FileAccess : : WRITE ) ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01: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-28 04:21:45 +02:00
takeover_paths = p_flags & ResourceSaver : : FLAG_REPLACE_SUBRESOURCE_PATHS ;
2014-03-14 02:57:24 +01:00
2020-05-14 16:41:43 +02:00
if ( ! p_path . begins_with ( " res:// " ) ) {
2014-06-28 04:21:45 +02:00
takeover_paths = false ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
local_path = p_path . get_base_dir ( ) ;
2019-02-24 14:45:08 +01:00
path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
f - > store_32 ( 0 ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01: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 04:54:10 +01: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 01:55:13 +01: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 01:55:13 +01:00
f - > store_32 ( format_flags ) ;
}
2021-07-23 21:01:18 +02: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-30 07:24:29 +02:00
for ( int i = 0 ; i < ResourceFormatSaverBinaryInstance : : RESERVED_FIELDS ; i + + ) {
2014-02-10 02:10:30 +01:00
f - > store_32 ( 0 ) ; // reserved
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01: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-10 02:10:30 +01:00
{
2022-05-03 01:43:50 +02:00
for ( const Ref < Resource > & E : saved_resources ) {
2014-02-10 02:10:30 +01:00
ResourceData & rd = resources . push_back ( ResourceData ( ) ) - > get ( ) ;
2022-04-28 22:49:10 +02:00
rd . type = _resource_get_class ( E ) ;
2014-02-10 02:10:30 +01:00
List < PropertyInfo > property_list ;
2021-07-16 05:45:57 +02:00
E - > get_property_list ( & property_list ) ;
2014-02-10 02:10:30 +01:00
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & F : property_list ) {
2021-07-16 05:45:57 +02:00
if ( skip_editor & & F . name . begins_with ( " __editor " ) ) {
2014-02-10 02:10:30 +01: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-16 05:45:57 +02:00
if ( ( F . usage & PROPERTY_USAGE_STORAGE ) ) {
2014-02-10 02:10:30 +01:00
Property p ;
2021-07-16 05:45:57 +02:00
p . name_idx = get_string_index ( F . name ) ;
2019-02-22 00:49:42 +01:00
2021-07-16 05:45:57 +02:00
if ( F . usage & PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT ) {
2019-02-22 00:49:42 +01:00
NonPersistentKey npk ;
2021-07-16 05:45:57 +02:00
npk . base = E ;
npk . property = F . name ;
2019-02-22 00:49:42 +01:00
if ( non_persistent_map . has ( npk ) ) {
p . value = non_persistent_map [ npk ] ;
}
} else {
2021-07-16 05:45:57 +02:00
p . value = E - > get ( F . name ) ;
2019-02-22 00:49:42 +01:00
}
2018-11-08 15:30:02 +01: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-16 05:45:57 +02:00
Variant default_value = ClassDB : : class_get_default_property_value ( E - > get_class ( ) , F . name ) ;
2018-11-08 15:30:02 +01:00
if ( default_value . get_type ( ) ! = Variant : : NIL & & bool ( Variant : : evaluate ( Variant : : OP_EQUAL , p . value , default_value ) ) ) {
2014-02-10 02:10:30 +01:00
continue ;
2018-11-08 15:30:02 +01:00
}
2021-07-16 05:45:57 +02:00
p . pi = F ;
2014-02-10 02:10:30 +01: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 12:38:24 +01:00
save_unicode_string ( f , strings [ i ] ) ;
2014-02-10 02:10:30 +01: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-24 01:15:56 +02:00
save_order . resize ( external_resources . size ( ) ) ;
2022-05-03 01:43:50 +02:00
for ( const KeyValue < Ref < Resource > , int > & E : external_resources ) {
2021-08-09 22:13:42 +02:00
save_order . write [ E . value ] = E . key ;
2015-08-24 01:15:56 +02:00
}
2014-02-10 02:10:30 +01:00
2015-08-24 01:15:56 +02:00
for ( int i = 0 ; i < save_order . size ( ) ; i + + ) {
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , save_order [ i ] - > get_save_class ( ) ) ;
2022-09-29 11:53:28 +02: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 21:01:18 +02:00
ResourceUID : : ID ruid = ResourceSaver : : get_resource_id_for_path ( save_order [ i ] - > get_path ( ) , false ) ;
f - > store_64 ( ruid ) ;
2014-02-10 02:10:30 +01: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 05:03:19 +02: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 10:42:46 +01:00
if ( ! r - > get_scene_unique_id ( ) . is_empty ( ) ) {
2021-07-21 02:36:56 +02:00
if ( used_unique_ids . has ( r - > get_scene_unique_id ( ) ) ) {
r - > set_scene_unique_id ( " " ) ;
2015-06-22 05:03:19 +02:00
} else {
2021-07-21 02:36:56 +02:00
used_unique_ids . insert ( r - > get_scene_unique_id ( ) ) ;
2015-06-22 05:03:19 +02:00
}
}
}
}
2022-05-13 15:04:37 +02:00
HashMap < Ref < Resource > , int > resource_map ;
2021-07-21 02:36:56 +02: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 10:42:46 +01:00
if ( r - > get_scene_unique_id ( ) . is_empty ( ) ) {
2021-07-21 02:36:56 +02: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-21 02:36:56 +02:00
if ( ! used_unique_ids . has ( new_id ) ) {
break ;
}
2015-06-22 05:03:19 +02:00
}
2021-07-21 02:36:56 +02:00
r - > set_scene_unique_id ( new_id ) ;
used_unique_ids . insert ( new_id ) ;
2015-06-22 05:03:19 +02:00
}
2021-07-21 02:36:56 +02:00
save_unicode_string ( f , " local:// " + r - > get_scene_unique_id ( ) ) ;
2014-06-28 04:21:45 +02:00
if ( takeover_paths ) {
2021-07-21 02:36:56 +02:00
r - > set_path ( p_path + " :: " + r - > get_scene_unique_id ( ) , true ) ;
2014-06-28 04:21:45 +02:00
}
2016-08-31 22:58:51 +02:00
# ifdef TOOLS_ENABLED
r - > set_edited ( false ) ;
# endif
2015-10-22 04:57:43 +02:00
} else {
2017-12-15 12:38:24 +01:00
save_unicode_string ( f , r - > get_path ( ) ) ; //actual external
2015-10-22 04:57:43 +02:00
}
2017-09-10 15:37:49 +02:00
ofs_pos . push_back ( f - > get_position ( ) ) ;
2014-02-10 02:10:30 +01:00
f - > store_64 ( 0 ) ; //offset in 64 bits
2021-07-21 02:36:56 +02:00
resource_map [ r ] = res_index + + ;
2014-02-10 02:10:30 +01: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 12:38:24 +01:00
save_unicode_string ( f , rd . type ) ;
2014-02-10 02:10:30 +01:00
f - > store_32 ( rd . properties . size ( ) ) ;
2021-07-24 15:46:25 +02:00
for ( const Property & p : rd . properties ) {
2014-02-10 02:10:30 +01: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-10 02:10:30 +01: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 04:54:10 +01:00
if ( f - > get_error ( ) ! = OK & & f - > get_error ( ) ! = ERR_FILE_EOF ) {
return ERR_CANT_CREATE ;
}
2014-02-10 02:10:30 +01: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 22:00:46 +02:00
String local_path = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path ) ;
2014-02-10 02:10:30 +01: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-10 02:10:30 +01: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-10 02:10:30 +01: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 12:29:46 +01:00
p_extensions - > push_back ( " res " ) ;
2020-05-14 16:41:43 +02:00
}
2014-02-10 02:10:30 +01:00
}
2020-04-02 01:20:12 +02:00
ResourceFormatSaverBinary * ResourceFormatSaverBinary : : singleton = nullptr ;
2015-08-24 01:15:56 +02:00
ResourceFormatSaverBinary : : ResourceFormatSaverBinary ( ) {
singleton = this ;
}