diff --git a/README.md b/README.md index 7de93cb..7788630 100644 --- a/README.md +++ b/README.md @@ -6,44 +6,44 @@ It adds two new node events and contains async functions. Usage Async =========== -1. create a async pool. +1. create a async instance. ```lua -pool = extended_api.Async.create_async_pool() +async = extended_api.Async() ``` 2. set the priority of the async pool to high. ```lua -extended_api.Async.priority(pool,50,500) +async.priority(50, 500) ``` 3. iterate from 1 to 50 and log the value i. ```lua -extended_api.Async.iterate(pool,1,50,function(i) +async.iterate(1, 50, function(i) minetest.log(i) end) ``` 4. run throught each element in a table. ```lua -local array = {"start","text2","text3","text4","text5","end"} -extended_api.Async.foreach(pool,array, function(k,v) +local array = {"start", "text2", "text3", "text4", "text5", "end"} +async.foreach(array, function(k,v) minetest.log(v) end) ``` 5. async do while loop. ```lua local c = 50 -extended_api.Async.do_while(pool,function() return c>0 end, function() +async.do_while(function() return c>0 end, function() minetest.log(c) c = c - 1 end) ``` 6. register a async globalstep. this one spams the chat with the word spam. ```lua -extended_api.Async.register_globalstep(pool,function(dtime) +async.register_globalstep(function(dtime) minetest.chat_send_all("spam") end) ``` 7. chain task runs a group of functions from a table. ```lua -extended_api.Async.chain_task(pool,{ +async.chain_task({ function(args) args.count = 1 minetest.log(args.count) @@ -57,11 +57,17 @@ end}) ``` 8. adds a single function to the task queue. This is a sort of waiting list. ```lua -extended_api.Async.queue_task(pool,function() +async.queue_task(function() minetest.log("Hello World!") end) ``` -Usage Node +9. Same as queue_task but the task does not go into a queue. +```lua +async.single_task(function() + minetest.log("Hello World!") +end) +``` +New Node Events =========== 1. this covers both functions. I made this for a way to awake node timers without abms. ```lua @@ -83,4 +89,27 @@ minetest.register_node("default:stone", { end end, }) -``` \ No newline at end of file +``` +New Registers +=========== +1. register_playerloop iterates through all players online. +```lua +extended_api.register_playerloop(function(dtime, _, player) + -- Empty +end) +``` +2. register_step excutes the given function in one minetest globalstep. +```lua +extended_api.register_step(function(dtime) + minetest.chat_send_all("spam") +end) +``` +3. functions on_wield and on_wield_switch happen when a player wields a item. +```lua +extended_api.register_on_wield("default:torch", function(item, itemname, player) + minetest.chat_send_all("You are wielding " .. itemname) +end) +extended_api.register_on_wield_switch("default:torch", function(item, itemname, player) + minetest.chat_send_all("You un-wielded " .. itemname) +end) +``` diff --git a/async.lua b/async.lua index 7fa3a64..2677636 100644 --- a/async.lua +++ b/async.lua @@ -1,201 +1,229 @@ -extended_api.Async = {} +function extended_api.Async() + local self = {} + + self.pool = {threads = {}, globalstep_threads = {}, task_queue = {}, resting = 200, maxtime = 200, queue_threads = 8, state = "suspended"} + + self.create_worker = function(func) + local thread = coroutine.create(func) + if not thread or coroutine.status(thread) == "dead" then + minetest.after(0.3, self.create_worker, func) + minetest.after(0.5, self.schedule_worker) + minetest.chat_send_all("Fall") + return + end + table.insert(self.pool.threads, thread) + end + + self.create_globalstep_worker = function(func) + local thread = coroutine.create(func) + if not thread or coroutine.status(thread) == "dead" then + minetest.after(0.3, self.create_globalstep_worker, func) + minetest.after(0.5, self.schedule_globalstep_worker) + return + end + table.insert(self.pool.globalstep_threads, thread) + end + self.run_worker = function(index) + local thread = self.pool.threads[index] + if not thread or coroutine.status(thread) == "dead" then + table.remove(self.pool.threads, index) + minetest.after(0, self.schedule_worker) + return false + else + coroutine.resume(thread) + minetest.after(0, self.schedule_worker) + return true + end + end -function extended_api.Async.create_async_pool() - local pool = {threads = {},globalstep_threads = {},task_queue = {},resting = 200,maxtime = 200,queue_threads = 8,state = "suspended"} - return pool -end + self.run_globalstep_worker = function(index) + local thread = self.pool.globalstep_threads[index] + if not thread or coroutine.status(thread) == "dead" then + table.remove(self.pool.globalstep_threads, index) + minetest.after(0, self.schedule_globalstep_worker) + return false + else + coroutine.resume(thread) + minetest.after(0, self.schedule_globalstep_worker) + return true + end + end -function extended_api.Async.create_worker(pool,func) - local thread = coroutine.create(func) - table.insert(pool.threads, thread) -end - -function extended_api.Async.create_globalstep_worker(pool,func) - local thread = coroutine.create(func) - table.insert(pool.globalstep_threads, thread) -end - -function extended_api.Async.run_worker(pool,index) - local thread = pool.threads[index] - if thread == nil or coroutine.status(thread) == "dead" then - table.remove(pool.threads, index) - minetest.after(0,extended_api.Async.schedule_worker,pool) + self.schedule_worker = function() + self.pool.state = "running" + for index, value in ipairs(self.pool.threads) do + minetest.after(self.pool.resting / 1000, self.run_worker, index) + return true + end + self.pool.state = "suspended" return false - else - coroutine.resume(thread) - minetest.after(0,extended_api.Async.schedule_worker,pool) - return true end -end -function extended_api.Async.run_globalstep_worker(pool,index) - local thread = pool.globalstep_threads[index] - if thread == nil or coroutine.status(thread) == "dead" then - table.remove(pool.globalstep_threads, index) - minetest.after(0,extended_api.Async.schedule_globalstep_worker,pool) + self.schedule_globalstep_worker = function() + for index, value in ipairs(self.pool.globalstep_threads) do + minetest.after(0, self.run_globalstep_worker, index) + return true + end return false - else - coroutine.resume(thread) - minetest.after(0,extended_api.Async.schedule_globalstep_worker,pool) - return true end -end -function extended_api.Async.schedule_worker(pool) - pool.state = "running" - for index,value in ipairs(pool.threads) do - minetest.after(pool.resting / 1000,extended_api.Async.run_worker,pool,index) - return true + self.priority = function(resting, maxtime) + self.pool.resting = resting + self.pool.maxtime = maxtime end - pool.state = "suspended" - return false -end -function extended_api.Async.schedule_globalstep_worker(pool) - for index,value in ipairs(pool.globalstep_threads) do - minetest.after(0,extended_api.Async.run_globalstep_worker,pool,index) - return true - end - return false -end - -function extended_api.Async.priority(pool,resting,maxtime) - pool.resting = resting - pool.maxtime = maxtime -end - -function extended_api.Async.iterate(pool,from,to,func,callback) - extended_api.Async.create_worker(pool,function() - local last_time = minetest.get_us_time() * 1000 - local maxtime = pool.maxtime - for i = from, to do - local b = func(i) - if b ~= nil and b == false then - break - end - if minetest.get_us_time() * 1000 > last_time + maxtime then - coroutine.yield() - last_time = minetest.get_us_time() * 1000 - end - end - if callback then - callback() - end - end) - extended_api.Async.schedule_worker(pool) -end - -function extended_api.Async.foreach(pool,array, func, callback) - extended_api.Async.create_worker(pool,function() - local last_time = minetest.get_us_time() * 1000 - local maxtime = pool.maxtime - for k,v in ipairs(array) do - local b = func(k,v) - if b ~= nil and b == false then - break - end - if minetest.get_us_time() * 1000 > last_time + maxtime then - coroutine.yield() - last_time = minetest.get_us_time() * 1000 - end - end - if callback then - callback() - end - end) - extended_api.Async.schedule_worker(pool) -end - -function extended_api.Async.do_while(pool,condition_func, func, callback) - extended_api.Async.create_worker(pool,function() - local last_time = minetest.get_us_time() * 1000 - local maxtime = pool.maxtime - while(condition_func()) do - local c = func() - if c ~= nil and c ~= condition_func() then - break - end - if minetest.get_us_time() * 1000 > last_time + maxtime then - coroutine.yield() - last_time = minetest.get_us_time() * 1000 - end - end - if callback then - callback() - end - end) - extended_api.Async.schedule_worker(pool) -end - -function extended_api.Async.register_globalstep(pool,func) - extended_api.Async.create_globalstep_worker(pool,function() - local last_time = minetest.get_us_time() * 1000 - local dtime = last_time - while(true) do - func(dtime) - dtime = minetest.get_us_time() * 1000 - -- 0.05 seconds - if minetest.get_us_time() * 1000 > last_time + 50 then - coroutine.yield() - local last_time = minetest.get_us_time() * 1000 - end - end - end) - extended_api.Async.schedule_globalstep_worker(pool) -end - -function extended_api.Async.chain_task(pool,tasks,callback) - extended_api.Async.create_worker(pool,function() - local pass_arg = nil - local last_time = minetest.get_us_time() * 1000 - local maxtime = pool.maxtime - for index, task_func in pairs(tasks) do - local p = task_func(pass_arg) - if p ~= nil then - pass_arg = p - end - if minetest.get_us_time() * 1000 > last_time + maxtime then - coroutine.yield() - last_time = minetest.get_us_time() * 1000 - end - end - if callback then - callback(pass_arg) - end - end) - extended_api.Async.schedule_worker(pool) -end - -function extended_api.Async.queue_task(pool,func,callback) - table.insert(pool.task_queue,{func = func,callback = callback}) - if pool.queue_threads > 0 then - pool.queue_threads = pool.queue_threads - 1 - extended_api.Async.create_worker(pool,function() - local pass_arg = nil - local last_time = minetest.get_us_time() * 1000 - local maxtime = pool.maxtime - while(true) do - local task_func = pool.task_queue[1] - table.remove(pool.task_queue,1) - if task_func and task_func.func then - pass_arg = nil - local p = task_func.func(pass_arg) - if p ~= nil then - pass_arg = p - end - if task_func.callback then - task_func.callback(pass_arg) - end - if minetest.get_us_time() * 1000 > last_time + maxtime then - coroutine.yield() - last_time = minetest.get_us_time() * 1000 - end - else - pool.queue_threads = pool.queue_threads + 1 + self.iterate = function(from, to, func, callback) + self.create_worker(function() + local last_time = minetest.get_us_time() / 1000 + local maxtime = self.pool.maxtime + for i = from, to do + local b = func(i) + if b ~= nil and b == false then break end + if minetest.get_us_time() / 1000 > last_time + maxtime then + coroutine.yield() + last_time = minetest.get_us_time() / 1000 + end + end + if callback then + callback() + end + return + end) + self.schedule_worker() + end + + self.foreach = function(array, func, callback) + self.create_worker(function() + local last_time = minetest.get_us_time() / 1000 + local maxtime = self.pool.maxtime + for k,v in ipairs(array) do + local b = func(k,v) + if b ~= nil and b == false then + break + end + if minetest.get_us_time() / 1000 > last_time + maxtime then + coroutine.yield() + last_time = minetest.get_us_time() / 1000 + end + end + if callback then + callback() + end + return + end) + self.schedule_worker() + end + + self.do_while = function(condition_func, func, callback) + self.create_worker(function() + local last_time = minetest.get_us_time() / 1000 + local maxtime = self.pool.maxtime + while(condition_func()) do + local c = func() + if c ~= nil and c ~= condition_func() then + break + end + if minetest.get_us_time() / 1000 > last_time + maxtime then + coroutine.yield() + last_time = minetest.get_us_time() / 1000 + end + end + if callback then + callback() + end + return + end) + self.schedule_worker() + end + + self.register_globalstep = function(func) + self.create_globalstep_worker(function() + local last_time = minetest.get_us_time() / 1000000 + local dtime = last_time + while(true) do + dtime = (minetest.get_us_time() / 1000000) - last_time + func(dtime) + -- 0.05 seconds + if minetest.get_us_time() / 1000000 > last_time + 0.05 then + coroutine.yield() + last_time = minetest.get_us_time() / 1000000 + end end end) - extended_api.Async.schedule_worker(pool) + self.schedule_globalstep_worker() end -end \ No newline at end of file + + self.chain_task = function(tasks, callback) + self.create_worker(function() + local pass_arg = nil + local last_time = minetest.get_us_time() / 1000 + local maxtime = self.pool.maxtime + for index, task_func in pairs(tasks) do + local p = task_func(pass_arg) + if p ~= nil then + pass_arg = p + end + if minetest.get_us_time() / 1000 > last_time + maxtime then + coroutine.yield() + last_time = minetest.get_us_time() / 1000 + end + end + if callback then + callback(pass_arg) + end + return + end) + self.schedule_worker() + end + + self.queue_task = function(func, callback) + table.insert(self.pool.task_queue, {func = func,callback = callback}) + if self.pool.queue_threads > 0 then + self.pool.queue_threads = self.pool.queue_threads - 1 + self.create_worker(function() + local pass_arg = nil + local last_time = minetest.get_us_time() / 1000 + local maxtime = self.pool.maxtime + while(true) do + local task_func = self.pool.task_queue[1] + table.remove(self.pool.task_queue, 1) + if task_func and task_func.func then + pass_arg = nil + local p = task_func.func() + if p ~= nil then + pass_arg = p + end + if task_func.callback then + task_func.callback(pass_arg) + end + if minetest.get_us_time() / 1000 > last_time + maxtime then + coroutine.yield() + last_time = minetest.get_us_time() / 1000 + end + else + self.pool.queue_threads = self.pool.queue_threads + 1 + return + end + end + end) + self.schedule_worker() + end + end + + self.single_task = function(func, callback) + self.create_worker(function() + local pass_arg = func() + if p ~= nil then + pass_arg = p + end + if task_func.callback then + task_func.callback(pass_arg) + end + return + end) + self.schedule_worker() + end + return self +end diff --git a/init.lua b/init.lua index 0b310d9..49a455b 100644 --- a/init.lua +++ b/init.lua @@ -2,5 +2,6 @@ modpath = minetest.get_modpath("extended_api") extended_api = {} -dofile(string.format("%s/node_funcs.lua",modpath)) -dofile(string.format("%s/async.lua",modpath)) \ No newline at end of file +dofile(string.format("%s/node_funcs.lua", modpath)) +dofile(string.format("%s/async.lua", modpath)) +dofile(string.format("%s/register.lua", modpath)) diff --git a/register.lua b/register.lua new file mode 100644 index 0000000..e7879b4 --- /dev/null +++ b/register.lua @@ -0,0 +1,104 @@ +extended_api.p_loop = {} +extended_api.step = {} + +local wield_list = {} +local wield_switch_list = {} + +minetest.register_globalstep(function(dtime) + local a1 = extended_api.p_loop + local a2 = extended_api.step + local count1 = #a1 + for _, player in pairs(minetest.get_connected_players()) do + for i=1, count1 do + a1[i](dtime, _, player) + end + end + local count2 = #a2 + for i=1, count2 do + a2[i](dtime) + end +end) + +function extended_api.register_playerloop(func) + table.insert(extended_api.p_loop, func) +end + +function extended_api.register_step(func) + table.insert(extended_api.step, func) +end + +function extended_api.register_on_wield(itemname, func) + if wield_list[itemname] then + local old = wield_list[itemname] + wield_list[itemname] = function(item, itemname, player) + func(item, itemname, player) + old(item, itemname, player) + end + else + wield_list[itemname] = func + end +end + +function extended_api.register_on_wield_switch(itemname, func) + if wield_switch_list[itemname] then + local old = wield_switch_list[itemname] + wield_switch_list[itemname] = function(item, itemname, player) + func(item, itemname, player) + old(item, itemname, player) + end + else + wield_switch_list[itemname] = func + end +end + +local wield_timer = 0 +local wield_limit = 0.2 +local players = {} + +local function create_wield_step() + extended_api.register_playerloop(function(dtime, _, player) + if wield_timer < wield_limit then + return + end + + local item = player:get_wielded_item() + local item_name = item:get_name() + local pname = player:get_player_name() + local ply = players[pname] + if not ply then + players[pname] = item + local wlf = wield_list[item_name] + if wlf then + wlf(item, item_name, player) + end + elseif ply:get_name() ~= item_name then + local old = ply:get_name() + players[pname] = item + local wlf = wield_switch_list[old] + + if wlf then + wlf(item, old, player) + end + + wlf = wield_list[item_name] + if wlf then + wlf(item, item_name, player) + end + end + end) + + extended_api.register_step(function(dtime) + if wield_timer < wield_limit then + wield_timer = wield_timer + dtime + return + else + wield_timer = 0 + end + end) +end + +minetest.register_on_leaveplayer(function(player) + players[player:get_player_name()] = nil +end) + +create_wield_step()