-
-
Notifications
You must be signed in to change notification settings - Fork 9
/
modloader.lua
118 lines (91 loc) · 2.81 KB
/
modloader.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
local physfs = require("physfs")
local class = require("class")
---@class sphere.ModLoader
---@operator call: sphere.ModLoader
local ModLoader = class()
local modsDirectoryPath = "moddedgame"
local scriptFileName = "mod.lua"
---@param path string
function ModLoader:new(path)
self.root = path
end
---@return table[]
local function getMods()
local mods = {}
local modDirs = love.filesystem.getDirectoryItems(modsDirectoryPath)
for _, dir in ipairs(modDirs) do
local modPath = modsDirectoryPath .. "/" .. dir .. "/" .. scriptFileName
local modModule = love.filesystem.getInfo(modPath)
local mod = {
scriptFile = nil,
instance = nil,
directory = dir,
}
if modModule then
mod.scriptFile = assert(love.filesystem.load(modPath))
end
table.insert(mods, mod)
end
return mods
end
---@param modPath string
---@param filePath string
---@param fileMap table
---@param conflicts string[]
local function hasConflict(modPath, filePath, fileMap, conflicts)
local path = modPath .. filePath
for _, file in ipairs(love.filesystem.getDirectoryItems(path)) do
local fullPath = filePath .. "/" .. file
if love.filesystem.getInfo(modPath .. fullPath, "directory") then
hasConflict(modPath, fullPath, fileMap, conflicts)
else
if fileMap[fullPath] ~= nil then
table.insert(conflicts, fullPath)
end
if file ~= scriptFileName then
fileMap[fullPath] = true
end
end
end
end
---@param mods table[]
---@return string[]
local function checkForConflicts(mods)
local conflicts = {}
local fileMap = {}
for _, mod in pairs(mods) do
hasConflict(modsDirectoryPath .. "/" .. mod.directory .. "/", "", fileMap, conflicts)
end
return conflicts
end
---@param root string
---@param directory string
local function mount(root, directory)
local success, err = physfs.mount(root .. "/" .. modsDirectoryPath .. "/" .. directory .. "/", "/", false)
success = success and true or false
if not success then
error("Error mounting mod: " .. err)
end
end
function ModLoader:loadMods()
local mods = getMods()
local conflicts = checkForConflicts(mods)
if #conflicts ~= 0 then
for _, file in ipairs(conflicts) do
print("Conflict: " .. file)
end
error("Two or more mods are modifying the same file. Check the console for details.")
end
for _, mod in pairs(mods) do
mount(self.root, mod.directory)
if mod.scriptFile then
mod.instance = mod.scriptFile()
end
end
for _, mod in pairs(mods) do
if mod.instance then
mod.instance:init(mods)
end
end
end
return ModLoader