Skip to content

Commit

Permalink
Allow installing obsoleted mods
Browse files Browse the repository at this point in the history
  • Loading branch information
qrrk committed Sep 23, 2021
1 parent a1e3733 commit 82f1c42
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 132 deletions.
38 changes: 24 additions & 14 deletions scenes/Catapult.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ margin_bottom = 91.0
]]
margin_top = 97.0
margin_right = 784.0
margin_bottom = 675.0
margin_bottom = 559.0
tab_align = 0
script = ExtResource( 16 )

Expand Down Expand Up @@ -588,6 +588,7 @@ current_dir = "/mnt/data/Godot/Catapult/Project"
current_path = "/mnt/data/Godot/Catapult/Project/"

[node name="Fonts" type="VBoxContainer" parent="Main/Tabs"]
visible = false
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 7.5
Expand Down Expand Up @@ -867,7 +868,6 @@ margin_right = 769.0
margin_bottom = 539.0

[node name="Settings" type="VBoxContainer" parent="Main/Tabs"]
visible = false
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 7.5
Expand Down Expand Up @@ -910,19 +910,28 @@ hint_tooltip = "Shorten release names to just the date and number
Short names save screen space but may be less clear."
text = "Shorten names of experimental releases"

[node name="ShowDebug" type="CheckButton" parent="Main/Tabs/Settings"]
[node name="ShowObsoleteMods" type="CheckButton" parent="Main/Tabs/Settings"]
margin_top = 140.0
margin_right = 769.0
margin_bottom = 169.0
hint_tooltip = "Show mods that come with the game but are marked
as \"obsolete\". Normally, such mods are not considered
as installed."
text = "List obsolete mods in installed"

[node name="ShowDebug" type="CheckButton" parent="Main/Tabs/Settings"]
margin_top = 175.0
margin_right = 769.0
margin_bottom = 204.0
hint_tooltip = "Shows the Debug tab with some testing functions
and enables debug messages in the status pane
(useful for troubleshooting)."
text = "Debug mode"

[node name="NumReleases" type="HBoxContainer" parent="Main/Tabs/Settings"]
margin_top = 175.0
margin_top = 210.0
margin_right = 769.0
margin_bottom = 204.0
margin_bottom = 239.0
hint_tooltip = "How many latest releases will be requested
from GitHub after starting the launcher, choosing
the game or clicking Refresh."
Expand All @@ -942,9 +951,9 @@ value = 30.0
rounded = true

[node name="ScaleOverride" type="HBoxContainer" parent="Main/Tabs/Settings"]
margin_top = 210.0
margin_top = 245.0
margin_right = 769.0
margin_bottom = 239.0
margin_bottom = 274.0
hint_tooltip = "Use this if the automatically inferred UI scale
looks too large or too small on your system.
(Automatic scale relies on system-reported
Expand Down Expand Up @@ -979,14 +988,14 @@ editable = false
suffix = "%"

[node name="HSeparator" type="HSeparator" parent="Main/Tabs/Settings"]
margin_top = 245.0
margin_top = 280.0
margin_right = 769.0
margin_bottom = 253.0
margin_bottom = 288.0

[node name="Migration" type="VBoxContainer" parent="Main/Tabs/Settings"]
margin_top = 259.0
margin_top = 294.0
margin_right = 769.0
margin_bottom = 381.0
margin_bottom = 416.0
hint_tooltip = "Choose which types of game data to carry over
into the new game version when updating."

Expand Down Expand Up @@ -1134,7 +1143,7 @@ size_flags_horizontal = 4
text = "Print a random Tip of the Day"

[node name="Log" type="RichTextLabel" parent="Main"]
margin_top = 681.0
margin_top = 565.0
margin_right = 784.0
margin_bottom = 984.0
focus_mode = 2
Expand Down Expand Up @@ -1203,10 +1212,10 @@ __meta__ = {
}

[connection signal="meta_clicked" from="Main/GameInfo/Description" to="." method="_on_Description_meta_clicked"]
[connection signal="tab_changed" from="Main/Tabs" to="." method="_on_Tabs_tab_changed"]
[connection signal="tab_changed" from="Main/Tabs" to="Main/Tabs/Mods" method="_on_Tabs_tab_changed"]
[connection signal="tab_changed" from="Main/Tabs" to="Main/Tabs/Fonts" method="_on_Tabs_tab_changed"]
[connection signal="tab_changed" from="Main/Tabs" to="Main/Tabs/Soundpacks" method="_on_Tabs_tab_changed"]
[connection signal="tab_changed" from="Main/Tabs" to="." method="_on_Tabs_tab_changed"]
[connection signal="tab_changed" from="Main/Tabs" to="Main/Tabs/Fonts" method="_on_Tabs_tab_changed"]
[connection signal="item_selected" from="Main/Tabs/Game/Builds/BuildsList" to="." method="_on_BuildsList_item_selected"]
[connection signal="pressed" from="Main/Tabs/Game/Builds/BtnRefresh" to="." method="_on_BtnRefresh_pressed"]
[connection signal="pressed" from="Main/Tabs/Game/BtnInstall" to="." method="_on_BtnInstall_pressed"]
Expand Down Expand Up @@ -1248,6 +1257,7 @@ __meta__ = {
[connection signal="toggled" from="Main/Tabs/Settings/PrintTips" to="Main/Tabs/Settings" method="_on_PrintTips_toggled"]
[connection signal="toggled" from="Main/Tabs/Settings/UpdateToSame" to="Main/Tabs/Settings" method="_on_UpdateToSame_toggled"]
[connection signal="toggled" from="Main/Tabs/Settings/ShortenNames" to="Main/Tabs/Settings" method="_on_ShortenNames_toggled"]
[connection signal="toggled" from="Main/Tabs/Settings/ShowObsoleteMods" to="Main/Tabs/Settings" method="_on_ShowObsoleteMods_toggled"]
[connection signal="toggled" from="Main/Tabs/Settings/ShowDebug" to="Main/Tabs/Settings" method="_on_ShowDebug_toggled"]
[connection signal="value_changed" from="Main/Tabs/Settings/NumReleases/sbNumReleases" to="Main/Tabs/Settings" method="_on_sbNumReleases_value_changed"]
[connection signal="toggled" from="Main/Tabs/Settings/ScaleOverride/cbScaleOverrideEnable" to="Main/Tabs/Settings" method="_on_cbScaleOverrideEnable_toggled"]
Expand Down
119 changes: 73 additions & 46 deletions scripts/ModManager.gd
Original file line number Diff line number Diff line change
Expand Up @@ -34,32 +34,32 @@ onready var _downloader = $"../Downloader"
onready var _workdir = OS.get_executable_path().get_base_dir()


var installed: Array = [] setget , _get_installed
var available: Array = [] setget , _get_available
var installed: Dictionary = {} setget , _get_installed
var available: Dictionary = {} setget , _get_available


func _get_installed() -> Array:
func _get_installed() -> Dictionary:

if installed == []:
if len(installed) == 0:
refresh_installed()

return installed


func _get_available() -> Array:
func _get_available() -> Dictionary:

if available == []:
if len(available) == 0:
refresh_available()

return available


func parse_mods_dir(mods_dir: String) -> Array:
func parse_mods_dir(mods_dir: String) -> Dictionary:

if not Directory.new().dir_exists(mods_dir):
return []
return {}

var result = []
var result = {}

for subdir in _fshelper.list_dir(mods_dir):
var f = File.new()
Expand Down Expand Up @@ -90,10 +90,10 @@ func parse_mods_dir(mods_dir: String) -> Array:
else:
info["id"] = info["name"]

result.append({
result[info["id"]] = {
"location": mods_dir + "/" + subdir,
"modinfo": info
})
}
break

f.close()
Expand All @@ -113,41 +113,63 @@ func _strip_html_tags(text: String) -> String:
s = s.replace(m.get_string(), "")

return s



func _sorting_comparison(a: Dictionary, b: Dictionary) -> bool:

return (a["modinfo"]["name"].nocasecmp_to(b["modinfo"]["name"]) == -1)
func mod_status(id: String) -> int:

# Returns mod installed status:
# 0 - not installed;
# 1 - installed;
# 2 - stock mod;
# 3 - stock mod but obsolete;
# 4 - installed with modified ID.

if id + "__" in installed:
return 4
elif id in installed:
if installed[id]["is_stock"]:
if installed[id]["is_obsolete"]:
return 3
else:
return 2
else:
return 1
else:
return 0


func refresh_installed(sort_by_name = true):
func refresh_installed():

var gamedir = _workdir + "/" + _settings.read("game") + "/current"
installed = []
installed = {}

var non_stock := {}
if Directory.new().dir_exists(gamedir + "/mods"):
var non_stock = parse_mods_dir(gamedir + "/mods")
for mod in non_stock:
mod["is_stock"] = false
installed.append_array(non_stock)
non_stock = parse_mods_dir(gamedir + "/mods")
for id in non_stock:
non_stock[id]["is_stock"] = false

var stock = parse_mods_dir(gamedir + "/data/mods")
for mod in stock:
mod["is_stock"] = true
installed.append_array(stock)
var stock := parse_mods_dir(gamedir + "/data/mods")
for id in stock:
stock[id]["is_stock"] = true
if ("obsolete" in stock[id]["modinfo"]) and (stock[id]["modinfo"]["obsolete"] == true):
stock[id]["is_obsolete"] = true
else:
stock[id]["is_obsolete"] = false

for id in non_stock:
installed[id] = non_stock[id]
installed[id]["is_stock"] = false
installed[id]["is_obsolete"] = false

if sort_by_name:
installed.sort_custom(self, "_sorting_comparison")
for id in stock:
installed[id] = stock[id]


func refresh_available(sort_by_name = true):
func refresh_available():

var mod_repo = _workdir + "/" + _settings.read("game") + "/mod_repo"
available = parse_mods_dir(mod_repo)

if sort_by_name:
available.sort_custom(self, "_sorting_comparison")


func _delete_mod(mod_id: String) -> void:
Expand All @@ -156,13 +178,8 @@ func _delete_mod(mod_id: String) -> void:
# Have to introduce an artificial delay, otherwise the engine becomes very
# crash-happy when processing large numbers of mods.

var mod = null
for item in installed:
if item["modinfo"]["id"] == mod_id:
mod = item
break

if mod:
if mod_id in installed:
var mod = installed[mod_id]
_fshelper.rm_dir(mod["location"])
yield(_fshelper, "rm_dir_done")
emit_signal("status_message", "Deleted %s" % mod["modinfo"]["name"])
Expand All @@ -183,7 +200,10 @@ func delete_mods(mod_ids: Array) -> void:
emit_signal("mod_deletion_started")

for id in mod_ids:
_delete_mod(id)
if mod_status(id) == 4:
_delete_mod(id + "__")
else:
_delete_mod(id)
yield(self, "_done_deleting_mod")

refresh_installed()
Expand All @@ -197,15 +217,22 @@ func _install_mod(mod_id: String) -> void:

var mods_dir = _workdir + "/" + _settings.read("game") + "/current/mods"

var mod = null
for item in available:
if item["modinfo"]["id"] == mod_id:
mod = item
break

if mod:
if mod_id in available:
var mod = available[mod_id]

_fshelper.copy_dir(mod["location"], mods_dir)
yield(_fshelper, "copy_dir_done")

if (mod_id in installed) and (installed[mod_id]["is_obsolete"] == true):
emit_signal("status_message", "There is already an obsoleted mod with ID %s. [i]%s[/i] will be installed with modified ID and name to avoid collisions."
% [mod_id, mod["modinfo"]["name"]])
var modinfo = mod["modinfo"].duplicate()
modinfo["id"] += "__"
modinfo["name"] += "*"
var f = File.new()
f.open(mods_dir.plus_file(mod["location"].get_file()).plus_file("modinfo.json"), File.WRITE)
f.store_string(JSON.print(modinfo, " "))

emit_signal("status_message", "Installed %s" % mod["modinfo"]["name"])
else:
emit_signal("status_message", "Could not find mod with ID \"%s\"" % mod_id, Enums.MSG_ERROR)
Expand Down
Loading

0 comments on commit 82f1c42

Please sign in to comment.