diff --git a/Autoload/Columnset.gd b/Autoload/Columnset.gd index 67c80268..2749a647 100644 --- a/Autoload/Columnset.gd +++ b/Autoload/Columnset.gd @@ -1,5 +1,6 @@ extends 'res://Class/ClmClass.gd' onready var oGame = Nodelist.list["oGame"] +onready var oBuffers = Nodelist.list["oBuffers"] var utilized = [] var orientation = [] @@ -39,7 +40,7 @@ func load_default_columnset(): func load_default_original_columnset(): var filePath = oGame.get_precise_filepath(oGame.DK_DATA_DIRECTORY, "SLABS.CLM") - var buffer = Filetypes.file_path_to_buffer(filePath) + var buffer = oBuffers.file_path_to_buffer(filePath) buffer.seek(0) var numberOfClmEntries = buffer.get_u16() diff --git a/Autoload/Cube.gd b/Autoload/Cube.gd index 200946d7..aa5bf01f 100644 --- a/Autoload/Cube.gd +++ b/Autoload/Cube.gd @@ -71,7 +71,7 @@ func _notification(what: int): read_cubes_cfg() # Refresh the display of anything that handles cubes - oOverheadGraphics.update_map_overhead_2d_textures() + oOverheadGraphics.update_full_overhead_map() oPickSlabWindow.add_slabs() oColumnEditor._on_ColumnEditor_visibility_changed() oSlabsetWindow._on_SlabsetWindow_visibility_changed() diff --git a/Autoload/Slabset.gd b/Autoload/Slabset.gd index 11fa1ed9..ed556b37 100644 --- a/Autoload/Slabset.gd +++ b/Autoload/Slabset.gd @@ -1,6 +1,7 @@ extends Node onready var oGame = Nodelist.list["oGame"] onready var oMessage = Nodelist.list["oMessage"] +onready var oBuffers = Nodelist.list["oBuffers"] var tng = [] var dat = [] @@ -57,8 +58,8 @@ func load_default_slabset(): func load_default_original_slabset(): - var dat_buffer = Filetypes.file_path_to_buffer(oGame.get_precise_filepath(oGame.DK_DATA_DIRECTORY, "SLABS.DAT")) - var tng_buffer = Filetypes.file_path_to_buffer(oGame.get_precise_filepath(oGame.DK_DATA_DIRECTORY, "SLABS.TNG")) + var dat_buffer = oBuffers.file_path_to_buffer(oGame.get_precise_filepath(oGame.DK_DATA_DIRECTORY, "SLABS.DAT")) + var tng_buffer = oBuffers.file_path_to_buffer(oGame.get_precise_filepath(oGame.DK_DATA_DIRECTORY, "SLABS.TNG")) var object_info = create_object_list(tng_buffer) if object_info.size() == 0: diff --git a/Class/GridClass.gd b/Class/GridClass.gd new file mode 100644 index 00000000..8b525189 --- /dev/null +++ b/Class/GridClass.gd @@ -0,0 +1,49 @@ +extends Node +class_name Grid + +const U8 = 1 +const U16 = 2 + +var buffer = StreamPeerBuffer.new() +var bytes_per_entry = 1 +var width = 0 +var height = 0 +var buffer_size = 0 + +func initialize(w, h, fillValue, setPerEntryBytes): + width = w + height = h + bytes_per_entry = setPerEntryBytes + buffer_size = width * height * bytes_per_entry + + # Clearing a buffer is troublesome, in order to do so I need to set the buffer to an equal-sized blank PoolByteArray. (this takes 0ms) + var blankByteArray = PoolByteArray([]) + blankByteArray.resize(buffer_size) + blankByteArray.fill(fillValue) + buffer.data_array = blankByteArray + + +func set_cell(x, y, value): + var seek_pos = (y * width + x) * bytes_per_entry + if seek_pos >= 0 and seek_pos < buffer_size: + buffer.seek(seek_pos) + if bytes_per_entry == U8: + buffer.put_u8(value) + elif bytes_per_entry == U16: + buffer.put_u16(value) + +func get_cell(x, y): + var seek_pos = (y * width + x) * bytes_per_entry + if seek_pos >= 0 and seek_pos < buffer_size: + buffer.seek(seek_pos) + if bytes_per_entry == U8: + return buffer.get_u8() + elif bytes_per_entry == U16: + return buffer.get_u16() + return -1 + +func set_cellv(pos, value): + set_cell(pos.x, pos.y, value) + +func get_cellv(pos): + return get_cell(pos.x, pos.y) diff --git a/Scenes/3dSelector.gd b/Scenes/3dSelector.gd index 17c336e1..40ba68b2 100644 --- a/Scenes/3dSelector.gd +++ b/Scenes/3dSelector.gd @@ -59,7 +59,7 @@ extends Spatial # var clmIndex # var newSize # if oGenerateTerrain.GENERATED_TYPE == oGenerateTerrain.GEN_MAP: -# clmIndex = oDataClmPos.get_cell(translation.x,translation.z) +# clmIndex = oDataClmPos.get_cell_clmpos(translation.x,translation.z) # elif oGenerateTerrain.GENERATED_TYPE == oGenerateTerrain.GEN_CLM: # clmIndex = oGenerateTerrain.get_clm_index(translation.x,translation.z) # diff --git a/Scenes/AddCustomSlabWindow.gd b/Scenes/AddCustomSlabWindow.gd index 963f2dc3..3163cbda 100644 --- a/Scenes/AddCustomSlabWindow.gd +++ b/Scenes/AddCustomSlabWindow.gd @@ -154,7 +154,7 @@ func copy_values_from_slabset_and_index_them(): func get_column_indexes_on_tile(cursorTile): for ySubtile in 3: for xSubtile in 3: - var newIndex = oDataClmPos.get_cell((cursorTile.x*3)+xSubtile, (cursorTile.y*3)+ySubtile) + var newIndex = oDataClmPos.get_cell_clmpos((cursorTile.x*3)+xSubtile, (cursorTile.y*3)+ySubtile) var i = (ySubtile*3) + xSubtile customSlabArrayOfSpinbox[i].value = newIndex diff --git a/Scenes/BrushPlacingPreview.gd b/Scenes/BrushPlacingPreview.gd index 51120a44..0a073af3 100644 --- a/Scenes/BrushPlacingPreview.gd +++ b/Scenes/BrushPlacingPreview.gd @@ -78,7 +78,7 @@ func make_brush_shape(constructType): var endPos = Vector2(oEditingTools.BRUSH_SIZE-1, oEditingTools.BRUSH_SIZE-1) var brushSize = (beginPos-endPos).abs() var center = Vector2(brushSize.x*0.5, brushSize.y*0.5) - print("brushSize: " + str(brushSize)) + for y in range(beginPos.y, endPos.y+1): for x in range(beginPos.x, endPos.x+1): if constructType == oSelection.CONSTRUCT_BRUSH: diff --git a/Autoload/Filetypes.gd b/Scenes/Buffers.gd similarity index 52% rename from Autoload/Filetypes.gd rename to Scenes/Buffers.gd index 22026c06..24449a26 100644 --- a/Autoload/Filetypes.gd +++ b/Scenes/Buffers.gd @@ -1,5 +1,9 @@ extends Node +onready var oWriteData = Nodelist.list["oWriteData"] +onready var oReadData = Nodelist.list["oReadData"] +onready var oCurrentFormat = Nodelist.list["oCurrentFormat"] + const FILE_TYPES = [ "LOF", # This must be read first so that MAPSIZE can be used in relation to the rest of the files "CLM", @@ -22,9 +26,8 @@ const FILE_TYPES = [ ] func new_blank(EXT): - var oReadData = Nodelist.list["oReadData"] match EXT: - "LOF" : oReadData.new_keeperfx_lof() + "LOF" : oReadData.new_lof() "CLM" : oReadData.new_clm() "DAT" : oReadData.new_dat() "APT" : oReadData.new_apt() @@ -44,17 +47,18 @@ func new_blank(EXT): "UNE" : oReadData.new_une() func read(filePath, EXT): - if File.new().file_exists(filePath) == false: print("File not found : " + filePath) return - - print("Attempting to read : "+filePath) + + print("Attempting to read : " + filePath) var CODETIME_START = OS.get_ticks_msec() - var buffer = file_path_to_buffer(filePath) - - var oReadData = Nodelist.list["oReadData"] + read_buffer_for_extension(buffer, EXT) + print('.' + EXT + ' read success in ' + str(OS.get_ticks_msec() - CODETIME_START) + 'ms') + +func read_buffer_for_extension(buffer, EXT): + buffer.seek(0) # Important! match EXT: "LOF" : oReadData.read_lof(buffer) "CLM" : oReadData.read_clm(buffer) @@ -74,43 +78,6 @@ func read(filePath, EXT): "WLB" : oReadData.read_wlb(buffer) "TXT" : oReadData.read_txt(buffer) "UNE" : oReadData.read_une(buffer) - - print('.'+EXT+' read success in '+str(OS.get_ticks_msec()-CODETIME_START)+'ms') - -func write(filePath, EXT): - print("Saving : "+filePath) - var CODETIME_START = OS.get_ticks_msec() - - var buffer = StreamPeerBuffer.new() - var oWriteData = Nodelist.list["oWriteData"] - match EXT: - "LOF" : oWriteData.write_keeperfx_lof(buffer) - "CLM" : oWriteData.write_clm(buffer) - "DAT" : oWriteData.write_dat(buffer) - "APT" : oWriteData.write_apt(buffer) - "APTFX" : oWriteData.write_aptfx(buffer) - "TNG" : oWriteData.write_tng(buffer) - "TNGFX" : oWriteData.write_tngfx(buffer) - "INF" : oWriteData.write_inf(buffer) - "SLB" : oWriteData.write_slb(buffer) - "OWN" : oWriteData.write_own(buffer) - "LIF" : oWriteData.write_lif(buffer,filePath) - "LGT" : oWriteData.write_lgt(buffer) - "LGTFX" : oWriteData.write_lgtfx(buffer) - "WIB" : oWriteData.write_wib(buffer) - "SLX" : oWriteData.write_slx(buffer) - "WLB" : oWriteData.write_wlb(buffer) - "TXT" : oWriteData.write_txt(buffer) - "UNE" : oWriteData.write_une(buffer) - - var file = File.new() - var err = file.open(filePath,File.WRITE) - if err == OK: - file.store_buffer(buffer.data_array) - print('.'+EXT+' wrote in '+str(OS.get_ticks_msec()-CODETIME_START)+'ms') - file.close() - - return err func file_path_to_buffer(filePath): var buffer = StreamPeerBuffer.new() @@ -119,3 +86,50 @@ func file_path_to_buffer(filePath): buffer.data_array = file.get_buffer(file.get_len()) file.close() return buffer + +func write(filePath, EXT): + print("Saving : " + filePath) + var CODETIME_START = OS.get_ticks_msec() + var buffer = get_buffer_for_extension(EXT, filePath) + var err = write_buffer_to_file(filePath, buffer, EXT, CODETIME_START) + if err == OK: + print('.' + EXT + ' wrote in ' + str(OS.get_ticks_msec() - CODETIME_START) + 'ms') + return err + +func write_buffer_to_file(filePath, buffer, EXT, CODETIME_START): + var file = File.new() + var err = file.open(filePath, File.WRITE) + if err == OK: + file.store_buffer(buffer.data_array) + file.close() + return err + +func get_buffer_for_extension(EXT, filePath): + match EXT: + "LOF": return oWriteData.write_keeperfx_lof() + "CLM": return oWriteData.write_clm() + "DAT": return oWriteData.write_dat() + "APT": return oWriteData.write_apt() + "APTFX": return oWriteData.write_aptfx() + "TNG": return oWriteData.write_tng() + "TNGFX": return oWriteData.write_tngfx() + "INF": return oWriteData.write_inf() + "SLB": return oWriteData.write_slb() + "OWN": return oWriteData.write_own() + "LIF": return oWriteData.write_lif(filePath) + "LGT": return oWriteData.write_lgt() + "LGTFX": return oWriteData.write_lgtfx() + "WIB": return oWriteData.write_wib() + "SLX": return oWriteData.write_slx() + "WLB": return oWriteData.write_wlb() + "TXT": return oWriteData.write_txt() + "UNE": return oWriteData.write_une() + +func should_process_file_type(EXT): + if oCurrentFormat.selected == 0: # Classic format + if ["LOF", "TNGFX", "APTFX", "LGTFX"].has(EXT): + return false + elif oCurrentFormat.selected == 1: # KFX format + if ["LIF", "TNG", "APT", "LGT"].has(EXT): + return false + return true diff --git a/Scenes/CLMGraphics.gd b/Scenes/CLMGraphics.gd index 7534dc0d..9f66999f 100644 --- a/Scenes/CLMGraphics.gd +++ b/Scenes/CLMGraphics.gd @@ -21,7 +21,7 @@ extends TileMap # var cubeFace # # # clmIndex is a position inside the 2048 column collection -# var clmIndex = oDataClmPos.get_cell(x,y) +# var clmIndex = oDataClmPos.get_cell_clmpos(x,y) # # # clmData is the 24 byte array. # var clmData = oDataClm.data[clmIndex] diff --git a/Scenes/Camera2D.gd b/Scenes/Camera2D.gd index 9a524ae3..6ed75f2a 100644 --- a/Scenes/Camera2D.gd +++ b/Scenes/Camera2D.gd @@ -24,7 +24,6 @@ var middleMousePanning = false #var mouseIsMoving = false var mouseInWindow = true -var skip_camera_reset = false func _ready(): reset_camera(M.xSize, M.ySize) diff --git a/Scenes/ColumnModels.gd b/Scenes/ColumnModels.gd index 77bd9bee..d7270593 100644 --- a/Scenes/ColumnModels.gd +++ b/Scenes/ColumnModels.gd @@ -71,7 +71,7 @@ extends Node # # for z in 255: # for x in 255: -# var idx = oDataClmPos.get_cell(z,x) +# var idx = oDataClmPos.get_cell_clmpos(z,x) # if oDataClm.solidMask[idx] > 0: # DON'T USE SOLID MASK LIKE THIS!!!!!!!!!!!!!!!!!!!!!!!! # tempArrays[Mesh.ARRAY_INDEX].append_array(columnMeshArrays[idx][Mesh.ARRAY_INDEX]) # tempArrays[Mesh.ARRAY_VERTEX].append_array(columnMeshArrays[idx][Mesh.ARRAY_VERTEX]) diff --git a/Scenes/CurrentMap.gd b/Scenes/CurrentMap.gd index 498ec620..cbb8a647 100644 --- a/Scenes/CurrentMap.gd +++ b/Scenes/CurrentMap.gd @@ -39,6 +39,7 @@ func _init(): func _on_ButtonNewMap_pressed(): oOpenMap.open_map("") # This means "blank" map + func set_path_and_title(newpath): if newpath != "": OS.set_window_title(newpath + ' - Unearth v'+Version.full) @@ -49,51 +50,24 @@ func set_path_and_title(newpath): oGame.reconstruct_command_line() # Always update command line whenever the path changes -var instancesToFree = [] -func _process(delta): - # For whatever reason, clearing here instead from an array prevents Godot from crashing - while instancesToFree.empty() == false: - instancesToFree.pop_back().queue_free() - func clear_map(): - var allInst = get_tree().get_nodes_in_group("Instance") - for id in allInst: - oInstances.remove_child(id) - id.position = Vector2(-9999999,-9999999) - id.visible = false - for group in id.get_groups(): - id.remove_from_group(group) - instancesToFree.append(id) - var CODETIME_START = OS.get_ticks_msec() - set_path_and_title("") + var allInst = get_tree().get_nodes_in_group("Instance") + for id in allInst: + oInstances.kill_instance(id) # "lif" oDataMapName.clear() # "wib" oDataSlx.clear_img() - # "wib" (Wibble) - oDataWibble.clear() - # "wlb" (Water Lava Block) - oDataLiquid.clear() - # "slb" - oDataSlab.clear() - # "own" - oDataOwnership.clear() oOverheadOwnership.clear() # "inf" oDataLevelStyle.data = 0 - # "dat" - oDataClmPos.clear() - # "clm" - oOverheadGraphics.clear_img() # 3D oGenerateTerrain.clear() #"TXT" oDataScript.data = "" - # "UNE" - oDataFakeSlab.clear() oScriptHelpers.clear() diff --git a/Scenes/CurrentTextures.gd b/Scenes/CurrentTextures.gd index 6310b8ca..3aeac003 100644 --- a/Scenes/CurrentTextures.gd +++ b/Scenes/CurrentTextures.gd @@ -93,7 +93,7 @@ func start(): texturesLoadedState = LOADING_SUCCESS # This is important to do here if updating textures while a map is already open - if oDataSlab.get_cell(0,0) != TileMap.INVALID_CELL: + if oDataSlab.get_cell(0,0) != -1: set_current_texture_pack() func scan_dk_data_directory(): diff --git a/Scenes/CustomSlabSystem.gd b/Scenes/CustomSlabSystem.gd index ddc97d0d..6a73ec50 100644 --- a/Scenes/CustomSlabSystem.gd +++ b/Scenes/CustomSlabSystem.gd @@ -49,10 +49,10 @@ func load_file(): } var retrieve_value - retrieve_value = cfg.get_value(section, "door_thing", null) # Default = null - if retrieve_value != null: slab_dict["door_thing"] = retrieve_value - retrieve_value = cfg.get_value(section, "door_orientation", null) - if retrieve_value != null: slab_dict["door_orientation"] = retrieve_value + retrieve_value = cfg.get_value(section, "door_thing", "NOT_FOUND") # Default = null + if retrieve_value != "NOT_FOUND": slab_dict["door_thing"] = retrieve_value + retrieve_value = cfg.get_value(section, "door_orientation", "NOT_FOUND") + if retrieve_value != "NOT_FOUND": slab_dict["door_orientation"] = retrieve_value add_custom_slab(slab_dict) diff --git a/Scenes/CustomTooltip.gd b/Scenes/CustomTooltip.gd index e980768a..bfd39f6e 100644 --- a/Scenes/CustomTooltip.gd +++ b/Scenes/CustomTooltip.gd @@ -39,13 +39,7 @@ func set_floortexture(floorTextureValue): dataTexture.create_from_image(dataImage, 0) dataImage.lock() - var valueInput = floorTextureValue - var r = clamp(valueInput, 0, 255) - valueInput -= 255 - var g = clamp(valueInput, 0, 255) - valueInput -= 255 - var b = clamp(valueInput, 0, 255) - dataImage.set_pixel(0, 0, Color8(r,g,b)) + dataImage.set_pixel(0, 0, Color8(floorTextureValue >> 16 & 255, floorTextureValue >> 8 & 255, floorTextureValue & 255)) dataImage.unlock() dataTexture.set_data(dataImage) diff --git a/Scenes/DataClm.gd b/Scenes/DataClm.gd index 13252e11..21e096d7 100644 --- a/Scenes/DataClm.gd +++ b/Scenes/DataClm.gd @@ -31,6 +31,7 @@ func store_default_data(): var unknownData #The second 4 bytes + func clm_data_exists(): if cubes.empty() == true: return false # Nothing in arrays, so column data doesn't exist @@ -39,11 +40,13 @@ func clm_data_exists(): func count_filled_clm_entries(): + var CODETIME_START = OS.get_ticks_msec() var numberOfFilledEntries = 0 for entry in 2048: if cubes[entry] != [0,0,0,0, 0,0,0,0]: numberOfFilledEntries += 1 oUniversalDetails.clmEntryCount = numberOfFilledEntries + print('count_filled_clm_entries: ' + str(OS.get_ticks_msec() - CODETIME_START) + 'ms') return numberOfFilledEntries func index_entry(cubeArray, setFloorID): @@ -68,13 +71,18 @@ func index_entry(cubeArray, setFloorID): oMessage.big("Error", "Clm entries are full. Try the 'Clear Unused' button in the Map Columns window.") return 0 +var a_column_has_changed_since_last_updating_utilized = false func update_all_utilized(): + if a_column_has_changed_since_last_updating_utilized == false: + return + a_column_has_changed_since_last_updating_utilized = false + var CODETIME_START = OS.get_ticks_msec() for clearIndex in 2048: utilized[clearIndex] = 0 for y in (M.ySize*3): for x in (M.xSize*3): - var value = oDataClmPos.get_cell(x,y) + var value = oDataClmPos.get_cell_clmpos(x,y) utilized[value] += 1 print('All CLM utilized updated in '+str(OS.get_ticks_msec()-CODETIME_START)+'ms') @@ -144,15 +152,15 @@ func sort_columns_by_utilized(): for y in (M.ySize*3): for x in (M.xSize*3): - var clmIndex = oDataClmPos.get_cell(x,y) - oDataClmPos.set_cell(x, y, dictSrcDest[clmIndex]) + var clmIndex = oDataClmPos.get_cell_clmpos(x,y) + oDataClmPos.set_cell_clmpos(x, y, dictSrcDest[clmIndex]) var shapePositionArray = [] for ySlab in range(0, M.ySize): for xSlab in range(0, M.xSize): shapePositionArray.append(Vector2(xSlab,ySlab)) - oOverheadGraphics.overhead2d_update_rect(shapePositionArray) + oOverheadGraphics.overhead2d_update_rect_single_threaded(shapePositionArray) utilized[0] = 0 # Pretend that the utilized value is maximum for column 0, so it's placed first. Set it back to 0 afterwards. diff --git a/Scenes/DataClmPos.gd b/Scenes/DataClmPos.gd new file mode 100644 index 00000000..22581443 --- /dev/null +++ b/Scenes/DataClmPos.gd @@ -0,0 +1,16 @@ +extends Grid + +func get_cell_clmpos(x, y): + var seek_pos = (y * width + x) * bytes_per_entry + if seek_pos >= 0 and seek_pos < buffer_size: + buffer.seek(seek_pos) + return abs(buffer.get_16()) + return 0 + +func set_cell_clmpos(x, y, value): + value = 65536-value + set_cell(x, y, value) + +# Alternatively, use: +#var value = 65536 - buffer.get_u16() +#if value == 65536: value = 0 diff --git a/Scenes/DataFakeSlab.gd b/Scenes/DataFakeSlab.gd new file mode 100644 index 00000000..5272f27b --- /dev/null +++ b/Scenes/DataFakeSlab.gd @@ -0,0 +1 @@ +extends Grid diff --git a/Scenes/DataLif.gd b/Scenes/DataLif.gd index afc8506e..342c32e0 100644 --- a/Scenes/DataLif.gd +++ b/Scenes/DataLif.gd @@ -1,7 +1,7 @@ extends Node onready var oReadData = Nodelist.list["oReadData"] onready var oDataLof = Nodelist.list["oDataLof"] - +onready var oBuffers = Nodelist.list["oBuffers"] var data = "" @@ -24,7 +24,7 @@ func clear(): func lif_name_text(pathString): - var buffer = Filetypes.file_path_to_buffer(pathString) + var buffer = oBuffers.file_path_to_buffer(pathString) var array = oReadData.lif_buffer_to_array(buffer) var mapName = oReadData.lif_array_to_map_name(array) return mapName @@ -40,7 +40,7 @@ func get_special_lif_text(pathString): # Uses the path only as a string rather t readSpecial = Settings.unearthdata.plus_file("ddisk1.lif") if readSpecial != "": - var buffer = Filetypes.file_path_to_buffer(readSpecial) + var buffer = oBuffers.file_path_to_buffer(readSpecial) var lifArray = oReadData.lif_buffer_to_array(buffer) if lifArray.empty() == false: diff --git a/Scenes/DataLiquid.gd b/Scenes/DataLiquid.gd new file mode 100644 index 00000000..5272f27b --- /dev/null +++ b/Scenes/DataLiquid.gd @@ -0,0 +1 @@ +extends Grid diff --git a/Scenes/DataLof.gd b/Scenes/DataLof.gd index 5f722a1c..5828bc2f 100644 --- a/Scenes/DataLof.gd +++ b/Scenes/DataLof.gd @@ -1,4 +1,5 @@ extends Node +onready var oBuffers = Nodelist.list["oBuffers"] var MAP_FORMAT_VERSION = "" var NAME_TEXT = "" @@ -38,7 +39,7 @@ func clear_all(): M.ySize = 85 func lof_name_text(pathString): - var buffer = Filetypes.file_path_to_buffer(pathString) + var buffer = oBuffers.file_path_to_buffer(pathString) buffer.seek(0) var value = buffer.get_string(buffer.get_size()) diff --git a/Scenes/DataOwnership.gd b/Scenes/DataOwnership.gd new file mode 100644 index 00000000..2800ed02 --- /dev/null +++ b/Scenes/DataOwnership.gd @@ -0,0 +1,23 @@ +extends Grid + +func set_cellv_ownership(pos, value): + var x = pos.x * 3 + var y = pos.y * 3 + var start_seek_pos = (y * width + x) * bytes_per_entry + if start_seek_pos >= 0 and start_seek_pos < buffer_size: + var seek_pos = start_seek_pos + for _i in range(3): + for _j in range(3): + buffer.seek(seek_pos) + buffer.put_u8(value) + seek_pos += bytes_per_entry + seek_pos += (width - 3) * bytes_per_entry + + +func get_cell_ownership(x, y): + return get_cell(x*3, y*3) + + + +func get_cellv_ownership(pos): + return get_cell(pos.x*3, pos.y*3) diff --git a/Scenes/DataSlab.gd b/Scenes/DataSlab.gd index b93553f6..5272f27b 100644 --- a/Scenes/DataSlab.gd +++ b/Scenes/DataSlab.gd @@ -1,16 +1 @@ -extends TileMap - -#func _ready(): -# tileDrawDist = 96 - -func subtile2grid(x,y): - return get_cell( int(x/3), int(y/3) ) - -#var IS_FLOOR = Slabs.IS_FLOOR -#var SLAB_TYPE = Slabs.SLAB_TYPE -#func is_touching_floor(x,y): -# if Slabs.array[subtile2grid(x+1,y)][SLAB_TYPE] == IS_FLOOR: return true -# if Slabs.array[subtile2grid(x-1,y)][SLAB_TYPE] == IS_FLOOR: return true -# if Slabs.array[subtile2grid(x,y+1)][SLAB_TYPE] == IS_FLOOR: return true -# if Slabs.array[subtile2grid(x,y-1)][SLAB_TYPE] == IS_FLOOR: return true -# return false +extends Grid diff --git a/Scenes/DataWibble.gd b/Scenes/DataWibble.gd new file mode 100644 index 00000000..5272f27b --- /dev/null +++ b/Scenes/DataWibble.gd @@ -0,0 +1 @@ +extends Grid diff --git a/Scenes/Editor.gd b/Scenes/Editor.gd index 4ef0404b..f611c13a 100644 --- a/Scenes/Editor.gd +++ b/Scenes/Editor.gd @@ -13,6 +13,7 @@ onready var oEditableBordersCheckbox = Nodelist.list["oEditableBordersCheckbox"] onready var oMenu = Nodelist.list["oMenu"] onready var oConfirmSaveBeforeQuit = Nodelist.list["oConfirmSaveBeforeQuit"] onready var oExportPreview = Nodelist.list["oExportPreview"] +onready var oUndoStates = Nodelist.list["oUndoStates"] enum { VIEW_2D = 0 @@ -21,8 +22,12 @@ enum { var currentView = VIEW_2D var fieldBoundary = Rect2() -var mapHasBeenEdited = false +var mapHasBeenEdited = false setget set_map_has_been_edited +func set_map_has_been_edited(setVal): + mapHasBeenEdited = setVal + if setVal == true: + oUndoStates.call_deferred("attempt_to_save_new_undo_state") func _ready(): get_tree().set_auto_accept_quit(false) @@ -33,14 +38,11 @@ func _unhandled_input(event): if Input.is_action_just_pressed('ui_cancel'): match currentView: VIEW_2D: - var foundDialogToClose = false - for i in oUi.listOfWindowDialogs: if is_instance_valid(i) == true: if i.visible == true: if i.get_close_button().visible == true: i.visible = false - foundDialogToClose = true VIEW_3D: if oExportPreview.visible == true: oExportPreview.hide() diff --git a/Scenes/ExportPreview.gd b/Scenes/ExportPreview.gd index c81179e2..549e17b2 100644 --- a/Scenes/ExportPreview.gd +++ b/Scenes/ExportPreview.gd @@ -56,7 +56,7 @@ func _on_ExportPreview_about_to_show(): oUiTools.visible = false oUi.hide_tools() oUi3D.visible = false - yield(oGenerateTerrain, "terrain_finished_generating") + yield(oGenerateTerrain, "terrain3D_finished_generating") oGame3D.visible = true modulate.a = 1.0 _on_SavePreviewMipmapsCheckbox_toggled(oSavePreviewMipmapsCheckbox.pressed) diff --git a/Scenes/GenerateBorderWindow.gd b/Scenes/GenerateBorderWindow.gd index bd2434f8..e2c4db34 100644 --- a/Scenes/GenerateBorderWindow.gd +++ b/Scenes/GenerateBorderWindow.gd @@ -22,6 +22,9 @@ onready var oNewMapSymmetricalBorder = Nodelist.list["oNewMapSymmetricalBorder"] onready var oNoiseDistance = Nodelist.list["oNoiseDistance"] onready var oMapSettingsWindow = Nodelist.list["oMapSettingsWindow"] onready var oCheckBoxNewMapAutoOpensMapSettings = Nodelist.list["oCheckBoxNewMapAutoOpensMapSettings"] +onready var oUndoStates = Nodelist.list["oUndoStates"] + +var currently_creating_new_map = false var noise = OpenSimplexNoise.new() var imageData = Image.new() @@ -84,12 +87,16 @@ func reinit_noise_preview(): func _on_ButtonNewMapOK_pressed(): + currently_creating_new_map = true + if oGame.EXECUTABLE_PATH == "": oMessage.quick("Error: Game executable is not set. Set in File -> Preferences") return oCurrentMap._on_ButtonNewMap_pressed() + yield(oOverheadGraphics, "graphics_thread_completed") + if Slabset.dat.empty() == true: oMessage.quick("Failed loading slabset, game executable might not be correct. Set in File -> Preferences") return @@ -111,13 +118,15 @@ func _on_ButtonNewMapOK_pressed(): # Blank overwrite_map_with_blank_values() - #Vector2(0,0), Vector2(M.xSize-1,M.ySize-1) - oSlabPlacement.generate_slabs_based_on_id(shapePositionArray, false) - visible = false # Close New Map window after pressing OK button + # yield must be used here, because this function has yields inside of it. + yield(oSlabPlacement.generate_slabs_based_on_id(shapePositionArray, false), "completed") + if oCheckBoxNewMapAutoOpensMapSettings.pressed == true: Utils.popup_centered(oMapSettingsWindow) + + currently_creating_new_map = false func overwrite_map_with_blank_values(): for y in range(1, M.ySize-1): diff --git a/Scenes/GenerateTerrain.gd b/Scenes/GenerateTerrain.gd index 63e79c0a..6dfb8e66 100644 --- a/Scenes/GenerateTerrain.gd +++ b/Scenes/GenerateTerrain.gd @@ -7,7 +7,7 @@ onready var oDataSlx = Nodelist.list["oDataSlx"] onready var oTextureCache = Nodelist.list["oTextureCache"] onready var oDataClm = Nodelist.list["oDataClm"] -signal terrain_finished_generating +signal terrain3D_finished_generating func start(): var CODETIME_START = OS.get_ticks_msec() @@ -38,13 +38,13 @@ func start(): var x = (xSlab*3) + xSubtile var z = (ySlab*3) + ySubtile - var clmIndex = oDataClmPos.get_cell(x,z) + var clmIndex = oDataClmPos.get_cell_clmpos(x,z) var surrClmIndex = [ - oDataClmPos.get_cell(x,z-1), - oDataClmPos.get_cell(x+1,z), - oDataClmPos.get_cell(x,z+1), - oDataClmPos.get_cell(x-1,z), + oDataClmPos.get_cell_clmpos(x,z-1), + oDataClmPos.get_cell_clmpos(x+1,z), + oDataClmPos.get_cell_clmpos(x,z+1), + oDataClmPos.get_cell_clmpos(x-1,z), ] # Fix the edges if x+1 >= (M.xSize*3): surrClmIndex[1] = TileMap.INVALID_CELL @@ -58,7 +58,7 @@ func start(): print('Codetime: ' + str(OS.get_ticks_msec() - CODETIME_START) + 'ms') yield(get_tree(),'idle_frame') # Important to solve race condition - emit_signal("terrain_finished_generating") + emit_signal("terrain3D_finished_generating") func loading_bar_start(): oLoadingBar.visible = true diff --git a/Scenes/GenerateTerrainOLD.gd b/Scenes/GenerateTerrainOLD.gd index b13b9e3a..7580fed6 100644 --- a/Scenes/GenerateTerrainOLD.gd +++ b/Scenes/GenerateTerrainOLD.gd @@ -138,7 +138,7 @@ func generation(): var pos = Vector3(x,y-1,z) var clmIndex if GENERATED_TYPE == GEN_MAP: - clmIndex = oDataClmPos.get_cell(x,z) + clmIndex = oDataClmPos.get_cell_clmpos(x,z) elif GENERATED_TYPE == GEN_CLM: if x/2 != x/2.0 or z/2 != z/2.0: continue #skips current loop clmIndex = ((z/2) * (TERRAIN_SIZE_X/2)) + (x/2) @@ -195,7 +195,7 @@ func set_cube_id_with_column_position_data(): blockMap[x][z] = [] blockMap[x][z].resize(TERRAIN_SIZE_Y) - var clmIndex = oDataClmPos.get_cell(x,z) + var clmIndex = oDataClmPos.get_cell_clmpos(x,z) blockMap[x][z] = oDataClm.cubes[clmIndex] # Warning: this is probably a reference. But it probably doesn't matter. func set_cube_id_to_clm_index(): diff --git a/Scenes/Instances.gd b/Scenes/Instances.gd index c364d8e0..22e55d9c 100644 --- a/Scenes/Instances.gd +++ b/Scenes/Instances.gd @@ -20,6 +20,8 @@ var thingScn = preload("res://Scenes/ThingInstance.tscn") var actionPointScn = preload("res://Scenes/ActionPointInstance.tscn") var lightScn = preload("res://Scenes/LightInstance.tscn") +func _ready(): + erase_instances_loop() func place_new_light(newThingType, newSubtype, newPosition, newOwnership): var id = lightScn.instance() @@ -139,10 +141,10 @@ func mirror_deletion_of_instance(instanceBeingDeleted): if is_instance_valid(getNodeAtMirroredPosition): if getNodeAtMirroredPosition.subtype == instanceBeingDeleted.subtype: if getNodeAtMirroredPosition.thingType == instanceBeingDeleted.thingType: - getNodeAtMirroredPosition.queue_free() + kill_instance(getNodeAtMirroredPosition) func placement_is_obstructed(thingType, placeSubtile): - var detectTerrainHeight = oDataClm.height[oDataClmPos.get_cell(placeSubtile.x,placeSubtile.y)] + var detectTerrainHeight = oDataClm.height[oDataClmPos.get_cell_clmpos(placeSubtile.x,placeSubtile.y)] if oPlaceThingsAnywhere.pressed == false and detectTerrainHeight >= 5 and thingType != Things.TYPE.EXTRA: # Lights and Action Points can always be placed anywhere return true return false @@ -249,7 +251,7 @@ func place_new_thing(newThingType, newSubtype, newPosition, newOwnership): # Pla id.subtype = newSubtype id.ownership = newOwnership - set_collectibles_ownership(id, slabID, oDataOwnership.get_cell(xSlab, ySlab)) + set_collectibles_ownership(id, slabID, oDataOwnership.get_cell_ownership(xSlab, ySlab)) match id.thingType: Things.TYPE.OBJECT: @@ -325,7 +327,7 @@ func place_new_thing(newThingType, newSubtype, newPosition, newOwnership): # Pla id.locationY = -32767 var goldID = get_node_on_subtile(locX, locY, "TreasuryGold") if is_instance_valid(goldID) == true: - goldID.queue_free() + kill_instance(goldID) id.locationX = locX id.locationY = locY elif id.thingType == Things.TYPE.DOOR: @@ -395,7 +397,7 @@ func spawn_attached(xSlab, ySlab, slabID, ownership, subtile, tngObj): # Spawns 1: id.subtype = 116 # Blue 2: id.subtype = 117 # Green 3: id.subtype = 118 # Yellow - 4: id.queue_free() # White + 4: kill_instance(id) # White 5: id.subtype = 119 # None elif slabID == Slabs.DUNGEON_HEART: if tngObj[Slabset.obj.THING_SUBTYPE] == 111: # Heart Flame (Red) @@ -404,8 +406,8 @@ func spawn_attached(xSlab, ySlab, slabID, ownership, subtile, tngObj): # Spawns 1: id.subtype = 120 # Blue 2: id.subtype = 121 # Green 3: id.subtype = 122 # Yellow - 4: id.queue_free() # White - 5: id.queue_free() # None + 4: kill_instance(id) # White + 5: kill_instance(id) # None add_child(id) @@ -423,12 +425,42 @@ func spawn_attached(xSlab, ySlab, slabID, ownership, subtile, tngObj): # Spawns # 3: partnerArrow.texture = preload("res://Art/torchdir3.png") # id.add_child(partnerArrow) +var instances_to_erase = [] + +func erase_instances_loop(): # started by _ready() + for i in 2: # We need 2 idle_frames to separate the wait from the 1 idle_frame that perform_undo uses + yield(get_tree(),'idle_frame') + var items_freed = 0 + var max_items_to_free = max(1, instances_to_erase.size() * 0.01) + #var FREEING_CODETIME_START = OS.get_ticks_msec() + + while true: + var id = instances_to_erase.pop_back() + if is_instance_valid(id): + items_freed += 1 + id.free() + if instances_to_erase.size() > 2000: # If you're not erasing them fast enough, leaving too many instances on the field creates its own lag. + continue + elif instances_to_erase.empty() == true or items_freed > max_items_to_free: + break + #if items_freed > 0: + #print(items_freed) + #print('Time spent freeing instances: ' + str(OS.get_ticks_msec() - FREEING_CODETIME_START) + 'ms') + + erase_instances_loop() + +func kill_instance(id): # Multi-thread safe + id.visible = false + for group in id.get_groups(): + id.remove_from_group(group) + instances_to_erase.append(id) + func manage_things_on_slab(xSlab, ySlab, slabID, ownership): if Slabs.data[slabID][Slabs.IS_SOLID] == true: var nodesOnSlab = get_all_nodes_on_slab(xSlab, ySlab, ["Thing"]) - for i in nodesOnSlab: - i.queue_free() + for id in nodesOnSlab: + kill_instance(id) else: var checkSlabLocationGroup = "slab_location_group_"+str(xSlab)+'_'+str(ySlab) for id in get_tree().get_nodes_in_group(checkSlabLocationGroup): @@ -439,12 +471,13 @@ func manage_things_on_slab(xSlab, ySlab, slabID, ownership): func set_collectibles_ownership(id, slabID, slabOwnership): if id.thingType == Things.TYPE.OBJECT: - var genre = Things.DATA_OBJECT[id.subtype][Things.EDITOR_TAB] - if Things.collectible_belonging.has(genre): - if slabID == Things.collectible_belonging[genre]: - id.ownership = slabOwnership - else: - id.ownership = 5 + if Things.DATA_OBJECT.has(id.subtype): + var genre = Things.DATA_OBJECT[id.subtype][Things.EDITOR_TAB] + if Things.collectible_belonging.has(genre): + if slabID == Things.collectible_belonging[genre]: + id.ownership = slabOwnership + else: + id.ownership = 5 func manage_thing_ownership_on_slab(xSlab, ySlab, ownership): var checkSlabLocationGroup = "slab_location_group_"+str(xSlab)+'_'+str(ySlab) @@ -490,7 +523,7 @@ func on_slab_update_thing_height(id): # Update heights of any manually placed ob if id.parentTile == 65535: # None. Not attached to any slab. var xSubtile = floor(id.locationX) var ySubtile = floor(id.locationY) - var detectTerrainHeight = oDataClm.height[oDataClmPos.get_cell(xSubtile,ySubtile)] + var detectTerrainHeight = oDataClm.height[oDataClmPos.get_cell_clmpos(xSubtile,ySubtile)] id.locationZ = detectTerrainHeight if id.subtype in [2,7]: update_stray_torch_height(id) @@ -504,7 +537,7 @@ func on_slab_delete_stray_door_thing_and_key(id, slabID): # Kill doors and keys that aren't on door slabIDs if id.is_in_group("Door") or id.is_in_group("Key"): if Slabs.is_door(slabID) == false: - id.queue_free() + kill_instance(id) @@ -542,7 +575,7 @@ func delete_attached_instances_on_slab(xSlab, ySlab): var groupName = 'attachedtotile_'+str((ySlab*M.xSize)+xSlab) if groupName == "attachedtotile_0": return # This fixes an edge case issue with Spinning Keys being destroyed if you click the top left corner for id in get_tree().get_nodes_in_group(groupName): - id.queue_free() + kill_instance(id) func get_free_index_number(): var listOfThingNumbers = [] diff --git a/Scenes/Main.gd b/Scenes/Main.gd index 675a6552..3b874867 100644 --- a/Scenes/Main.gd +++ b/Scenes/Main.gd @@ -46,7 +46,6 @@ func initialize_window_settings(): OS.window_fullscreen = false - #func get_mipmap(img, level): # Doesn't need to care about formats, but can't handle the smallest MIP level # if img.has_mipmaps() == false: return # diff --git a/Scenes/Main.tscn b/Scenes/Main.tscn index f12503fb..0d51c034 100644 --- a/Scenes/Main.tscn +++ b/Scenes/Main.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=183 format=2] +[gd_scene load_steps=188 format=2] [ext_resource path="res://Scenes/SlabStyle.gd" type="Script" id=1] [ext_resource path="res://Scenes/SlabPlacement.gd" type="Script" id=2] @@ -14,7 +14,7 @@ [ext_resource path="res://Global/FPScounter.gd" type="Script" id=12] [ext_resource path="res://Scenes/DataSlab.gd" type="Script" id=13] [ext_resource path="res://Scenes/OverheadOwnership.gd" type="Script" id=14] -[ext_resource path="res://Art/Wibble_1.png" type="Texture" id=15] +[ext_resource path="res://Scenes/DataLiquid.gd" type="Script" id=15] [ext_resource path="res://Scenes/SettingWithValue.tscn" type="PackedScene" id=16] [ext_resource path="res://Theme/UnearthTheme.theme" type="Theme" id=17] [ext_resource path="res://Scenes/BoxSprite.gd" type="Script" id=18] @@ -37,7 +37,7 @@ [ext_resource path="res://Scenes/ConfirmDecompression.gd" type="Script" id=35] [ext_resource path="res://Shaders/FlashNeutralRooms.gdshader" type="Shader" id=36] [ext_resource path="res://Scenes/Editor.gd" type="Script" id=37] -[ext_resource path="res://Art/Wibble_2.png" type="Texture" id=38] +[ext_resource path="res://Scenes/DataClmPos.gd" type="Script" id=38] [ext_resource path="res://Scenes/DataClm.gd" type="Script" id=39] [ext_resource path="res://Scenes/ViewColumn.gd" type="Script" id=40] [ext_resource path="res://Scenes/LoadingBar.gd" type="Script" id=41] @@ -96,7 +96,7 @@ [ext_resource path="res://Scenes/Inspector.gd" type="Script" id=94] [ext_resource path="res://Shaders/cursorMat.tres" type="Material" id=95] [ext_resource path="res://Art/Cursor32x32Yellow.png" type="Texture" id=96] -[ext_resource path="res://Art/Wibble_0.png" type="Texture" id=97] +[ext_resource path="res://Scenes/DataFakeSlab.gd" type="Script" id=97] [ext_resource path="res://Scenes/TilemapDebug.gd" type="Script" id=98] [ext_resource path="res://Scenes/DataSlx.gd" type="Script" id=99] [ext_resource path="res://Scenes/CurrentMap.gd" type="Script" id=100] @@ -161,50 +161,12 @@ [ext_resource path="res://dk_images/landviews/rgmap00.png" type="Texture" id=159] [ext_resource path="res://Scenes/MapCoordinatesWindow.gd" type="Script" id=160] [ext_resource path="res://dk_images/landviews/ensign_lvl5.png" type="Texture" id=161] - -[sub_resource type="TileSet" id=1] -0/name = "Wibble_0.png 0" -0/texture = ExtResource( 97 ) -0/tex_offset = Vector2( 0, 0 ) -0/modulate = Color( 1, 1, 1, 1 ) -0/region = Rect2( 0, 0, 32, 32 ) -0/tile_mode = 0 -0/occluder_offset = Vector2( 0, 0 ) -0/navigation_offset = Vector2( 0, 0 ) -0/shape_offset = Vector2( 0, 0 ) -0/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) -0/shape_one_way = false -0/shape_one_way_margin = 0.0 -0/shapes = [ ] -0/z_index = 0 -1/name = "Wibble_1.png 1" -1/texture = ExtResource( 15 ) -1/tex_offset = Vector2( 0, 0 ) -1/modulate = Color( 1, 1, 1, 1 ) -1/region = Rect2( 0, 0, 32, 32 ) -1/tile_mode = 0 -1/occluder_offset = Vector2( 0, 0 ) -1/navigation_offset = Vector2( 0, 0 ) -1/shape_offset = Vector2( 0, 0 ) -1/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) -1/shape_one_way = false -1/shape_one_way_margin = 0.0 -1/shapes = [ ] -1/z_index = 0 -2/name = "Wibble_2.png 2" -2/texture = ExtResource( 38 ) -2/tex_offset = Vector2( 0, 0 ) -2/modulate = Color( 1, 1, 1, 1 ) -2/region = Rect2( 0, 0, 32, 32 ) -2/tile_mode = 0 -2/occluder_offset = Vector2( 0, 0 ) -2/navigation_offset = Vector2( 0, 0 ) -2/shape_offset = Vector2( 0, 0 ) -2/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) -2/shape_one_way = false -2/shape_one_way_margin = 0.0 -2/shapes = [ ] -2/z_index = 0 +[ext_resource path="res://Scenes/DataOwnership.gd" type="Script" id=162] +[ext_resource path="res://Scenes/NodeTest.gd" type="Script" id=163] +[ext_resource path="res://Scenes/DataWibble.gd" type="Script" id=164] +[ext_resource path="res://Scenes/Buffers.gd" type="Script" id=165] +[ext_resource path="res://Scenes/UndoStates.gd" type="Script" id=166] +[ext_resource path="res://Scenes/ThreadedSaveUndo.gd" type="Script" id=167] [sub_resource type="CubeMesh" id=2] size = Vector3( 1, 1, 1 ) @@ -384,29 +346,26 @@ script = ExtResource( 100 ) [node name="DataSlx" type="Node" parent="CurrentMap"] script = ExtResource( 99 ) -[node name="DataWibble" type="TileMap" parent="CurrentMap"] -visible = false -modulate = Color( 1, 1, 1, 0.243137 ) -position = Vector2( -16, -16 ) -tile_set = SubResource( 1 ) -cell_size = Vector2( 32, 32 ) -format = 1 +[node name="DataWibble" type="Node" parent="CurrentMap"] +script = ExtResource( 164 ) -[node name="DataLiquid" type="TileMap" parent="CurrentMap"] -format = 1 +[node name="DataLiquid" type="Node" parent="CurrentMap"] +script = ExtResource( 15 ) -[node name="DataSlab" type="TileMap" parent="CurrentMap"] -format = 1 +[node name="DataSlab" type="Node" parent="CurrentMap"] script = ExtResource( 13 ) -[node name="DataOwnership" type="TileMap" parent="CurrentMap"] -format = 1 +[node name="DataOwnership" type="Node" parent="CurrentMap"] +script = ExtResource( 162 ) + +[node name="NodeTest" type="Node" parent="CurrentMap"] +script = ExtResource( 163 ) [node name="DataLevelStyle" type="Node" parent="CurrentMap"] script = ExtResource( 11 ) -[node name="DataClmPos" type="TileMap" parent="CurrentMap"] -format = 1 +[node name="DataClmPos" type="Node" parent="CurrentMap"] +script = ExtResource( 38 ) [node name="DataClm" type="Node2D" parent="CurrentMap"] script = ExtResource( 39 ) @@ -420,24 +379,33 @@ script = ExtResource( 117 ) [node name="DataLof" type="Node" parent="CurrentMap"] script = ExtResource( 141 ) -[node name="DataFakeSlab" type="TileMap" parent="CurrentMap"] -format = 1 +[node name="DataFakeSlab" type="Node" parent="CurrentMap"] +script = ExtResource( 97 ) -[node name="OpenMap" type="Node" parent="."] -script = ExtResource( 5 ) +[node name="UndoStates" type="Node" parent="."] +script = ExtResource( 166 ) + +[node name="ThreadedSaveUndo" type="Node" parent="UndoStates"] +script = ExtResource( 167 ) + +[node name="Buffers" type="Node" parent="."] +script = ExtResource( 165 ) -[node name="ReadData" type="Node" parent="OpenMap"] +[node name="ReadData" type="Node" parent="Buffers"] script = ExtResource( 20 ) +[node name="WriteData" type="Node" parent="Buffers"] +script = ExtResource( 32 ) + +[node name="OpenMap" type="Node" parent="."] +script = ExtResource( 5 ) + [node name="RNC" type="Node" parent="OpenMap"] script = ExtResource( 53 ) [node name="SaveMap" type="Node" parent="."] script = ExtResource( 31 ) -[node name="WriteData" type="Node" parent="SaveMap"] -script = ExtResource( 32 ) - [node name="CustomObjectSystem" type="Node" parent="."] script = ExtResource( 92 ) @@ -1675,7 +1643,6 @@ custom_colors/font_color_hover = Color( 1, 0.65098, 0.556863, 1 ) custom_colors/font_color_pressed = Color( 0.333333, 0.607843, 1, 1 ) text = "Edit" align = 0 -items = [ "Map columns", null, 0, false, false, 0, 0, null, "", false, "Custom objects", null, 0, false, false, 1, 0, null, "", false, "Resize map", null, 0, false, false, 2, 0, null, "", false, "Update all slabs", null, 0, false, false, 3, 0, null, "", false, "", null, 0, false, true, -1, 0, null, "", true, "Make a tileset", null, 0, false, false, 4, 0, null, "", false, "Slabset", null, 0, false, false, 5, 0, null, "", false ] switch_on_hover = true __meta__ = { "_edit_use_anchors_": false diff --git a/Scenes/MapBrowser.gd b/Scenes/MapBrowser.gd index 90e7e756..106f8caf 100644 --- a/Scenes/MapBrowser.gd +++ b/Scenes/MapBrowser.gd @@ -19,6 +19,8 @@ onready var oMapBrowserTabContainer = Nodelist.list["oMapBrowserTabContainer"] onready var oRandomMapContainer = Nodelist.list["oRandomMapContainer"] onready var oMenu = Nodelist.list["oMenu"] onready var oInspector = Nodelist.list["oInspector"] +onready var oOverheadGraphics = Nodelist.list["oOverheadGraphics"] +onready var oMapBrowser = Nodelist.list["oMapBrowser"] func _ready(): @@ -167,6 +169,9 @@ func _on_MapBrowser_visibility_changed(): func toggle_map_preview(togglePreview): + if togglePreview == false and oMapBrowser.visible == true: + yield(oOverheadGraphics, "graphics_thread_completed") + oQuickMapPreview.visible = togglePreview # Toggle to false if currently selecting the opened map diff --git a/Scenes/Menu.gd b/Scenes/Menu.gd index 3557f4cd..b9eb5388 100644 --- a/Scenes/Menu.gd +++ b/Scenes/Menu.gd @@ -40,7 +40,7 @@ onready var oResizeCurrentMapSize = Nodelist.list["oResizeCurrentMapSize"] onready var oGridDataWindow = Nodelist.list["oGridDataWindow"] onready var oCamera2D = Nodelist.list["oCamera2D"] onready var oActionPointListWindow = Nodelist.list["oActionPointListWindow"] - +onready var oUndoStates = Nodelist.list["oUndoStates"] var recentlyOpened = [] var recentlyOpenedPopupMenu = PopupMenu.new() @@ -68,6 +68,28 @@ func _ready(): oMenuButtonEdit.get_popup().connect("id_pressed",self,"_on_EditSubmenu_Pressed") oMenuButtonView.get_popup().connect("id_pressed",self,"_on_ViewSubmenu_Pressed") oMenuButtonHelp.get_popup().connect("id_pressed",self,"_on_HelpSubmenu_Pressed") + + add_edit_menu_items() + +func add_edit_menu_items(): + # Add menu items to oMenuButtonEdit + var edit_popup = oMenuButtonEdit.get_popup() + + edit_popup.add_item("Undo", 0) + edit_popup.add_separator() + edit_popup.add_item("Map columns", 1) + edit_popup.add_item("Custom objects", 2) + edit_popup.add_item("Resize map", 3) + edit_popup.add_item("Update all slabs", 4) + edit_popup.add_separator() + edit_popup.add_item("Make a tileset", 5) + edit_popup.add_item("Slabset", 6) + +func update_undo_availability(): + if oUndoStates.undo_history.size() <= 1: + oMenuButtonEdit.get_popup().set_item_disabled(0, true) + else: + oMenuButtonEdit.get_popup().set_item_disabled(0, false) func _on_RecentSubmenu_Pressed(pressedID): @@ -96,28 +118,32 @@ func initialize_recently_opened(value): recentlyOpened = value populate_recently_opened() +var tdir = Directory.new() func populate_recently_opened(): recentlyOpenedPopupMenu.clear() for i in range(recentlyOpened.size() - 1, -1, -1): # iterate in reverse - var filePath = recentlyOpened[i] - - if Directory.new().file_exists(filePath.get_basename()+".slb") == false and Directory.new().file_exists(filePath.get_basename()+".SLB") == false: + var filePath = recentlyOpened[i].get_basename() + if tdir.file_exists(filePath + ".slb") == false and tdir.file_exists(filePath + ".SLB") == false: recentlyOpened.remove(i) for i in recentlyOpened.size(): - var filePath = recentlyOpened[i] + var filePath = recentlyOpened[i].get_basename() filePath = filePath.replace("\\", "/") var mapName = "" - if mapName == "": mapName = oDataLof.lof_name_text(filePath + ".lof") - if mapName == "": mapName = oDataLof.lof_name_text(filePath + ".LOF") - if mapName == "": mapName = oDataMapName.lif_name_text(filePath + '.lif') - if mapName == "": mapName = oDataMapName.lif_name_text(filePath + '.LIF') - if mapName == "": mapName = oDataMapName.get_special_lif_text(filePath) - if mapName == "": mapName = oDataMapName.get_special_lif_text(filePath) + if tdir.file_exists(filePath + ".lof"): + mapName = oDataLof.lof_name_text(filePath + ".lof") + elif tdir.file_exists(filePath + ".LOF"): + mapName = oDataLof.lof_name_text(filePath + ".LOF") + elif tdir.file_exists(filePath + ".lif"): + mapName = oDataMapName.lif_name_text(filePath + '.lif') + elif tdir.file_exists(filePath + ".LIF"): + mapName = oDataMapName.lif_name_text(filePath + '.LIF') + else: + mapName = oDataMapName.get_special_lif_text(filePath) # Trim game directory from path to make it look nicer var baseDir = oGame.GAME_DIRECTORY.replace('\\','/') @@ -161,7 +187,9 @@ func constantly_monitor_play_button_state(): oMenuPlayButton.disabled = true oMenuPlayButton.hint_tooltip = "Map must be saved in the correct directory in order to play." - if oEditor.mapHasBeenEdited == true: + if oCurrentMap.path == "": + oMenuPlayButton.text = "Save & Play" + elif oEditor.mapHasBeenEdited == true: oMenuPlayButton.text = "Save & Play" else: oMenuPlayButton.text = "Play" @@ -182,18 +210,20 @@ func _on_FileSubmenu_Pressed(pressedID): func _on_EditSubmenu_Pressed(pressedID): match pressedID: - 0: # Custom columns + 0: # Undo + oUndoStates.perform_undo() + 1: # Custom columns Utils.popup_centered(oColumnEditor) - 1: # Custom objects + 2: # Custom objects Utils.popup_centered(oAddCustomObjectWindow) - 2: # Resize and shift + 3: # Resize and shift Utils.popup_centered(oResizeCurrentMapSize) - 3: # Update all slabs + 4: # Update all slabs if oDataSlab.get_cell(0,0) != TileMap.INVALID_CELL: Utils.popup_centered(oConfirmAutoGen) - 4: # Texture editing + 5: # Texture editing Utils.popup_centered(oTextureEditingWindow) - 5: # Modify slabset + 6: # Modify slabset Utils.popup_centered(oSlabsetWindow) func _on_slab_style_window_close_button_clicked(): @@ -285,5 +315,4 @@ func _on_PlayButton_pressed(): # Use normal Button instead of MenuButton in comb oMenuPlayButton.connect("pressed",self,"_on_PlayButton_pressed") func _on_ConfirmDiscardChanges_confirmed(): - oCamera2D.skip_camera_reset = true oOpenMap.open_map(oCurrentMap.path) diff --git a/Scenes/NodeTest.gd b/Scenes/NodeTest.gd new file mode 100644 index 00000000..742148d9 --- /dev/null +++ b/Scenes/NodeTest.gd @@ -0,0 +1,5 @@ +extends Node + + +func clear(): + pass diff --git a/Scenes/OpenMap.gd b/Scenes/OpenMap.gd index 8c8e17ec..7bc6d159 100644 --- a/Scenes/OpenMap.gd +++ b/Scenes/OpenMap.gd @@ -39,7 +39,8 @@ onready var oPickThingWindow = Nodelist.list["oPickThingWindow"] onready var oCustomObjectSystem = Nodelist.list["oCustomObjectSystem"] onready var oCurrentFormat = Nodelist.list["oCurrentFormat"] onready var oSetNewFormat = Nodelist.list["oSetNewFormat"] - +onready var oBuffers = Nodelist.list["oBuffers"] +onready var oUndoStates = Nodelist.list["oUndoStates"] var TOTAL_TIME_TO_OPEN_MAP @@ -47,13 +48,10 @@ var compressedFiles = [] var ALWAYS_DECOMPRESS = false # Default to false func start(): - get_tree().connect("files_dropped", self, "_on_files_dropped") if oGame.EXECUTABLE_PATH == "": return # Silently wait for user to set executable path. No need to show an error. - - if OS.get_cmdline_args(): # FILE ASSOCIATION var cmdLine = OS.get_cmdline_args() @@ -61,7 +59,8 @@ func start(): open_map(cmdLine[0]) else: if OS.has_feature("standalone") == false: - #yield(get_tree(), "idle_frame") + #for i in 200: + # yield(get_tree(), "idle_frame") #oCurrentMap.clear_map() open_map("D:/Dungeon Keeper/levels/personal/map00002.slb") pass @@ -77,6 +76,7 @@ func _on_files_dropped(_files, _screen): open_map(_files[0]) func open_map(filePath): + # a filePath of "" means make a blank map. # This will replace \ with /, just for the sake of fixing ugliness @@ -92,14 +92,15 @@ func open_map(filePath): oMessage.quick("Error: Cannot open map because textures haven't been loaded") return + print("----------- Opening map ------------") + TOTAL_TIME_TO_OPEN_MAP = OS.get_ticks_msec() + # Always begin by clearing map oCurrentMap.clear_map() - # Close windows that I want closed oMapSettingsWindow.visible = false oColumnEditor.visible = false - TOTAL_TIME_TO_OPEN_MAP = OS.get_ticks_msec() var map = filePath.get_basename() load_cfg_stuff(map) @@ -120,7 +121,7 @@ func open_map(filePath): print("NEW MAPSIZE = " + str(M.xSize) + " " + str(M.ySize)) var formatType = 0 - for EXT in Filetypes.FILE_TYPES: + for EXT in oBuffers.FILE_TYPES: if oCurrentMap.currentFilePaths.has(EXT) == true: # Don't bother reading original formats if KFX format files have been found @@ -138,10 +139,11 @@ func open_map(filePath): if EXT == "APTFX": formatType = 1 if EXT == "LGTFX": formatType = 1 - Filetypes.read(oCurrentMap.currentFilePaths[EXT][oCurrentMap.PATHSTRING], EXT.to_upper()) + var readPath = oCurrentMap.currentFilePaths[EXT][oCurrentMap.PATHSTRING] + oBuffers.read(readPath, EXT.to_upper()) else: print("Missing " + EXT + " file, so create blank data for that one.") - Filetypes.new_blank(EXT.to_upper()) + oBuffers.new_blank(EXT.to_upper()) # Assign name data to any that's missing if EXT == "LIF": @@ -163,7 +165,10 @@ func open_map(filePath): if map == "": oCurrentFormat.selected = oSetNewFormat.selected - finish_opening_map(map) + continue_load(map) + continue_load_openmap(map) + print('TOTAL time to open map: '+str(OS.get_ticks_msec()-TOTAL_TIME_TO_OPEN_MAP)+'ms') + print("----------------------------------------------") else: if ALWAYS_DECOMPRESS == false: oConfirmDecompression.dialog_text = "In order to open this map, these files must be decompressed: \n\n" #'Unable to open map, it contains files which have RNC compression: \n\n' @@ -174,10 +179,10 @@ func open_map(filePath): else: # Begin decompression without confirmation dialog _on_ConfirmDecompression_confirmed() -# else: -# oMessage.quick("Error: Map files not found") + func load_cfg_stuff(map): + var CODETIME_START = OS.get_ticks_msec() Things.reset_thing_data_to_default() if Cube.tex.empty() == true: Cube.read_cubes_cfg() @@ -191,36 +196,30 @@ func load_cfg_stuff(map): var fullPathToMainCfg = oGame.get_precise_filepath(parentDirectory, mainCfgName) if fullPathToMainCfg != "": Things.get_cfgs_directory(fullPathToMainCfg) + print('load_cfg_stuff: ' + str(OS.get_ticks_msec() - CODETIME_START) + 'ms') - -func finish_opening_map(map): +func continue_load(map): + # initialize_editor_components oPickThingWindow.initialize_thing_grid_items() - oCurrentMap.set_path_and_title(map) - oDynamicMapTree.highlight_current_map() oEditor.update_boundaries() - oEditor.mapHasBeenEdited = false oScriptEditor.initialize_for_new_map() oOverheadOwnership.start() oScriptHelpers.start() - - + + # update_editor_data if Slabset.dat.empty() == true: Slabset.load_default_slabset() if Columnset.cubes.empty() == true: Columnset.load_default_columnset() - oOverheadGraphics.update_map_overhead_2d_textures() - oPickSlabWindow.add_slabs() - oDataClm.count_filled_clm_entries() + oOverheadGraphics.update_full_overhead_map() + oDataClm.count_filled_clm_entries() + oTextureCache.set_current_texture_pack() - - if oCurrentMap.path == "": - oMessage.quick('New map') - else: - oMessage.quick('Opened map') - + + # finalize_map_opening oEditor.set_view_2d() - + oMenu.add_recent(map) # When opening a map, be sure that column 0 is empty. Otherwise apply a fix. @@ -232,38 +231,36 @@ func finish_opening_map(map): oMessage.quick("Fixed column index 0, re-save your map.") oDataClm.store_default_data() - - if oCamera2D.skip_camera_reset == false: - oCamera2D.reset_camera(M.xSize, M.ySize) + +func continue_load_openmap(map): + oEditor.mapHasBeenEdited = false + oPickSlabWindow.add_slabs() + oDynamicMapTree.highlight_current_map() + oCurrentMap.set_path_and_title(map) + oCamera2D.reset_camera(M.xSize, M.ySize) + oUndoStates.clear_history() + if map == "": + oMessage.quick('New map') else: - oCamera2D.skip_camera_reset = false - -# if oGame.running_keeperfx() == true: -# if oCurrentFormat.selected == 1: # KFX format -# if oGame.KEEPERFX_VERSION_INT != 500: # Skip worrying about the compiled versions (0.5.0.0) -# if oGame.KEEPERFX_VERSION_INT != 0 and oGame.KEEPERFX_VERSION_INT < oGame.KEEPERFX_VERSION_REQUIRED_INT: -# -# oMessage.big("Warning", "Your KeeperFX version is " + oGame.KEEPERFX_VERSION_STRING + " which is too old to use the features of KFX Map Format in-game. Download the latest alpha to rectify.") + oMessage.quick('Opened map') - print('TOTAL time to open map: '+str(OS.get_ticks_msec()-TOTAL_TIME_TO_OPEN_MAP)+'ms') func _on_ConfirmDecompression_confirmed(): - #var CODETIME_START = OS.get_ticks_msec() print('Attempting to decompress...') - # Decompress files - #var dir = Directory.new() + for path in compressedFiles: oRNC.decompress(path) - #print('Decompressed in '+str(OS.get_ticks_msec()-CODETIME_START)+'ms') # Retry opening the map - # (any of the compressed files will have the appropriate name) open_map(compressedFiles[0]) + func _on_FileDialogOpen_file_selected(path): open_map(path) + func get_accompanying_files(map): + var CODETIME_START = OS.get_ticks_msec() var baseDir = map.get_base_dir() var mapName = map.get_file().get_basename() # Get the map name without the extension @@ -278,47 +275,10 @@ func get_accompanying_files(map): var fileBaseName = fileName.get_basename() # Get the file name without the extension if fileBaseName.to_upper() == mapName.to_upper(): var EXT = fileName.get_extension().to_upper() - if Filetypes.FILE_TYPES.has(EXT): + if oBuffers.FILE_TYPES.has(EXT): var fullPath = baseDir.plus_file(fileName) var getModifiedTime = File.new().get_modified_time(fullPath) dict[EXT] = [fullPath, getModifiedTime] fileName = dir.get_next() + print('get_accompanying_files: ' + str(OS.get_ticks_msec() - CODETIME_START) + 'ms') return dict - - - - - - - - -#file.seek(2+(3*( x + (y*85)))) -# for x in 85: -# for y in 85: -# #1ms -# value = file.get_8() #8ms -# file.seek(1 * ( (y*(85)) + x ) ) #2ms -# GridOwnership.set_cell(Vector2(x,y),value) - - - # 8 bytes per subtile - # 3 subtiles per tile - # 85 tiles per side - # 255 tiles total - # + 2 subtiles * 85 - # + 2 subtiles * 85 -# var subtileY = 0 -# var subtileX = 0 -# var dataHeight = (85*3)+1 -# var dataWidth = (85*3)+1 -# while subtileY <= dataHeight: -# while subtileX <= dataWidth: -# file.seek( subtileX + (subtileY*dataWidth)) -# value = file.get_8() -# GridOwnership.set_cell(Vector2(floor(subtileX/3),floor(subtileY/3)),value) -# subtileX+=1 -# subtileX = 0 -# subtileY += 1 - - - diff --git a/Scenes/OverheadGraphics.gd b/Scenes/OverheadGraphics.gd index 8311dd60..d5b713fa 100644 --- a/Scenes/OverheadGraphics.gd +++ b/Scenes/OverheadGraphics.gd @@ -6,58 +6,119 @@ onready var oDataClm = Nodelist.list["oDataClm"] onready var oDataSlx = Nodelist.list["oDataSlx"] onready var oTextureCache = Nodelist.list["oTextureCache"] onready var oDataLevelStyle = Nodelist.list["oDataLevelStyle"] +onready var oUndoStates = Nodelist.list["oUndoStates"] +onready var oQuickMapPreviewDisplay = Nodelist.list["oQuickMapPreviewDisplay"] + +signal graphics_thread_completed + +var thread_currently_processing = false var overheadImgData = Image.new() var overheadTexData = ImageTexture.new() var arrayOfColorRects = [] -func update_map_overhead_2d_textures(): +var thread = Thread.new() +var semaphore = Semaphore.new() +var mutex = Mutex.new() +var job_queue = [] +var pixel_data = PoolByteArray() + + + +func _ready(): + thread.start(self, "multi_threaded") + + +func update_full_overhead_map(): var CODETIME_START = OS.get_ticks_msec() if arrayOfColorRects.empty() == true: initialize_display_fields() else: update_display_fields_size() - - overheadImgData.create((M.xSize*3), (M.ySize*3), false, Image.FORMAT_RGB8) - overheadTexData.create_from_image(overheadImgData, 0) var shapePositionArray = [] for ySlab in range(0, M.ySize): for xSlab in range(0, M.xSize): shapePositionArray.append(Vector2(xSlab,ySlab)) - overhead2d_update_rect(shapePositionArray) + mutex.lock() + job_queue.append(shapePositionArray) + mutex.unlock() + + thread_currently_processing = true + semaphore.post() # Release the semaphore to signal the thread to process the job print('Overhead graphics done in '+str(OS.get_ticks_msec()-CODETIME_START)+'ms') -func overhead2d_update_rect(shapePositionArray): - # Include surrounding - #rectStart -= Vector2(1,1) - #rectEnd += Vector2(1,1) - #rectStart = Vector2(clamp(rectStart.x, 0, M.xSize-1), clamp(rectStart.y, 0, M.ySize-1)) - #rectEnd = Vector2(clamp(rectEnd.x, 0, M.xSize-1), clamp(rectEnd.y, 0, M.ySize-1)) -# print('rectStart: '+str(rectStart)) -# print('rectEnd: '+str(rectEnd)) - - overheadImgData.lock() - #for ySlab in range(rectStart.y, rectEnd.y+1): - # for xSlab in range(rectStart.x, rectEnd.x+1): +# Using a single threaded version for updating partial graphics. +# and a multi-threaded version for updating the entire map's graphics. +func overhead2d_update_rect_single_threaded(shapePositionArray): + #pixel_data = generate_pixel_data(pixel_data, shapePositionArray) + + var width = M.xSize * 3 + var height = M.ySize * 3 + pixel_data.resize(width * height * 3) # Assuming RGB8 format for pos in shapePositionArray: -# print('xSlab: '+str(xSlab)) -# print('ySlab: '+str(ySlab)) - var slabID = oDataSlab.get_cell(pos.x, pos.y) - for ySubtile in 3: - for xSubtile in 3: - var x = (pos.x * 3) + xSubtile - var y = (pos.y * 3) + ySubtile - overheadImgData.set_pixel(x,y,get_overhead_face_value(x, y, slabID)) - overheadImgData.unlock() + var basePosX = pos.x * 3 + var basePosY = pos.y * 3 + for i in range(9): # 3x3 subtiles + var x = basePosX + (i % 3) + var y = basePosY + (i / 3) + var clmIndex = oDataClmPos.get_cell_clmpos(x, y) + var cubeFace = oDataClm.get_top_cube_face(clmIndex, 0) + var pixelIndex = ((y * width) + x) * 3 + + pixel_data[pixelIndex] = cubeFace >> 16 & 255 + pixel_data[pixelIndex + 1] = cubeFace >> 8 & 255 + pixel_data[pixelIndex + 2] = cubeFace & 255 + + overheadImgData.create_from_data(M.xSize * 3, M.ySize * 3, false, Image.FORMAT_RGB8, pixel_data) + overheadTexData.create_from_image(overheadImgData, 0) + +func multi_threaded(): + while true: + semaphore.wait() # Acquire the semaphore before processing + print("graphics multi_threaded start") + + mutex.lock() + var shapePositionArray = job_queue.pop_front() + mutex.unlock() + + var newPixelData = PoolByteArray() + var resulting_pixel_data = generate_pixel_data(newPixelData, shapePositionArray) + call_deferred("thread_done", resulting_pixel_data) + print("graphics multi_threaded end") + +func thread_done(resulting_pixel_data): + pixel_data = resulting_pixel_data + overheadImgData.create_from_data(M.xSize * 3, M.ySize * 3, false, Image.FORMAT_RGB8, pixel_data) + + overheadTexData.create_from_image(overheadImgData, 0) - overheadTexData.set_data(overheadImgData) + thread_currently_processing = false + emit_signal("graphics_thread_completed") - #overheadImgData.save_png("res://viewTextures.png") +func generate_pixel_data(pixData, shapePositionArray): + var width = M.xSize * 3 + var height = M.ySize * 3 + pixData.resize(width * height * 3) # Assuming RGB8 format + for pos in shapePositionArray: + var basePosX = pos.x * 3 + var basePosY = pos.y * 3 + for i in range(9): # 3x3 subtiles + var x = basePosX + (i % 3) + var y = basePosY + (i / 3) + var clmIndex = oDataClmPos.get_cell_clmpos(x, y) + var cubeFace = oDataClm.get_top_cube_face(clmIndex, 0) + var pixelIndex = ((y * width) + x) * 3 + + pixData[pixelIndex] = cubeFace >> 16 & 255 + pixData[pixelIndex + 1] = cubeFace >> 8 & 255 + pixData[pixelIndex + 2] = cubeFace & 255 + return pixData + func initialize_display_fields(): arrayOfColorRects.clear() # just in case @@ -97,152 +158,3 @@ func update_display_fields_size(): for displayField in arrayOfColorRects: displayField.rect_size = Vector2(M.xSize * 96, M.ySize * 96) displayField.material.set_shader_param("fieldSizeInSubtiles", Vector2((M.xSize*3), (M.ySize*3))) - -func get_overhead_face_value(x, y, slabID): - # clmIndex is a position inside the 2048 column collection - var clmIndex = oDataClmPos.get_cell(x, y) - - if clmIndex > 2048: - clmIndex = 0 - - # clmData is the 24 byte array. - var cubeFace = oDataClm.get_top_cube_face(clmIndex, slabID) - - var valueInput = cubeFace - var r = clamp(valueInput, 0, 255) - valueInput -= 255 - var g = clamp(valueInput, 0, 255) - valueInput -= 255 - var b = clamp(valueInput, 0, 255) - return Color8(r,g,b) - -func clear_img(): - if overheadImgData.is_empty() == false: - overheadImgData.fill(Color(0,0,0,1)) - overheadTexData.set_data(overheadImgData) - -#func _ready(): -# animImgData.create(8, 42, false, Image.FORMAT_RGB8) -# animTexData.create_from_image(animImgData, 0) -# map_anim_2d_textures() -# -#func map_anim_2d_textures(): -# var CODETIME_START = OS.get_ticks_msec() -# animImgData.lock() -# for y in 42: -# for x in 8: -# var col = get_anim_face_value(x, y) -# animImgData.set_pixel(x,y,col) -# animImgData.unlock() -# -# animImgData.save_png("textureanimationdatabase.png") -# -# animTexData.set_data(animImgData) -# material.set_shader_param("animationDatabase", animTexData) -# -# print('Anim graphics done in '+str(OS.get_ticks_msec()-CODETIME_START)+'ms') - -#func get_anim_face_value(x, y): -# var cubeFace = Cube.texAnim[(y * 8) + x] -# var valueInput = cubeFace -# var r = clamp(valueInput, 0, 255) -# valueInput -= 255 -# var g = clamp(valueInput, 0, 255) -# valueInput -= 255 -# var b = clamp(valueInput, 0, 255) -# #print(str(r)+' '+str(g)+' '+str(b)) -# return Color8(r,g,b) - -#func _ready(): -# var CODETIME_START = OS.get_ticks_msec() -# set_tex_anim_data_array() -# material.set_shader_param("animationDatabase", array2texture(TMAPDATA_ANIMATION, Vector2(8,42))) -# print('TMAPDATA_ANIMATION created in '+str(OS.get_ticks_msec()-CODETIME_START)+'ms') - -#func map_overhead_2d_textures(): -# var CODETIME_START = OS.get_ticks_msec() -# -# #290ms -# set_tex_data_array() -# #4ms -# material.set_shader_param("viewTextures", array2texture(TMAPDATA_OVERHEAD_2D, Vector2(255,255))) -# -# print('TMAPDATA_OVERHEAD_2D created in '+str(OS.get_ticks_msec()-CODETIME_START)+'ms') - - - - -#func set_tex_data_array(): -# #Array size needs to precisely match the array_width and array_height -# TMAPDATA_OVERHEAD_2D.clear() -# var height = 255 -# var width = 255 -# TMAPDATA_OVERHEAD_2D.resize(height * width * 3) -# for y in height: # Subtiles -# for x in width: -# update_overhead_face(x,y) -# -#func update_overhead_face(x, y): -# var cubeFace -# # clmIndex is a position inside the 2048 column collection -# var clmIndex = oDataClmPos.get_cell(x,y) -# # clmData is the 24 byte array. -# var clmData = oDataClm.data[clmIndex] -# #print(clmData) -# # Get the cubeIDs from that array -# var cubeID = oDataClm.get_highest_existing_cube(clmData) -# # Get the highest cubeID -# if cubeID != 0: -# # Get one of the 6 faces of the cube from the massive array of cube sides. -# -# cubeFace = Cube.tex[cubeID][Cube.SIDE_TOP] -# else: -# # Show floor texture because there were no cubes -# cubeFace = oDataClm.get_base(clmData) -# -# var valueInput = cubeFace -# -# var r = clamp(valueInput, 0, 255) -# valueInput -= 255 -# var g = clamp(valueInput, 0, 255) -# valueInput -= 255 -# var b = clamp(valueInput, 0, 255) -# -# var width = 255 -# -# var idx = ((y * width) + x) * 3 -# TMAPDATA_OVERHEAD_2D[idx+0] = r -# TMAPDATA_OVERHEAD_2D[idx+1] = g -# TMAPDATA_OVERHEAD_2D[idx+2] = b - -#func set_tex_anim_data_array(): -# TMAPDATA_ANIMATION.clear() -# var height = 42 -# var width = 8 -# TMAPDATA_ANIMATION.resize(height * width * 3) -# for y in height: -# for x in width: -# var cubeFace = Cube.texAnim[(y * 8) + x] -# -# var valueInput = cubeFace -# var r = clamp(valueInput, 0, 255) -# valueInput -= 255 -# var g = clamp(valueInput, 0, 255) -# valueInput -= 255 -# var b = clamp(valueInput, 0, 255) -# var idx = ((y * width) + x) * 3 -# TMAPDATA_ANIMATION[idx+0] = r -# TMAPDATA_ANIMATION[idx+1] = g -# TMAPDATA_ANIMATION[idx+2] = b -# -#func array2texture(array, size): -# var byte_array = PoolByteArray(array) -# var img = Image.new() -# var texture = ImageTexture.new() -# -# if array.size() > 0: -# img.create_from_data(size.x, size.y, false, Image.FORMAT_RGB8, byte_array) -# texture.create_from_image(img, 0) -# -# #img.save_png("png.png") -# return texture diff --git a/Scenes/OverheadOwnership.gd b/Scenes/OverheadOwnership.gd index f354d023..747755da 100644 --- a/Scenes/OverheadOwnership.gd +++ b/Scenes/OverheadOwnership.gd @@ -45,12 +45,13 @@ func clear(): slabOwnershipTexture.create_from_image(slabOwnershipImage, 0) func start(): + var CODETIME_START = OS.get_ticks_msec() slabOwnershipImage.create(M.xSize,M.ySize,false,Image.FORMAT_RGBA8) # Read ownership data as pixels slabOwnershipImage.lock() for ySlab in M.ySize: for xSlab in M.xSize: - var getOwner = oDataOwnership.get_cell(xSlab,ySlab) + var getOwner = oDataOwnership.get_cell_ownership(xSlab,ySlab) if getOwner <= 5: slabOwnershipImage.set_pixel(xSlab, ySlab, Constants.ownerRoomCol[getOwner]) slabOwnershipImage.unlock() @@ -60,6 +61,7 @@ func start(): #yield(get_tree(),'idle_frame') #print(oColorRectSlabOwner.rect_scale) #oColorRectSlabOwner.rect_position = Vector2(96,96) + print('overhead ownership (start): ' + str(OS.get_ticks_msec() - CODETIME_START) + 'ms') func ownership_paint_shape(shapePositionArray, ownership): @@ -69,7 +71,7 @@ func ownership_paint_shape(shapePositionArray, ownership): for pos in shapePositionArray: var slabID = oDataSlab.get_cell(pos.x, pos.y) if oSlabPlacement.slabID_is_ownable(slabID) == true: - oDataOwnership.set_cellv(pos, ownership) # Set cell data + oDataOwnership.set_cellv_ownership(pos, ownership) # Set cell data slabOwnershipImage.set_pixelv(pos, setColour) # Set image data slabOwnershipImage.unlock() @@ -78,7 +80,7 @@ func ownership_paint_shape(shapePositionArray, ownership): func update_ownership_image_based_on_shape(shapePositionArray): slabOwnershipImage.lock() for pos in shapePositionArray: - var ownership = oDataOwnership.get_cellv(pos) # Get cell data + var ownership = oDataOwnership.get_cellv_ownership(pos) # Get cell data var setColour = Constants.ownerRoomCol[ownership] slabOwnershipImage.set_pixelv(pos, setColour) # Set image data slabOwnershipImage.unlock() diff --git a/Scenes/PickSlabWindow.gd b/Scenes/PickSlabWindow.gd index 18da94c0..7622cd79 100644 --- a/Scenes/PickSlabWindow.gd +++ b/Scenes/PickSlabWindow.gd @@ -71,6 +71,7 @@ func update_selection_position(): func add_slabs(): + var CODETIME_START = OS.get_ticks_msec() clear_grid() oOnlyOwnership.initialize_grid_items() oSlabStyle.initialize_grid_items() @@ -121,6 +122,7 @@ func add_slabs(): if visible == true: set_selection(oSelection.paintSlab) # Default initial selection + print('add_slabs: ' + str(OS.get_ticks_msec() - CODETIME_START) + 'ms') func custom_slab_add_new_button(): var scene = preload('res://Scenes/GenericGridItem.tscn') diff --git a/Scenes/PickThingWindow.gd b/Scenes/PickThingWindow.gd index 56c2ef63..b7209466 100644 --- a/Scenes/PickThingWindow.gd +++ b/Scenes/PickThingWindow.gd @@ -61,9 +61,10 @@ func _ready(): func initialize_thing_grid_items(): yield(get_tree(),'idle_frame') # Needed for loading animation IDs from call_deferred in Things singleton + var CODETIME_START = OS.get_ticks_msec() remove_all_grid_items() - var CODETIME_START = OS.get_ticks_msec() + for thingCategory in [Things.TYPE.OBJECT, Things.TYPE.CREATURE, Things.TYPE.TRAP, Things.TYPE.DOOR, Things.TYPE.EFFECTGEN, Things.TYPE.EXTRA]: match thingCategory: @@ -185,10 +186,11 @@ func add_item_to_grid(tabID, id, set_text): id.connect("pressed",self,"pressed",[id]) id.rect_min_size = Vector2(grid_item_size.x * grid_window_scale, grid_item_size.y * grid_window_scale) - yield(get_tree(),'idle_frame') - var subtype = id.get_meta("thingSubtype") - if Things.LIST_OF_BOXES.has(subtype): - add_workshop_item_sprite_overlay(id, subtype) + #yield(get_tree(),'idle_frame') + if is_instance_valid(id) == true: + var subtype = id.get_meta("thingSubtype") + if Things.LIST_OF_BOXES.has(subtype): + add_workshop_item_sprite_overlay(id, subtype) func add_workshop_item_sprite_overlay(textureParent, subtype): var itemType = Things.LIST_OF_BOXES[subtype][0] diff --git a/Scenes/PlaceThingWithSlab.gd b/Scenes/PlaceThingWithSlab.gd index ba51f723..2690adc4 100644 --- a/Scenes/PlaceThingWithSlab.gd +++ b/Scenes/PlaceThingWithSlab.gd @@ -59,7 +59,7 @@ func create_door_thing(xSlab, ySlab, ownership): var doorID = oInstances.get_node_on_subtile(createAtPos.x, createAtPos.y, "Door") if is_instance_valid(doorID): rememberLockedState = doorID.doorLocked - doorID.queue_free() + oInstances.kill_instance(doorID) var id = oInstances.place_new_thing(Things.TYPE.DOOR, 0, createAtPos, ownership) id.doorLocked = rememberLockedState diff --git a/Scenes/QuickMapPreview.gd b/Scenes/QuickMapPreview.gd index cc581f63..6540d944 100644 --- a/Scenes/QuickMapPreview.gd +++ b/Scenes/QuickMapPreview.gd @@ -4,7 +4,7 @@ onready var oRNC = Nodelist.list["oRNC"] onready var oReadData = Nodelist.list["oReadData"] onready var oCamera2D = Nodelist.list["oCamera2D"] onready var oMapBrowserTabContainer = Nodelist.list["oMapBrowserTabContainer"] - +onready var oBuffers = Nodelist.list["oBuffers"] var img = Image.new() var tex = ImageTexture.new() @@ -103,7 +103,7 @@ func update_img(slbFilePath): elif File.new().file_exists(slbFilePath.get_basename()+".LOF") == true: lofFilePath = slbFilePath.get_basename()+".LOF" - var lofBuffer = Filetypes.file_path_to_buffer(lofFilePath) + var lofBuffer = oBuffers.file_path_to_buffer(lofFilePath) var xy = oReadData.read_mapsize_from_lof(lofBuffer) #print(xy) @@ -122,10 +122,10 @@ func update_img(slbFilePath): var ownBuffer = null if ownFilePath != "": - ownBuffer = Filetypes.file_path_to_buffer(ownFilePath) + ownBuffer = oBuffers.file_path_to_buffer(ownFilePath) ownBuffer.seek(0) - var slbBuffer = Filetypes.file_path_to_buffer(slbFilePath) + var slbBuffer = oBuffers.file_path_to_buffer(slbFilePath) slbBuffer.seek(0) var slabID diff --git a/Scenes/ReadData.gd b/Scenes/ReadData.gd index e0a90364..c718d521 100644 --- a/Scenes/ReadData.gd +++ b/Scenes/ReadData.gd @@ -15,21 +15,34 @@ onready var oDataFakeSlab = Nodelist.list["oDataFakeSlab"] onready var oDataLof = Nodelist.list["oDataLof"] onready var oMessage = Nodelist.list["oMessage"] -onready var TILE_SIZE = Constants.TILE_SIZE -onready var SUBTILE_SIZE = Constants.SUBTILE_SIZE - -#var tng_creation_order = [] -#var lgt_creation_order = [] -#var apt_creation_order = [] - var value # just so I don't have to initialize the var in every function +func read_mapsize_from_lof(buffer): + buffer.seek(0) + value = buffer.get_string(buffer.get_size()) + value = value.replace(char(0x200B), "") # Remove zero width spaces + var array = value.split("\n") + for line in array: + if line.begins_with(";"): + continue + + var lineParts = line.split("=") + + if lineParts.size() == 2: + if lineParts[0].strip_edges() == "MAPSIZE": + var sizeString = lineParts[1].strip_edges().split(" ") + if sizeString.size() == 2: + var x = sizeString[0].to_int() + var y = sizeString[1].to_int() + return Vector2(x,y) + return Vector2(85,85) + func read_lof(buffer): + buffer.seek(0) # Be sure to default to 85x85 in case it can't be read. oDataLof.use_size(85,85) oDataLof.KIND = "FREE" # Default to free if it can't be read. Goes ABOVE the check. - buffer.seek(0) value = buffer.get_string(buffer.get_size()) value = value.replace(char(0x200B), "") # Remove zero width spaces var array = value.split("\n") @@ -73,35 +86,15 @@ func read_lof(buffer): var y = sizeString[1].to_int() oDataLof.use_size(x,y) -func new_keeperfx_lof(): +func new_lof(): oDataLof.KIND = "FREE" -func read_mapsize_from_lof(buffer): - buffer.seek(0) - value = buffer.get_string(buffer.get_size()) - value = value.replace(char(0x200B), "") # Remove zero width spaces - var array = value.split("\n") - for line in array: - if line.begins_with(";"): - continue - - var lineParts = line.split("=") - - if lineParts.size() == 2: - if lineParts[0].strip_edges() == "MAPSIZE": - var sizeString = lineParts[1].strip_edges().split(" ") - if sizeString.size() == 2: - var x = sizeString[0].to_int() - var y = sizeString[1].to_int() - return Vector2(x,y) - return Vector2(85,85) - func read_slx(buffer): + buffer.seek(0) # 0 = Use map's original # 1 = Tileset 0 # 2 = Tileset 1 # 3 = Tileset 2, etc. - buffer.seek(0) oDataSlx.slxImgData.create(M.xSize, M.ySize, false, Image.FORMAT_RGB8) oDataSlx.slxTexData.create_from_image(oDataSlx.slxImgData, 0) oDataSlx.slxImgData.lock() @@ -120,35 +113,26 @@ func new_slx(): oDataSlx.slxTexData.create_from_image(oDataSlx.slxImgData, 0) func read_une(buffer): - buffer.seek(0) - for ySlab in M.ySize: - for xSlab in M.xSize: - value = buffer.get_u16() - oDataFakeSlab.set_cell(xSlab,ySlab,value) + oDataFakeSlab.initialize(M.xSize, M.ySize, 0, Grid.U16) + oDataFakeSlab.buffer.set_data_array(buffer.data_array) + func new_une(): - for ySlab in M.ySize: - for xSlab in M.xSize: - oDataFakeSlab.set_cell(xSlab,ySlab,0) + oDataFakeSlab.initialize(M.xSize, M.ySize, 0, Grid.U16) + func read_wlb(buffer): - buffer.seek(0) - for ySlab in M.ySize: - for xSlab in M.xSize: - value = buffer.get_u8() - oDataLiquid.set_cell(xSlab,ySlab,value) + oDataLiquid.initialize(M.xSize, M.ySize, 0, Grid.U8) + oDataLiquid.buffer.set_data_array(buffer.data_array) + func new_wlb(): - pass + oDataLiquid.initialize(M.xSize, M.ySize, 0, Grid.U8) func read_wib(buffer): - buffer.seek(0) - var dataHeight = (M.ySize*3)+1 - var dataWidth = (M.xSize*3)+1 - for subtileY in dataHeight: - for subtileX in dataWidth: - value = buffer.get_u8() - oDataWibble.set_cell(subtileX,subtileY,value) + oDataWibble.initialize((M.xSize * 3) + 1, (M.ySize * 3) + 1, 0, Grid.U8) + oDataWibble.buffer.set_data_array(buffer.data_array) + func new_wib(): - pass + oDataWibble.initialize((M.xSize * 3) + 1, (M.ySize * 3) + 1, 0, Grid.U8) func read_inf(buffer): buffer.seek(0) @@ -166,46 +150,25 @@ func new_txt(): pass func read_slb(buffer): - buffer.seek(0) - for ySlab in M.ySize: - for xSlab in M.xSize: - #print('x:' + str(xSlab) + " " + 'y:' + str(ySlab)) - value = buffer.get_u8() - buffer.get_u8() # skip second byte - oDataSlab.set_cell(xSlab,ySlab,value) + oDataSlab.initialize(M.xSize, M.ySize, 0, Grid.U16) + oDataSlab.buffer.set_data_array(buffer.data_array) + func new_slb(): - for ySlab in M.ySize: - for xSlab in M.xSize: - oDataSlab.set_cell(xSlab,ySlab,0) + oDataSlab.initialize(M.xSize, M.ySize, 0, Grid.U16) func read_own(buffer): - buffer.seek(0) - var dataHeight = (M.ySize*3)+1 - var dataWidth = (M.xSize*3)+1 - for ySubtile in dataHeight: - for xSubtile in dataWidth: - value = buffer.get_u8() - oDataOwnership.set_cell(xSubtile/3,ySubtile/3,value) + oDataOwnership.initialize((M.xSize*3)+1, (M.ySize*3)+1, 5, Grid.U8) + oDataOwnership.buffer.set_data_array(buffer.data_array) + func new_own(): - pass + oDataOwnership.initialize((M.xSize*3)+1, (M.ySize*3)+1, 5, Grid.U8) func read_dat(buffer): - buffer.seek(0) - var dataHeight = (M.ySize*3)+1 - var dataWidth = (M.xSize*3)+1 - for ySubtile in dataHeight: - for xSubtile in dataWidth: - #buffer.seek(2*(xSubtile + (ySubtile*dataWidth))) - value = 65536 - buffer.get_u16() - if value == 65536: value = 0 - - oDataClmPos.set_cell(xSubtile,ySubtile,value) + oDataClmPos.initialize((M.xSize*3)+1, (M.ySize*3)+1, 0, Grid.U16) + oDataClmPos.buffer.set_data_array(buffer.data_array) + func new_dat(): - var dataHeight = (M.ySize*3)+1 - var dataWidth = (M.xSize*3)+1 - for ySubtile in dataHeight: - for xSubtile in dataWidth: - oDataClmPos.set_cell(xSubtile,ySubtile,0) + oDataClmPos.initialize((M.xSize*3)+1, (M.ySize*3)+1, 0, Grid.U16) func read_clm(buffer): oDataClm.clear_all_column_data() @@ -228,15 +191,6 @@ func read_clm(buffer): oDataClm.lintel[entry] = get_lintel oDataClm.height[entry] = get_height -# var get_height = specialByte / 16 -# oDataClm.height.append(get_height) -# specialByte -= get_height * 16 -# var get_lintel = specialByte / 2 -# oDataClm.lintel.append(get_lintel) -# specialByte -= get_lintel * 2 -# var get_permanent = specialByte -# oDataClm.permanent.append(get_permanent) - oDataClm.solidMask[entry] = buffer.get_u16() # 3-4 oDataClm.floorTexture[entry] = buffer.get_u16() # 5-6 oDataClm.orientation[entry] = buffer.get_u8() # 7 @@ -316,6 +270,7 @@ func new_lgt(): pass func read_lgtfx(buffer): + buffer.seek(0) value = buffer.get_string(buffer.get_size()) value = value.replace(char(0x200B), "") # Remove zero width spaces @@ -414,6 +369,7 @@ func new_tng(): pass func read_tngfx(buffer): + buffer.seek(0) value = buffer.get_string(buffer.get_size()) value = value.replace(char(0x200B), "") # Remove zero width spaces @@ -497,6 +453,8 @@ func new_tngfx(): func read_aptfx(buffer): + buffer.seek(0) + value = buffer.get_string(buffer.get_size()) value = value.replace(char(0x200B), "") # Remove zero width spaces @@ -527,50 +485,8 @@ func read_aptfx(buffer): func new_aptfx(): pass -# var bufferPos = 0 -# buffer.seek(bufferPos) -# # These are unused for now but they can be used for extending maximum TNG entries beyond 65,535 -# var numberOfTngEntries = buffer.get_u32() -# var numberOfLgtEntries = buffer.get_u32() -# var numberOfAptEntries = buffer.get_u32() -# bufferPos += 12 -# -# for entry in tng_creation_order.size(): -# bufferPos += (entry * 256) -# buffer.seek(bufferPos) -# var id = tng_creation_order[entry] -# id.locationX = buffer.get_u32() + (id.locationX - int(id.locationX)) # 0-3 -# id.locationY = buffer.get_u32() + (id.locationY - int(id.locationY)) # 4-7 -# id.locationZ = buffer.get_u32() + (id.locationZ - int(id.locationZ)) # 8-11 -# # Unused : 12-255 -# -# for entry in lgt_creation_order.size(): -# bufferPos += (entry * 256) -# buffer.seek(bufferPos) -# var id = lgt_creation_order[entry] -# id.locationX = buffer.get_u32() + (id.locationX - int(id.locationX)) # 0-3 -# id.locationY = buffer.get_u32() + (id.locationY - int(id.locationY)) # 4-7 -# id.locationZ = buffer.get_u32() + (id.locationZ - int(id.locationZ)) # 8-11 -# # Unused : 12-255 -# -# for entry in apt_creation_order.size(): -# bufferPos += (entry * 256) -# buffer.seek(bufferPos) -# var id = apt_creation_order[entry] -# id.locationX = buffer.get_u32() + (id.locationX - int(id.locationX)) # 0-3 -# id.locationY = buffer.get_u32() + (id.locationY - int(id.locationY)) # 4-7 -# # Unused : 12-255 - -#func _ready(): #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# var file = File.new() -# file.open("res://unearthdata/dklevels.lof",File.READ) -# var buffer = StreamPeerBuffer.new() -# buffer.data_array = file.get_buffer(file.get_len()) -# file.close() -# -# read_lif(buffer) - func read_lif(buffer): + buffer.seek(0) var array = lif_buffer_to_array(buffer) var mapName = lif_array_to_map_name(array) oDataMapName.set_map_name(mapName) @@ -607,70 +523,3 @@ func lif_array_to_map_name(array): # Read map name normally return array[0][1] - - - - - - - - - - - - - - - - - - - - - - - - - - - -#func parse_lif_text(file): -# #I'm using get_csv_line() which means the lines MUST have commas separating the values. -# var array = [] -# while true: -# var stringArray = file.get_csv_line() -# if stringArray.size() > 1: -# stringArray[0] = stringArray[0].strip_edges(true,true) -# stringArray[1] = stringArray[1].strip_edges(true,true) -# -# # If second array has Translation ID (so it looks like #201 or something), then read the next line. -# if "#" in stringArray[1]: -# stringArray[1] = file.get_line().trim_prefix(';') -# array.append(stringArray) -# else: -# break -# # Array can look like this: [[80, Morkardar], [81, Korros Tor], [82, Kari-Mar], [83, Belbata], [84, Caddis Fell], [85, Pladitz], [86, Abbadon], [87, Svatona], [88, Kanasko], [91, Netzcaro], [93, Batezek], [94, Benetzaron], [95, Daka-Gorn], [97, Dixaroc], [92, Belial]] -# # Or like this if there's only one entry: [[80, Morkardar]] -# return array - - - - - - - - # Move to the next character until a number isn't found - # Then strip spaces and commas from the beginning - -# var string = buffer.get_as_text() -# var newString = "" -# for i in string.length(): -# if string.substr(i,1).is_valid_integer() == false: -# -# # Get rid of comma if there's one -# if string.substr(i,1) == ",": -# i+=1 -# -# newString = string.right(i) -# break -# return newString.strip_edges(true,true) diff --git a/Scenes/ReadPalette.gd b/Scenes/ReadPalette.gd index c652d368..9ad07734 100644 --- a/Scenes/ReadPalette.gd +++ b/Scenes/ReadPalette.gd @@ -1,4 +1,5 @@ extends Node +onready var oBuffers = Nodelist.list["oBuffers"] var dictionary = {} # Just two different ways to read the palette, for speed. @@ -6,7 +7,7 @@ func read_palette(path): var array = [] array.resize(256) - var buffer = Filetypes.file_path_to_buffer(path) + var buffer = oBuffers.file_path_to_buffer(path) if buffer.get_size() > 0: for i in 256: # File has a size of 768 bytes but we get 3 values each loop # Multiply by 4 because colors are 0-63 instead of 0-255 diff --git a/Scenes/ResizeCurrentMapSize.gd b/Scenes/ResizeCurrentMapSize.gd index 207c5712..1032b9a6 100644 --- a/Scenes/ResizeCurrentMapSize.gd +++ b/Scenes/ResizeCurrentMapSize.gd @@ -15,6 +15,7 @@ onready var oLoadingBar = Nodelist.list["oLoadingBar"] onready var oDataClmPos = Nodelist.list["oDataClmPos"] onready var oCurrentFormat = Nodelist.list["oCurrentFormat"] onready var oMapSettingsWindow = Nodelist.list["oMapSettingsWindow"] +onready var oInstances = Nodelist.list["oInstances"] func _on_ResizeCurrentMapSizeButton_pressed(): Utils.popup_centered(self) @@ -77,7 +78,7 @@ func remove_outside_instances(newWidth, newHeight): for instance in get_tree().get_nodes_in_group("Instance"): if instance.locationX >= newWidthInSubtiles or instance.locationY >= newHeightInSubtiles: deletedInstancesCount += 1 - instance.queue_free() + oInstances.kill_instance(instance) if deletedInstancesCount > 0: oMessage.quick("Deleted " + str(deletedInstancesCount) + " instances that were outside of the new map size.") @@ -85,7 +86,7 @@ func remove_outside_instances(newWidth, newHeight): func update_editor_appearance(): oEditor.update_boundaries() oOverheadOwnership.start() - oOverheadGraphics.update_map_overhead_2d_textures() + oOverheadGraphics.update_full_overhead_map() # The main function that calls all the helper functions func _on_ResizeApplyButton_pressed(): @@ -123,7 +124,7 @@ func set_various_grid_data(newWidth, newHeight, previousWidth, previousHeight): for x in prevWidthInSubtiles: for y in prevHeightInSubtiles: if x >= newWidthInSubtiles or y >= newHeightInSubtiles: - oDataClmPos.set_cell(x, y, 0) + oDataClmPos.set_cell_clmpos(x, y, 0) @@ -168,7 +169,7 @@ func _on_ResizeFillWithID_value_changed(value): # # oEditor.update_boundaries() # oOverheadOwnership.start() -# oOverheadGraphics.update_map_overhead_2d_textures() +# oOverheadGraphics.update_full_overhead_map() # # # Apply changes for added positions # oSlabPlacement.place_shape_of_slab_id(positionsToUpdate.keys(), Slabs.EARTH, 5) diff --git a/Scenes/SaveMap.gd b/Scenes/SaveMap.gd index bd9e6da9..2cc1b1ea 100644 --- a/Scenes/SaveMap.gd +++ b/Scenes/SaveMap.gd @@ -1,6 +1,6 @@ extends Node + onready var oGame = Nodelist.list["oGame"] -onready var oWriteData = Nodelist.list["oWriteData"] onready var oMessage = Nodelist.list["oMessage"] onready var oEditor = Nodelist.list["oEditor"] onready var oCurrentMap = Nodelist.list["oCurrentMap"] @@ -10,59 +10,55 @@ onready var oScriptEditor = Nodelist.list["oScriptEditor"] onready var oMenu = Nodelist.list["oMenu"] onready var oCurrentFormat = Nodelist.list["oCurrentFormat"] onready var oDataClm = Nodelist.list["oDataClm"] +onready var oBuffers = Nodelist.list["oBuffers"] var queueExit = false func save_map(filePath): # auto opens other files var map = filePath.get_basename() - var SAVETIME_START = OS.get_ticks_msec() - delete_existing_files(map) - var writeFailure = false + oDataClm.update_all_utilized() # Doesn't need to be in "Undo" - for EXT in Filetypes.FILE_TYPES: - - # List of file extensions to skip creating - # Remember "continue" means skip - if oCurrentFormat.selected == 0: # Classic format - if ["LOF","TNGFX","APTFX","LGTFX"].has(EXT): - continue # skip saving this filetype - elif oCurrentFormat.selected == 1: # KFX format - if ["LIF","TNG","APT","LGT"].has(EXT): - continue # skip saving this filetype + var writeFailure = false + for EXT in oBuffers.FILE_TYPES: + if not oBuffers.should_process_file_type(EXT): + continue # skip saving this filetype var saveToFilePath = map + '.' + EXT.to_lower() - - var err = Filetypes.write(saveToFilePath, EXT.to_upper()) + var err = oBuffers.write(saveToFilePath, EXT.to_upper()) if err != OK: writeFailure = true + var getModifiedTime = File.new().get_modified_time(saveToFilePath) oCurrentMap.currentFilePaths[EXT] = [saveToFilePath, getModifiedTime] if writeFailure == true: - oMessage.big("Error","Saving failed. Try saving to a different directory.") + oMessage.big("Error", "Saving failed. Try saving to a different directory.") else: print('Total time to save: ' + str(OS.get_ticks_msec() - SAVETIME_START) + 'ms') + if oDataScript.data == "": - oMessage.big("Warning","Your map has no script. Use the Script Generator in Map Settings to give your map basic functionality.") + oMessage.big("Warning", "Your map has no script. Use the Script Generator in Map Settings to give your map basic functionality.") + oMessage.quick('Saved map') oCurrentMap.set_path_and_title(filePath) oEditor.mapHasBeenEdited = false oScriptEditor.set_script_as_edited(false) oDataClm.store_default_data() # This makes it so the map Column Editor's default columns are now reflected as "what's saved" oMapSettingsWindow.visible = false + # This goes last. Queued from when doing "save before quitting" and "save as" before quitting. if queueExit == true: get_tree().quit() func delete_existing_files(map): - var fileTypesToDelete = [] + var fileTypesToDelete = [] if OS.get_name() == "X11": # Important for Linux to delete all files otherwise duplicates can be created. (Lowercase files can be saved without replacing the uppercase files) - fileTypesToDelete = Filetypes.FILE_TYPES + fileTypesToDelete = oBuffers.FILE_TYPES else: # If switching formats, then it's important to delete files of the other format (TNG and TNGFX shouldn't exist at the same time) if oCurrentFormat.selected == 0: # Classic format @@ -73,6 +69,7 @@ func delete_existing_files(map): var baseDirectory = map.get_base_dir() var MAP_NAME = map.get_basename().get_file().to_upper() + var dir = Directory.new() if dir.open(baseDirectory) == OK: dir.list_dir_begin(true, false) @@ -81,7 +78,6 @@ func delete_existing_files(map): if MAP_NAME in fileName.to_upper(): # Only delete the accompanying file types that I'm about to write if fileTypesToDelete.has(fileName.get_extension().to_upper()): - if dir.file_exists(fileName) == true: # Ensure any files being removed are definitely files and never directories print("Deleted: " + fileName) dir.remove(fileName) @@ -91,15 +87,3 @@ func delete_existing_files(map): func clicked_save_on_menu(): save_map(oCurrentMap.path) - -# if File.new().file_exists(path + ".slb") == true: -# mapPathSave = path -# oConfirmOverwrite.Utils.popup_centered(self) -# else: -# oSaveMap.save_map(path) -# hide() -# -#var mapPathSave # set before popping up the overwrite confirmation box -#func _on_ConfirmOverwrite_confirmed(): -# oSaveMap.save_map(mapPathSave) -# hide() diff --git a/Scenes/ScriptEditor.gd b/Scenes/ScriptEditor.gd index 06f06f87..fb2f8872 100644 --- a/Scenes/ScriptEditor.gd +++ b/Scenes/ScriptEditor.gd @@ -8,6 +8,7 @@ onready var oScriptEmptyStatus = Nodelist.list["oScriptEmptyStatus"] onready var oScriptHelpers = Nodelist.list["oScriptHelpers"] onready var oUi = Nodelist.list["oUi"] onready var oMapSettingsTabs = Nodelist.list["oMapSettingsTabs"] +onready var oBuffers = Nodelist.list["oBuffers"] var scriptHasBeenEditedInUnearth = false @@ -87,7 +88,7 @@ func check_if_txt_file_has_been_modified(): oMessage.quick("Script reloaded from file.") #"Script was reloaded from file." oCurrentMap.currentFilePaths["TXT"][oCurrentMap.MODIFIED_DATE] = getModifiedTime # Reload - Filetypes.read(filePath, "TXT") + oBuffers.read(filePath, "TXT") update_texteditor() set_script_as_edited(false) diff --git a/Scenes/ScriptGenerator.gd b/Scenes/ScriptGenerator.gd index f9277c9c..680013f0 100644 --- a/Scenes/ScriptGenerator.gd +++ b/Scenes/ScriptGenerator.gd @@ -186,11 +186,12 @@ func initialize_researchables(): if what == IS_MAGIC: for checkAll in listMagic: if checkAll[0] == ID: - idItem.hint_tooltip = Things.DATA_OBJECT[ID][Things.NAME] - idItem.set_meta("variable",checkAll[1]) # function text - idItem.set_meta("ID", ID) - idItem.type = idItem.MAGIC - idItem.set_magic_texture(ID) + if Things.DATA_OBJECT.has(ID): + idItem.hint_tooltip = Things.DATA_OBJECT[ID][Things.NAME] + idItem.set_meta("variable",checkAll[1]) # function text + idItem.set_meta("ID", ID) + idItem.type = idItem.MAGIC + idItem.set_magic_texture(ID) break elif what == IS_ROOM: for checkAll in listRoom: diff --git a/Scenes/Selection.gd b/Scenes/Selection.gd index 95332407..22cd104a 100644 --- a/Scenes/Selection.gd +++ b/Scenes/Selection.gd @@ -84,9 +84,10 @@ func newPaintSubtype(value): oOwnerSelection.collectible_ownership_mode(false) if paintThingType == Things.TYPE.OBJECT: - var genre = Things.DATA_OBJECT[paintSubtype][Things.EDITOR_TAB] - if Things.collectible_belonging.has(genre): - oOwnerSelection.collectible_ownership_mode(true) + if Things.DATA_OBJECT.has(paintSubtype): + var genre = Things.DATA_OBJECT[paintSubtype][Things.EDITOR_TAB] + if Things.collectible_belonging.has(genre): + oOwnerSelection.collectible_ownership_mode(true) func newOwnership(value): @@ -101,7 +102,7 @@ func newPaintSlab(value): func update_under_cursor(): cursorOverSlab = oSelector.get_slabID_at_pos(oSelector.cursorTile) - cursorOverSlabOwner = oDataOwnership.get_cellv(oSelector.cursorTile) + cursorOverSlabOwner = oDataOwnership.get_cellv_ownership(oSelector.cursorTile) oSlabSideViewer.update_side() func update_paint(): @@ -252,7 +253,7 @@ func place_subtile(placeSubtile): oEditor.mapHasBeenEdited = true if paintThingType != null: - var detectTerrainHeight = oDataClm.height[oDataClmPos.get_cell(placeSubtile.x,placeSubtile.y)] + var detectTerrainHeight = oDataClm.height[oDataClmPos.get_cell_clmpos(placeSubtile.x, placeSubtile.y)] var newPos:Vector3 = Vector3(placeSubtile.x + 0.5, placeSubtile.y + 0.5, detectTerrainHeight) match paintThingType: @@ -292,7 +293,7 @@ func manually_delete_one_instance(inst): if oMirrorPlacementCheckBox.pressed == true: oInstances.mirror_deletion_of_instance(inst) - inst.queue_free() + oInstances.kill_instance(inst) #func ui_hover(): # if oSelector.cursorIsOnGrid == true: diff --git a/Scenes/Selector.gd b/Scenes/Selector.gd index e1a513be..296493ce 100644 --- a/Scenes/Selector.gd +++ b/Scenes/Selector.gd @@ -166,6 +166,7 @@ func mouse_button_on_field(): # Release button if Input.is_action_just_released("mouse_left"): + OS.move_window_to_foreground() # See if this helps any issues which cause Unearth minimize button to stop working. if is_instance_valid(holdClickOnInstance): if draggingInstance == true: draggingInstance = false @@ -177,7 +178,7 @@ func mouse_button_on_field(): # Readjust the thing's height when dragging it from different heights if holdClickOnInstance.locationZ != 2.875: # don't knock torches onto the ground if dragging them (accidental clicks would knock them down too) - var detectTerrainHeight = oDataClm.height[oDataClmPos.get_cellv(snapToPos)] + var detectTerrainHeight = oDataClm.height[oDataClmPos.get_cell_clmpos(snapToPos.x,snapToPos.y)] holdClickOnInstance.locationZ = detectTerrainHeight oInstances.mirror_adjusted_value(holdClickOnInstance, "locationXYZ", originalPosition) @@ -233,7 +234,7 @@ func mouse_button_on_field(): for inst in nodesOnSlab: if oMirrorPlacementCheckBox.pressed == true: oInstances.mirror_deletion_of_instance(inst) - inst.queue_free() + oInstances.kill_instance(inst) oThingDetails.update_details() @@ -297,7 +298,7 @@ func moved_to_new_subtile(): if mode == MODE_SUBTILE: canPlace = true if oUseSlabOwnerCheckBox.pressed == true and visible == true: - oSelection.paintOwnership = oDataOwnership.get_cellv(cursorTile) + oSelection.paintOwnership = oDataOwnership.get_cellv_ownership(cursorTile) #func fadeOutWalls(delta): # if Slabs.array[oSelection.cursorOverSlab][Slabs.SIDE_OF] == Slabs.SIDE_SLAB: diff --git a/Scenes/SlabDisplay.gd b/Scenes/SlabDisplay.gd index bfa5990d..1b064314 100644 --- a/Scenes/SlabDisplay.gd +++ b/Scenes/SlabDisplay.gd @@ -47,13 +47,7 @@ func set_visual(columnArray): # Slabset slab (normal slab) cubeFace = Columnset.get_top_cube_face(columnArray[(y*3) + x], slabID) - var valueInput = cubeFace - var r = clamp(valueInput, 0, 255) - valueInput -= 255 - var g = clamp(valueInput, 0, 255) - valueInput -= 255 - var b = clamp(valueInput, 0, 255) - dataImage.set_pixel(x, y, Color8(r,g,b)) + dataImage.set_pixel(x, y, Color8(cubeFace >> 16 & 255, cubeFace >> 8 & 255, cubeFace & 255)) if panelView == Slabs.PANEL_SIDE_VIEW or panelView == Slabs.PANEL_DOOR_VIEW: var y = 2 @@ -67,14 +61,7 @@ func set_visual(columnArray): var cubeID = Columnset.cubes[clmIndex][sideViewZoffset-z] var cubeFace = Cube.tex[cubeID][Cube.SIDE_SOUTH] - - var valueInput = cubeFace - var r = clamp(valueInput, 0, 255) - valueInput -= 255 - var g = clamp(valueInput, 0, 255) - valueInput -= 255 - var b = clamp(valueInput, 0, 255) - dataImage.set_pixel(x, z, Color8(r,g,b)) + dataImage.set_pixel(x, z, Color8(cubeFace >> 16 & 255, cubeFace >> 8 & 255, cubeFace & 255)) dataImage.unlock() diff --git a/Scenes/SlabNameDisplay.gd b/Scenes/SlabNameDisplay.gd index 75fd7222..ca2724a4 100644 --- a/Scenes/SlabNameDisplay.gd +++ b/Scenes/SlabNameDisplay.gd @@ -12,4 +12,4 @@ func _process(delta): slabName = Slabs.data[slabID][Slabs.NAME] text = slabName + ' : ' + str(slabID) - #get_parent().self_modulate = Constants.ownerRoomCol[oDataOwnership.get_cell(oSelector.cursorTile.x,oSelector.cursorTile.y)] + #get_parent().self_modulate = Constants.ownerRoomCol[oDataOwnership.get_cell_ownership(oSelector.cursorTile.x,oSelector.cursorTile.y)] diff --git a/Scenes/SlabPalette.gd b/Scenes/SlabPalette.gd index 45dbfeb2..d05b3f6c 100644 --- a/Scenes/SlabPalette.gd +++ b/Scenes/SlabPalette.gd @@ -508,7 +508,7 @@ extends Node # var value = Columnset.dat[slabVariation][subtile] # slab variation - subtile of that variation # var ySubtile = subtile/3 # var xSubtile = subtile-(ySubtile*3) -# oDataClmPos.set_cell( (xSlab*3)+xSubtile, (ySlab*3)+ySubtile, value) +# oDataClmPos.set_cell_clmpos( (xSlab*3)+xSubtile, (ySlab*3)+ySubtile, value) #func update_slab_palette_for_map(): # var dictionary = {} diff --git a/Scenes/SlabPlacement.gd b/Scenes/SlabPlacement.gd index 22bc11e8..7ed9186d 100644 --- a/Scenes/SlabPlacement.gd +++ b/Scenes/SlabPlacement.gd @@ -106,14 +106,14 @@ func mirror_placement(shapePositionArray, mirrorWhat): if calculateOwner == true: if oMirrorOptions.ui_quadrants_have_owner(mainPaint) == false: - oDataOwnership.set_cellv(toPos, mainPaint) + oDataOwnership.set_cellv_ownership(toPos, mainPaint) else: if mainPaint == quadrantDestinationOwner: - oDataOwnership.set_cellv(toPos, quadrantClickedOnOwner) + oDataOwnership.set_cellv_ownership(toPos, quadrantClickedOnOwner) else: match oMirrorOptions.splitType: 0,1: - oDataOwnership.set_cellv(toPos, quadrantDestinationOwner) + oDataOwnership.set_cellv_ownership(toPos, quadrantDestinationOwner) 2: var otherTwoQuadrants = [] for i in 4: @@ -123,11 +123,11 @@ func mirror_placement(shapePositionArray, mirrorWhat): if otherTwoQuadrants.size() == 2: if quadrantDestinationOwner == otherTwoQuadrants[0]: - oDataOwnership.set_cellv(toPos, otherTwoQuadrants[1]) + oDataOwnership.set_cellv_ownership(toPos, otherTwoQuadrants[1]) else: - oDataOwnership.set_cellv(toPos, otherTwoQuadrants[0]) + oDataOwnership.set_cellv_ownership(toPos, otherTwoQuadrants[0]) else: - oDataOwnership.set_cellv(toPos, quadrantDestinationOwner) + oDataOwnership.set_cellv_ownership(toPos, quadrantDestinationOwner) # Always add position to mirroredPositionArray, decide what to do with the positions after the loop is done. mirroredPositionArray.append(toPos) @@ -161,7 +161,7 @@ func place_shape_of_slab_id(shapePositionArray, slabID, ownership): #var CODETIME_START = OS.get_ticks_msec() for pos in shapePositionArray: - oDataOwnership.set_cellv(pos, ownership) + oDataOwnership.set_cellv_ownership(pos, ownership) if slabID < 1000: oDataFakeSlab.set_cellv(pos, 0) @@ -220,7 +220,7 @@ func place_shape_of_slab_id(shapePositionArray, slabID, ownership): var surrSlab = oDataSlab.get_cellv(threePos) # Only IDs that are EARTH or EARTH_WITH_TORCH will become fortified walls. if surrSlab == Slabs.EARTH or surrSlab == Slabs.EARTH_WITH_TORCH: - oDataOwnership.set_cellv(threePos, ownership) + oDataOwnership.set_cellv_ownership(threePos, ownership) #var autoWallID = auto_wall(threePos.x, threePos.y, slabID) oDataSlab.set_cellv(threePos, Slabs.WALL_AUTOMATIC) shapePositionArray.append(threePos) @@ -248,7 +248,7 @@ func generate_slabs_based_on_id(shapePositionArray, updateNearby): if oOnlyOwnership.visible == true and autogen_was_called == false: for pos in shapePositionArray: var slabID = oDataSlab.get_cell(pos.x, pos.y) - var ownership = oDataOwnership.get_cell(pos.x, pos.y) + var ownership = oDataOwnership.get_cell_ownership(pos.x, pos.y) if Slabs.data.has(slabID): oInstances.manage_thing_ownership_on_slab(pos.x, pos.y, ownership) @@ -297,7 +297,7 @@ func generate_slabs_based_on_id(shapePositionArray, updateNearby): for pos in shapePositionArray: var slabID = oDataSlab.get_cell(pos.x, pos.y) - var ownership = oDataOwnership.get_cell(pos.x, pos.y) + var ownership = oDataOwnership.get_cell_ownership(pos.x, pos.y) if Slabs.data.has(slabID): do_slab(pos.x, pos.y, slabID, ownership) @@ -314,8 +314,8 @@ func generate_slabs_based_on_id(shapePositionArray, updateNearby): #print('Generated slabs in : '+str(OS.get_ticks_msec()-CODETIME_START)+'ms') - oOverheadGraphics.overhead2d_update_rect(shapePositionArray) - + oOverheadGraphics.overhead2d_update_rect_single_threaded(shapePositionArray) + func do_update_auto_walls(slabID): # If this ID has been set to WALL_AUTOMATIC, by whatever reason, then it must be updated. This doesn't mean you're placing a WALL_AUTOMATIC, just that this slab has been set to it. @@ -405,7 +405,7 @@ func _on_ConfirmAutoGen_confirmed(): shapePositionArray.append(Vector2(xSlab,ySlab)) autogen_was_called = true - generate_slabs_based_on_id(shapePositionArray, updateNearby) + yield(generate_slabs_based_on_id(shapePositionArray, updateNearby), "completed") autogen_was_called = false print('Auto-generated all slabs: ' + str(OS.get_ticks_msec() - CODETIME_START) + 'ms') @@ -743,15 +743,16 @@ func slabset_position_to_column_data(slabsetIndexGroup, ownership): # for i in 9: # var ySubtile = positionsArray3x3[i].y#i/3 # var xSubtile = positionsArray3x3[i].x#i - (ySubtile*3) -# oDataClmPos.set_cell((xSlab*3)+xSubtile, (ySlab*3)+ySubtile, array[i]) +# oDataClmPos.set_cell_clmpos((xSlab*3)+xSubtile, (ySlab*3)+ySubtile, array[i]) func set_columns(xSlab, ySlab, constructedColumns, constructedFloor): + oDataClm.a_column_has_changed_since_last_updating_utilized = true for i in 9: var clmIndex = oDataClm.index_entry(constructedColumns[i], constructedFloor[i]) var ySubtile = i/3 var xSubtile = i - (ySubtile*3) - oDataClmPos.set_cell((xSlab*3)+xSubtile, (ySlab*3)+ySubtile, clmIndex) + oDataClmPos.set_cell_clmpos((xSlab*3)+xSubtile, (ySlab*3)+ySubtile, clmIndex) func get_tall_bitmask(surrID): var bitmask = 0 @@ -762,10 +763,10 @@ func get_tall_bitmask(surrID): return bitmask func get_wall_bitmask(xSlab, ySlab, surrID, ownership): - var ownerS = oDataOwnership.get_cell(xSlab, ySlab+1) - var ownerW = oDataOwnership.get_cell(xSlab-1, ySlab) - var ownerN = oDataOwnership.get_cell(xSlab, ySlab-1) - var ownerE = oDataOwnership.get_cell(xSlab+1, ySlab) + var ownerS = oDataOwnership.get_cell_ownership(xSlab, ySlab+1) + var ownerW = oDataOwnership.get_cell_ownership(xSlab-1, ySlab) + var ownerN = oDataOwnership.get_cell_ownership(xSlab, ySlab-1) + var ownerE = oDataOwnership.get_cell_ownership(xSlab+1, ySlab) if ownerS == 5: ownerS = ownership # If next to a Player 5 wall, treat it as earth, don't put up a wall against it. if ownerW == 5: ownerW = ownership if ownerN == 5: ownerN = ownership @@ -822,14 +823,14 @@ func get_surrounding_slabIDs(xSlab, ySlab): func get_surrounding_ownership(xSlab, ySlab): var surrOwner = [] surrOwner.resize(8) - surrOwner[dir.n] = oDataOwnership.get_cell(xSlab, ySlab-1) - surrOwner[dir.s] = oDataOwnership.get_cell(xSlab, ySlab+1) - surrOwner[dir.e] = oDataOwnership.get_cell(xSlab+1, ySlab) - surrOwner[dir.w] = oDataOwnership.get_cell(xSlab-1, ySlab) - surrOwner[dir.ne] = oDataOwnership.get_cell(xSlab+1, ySlab-1) - surrOwner[dir.nw] = oDataOwnership.get_cell(xSlab-1, ySlab-1) - surrOwner[dir.se] = oDataOwnership.get_cell(xSlab+1, ySlab+1) - surrOwner[dir.sw] = oDataOwnership.get_cell(xSlab-1, ySlab+1) + surrOwner[dir.n] = oDataOwnership.get_cell_ownership(xSlab, ySlab-1) + surrOwner[dir.s] = oDataOwnership.get_cell_ownership(xSlab, ySlab+1) + surrOwner[dir.e] = oDataOwnership.get_cell_ownership(xSlab+1, ySlab) + surrOwner[dir.w] = oDataOwnership.get_cell_ownership(xSlab-1, ySlab) + surrOwner[dir.ne] = oDataOwnership.get_cell_ownership(xSlab+1, ySlab-1) + surrOwner[dir.nw] = oDataOwnership.get_cell_ownership(xSlab-1, ySlab-1) + surrOwner[dir.se] = oDataOwnership.get_cell_ownership(xSlab+1, ySlab+1) + surrOwner[dir.sw] = oDataOwnership.get_cell_ownership(xSlab-1, ySlab+1) return surrOwner diff --git a/Scenes/ThingInstance.gd b/Scenes/ThingInstance.gd index 84e7e81c..4bb05f9c 100644 --- a/Scenes/ThingInstance.gd +++ b/Scenes/ThingInstance.gd @@ -318,7 +318,7 @@ func update_spinning_key(): # Called after changing the lock state # Door is unlocked if is_instance_valid(keyID) == true: # There's a key, so remove it - keyID.queue_free() + oInstances.kill_instance(keyID) else: # Door is locked if is_instance_valid(keyID) == false: diff --git a/Scenes/ThreadedSaveUndo.gd b/Scenes/ThreadedSaveUndo.gd new file mode 100644 index 00000000..583c7e46 --- /dev/null +++ b/Scenes/ThreadedSaveUndo.gd @@ -0,0 +1,45 @@ +extends Node + +onready var oBuffers = Nodelist.list["oBuffers"] +onready var oUndoStates = Nodelist.list["oUndoStates"] +onready var oCurrentMap = Nodelist.list["oCurrentMap"] +onready var oMessage = Nodelist.list["oMessage"] + +var semaphore = Semaphore.new() +var thread = Thread.new() + +func _enter_tree(): + thread.start(self, "run_threaded_undo_save") + +func run_threaded_undo_save(_userdata): + while true: + semaphore.wait() + print("Start multi-threaded save undo state") + var CODETIME_START = OS.get_ticks_msec() + + var consistent_state = {} + # Repeat the data capture until the captured state is consistent + while true: + consistent_state = create_state() + var compare_state = create_state() + + # For some reason TNGFX occasionally breaks + if compare_state.has("TNGFX") and compare_state["TNGFX"] == null: + oMessage.big("Undo state error", "TNGFX buffer broke") + continue + if oUndoStates.are_states_equal(consistent_state, compare_state): + break + + # The captured state is consistent, save it as the undo state + oUndoStates.call_deferred("on_undo_state_saved", consistent_state) + print("End multi-threaded save undo state: " + str(OS.get_ticks_msec() - CODETIME_START) + "ms") + +func create_state(): + var new_state = {} + for EXT in oBuffers.FILE_TYPES: + #print("Undo processing: ", EXT) + if oBuffers.should_process_file_type(EXT) == false: + continue + new_state[EXT] = oBuffers.get_buffer_for_extension(EXT, oCurrentMap.path) + return new_state + diff --git a/Scenes/UndoStates.gd b/Scenes/UndoStates.gd new file mode 100644 index 00000000..df12f511 --- /dev/null +++ b/Scenes/UndoStates.gd @@ -0,0 +1,113 @@ +extends Node + +onready var oCurrentFormat = Nodelist.list["oCurrentFormat"] +onready var oBuffers = Nodelist.list["oBuffers"] +onready var oCurrentMap = Nodelist.list["oCurrentMap"] +onready var oOpenMap = Nodelist.list["oOpenMap"] +onready var oMessage = Nodelist.list["oMessage"] +onready var oThreadedSaveUndo = Nodelist.list["oThreadedSaveUndo"] +onready var oLoadingBar = Nodelist.list["oLoadingBar"] +onready var oNewMapWindow = Nodelist.list["oNewMapWindow"] +onready var oEditor = Nodelist.list["oEditor"] +onready var oMenu = Nodelist.list["oMenu"] + + +var is_saving_state = false +var undo_history = [] +var max_undo_states = 256 +var performing_undo = false + +func _input(event): + if event.is_action_pressed("undo"): + perform_undo() + + +func clear_history(): + oMessage.quick("Undo history cleared") + undo_history.clear() + oMenu.update_undo_availability() + + is_saving_state = false # To be sure it's executed + call_deferred("attempt_to_save_new_undo_state") + + +func attempt_to_save_new_undo_state(): # called by oEditor + if is_saving_state == false: + is_saving_state = true + while Input.is_mouse_button_pressed(BUTTON_LEFT) or oLoadingBar.visible == true or oNewMapWindow.currently_creating_new_map == true: + yield(get_tree(), "idle_frame") + oThreadedSaveUndo.semaphore.post() + + +func on_undo_state_saved(new_state): + if undo_history.size() >= 2 and are_states_equal(new_state, undo_history[1]): + oMessage.quick("Didn't add undo state as it is the same as the previous undo-state") + is_saving_state = false + return + if undo_history.size() >= max_undo_states: + undo_history.pop_back() + undo_history.push_front(new_state) + oMenu.update_undo_availability() + + oMessage.quick("Undo history size: " + str(undo_history.size()) + " (test)") + + + is_saving_state = false + + +func perform_undo(): + print("perform_undo") + if performing_undo == true or undo_history.size() <= 1: + return + var previous_state = undo_history[1] + if typeof(previous_state) != TYPE_DICTIONARY: + print("Error: previous_state is not a dictionary") + oMessage.big("Undo state error", "previous_state is not a dictionary") + return + + var CODETIME_START = OS.get_ticks_msec() + performing_undo = true + + oCurrentMap.clear_map() + + for EXT in previous_state: + var buffer = previous_state[EXT] + if buffer == null or !(buffer is StreamPeerBuffer): + print("Undo state error: buffer '%s' is not a valid StreamPeerBuffer" % EXT) + oMessage.big("Undo state error", "Buffer '%s' is not a valid StreamPeerBuffer" % EXT) + continue + var undotimeExt = OS.get_ticks_msec() + oBuffers.read_buffer_for_extension(buffer, EXT) + print(str(EXT) + ' Undotime: ' + str(OS.get_ticks_msec() - undotimeExt) + 'ms') + + oOpenMap.continue_load(oCurrentMap.path) + undo_history.pop_front() + oMenu.update_undo_availability() + oMessage.quick("Undo performed") + + if undo_history.size() <= 1: + oEditor.mapHasBeenEdited = false + + print('perform_undo: ' + str(OS.get_ticks_msec() - CODETIME_START) + 'ms') + + var IDLE_FRAME_CODETIME_START = OS.get_ticks_msec() + yield(get_tree(), 'idle_frame') + print('Idle frame (after undo): ' + str(OS.get_ticks_msec() - IDLE_FRAME_CODETIME_START) + 'ms') + + performing_undo = false + + + +func are_states_equal(state1, state2): # (0ms or 1ms) + for EXT in state1.keys(): + var buffer1 = state1[EXT] + var buffer2 = state2.get(EXT) + if buffer1 is StreamPeerBuffer and buffer2 is StreamPeerBuffer: + if buffer1.data_array != buffer2.data_array: + return false + + if buffer1 == null and buffer2 != null: + return false + if buffer1 != null and buffer2 == null: + return false + return true diff --git a/Scenes/ViewColumn.gd b/Scenes/ViewColumn.gd index 9c28e4fd..62e5107e 100644 --- a/Scenes/ViewColumn.gd +++ b/Scenes/ViewColumn.gd @@ -28,7 +28,7 @@ func update_details(): if oEditor.currentView == oEditor.VIEW_2D and oUi.mouseOnUi == false: pos = oSelector.cursorSubtile - entryIndex = oDataClmPos.get_cell(pos.x,pos.y) + entryIndex = oDataClmPos.get_cell_clmpos(pos.x,pos.y) # elif oEditor.currentView == oEditor.VIEW_3D: # if oGenerateTerrain.GENERATED_TYPE == oGenerateTerrain.GEN_MAP: # pos = Vector2(oSelector3D.translation.x, oSelector3D.translation.z) diff --git a/Scenes/VoxelGen.gd b/Scenes/VoxelGen.gd index 28d82e71..89ec2e59 100644 --- a/Scenes/VoxelGen.gd +++ b/Scenes/VoxelGen.gd @@ -81,7 +81,7 @@ static func add_face(array, pos, side, textureID): array[Mesh.ARRAY_TEX_UV].append_array(uv[side]) - var appendData = Vector2(textureID, textureID) + var appendData = Vector2(float((textureID >> 16) & 65535), float(textureID & 65535)) array[Mesh.ARRAY_TEX_UV2].append_array([ appendData, appendData, diff --git a/Scenes/WriteData.gd b/Scenes/WriteData.gd index a20fad25..83d74ad0 100644 --- a/Scenes/WriteData.gd +++ b/Scenes/WriteData.gd @@ -17,7 +17,8 @@ onready var oCurrentFormat = Nodelist.list["oCurrentFormat"] var value # just so I don't have to initialize the var in every function -func write_keeperfx_lof(buffer): +func write_keeperfx_lof(): + var buffer = StreamPeerBuffer.new() var newString = "" newString += "; KeeperFX Level Overview File (LOF)" + "\n" newString += "MAP_FORMAT_VERSION = " + str(Version.unearth_map_format_version).pad_decimals(2) + "\n" @@ -38,9 +39,10 @@ func write_keeperfx_lof(buffer): newString += "MAPSIZE = " + str(M.xSize) + " " + str(M.ySize) var scriptBytes = newString.to_ascii() buffer.put_data(scriptBytes) + return buffer - -func write_lif(buffer, filePath): +func write_lif(filePath): + var buffer = StreamPeerBuffer.new() var mapNumber = filePath.get_file().get_basename().to_upper().trim_prefix('MAP') # Remove 3 leading zeroes. I could remove 4 but I'm unsure if I should. @@ -50,8 +52,10 @@ func write_lif(buffer, filePath): value = mapNumber + ', ' + oDataMapName.data buffer.put_data(value.to_utf8()) + return buffer -func write_txt(buffer): +func write_txt(): + var buffer = StreamPeerBuffer.new() value = oDataScript.data # I'm only using \n (LF) instead of \r\n (CRLF), because to_ascii() is removing the \r (CR) for some reason. # Old Notepad will not display TXT files correctly. @@ -60,48 +64,41 @@ func write_txt(buffer): value = value.replace(char(0x200B), "") # Remove zero width spaces var scriptBytes = value.to_ascii() buffer.put_data(scriptBytes) + return buffer + +func write_une(): + var buffer = StreamPeerBuffer.new() + buffer.data_array = oDataFakeSlab.buffer.data_array + return buffer + +func write_wlb(): + var buffer = StreamPeerBuffer.new() + buffer.data_array = oDataLiquid.buffer.data_array + return buffer + +func write_wib(): + var buffer = StreamPeerBuffer.new() + buffer.data_array = oDataWibble.buffer.data_array + return buffer + +func write_slb(): + var buffer = StreamPeerBuffer.new() + buffer.data_array = oDataSlab.buffer.data_array + return buffer -func write_une(buffer): - for ySlab in M.ySize: - for xSlab in M.xSize: - value = oDataFakeSlab.get_cell(xSlab,ySlab) - buffer.put_16(value) - -func write_wlb(buffer): - for ySlab in M.ySize: - for xSlab in M.xSize: - value = oDataLiquid.get_cell(xSlab,ySlab) - buffer.put_8(value) - -func write_wib(buffer): - var dataHeight = (M.ySize*3)+1 - var dataWidth = (M.xSize*3)+1 - for subtileY in dataHeight: - for subtileX in dataWidth: - buffer.put_8(oDataWibble.get_cell(subtileX,subtileY)) - -func write_slb(buffer): - for y in M.ySize: - for x in M.xSize: - value = oDataSlab.get_cell(x,y) - #print('x:' + str(x) + " " + 'y:' + str(y)) - buffer.put_8(value) - buffer.put_8(0) - -func write_own(buffer): - var dataHeight = (M.ySize * 3) + 1 - var dataWidth = (M.xSize * 3) + 1 - var size = dataHeight * dataWidth - for i in size: - var subtileX = i % dataWidth - var subtileY = i / dataWidth - buffer.put_8(oDataOwnership.get_cell(subtileX / 3, subtileY / 3)) - -func write_tng(buffer): +func write_own(): + var buffer = StreamPeerBuffer.new() + buffer.data_array = oDataOwnership.buffer.data_array + return buffer + +func write_tng(): + var buffer = StreamPeerBuffer.new() var numberOfTngEntries = get_tree().get_nodes_in_group("Thing").size() buffer.put_16(numberOfTngEntries) for thingNode in get_tree().get_nodes_in_group("Thing"): + if thingNode.is_queued_for_deletion() == true: + continue buffer.put_8(fmod(thingNode.locationX,1.0) * 256) # 0 buffer.put_8(int(thingNode.locationX)) # 1 buffer.put_8(fmod(thingNode.locationY,1.0) * 256) # 2 @@ -147,109 +144,81 @@ func write_tng(buffer): buffer.put_8(thingNode.data17) # 17 buffer.put_16(thingNode.data18_19) # 18-19 buffer.put_8(thingNode.data20) # 20 + return buffer -func write_tngfx(buffer): - var t = "" - var numberOfTngEntries = get_tree().get_nodes_in_group("Thing").size() - t += "[common]" + "\n" - t += "ThingsCount = " + str(numberOfTngEntries) + "\n" +func write_tngfx(): + var buffer = StreamPeerBuffer.new() + var groupNames = { + Things.TYPE.OBJECT: "Object", + Things.TYPE.CREATURE: "Creature", + Things.TYPE.EFFECTGEN: "EffectGen", + Things.TYPE.TRAP: "Trap", + Things.TYPE.DOOR: "Door" + } + + var lines = PoolStringArray() + lines.append("[common]") + lines.append("") # This gets changed at the end var entryNumber = 0 for thingType in [Things.TYPE.DOOR, Things.TYPE.OBJECT, Things.TYPE.CREATURE, Things.TYPE.EFFECTGEN, Things.TYPE.TRAP]: - var groupName = "UnknownThingType" - match thingType: - Things.TYPE.OBJECT: groupName = "Object" - Things.TYPE.CREATURE: groupName = "Creature" - Things.TYPE.EFFECTGEN: groupName = "EffectGen" - Things.TYPE.TRAP: groupName = "Trap" - Things.TYPE.DOOR: groupName = "Door" + var groupName = groupNames[thingType] + for thingNode in get_tree().get_nodes_in_group(groupName): - t += "\n" - t += "[thing"+str(entryNumber)+"]" + "\n" - - t += "ThingType = \"" +groupName + "\"\n" - -# var setSubtype = "???" -# match thingType: -# Things.TYPE.OBJECT: -# if Things.DATA_OBJECT.has(thingNode.subtype): -# setSubtype = Things.DATA_OBJECT[thingNode.subtype][Things.KEEPERFX_NAME] -# Things.TYPE.CREATURE: -# if Things.DATA_CREATURE.has(thingNode.subtype): -# setSubtype = Things.DATA_CREATURE[thingNode.subtype][Things.KEEPERFX_NAME] -# Things.TYPE.EFFECTGEN: -# if Things.DATA_EFFECTGEN.has(thingNode.subtype): -# setSubtype = Things.DATA_EFFECTGEN[thingNode.subtype][Things.KEEPERFX_NAME] -# Things.TYPE.TRAP: -# if Things.DATA_TRAP.has(thingNode.subtype): -# setSubtype = Things.DATA_TRAP[thingNode.subtype][Things.KEEPERFX_NAME] -# Things.TYPE.DOOR: -# if Things.DATA_DOOR.has(thingNode.subtype): -# setSubtype = Things.DATA_DOOR[thingNode.subtype][Things.KEEPERFX_NAME] -# if setSubtype == null: -# setSubtype = "???" -# t += "Subtype = \"" + setSubtype + "\"\n" - - t += "Subtype = " + str(thingNode.subtype) + "\n" - - t += "Ownership = " +str(thingNode.ownership) + "\n" - + if thingNode.is_queued_for_deletion() == true: + continue + lines.append("") + lines.append("[thing" + str(entryNumber) + "]") + lines.append("ThingType = \"" + groupName + "\"") + lines.append("Subtype = " + str(thingNode.subtype)) + lines.append("Ownership = " + str(thingNode.ownership)) + if thingNode.effectRange != null: - var setRange = str(int(thingNode.effectRange)) - var setRangeInner = str(fmod(thingNode.effectRange,1.0) * 256) - t += "EffectRange = [" + setRange + ", " + setRangeInner + "]" + "\n" - + lines.append("EffectRange = [" + str(int(thingNode.effectRange)) + ", " + str(int(fmod(thingNode.effectRange, 1.0) * 256)) + "]") if thingNode.parentTile != null: - t += "ParentTile = " +str(thingNode.parentTile) + "\n" - elif thingNode.index != null: - t += "Index = " +str(thingNode.index) + "\n" - + lines.append("ParentTile = " + str(thingNode.parentTile)) + if thingNode.index != null: + lines.append("Index = " + str(thingNode.index)) if thingNode.doorOrientation != null: - t += "DoorOrientation = " +str(thingNode.doorOrientation) + "\n" - + lines.append("DoorOrientation = " + str(thingNode.doorOrientation)) if thingNode.creatureLevel != null: - t += "CreatureLevel = " +str(thingNode.creatureLevel) + "\n" - elif thingNode.doorLocked != null: - t += "DoorLocked = " +str(thingNode.doorLocked) + "\n" - elif thingNode.herogateNumber != null: - t += "HerogateNumber = " +str(thingNode.herogateNumber) + "\n" - elif thingNode.boxNumber != null: - t += "CustomBox = " +str(thingNode.boxNumber) + "\n" - - # Extended KeeperFX variables + lines.append("CreatureLevel = " + str(thingNode.creatureLevel)) + if thingNode.doorLocked != null: + lines.append("DoorLocked = " + str(thingNode.doorLocked)) + if thingNode.herogateNumber != null: + lines.append("HerogateNumber = " + str(thingNode.herogateNumber)) + if thingNode.boxNumber != null: + lines.append("CustomBox = " + str(thingNode.boxNumber)) if thingNode.creatureName != null and thingNode.creatureName != "": - t += "CreatureName = " + '"' + str(thingNode.creatureName) + '"' + "\n" + lines.append("CreatureName = \"" + thingNode.creatureName + "\"") if thingNode.creatureGold != null: - t += "CreatureGold = " +str(thingNode.creatureGold) + "\n" + lines.append("CreatureGold = " + str(thingNode.creatureGold)) if thingNode.creatureInitialHealth != null: - t += "CreatureInitialHealth = " +str(thingNode.creatureInitialHealth) + "\n" + lines.append("CreatureInitialHealth = " + str(thingNode.creatureInitialHealth)) if thingNode.orientation != null: - t += "Orientation = " +str(thingNode.orientation) + "\n" + lines.append("Orientation = " + str(thingNode.orientation)) if thingNode.goldValue != null: - t += "GoldValue = " +str(thingNode.goldValue) + "\n" - - var x = str(int(thingNode.locationX)) - var xInner = str(fmod(thingNode.locationX,1.0) * 256) - var y = str(int(thingNode.locationY)) - var yInner = str(fmod(thingNode.locationY,1.0) * 256) - var z = str(int(thingNode.locationZ)) - var zInner = str(fmod(thingNode.locationZ,1.0) * 256) - - t += "SubtileX = [" + x + ", " + xInner + "]" + "\n" - t += "SubtileY = [" + y + ", " + yInner + "]" + "\n" - t += "SubtileZ = [" + z + ", " + zInner + "]" + "\n" - + lines.append("GoldValue = " + str(thingNode.goldValue)) + + lines.append("SubtileX = [" + str(int(thingNode.locationX)) + ", " + str(int(fmod(thingNode.locationX, 1.0) * 256)) + "]") + lines.append("SubtileY = [" + str(int(thingNode.locationY)) + ", " + str(int(fmod(thingNode.locationY, 1.0) * 256)) + "]") + lines.append("SubtileZ = [" + str(int(thingNode.locationZ)) + ", " + str(int(fmod(thingNode.locationZ, 1.0) * 256)) + "]") entryNumber += 1 - buffer.put_data(t.to_ascii()) + lines.set(1, "ThingsCount = " + str(entryNumber)) + buffer.put_data("\n".join(lines).to_ascii()) + return buffer -func write_apt(buffer): +func write_apt(): + var buffer = StreamPeerBuffer.new() var numberOfActionPoints = get_tree().get_nodes_in_group("ActionPoint").size() buffer.put_32(numberOfActionPoints) for apNode in get_tree().get_nodes_in_group("ActionPoint"): + if apNode.is_queued_for_deletion() == true: + continue buffer.put_8(fmod(apNode.locationX,1.0) * 256) # 0 buffer.put_8(int(apNode.locationX)) # 1 buffer.put_8(fmod(apNode.locationY,1.0) * 256) # 2 @@ -258,42 +227,47 @@ func write_apt(buffer): buffer.put_8(int(apNode.pointRange)) # 5 buffer.put_8(apNode.pointNumber) # 6 buffer.put_8(apNode.data7) # 7 + return buffer -func write_aptfx(buffer): - var t = "" - var numberOfActionPoints = get_tree().get_nodes_in_group("ActionPoint").size() - t += "[common]" + "\n" - t += "ActionPointsCount = " + str(numberOfActionPoints) + "\n" + +func write_aptfx(): + var buffer = StreamPeerBuffer.new() + var lines = PoolStringArray() + lines.append("[common]") + lines.append("") # This gets changed at the end var entryNumber = 0 for apNode in get_tree().get_nodes_in_group("ActionPoint"): - t += "\n" - t += "[actionpoint"+str(entryNumber)+"]" + "\n" + if apNode.is_queued_for_deletion() == true: + continue + lines.append("") + lines.append("[actionpoint" + str(entryNumber) + "]") if apNode.pointNumber != null: - t += "PointNumber = " +str(apNode.pointNumber) + "\n" + lines.append("PointNumber = " + str(apNode.pointNumber)) if apNode.pointRange != null: var setRange = str(int(apNode.pointRange)) - var setRangeInner = str(fmod(apNode.pointRange,1.0) * 256) - t += "PointRange = [" + setRange + ", " + setRangeInner + "]" + "\n" + var setRangeInner = str(fmod(apNode.pointRange, 1.0) * 256) + lines.append("PointRange = [" + setRange + ", " + setRangeInner + "]") + + lines.append("SubtileX = [" + str(int(apNode.locationX)) + ", " + str(int(fmod(apNode.locationX, 1.0) * 256)) + "]") + lines.append("SubtileY = [" + str(int(apNode.locationY)) + ", " + str(int(fmod(apNode.locationY, 1.0) * 256)) + "]") - var x = str(int(apNode.locationX)) - var xInner = str(fmod(apNode.locationX,1.0) * 256) - var y = str(int(apNode.locationY)) - var yInner = str(fmod(apNode.locationY,1.0) * 256) - t += "SubtileX = [" + x + ", " + xInner + "]" + "\n" - t += "SubtileY = [" + y + ", " + yInner + "]" + "\n" entryNumber += 1 - buffer.put_data(t.to_ascii()) + lines.set(1, "ActionPointsCount = " + str(entryNumber)) + buffer.put_data("\n".join(lines).to_ascii()) + return buffer -func write_lgt(buffer): +func write_lgt(): + var buffer = StreamPeerBuffer.new() var numberOfLightPoints = get_tree().get_nodes_in_group("Light").size() buffer.put_32(numberOfLightPoints) for lightNode in get_tree().get_nodes_in_group("Light"): - + if lightNode.is_queued_for_deletion() == true: + continue buffer.put_8(fmod(lightNode.lightRange,1.0) * 256) # 0 buffer.put_8(int(lightNode.lightRange)) # 1 buffer.put_8(lightNode.lightIntensity) # 2 @@ -313,108 +287,104 @@ func write_lgt(buffer): buffer.put_8(lightNode.data16) # 16 buffer.put_8(lightNode.data17) # 17 buffer.put_16(lightNode.parentTile) # 18-19 + return buffer -func write_lgtfx(buffer): - var t = "" - var numberOfLightPoints = get_tree().get_nodes_in_group("Light").size() - t += "[common]" + "\n" - t += "LightsCount = " + str(numberOfLightPoints) + "\n" +func write_lgtfx(): + var buffer = StreamPeerBuffer.new() + var lines = PoolStringArray() + lines.append("[common]") + lines.append("") # This gets changed at the end var entryNumber = 0 for lightNode in get_tree().get_nodes_in_group("Light"): - t += "\n" - t += "[light"+str(entryNumber)+"]" + "\n" + if lightNode.is_queued_for_deletion() == true: + continue + lines.append("") + lines.append("[light" + str(entryNumber) + "]") if lightNode.lightIntensity != null: - t += "LightIntensity = " +str(lightNode.lightIntensity) + "\n" + lines.append("LightIntensity = " + str(lightNode.lightIntensity)) if lightNode.lightRange != null: var setRange = str(int(lightNode.lightRange)) - var setRangeInner = str(fmod(lightNode.lightRange,1.0) * 256) - t += "LightRange = [" + setRange + ", " + setRangeInner + "]" + "\n" + var setRangeInner = str(fmod(lightNode.lightRange, 1.0) * 256) + lines.append("LightRange = [" + setRange + ", " + setRangeInner + "]") if lightNode.parentTile != null: - t += "ParentTile = " +str(lightNode.parentTile) + "\n" + lines.append("ParentTile = " + str(lightNode.parentTile)) + + lines.append("SubtileX = [" + str(int(lightNode.locationX)) + ", " + str(int(fmod(lightNode.locationX, 1.0) * 256)) + "]") + lines.append("SubtileY = [" + str(int(lightNode.locationY)) + ", " + str(int(fmod(lightNode.locationY, 1.0) * 256)) + "]") + lines.append("SubtileZ = [" + str(int(lightNode.locationZ)) + ", " + str(int(fmod(lightNode.locationZ, 1.0) * 256)) + "]") - var x = str(int(lightNode.locationX)) - var xInner = str(fmod(lightNode.locationX,1.0) * 256) - var y = str(int(lightNode.locationY)) - var yInner = str(fmod(lightNode.locationY,1.0) * 256) - var z = str(int(lightNode.locationZ)) - var zInner = str(fmod(lightNode.locationZ,1.0) * 256) - t += "SubtileX = [" + x + ", " + xInner + "]" + "\n" - t += "SubtileY = [" + y + ", " + yInner + "]" + "\n" - t += "SubtileZ = [" + z + ", " + zInner + "]" + "\n" entryNumber += 1 - buffer.put_data(t.to_ascii()) + lines.set(1, "LightsCount = " + str(entryNumber)) + buffer.put_data("\n".join(lines).to_ascii()) + return buffer + -func write_inf(buffer): +func write_inf(): + var buffer = StreamPeerBuffer.new() value = oDataLevelStyle.data buffer.put_8(value) + return buffer + +func write_slx(): + var buffer = StreamPeerBuffer.new() + var slx_data = oDataSlx.slxImgData.get_data() + for i in range(0, slx_data.size(), 3): + buffer.put_8(slx_data[i]) + return buffer + + +func write_dat(): + var buffer = StreamPeerBuffer.new() + buffer.data_array = oDataClmPos.buffer.data_array + return buffer + +func write_clm(): + var buffer = StreamPeerBuffer.new() -func write_slx(buffer): - oDataSlx.slxImgData.lock() - for ySlab in M.ySize: - for xSlab in M.xSize: - value = oDataSlx.slxImgData.get_pixel(xSlab,ySlab).r8 - # This is unncessary as the lower 4 bits will be used anyway, if the number is in the range 0-15 - var lower4bits = value & 0x0F - buffer.put_8(lower4bits) - oDataSlx.slxImgData.unlock() - -func write_dat(buffer): - var dataHeight = (M.ySize*3)+1 - var dataWidth = (M.xSize*3)+1 - for subtileY in dataHeight: - for subtileX in dataWidth: - buffer.seek(2*(subtileX + (subtileY*dataWidth))) - - value = 65536 - oDataClmPos.get_cell(subtileX,subtileY) - if value == 65536: value = 0 - - buffer.put_16(value) - -func write_clm(buffer): - oDataClm.update_all_utilized() - var numberOfClmEntries = 2048 buffer.put_16(numberOfClmEntries) - buffer.put_data([0,0]) + buffer.put_data([0, 0]) buffer.put_16(oDataClm.unknownData) - buffer.put_data([0,0]) - + buffer.put_data([0, 0]) + + var data = PoolByteArray() + data.resize(numberOfClmEntries * 24) + + var utilized = oDataClm.utilized + var permanent = oDataClm.permanent + var lintel = oDataClm.lintel + var height = oDataClm.height + var solidMask = oDataClm.solidMask + var floorTexture = oDataClm.floorTexture + var orientation = oDataClm.orientation + var cubes = oDataClm.cubes + for entry in numberOfClmEntries: - buffer.put_16(oDataClm.utilized[entry]) # 0-1 - #buffer.put_8(oDataClm.permanent[entry] + (oDataClm.lintel[entry]*2) + (oDataClm.height[entry]*16)) # 2 - buffer.put_8((oDataClm.permanent[entry] & 1) + ((oDataClm.lintel[entry] & 7) << 1) + ((oDataClm.height[entry] & 15) << 4)) - buffer.put_16(oDataClm.solidMask[entry]) # 3-4 - buffer.put_16(oDataClm.floorTexture[entry]) # 5-6 - buffer.put_8(oDataClm.orientation[entry]) # 7 - + var index = entry * 24 + + data[index] = utilized[entry] & 0xFF + data[index + 1] = (utilized[entry] >> 8) & 0xFF + + data[index + 2] = (permanent[entry] & 1) + ((lintel[entry] & 7) << 1) + ((height[entry] & 15) << 4) + + data[index + 3] = solidMask[entry] & 0xFF + data[index + 4] = (solidMask[entry] >> 8) & 0xFF + + data[index + 5] = floorTexture[entry] & 0xFF + data[index + 6] = (floorTexture[entry] >> 8) & 0xFF + + data[index + 7] = orientation[entry] + + var cubesEntry = cubes[entry] for cubeNumber in 8: - buffer.put_16(oDataClm.cubes[entry][cubeNumber]) # 8-23 - -# var specialByte = buffer.put_8() # 2 -# var get_height = specialByte / 16 -# oDataClm.height.append(get_height) -# specialByte -= get_height * 16 -# var get_lintel = specialByte / 2 -# oDataClm.lintel.append(get_lintel) -# specialByte -= get_lintel * 2 -# var get_permanent = specialByte -# oDataClm.permanent.append(get_permanent) - - -# for entry in numberOfClmEntries: -# var twentyFourByteArray = oDataClm.data[entry] -# -# buffer.put_16(oDataClm.utilized[entry]) -# -# var pos = 8 + (entry * 24) -# for i in range(2, 24): # Skip "USE" value -# #for i in 24: -# buffer.seek(pos+i) -# value = twentyFourByteArray[i] -# buffer.put_8(value) + var cube = cubesEntry[cubeNumber] + data[index + 8 + cubeNumber * 2] = cube & 0xFF + data[index + 9 + cubeNumber * 2] = (cube >> 8) & 0xFF + buffer.put_data(data) + return buffer diff --git a/Scenes/oAnalyzeGrids.gd b/Scenes/oAnalyzeGrids.gd index 22e6b4a8..e266e459 100644 --- a/Scenes/oAnalyzeGrids.gd +++ b/Scenes/oAnalyzeGrids.gd @@ -21,7 +21,7 @@ onready var tilemap_data = { "Wibble": {"extension": ".wib", "grid_type": "SUBTILE", "node": oDataWibble}, "Liquid": {"extension": ".wlb", "grid_type": "TILE", "node": oDataLiquid}, "Slab": {"extension": ".slb", "grid_type": "TILE", "node": oDataSlab}, - "Ownership": {"extension": ".own", "grid_type": "TILE", "node": oDataOwnership}, + "Ownership": {"extension": ".own", "grid_type": "SUBTILE", "node": oDataOwnership}, "Column Positions": {"extension": ".dat", "grid_type": "SUBTILE", "node": oDataClmPos}, "Fake Slabs": {"extension": ".une", "grid_type": "TILE", "node": oDataFakeSlab}, "Style": {"extension": ".slx", "grid_type": "TILE", "node": oDataSlx} diff --git a/Shaders/display_texture_2d.shader b/Shaders/display_texture_2d.shader index cac78497..91ab93c6 100644 --- a/Shaders/display_texture_2d.shader +++ b/Shaders/display_texture_2d.shader @@ -44,9 +44,10 @@ int getAnimationFrame(int frame, int index) { return int(value.r+value.g+value.b); } +// Convert RGB values to one integer int getIndex(ivec2 coords) { - vec3 value = texelGet(viewTextures, coords, 0).rgb * vec3(255.0,255.0,255.0); - return int(value.r+value.g+value.b); + vec3 value = texelGet(viewTextures, coords, 0).rgb; + return (int(value.r * 255.0) << 16) | (int(value.g * 255.0) << 8) | int(value.b * 255.0); } void fragment() { diff --git a/Shaders/display_texture_3d.shader b/Shaders/display_texture_3d.shader index 92e5c9a9..f2064060 100644 --- a/Shaders/display_texture_3d.shader +++ b/Shaders/display_texture_3d.shader @@ -34,6 +34,12 @@ int getAnimationFrame(int frame, int index){ return int(value.r+value.g+value.b); } +int getIndex(vec2 uv2) { + // This is a bit of a hack, but allows us to store the texture index within the mesh as UV2. + // Adding 0.5 so the int() floor will be correct. + return (int(uv2.x + 0.5) << 16) | int(uv2.y + 0.5); +} + void vertex() { worldPos = WORLD_MATRIX * vec4(VERTEX, 1.0); //required when using skip_vertex_transform VERTEX = (INV_CAMERA_MATRIX * worldPos).xyz; //required when using skip_vertex_transform @@ -42,7 +48,7 @@ void vertex() { void fragment() { // This is a bit of a hack, but allows us to store the texture index within the mesh as UV2. // Adding 0.5 so the int() floor will be correct. - int index = int(UV2.x+0.5); + int index = getIndex(UV2); if (index >= 544) { // 544 is the index where the TexAnims start (544 - 585) int frame = int(mod(TIME * TEXTURE_ANIMATION_SPEED, 8)); diff --git a/project.godot b/project.godot index a12aa39c..bee6e5ea 100644 --- a/project.godot +++ b/project.godot @@ -19,6 +19,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://Class/EditableLabel.gd" }, { +"base": "Node", +"class": "Grid", +"language": "GDScript", +"path": "res://Class/GridClass.gd" +}, { "base": "VBoxContainer", "class": "SpecialTabContainer", "language": "GDScript", @@ -37,6 +42,7 @@ _global_script_classes=[ { _global_script_class_icons={ "CustomSpinBox": "", "EditableLabel": "", +"Grid": "", "SpecialTabContainer": "", "SpinBoxPropertiesValue": "", "VariationConstructs": "" @@ -59,7 +65,6 @@ Settings="*res://Autoload/Settings.gd" Things="*res://Autoload/Things.gd" Nodelist="*res://Autoload/Nodelist.gd" Utils="*res://Autoload/Utils.gd" -Filetypes="*res://Autoload/Filetypes.gd" M="*res://Autoload/M.gd" Slabset="*res://Autoload/Slabset.gd" Columnset="*res://Autoload/Columnset.gd" @@ -69,6 +74,7 @@ Version="*res://Autoload/Version.gd" gdscript/warnings/unused_argument=false gdscript/warnings/return_value_discarded=false +gdscript/warnings/integer_division=false [display] @@ -266,6 +272,16 @@ adjust_range={ "events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777240,"physical_scancode":0,"unicode":0,"echo":false,"script":null) ] } +undo={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":90,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} +redo={ +"deadzone": 0.5, +"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":true,"meta":false,"command":true,"pressed":false,"scancode":89,"physical_scancode":0,"unicode":0,"echo":false,"script":null) + ] +} [mono]