Initial commit.
This commit is contained in:
18
Services/CLIService.gd
Normal file
18
Services/CLIService.gd
Normal file
@@ -0,0 +1,18 @@
|
||||
extends Node
|
||||
|
||||
var _args = {
|
||||
|
||||
}
|
||||
|
||||
func parse_arguments():
|
||||
var args = Array(OS.get_cmdline_args())
|
||||
for arg in args:
|
||||
arg = arg.trim_prefix('--')
|
||||
var split_arg = arg.split('=')
|
||||
_args[split_arg[0]] = split_arg[1]
|
||||
|
||||
func get(arg):
|
||||
if arg in _args:
|
||||
return _args[arg]
|
||||
else:
|
||||
return null
|
||||
14
Services/ConsoleService.gd
Normal file
14
Services/ConsoleService.gd
Normal file
@@ -0,0 +1,14 @@
|
||||
extends Node
|
||||
|
||||
signal on_log;
|
||||
signal on_error;
|
||||
|
||||
var log_messages = []
|
||||
|
||||
func log(message):
|
||||
log_messages.append(String(message))
|
||||
emit_signal('on_log', log_messages)
|
||||
|
||||
func error(message):
|
||||
log_messages.append("Error: " + String(message))
|
||||
emit_signal('on_error', log_messages)
|
||||
49
Services/NetworkService.gd
Normal file
49
Services/NetworkService.gd
Normal file
@@ -0,0 +1,49 @@
|
||||
extends Node
|
||||
|
||||
signal on_client_connected;
|
||||
signal on_server_connected;
|
||||
signal on_server_disconnected;
|
||||
|
||||
var NETWORK_MODE = "client"
|
||||
var local_server_pid = null
|
||||
var server_hash = null
|
||||
|
||||
func _ready():
|
||||
get_tree().connect("network_peer_connected", self, "server_on_peer_connected")
|
||||
get_tree().connect("connected_to_server", self, "client_on_connection_succeeded")
|
||||
get_tree().connect("connection_failed", self, "client_on_connection_failed")
|
||||
self.connect("tree_exiting", self, "cleanup_local_server")
|
||||
|
||||
func create_local_server():
|
||||
local_server_pid = OS.execute(OS.get_executable_path(), ["--mode=server", "--port=9801"], false)
|
||||
|
||||
func cleanup_local_server():
|
||||
if local_server_pid:
|
||||
OS.kill(local_server_pid)
|
||||
|
||||
func get_local_connection():
|
||||
return {"host": "127.0.0.1", "port": 9801}
|
||||
|
||||
func init_server(port: int):
|
||||
NETWORK_MODE = "server"
|
||||
var peer = NetworkedMultiplayerENet.new()
|
||||
peer.create_server(port, 256)
|
||||
get_tree().set_network_peer(peer)
|
||||
|
||||
|
||||
func init_client(host: String, port: int):
|
||||
NETWORK_MODE = "client"
|
||||
server_hash = (host+String(port)).md5_text()
|
||||
var peer = NetworkedMultiplayerENet.new()
|
||||
peer.create_client(host, port)
|
||||
get_tree().set_network_peer(peer)
|
||||
|
||||
func server_on_peer_connected(id: int):
|
||||
emit_signal("on_client_connected", id)
|
||||
|
||||
func client_on_connection_succeeded():
|
||||
emit_signal("on_server_connected");
|
||||
|
||||
func client_on_connection_failed():
|
||||
emit_signal("on_server_disconnected", "Connection Failed")
|
||||
|
||||
74
Services/Old/ConnectionService.gd
Normal file
74
Services/Old/ConnectionService.gd
Normal file
@@ -0,0 +1,74 @@
|
||||
extends Node
|
||||
|
||||
var ConsoleService
|
||||
var NetworkService
|
||||
|
||||
func _ready():
|
||||
NetworkService = $"/root/NetworkService"
|
||||
ConsoleService = $"/root/ConsoleService"
|
||||
NetworkService.connect("on_client_connected", self, "on_client_connected")
|
||||
NetworkService.connect("on_server_connected", self, "on_server_connected")
|
||||
NetworkService.connect("on_server_disconnected", self, "on_server_disconnected")
|
||||
|
||||
func on_client_connected(id: int):
|
||||
if NetworkService.NETWORK_MODE == 'server':
|
||||
var server_mods = get_local_mods()
|
||||
rpc_id(id, "compute_needed_mods", server_mods)
|
||||
|
||||
func get_local_mods():
|
||||
var md5_hashes = []
|
||||
for mod_desc in ModService.mod_arr:
|
||||
if not mod_desc.md5: continue
|
||||
md5_hashes.push_back(mod_desc.md5)
|
||||
return md5_hashes
|
||||
|
||||
remote func send_mods_to_client(id: int, needed_mods: Array):
|
||||
var ModService = $"/root/ModService"
|
||||
for mod_desc in ModService.mod_arr:
|
||||
if not needed_mods.has(mod_desc.md5):
|
||||
continue
|
||||
if mod_desc.type != 'zip':
|
||||
continue
|
||||
var mod_file = File.new()
|
||||
mod_file.open(mod_desc.path, 1)
|
||||
var file_length = mod_file.get_len()
|
||||
var bytes = mod_file.get_buffer(file_length)
|
||||
ConsoleService.log("Sending mod "+mod_desc.name+" with size: "+String(bytes.size()/1000000)+"MB")
|
||||
rpc_id(id, "receive_mod", mod_desc.name, bytes)
|
||||
|
||||
remote func compute_needed_mods(server_mods: Array):
|
||||
var needed_mods_md5 = server_mods
|
||||
var dir = Directory.new()
|
||||
var err = dir.make_dir_recursive('user://servers/'+NetworkService.server_hash+'/mods')
|
||||
var mod_dir_exists = dir.open('user://servers/'+NetworkService.server_hash+'/mods')
|
||||
dir.list_dir_begin()
|
||||
|
||||
while true:
|
||||
var file = dir.get_next()
|
||||
var basename = file.get_basename()
|
||||
if file == "":
|
||||
break
|
||||
if file.ends_with(".zip") and server_mods.has(basename):
|
||||
needed_mods_md5.erase(basename)
|
||||
|
||||
dir.list_dir_end()
|
||||
|
||||
rpc_id(1, 'send_mods_to_client', get_tree().get_network_unique_id(), needed_mods_md5)
|
||||
|
||||
remote func receive_mod(name: String, bytes: PoolByteArray):
|
||||
ConsoleService.log("Receiving mod "+name+" with size: "+String(bytes.size()/1000000)+"MB")
|
||||
var file_path = 'user://servers/'+NetworkService.server_hash+'/mods/'+name+'.zip'
|
||||
var dir_path = file_path.get_base_dir()
|
||||
var mod_file = File.new()
|
||||
var dir = Directory.new()
|
||||
var err = dir.make_dir_recursive(dir_path)
|
||||
mod_file.open(file_path, 2)
|
||||
mod_file.store_buffer(bytes)
|
||||
mod_file.close()
|
||||
dir.rename(file_path, dir_path+'/'+mod_file.get_md5(file_path)+'.zip')
|
||||
|
||||
func on_server_connected():
|
||||
pass
|
||||
|
||||
func on_server_disconnected():
|
||||
pass
|
||||
122
Services/Old/ModService.gd
Normal file
122
Services/Old/ModService.gd
Normal file
@@ -0,0 +1,122 @@
|
||||
extends Node
|
||||
|
||||
var ConsoleService
|
||||
|
||||
var data_path = "."
|
||||
var mod_dict = {}
|
||||
var mod_arr = []
|
||||
var mod_instances = {}
|
||||
|
||||
func _ready():
|
||||
ConsoleService = $"/root/ConsoleService"
|
||||
|
||||
# Locate all mods that can be loaded for the given game.
|
||||
func find_local_mods():
|
||||
var dir = Directory.new()
|
||||
|
||||
var mod_dir_exists = dir.open(data_path + "/mods")
|
||||
if (mod_dir_exists != 0):
|
||||
dir.change_dir(data_path)
|
||||
dir.make_dir("mods")
|
||||
dir.change_dir(data_path + "/mods")
|
||||
|
||||
dir.list_dir_begin()
|
||||
|
||||
while true:
|
||||
var file = dir.get_next()
|
||||
var basename = file.get_basename()
|
||||
if file == "":
|
||||
break
|
||||
elif file.ends_with(".zip"):
|
||||
var mod_desc = {
|
||||
"name": basename,
|
||||
"path": data_path + "/mods/" + file,
|
||||
"md5": File.new().get_md5(data_path + "/mods/" + file),
|
||||
"type": "zip"
|
||||
}
|
||||
mod_arr.append(mod_desc)
|
||||
mod_dict[mod_desc.name] = mod_desc
|
||||
elif dir.file_exists(basename+"/main.gd"):
|
||||
var mod_desc = {
|
||||
"name": basename,
|
||||
"path": data_path + "/mods/" + file,
|
||||
"md5": null,
|
||||
"type": "folder"
|
||||
}
|
||||
mod_arr.append(mod_desc)
|
||||
mod_dict[mod_desc.name] = mod_desc
|
||||
|
||||
dir.list_dir_end()
|
||||
|
||||
# Prepare initial instances of mods for preprocessing. Used to determine mod dependencies and configuration
|
||||
# Prior to final loading and initialization.
|
||||
func preload_instances():
|
||||
if mod_arr.size() == 0:
|
||||
ConsoleService.error("[ModService] No mods found (Run find_local_mods and download_server_mods first)")
|
||||
return
|
||||
|
||||
for mod_desc in mod_arr:
|
||||
mod_instances[mod_desc.name] = _get_mod_instance(mod_desc)
|
||||
if !mod_instances[mod_desc.name]:
|
||||
ConsoleService.error("[ModService] Failed to load mod '"+mod_desc.name+"'")
|
||||
|
||||
func compute_dependency_graph():
|
||||
if mod_instances.size() == 0:
|
||||
ConsoleService.error("[ModService] Mods have not been preloaded (Run preload_instances first)")
|
||||
return
|
||||
|
||||
var resolved = []; # Properly ordered mod list.
|
||||
for mod_desc in mod_arr:
|
||||
_resolve_dependency(mod_desc, resolved, [])
|
||||
|
||||
return resolved
|
||||
|
||||
func _resolve_dependency(mod_desc: Dictionary, resolved: Array, unresolved: Array):
|
||||
if mod_desc in resolved:
|
||||
return
|
||||
# Seen is used to prevent
|
||||
unresolved.append(mod_desc)
|
||||
if not "dependencies" in mod_instances[mod_desc.name]:
|
||||
resolved.append(mod_desc)
|
||||
unresolved.erase(mod_desc)
|
||||
return
|
||||
|
||||
var deps = mod_instances[mod_desc.name].dependencies
|
||||
for dep in deps:
|
||||
var dep_desc = mod_dict[dep]
|
||||
if not dep_desc in resolved:
|
||||
if dep_desc in unresolved:
|
||||
ConsoleService.error("[ModService] Circular dependency between '"+mod_desc.name+"' <-> '"+dep+"'")
|
||||
assert(false)
|
||||
if not dep in mod_instances:
|
||||
ConsoleService.error("[ModService] Mod '"+mod_desc.name+"' requires mod '"+dep+"' to be installed, but it is not")
|
||||
assert(false)
|
||||
_resolve_dependency(dep_desc, resolved, unresolved)
|
||||
resolved.append(mod_desc)
|
||||
unresolved.erase(mod_desc)
|
||||
|
||||
func load_mods():
|
||||
if mod_arr.size() == 0:
|
||||
print("[ModService] No mods found (Run find_mods first)")
|
||||
return
|
||||
|
||||
for mod_desc in mod_arr:
|
||||
var mod_instance = _get_mod_instance(mod_desc)
|
||||
mod_instances[mod_desc.name] = mod_instance
|
||||
if !mod_instance:
|
||||
ConsoleService.log("[ModService] Failed to load mod '"+mod_desc.name+"'")
|
||||
continue
|
||||
|
||||
$"/root/Main/Mods".add_child(mod_instance)
|
||||
if mod_instance.has_method('init'):
|
||||
mod_instance.init()
|
||||
|
||||
func _get_mod_instance(mod_desc: Dictionary):
|
||||
if mod_desc.type == 'zip':
|
||||
ProjectSettings.load_resource_pack(mod_desc.path, true)
|
||||
|
||||
var mod_script = load("res://mods/"+mod_desc.name+"/main.gd");
|
||||
if !mod_script:
|
||||
return
|
||||
var mod_instance = mod_script.new()
|
||||
return mod_instance
|
||||
81
Services/PackageService.gd
Normal file
81
Services/PackageService.gd
Normal file
@@ -0,0 +1,81 @@
|
||||
extends Node
|
||||
|
||||
onready var ConsoleService = $"/root/ConsoleService"
|
||||
|
||||
var package_dict = {}
|
||||
var package_load_order = []
|
||||
|
||||
# Locate all packages that can be loaded.
|
||||
func discover_packages():
|
||||
var dir = Directory.new()
|
||||
dir.open("res://packages")
|
||||
dir.list_dir_begin()
|
||||
|
||||
while true:
|
||||
var package_name = dir.get_next()
|
||||
if package_name == "": break
|
||||
if not dir.current_is_dir() or package_name == "." or package_name == "..": continue
|
||||
|
||||
var package_script = load("res://packages/"+package_name+"/main.gd");
|
||||
if !package_script: continue
|
||||
|
||||
var package = {
|
||||
"name": package_script.package.name if package_script.package.has("name") else package_name,
|
||||
"version": package_script.package.version if package_script.package.has("version") else "1.0.0",
|
||||
"dependencies": package_script.package.dependencies if package_script.package.has("dependencies") else [],
|
||||
"_script": package_script
|
||||
}
|
||||
package_dict[package.name] = package
|
||||
|
||||
dir.list_dir_end()
|
||||
_compute_dependency_graph()
|
||||
|
||||
func load_packages():
|
||||
for package_name in package_load_order:
|
||||
var package = package_dict[package_name]
|
||||
package._instance = package._script.new()
|
||||
if !package._instance:
|
||||
ConsoleService.log("[PackageService] Failed to load package '"+package.name+"'")
|
||||
continue
|
||||
|
||||
func init_packages():
|
||||
for package_name in package_load_order:
|
||||
var package = package_dict[package_name]
|
||||
if not package.has("_instance"):
|
||||
ConsoleService.log("[PackageService] Package '"+package.name+"' has not been loaded. Please load before initializing.")
|
||||
continue
|
||||
$"/root/Main/Packages".add_child(package._instance)
|
||||
if package._instance.has_method('init'):
|
||||
package._instance.init()
|
||||
|
||||
func _compute_dependency_graph():
|
||||
if package_dict.size() == 0:
|
||||
ConsoleService.error("[PackageService] packages have not been preloaded (Run preload_instances first)")
|
||||
return
|
||||
|
||||
var resolved = []; # Properly ordered package list.
|
||||
for package in package_dict.values():
|
||||
_resolve_dependency(package, resolved, [])
|
||||
|
||||
package_load_order = resolved
|
||||
|
||||
func _resolve_dependency(package: Dictionary, resolved: Array, unresolved: Array):
|
||||
if package.name in resolved:
|
||||
return
|
||||
# Unresolved is used to prevent recursive lookups.
|
||||
unresolved.append(package.name)
|
||||
|
||||
for dependency_name in package.dependencies:
|
||||
if dependency_name in resolved: continue
|
||||
if dependency_name in unresolved:
|
||||
ConsoleService.error("[PackageService] Circular dependency between '"+package.name+"' <-> '"+dependency_name+"'")
|
||||
assert(false)
|
||||
if not package_dict.has(dependency_name):
|
||||
ConsoleService.error("[PackageService] package '"+package.name+"' requires package '"+dependency_name+"' to be installed, but it is not")
|
||||
assert(false)
|
||||
|
||||
var dependency = package_dict[dependency_name]
|
||||
_resolve_dependency(dependency, resolved, unresolved)
|
||||
|
||||
resolved.append(package.name)
|
||||
unresolved.erase(package.name)
|
||||
24
Services/TaskService.gd
Normal file
24
Services/TaskService.gd
Normal file
@@ -0,0 +1,24 @@
|
||||
extends Node
|
||||
|
||||
var tasks = {}
|
||||
|
||||
func start(name: String, message: String):
|
||||
var task = Task.new(name, message)
|
||||
if not tasks[task.name]: tasks[task.name] = []
|
||||
tasks[task.name].append(task)
|
||||
emit_signal('started:'+name, task)
|
||||
|
||||
func complete(name: String):
|
||||
if not tasks[name]: return
|
||||
var task = tasks[name].pop_front()
|
||||
if tasks[name].size() == 0:
|
||||
tasks.erase(name)
|
||||
emit_signal('completed:'+name, task)
|
||||
|
||||
class Task:
|
||||
var name = ''
|
||||
var message = ''
|
||||
|
||||
func _init(_name: String, _message: String):
|
||||
name = _name
|
||||
message = _message
|
||||
Reference in New Issue
Block a user