Created
March 12, 2026 16:20
-
-
Save increpare/becac8047bbf4354d2b0527fc7c7b9a0 to your computer and use it in GitHub Desktop.
OeufSerializer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| String OeufSerializer::serialize_to_string(const Array &p_savedat) const { | |
| if (p_savedat.size() != 5) { | |
| ERR_PRINT(vformat("serialize_to_string: Invalid savedat array size (expected 5, got %d)", p_savedat.size())); | |
| return ""; | |
| } | |
| Dictionary level_state_data = p_savedat[0]; | |
| Array voxel_data = level_state_data["voxel_data"]; | |
| Array layers = level_state_data["layers"]; | |
| // entities - support both legacy (array) and versioned (dict with "version" + "entities") | |
| Variant entities_slot = p_savedat[4]; | |
| int entities_version = 0; | |
| Array entities; | |
| if (entities_slot.get_type() == Variant::DICTIONARY) { | |
| Dictionary d = entities_slot; | |
| entities_version = d["version"]; | |
| entities = d["entities"]; | |
| } else { | |
| entities = entities_slot; | |
| } | |
| TextWriter writer; | |
| int voxel_count = voxel_data.size(); | |
| int entities_count = entities.size(); | |
| int layers_count = layers.size(); | |
| // Rough estimate: ~40 bytes per voxel, ~100 per entity, plus overhead | |
| size_t estimated_size = 1024 + (voxel_count * 40) + (entities_count * 100); | |
| writer.reserve(estimated_size); | |
| // version | |
| writer.put_tag("version"); | |
| writer.put_int(level_state_data["version"]); | |
| writer.end_line(); | |
| // voxel_data | |
| writer.put_tag("voxels"); | |
| writer.put_int(voxel_count); | |
| writer.end_line(); | |
| Vector3i last_position = Vector3i(0, 0, 0); | |
| for (int i = 0; i < voxel_count; i++) { | |
| Array voxel = voxel_data[i]; | |
| Vector3i v = voxel[0]; | |
| Vector3i delta = v - last_position; | |
| writer.put_tag("vx"); | |
| if (delta.x >= -128 && delta.x <= 127 && delta.y >= -128 && delta.y <= 127 && delta.z >= -128 && delta.z <= 127) { | |
| writer.put_int(0); // type delta | |
| writer.put_int(delta.x); | |
| writer.put_int(delta.y); | |
| writer.put_int(delta.z); | |
| } else { | |
| writer.put_int(1); // type absolute | |
| writer.put_int(v.x); | |
| writer.put_int(v.y); | |
| writer.put_int(v.z); | |
| } | |
| last_position = v; | |
| writer.put_int(voxel[1]); // blocktype | |
| writer.put_int(voxel[2]); // tx | |
| writer.put_int(voxel[3]); // ty | |
| int rot = voxel[4]; | |
| int vflip = (bool)voxel[5] ? 1 : 0; | |
| writer.put_int(rot + vflip * 4); | |
| writer.put_int(voxel[6]); // extra | |
| writer.end_line(); | |
| } | |
| // layers | |
| writer.put_tag("layers"); | |
| writer.put_int(layers_count); | |
| writer.end_line(); | |
| for (int i = 0; i < layers_count; i++) { | |
| Dictionary layer = layers[i]; | |
| writer.put_tag("l"); | |
| writer.put_string(layer["name"]); | |
| writer.put_int((bool)layer["visible"] ? 1 : 0); | |
| writer.end_line(); | |
| } | |
| // selected_layer_idx | |
| writer.put_tag("selected"); | |
| writer.put_int(level_state_data["selected_layer_idx"]); | |
| writer.end_line(); | |
| // camera | |
| writer.put_tag("cp"); | |
| writer.put_vector3(p_savedat[1]); | |
| writer.end_line(); | |
| writer.put_tag("cbr"); | |
| writer.put_vector3(p_savedat[2]); | |
| writer.end_line(); | |
| writer.put_tag("crr"); | |
| writer.put_vector3(p_savedat[3]); | |
| writer.end_line(); | |
| // entities (version, then count) | |
| writer.put_tag("entities_version"); | |
| writer.put_int(entities_version); | |
| writer.end_line(); | |
| writer.put_tag("entities"); | |
| writer.put_int(entities_count); | |
| writer.end_line(); | |
| for (int i = 0; i < entities_count; i++) { | |
| Dictionary entity = entities[i]; | |
| writer.put_tag("e"); | |
| writer.put_string(entity["name"]); | |
| int32_t entity_type = entity["type"]; | |
| writer.put_int(entity_type); | |
| writer.put_vector3i(entity["position"]); | |
| writer.put_int(entity["layer"]); | |
| uint8_t flags = 0; | |
| String meta_str; | |
| String asset_name_str; | |
| int32_t dir_value = 0; | |
| if (entity.has("dir")) { | |
| dir_value = entity["dir"]; | |
| flags |= 0x01; | |
| } | |
| if (entity.has("meta")) { | |
| meta_str = entity["meta"]; | |
| if (!meta_str.is_empty()) flags |= 0x02; | |
| } | |
| if (entity.has("asset_name")) { | |
| asset_name_str = entity["asset_name"]; | |
| if (!asset_name_str.is_empty()) flags |= 0x04; | |
| } | |
| writer.put_int(flags); | |
| if (flags & 0x01) writer.put_int(dir_value + 1); | |
| if (flags & 0x02) writer.put_string(meta_str); | |
| if (flags & 0x04) writer.put_string(asset_name_str); | |
| if (entity_type == 3) { | |
| Vector3i size_EDS = entity.has("size_EDS") ? (Vector3i)entity["size_EDS"] : Vector3i(); | |
| writer.put_vector3i(size_EDS); | |
| Vector3i size_WUN = entity.has("size_WUN") ? (Vector3i)entity["size_WUN"] : Vector3i(); | |
| writer.put_vector3i(size_WUN); | |
| } | |
| writer.end_line(); | |
| } | |
| return writer.get_string(); | |
| } | |
| Array OeufSerializer::deserialize_from_string(const godot::String &p_string) const { | |
| TextReaderTokenized reader(p_string); | |
| Array savedat; | |
| Dictionary level_state_data; | |
| TypedArray<Array> voxel_data; | |
| Array layers; | |
| TypedArray<Dictionary> entities; | |
| int entities_version = 0; | |
| Vector3 camera_pos; | |
| Vector3 camera_base_rotation; | |
| Vector3 camera_rot_rotation; | |
| Vector3i last_position = Vector3i(0, 0, 0); | |
| while (reader.has_more_lines()) { | |
| TextReaderTokenized::LineTokenizer t = reader.next_line(); | |
| String tag = t.next_token(); | |
| if (tag == "") continue; | |
| if (tag == "version") { | |
| level_state_data[StringName("version")] = t.next_int(); | |
| } else if (tag == "entities_version") { | |
| entities_version = t.next_int(); | |
| } else if (tag == "entities") { | |
| t.next_int(); // consume count (entities are parsed from "e" tags) | |
| } else if (tag == "vx") { | |
| Array voxel; | |
| int type = t.next_int(); | |
| if (type == 0) { | |
| last_position += t.next_vector3i(); | |
| } else { | |
| last_position = t.next_vector3i(); | |
| } | |
| voxel.append(last_position); | |
| voxel.append(t.next_int()); // blocktype | |
| voxel.append(t.next_int()); // tx | |
| voxel.append(t.next_int()); // ty | |
| int rot_vflip = t.next_int(); | |
| voxel.append(rot_vflip & 3); | |
| voxel.append((rot_vflip & 4) != 0); | |
| voxel.append(t.next_int()); // extra | |
| voxel_data.append(voxel); | |
| } else if (tag == "l") { | |
| Dictionary layer; | |
| layer[StringName("name")] = t.next_token(); | |
| layer[StringName("visible")] = t.next_int() != 0; | |
| layers.append(layer); | |
| } else if (tag == "selected") { | |
| level_state_data[StringName("selected_layer_idx")] = t.next_int(); | |
| } else if (tag == "cp") { | |
| camera_pos = t.next_vector3(); | |
| } else if (tag == "cbr") { | |
| camera_base_rotation = t.next_vector3(); | |
| } else if (tag == "crr") { | |
| camera_rot_rotation = t.next_vector3(); | |
| } else if (tag == "e") { | |
| Dictionary entity; | |
| entity[StringName("name")] = t.next_token(); | |
| int type = t.next_int(); | |
| entity[StringName("type")] = type; | |
| entity[StringName("position")] = t.next_vector3i(); | |
| if (entities_version >= 3){ | |
| //entities have a layer | |
| entity[StringName("layer")] = t.next_int(); | |
| } else { | |
| entity[StringName("layer")] = 0; | |
| } | |
| int flags = t.next_int(); | |
| if (flags & 0x01) entity[StringName("dir")] = t.next_int() - 1; | |
| if (flags & 0x02) entity[StringName("meta")] = t.next_token(); | |
| if (flags & 0x04) entity[StringName("asset_name")] = t.next_token(); | |
| if (type == 3) { | |
| entity[StringName("size_EDS")] = t.next_vector3i(); | |
| entity[StringName("size_WUN")] = t.next_vector3i(); | |
| } | |
| entities.append(entity); | |
| } | |
| } | |
| level_state_data[StringName("voxel_data")] = voxel_data; | |
| level_state_data[StringName("layers")] = layers; | |
| Dictionary entities_dict; | |
| entities_dict[StringName("version")] = entities_version; | |
| entities_dict[StringName("entities")] = entities; | |
| savedat.append(level_state_data); | |
| savedat.append(camera_pos); | |
| savedat.append(camera_base_rotation); | |
| savedat.append(camera_rot_rotation); | |
| savedat.append(entities_dict); | |
| return savedat; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment