Yonaba / Jumper

Fast, lightweight and easy-to-use pathfinding library for grid-based games
http://yonaba.github.io/Jumper
MIT License
607 stars 122 forks source link

Integrating Jumper in TrAinsported #15

Closed maxxst closed 10 years ago

maxxst commented 11 years ago

Hi there I'm trying to connect the Jumper library with the programming game trAInsported but I'm unable to get the require 'foo.bar' thing working .. is this a known issue or am I just to stupid ?

Yonaba commented 11 years ago

Maybe you can be more explicit about the exact problem (error message), or show the relevant part of your code ?

maxxst commented 11 years ago

hey thanks for the fast response :) In trAInsporting everything happens in the AI folder. So I copied the the jumper-folder in there and created a new AI:

Grid = require 'jumper.grid'
PF = require 'jumper.pathfinder'

function ai.init(map, money)
  local walkable = function(v) return v == 'C' end
  local grid = Grid(map)
  local finder = PF(grid, 'ASTAR',walkable)
  finder:annotateGrid()

  for y = 1, #map do
    local s = ''
    for x = 1, #map[y] do
      local node = grid:getNodeAt(x,y)
      s = (s .. ' ' .. node:getClearance(walkable))
    end
    print(s)
  end
end

but when I start with that I get the following error: no such file or directory when I replace the . with / it works but the the variable is nil

EDIT

I guess it's a problem with the implementation of trAInsported's require ... but I have to work with this version so maybe you have an idea for a workaround ?

Yonaba commented 11 years ago

I see what's going on here. This is simply due to the way trAinsported handle Ai files. For security reasons, the game emulates a sandbox, inside which some native Lua functions were redefined. require is supported inside the sandbox, but it acts as a shortcut to dofile, which is just supposed to execute a chunk but not to return anything. That's the reason why you get a nil as a return value.

Well, that said, it won't be that hard to workaround that. Instead of having multiple files, i'll have to pack the whole module (set of files) into a single file, and expose some parts of its API into the global environment, so that they will be imported when using the require function in the game sandbox. Unfortunately, there's no way to do it straight, as it might require to tweak a bit the source code.

I'll be taking a closer look at it, as soon as I can manage to find some spare time. I will probably set this on a different development branch in this repository.

maxxst commented 11 years ago

I will have a closer look too :-) but thanks a lot  ~ Max

On Sat, Jul 20, 2013 at 1:55 PM, Roland Y. notifications@github.com wrote:

I see what's going on here. This is simply due to the way trAinsported handle Ai files. For security reasons, the game emulates a sandbox, inside which some native Lua functions were redefined. require is supported inside the sandbox, but it acts as a shortcut to dofile, which is just supposed to execute a chunk but not to return anything. That's the reason why you get a nil as a return value. Well, that said, it won't be that hard to workaround that. Instead of having multiple files, i'll have to pack the whole module (set of files) into a single file, and expose some parts of its API into the global environment, so that they will be imported when using the require function in the game sandbox. Unfortunately, there's no way to do it straight, as it might require to tweak a bit the source code. I'll be taking a closer look at it, as soon as I can manage to find some spare time.

I will probably set this on a different development branch in this repository.

Reply to this email directly or view it on GitHub: https://github.com/Yonaba/Jumper/issues/15#issuecomment-21292485

Yonaba commented 11 years ago

@maxxst : Just pushed a patch into a new branch of the repository. See commit 80b05dacec. Don't forget to take a quick look at the Readme, more precisely to the example of use. How is that working for you ?

maxxst commented 11 years ago

thanks for your work I will have a look later today

you are the best :D

maxxst commented 11 years ago

sadly

require '_jumper/jumper.lua'
function ai.init(map, money)
  -- Simple check to assert if Jumper was successfully imported
  assert(Jumper and type(Jumper) == 'table', 'Error loading the Jumper module')

  local walkable = function(v) return v == 'C' end

  -- Library setup
  local Grid = Jumper.Grid -- Alias to the Grid submodule
  local Pathfinder = Jumper.Pathfinder -- Alias to the Pathfinder submodule

  local grid = Grid(map)
  -- Creates a pathfinder object using Jump Point Search
  local myFinder = Pathfinder(grid, 'JPS', walkable) 

  -- Define start and goal locations coordinates
  local startx, starty = 1,1
  local endx, endy = 5,1

  -- Calculates the path, and its length
  local path = myFinder:getPath(startx, starty, endx, endy)
  if path then
    print(('Path found! Length: %.2f'):format(path:getLength()))
      for node, count in path:nodes() do
        print(('Step: %d - x: %d - y: %d'):format(count, node.x, node.y))
      end
  end
end

produces the following error: attempt to call local 'setmetatable' (a nil value) already in the require

Filestructure

AI
| - _jumper
| | - jumper.lua
| - jumperAI.lua
Yonaba commented 11 years ago

Yes, I had a terrible feeling right after pushing this. I didn't totally fix the problem. The thing is, trAinsported sandbox doesn't support setmetatable or getmetatable functions. I should have expected that, as they are unsecure. That's the reason why it fails to load the module.

The problem is, due to the way Jumper is organized, and due to the fact it has to return objects to the user and facilities to manipulate them, I am using an object oriented programming style. And a lot of the code relies on those two functions (I mean (set/get)metatable) because of inheritance between internal objects/classes. I will probably have to consider emulating internally classes with my own proper subset of inheritance facilities to solve the problem. That seems very doable.

Anyway, you can work around that as of now by modifying the source code of your own copy of trAinsported, to start playing with Jumper. Just add those two lines in the file sandbox.lua after line 96 in the sandbox.createNew function.

sb.setmetatable = setmetatable
sb.getmetatable = getmetatable
sb.assert = assert

Of course, it will work only for your own copy of the game, as adding this would break the sandboxing security. But as I said, it's a workaround :P

Note: make sure the map passed to the Grid module is actually compatible with Jumper's map. Otherwise, you might have to convert them.

Yonaba commented 11 years ago

@maxxst : New commit (see 3a32dd4768). Should solve the problem, hopefully.

maxxst commented 11 years ago

so I used your new commit and got a later error:

attempt to compare two table values in f_min called by precolate_up ...

maxxst commented 11 years ago

i changed it to

-- Default comparison function
local function f_min(a,b)
    if type(a) == 'table' and type(b) == 'table' then
        return #a < #b
    end
    return a < b
end

seems to work now

but I have no idea what I am doing xD

Yonaba commented 11 years ago

Oh, silly me, I fixed it. The comparison should be based on the F-cost property.