Also hang on, did you sneak in Craft’s entity:add back into Modern in the latest build @sim
? Awesome entity:add seems to work in a one liner again without my dependency thank you ![]()
This is how the _obj model for the spaceship seems to appear in editor for me with being autocompleted to spaceCraft3_obj and will appear this way when selected from the asset viewer too.
@sim Here’s another horribly compressed gif screen recording of this time pressing the “Generate” button in EverLancer. Codea’s UI is frozen after doing this despite it seemingly still running, this is what I mean by the Tasks code is somehow interfering with Codea’s main thread somewhere. The only way out seems to be restarting the editor, which then shows a “report crash” notification from TestFlight.

Gosh that looks cool I wish I could run it
@UberGoober It might be possible to make it run if the “World Generator” example runs for you. I started this project duplicating by the example directly with Codea, so it might work if you start from there then replace the tabs. Do you have different asset names in your “World Generator” example somehow if this works for you? As this is where all the assets except the spaceship are from otherwise (although there doesn’t appear to be any ‘in project’ assets when I check in my version of the project).
World Generator Runs.zip (2.1 MB)
I had to tweak the original world generator because it crashes Codea on my iPhone 16e. I forget exactly what I did but it was something like lowering the texture resolution.
In any case this version runs just fine on my phone.
@UberGoober I think I have fixed the problem that was stopping the initial planet generation working.
The update function hook for ‘Tasks’ in CraftExtensions needed altering although the generate button still freezes Codeas UI.
_G['update'] = extensions.hook(_G['update'],function(base,...)
Tasks.update()
base(...)
end)
Let me know how you get on with this version ![]()
EverLancer2.zip (2.2 MB)
This one works and looks very nice thank you. Oh it put this message out of order! Weird.
@UberGoober @sim Just found that it is something about the print statements from Tasks.debug=true causing Codea to freeze/crash when pressing the generate button. So a fix for now is just commenting out Tasks.debug = true from the Generate button’s callback.
parameter.action("Generate", function()
--Tasks.debug = true
generate()
end)
Sorry to report it but that doesn’t affect the crashing.
Haha don’t worry I almost wasn’t expecting it to be that simple…
Here’s another possible fix/slight difference in my version, that I’ve been experimenting with too, in CraftExtensions in the Tasks tab, swap the update hook to:
_G['update'] = extensions.hook(_G['update'],function(base,...)
self.mainThread = coroutine.running()
Tasks.update()
base(...)
end)
Although for some reason for me it seems to work whether I have self.mainThread = coroutine.running() or not as long as I have a Tasks.debug = true commented out too
. Does feel suspiciously timing oriented, which is definitely possible, whether it’s my simulated ‘threads’ / Tasks misbehaving between each other or something else I am not sure.
There is a consideration for certain drawing functions that must be called from draw/update, as in Codea’s main thread, as opposed to in the ‘background’ / inside coroutines which will cause a crash too however. Which is difficult to trace, it’s entirely possible there’s some circumstances I have not accounted for occurring too
.
I could do with a way of getting a traceback in this circumstance, when I’ve broken Codea itself somehow and caused it to crash. I don’t know if this is possible though? ( also @sim )
You can write it yourself and you can to some extend use pcall and stacktrace. To write it yourself you have to save the log to local settings so you can retrieve it after the app relaunches.
Yeah I have tried this too, the problem on my side is there’s no unexpected stops in the trace etc and rendering keeps going afterwards. So really I think I might need Codea’s trace from an Objective-C / Xcode point of view or a debugger which I can breakpoint it all over with ![]()
Several people (including me!) have posted different debuggers with different abilities on the forums. I think @Steppers even made one that’s on WebRepo. I would not use mine, it’s somewhat lame, but the others might be helpful.
Kind of a project night cobra thing right there too lol
Ohh interesting I’ve have not seen these, I shall have to give them a go and/or extend them ![]()
Assuming I did this the way you intended:
Tasks = class()
Tasks.debug = false
Tasks.all = {}
Tasks.update = function()
for tasks in pairs(Tasks.all) do
tasks:resume()
end
end
TaskInvoker = class()
function TaskInvoker:init(func,...)
self.func = func
self.args = {...}
end
function TaskInvoker:invoke()
return {self.func(table.unpack(self.args))}
end
TaskSleeper = class()
function TaskSleeper:init(timeout)
self.timeout = timeout or 0
end
function Tasks:init(entity)
self.tasks = {}
self.limit = 0.75
Tasks.all[self]=self
end
function Tasks:run(func, args, callback)
if type(args) == "function" then
callback = args
args = nil
end
local task = {
thread = coroutine.create(function(...)
--coroutine.yield()
return func(...)
end),
args = args or {},
callback = callback,
clock = 0
}
self.tasks[task.thread] = task
if Tasks.debug then
print(task.thread," - run")
end
end
function Tasks:clock()
return os.clock()
end
function Tasks:resume()
--self.mainThread = coroutine.running()
local startTime = self:clock()
local maxTime = self:clock() + self.limit
local removeTasks = {}
local resumeTasks = {}
for thread, task in pairs(self.tasks) do
if startTime > task.clock then
resumeTasks[thread] = task
end
end
for thread, task in pairs(resumeTasks) do
local threadStatus = coroutine.status(thread)
local results = {}
local resultsStatus = false
local args = task.args or {}
if threadStatus ~= "dead" then
if Tasks.debug then
print(thread," - resume")
end
results = {coroutine.resume(thread, table.unpack(args))}
resultsStatus = results[1]
table.remove(results,1)
local result = results[1]
if result and type(result) == "table" and result.is_a then
if result:is_a(TaskInvoker) then
if Tasks.debug then
print(thread, " - invoke")
end
local invoker = result
results = invoker:invoke()
elseif result:is_a(TaskSleeper) then
if Tasks.debug then
print(thread," - sleep")
end
task.clock = self:clock() + result.timeout
end
end
assert(type(task) == "table", tostring(task))
if Tasks.debug then
print(thread," - results")
for k,v in pairs(results) do
print(k,"= ",v)
end
end
task.args = results
threadStatus = coroutine.status(thread)
end
if threadStatus == "dead" then
if Tasks.debug then
print(thread, " - callback")
end
local callback = task.callback
if callback then
callback(table.unpack(task.args))
end
table.insert(removeTasks, thread)
end
if self:clock() >= maxTime then
break
end
end
for i,thread in ipairs(removeTasks) do
if Tasks.debug then
print(thread, " - dead")
end
self.tasks[thread]=nil
end
end
function Tasks:running()
local thread = coroutine.running()
return self.tasks[thread]
end
function Tasks:destroy()
Tasks.all[self] = nil
end
Task = class()
function Task:init(func,args,callback)
self.func = func
self.args = args or {}
self.callback = callback
end
function Task:execute()
return self.func(table.unpack(self.args))
end
TasksExtension = class()
function TasksExtension:init()
end
function TasksExtension:setup()
Tasks.pool = Tasks()
self.mainThread = coroutine.running()
Task.yield = function(...)
local thread = coroutine.running()
if thread ~= self.mainThread then
if Tasks.debug then
print(thread," - yield")
end
return coroutine.yield(...)
end
return ...
end
Task.sleep = function(timeout)
return Task.yield(TaskSleeper(timeout))
end
Task.invoke = function(func, ...)
local thread = coroutine.running()
if thread ~= self.mainThread then
if Tasks.debug then
print(thread," - invoke ",func,...)
end
return Task.yield(TaskInvoker(func,...))
end
return func(...)
end
Task.run = function(task, args, callback)
if type(args) == "function" then
callback = args
args = nil
end
args = args or {}
if type(task) == "function" then
local func = task
task = Task(func, args, callback)
end
assert(type(task) == "table" and task.is_a and task:is_a(Task))
local taskFunc = function() return Task.invoke() end
Tasks.pool:run(task.execute, {task}, task.callback)
return task
end
_G['update'] = extensions.hook(_G['update'],function(base,...)
self.mainThread = coroutine.running()
Tasks.update()
base(...)
end)
end
extensions.register(TasksExtension())
…and didn’t mess anything else up, I’m still seeing the crash.
This should go on WebRepo if you’re willing.
I am definitely willing to, I was holding off for now while I try fix the project crashing Codea ![]()
It’s working for me now
Yeah it does this haha I think I also know why though. It’s an out of memory issue due to my handling of textures during generation and scaling Codea does in the background per device interacting with each other undesirably. Which @jfperusse kindly dug into and explained what was happening to Codea to cause the crashes. I was intending to optimise this anyway as it’s necessary to squeeze as much memory as possible for something like what I plan with it for planetary landings with voxels. Once I can get my head round the theory around how more exactly ![]()
![]()
