mirror of
https://github.com/rayaman/multi.git
synced 2026-09-05 07:27:35 -04:00
Threading working in love2d
This commit is contained in:
@@ -11,25 +11,27 @@ function multi:newSystemThreadedQueue(name)
|
||||
|
||||
c.Name = name
|
||||
c.Type = multi.registerType("s_queue")
|
||||
c.chan = love.thread.newChannel()
|
||||
c.chan = love.thread.getChannel(name)
|
||||
|
||||
function c:push(dat)
|
||||
self.chan:push(THREAD.packValue(dat))
|
||||
end
|
||||
|
||||
function c:pop()
|
||||
return THREAD.unpackValue(self.chan:pop())
|
||||
return THREAD.unpackValue(self.chan:pop())
|
||||
end
|
||||
|
||||
function c:peek()
|
||||
return THREAD.unpackValue(self.chan:peek())
|
||||
return THREAD.unpackValue(self.chan:peek())
|
||||
end
|
||||
|
||||
function c:init()
|
||||
self.chan = love.thread.getChannel(self.Name)
|
||||
return self
|
||||
end
|
||||
|
||||
function c:Hold(opt)
|
||||
local multi, thread = require("multi"):init()
|
||||
if opt.peek then
|
||||
return thread.hold(function()
|
||||
return self:peek()
|
||||
@@ -73,6 +75,7 @@ function multi:newSystemThreadedTable(name)
|
||||
c.__init = c.init
|
||||
|
||||
function c:Hold(opt)
|
||||
local multi, thread = require("multi"):init()
|
||||
if opt.key then
|
||||
return thread.hold(function()
|
||||
return self.tab[opt.key]
|
||||
|
||||
@@ -5,11 +5,13 @@ end
|
||||
local ThreadFileData = [[
|
||||
ISTHREAD = true
|
||||
args = {...}
|
||||
THREAD_ID = table.remove(args, 1)
|
||||
THREAD_NAME = table.remove(args, 1)
|
||||
GLOBAL, THREAD = require("multi.integration.loveManager.threads"):init()
|
||||
__FUNC = THREAD.unpackValue(table.remove(args, 1))
|
||||
ARGS = THREAD.unpackValue(table.remove(args, 1))
|
||||
THREAD_ID = args[1]
|
||||
THREAD_NAME = args[2]
|
||||
GLOBAL, THREAD, DEFER = require("multi.integration.loveManager.threads"):init()
|
||||
__FUNC = THREAD.unpackValue(args[3])
|
||||
ARGS = THREAD.unpackValue(args[4])
|
||||
settings = args[5]
|
||||
if ARGS == nil then ARGS = {} end
|
||||
math.randomseed(THREAD_ID)
|
||||
math.random()
|
||||
math.random()
|
||||
@@ -21,10 +23,16 @@ if GLOBAL["__env"] then
|
||||
_G[i] = v
|
||||
end
|
||||
end
|
||||
multi, thread = require("multi"):init()
|
||||
multi, thread = require("multi"):init{error=true, warning=true, print=true, priority=true}
|
||||
multi.defaultSettings.print = true
|
||||
require("multi.integration.loveManager.extensions")
|
||||
require("multi.integration.sharedExtensions")
|
||||
stab["returns"] = {__FUNC(multi.unpack(ARGS))}
|
||||
local returns = {pcall(__FUNC, multi.unpack(ARGS))}
|
||||
table.remove(returns,1)
|
||||
stab["returns"] = returns
|
||||
for i,v in pairs(DEFER) do
|
||||
pcall(v)
|
||||
end
|
||||
]]
|
||||
|
||||
_G.THREAD_NAME = "MAIN_THREAD"
|
||||
@@ -49,7 +57,7 @@ function multi:newSystemThread(name, func, ...)
|
||||
c.Name = name
|
||||
c.ID = tid
|
||||
c.thread = love.thread.newThread(ThreadFileData)
|
||||
c.thread:start(c.ID, c.Name, THREAD.packValue(func), THREAD.packValue({...}))
|
||||
c.thread:start(c.ID, c.Name, THREAD.packValue(func), THREAD.packValue({...}), multi.defaultSettings)
|
||||
c.stab = THREAD.createTable(name .. c.ID)
|
||||
c.creationTime = os.clock()
|
||||
c.OnDeath = multi:newConnection()
|
||||
|
||||
@@ -25,19 +25,76 @@ require("love.timer")
|
||||
require("love.system")
|
||||
require("love.data")
|
||||
require("love.thread")
|
||||
local utils = require("multi.integration.loveManager.utils")
|
||||
local multi, thread = require("multi"):init()
|
||||
|
||||
local NIL = love.data.newByteData("\3")
|
||||
|
||||
-- If a non table/function is supplied we just return it
|
||||
local function packValue(t)
|
||||
return utils.pack(t)
|
||||
-- Checks if the given value is a LOVE2D object (i.e. has metatable with __index field) and if that __index field contains functions typical of LOVE2D objects
|
||||
function isLoveObject(value)
|
||||
-- Check if the value has metatable
|
||||
if type(value) == "userdata" and getmetatable(value) then
|
||||
-- Check if the metatable has the __index field
|
||||
local index = getmetatable(value).__index
|
||||
if type(index) == "table" then
|
||||
-- Check if the metatable's __index table contains functions typical of LOVE2D objects
|
||||
if index.draw or index.update or index.getWidth or index.getHeight or index.getString or index.getPointer then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- If a non table/function is supplied we just return it
|
||||
local function unpackValue(d)
|
||||
return utils.unpack(d)
|
||||
-- Converts any function values in a table to a string with the value "\1\2:func:<function_string>" where <function_string> is the Lua stringified version of the function
|
||||
function tableToFunctionString(t)
|
||||
if type(t) == "nil" then return "\1\2:nil:" end
|
||||
if type(t) == "function" then return "\1\2:func:"..string.dump(t) end
|
||||
if type(t) ~= "table" then return t end
|
||||
local newtable = {}
|
||||
for k, v in pairs(t) do
|
||||
if type(v) == "function" then
|
||||
newtable[k] = "\1\2:func:"..string.dump(v)
|
||||
elseif type(v) == "table" then
|
||||
newtable[k] = tableToFunctionString(v)
|
||||
elseif isLoveObject(v) then
|
||||
newtable[k] = v
|
||||
elseif type(v) == "userdata" then
|
||||
newtable[k] = tostring(v)
|
||||
else
|
||||
newtable[k] = v
|
||||
end
|
||||
end
|
||||
return newtable
|
||||
end
|
||||
|
||||
-- Converts strings with the value "\1\2:func:<function_string>" back to functions
|
||||
function functionStringToTable(t)
|
||||
if type(t) == "string" and t:sub(1, 8) == "\1\2:func:" then return loadstring(t:sub(9, -1)) end
|
||||
if type(t) == "string" and t:sub(1, 7) == "\1\2:nil:" then return nil end
|
||||
if type(t) ~= "table" then return t end
|
||||
for k, v in pairs(t) do
|
||||
if type(v) == "string" then
|
||||
if v:sub(1, 8) == "\1\2:func:" then
|
||||
t[k] = loadstring(v:sub(9, -1))
|
||||
else
|
||||
t[k] = v
|
||||
end
|
||||
elseif type(v) == "table" then
|
||||
t[k] = functionStringToTable(v)
|
||||
else
|
||||
t[k] = v
|
||||
end
|
||||
end
|
||||
if t.init then
|
||||
t:init()
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local function packValue(t)
|
||||
return tableToFunctionString(t)
|
||||
end
|
||||
|
||||
local function unpackValue(t)
|
||||
return functionStringToTable(t)
|
||||
end
|
||||
|
||||
local function createTable(n)
|
||||
@@ -53,6 +110,11 @@ local function createTable(n)
|
||||
end
|
||||
local function get(name)
|
||||
return unpackValue(love.thread.getChannel(n .. name):peek())
|
||||
-- if type(data) == "table" and data.init then
|
||||
-- return data:init()
|
||||
-- else
|
||||
-- return data
|
||||
-- end
|
||||
end
|
||||
return setmetatable({},
|
||||
{
|
||||
@@ -67,7 +129,7 @@ local function createTable(n)
|
||||
end
|
||||
|
||||
function INIT()
|
||||
local GLOBAL, THREAD = createTable("__GLOBAL__"), {}
|
||||
local GLOBAL, THREAD, DEFER = createTable("__GLOBAL__"), {}, {}
|
||||
local status_channel, console_channel = love.thread.getChannel("__status_channel__" .. THREAD_ID),
|
||||
love.thread.getChannel("__console_channel__")
|
||||
|
||||
@@ -92,11 +154,7 @@ function INIT()
|
||||
repeat
|
||||
wait()
|
||||
until GLOBAL[name] ~= nil
|
||||
if type(GLOBAL[name].__init) == "function" then
|
||||
return GLOBAL[name]:__init()
|
||||
else
|
||||
return GLOBAL[name]
|
||||
end
|
||||
return GLOBAL[name]
|
||||
end, true)
|
||||
|
||||
function THREAD.getCores()
|
||||
@@ -153,10 +211,14 @@ function INIT()
|
||||
end
|
||||
|
||||
function THREAD.defer(func)
|
||||
multi.OnExit(func)
|
||||
table.insert(DEFER, func)
|
||||
end
|
||||
|
||||
return GLOBAL, THREAD
|
||||
function THREAD.sync()
|
||||
-- Maybe do something...
|
||||
end
|
||||
|
||||
return GLOBAL, THREAD, DEFER
|
||||
end
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
require("love.data")
|
||||
local utils = {}
|
||||
local NIL = {Type="nil"}
|
||||
|
||||
--love.data.newByteData("\2"..serpent.dump({t,true},{safe = true}))
|
||||
|
||||
local ltype = function(v) return v:type() end
|
||||
local t = function(value)
|
||||
local v = type(value)
|
||||
if v == "userdata" then
|
||||
local status, return_or_err = pcall(ltype, value)
|
||||
if status then return return_or_err else return "userdata" end
|
||||
else return v end
|
||||
end
|
||||
|
||||
function utils.pack(tbl, seen)
|
||||
if type(tbl) == "function" then return {["__$FUNC$__"] = love.data.newByteData(string.dump(tbl))} end
|
||||
if type(tbl) ~= "table" then return tbl end
|
||||
local seen = seen or {}
|
||||
local result = {}
|
||||
result.__isPacked = true
|
||||
for i,v in pairs(tbl) do
|
||||
if seen[v] then
|
||||
result[i] = v
|
||||
elseif t(v) == "table" then
|
||||
seen[v] = true
|
||||
result[i] = utils.pack(v, seen)
|
||||
elseif t(v) == "function" then
|
||||
result["$F"..i] = love.data.newByteData(string.dump(v))
|
||||
elseif t{v} == "userdata" then
|
||||
result[i] = "userdata"
|
||||
else -- Handle what we need to and pass the rest along as a value
|
||||
result[i] = v
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function utils.unpack(tbl)
|
||||
if not tbl then return nil end
|
||||
if type(tbl) ~= "table" then return tbl end
|
||||
if tbl["__$FUNC$__"] then return loadstring(tbl["__$FUNC$__"]:getString()) end
|
||||
for i,v in pairs(tbl) do
|
||||
if type(i) == "string" and i:sub(1,2) == "$F" then
|
||||
local rawfunc = v:getString()
|
||||
v:release()
|
||||
tbl[i] = nil
|
||||
tbl[i:sub(3,-1)] = loadstring(rawfunc)
|
||||
end
|
||||
if type(v) == "table" then
|
||||
utils.unpack(v)
|
||||
end
|
||||
end
|
||||
tbl.__isPacked = nil
|
||||
return tbl
|
||||
end
|
||||
|
||||
return utils
|
||||
Reference in New Issue
Block a user