[Solved] PackedByteArray not saving in PackedScene

Godot Version

Godot 4.4

Question

I’ve built a level editor that can export packed scenes so I can more easily build levels for my game - and so far everything seems to work properly. My editor generates a level mesh, a skybox, static objects, and spawners - which all save properly.

However, I’m also saving a 256x256 grid alongside my level (making a hex grid strategy game)
I’m giving each cell 16 bits of data - or 2 bytes - leading to me having a 256x256x2 PackedByteArray (131072 elements)

When saving my level into a PackedScene, the PackedByteArray doesn’t get saved with it - and it seems to be the only thing not getting saved.

Is there some behavior in Godot preventing it from saving large pieces of data? Or why would this happen / how could I circumvent it?

EDIT:
Forcing the PackedByteArray to be a much smaller size (I tried 5 elements) didn’t fix the issue.
So I guess it’s just that PackedByteArrays don’t save into PackedScenes?

EDIT 2:
Converting the PackedByteArray into a non-packed array of integers seems to save properly - but that feels like an unnecessary conversion for saving and loading a level

If you really want to know why, your best bet might be to see if there are any bugs or feature requests on the GitHub project that talk about this.

This code works just fine:

my_node.gd

extends Node

@export_storage var data:PackedByteArray
extends Node


func _ready() -> void:
	var n = preload("res://my_node.gd").new()
	for x in 256:
		for y in 256:
			n.data.append(randi() % 256)
			n.data.append(randi() % 256)

	prints("Written", n.data.size())

	var ps = PackedScene.new()
	ps.pack(n)
	ResourceSaver.save(ps, "user://scene.tscn")

	var scn = ResourceLoader.load("user://scene.tscn").instantiate()
	prints("Loaded", scn.data.size())

Prints:

Written 131072
Loaded 131072

The saved data:

How are you saving that scene? How are you exporting the PackedByteArray?

1 Like

Ah - good to know about @export_storage, I had just been using @export

Here’s what I use for saving my scene:

func _on_export_pressed() -> void:
	MapGen.PrepareForExport()
	var toSave = PackedScene.new()
	if toSave.pack(PreviewGrid) == OK:
		var path = ExportPath + FileName + "/"
		DirAccess.make_dir_recursive_absolute(path)
		ResourceSaver.save(toSave, path + FileName + ".tscn")

And notably, here’s the implementation of PrepareForExport():

func PrepareForExport():
	for i in GridPreview.multimesh.instance_count:
		var data: Color = Color(CoreTypes.CELL_COLOR.EMPTY,0.0,0.0,0.0)
		GridPreview.multimesh.set_instance_custom_data(i, data)
	GridPreview.Lightmap = load("res://Scenes/Grid/Skybox/level_lightmap.tscn").instantiate()
	GridPreview.add_child(GridPreview.Lightmap)
	GridPreview.Lightmap.owner = GridPreview

This wasn’t saving GridPreview.Grid - so I updated it to this (which works but is ugly):

func PrepareForExport():
	for i in GridPreview.multimesh.instance_count:
		var data: Color = Color(CoreTypes.CELL_COLOR.EMPTY,0.0,0.0,0.0)
		GridPreview.multimesh.set_instance_custom_data(i, data)
	GridPreview.Lightmap = load("res://Scenes/Grid/Skybox/level_lightmap.tscn").instantiate()
	GridPreview.add_child(GridPreview.Lightmap)
	GridPreview.Lightmap.owner = GridPreview
	GridPreview.SaveGrid.clear()
	var intArray = GridPreview.Grid.to_int64_array()
	for i in intArray:
		GridPreview.SaveGrid.push_back(i)

And the variables in question are currently setup like so:

var Grid: PackedByteArray = []
@export_storage var SaveGrid: Array[int] = []

I’ve tried adding @export or @export_storage to Grid, but no matter what I do it won’t save but SaveGrid will

Oh!
The issue was setting the PackedByteArray to an empty array in its declaration

Changing

@export_storage var Grid: PackedByteArray = []

into

@export_storage var Grid: PackedByteArray

Fixes the issue

Odd - but glad to have it working

1 Like