Формат .rscene и .rprefab
Полный уровень с двумя экземплярами префаба, внешним стилем и сохранённым сигналом; структура файла и UID.
Запустить полный пример
В C#-проекте Reckfell 1.0.0 создайте файлы по указанным путям от asset://. Добавьте FormatGallery2D.cs в корень проекта. Прикрепите его к Entity2D отдельного уровня, задайте базовый viewport 640×420, соберите C# и нажмите F6. Появятся два синих объекта. Правый крупнее; кнопка × удаляет только свой экземпляр.
Assets/BadgeStyle.rdata
[reckfell_resource type="StyleBoxFlat" format=3]
[resource]
bg_color = Color(0.18, 0.36, 0.95, 1)
corner_radius_top_left = 12
corner_radius_top_right = 12
corner_radius_bottom_left = 12
corner_radius_bottom_right = 12Actors/Badge.rprefab
; This comment is not retained by ResourceSaver.
[reckfell_tree format=3]
[ext_resource type="StyleBox" path="asset://Assets/BadgeStyle.rdata" id="Style"]
[entity name="Badge" type="Entity2D" groups=["format_badges"]]
[entity name="Panel" type="Panel" parent="."]
offset_right = 112.0
offset_bottom = 64.0
mouse_filter = 2
theme_override_styles/panel = ExtResource("Style")
[entity name="Mount" type="Entity2D" parent="."]
[entity name="Pivot" type="Marker2D" parent="."]
unique_name_in_owner = true
position = Vector2(56, 32)
[entity name="Remove" type="Button" parent="."]
offset_left = 76.0
offset_top = 12.0
offset_right = 102.0
offset_bottom = 52.0
text = "×"
[connection signal="pressed" from="Remove" to="." method="queue_free"]Levels/FormatShowcase.rscene
[reckfell_tree format=3]
[ext_resource type="PackedEntity" path="asset://Actors/Badge.rprefab" id="Badge"]
[entity name="FormatShowcase" type="Entity2D"]
[entity name="Left" parent="." instance=ExtResource("Badge")]
position = Vector2(100, 190)
[entity name="Right" parent="." instance=ExtResource("Badge")]
position = Vector2(350, 190)
scale = Vector2(1.25, 1.25)FormatGallery2D.cs
using Reckfell;
public partial class FormatGallery2D : Entity2D
{
public Entity2D Gallery { get; private set; } = null!;
public override void _Ready()
{
var packed = ResourceLoader.Load<PackedEntity>("asset://Levels/FormatShowcase.rscene");
if (packed is null || !packed.CanInstantiate())
{
ReckfellApi.PrintErr("Cannot load FormatShowcase.rscene");
return;
}
Gallery = packed.Instantiate<Entity2D>();
AddChild(Gallery);
AddChild(new Label
{
Position = new Vector2(28, 24),
Text = TranslationServer.GetLocale().StartsWith("ru")
? "Уровень: два экземпляра одного префаба"
: "Level: two instances of one prefab"
});
foreach (string name in new[] { "Left", "Right" })
{
var instance = Gallery.GetEntity<Entity2D>(name);
var pivot = instance.GetEntity<Marker2D>("%Pivot");
instance.AddChild(new Label { Position = new Vector2(0, 84), Text = name + " · %Pivot " + pivot.Position });
}
}
}Прочитать дерево
Первый тег [reckfell_tree] задаёт дерево PackedEntity. Затем идут ext_resource, sub_resource при наличии, entity и connection. В .rdata первым идёт [reckfell_resource type="..."]; свойства главного ресурса размещаются под [resource].
| Запись | Значение |
|---|---|
| ext_resource | Ссылка на внешний ассет по path, type и локальному id |
| sub_resource | Ресурс, встроенный в этот файл; не отдельный ассет по соседнему пути |
| ExtResource("Badge") | Обращение к локальному id внешнего ресурса |
| SubResource("Shape") | Обращение к локальному id встроенного ресурса |
| entity с type | Создание Entity указанного класса |
| entity с instance | Создание экземпляра PackedEntity |
| parent="." | Непосредственный ребёнок корня этого файла |
| connection | Сохранённая связь signal → method по путям from/to |
id="Badge" — локальная метка ссылки, не глобальный UID. parent — путь в дереве Entity, не путь файловой системы. position и scale у Left/Right — переопределения экземпляра: они не переписывают Badge.rprefab. Один внешний StyleBox используется обоими экземплярами; изменение общего ресурса может затронуть оба.
В примере владелец обычных дочерних записей восстанавливается корнем префаба. В C# один AddChild не назначает Owner: правила программного сохранения разобраны отдельно. Нативный стенд проверяет реальные области владельцев и сохранённый сигнал, а не только успешный разбор текста.
UID и локальные идентификаторы
uid="uid://..." в заголовке обозначает идентичность файла. unique_id у entity помогает сериализатору отслеживать запись Entity; UniqueNameInOwner и путь %Pivot решают другую задачу — поиск объекта в области Owner. Эти значения не взаимозаменяемы и не являются сетевым ID.
UID не хранит содержимое файла и не находит любой перемещённый файл сам. Нужен реестр UID → путь. В runtime ResourceLoader.GetResourceUid читает реестр; проверенный исходник редакторного режима также умеет читать заголовки через загрузчики. ResourceUid.PathToUid может вернуть исходный путь, если UID неизвестен. В проверке нового процесса реестр для сгенерированного тестового ассета восстанавливается явно: это не доказательство автоматического обнаружения user://.
Сохранения игрока в user:// адресуйте по своей схеме и стабильным игровым ID. ResourceSaver.SetUid не заменяет регистрацию UID в runtime. Для user:// в проверенной сборке обнаружен случай, когда SetUid возвращает Ok, но оставляет временный .uidren без замены исходного файла; пример на этот метод не опирается.
Исправить ошибку загрузки
| Симптом | Что проверить |
|---|---|
| Неизвестный тип файла или ошибка разбора | Заголовок, расширение, кавычки, типы значений и строку в диагностике |
| Saved with newer format version | Не менять номер вручную; открыть исходник сборкой, поддерживающей его данные |
| Нет внешнего ресурса | path, локальный id и импорт нужного ассета |
| Не находится Entity | Имя и parent, а для %Name — Owner и UniqueNameInOwner |
| Пропал комментарий или значение по умолчанию | Нормализация сериализатором, а не доказательство потери игровой логики |
Комментарии с ; и необязательные пробелы не сохраняют своё оформление после записи. Старое поле load_steps не является числом Entity или версией движка; текущий сериализатор его не записывает. Не генерируйте unique_id/parent_id_path/owner_uid_path вручную для произвольных вложенных деревьев: дайте редактору сохранить связи.