Skip to content

Instantly share code, notes, and snippets.

@zvodd
Created February 5, 2026 01:16
Show Gist options
  • Select an option

  • Save zvodd/4774905f38e0b01c438ce316087153f3 to your computer and use it in GitHub Desktop.

Select an option

Save zvodd/4774905f38e0b01c438ce316087153f3 to your computer and use it in GitHub Desktop.
Godot 3 Resource file Save Editor UI
extends Panel
# Path updated: Now points through the ScrollContainer
onready var edit_area : VBoxContainer = $"HBoxContainer/ScrollContainer/EditArea"
onready var edlo = EditSaveResMarshal.new()
func _ready():
# Ensure the EditArea stretches to fill the width of the ScrollContainer
edit_area.size_flags_horizontal = SIZE_EXPAND_FILL
populate_editor(edlo.save_dict)
print(edlo.save_dict)
func populate_editor(data_dict):
# Clear existing rows
for child in edit_area.get_children():
child.queue_free()
for key in data_dict:
var value = data_dict[key]
var type_id = typeof(value)
# Create the row
var row = HBoxContainer.new()
row.size_flags_horizontal = SIZE_EXPAND_FILL
# Add a bit of spacing between rows
row.add_constant_override("separation", 10)
# 1. Add Label
var label = Label.new()
label.text = str(key).capitalize()
label.rect_min_size.x = 150 # Fixed width ensures inputs line up vertically
row.add_child(label)
# 2. Add Input based on type
var input_node = _create_input_for_type(type_id, value, key)
if input_node:
input_node.size_flags_horizontal = SIZE_EXPAND_FILL
row.add_child(input_node)
edit_area.add_child(row)
# Helper function to keep populate_editor clean
func _create_input_for_type(type_id, value, key):
match type_id:
TYPE_BOOL:
var input = CheckBox.new()
input.pressed = value
input.connect("toggled", self, "_on_value_changed", [key])
return input
TYPE_STRING:
var input = LineEdit.new()
input.text = str(value)
input.connect("text_changed", self, "_on_value_changed", [key])
return input
TYPE_INT, TYPE_REAL:
var input = SpinBox.new()
input.allow_greater = true
input.allow_lesser = true
input.value = float(value)
# Set step to 0.1 for floats, 1 for ints
input.step = 0.1 if type_id == TYPE_REAL else 1.0
input.connect("value_changed", self, "_on_value_changed", [key])
return input
return null
func _on_value_changed(new_value, key):
edlo.save_dict[key] = new_value
print("Data updated -> ", key, ": ", new_value)
func _on_Save_pressed():
edlo.saver()
func _on_LoadSave_pressed():
populate_editor(edlo.save_dict)
[gd_scene load_steps=4 format=2]
[ext_resource path="res://assets/nurom.tres" type="DynamicFont" id=1]
[ext_resource path="res://EditSave.gd" type="Script" id=2]
[sub_resource type="StyleBoxEmpty" id=1]
[node name="Control" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
rect_pivot_offset = Vector2( -41, 60 )
[node name="Panel" type="Panel" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource( 2 )
[node name="HBoxContainer" type="HBoxContainer" parent="Panel"]
anchor_right = 1.0
anchor_bottom = 1.0
[node name="VBoxContainer" type="VBoxContainer" parent="Panel/HBoxContainer"]
margin_right = 138.0
margin_bottom = 1080.0
[node name="LoadBtn" type="Button" parent="Panel/HBoxContainer/VBoxContainer"]
margin_right = 138.0
margin_bottom = 60.0
custom_colors/font_color_disabled = Color( 0.0745098, 0.0745098, 0.0745098, 1 )
custom_colors/font_color = Color( 0.745098, 0.745098, 0.745098, 1 )
custom_colors/font_color_hover = Color( 1, 1, 1, 1 )
custom_colors/font_color_pressed = Color( 0, 0, 0, 1 )
custom_fonts/font = ExtResource( 1 )
custom_styles/normal = SubResource( 1 )
text = "Load"
flat = true
[node name="SaveBtn" type="Button" parent="Panel/HBoxContainer/VBoxContainer"]
margin_top = 64.0
margin_right = 138.0
margin_bottom = 124.0
custom_colors/font_color_disabled = Color( 0.0745098, 0.0745098, 0.0745098, 1 )
custom_colors/font_color = Color( 0.745098, 0.745098, 0.745098, 1 )
custom_colors/font_color_hover = Color( 1, 1, 1, 1 )
custom_colors/font_color_pressed = Color( 0, 0, 0, 1 )
custom_fonts/font = ExtResource( 1 )
custom_styles/normal = SubResource( 1 )
text = "Save"
flat = true
[node name="ScrollContainer" type="ScrollContainer" parent="Panel/HBoxContainer"]
margin_left = 142.0
margin_right = 142.0
margin_bottom = 1080.0
scroll_horizontal_enabled = false
[node name="EditArea" type="VBoxContainer" parent="Panel/HBoxContainer/ScrollContainer"]
[connection signal="pressed" from="Panel/HBoxContainer/VBoxContainer/LoadBtn" to="Panel" method="_on_LoadSave_pressed"]
[connection signal="pressed" from="Panel/HBoxContainer/VBoxContainer/SaveBtn" to="Panel" method="_on_Save_pressed"]
class_name EditSaveResMarshal
extends Object
const savpath = "user://save.dat"
var save_dict = {}
var DEFAULT_DATA = {
"pogo2nd": "",
"spray2nd": "",
"coin2nd": "",
"hammer2nd": "",
"pogo": "",
"spray": "",
"coin": "",
"hammer": "",
"equippable": "",
"coinDist": "",
"paperPlane": "",
"noteBook": "",
"clock": "",
"alreadyDone": "",
"tutTime": "",
"firstBossTalk": "",
"firstHallTalk": "",
"secondHallTalk": "",
"secondBossTalk": "",
"firstRoomChat": "",
"secondRoomChat": "",
"thirdBossTalk": "",
"firstCorriTalk": "",
"secondCorriTalk": "",
"fourthBossTalk": "",
"objective": "",
"sodaCup": "",
"bench": "",
"switch": "",
"chair": "",
"skateboard": "",
"fan": ""
}
func _init():
# Start with defaults
save_dict = DEFAULT_DATA.duplicate()
self.loader()
func loader():
var file = File.new()
if file.file_exists(savpath):
var error = file.open(savpath, File.READ)
if error == OK:
var loaded_data = file.get_var()
file.close()
if loaded_data is Dictionary:
# 2. Automated Transfer
# We loop through our template to see what needs to be filled
for key in save_dict.keys():
if loaded_data.has(key):
save_dict[key] = loaded_data[key]
else:
print("No save file found, using defaults.")
func saver():
var file = File.new()
var error = file.open(savpath, File.WRITE)
if error == OK:
file.store_var(save_dict)
file.close()
print("Saved successfully.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment