diff --git a/scripts/loaders/save_loader.gd b/scripts/loaders/save_loader.gd index 95d6849..bc25e7e 100644 --- a/scripts/loaders/save_loader.gd +++ b/scripts/loaders/save_loader.gd @@ -47,7 +47,27 @@ func get_struct(buffer: StreamPeer, struct_name: String) -> Dictionary: return {} return struct_types[struct_name].get_value(buffer, [0, 0]) -func get_save_slot(sram: File, slot_id: int): +func put_struct(buffer: StreamPeer, struct_name: String, data: Dictionary): + if not (struct_name in struct_types): + print_debug('Attempted to put undeclared struct: "%s"' % struct_name) + return + struct_types[struct_name].put_value(buffer, data, [0, 0]) + +func deserialize_save_slot(bytes: PoolByteArray) -> Dictionary: + var buffer = StreamPeerBuffer.new() + buffer.data_array = bytes + return struct_types['Save_slot'].get_value(buffer, [0, 0]) + +func serialize_save_slot(data: Dictionary) -> PoolByteArray: + var buffer = StreamPeerBuffer.new() + struct_types['Save_slot'].put_value(buffer, data, [0, 0]) + var padding := PoolByteArray() + padding.resize(0x100) + padding.fill(0) + buffer.put_data(padding) + return buffer.data_array + +func get_save_slot(sram: File, slot_id: int) -> StreamPeerBuffer: var buffer := StreamPeerBuffer.new() sram.seek(0x700 * slot_id) buffer.set_data_array(sram.get_buffer(0x700)) diff --git a/scripts/struct.gd b/scripts/struct.gd index 3e84f60..e1a67d9 100644 --- a/scripts/struct.gd +++ b/scripts/struct.gd @@ -78,7 +78,7 @@ class UBits extends StructType: return value func put_value(buffer: StreamPeer, value, leftover_bits: Array): - leftover_bits[1] |= value << bits + leftover_bits[1] |= value << leftover_bits[0] leftover_bits[0] += bits while leftover_bits[0] >= 8: buffer.put_8(leftover_bits[1] & 0xFF) diff --git a/test/unit_tests.gd b/test/unit_tests.gd index a47615f..579398e 100644 --- a/test/unit_tests.gd +++ b/test/unit_tests.gd @@ -2,6 +2,15 @@ extends Control var dir_user := Directory.new() const P_TESTDATA := 'user://test_data/' +# Shared state between tests +var save_slot_buffers = [] +var save_slot_dicts = [] + +func test(label, input): + if input: + print('SUCCESS: ' + label) + else: + print('FAILURE: ' + label) func load_snes_savefile(filename: String = 'res://test.srm'): var save_file := File.new() @@ -11,17 +20,14 @@ func load_snes_savefile(filename: String = 'res://test.srm'): var error: print_debug('Failed to open test.srm for reading: %d' % error) return - var save_slots = [] - var save_slot_dicts = [] for i in 4: - save_slots.append(SaveLoader.get_save_slot(save_file, i)) - save_slot_dicts.append(SaveLoader.get_struct(save_slots[i], 'Save_slot')) + self.save_slot_buffers.append(SaveLoader.get_save_slot(save_file, i)) + self.save_slot_dicts.append(SaveLoader.deserialize_save_slot(self.save_slot_buffers[i].data_array)) print('Loaded test save file') - return save_slot_dicts func generate_known_good_results(): - var save_slot_dicts = load_snes_savefile() - if not save_slot_dicts: + load_snes_savefile() + if not self.save_slot_dicts: return match dir_user.make_dir_recursive(P_TESTDATA): OK: @@ -30,7 +36,7 @@ func generate_known_good_results(): print_debug('Failed to create "%s" with error code %d' % [P_TESTDATA, error]) return var filename := P_TESTDATA + 'test.srm.json' - match Common.save_json(filename, save_slot_dicts): + match Common.save_json(filename, self.save_slot_dicts): OK: pass var error: @@ -38,8 +44,8 @@ func generate_known_good_results(): return func test_save_loading() -> bool: - var save_slot_dicts = load_snes_savefile() - if not save_slot_dicts: + load_snes_savefile() + if not self.save_slot_dicts: print_debug('Failed to load test savefile') return false var filename := P_TESTDATA + 'test.srm.json' @@ -47,7 +53,7 @@ func test_save_loading() -> bool: match typeof(known_good): TYPE_ARRAY: print_debug('Comparing known savefile results') - return Common.are_arrays_equal(save_slot_dicts, known_good) + return Common.are_arrays_equal(self.save_slot_dicts, known_good) TYPE_DICTIONARY: print_debug('Known savefile results "%s" is a dict instead of an array. Did we change formats?' % filename) return false @@ -55,6 +61,24 @@ func test_save_loading() -> bool: print_debug('Failed to load known savefile results "%s"' % filename) return false +func test_save_serialization() -> bool: + if not self.save_slot_dicts: + print_debug('test savefile not loaded') + return false + for i in 4: + var bytes = SaveLoader.serialize_save_slot(self.save_slot_dicts[i]) + if bytes != self.save_slot_buffers[i].data_array: + print_debug('Slot %d failed to serialize correctly, rescanning' % i) + for j in 0x700: + var b1: int = bytes[j] + var b2: int = self.save_slot_buffers[i].data_array[j] + if b1 != b2: + print_debug('Mismatch occurs at byte %d: %d vs %d' % [j, b1, b2]) + return false + return true + + + # Called when the node enters the scene tree for the first time. func _ready() -> void: @@ -64,5 +88,6 @@ func _ready() -> void: var error: print_debug('Failed to open user directory') # generate_known_good_results() # Uncomment this to get your sample on first run - print(test_save_loading()) + test('SNES save file loaded to array of dictionaries', test_save_loading()) + test('SNES save file slots serialized from dictionaries', test_save_serialization()) get_tree().quit()