From 299d520af6b3e54ec81edcf5217c66d44ee0ead6 Mon Sep 17 00:00:00 2001 From: Till Affeldt Date: Tue, 14 Apr 2020 11:25:00 +0200 Subject: [PATCH] Implement sounds, enable start and stop events --- TODO.md | 7 ++---- ca_effects/clouds.lua | 4 ++-- ca_effects/skybox.lua | 2 +- ca_effects/sound.lua | 55 +++++++++++++++++++++++++++++++++++++++---- init.lua | 5 +++- lib/api.lua | 10 +++++--- lib/influences.lua | 30 +++++++++++++++++++++++ lib/main.lua | 3 ++- lib/trigger.lua | 52 ++++++++++++++++++++++++++++++++++++---- 9 files changed, 146 insertions(+), 22 deletions(-) create mode 100644 lib/influences.lua diff --git a/TODO.md b/TODO.md index d8f494e..c01ad06 100644 --- a/TODO.md +++ b/TODO.md @@ -2,21 +2,18 @@ ## Required for MVP - Test non-random heat and humidity values -- Re-implement sounds into new engine -- Implement start/end events - Make sure all weather presets are working -- Implement chat commands ## Planned for first release - Improve test_condition function - Implement ABM system for additional effects - Add light level to possible conditions - Implement fallback for sky changes without skylayer -- Configurable number of days in a year -- Add license information to source files - Write helpful README - Find good values for weather conditions - Set effects on player join +- Improve value structures of particle and skybox effects +- Make sounds adjust to changes by weather presets ## Nice to have - Write documentation on how to add weathers and effects diff --git a/ca_effects/clouds.lua b/ca_effects/clouds.lua index 32cb997..1bb3ecf 100644 --- a/ca_effects/clouds.lua +++ b/ca_effects/clouds.lua @@ -4,7 +4,7 @@ if not minetest.get_modpath("skylayer") then return end local SKYBOX_NAME = "climate_api:clouds" local function set_clouds(player, clouds) - sky = { name = SKYBOX_NAME, cloud_data = clouds } + local sky = { name = SKYBOX_NAME, cloud_data = clouds } skylayer.add_layer(player:get_player_name(), sky) end @@ -44,5 +44,5 @@ local function remove_effect(player_data) end climate_api.register_effect("climate_api:clouds", handle_effect, "tick") -climate_api.register_effect("climate_api:clouds", remove_effect, "end") +climate_api.register_effect("climate_api:clouds", remove_effect, "stop") climate_api.set_effect_cycle("climate_api:clouds", climate_api.LONG_CYCLE) \ No newline at end of file diff --git a/ca_effects/skybox.lua b/ca_effects/skybox.lua index e876f36..d5d9719 100644 --- a/ca_effects/skybox.lua +++ b/ca_effects/skybox.lua @@ -31,5 +31,5 @@ local function remove_effect(player_data) end climate_api.register_effect("climate_api:skybox", handle_effect, "tick") -climate_api.register_effect("climate_api:skybox", remove_effect, "end") +climate_api.register_effect("climate_api:skybox", remove_effect, "stop") climate_api.set_effect_cycle("climate_api:skybox", climate_api.LONG_CYCLE) \ No newline at end of file diff --git a/ca_effects/sound.lua b/ca_effects/sound.lua index 890cbd4..4edc9b1 100644 --- a/ca_effects/sound.lua +++ b/ca_effects/sound.lua @@ -1,14 +1,59 @@ if not climate_mod.settings.sound then return end -return +local handles = {} +local function start_sound(pname, weather, sound) + if handles[pname] == nil then handles[pname] = {} end + if handles[pname][weather] ~= nil then return end + local handle = minetest.sound_play(sound, { + to_player = pname, + loop = true + }) + handles[pname][weather] = handle +end -local function update_effect(player_data) +local function stop_sound(pname, weather, sound) + if handles[pname] == nil or handles[pname][weather] == nil then return end + local handle = handles[pname][weather] + minetest.sound_stop(handle) + handles[pname][weather] = nil +end + +local function start_effect(player_data) for playername, data in pairs(player_data) do for weather, value in pairs(data) do - climate_mod.effects.play_sound(player, value) + start_sound(playername, weather, value) end end end -climate_api.register_effect("climate_api:sound", update_effect, "change") -climate_api.set_effect_cycle("climate_api:skybox", climate_api.MEDIUM_CYCLE) \ No newline at end of file +local function handle_effect(player_data, prev_data) + for playername, data in pairs(player_data) do + for weather, value in pairs(data) do + if prev_data[playername][weather] == nil then + start_sound(playername, weather, sound) + end + end + end + + for playername, data in pairs(prev_data) do + for weather, value in pairs(data) do + if player_data[playername][weather] == nil then + stop_sound(playername, weather, sound) + end + end + end +end + +local function stop_effect(prev_data) + minetest.log(dump2(prev_data, "stop_effect")) + for playername, data in pairs(prev_data) do + for weather, value in pairs(data) do + stop_sound(playername, weather, value) + end + end +end + +climate_api.register_effect("climate_api:sound", start_effect, "start") +climate_api.register_effect("climate_api:sound", handle_effect, "tick") +climate_api.register_effect("climate_api:sound", stop_effect, "stop") +climate_api.set_effect_cycle("climate_api:sound", 0) \ No newline at end of file diff --git a/init.lua b/init.lua index 53ae2e9..2c0d09c 100644 --- a/init.lua +++ b/init.lua @@ -38,18 +38,21 @@ climate_mod.current_effects = {} climate_mod.weathers = {} climate_mod.effects = {} climate_mod.cycles = {} +climate_mod.influences = {} -- import core API climate_mod.state = dofile(modpath .. "/lib/datastorage.lua") climate_api = dofile(modpath .. "/lib/api.lua") climate_api.utility = dofile(modpath .. "/lib/api_utility.lua") climate_api.environment = dofile(modpath .. "/lib/environment.lua") +--climate_api = dofile(modpath .. "/lib/influences.lua") climate_mod.world = dofile(modpath .. "/lib/world.lua") climate_mod.trigger = dofile(modpath .. "/lib/trigger.lua") dofile(modpath.."/lib/main.lua") dofile(modpath.."/lib/commands.lua") -- import predefined environment effects +dofile(modpath .. "/ca_effects/clouds.lua") dofile(modpath .. "/ca_effects/particles.lua") dofile(modpath .. "/ca_effects/skybox.lua") -dofile(modpath .. "/ca_effects/clouds.lua") +dofile(modpath .. "/ca_effects/sound.lua") diff --git a/lib/api.lua b/lib/api.lua index abdc7f5..c40bba3 100644 --- a/lib/api.lua +++ b/lib/api.lua @@ -2,7 +2,7 @@ local api = {} api.SHORT_CYCLE = 0.03 -- for particles and fast animations api.DEFAULT_CYCLE = 0.1 -- for most effect types -api.MEDIUM_CYCKE = 2.0 -- for ressource intensive tasks +api.MEDIUM_CYCLE = 2.0 -- for ressource intensive tasks api.LONG_CYCLE = 5.0 -- for write operations and skybox changes function api.register_weather(name, conditions, effects) @@ -17,13 +17,13 @@ end function api.register_effect(name, handler, htype) -- check for valid handler types if htype ~= "start" and htype ~= "tick" and htype ~= "stop" then - minetest.log("warn", "[Climate API] Invalid effect handler type: " .. htype) + minetest.log("warning", "[Climate API] Invalid effect handler type: " .. htype) return end -- create effect handler registry if not existent yet if type(climate_mod.effects[name]) == "nil" then climate_mod.effects[name] = { start = {}, tick = {}, stop = {} } - climate_mod.cycles[name] = { timespan = DEFAULT_CYCLE, timer = 0 } + climate_mod.cycles[name] = { timespan = api.DEFAULT_CYCLE, timer = 0 } end -- store effect handler table.insert(climate_mod.effects[name][htype], handler) @@ -33,4 +33,8 @@ function api.set_effect_cycle(name, cycle) climate_mod.cycles[name].timespan = cycle end +--[[function api.register_influence(name, func) + climate_mod.influences[name] = func +end]] + return api diff --git a/lib/influences.lua b/lib/influences.lua new file mode 100644 index 0000000..6536080 --- /dev/null +++ b/lib/influences.lua @@ -0,0 +1,30 @@ +climate_api.register_influence("heat", function(player) + return climate_mod.get_heat(player:get_pos()) +end) + +climate_api.register_influence("humidity", function(player) + return climate_mod.get_humidity(player:get_pos()) +end) + +climate_api.register_influence("windspeed", function(player) + local wind_x = climate_mod.state:get_float("wind_x") + local wind_z = climate_mod.state:get_float("wind_z") + return vector.length({x = wind_x, y = 0, z = wind_z}) +end) + +climate_api.register_influence("wind_x", function(player) + return climate_mod.state:get_float("wind_x") +end) + +climate_api.register_influence("wind_z", function(player) + return climate_mod.state:get_float("wind_z") +end) + +climate_api.register_influence("height", function(player) + local ppos = player:get_pos() + return ppos.y +end) + +climate_api.register_influence("light", function(player) + return minetest.env:get_node_light(player:get_pos(), 0.5) +end) \ No newline at end of file diff --git a/lib/main.lua b/lib/main.lua index 71f2773..22c2e43 100644 --- a/lib/main.lua +++ b/lib/main.lua @@ -16,12 +16,13 @@ minetest.register_globalstep(function(dtime) climate_mod.world.update_status(noise_timer) end + local previous_effects = climate_mod.current_effects climate_mod.current_effects = climate_mod.trigger.get_active_effects() for name, effect in pairs(climate_mod.effects) do if climate_mod.cycles[name].timespan < climate_mod.cycles[name].timer + dtime then climate_mod.cycles[name].timer = 0 - climate_mod.trigger.call_handlers(name, climate_mod.current_effects[name]) + climate_mod.trigger.call_handlers(name, climate_mod.current_effects[name], previous_effects[name]) else climate_mod.cycles[name].timer = climate_mod.cycles[name].timer + dtime end diff --git a/lib/trigger.lua b/lib/trigger.lua index b449fcc..4f217b2 100644 --- a/lib/trigger.lua +++ b/lib/trigger.lua @@ -91,10 +91,54 @@ function trigger.get_active_effects() return effects end -function trigger.call_handlers(name, effect) - if type(effect) == "nil" then return end - for _, handler in ipairs(climate_mod.effects[name]["tick"]) do - handler(effect) +function trigger.call_handlers(name, effect, prev_effect) + if effect == nil then effect = {} end + if prev_effect == nil then prev_effect = {} end + + local starts = {} + local has_starts = false + local ticks = {current = {}, prev = {}} + local has_ticks = false + local stops = {} + local has_stops = false + + for player, sources in pairs(effect) do + if type(prev_effect[player]) ~= "nil" then + has_ticks = true + ticks.current[player] = sources + ticks.prev[player] = prev_effect[player] + --prev_effect[player] = nil -- remove any found entries + else + has_starts = true + starts[player] = sources + end + end + + for player, sources in pairs(prev_effect) do + if type(effect[player]) == "nil" then + stops[player] = sources + has_stops = true + end + end + + if has_starts then + for _, handler in ipairs(climate_mod.effects[name]["start"]) do + handler(starts) + end + end + + if has_ticks then + for _, handler in ipairs(climate_mod.effects[name]["tick"]) do + handler(ticks.current, ticks.prev) + end + end + + -- remaining table lists ending effects + if has_stops then + minetest.log(dump2(name, "AAAAAAAAAAA")) + for _, handler in ipairs(climate_mod.effects[name]["stop"]) do + handler(stops) + end end end