Skip to content

Commit

Permalink
Merge pull request #283 from Ruin0x11/refactor/aspect-smithing
Browse files Browse the repository at this point in the history
Refactor smithing mod to use aspects
  • Loading branch information
Ruin0x11 authored Apr 18, 2021
2 parents 5db3097 + 4c02802 commit f5c2b41
Show file tree
Hide file tree
Showing 40 changed files with 686 additions and 151 deletions.
6 changes: 5 additions & 1 deletion src/api/IAspect.lua
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
local IAspectModdable = require("api.IAspectModdable")

local IAspect = class.interface("IAspect", {}, { IAspectModdable })
local IAspect = class.interface("IAspect", { localize_action = "function" }, { IAspectModdable })

function IAspect:localize_action(obj, iface)
return "???"
end

return IAspect
2 changes: 1 addition & 1 deletion src/api/IEventEmitter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ function IEventEmitter:on_reload_prototype(old_id)

local events = self.proto and self.proto.events
if events then
Log.debug("Loading %d events of %s:%s for object %d", #events, self._type, self._id, self.uid)
Log.debug("Loading %d events of %s:%s for object %s", #events, self._type, self._id, self)
self:connect_self_multiple(events, true)
end
end
Expand Down
9 changes: 9 additions & 0 deletions src/api/test/TestUtil.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ local field = require("game.field")
local Item = require("api.Item")
local Enum = require("api.Enum")
local IItem = require("api.item.IItem")
local env = require("internal.env")
local hotload = require("internal.hotload")

local TestUtil = {}

Expand Down Expand Up @@ -62,4 +64,11 @@ function TestUtil.stripped_item(id, map, x, y, amount, aspects)
return item
end

local transient_paths = table.set {}

function TestUtil.hotload_code(path, mod_id, code)
env.load_transient_path(path, mod_id, code)
return hotload.hotload(path, false)
end

return TestUtil
69 changes: 54 additions & 15 deletions src/internal/env.lua
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ local SANDBOX_GLOBALS = {
"unpack",
"xpcall",
"collectgarbage",
"getmetatable",
"setmetatable",

-- Lua stdlib
"table",
Expand Down Expand Up @@ -96,6 +98,10 @@ local paths_loaded_by_hooked_require = {}
-- This table supports retrieving a module/class table given a function object.
local fn_to_module = setmetatable({}, { __mode = "k" })

-- Paths with in-memory Lua code strings. Used for testing.
-- Looks like {{ mod_id = "@test@", code = "require()..." }}
local transient_paths = {}

-- This flag is used for e.g. relayouting all UI layers on hotload so
-- the changes are visible immediately and on_hotload() can be called.
local hotloaded_this_frame = false
Expand Down Expand Up @@ -197,6 +203,10 @@ local function can_load_native_libs(mod_env)
end

local function get_require_path(path, mod_env)
if transient_paths[path] then
return path
end

local resolved = package.searchpath(path, package.path)

if resolved == nil and can_load_native_libs(mod_env) then
Expand Down Expand Up @@ -291,7 +301,12 @@ local function env_dofile(path, mod_env)
rawset(_G, "_ENV", nil)
chunk, err = loadstring(str)
else
chunk, err = loadfile(resolved)
local transient = transient_paths[path]
if transient then
chunk, err = loadstring(transient.code)
else
chunk, err = loadfile(resolved)
end
end

if chunk == nil then
Expand All @@ -313,6 +328,11 @@ end
function env.load_sandboxed_chunk(path, mod_name)
mod_name = mod_name or env.find_calling_mod()

local transient = transient_paths[path]
if transient then
mod_name = transient.mod_id
end

-- TODO: cache this somewhere.
local mod_env = env.generate_sandbox(mod_name, true)

Expand All @@ -337,6 +357,10 @@ local function get_load_type(path)
end

local function can_hotload(path)
if transient_paths[path] then
return true
end

if get_require_path(path) == nil then
return false
end
Expand Down Expand Up @@ -606,7 +630,12 @@ function env.hotload_path(path, also_deps)
local loaded = package.loaded[path]
if not loaded then
Log.warn("Tried to hotload '%s', but path was not yet loaded. Requiring normally.", path)
return env.safe_require(path, false)

local result = env.safe_require(path, false)
return {
require_path = path,
module = result
}
end

if also_deps then
Expand All @@ -619,7 +648,7 @@ function env.hotload_path(path, also_deps)
HOTLOADING_PATH = path
local result = env.require(path, true)
HOTLOADING_PATH = false
Log.trace("End hotload: %s %s", path, inspect(result))
Log.trace("End hotload: %s %s", path, result)

if also_deps then
HOTLOAD_DEPS = false
Expand All @@ -628,9 +657,8 @@ function env.hotload_path(path, also_deps)
hotloaded_this_frame = true

return {
result = result,
require_path = path,
module = package.loaded[path]
module = result
}
end

Expand All @@ -642,16 +670,6 @@ function env.hotload_all()
end
end

-- Redefines a single function on an API table by loading its chunk
-- and copying only it to the currently loaded table.
-- NOTE: The function cannot reference any chunk-local upvalues, or
-- the behavior will not work as expected if used along with the other
-- values in the table, since they may reference the same-named
-- upvalue but in the original chunk.
function env.redefine(path, name)
-- TODO
end

--- Returns the currently hotloading path if hotloading is ongoing.
--- Used to implement specific support for hotloading in global
--- variables besides the entries in package.loaded.
Expand Down Expand Up @@ -754,6 +772,26 @@ function env.is_loaded(path)
return package.loaded[path] ~= nil
end

function env.unload_path(path)
paths_loaded_by_hooked_require[path] = nil
require_path_cache[path] = nil
transient_paths[path] = nil
package.loaded[path] = nil
end

function env.load_transient_path(path, mod_id, code)
assert(type(mod_id) == "string")
assert(type(code) == "string")
transient_paths[path] = { mod_id = mod_id, code = code }
end

function env.unload_transient_paths()
for path, _ in pairs(transient_paths) do
env.unload_path(path)
end
transient_paths = {}
end

function env.restart_debug_server()
Log.warn("Restarting debug server...")
env.server_needs_restart = true
Expand Down Expand Up @@ -794,6 +832,7 @@ function env.reset()
paths_loaded_by_hooked_require = {}
require_path_cache = setmetatable({}, { __mode = "k" })
fn_to_module = setmetatable({}, { __mode = "k" })
transient_paths = {}
hotloaded_this_frame = false

Log = require("api.Log")
Expand Down
10 changes: 5 additions & 5 deletions src/internal/hotload.lua
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@ function hotload.hotload(path_or_class, also_deps)
path_or_class = path
end

local ok, result, err
local ok, result, hotload_result, err
ok, result = pcall(Event.trigger, "base.on_hotload_begin", {path_or_class=path_or_class,also_deps=also_deps})
if not ok then
Log.error("Error on on_hotload_begin: %s", result)
err = result
end

ok, result = xpcall(env.hotload_path, debug.traceback, path_or_class, also_deps)
ok, hotload_result = xpcall(env.hotload_path, debug.traceback, path_or_class, also_deps)
if not ok then
Log.error("Error on hotload_path: %s", result)
err = result
err = hotload_result
end

ok, result = xpcall(Event.trigger, debug.traceback,
Expand All @@ -61,7 +61,7 @@ function hotload.hotload(path_or_class, also_deps)
path_or_class=path_or_class,
also_deps=also_deps,
ok=ok,
result=result
result=hotload_result
})

if not ok then
Expand All @@ -73,7 +73,7 @@ function hotload.hotload(path_or_class, also_deps)
error(err)
end

return result
return hotload_result
end

Event.register("base.on_hotload_end", "Hotload field renderer",
Expand Down
19 changes: 19 additions & 0 deletions src/mod/elona/api/Gardening.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ local Chara = require("api.Chara")
local Save = require("api.Save")
local Weather = require("mod.elona.api.Weather")
local IItemSeed = require("mod.elona.api.aspect.IItemSeed")
local Itemgen = require("mod.elona.api.Itemgen")

local Gardening = {}

Expand Down Expand Up @@ -213,4 +214,22 @@ function Gardening.harvest_plant(plant, chara)
-- <<<<<<<< elona122/shade2/action.hsp:2351 return ..
end

function Gardening.generate_item(cb)
if type(cb) == "table" then
local filter = cb
cb = function() return table.deepcopy(filter) end
end
return function(plant, params)
local filter = cb(plant, params)

filter.level = filter.level or params.chara:skill_level("elona.gardening") / 2 + 15
filter.quality = filter.quality or Enum.Quality.Normal
filter.no_stack = true

local item = Itemgen.create(plant.x, plant.y, filter, params.chara)
Gui.mes("action.plant.harvest", item:build_name())
item:stack(true)
end
end

return Gardening
6 changes: 6 additions & 0 deletions src/mod/elona/api/aspect/IEvented.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
local IEvented = class.interface("IEvented",
{
get_events = "function"
})

return IEvented
4 changes: 4 additions & 0 deletions src/mod/elona/api/aspect/IItemSeed.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ local IItemSeed = class.interface("IItemSeed", { plant_id = "string" }, { IAspec

IItemSeed.default_impl = "mod.elona.api.aspect.ItemSeedAspect"

function IItemSeed:localize_action()
return "base:aspect._.elona.IItemSeed.action_name"
end

return IItemSeed
2 changes: 1 addition & 1 deletion src/mod/elona/api/aspect/IItemUseable.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
local IItemUseable = class.interface("IItemUseable",
{
on_use = "function",
on_use = "function"
})

return IItemUseable
35 changes: 8 additions & 27 deletions src/mod/elona/data/plant.lua
Original file line number Diff line number Diff line change
@@ -1,70 +1,51 @@
local Gui = require("api.Gui")
local Itemgen = require("mod.elona.api.Itemgen")
local Rand = require("api.Rand")
local Filters = require("mod.elona.api.Filters")
local Save = require("api.Save")
local Enum = require("api.Enum")
local Gardening = require("mod.elona.api.Gardening")

data:add_type {
name = "plant"
}

local function generate_item(cb)
if type(cb) == "table" then
local filter = cb
cb = function() return table.deepcopy(filter) end
end
return function(plant, params)
local filter = cb(plant, params)

filter.level = filter.level or params.chara:skill_level("elona.gardening") / 2 + 15
filter.quality = filter.quality or Enum.Quality.Normal
filter.no_stack = true

local item = Itemgen.create(plant.x, plant.y, filter, params.chara)
Gui.mes("action.plant.harvest", item:build_name())
item:stack(true)
end
end

data:add {
_type = "elona.plant",
_id = "vegetable",
growth_difficulty = 10,
regrowth_difficulty = 15,
on_harvest = generate_item { categories = "elona.food_vegetable" }
on_harvest = Gardening.generate_item { categories = "elona.food_vegetable" }
}

data:add {
_type = "elona.plant",
_id = "fruit",
growth_difficulty = 10,
regrowth_difficulty = 15,
on_harvest = generate_item { categories = "elona.food_fruit" }
on_harvest = Gardening.generate_item { categories = "elona.food_fruit" }
}

data:add {
_type = "elona.plant",
_id = "herb",
growth_difficulty = 30,
regrowth_difficulty = 40,
on_harvest = generate_item { categories = "elona.crop_herb" }
on_harvest = Gardening.generate_item { categories = "elona.crop_herb" }
}

data:add {
_type = "elona.plant",
_id = "gem",
growth_difficulty = 15,
regrowth_difficulty = 25,
on_harvest = generate_item { categories = "elona.ore_valuable" }
on_harvest = Gardening.generate_item { categories = "elona.ore_valuable" }
}

data:add {
_type = "elona.plant",
_id = "magical_plant",
growth_difficulty = 25,
regrowth_difficulty = 30,
on_harvest = generate_item { categories = "elona.rod" }
on_harvest = Gardening.generate_item { categories = "elona.rod" }
}

local function generate_artifact()
Expand All @@ -79,7 +60,7 @@ data:add {
_id = "unknown_plant",
growth_difficulty = 25,
regrowth_difficulty = 35,
on_harvest = generate_item(function(plant, params)
on_harvest = Gardening.generate_item(function(plant, params)
local filter = {
categories = Rand.choice(Filters.fsetplantunknown)
}
Expand All @@ -101,7 +82,7 @@ data:add {
_id = "artifact",
growth_difficulty = 40,
regrowth_difficulty = math.huge,
on_harvest = generate_item(function(plant, params)
on_harvest = Gardening.generate_item(function(plant, params)
local filter = {}
if Rand.one_in(50) then
filter = generate_artifact()
Expand Down
Loading

0 comments on commit f5c2b41

Please sign in to comment.