BroccoliUtils - Misc. Collections of Libraries

Showcase your libraries, tools and other projects that help your fellow love users.
Post Reply
User avatar
BroccoliRaab
Prole
Posts: 8
Joined: Tue Jun 27, 2017 3:58 am

BroccoliUtils - Misc. Collections of Libraries

Post by BroccoliRaab »

BroccoliUtils is a collection of Libraries that I have used for developing my own games with Love2D.


It has a libraries for:
  • Saving data as a lua file that when run returns a table with all of your data
  • Using timers to run a function periodically, or create a delay before it runs
  • Converting a spritesheet into a table of quad objects
  • Creating animations as objects from a spritesheet or a directory containing pictures
  • Drawing to a game scene like a canvas for it to render each thing to draw to them in order as objects[
  • Handling events for each scene
  • Creating a GUI by rendering functions that draw to the screen as objects that can be altered or have events tied to them
https://github.com/BroccolliRaab/BroccoliUtils

I am still in the process of documenting it
Documentation: https://github.com/BroccolliRaab/BroccoliUtils/wiki
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: BroccoliUtils - Misc. Collections of Libraries

Post by ivan »

A few notes on your saveData util:
- it will hang with table cycles: a = {} a.b = a
- easier way to escape strings: escaped = string.format("%q", raw)
- loading code from the appdata directory is not "safe", consider looking into setenv
User avatar
BroccoliRaab
Prole
Posts: 8
Joined: Tue Jun 27, 2017 3:58 am

Re: BroccoliUtils - Misc. Collections of Libraries

Post by BroccoliRaab »

I thought I added an assert statement that would not allow cyclic tables, but I guess not. I'll fix that.
I didn't know about that string.format so thats awesome to know about, And I probably should have known not to load from appdata. Of course thats a bad idea. I will update those things when I get the chance. I'll at least add the assert right now.
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: BroccoliUtils - Misc. Collections of Libraries

Post by ivan »

The cycles thing is not that important - but if you want to assert/support it then you need something like:

Code: Select all

  local function formatData1(data, visited)
   visited = visited or {}
   assert(not visited[data], "Cyclic tables are not allowed. At least not yet.")
   visited[data] = true
    ...
      for i, v in pairs(data) do
        ...
        if type(v) == "table" then
          ...
          formatData1(v, visited)
        
probably should have known not to load from appdata. Of course thats a bad idea
It's not bad, just remember that other apps can write to the appdata directory too.
Basically, you don't want to give global access to code loaded from non trusted locations.
Before you execute the saved script, use setfenv ( https://www.lua.org/pil/14.3.html )
User avatar
ivan
Party member
Posts: 1915
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: BroccoliUtils - Misc. Collections of Libraries

Post by ivan »

Regarding your timer lib: you can't store the index of a timer, because when you use table.remove all of the existing indexes shift over.
Also, you don't need "self:" when you are working with closures.
This is untested but it might give you a few ideas:

Code: Select all

local dim4 = {}

local timers = {}

function dim4.newTimer(isclock, delay, func, ...)
  local running = false
  local elapsed = 0
  local t = {}
  function t.update(dt)
    elapsed = elapsed + dt
    if elapsed < delay then
      return true
    end
    t.callback()
    if isclock then
      elapsed = elapsed%delay
    end
    return isclock
  end
  function t.callback()
    func(elapsed, ...)
  end
  function t.start()
    if running then
      running = true
      table.insert(timers, t)
    end
  end
  function t.stop(index)
    if running then
      running = false
      if not index then
        for i = 1, #timers do
          if timers[i] == t then
            index = i
            break
          end
        end
      end
      assert(t == timers[index])
      table.remove(timers, index)
    end
  end
  function t.reset()
    elapsed = 0
  end
  function t.destroy()
    t.stop()
    func = nil
    elapsed = nil
  end
  return t
end

function dim4.update(dt)
  for i = #timers, 1, -1 do
    local t = timers[i]
    if not t.update(dt) then
      t.stop(i)
    end
  end
end

return dim4
Note that in "destroy" we unset the important "func" reference and the "elapsed" variable - this ensures that your timer cannot be used after calling "destroy".
One of the benefits of closures is that you have access to the original up-values so you can pass additional arguments:

Code: Select all

local dim4 = require("path.to.dim4")

function trigger(actualtime, p)
  print(actualtime, p)
end

dim4.newTimer(true, 1, trigger, "every second!")
dim4.newTimer(false, 5, trigger, "once after five seconds")

function love.update(dt)
  dim4.update(dt)
end
grump
Party member
Posts: 947
Joined: Sat Jul 22, 2017 7:43 pm

Re: BroccoliUtils - Misc. Collections of Libraries

Post by grump »

BroccoliRaab wrote: Mon Mar 05, 2018 7:38 pm I'll at least add the assert right now.

Code: Select all

Error: Syntax error: saveData.lua:64: ')' expected near '='
You're assigning a value in the assert line when you should be comparing it using ~=.

Check ivan's example code, it shows how to detect cycles, even deeply nested cycles. Just checking the current table for references to itself is not enough.

There are some more checks needed to make it stable:

Code: Select all

local sd = require('saveData')
local t = { [love.image.newImageData(8, 8)] = 64 }

sd.save(t, 'test.lua')
This results in invalid code that can't be loaded. I would expect a serialization library to fail in this case and tell me what went wrong. Better check if all index types are valid, not just for tables as indices. From the top of my head: userdata, table, function and thread are problematic. There may be more.
Post Reply

Who is online

Users browsing this forum: Amazon [Bot] and 3 guests