2020-09-29 14:53:00 +02:00
|
|
|
extends Node
|
|
|
|
|
2021-09-06 23:15:34 +02:00
|
|
|
var lang = "it" # Variable for localization
|
|
|
|
|
2020-09-29 14:53:00 +02:00
|
|
|
var debug_file_io = false
|
|
|
|
|
|
|
|
# Crash the game and display the error message.
|
|
|
|
func crash(message):
|
|
|
|
push_error(message)
|
2020-09-29 16:12:58 +02:00
|
|
|
print("FATAL ERROR: " + message)
|
2020-09-29 14:53:00 +02:00
|
|
|
get_tree().quit()
|
2020-09-29 16:12:58 +02:00
|
|
|
# Oh, still here? Let's crash more violently, by calling a non-existing method.
|
2020-10-01 13:11:29 +02:00
|
|
|
# Violent delights have violent ends.
|
2020-09-29 16:12:58 +02:00
|
|
|
get_tree().fatal_error()
|
2020-09-29 14:53:00 +02:00
|
|
|
|
2020-11-10 15:27:42 +01:00
|
|
|
func map(array, object, f):
|
|
|
|
var new_array = []
|
|
|
|
for i in range(array.size()):
|
|
|
|
new_array.push_back(object.call(f, array[i]))
|
|
|
|
return new_array
|
|
|
|
|
2020-09-29 14:53:00 +02:00
|
|
|
# Run a simple command with arguments, blocking, using OS.execute.
|
|
|
|
func exec(command, args=[], crash_on_fail=true):
|
|
|
|
var debug = false
|
|
|
|
|
|
|
|
if debug:
|
|
|
|
print("exec: %s [%s]" % [command, PoolStringArray(args).join(", ")])
|
|
|
|
|
|
|
|
var output = []
|
|
|
|
var exit_code = OS.execute(command, args, true, output, true)
|
|
|
|
output = output[0]
|
2020-10-20 18:44:33 +02:00
|
|
|
|
2020-09-29 14:53:00 +02:00
|
|
|
if exit_code != 0 and crash_on_fail:
|
2020-10-20 18:44:33 +02:00
|
|
|
helpers.crash("OS.execute failed: %s [%s] Output: %s \nExit Code %d" % [command, PoolStringArray(args).join(", "), output, exit_code])
|
|
|
|
elif debug:
|
|
|
|
print("Output: %s" %output)
|
2020-09-29 14:53:00 +02:00
|
|
|
|
2020-10-22 16:19:22 +02:00
|
|
|
return {"output": output, "exit_code": exit_code}
|
2020-09-29 14:53:00 +02:00
|
|
|
|
2021-02-23 13:06:58 +01:00
|
|
|
func exec_async(command, args=[]):
|
|
|
|
OS.execute(command, args, false)
|
|
|
|
|
2020-09-29 14:53:00 +02:00
|
|
|
# Return the contents of a file. If no fallback_string is provided, crash when
|
|
|
|
# the file doesn't exist.
|
|
|
|
func read_file(path, fallback_string=null):
|
|
|
|
if debug_file_io:
|
|
|
|
print("reading " + path)
|
|
|
|
var file = File.new()
|
|
|
|
var open_status = file.open(path, File.READ)
|
|
|
|
if open_status == OK:
|
|
|
|
var content = file.get_as_text()
|
|
|
|
file.close()
|
|
|
|
return content
|
|
|
|
else:
|
|
|
|
if fallback_string != null:
|
|
|
|
return fallback_string
|
|
|
|
else:
|
|
|
|
helpers.crash("File %s could not be read, and has no fallback" % path)
|
|
|
|
|
|
|
|
func write_file(path, content):
|
|
|
|
if debug_file_io:
|
|
|
|
print("writing " + path)
|
2021-02-05 16:20:52 +01:00
|
|
|
|
|
|
|
# Create the base directory of the file, if it doesn't exist.
|
|
|
|
var parts = Array(path.split("/"))
|
|
|
|
parts.pop_back()
|
|
|
|
var dirname = PoolStringArray(parts).join("/")
|
|
|
|
var dir = Directory.new()
|
|
|
|
if not dir.dir_exists(path):
|
|
|
|
dir.make_dir_recursive(dirname)
|
|
|
|
|
2020-09-29 14:53:00 +02:00
|
|
|
var file = File.new()
|
|
|
|
file.open(path, File.WRITE)
|
|
|
|
file.store_string(content)
|
|
|
|
file.close()
|
|
|
|
return true
|
2020-09-29 17:52:31 +02:00
|
|
|
|
|
|
|
func parse_args():
|
|
|
|
var arguments = {}
|
|
|
|
for argument in OS.get_cmdline_args():
|
|
|
|
if argument.substr(0, 2) == "--":
|
|
|
|
# Parse valid command-line arguments into a dictionary
|
|
|
|
if argument.find("=") > -1:
|
|
|
|
var key_value = argument.split("=")
|
|
|
|
arguments[key_value[0].lstrip("--")] = key_value[1]
|
|
|
|
else:
|
|
|
|
arguments[argument.lstrip("--")] = true
|
|
|
|
return arguments
|
2020-09-29 18:21:39 +02:00
|
|
|
|
|
|
|
func careful_delete(path_inside):
|
2021-04-12 16:01:02 +02:00
|
|
|
var expected_prefix = "%s/tmp/" % OS.get_user_data_dir()
|
2020-09-29 18:21:39 +02:00
|
|
|
|
|
|
|
var os = OS.get_name()
|
2021-04-12 16:01:02 +02:00
|
|
|
if os == "Windows":
|
2021-04-12 15:43:02 +02:00
|
|
|
# In the game, we use forward slashes:
|
|
|
|
expected_prefix = expected_prefix.replace("\\", "/")
|
2021-03-24 15:38:53 +01:00
|
|
|
# Windows treats paths case-insensitively:
|
|
|
|
expected_prefix = expected_prefix.to_lower()
|
|
|
|
path_inside = path_inside.to_lower()
|
2020-09-29 18:21:39 +02:00
|
|
|
|
|
|
|
if path_inside.substr(0,expected_prefix.length()) != expected_prefix:
|
|
|
|
helpers.crash("Refusing to delete directory %s that does not start with %s" % [path_inside, expected_prefix])
|
|
|
|
else:
|
2020-10-26 19:56:52 +01:00
|
|
|
game.global_shell.cd(game.tmp_prefix)
|
2020-09-29 18:21:39 +02:00
|
|
|
game.global_shell.run("rm -rf '%s'" % path_inside)
|
2020-09-30 17:46:43 +02:00
|
|
|
|
|
|
|
func parse(file):
|
|
|
|
var text = read_file(file)
|
|
|
|
var result = {}
|
|
|
|
var current_section
|
|
|
|
|
|
|
|
var section_regex = RegEx.new()
|
|
|
|
section_regex.compile("^\\[(.*)\\]$")
|
|
|
|
|
|
|
|
var assignment_regex = RegEx.new()
|
|
|
|
assignment_regex.compile("^([a-z ]+)=(.*)$")
|
|
|
|
|
|
|
|
for line in text.split("\n"):
|
|
|
|
# Skip comments.
|
|
|
|
if line.substr(0, 1) == ";":
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Parse a [section name].
|
|
|
|
var m = section_regex.search(line)
|
|
|
|
if m:
|
|
|
|
current_section = m.get_string(1)
|
|
|
|
result[current_section] = ""
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Parse a direct=assignment.
|
|
|
|
m = assignment_regex.search(line)
|
|
|
|
if m:
|
|
|
|
var key = m.get_string(1).strip_edges()
|
|
|
|
var value = m.get_string(2).strip_edges()
|
|
|
|
result[key] = value
|
|
|
|
continue
|
|
|
|
|
|
|
|
# At this point, the line is just content belonging to the current section.
|
|
|
|
if current_section:
|
|
|
|
result[current_section] += line + "\n"
|
|
|
|
|
|
|
|
for key in result:
|
|
|
|
result[key] = result[key].strip_edges()
|
|
|
|
|
|
|
|
return result
|
2020-10-23 13:07:16 +02:00
|
|
|
|
|
|
|
func abbreviate(text, max_length):
|
|
|
|
if text.length() > max_length-3:
|
|
|
|
text = text.substr(0, max_length-3) + "..."
|
|
|
|
|
|
|
|
return text
|