write something there
This commit is contained in:
commit
b4b6c08f4f
8546 changed files with 309825 additions and 0 deletions
69
mods/music_modpack/README.md
Normal file
69
mods/music_modpack/README.md
Normal file
|
@ -0,0 +1,69 @@
|
|||
# music_modpack
|
||||
|
||||

|
||||
|
||||
## Overview
|
||||
Music modpack with API for easy in-game music playback and custom track registration.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Minetest 5.0.0+
|
||||
- Minetest_game 5.0.0+
|
||||
- [sfinv_buttons](https://repo.or.cz/minetest_sfinv_buttons.git) (Optional, but highly recommended: easy way to open music settings menu)
|
||||
|
||||
## Features
|
||||
|
||||
- Time-based music
|
||||
- Elevation-based music
|
||||
- Formspec for music settings
|
||||
|
||||
## Settings
|
||||
By default, settings menu is only available with `/musicsettings` command. If you have sfinv_buttons installed, music menu is available in inventory->more->music settings
|
||||
|
||||
## Adding your own music
|
||||
Call music.register_track() with following definition:
|
||||
|
||||
```Lua
|
||||
music.register_track({
|
||||
name = "my_track",
|
||||
length = 200,
|
||||
gain = 1,
|
||||
day = true,
|
||||
night = true,
|
||||
ymin = 0,
|
||||
ymax = 31000,
|
||||
})
|
||||
```
|
||||
|
||||
- name - name of the sound file in your mod sounds folder, without extension (.ogg)
|
||||
- length - length of the track in seconds
|
||||
- gain - volume, value from 0 to 1
|
||||
- day - track will be played at day
|
||||
- night - track will be played at night
|
||||
- ymin - minimum elevation for track to play
|
||||
- ymax - maximum elevation for track to play
|
||||
|
||||
## Settingtypes
|
||||
Available settings that you can put in your minetest.conf directly, or access them via "Settings->All Settings->Mods->music_modpack" menu.
|
||||
|
||||
```
|
||||
music_time_interval = integer, Interval between attempts to play music, default is 60
|
||||
music_cleanup_interval = integer, interval between attempts to clean up player state, default is 5
|
||||
music_global_gain = float, global music volume, default is 0.3
|
||||
music_add_random_delay = boolean, if to add a random delay to interval between attempts, default is true
|
||||
music_maximum_random_delay = - integer, maximum random delay in seconds, default is 30
|
||||
music_display_playback_messages = boolean, display messages when music starts for a certain player, default is true
|
||||
```
|
||||
|
||||
Music packs also provide settingtypes with corresponding height limits.
|
||||
|
||||
## Content
|
||||
Default pack features 11 tracks from composer Kevin McLeod. Tracks are split into day tracks and night tracks. If music_dfcaverns is not enabled, night tracks also play underground (up to -31000).
|
||||
Music_dfcaverns is an additional pack of music for underground layers from [dfcaverns](https://github.com/FaceDeer/dfcaverns/), featuring 13 tracks from composer Kevin McLeod. Tracks split into three categories, each for one cavern layer from dfcaverns, and their heights are set accordingly. Dfcaverns modpack is not required, however, and it is recommended to enable this pack even without dfcaverns, unless client connection speed is an issue.
|
||||
|
||||
## License
|
||||
|
||||
Code is licensed under GPLv3.
|
||||
|
||||
All music used in this mod was produced by Kevin McLeod and released under CC BY 4.0. [link to the license](https://creativecommons.org/licenses/by/4.0/).
|
||||
Original music can be found [here](https://incompetech.com/music/royalty-free/music.html).
|
1
mods/music_modpack/description.txt
Normal file
1
mods/music_modpack/description.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Music modpack with API for easy in-game music playback and custom track registration.
|
0
mods/music_modpack/modpack.txt
Normal file
0
mods/music_modpack/modpack.txt
Normal file
288
mods/music_modpack/music_api/api.lua
Normal file
288
mods/music_modpack/music_api/api.lua
Normal file
|
@ -0,0 +1,288 @@
|
|||
music = {}
|
||||
local players = {}
|
||||
local tracks = {}
|
||||
|
||||
--Settingtypes
|
||||
local time_interval = tonumber(minetest.settings:get("music_time_interval")) or 90
|
||||
local cleanup_interval = tonumber(minetest.settings:get("music_cleanup_interval")) or 5
|
||||
local global_gain = tonumber(minetest.settings:get("music_global_gain")) or 0.1
|
||||
local add_random_delay = minetest.settings:get_bool("music_add_random_delay", true)
|
||||
local maximum_random_delay = tonumber(minetest.settings:get("music_maximum_random_delay")) or 45
|
||||
local display_playback_messages = minetest.settings:get_bool("music_display_playback_messages", true)
|
||||
local random_delay = 0
|
||||
|
||||
--Initialize random delay on the first run
|
||||
if add_random_delay then
|
||||
random_delay = math.random(maximum_random_delay)
|
||||
end
|
||||
|
||||
--Internal functions
|
||||
local function load_player_settings(name)
|
||||
|
||||
local file = io.open(minetest.get_worldpath() .. "/music_settings.mt", "r")
|
||||
|
||||
if file then
|
||||
local rawfile = file:read()
|
||||
io.close(file)
|
||||
if rawfile then
|
||||
local settings = minetest.deserialize(rawfile)
|
||||
if settings[name] then
|
||||
players[name].settings = settings[name]
|
||||
end
|
||||
else
|
||||
minetest.log("error", "[Music_api] Unable to read volume settings!")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function save_player_settings(name)
|
||||
|
||||
local path = minetest.get_worldpath() .. "/music_settings.mt"
|
||||
local file = io.open(path, "r")
|
||||
local settings = {}
|
||||
|
||||
if file then
|
||||
local rawfile = file:read()
|
||||
io.close(file)
|
||||
if rawfile then
|
||||
settings = minetest.deserialize(rawfile) or {}
|
||||
end
|
||||
end
|
||||
|
||||
settings[name] = players[name].settings
|
||||
|
||||
file = io.open(path, "w")
|
||||
|
||||
if file then
|
||||
local rawfile = minetest.serialize(settings)
|
||||
file:write(rawfile)
|
||||
io.close(file)
|
||||
minetest.log("action", "[Music_api] Saving volume settings for " .. name)
|
||||
else
|
||||
minetest.log("error", "[Music_api] Unable to save volume settings!")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function play_track(name)
|
||||
|
||||
-- Do not play music for dead players or if music is already playing
|
||||
local p = players[name]
|
||||
if not p or p.is_dead or p.playing then
|
||||
return
|
||||
end
|
||||
|
||||
local player = minetest.get_player_by_name(name)
|
||||
local player_pos = player:get_pos()
|
||||
local possible_tracks = {}
|
||||
local time = minetest.get_timeofday()
|
||||
|
||||
--Assemble list of fitting tracks
|
||||
for _,track in pairs(tracks) do
|
||||
if track.name ~= p.previous and ((track.day and time > 0.25 and time < 0.75) or
|
||||
(track.night and ((time < 0.25 and time >= 0) or (time > 0.75 and time <= 1)))) and
|
||||
player_pos.y >= track.ymin and player_pos.y < track.ymax
|
||||
then
|
||||
table.insert(possible_tracks, track)
|
||||
end
|
||||
end
|
||||
|
||||
--Return if no music fits
|
||||
if #possible_tracks == 0 then
|
||||
p.previous = nil
|
||||
return
|
||||
end
|
||||
|
||||
--Select random track from fitting
|
||||
local track = possible_tracks[math.random(#possible_tracks)]
|
||||
|
||||
--Start playback
|
||||
if display_playback_messages then
|
||||
minetest.log("action", "[Music_api]: Starting playblack for: " .. name .. " " .. track.name .. " Available tracks for user: " .. #possible_tracks .. " Random delay: " .. random_delay)
|
||||
end
|
||||
p.track_handle = minetest.sound_play(track.name, {to_player = name, gain = track.gain * global_gain * p.settings.gain})
|
||||
p.playing = true
|
||||
p.previous = track.name
|
||||
p.playback_started = os.time()
|
||||
p.track_def = track
|
||||
|
||||
end
|
||||
|
||||
local function stop_track(name,step)
|
||||
local p = players[name]
|
||||
if p and p.playing and p.track_handle then
|
||||
minetest.sound_fade(p.track_handle,step or 0.01,0)
|
||||
p.playing = false
|
||||
p.track_handle = nil
|
||||
p.playback_started = nil
|
||||
p.track_def = nil
|
||||
if display_playback_messages then
|
||||
minetest.log("action", "[Music_api]: Stopping playback for: " .. name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function display_music_settings(name)
|
||||
|
||||
local user
|
||||
if type(name) ~= "string" and name:is_player() then
|
||||
user = name:get_player_name()
|
||||
else
|
||||
user = name
|
||||
end
|
||||
|
||||
local volume = math.floor(players[user].settings.gain * 1000)
|
||||
local formspec = "size[5,2]" .. default.gui_bg .. default.gui_bg_img ..
|
||||
"textarea[0.3,0.06;2,1;;Volume:;]" ..
|
||||
"scrollbar[0,0.6;4.8,0.25;horizontal;volume;" .. tostring(volume) .. "]" ..
|
||||
"button[0,1.5;1,0.3;play;Play]" ..
|
||||
"button[0.9,1.5;1,0.3;stop;Stop]" ..
|
||||
"button_exit[3,1.5;2,0.3;accept;Accept]"
|
||||
minetest.show_formspec(user, "music_settings", formspec)
|
||||
|
||||
end
|
||||
|
||||
--Registrations
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname ~= "music_settings" then return end
|
||||
local name = player:get_player_name()
|
||||
local p = players[name]
|
||||
if fields.volume then
|
||||
local params = minetest.explode_scrollbar_event(fields.volume)
|
||||
p.settings.gain = params.value / 1000
|
||||
end
|
||||
if fields.play then
|
||||
if p.playing then
|
||||
stop_track(name,0.05)
|
||||
end
|
||||
play_track(name)
|
||||
end
|
||||
if fields.stop then
|
||||
stop_track(name,0.05)
|
||||
end
|
||||
if fields.accept or fields.quit then
|
||||
save_player_settings(name)
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local name = player:get_player_name()
|
||||
players[name] = {playing = false, playback_started = nil, track_handle = nil, track_def = nil, previous = nil, settings = {gain = 0.5}, is_dead = player:get_hp() <= 0}
|
||||
load_player_settings(name)
|
||||
end
|
||||
)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
local name = player:get_player_name()
|
||||
players[name] = nil
|
||||
end
|
||||
)
|
||||
|
||||
minetest.register_chatcommand("musicsettings",{
|
||||
params = "",
|
||||
description = "Displays music settings menu",
|
||||
privs = {shout = true},
|
||||
func = display_music_settings
|
||||
})
|
||||
|
||||
if minetest.get_modpath("sfinv_buttons") then
|
||||
sfinv_buttons.register_button("show_music_settings",
|
||||
{
|
||||
title = "Music Settings",
|
||||
action = display_music_settings,
|
||||
tooltip = "Show music settings",
|
||||
image = "music_sfinv_buttons_icon.png",
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
local cleanup_timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
|
||||
cleanup_timer = cleanup_timer + dtime
|
||||
if cleanup_timer < cleanup_interval then return end
|
||||
cleanup_timer = 0
|
||||
|
||||
for k,v in pairs(players) do
|
||||
local track = v.track_def
|
||||
if track then
|
||||
if v.playing and os.time() > v.playback_started + track.length then
|
||||
stop_track(k)
|
||||
end
|
||||
|
||||
-- Stop music when it is no longer appropriate for the given conditions
|
||||
if v.playing then
|
||||
local time = minetest.get_timeofday()
|
||||
local player = minetest.get_player_by_name(k)
|
||||
if player then
|
||||
local player_pos = player:get_pos()
|
||||
if not ((track.day and time > 0.205 and time < 0.76) or
|
||||
(track.night and ((time < 0.205 and time >= 0) or (time > 0.76 and time <= 1)))) or
|
||||
player_pos.y < track.ymin or player_pos.y > track.ymax
|
||||
then
|
||||
stop_track(k)
|
||||
play_track(k) -- start new track for the appropriate conditions
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local track_timer = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
|
||||
--Increment timer, return if it doesn't, reset it if it does and continue with function execution
|
||||
track_timer = track_timer + dtime
|
||||
if track_timer < time_interval + random_delay then return end
|
||||
track_timer = 0
|
||||
|
||||
--Return if no tracks are defined
|
||||
if next(tracks) == nil then return end
|
||||
|
||||
--Play music for every player
|
||||
for k,v in pairs(players) do
|
||||
play_track(k)
|
||||
end
|
||||
|
||||
--Change random delay if enabled on each play attempt
|
||||
if add_random_delay then
|
||||
random_delay = math.random(maximum_random_delay)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
--API function
|
||||
function music.register_track(def)
|
||||
|
||||
if def.name == nil or def.length == nil then
|
||||
minetest.log("error", "[Music_api] Missing track definition parameters!")
|
||||
return
|
||||
end
|
||||
|
||||
local track_def = {
|
||||
name = def.name,
|
||||
length = def.length,
|
||||
gain = def.gain or 1,
|
||||
day = def.day or false,
|
||||
night = def.night or false,
|
||||
ymin = def.ymin or -31000,
|
||||
ymax = def.ymax or 31000,
|
||||
}
|
||||
|
||||
table.insert(tracks, track_def)
|
||||
end
|
||||
|
||||
-- Don't play music for dead players
|
||||
minetest.register_on_dieplayer(function(player)
|
||||
local name = player:get_player_name()
|
||||
stop_track(name,0.025)
|
||||
players[name].is_dead = true
|
||||
end)
|
||||
|
||||
-- Enable music for respawned players
|
||||
minetest.register_on_dieplayer(function(player)
|
||||
local name = player:get_player_name()
|
||||
players[name].is_dead = false
|
||||
end)
|
1
mods/music_modpack/music_api/depends.txt
Normal file
1
mods/music_modpack/music_api/depends.txt
Normal file
|
@ -0,0 +1 @@
|
|||
sfinv_buttons?
|
1
mods/music_modpack/music_api/description.txt
Normal file
1
mods/music_modpack/music_api/description.txt
Normal file
|
@ -0,0 +1 @@
|
|||
An api and manager for in-game music
|
2
mods/music_modpack/music_api/init.lua
Normal file
2
mods/music_modpack/music_api/init.lua
Normal file
|
@ -0,0 +1,2 @@
|
|||
local path = minetest.get_modpath("music_api")
|
||||
dofile(path .. "/api.lua")
|
1
mods/music_modpack/music_api/mod.conf
Normal file
1
mods/music_modpack/music_api/mod.conf
Normal file
|
@ -0,0 +1 @@
|
|||
name = music_api
|
17
mods/music_modpack/music_api/settingtypes.txt
Normal file
17
mods/music_modpack/music_api/settingtypes.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
#Interval between attempts to play music
|
||||
music_time_interval (Interval between attempts to play music) int 60
|
||||
|
||||
#Interval between attempts to clean up player playback state
|
||||
music_cleanup_interval (Interval between attempts to clean up player playback state) int 5
|
||||
|
||||
#Music volume
|
||||
music_global_gain (Music volume) float 0.3 0.0 1.0
|
||||
|
||||
#Add random delay to music
|
||||
music_add_random_delay (Add random delay to each music start attempt) bool true
|
||||
|
||||
#Maximum random delay (from 0) to add
|
||||
music_maximum_random_delay (Maximum random delay to add) int 30
|
||||
|
||||
#Display info messages in server console
|
||||
music_display_playback_messages (Display info messages in server console) bool true
|
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
Loading…
Add table
Add a link
Reference in a new issue