Advertisement
Guest User

Love2d Threads

a guest
Jul 15th, 2016
136
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.52 KB | None | 0 0
  1. if not love or not love.filesystem or not love.thread then
  2.     error('This plugin for LOVE2D framework, and not works with other lua-builds'..
  3.                 'Also it requires love.filesystem and love.thread modules', 2)
  4. end
  5.  
  6. local thread = {}
  7.  
  8. -- List for storing all thread names and checking unique names (links)
  9. local namelist = {}
  10. function namelist:checkName(name)
  11.     for i, v in ipairs(self) do
  12.         if name == v then return true end
  13.     end
  14. end
  15. function namelist:removeName(name)
  16.     for i, v in ipairs(threadlist) do
  17.         if name == v then
  18.             table.remove(threadlist, i)
  19.             break
  20.         end
  21.     end
  22. end
  23.  
  24. setmetatable(thread, {__call =
  25.     function(self, name, userfunction, callbackList)
  26.         --assertions
  27.         name = type(name) == 'string' and name
  28.             or error('Thread: arg#1 name as string expected, got '..type(name), 2)
  29.         userfunction = type(userfunction) == 'string' and userfunction
  30.             or error('Thread: arg#2 thread function as string expected, got '..type(userfunction), 2)
  31.         --checking name
  32.         if namelist:checkName(name) then error('Thread with this name "'..name..'" already exists', 2)
  33.         else table.insert(namelist, name) end
  34.         --check callbacks as functions
  35.         if callbackList then
  36.             for k, v in pairs(callbackList) do
  37.                 if type(v) ~= 'function' then v = nil end
  38.             end
  39.         end
  40.         --if function is path to file - load it
  41.         if love.filesystem.isFile(userfunction) then
  42.             userfunction = love.filesystem.read(userfunction)
  43.         end
  44.         local o = {}
  45.         o.name = name
  46.         --class with set of thread functions
  47.         local class = [[
  48.             do
  49.                 arg = {...}
  50.                 local t = {}
  51.                 t.name = "REG_NAME"
  52.                 t.inner = love.thread.getChannel(t.name.."_i")
  53.                 t.outer = love.thread.getChannel(t.name.."_o")
  54.                 thread = {}
  55.                 function thread:push(data) t.outer:push(data) end
  56.                 local link = {}
  57.                 function link:new(inner, outer)
  58.                     return setmetatable({inner = inner, outer = outer}, {__index = link})
  59.                 end
  60.                 function link:clear()
  61.                     self.inner:clear()
  62.                     self.outer:clear()
  63.                 end
  64.                 function link:push(data) self.outer:push(data) end
  65.                 function link:pop() return self.inner:pop() end
  66.                 function thread:newLink(threadname)
  67.                     print(self:getName()..' create link to '..threadname)
  68.                     local nameA, nameB = self:getName(), threadname
  69.                     return nameA > nameB and
  70.                         link:new(
  71.                             love.thread.getChannel(nameA..nameB..'_blue'),
  72.                             love.thread.getChannel(nameA..nameB..'_red')
  73.                         )
  74.                         or
  75.                         link:new(
  76.                             love.thread.getChannel(nameB..nameA..'_red'),
  77.                             love.thread.getChannel(nameB..nameA..'_blue')
  78.                         )
  79.                 end
  80.                 function thread:clear() t.inner:clear(); t.outer:clear() end
  81.                 function thread:pop() return t.inner.pop() end
  82.                 function thread:getName() return t.name end
  83.                 function thread:getCount() return t.inner:getCount() end
  84.                 function thread:popAll()
  85.                     local o = {}
  86.                     local data = thread:pop()
  87.                     while data do
  88.                         table.insert(o, data)
  89.                         data = thread:pop()
  90.                     end
  91.                     return o
  92.                 end
  93.             end
  94.         ]]
  95.         --set name of thread
  96.         class = class:gsub('REG_NAME', o.name)
  97.         --[[Replace all newline characters for make code-oneliner.
  98.             Errors returns string number, but   a lot of code before user
  99.             functions make it difficult to find the line with the
  100.             error is returned.]]
  101.         class = class:gsub('[\n\r$]+', ' ')
  102.         --remove all tab characters because i want it
  103.         class = class:gsub('[   ]+', '')
  104.         --i love gsub so much!
  105.        
  106.         o.thread = love.thread.newThread(class..userfunction..'\n\n\n\n'); class = nil
  107.         o.callback = callbackList or {}
  108.         o.channel = {}
  109.         o.channel.i = love.thread.getChannel(o.name.."_i")  --main --in channel--> thread
  110.         o.channel.o = love.thread.getChannel(o.name.."_o")  --main <-out channel-- thread
  111.         o.dbg = true
  112.         self.__index = self
  113.         return setmetatable(o, self)
  114.     end,})
  115.  
  116. local cbNames = {'receive', 'finish', 'error', 'kill'}
  117. local function checkCallback(name)
  118.  
  119.     if not name or type(name) ~= 'string' then error('Thread:setCallback(name, func) arg#1 string expected got '..type(name), 3) end
  120.     for i, v in ipairs(cbNames) do
  121.         if v == name:lower() then return true end
  122.     end
  123. end
  124.  
  125. function thread:setCallback(name, f)
  126.     if not checkCallback(name) then error('Thread:setCallback(name, func) arg#1 name must be '..table.concat(cbNames, ' or '), 2) end
  127.     if type(f) ~= 'function' then error('Thread:setCallback(name, func) arg#2 func must be function', 2) end
  128.     --List of name:
  129.     ---receive: function(self, msg) Calls if thread send the message to parent program.
  130.     ---finish:  function(self, ...) Calls if thread finish self work. '...' contain all unreaded messages
  131.     ---error:   function(self, err) Calls if thread got error.
  132.     ---kill:    function(self)    Calls if parent program kill the thread.
  133.     self.callback[name:lower()] = f
  134. end
  135.  
  136. function thread:start(...)
  137.     self.thread:start(...)
  138.     self.state = 'run'
  139. end
  140.  
  141. function thread:kill()
  142.     namelist:removeName(self.name)
  143.     self.thread:kill()
  144.     self:clear()
  145.     local res = self.callback.kill and {self.callback.kill(self, self:receiveAll())}
  146.     self = nil
  147.     return unpack(res)
  148. end
  149.  
  150. function thread:wait()
  151.     self.state = 'wait'
  152.     self.thread:wait()
  153. end
  154.  
  155. function thread:isRunning()
  156.     return self.thread:isRunning()
  157. end
  158.  
  159. function thread:getError()
  160.     return self.thread:getError()
  161. end
  162.  
  163. function thread:send(data)
  164.     self.channel.i:push(data)
  165. end
  166.  
  167. function thread:supply(data)
  168.     self.channel.i:supply(data)
  169. end
  170.  
  171. function thread:receive()
  172.     return self.channel.o:pop()
  173. end
  174.  
  175. function thread:receiveAll()
  176.     local o = {}
  177.     for i = 1, self.channel.o:getCount() do
  178.         table.insert(o, self:receive())
  179.     end
  180.     return o
  181. end
  182.  
  183. function thread:clear()
  184.     self.channel.i:clear()
  185.     self.channel.o:clear()
  186. end
  187.  
  188. function thread:getCount()
  189.     return self.channel.o:getCount()
  190. end
  191.  
  192. function thread:getChannel(name)
  193.     return  love.thread.getChannel(name)
  194. end
  195.  
  196. function thread:debug(v)
  197.     self.dbg = not not v
  198. end
  199.  
  200. function thread:update()
  201.     if self.state == 'run' then
  202.         if not self.thread:isRunning() then
  203.             self.state = 'finish'
  204.             if self.callback.finish then
  205.                 self.callback.finish(self, self:receiveAll())
  206.                 self:clear()
  207.             end
  208.         end
  209.        
  210.         local err = self.thread:getError()
  211.         if err and self.dbg then print('Thread "'..self.name..'" err: '..tostring(err)) end
  212.         if err and self.callback.error then
  213.             self.callback.error(self, err)
  214.         elseif err then
  215.             self:kill()
  216.         end
  217.     end
  218.     if self.callback.receive then
  219.         for _, data in ipairs(self:receiveAll()) do
  220.             self.callback.receive(self, data)
  221.             if self.dbg then
  222.                 print('Thread send msg: '..tostring(data))
  223.             end
  224.         end
  225.     end
  226. end
  227.  
  228. return thread
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement