[Library] Commonlib [commonlib] [0.1]

User avatar
rubenwardy
Member
 
Posts: 4500
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy

[Library] Commonlib [commonlib] [0.1]

by rubenwardy » Sat Feb 16, 2013 18:03

[h]Commonlib[/h]

This adds common functions that help Minetest modders achieve perfection in both their mod, and in interacting with other mods too.

You can include the whole library as a mod (recommended) or just include some modules in your mod.

Contains

  • Soft depend
  • Vector calculations, such as distance and speed
  • Terrain calculations, such as find the surface
  • See who owns a node
  • Table loading and saving
  • Player exists

Complete list

Image

[h]Download[/h]


Download the library
or view the code

License: CC-BY-SA

  • These conditions apply to the Commonlib code, and not to any mods using the library.
  • Commonlib is counted as a seperate library rather than part of the mod using it.
  • This means you can use Commonlib in a mod with a different license to this.

Image

[h]The Project[/h]

Aim: To promote and make easy mod making etiquette, in particular adding soft support/depends for other mods.

Thanks to: Sapier, Celeron55, PilzAdam, VanessaE

Image

[h]Help Us[/h]
This is meant to be a community project, so feel free to do some work to it.
Ideas are also good.
Last edited by rubenwardy on Wed Feb 20, 2013 13:10, edited 1 time in total.
 

User avatar
PilzAdam
Member
 
Posts: 4026
Joined: Fri Jul 20, 2012 16:19
GitHub: PilzAdam
IRC: PilzAdam

by PilzAdam » Sat Feb 16, 2013 18:09

Some vector stuff:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
local v3 = {}
function v3.new(x, y, z)
    if x == nil then
        return {
            x = 0,
            y = 0,
            z = 0
        }
    end
    if type(x) == "table" then
        return {
            x = x.x,
            y = x.y,
            z = x.z,
        }
    end
    return {
        x = x,
        y = y,
        z = z,
    }
end
function v3.floor(v)
    return {
        x = math.floor(v.x),
        y = math.floor(v.y),
        z = math.floor(v.z),
    }
end
function v3.cmp(v, w)
    return (
        v.x == w.x and
        v.y == w.y and
        v.z == w.z
    )
end
function v3.add(v, w)
    return {
        x = v.x + w.x,
        y = v.y + w.y,
        z = v.z + w.z,
    }
end
function v3.sub(v, w)
    return {
        x = v.x - w.x,
        y = v.y - w.y,
        z = v.z - w.z,
    }
end
function v3.mul(v, a)
    return {
        x = v.x * a,
        y = v.y * a,
        z = v.z * a,
    }
end
function v3.len(v)
    return math.sqrt(
        math.pow(v.x, 2) +
        math.pow(v.y, 2) +
        math.pow(v.z, 2)
    )
end
function v3.norm(v)
    return v3.mul(v, 1.0 / v3.len(v))
end
function v3.distance(v, w)
    return math.sqrt(
        math.pow(v.x - w.x, 2) +
        math.pow(v.y - w.y, 2) +
        math.pow(v.z - w.z, 2)
    )
end
function v3.rotate_y(v, a)
    return {
        x = v.x * math.cos(a) - v.z * math.sin(a),
        y = v.y,
        z = v.x * math.sin(a) + v.z * math.cos(a),
    }
end

From celeron55's blockmobs mod, WTFPL.

I'd suggest to just create a global v3 table, where are this functions are stored.
 

User avatar
rubenwardy
Member
 
Posts: 4500
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy

by rubenwardy » Sat Feb 16, 2013 18:32

Thank you PilzAdam.

Code added
 

Sokomine
Member
 
Posts: 2980
Joined: Sun Sep 09, 2012 17:31

by Sokomine » Sun Feb 17, 2013 17:45

Good thing! Could you include common functions to store and retrieve data (tables) as well? Plus a function that checks if an area is owned would be good (VanessaE has one in homedecor).

Recently I noticed that copying tables in lua is a pain. The language lacks some very basic functionality that ought to be part of a language. Functions for tables that copy them (deepcopy), return the index of a value from a table, and that return if a value is part of a table or not would be helpful. Or maybe there's a lib out there already somewhere that adds these things?

[Edit] And please make sure this gets into default_game.[/Edit]
Last edited by Sokomine on Sun Feb 17, 2013 17:46, edited 1 time in total.
A list of my mods can be found here.
 

rarkenin
Member
 
Posts: 668
Joined: Tue Nov 20, 2012 20:48

by rarkenin » Sun Feb 17, 2013 17:53

I'll see if I can make some more include libraries.
Admin pro tempore on 0gb.us:30000. Ask me if you have a problem, or just want help.
This is a signature virus. Add me to your signature so that I can multiply.
Now working on my own clone, Mosstest.
I guess I'm back for some time.
 

User avatar
rubenwardy
Member
 
Posts: 4500
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy

by rubenwardy » Sun Feb 17, 2013 18:36

Sokomine wrote:Good thing! Could you include common functions to store and retrieve data (tables) as well?


http://dev.minetest.net/serialize

Sokomine wrote:Plus a function that checks if an area is owned would be good (VanessaE has one in homedecor).


These have been added
Last edited by rubenwardy on Sun Feb 17, 2013 18:54, edited 1 time in total.
 

rarkenin
Member
 
Posts: 668
Joined: Tue Nov 20, 2012 20:48

by rarkenin » Sun Feb 17, 2013 21:25

I'm not planning much, as I am busy with other programming, but I might implement a binary search tree.
Admin pro tempore on 0gb.us:30000. Ask me if you have a problem, or just want help.
This is a signature virus. Add me to your signature so that I can multiply.
Now working on my own clone, Mosstest.
I guess I'm back for some time.
 

Sokomine
Member
 
Posts: 2980
Joined: Sun Sep 09, 2012 17:31

by Sokomine » Mon Feb 18, 2013 18:10

minetest.serialize is usually one part of storing table data. I was thinking more of a function that looks for the right world dir, creates the file there and dumps the data. In short, one location that can later be adopted to diffrend needs (i.e. storage of that data in a database, new, safer io-routines).
A list of my mods can be found here.
 

User avatar
Bas080
Member
 
Posts: 398
Joined: Mon May 21, 2012 15:54
GitHub: bas080
IRC: bas080
In-game: bas080

by Bas080 » Tue Feb 19, 2013 04:10

Some suggestions for the library
* Save/Load function 3d area of nodes
* "selectors" to get nodes at (nth) top/bottom/east/south/west/north/area.
* Function for perlin noise something like perlin(seed, saturation, etc, etc)
* Check if area is free(of certain nodes)(air or other nodes) isfree({nodes},areaHeight,areaWidth) or isfree({nodes},{positions table})
* fillArea({node, chance},{positions table})

Just some ideas. Not all useful but maybe a bit useful
 

Sokomine
Member
 
Posts: 2980
Joined: Sun Sep 09, 2012 17:31

by Sokomine » Wed Feb 20, 2013 03:10

* check if a player exists (i.e. has been one the server at least once or even has interact)
A list of my mods can be found here.
 

rarkenin
Member
 
Posts: 668
Joined: Tue Nov 20, 2012 20:48

by rarkenin » Wed Feb 20, 2013 13:47

Binary search tree for fast lookup(I abandoned my BST after my schedule went haywire with science competition)
Admin pro tempore on 0gb.us:30000. Ask me if you have a problem, or just want help.
This is a signature virus. Add me to your signature so that I can multiply.
Now working on my own clone, Mosstest.
I guess I'm back for some time.
 

User avatar
Calinou
Member
 
Posts: 3124
Joined: Mon Aug 01, 2011 14:26
GitHub: Calinou
IRC: Calinou
In-game: Calinou

by Calinou » Wed Feb 20, 2013 20:12

Bas080 wrote:* fillArea({node, chance},{positions table})

If this is implemented, it should be named fill_area, not fillArea.

Sokomine wrote:* check if a player exists (i.e. has been one the server at least once or even has interact)


You can do that somehow, check if a player has "shout" privilege. This however doesn't work if you disable shout by default. If you do, then create a dummy privilege that does nothing and is given to everyone then check whether a player has it.
 

User avatar
rubenwardy
Member
 
Posts: 4500
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy

by rubenwardy » Thu Feb 21, 2013 11:02

Calinou wrote:
Bas080 wrote:* fillArea({node, chance},{positions table})

If this is implemented, it should be named fill_area, not fillArea.

Sokomine wrote:* check if a player exists (i.e. has been one the server at least once or even has interact)


You can do that somehow, check if a player has "shout" privilege. This however doesn't work if you disable shout by default. If you do, then create a dummy privilege that does nothing and is given to everyone then check whether a player has it.


I have already added this
 

User avatar
0gb.us
Member
 
Posts: 841
Joined: Sun Sep 16, 2012 01:55

by 0gb.us » Thu Feb 21, 2013 12:17

If added to the default game, it shouldn't have functions that specifically apply to node_ownership, which is not in the default game. That's not the only way to own nodes. There's also 0gb_us, protector, protectorplus, landrush .... You get the point.

EDIT: Unless you add some way to register the "protected by check function", so all of these plugins could hook into yours and provide a way to tell who owns an area.

Then again, I'm fairly certain all these things already provide a built-in way to tell who owns a node.
Last edited by 0gb.us on Thu Feb 21, 2013 12:21, edited 1 time in total.
 

Sokomine
Member
 
Posts: 2980
Joined: Sun Sep 09, 2012 17:31

by Sokomine » Fri Feb 22, 2013 15:57

The goal is to get commonlib to be part of the game. It belongs to default once it's complete enough.
A list of my mods can be found here.
 

User avatar
jordan4ibanez
Member
 
Posts: 1865
Joined: Tue Sep 27, 2011 18:44
GitHub: jordan4ibanez
IRC: jordan4ibanez
In-game: jordan4ibanez

by jordan4ibanez » Fri Feb 22, 2013 20:29

What is this useful for?
If you can think it, you can make it.
 

User avatar
Mito551
Member
 
Posts: 1271
Joined: Sat Jun 16, 2012 15:03

by Mito551 » Fri Feb 22, 2013 23:13

jordan4ibanez wrote:What is this useful for?


mobs stuff, flat stuff, locking stuff, whatever
Last edited by Mito551 on Fri Feb 22, 2013 23:13, edited 1 time in total.
 

prestidigitator
Member
 
Posts: 632
Joined: Thu Feb 21, 2013 23:54

by prestidigitator » Sat Feb 23, 2013 00:33

In terms of some vector math, here is some ray/volume tracing code I wrote as part of a wands mod I have been working on (yeah, I thought appending two arrays would probably be part of the Lua API somewhere, but...).

WTFPL (I'm sure you'll want to change the names from camelCase and of course change the namespace.)

Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
local appendList = function(lTable, rTable)
   for i, value in ipairs(rTable) do
      table.insert(lTable, value)
   end
end

-- Returns all combinations of +x, -x, +y, -y, +z, -z for the given vector,
-- reflecting it about each of the xy, xz, and yz planes.  If any component
-- is zero, it generates only one vector for each unique combination of the
-- other reflected components.  No guarantee is made about the order of the
-- returned vectors.
--
-- For example, the (shorthand) input (0, 1, 3) will return a list with the
-- (shorthand) values (0, -1, -3), (0, -1, +3), (0, +1, -3), (0, +1, +3),
-- though not necessarily in that order.
--
-- @param vec
--    The vector to be reflected.
local signCombos
do
   local flipZ = function(vec)
      local z = vec.z
      if z == 0 then
         return { vec }
      else
         return { vec, { x = vec.x, y = vec.y, z = -z } }
      end
   end

   local flipYz = function(vec)
      local y = vec.y
      if y == 0 then
         return flipZ(vec)
      else
         local vecs = flipZ(vec)
         local negVecs = {}
         for i, v in pairs(vecs) do
            table.insert(negVecs, { x = v.x, y = -y, z = v.z})
         end
         appendList(vecs, negVecs)
         return vecs
      end
   end

   signCombos = function(vec)
      local x = vec.x
      if x == 0 then
         return flipYz(vec)
      else
         local vecs = flipYz(vec)
         local negVecs = {}
         for i, v in pairs(vecs) do
            table.insert(negVecs, { x = -x, y = v.y, z = v.z })
         end
         appendList(vecs, negVecs)
         return vecs
      end
   end
end

--- Interpolates along a ray starting at a given position and heading in a
 -- given direction, calling the provided callback function for each step
 -- along the path.  Steps are in unit increments along the fastest changing
 -- dimension, so if the axis closest to the ray's direction is -x, each
 -- step will have x decremented by one until maxDist total distance along
 -- the ray is reached.
 --
 -- The callback function has the form function(pos, dist, userParam) and
 -- returns true if the traversal should continue.  The first parameter is
 -- the current interpolated position along the path.  The second parameter
 -- is the current distance along the path.  The third parameter is the
 -- userParam parameter passed to this function.
 --
 -- @param startPos
 --    The ray's starting position: {x = ..., y = ..., z = ...}
 -- @param tangentVec
 --    A unit vector (assumed) in the direction of the ray:
 --    {x = ..., y = ..., z = ...}
 -- @param minDist
 --    The minimum distance to which to start traversing the ray.  Will
 --    simply skip steps until the distance is at least this high.
 -- @param maxDist
 --    The maximum total distance along which to traverse the ray.  If
 --    negative, traversal will continue indefinitely until the callback
 --    indicates it is done.
 -- @param callback
 --    Function called at each position along the ray's path.
 -- @param userParam
 --    Value passed as the last argument to each invocation of the callback.
function wands.rayTrace(
            startPos, tangentVec, minDist, maxDist, callback, userParam)
   local uVar = "x"
   local duDt = tangentVec[uVar];
   local magDuDt = math.abs(duDt)

   for vVar, dvDt in pairs(tangentVec) do
      local magDvDt = math.abs(dvDt)
      if magDvDt > magDuDt then
         uVar = vVar
         duDt = dvDt
         magDuDt = magDvDt
      end
   end

   local dt = 1.0/magDuDt
   local t
   if minDist > 0.0 then t = math.ceil(minDist/dt)*dt else t = 0.0 end
   repeat
      local cont = callback(
                      {
                         x = startPos.x + t * tangentVec.x,
                         y = startPos.y + t * tangentVec.y,
                         z = startPos.z + t * tangentVec.z
                      },
                      t,
                      userParam)

      if not cont then break end

      t = t + dt
   until maxDist >= 0 and t > maxDist
end



--- Interpolates throughout the volume of a sphere centered at a given
 -- position with a given radius, calling the provided callback function for
 -- each voxel touched by the sphere.
 --
 -- The given position for the center of the sphere is first rounded to the
 -- nearest integer coordinates, and the center of each voxel is assumed to
 -- be offset from this by integer values in each coordinate direction.  A
 -- voxel is traversed if any of its corners is inside or on the surface of
 -- the perfect sphere.  It is considered "inside" if all of its corners are
 -- completely inside and not touching the surface of the perfect sphere.
 --
 -- No order is guaranteed for the traversal, so the callback function
 -- should only stop traversal if, for example, it just needs to find one
 -- thing in the volume and has found it in the current step.
 --
 -- The callback function has the form function(pos, rSq, inside, userParam)
 -- and returns true if the traversal should continue.  The first parameter
 -- is the position of the center of the current voxel.  The second
 -- parameter is the square of the distance from the center of the sphere to
 -- the center of the current voxel.  The third parameter is a boolean
 -- indicating whether the voxel is considered "inside" the sphere.  The
 -- fourth parameter is the userParam parameter passed to this function.
 --
 -- @param centerPos
 --    The sphere's center position: {x = ..., y = ..., z = ...}
 -- @param radius
 --    The radius of the sphere.  Must be a positive number (assumed), but
 --    need not be an integer.
 -- @param callback
 --    Function called at each voxel touched by the sphere.
 -- @param userParam
 --    Value passed as the last argument to each invocation of the callback.
function wands.sphereTrace(centerPos, radius, callback, userParam)
   local center = { x = math.floor(centerPos.x+0.5),
                    y = math.floor(centerPos.y+0.5),
                    z = math.floor(centerPos.z+0.5) }
   local sphereRadSq = radius^2

   for rx = 0, radius+1 do
      local rxSq = rx^2

      for ry = 0, radius+1 do
         local rySq = ry^2
         local hrSq = rxSq + rySq

         -- make up differences between ri^2 and (ri-0.5)^2
         local nearHrSq = hrSq - rx - ry + 0.5

         local hSq = sphereRadSq-nearHrSq
         if hSq >= 0.0 then
            local h = math.ceil(math.sqrt(hSq))

            for rz = 0, h+1 do
               local rzSq = rz^2
               local rSq = hrSq + rzSq

               -- make up differences between ri^2 and (ri-0.5)^2
               local nearRSq = rSq - rx - ry - rz + 0.75
               if nearRSq > sphereRadSq then break end

               -- make up differences between ri^2 and (ri+0.5)^2
               local farRSq = rSq + rx + ry + rz + 0.75
               local inside = (farRSq < sphereRadSq)

               for i, v in pairs(signCombos({ x = rx, y = ry, z = rz })) do
                  local cont =
                     callback(
                        {
                           x = center.x + v.x,
                           y = center.y + v.y,
                           z = center.z + v.z
                        },
                        rSq,
                        inside,
                        userParam)

                  if not cont then return end
               end
            end
         end
      end
   end
end
 

User avatar
0gb.us
Member
 
Posts: 841
Joined: Sun Sep 16, 2012 01:55

by 0gb.us » Sat Feb 23, 2013 01:11

Sokomine wrote:The goal is to get commonlib to be part of the game. It belongs to default once it's complete enough.


Yes, I understand that. Which is why the stuff that is in commonlib but is specific to node_ownership should be removed. Things that are specific to node_ownership do not belong in the default game.
 

prestidigitator
Member
 
Posts: 632
Joined: Thu Feb 21, 2013 23:54

by prestidigitator » Sun Feb 24, 2013 01:35

I have created a full Vec3 "class" that is 100% compatible with the vector tables Minetest uses. It provides basically everything you could want to do with a vector: construction, copying, addition, subtraction, negation, getting length, dot, cross, multiplication by a scalar, etc. Also, it uses operator overloading so you can write, for example, v1+v2 in addition to v1:add(v2) or Vec3.add(v1, v2).

All code is WTFPL.

Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
local Vec3_obj_meta = {}

--- 3D vector class/operations.
 --
 -- Note that methods can be called in either an object-oriented way:
 --    v1 = Vec3(1, 2, 3)
 --    v2 = v1:add({ x = 2, y = 2, z = 0 })
 -- or as simple functions:
 --    Vec3.add({ x = 1, y = 2, z = 3 }, { x = 2, y = 2, z = 0 })
 --
 -- All methods that can be called on a Vec3 using ":" may be called on a table
 -- using the second functional syntax, but the first parameter MUST have the
 -- expected components "x", "y", and "z".  If a vector is used as the second
 -- paramter, it may instead be a list/array with numeric indices, like
 -- { 1.0, 2.0, 3.0 } in place of { x = 1.0, y = 2.0, z = 3.0 }.
 --
 -- @author prestidigitator (as registered at forum.minetest.net)
 -- @copyright 2013, licensed under WTFPL
 --
Vec3 =
   {
      --- Constructs a Vec3 from three numbers.
       --
       -- Call with one of:
       --    Vec3.new(x, y, z)
       --    Vec3(x, y, z)
       --
       -- @return a new Vec3 object
      new = function(x, y, z)
         local obj = { x = x or 0.0, y = y or 0.0, z = z or 0.0 }
         setmetatable(obj, Vec3_obj_meta)
         return obj
      end,

      --- Constructs a new copy of a Vec3.
       --
       -- Call with one of:
       --    vec:new_copy()
       --    Vec3.new_copy(vec)
       --    Vec3(vec)
       --
       -- @return a new Vec3 object that is a copy of the parameter
      new_copy = function(v)
         local obj = { x = v.x or v[1] or 0.0,
                       y = v.y or v[2] or 0.0,
                       z = v.z or v[3] or 0.0 }
         setmetatable(obj, Vec3_obj_meta)
         return obj
      end,

      --- Computes the square of the length of a Vec3.
       --
       -- Call with one of:
       --    vec:len_sq()
       --    Vec3.len_sq(vec)
       --
       -- @return A number
      len_sq = function(v)
         return v.x^2 + v.y^2 + v.z^2
      end,

      --- Computes the length of a Vec3.
       --
       -- Call with one of:
       --    vec:len()
       --    Vec3.len(vec)
       --
       -- @return A number
      len = function(v)
         return math.sqrt(v.x^2 + v.y^2 + v.z^2)
      end,

      --- Computes a unit vector pointing in the same direction as a Vec3.
       -- Undefined for a zero-vector and may throw an error.
       --
       -- Call with one of:
       --    vec:unit()
       --    Vec3.unit(vec)
       --
       -- @return A new Vec3 with length 1.0
      unit = function(v)
         local len = math.sqrt(v.x^2 + v.y^2 + v.z^2)
         return Vec3.new(v.x/len, v.y/len, v.z/len)
      end,

      --- Multiplies a Vec3 by a number.
       --
       -- Call with one of:
       --    vec:mul(m)
       --    Vec3.mul(vec, m)
       --    vec*m
       --    m*vec
       --
       -- @return a new Vec3 object with the result of the operation
      mul = function(v, m)
         return Vec3.new(v.x*m, v.y*m, v.z*m)
      end,

      --- Divides a Vec3 by a number.
       --
       -- Call with one of:
       --    vec:div(m)
       --    Vec3.div(vec, m)
       --    vec/m
       --
       -- @return a new Vec3 object with the result of the operation
      div = function(v, m)
         return Vec3.new(v.x/m, v.y/m, v.z/m)
      end,

      --- Negates a Vec3 (signs of all components are inverted).
       --
       -- Call with one of:
       --    vec:unm()
       --    Vec3.unm(vec)
       --    -vec
       --
       -- @return a new Vec3 object with the result of the operation
      unm = function(v)
         return Vec3.new(-v.x, -v.y, -v.z)
      end,

      --- Adds two Vec3s or a Vec3 composed of three given components.
       --
       -- Call with one of:
       --    vec1:add(vec2)
       --    vec1:add(x, y, z)
       --    Vec3.add(vec1, vec2)
       --    Vec3.add(vec1, x, y, z)
       --    vec1 + vec2
       --
       -- @return a new Vec3 object with the result of the operation
      add = function(v, a, b, c)
         if type(a) == "table" then
            return Vec3.new(v.x + (a.x or a[1] or 0.0),
                            v.y + (a.y or a[2] or 0.0),
                            v.z + (a.z or a[3] or 0.0))
         else
            return Vec3.new(v.x + a, v.y + b, v.z + c)
         end
      end,

      --- Subtracts two Vec3s or a Vec3 composed of three given components.
       --
       -- Call with one of:
       --    vec1:sub(vec2)
       --    vec1:sub(x, y, z)
       --    Vec3.sub(vec1, vec2)
       --    Vec3.sub(vec1, x, y, z)
       --    vec1 - vec2
       --
       -- @return a new Vec3 object with the result of the operation
      sub = function(v, a, b, c)
         if type(a) == "table" then
            return Vec3.new(v.x - (a.x or a[1] or 0.0),
                            v.y - (a.y or a[2] or 0.0),
                            v.z - (a.z or a[3] or 0.0))
         else
            return Vec3.new(v.x - a, v.y - b, v.z - c)
         end
      end,

      --- Tests two Vec3s or a Vec3 composed of three given components for
       -- exact component-wise equality.
       --
       -- Call with one of:
       --    vec1:eq(vec2)
       --    vec1:eq(x, y, z)
       --    Vec3.eq(vec1, vec2)
       --    Vec3.eq(vec1, x, y, z)
       --    vec1 == vec2
       --    vec1 ~= vec2
       -- Note that because of built-in Lua logic "==" and "~=" work ONLY if
       -- vec1 and vec2 are actually Vec3s (not tables).
       --
       -- @return a new Vec3 object with the result of the operation
      eq = function(v, a, b, c)
         if type(a) == "table" then
            return v.x == (a.x or a[1] or 0.0) and
                   v.y == (a.y or a[2] or 0.0) and
                   v.z == (a.z or a[3] or 0.0)
         else
            return v.x == a and v.y == b and v.z == c
         end
      end,

      --- Takes the dot product of a Vec3 and a Vec3s or a Vec3 composed of
       -- three given components.
       --
       -- Call with one of:
       --    vec1:dot(vec2)
       --    vec1:dot(x, y, z)
       --    Vec3.dot(vec1, vec2)
       --    Vec3.dot(vec1, x, y, z)
       --
       -- @return a number
      dot = function(v, a, b, c)
         if type(a) == "table" then
            return v.x * (a.x or a[1] or 0.0) +
                   v.y * (a.y or a[2] or 0.0) +
                   v.z * (a.z or a[3] or 0.0)
         else
            return v.x * a + v.y * b + v.z * c
         end
      end,

      --- Takes the cross product of a Vec3 and a Vec3s or a Vec3 composed of
       -- three given components.
       --
       -- Call with one of:
       --    vec1:cross(vec2)
       --    vec1:cross(x, y, z)
       --    Vec3.cross(vec1, vec2)
       --    Vec3.cross(vec1, x, y, z)
       --
       -- @return a new Vec3 with the result of the operation
      cross = function(v, a, b, c)
         local ux, uy, uz
         if type(a) == "table" then
            ux = a.x or a[1] or 0.0
            uy = a.y or a[2] or 0.0
            uz = a.z or a[3] or 0.0
         else
            ux = a or 0.0
            uy = b or 0.0
            uz = c or 0.0
         end

         return Vec3.new(v.y*uz - v.z*uy, v.z*ux - v.x*uz, v.x*uy - v.y*ux)
      end,

      --- Rotates this (the first) vector around the second vector by the
       -- given angle.
       --
       -- Call with one of:
       --    vec:rot_around(axis, angle)
       --    Vec3.rot_around(vec, axis, angle)
       --
       -- @param axis
       --    The axis about which to rotate.
       -- @param angle
       --    The angle by which to rotate this vector, in radians.
       -- @return
       --    a new Vec3 with the result of the operation.
      rot_around = function(v, axis, angle)
         local uaxis = Vec3.new_copy(axis):unit()

         local alen = uaxis:dotvec(v)
         local avec = uaxis:mul(alen)

         local pvec = Vec3.subvec(v, avec)
         local rvec = uaxis:crossvec(v)

         local v1 = pvec:mul(math.cos(angle))
         local v2 = rvec:mul(math.sin(angle))

         return avec:addvec(v1):addvec(v2)
      end,

      --- Adds two Vec3s. Optimized for pure Vec3/table operations by removing
       -- type checking and conditionals.  If called with Vec3-likes table(s),
       -- ensure all expected components "x", "y", and "z" exist.
       --
       -- Call with one of:
       --    vec1:addvec(vec2)
       --    Vec3.addvec(vec1, vec2)
       --
       -- @return a new Vec3 object with the result of the operation
      addvec = function(v1, v2)
         return Vec3.new(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z)
      end,

      --- Subtracts two Vec3s. Optimized for pure Vec3/table operations by
       -- removing type checking and conditionals.  If called with Vec3-likes
       -- table(s), ensure all expected components "x", "y", and "z" exist.
       --
       -- Call with one of:
       --    vec1:subvec(vec2)
       --    Vec3.subvec(vec1, vec2)
       --
       -- @return a new Vec3 object with the result of the operation
      subvec = function(v1, v2)
         return Vec3.new(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z)
      end,

      --- Tests two Vec3s for exact component-wise equality. Optimized for pure
       -- Vec3/table operations by removing type checking and conditionals.
       -- If called with Vec3-likes table(s), ensure all expected components
       -- "x", "y", and "z" exist.
       --
       -- Call with one of:
       --    vec1:eqvec(vec2)
       --    Vec3.eqvec(vec1, vec2)
       --
       -- @return a new Vec3 object with the result of the operation
      eqvec = function(v1, v2)
         return v1.x == v2.x and v1.y == v2.y and v1.z == v2.z
      end,

      --- Takes the dot product of two Vec3s. Optimized for pure Vec3/table
       -- operations by removing type checking and conditionals.  If called
       -- with Vec3-likes table(s), ensure all expected components "x", "y",
       -- and "z" exist.
       --
       -- Call with one of:
       --    vec1:dotvec(vec2)
       --    Vec3.dotvec(vec1, vec2)
       --
       -- @return a number
      dotvec = function(v1, v2)
         return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
      end,

      --- Takes the cross product of two Vec3s. Optimized for pure Vec3/table
       -- operations by removing type checking and conditionals.  If called
       -- with Vec3-likes table(s), ensure all expected components "x", "y",
       -- and "z" exist.
       --
       -- Call with one of:
       --    vec1:crossvec(vec2)
       --    Vec3.crossvec(vec1, vec2)
       --
       -- @return a new Vec3 with the result of the operation
      crossvec = function(v1, v2)
         return Vec3.new(v1.y*v2.z - v1.z*v2.y,
                         v1.z*v2.x - v1.x*v2.z,
                         v1.x*v2.y - v1.y*v2.x)
      end,

      --- Converts Vec3 to a string with format "(x,y,z)".
       --
       -- @return a string
      tostring = function(v)
         return "("..
                (v.x or v[1] or "0")
                ..","..
                (v.y or v[2] or "0")
                ..","..
                (v.z or v[3] or "0")
                ..")"
      end
   }

Vec3_obj_meta.__index = Vec3
Vec3_obj_meta.__add = Vec3.addvec
Vec3_obj_meta.__sub = Vec3.subvec
Vec3_obj_meta.__div = Vec3.div
Vec3_obj_meta.__unm = Vec3.unm
Vec3_obj_meta.__eq = Vec3.eq
Vec3_obj_meta.__tostring = Vec3.tostring

Vec3_obj_meta.__mul = function(a, b)
   if type(a) == "table" then
      return Vec3.mul(a, b)
   else
      return Vec3.mul(b, a)
   end
end

setmetatable(
   Vec3,
   {
      __call = function(dummy, a, b, c)
         if type(a) == "table" then
            return Vec3.new_copy(a)
         else
            return Vec3.new(a, b, c)
         end
      end
   })


EDIT: Fixed multiplication of scalar by vector (m*v vs. v*m).
EDIT: Added rot_around(...) method to rotate around an arbitrary axis.
Last edited by prestidigitator on Sun Feb 24, 2013 03:54, edited 1 time in total.
 

prestidigitator
Member
 
Posts: 632
Joined: Thu Feb 21, 2013 23:54

by prestidigitator » Sun Feb 24, 2013 01:37

Here are some unit tests for the above Vec3 class. This should also provide some examples of how to use the class.

All code is again WTFPL.

Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
dofile("Vec3.lua")

local v1, v2, v3

-- Constructors

v1 = Vec3.new()
assert(0.0 == v1.x)
assert(0.0 == v1.y)
assert(0.0 == v1.z)

v1 = Vec3.new_copy({})
assert(0.0 == v1.x)
assert(0.0 == v1.y)
assert(0.0 == v1.z)

v1 = Vec3()
assert(0.0 == v1.x)
assert(0.0 == v1.y)
assert(0.0 == v1.z)

v1 = Vec3.new(1.0, 2.0, 3.0)
assert(1.0 == v1.x)
assert(2.0 == v1.y)
assert(3.0 == v1.z)

v1 = Vec3(4.0, 5.0, 6.0)
assert(4.0 == v1.x)
assert(5.0 == v1.y)
assert(6.0 == v1.z)

v1 = Vec3.new_copy({ x = 7.0, y = 8.0, z = 9.0 })
assert(7.0 == v1.x)
assert(8.0 == v1.y)
assert(9.0 == v1.z)

v1 = Vec3.new_copy({ 10.0, 11.0, 12.0 })
assert(10.0 == v1.x)
assert(11.0 == v1.y)
assert(12.0 == v1.z)

v2 = Vec3.new_copy(v1)
assert(10.0 == v2.x)
assert(11.0 == v2.y)
assert(12.0 == v2.z)
assert(not rawequal(v1, v2))

v2 = v1:new_copy()
assert(10.0 == v2.x)
assert(11.0 == v2.y)
assert(12.0 == v2.z)
assert(not rawequal(v1, v2))

v2 = Vec3(v1)
assert(10.0 == v2.x)
assert(11.0 == v2.y)
assert(12.0 == v2.z)
assert(not rawequal(v1, v2))

v1 = Vec3({ x = 13.0, y = 14.0, z = 15.0 })
assert(13.0 == v1.x)
assert(14.0 == v1.y)
assert(15.0 == v1.z)

v1 = Vec3({ 16.0, 17.0, 18.0 })
assert(16.0 == v1.x)
assert(17.0 == v1.y)
assert(18.0 == v1.z)

-- Length

v1 = Vec3(0.0, 0.0, 0.0)
assert(v1:len_sq() == 0.0)
assert(v1:len() == 0.0)

v1 = Vec3(1.0, 0.0, 0.0)
assert(v1:len_sq() == 1.0)
assert(v1:len() == 1.0)

v1 = Vec3(1.0, 1.0, 1.0)
assert(v1:len_sq() == 3.0)
assert(math.abs(v1:len() - math.sqrt(3.0)) < 0.001)

-- Unit Vectors

v1 = Vec3(7.0, 0.0, 0.0)
v2 = v1:unit()
assert(math.abs(v2.x - 1.0) < 0.001)
assert(math.abs(v2.y - 0.0) < 0.001)
assert(math.abs(v2.z - 0.0) < 0.001)
assert(math.abs(v2:len_sq() - 1.0) < 0.001)
assert(math.abs(v2:len() - 1.0) < 0.001)

v1 = Vec3(1.0, 1.0, 1.0)
v2 = v1:unit()
assert(math.abs(math.sqrt(3.0)*v2.x - 1.0) < 0.001)
assert(math.abs(math.sqrt(3.0)*v2.y - 1.0) < 0.001)
assert(math.abs(math.sqrt(3.0)*v2.z - 1.0) < 0.001)
assert(math.abs(v2:len_sq() - 1.0) < 0.001)
assert(math.abs(v2:len() - 1.0) < 0.001)

-- Multiplication

v1 = Vec3(1.0, 2.0, 3.0)
v2 = v1:mul(5.0)
assert(5.0 == v2.x)
assert(10.0 == v2.y)
assert(15.0 == v2.z)
assert(math.sqrt(25.0*v1:len_sq() - v2:len_sq()) < 0.001)
assert(math.sqrt(5.0*v1:len() - v2:len()) < 0.001)

v2 = v1 * 7.0
assert(7.0 == v2.x)
assert(14.0 == v2.y)
assert(21.0 == v2.z)
assert(math.sqrt(49.0*v1:len_sq() - v2:len_sq()) < 0.001)
assert(math.sqrt(7.0*v1:len() - v2:len()) < 0.001)

v2 = 11.0 * v1
assert(11.0 == v2.x)
assert(22.0 == v2.y)
assert(33.0 == v2.z)
assert(math.sqrt(121.0*v1:len_sq() - v2:len_sq()) < 0.001)
assert(math.sqrt(11.0*v1:len() - v2:len()) < 0.001)

-- Division

v1 = Vec3(1.0, 2.0, 3.0)
v2 = v1:div(2.0)
assert(0.5 == v2.x)
assert(1.0 == v2.y)
assert(1.5 == v2.z)
assert(math.sqrt(v1:len_sq() - 4.0*v2:len_sq()) < 0.001)
assert(math.sqrt(v1:len() - 2.0*v2:len()) < 0.001)

-- Negation

v1 = Vec3(5.0, 4.0, 3.0)
v2 = v1:unm()
assert(-5.0 == v2.x)
assert(-4.0 == v2.y)
assert(-3.0 == v2.z)

v2 = -v1
assert(-5.0 == v2.x)
assert(-4.0 == v2.y)
assert(-3.0 == v2.z)

-- Addition

v1 = Vec3(10.0, 20.0, 30.0)
v2 = Vec3(1.0, 2.0, 3.0)
v3 = v1:add(v2)
assert(11.0 == v3.x)
assert(22.0 == v3.y)
assert(33.0 == v3.z)

v3 = v1:add(5.0, 6.0, 7.0)
assert(15.0 == v3.x)
assert(26.0 == v3.y)
assert(37.0 == v3.z)

v2 = Vec3(-1.0, -2.0, -3.0)
v3 = v1 + v2
assert(9.0 == v3.x)
assert(18.0 == v3.y)
assert(27.0 == v3.z)


-- Subtraction

v1 = Vec3(10.0, 20.0, 30.0)
v2 = Vec3(1.0, 2.0, 3.0)
v3 = v1:sub(v2)
assert(9.0 == v3.x)
assert(18.0 == v3.y)
assert(27.0 == v3.z)

v3 = v1:sub(5.0, 6.0, 7.0)
assert(5.0 == v3.x)
assert(14.0 == v3.y)
assert(23.0 == v3.z)

v2 = Vec3(-1.0, -2.0, -3.0)
v3 = v1 - v2
assert(11.0 == v3.x)
assert(22.0 == v3.y)
assert(33.0 == v3.z)

-- Equality

v1 = Vec3(-3.0, -4.0, -5.0)
v2 = Vec3(-3.0, -4.0, -5.0)
v3 = v1:new_copy()
assert(v1:eq(v1))
assert(v1:eq(v2))
assert(v2:eq(v1))
assert(v1:eq(v3))
assert(v3:eq(v1))
assert(v1:eq(-3.0, -4.0, -5.0))
assert(v1:eq({ x = -3.0, y = -4.0, z = -5.0 }))
assert(v1:eq({ -3.0, -4.0, -5.0 }))

v1 = Vec3(6.0, 17.0, 83.0)
v2 = Vec3(6.0, 17.0, 83.0)
v3 = Vec3(v1)
assert(v1 == v1)
assert(v1 == v2)
assert(v2 == v1)
assert(v1 == v3)
assert(v3 == v1)
assert(v1:eq({ x = 6.0, y = 17.0, z = 83.0 }))
assert(not (v1 ~= v1))
assert(not (v1 ~= v2))
assert(not (v2 ~= v1))
assert(not (v1 ~= v3))
assert(not (v3 ~= v1))

-- Dot Product

v1 = Vec3(2.0, 3.0, 5.0)
v2 = Vec3(7.0, 11.0, 13.0)
assert(v1:dot(v2) == 112.0)
assert(v1:dotvec(v2) == 112.0)
assert(v1:dot(v1) == v1:len_sq())
assert(v1:dot(4.0, 3.0, 2.0) == 27.0)

v1 = Vec3(1.0, 0.0, 0.0)
assert(v1:dot(0.0, 1.0, 0.0) == 0.0)
assert(v1:dot(0.0, 0.0, 1.0) == 0.0)
assert(v1:dot(0.0, 1.0, 1.0) == 0.0)

-- Cross Product

v1 = Vec3(1.0, 0.0, 0.0)
v2 = Vec3(0.0, 1.0, 0.0)
assert(v1:cross(v1):eq(Vec3()))
assert(v2:cross(v2):eq(Vec3()))
assert(v1:cross(v2):eq({ 0.0, 0.0, 1.0 }))
assert(v2:cross(v1):eq({ 0.0, 0.0, -1.0 }))
assert(v1:cross(0.0, 0.0, 1.0):eq({ 0.0, -1.0, 0.0 }))
assert(Vec3.cross(Vec3(0.0, 1.0, 0.0), { 0.0, 0.0, 1.0 }):eq({ 1.0, 0.0, 0.0 }))

v1 = Vec3(3.0, 7.0, 17.0)
v2 = Vec3(2.0, 11.0, 19.0)
assert(v1:cross(v1):eq(Vec3()))
assert(v2:cross(v2):eq(Vec3()))
assert(v1:cross(v2):eq({ -54.0, -23.0, 19.0 }))
assert(v1:crossvec(v2):eq({ -54.0, -23.0, 19.0 }))
assert(v2:cross(v1):eq({ 54.0, 23.0, -19.0 }))
assert(v2:crossvec(v1):eq({ 54.0, 23.0, -19.0 }))

-- Rotation

v1 = Vec3(1.0, 0.0, 0.0)
v2 = Vec3(0.0, 1.0, 0.0)
v3 = v1:rot_around(v2, 0.5*math.pi)
assert(v3:sub({ 0.0, 0.0, -1.0 }):len_sq() < 0.001)
v3 = v1:rot_around(v2, math.pi)
assert(v3:sub(-v1):len_sq() < 0.001)
v3 = v1:rot_around(v2, 1.5*math.pi)
assert(v3:sub({ 0.0, 0.0, 1.0 }):len_sq() < 0.001)
v3 = v1:rot_around(v2, 2.0*math.pi)
assert(v3:sub(v1):len_sq() < 0.001)

v3 = v2:rot_around(v1, 0.5*math.pi)
assert(v3:sub({ 0.0, 0.0, 1.0 }):len_sq() < 0.001)
v3 = v2:rot_around(v1, math.pi)
assert(v3:sub(-v2):len_sq() < 0.001)
v3 = v2:rot_around(v1, 1.5*math.pi)
assert(v3:sub({ 0.0, 0.0, -1.0 }):len_sq() < 0.001)
v3 = v2:rot_around(v1, 2.0*math.pi)
assert(v3:sub(v2):len_sq() < 0.001)

v1 = Vec3(1.0, 0.0, 0.0)
v2 = Vec3(0.0, 0.0, 1.0)
v3 = v1:rot_around(v2, 0.5*math.pi)
assert(v3:sub({ 0.0, 1.0, 0.0 }):len_sq() < 0.001)
v3 = v1:rot_around(v2, math.pi)
assert(v3:sub(-v1):len_sq() < 0.001)
v3 = v1:rot_around(v2, 1.5*math.pi)
assert(v3:sub({ 0.0, -1.0, 0.0 }):len_sq() < 0.001)

v1 = Vec3(1.0, 0.0, 0.0)
v2 = Vec3(1.0, 1.0, 1.0)
v3 = v1:rot_around(v2, 2.0*math.pi/3.0)
assert(v3:sub({ 0.0, 1.0, 0.0 }):len_sq() < 0.001)
v3 = v3:rot_around(v2, 2.0*math.pi/3.0)
assert(v3:sub({ 0.0, 0.0, 1.0 }):len_sq() < 0.001)
v3 = v3:rot_around(v2, 2.0*math.pi/3.0)
assert(v3:sub(v1):len_sq() < 0.001)

print("Vec3 unit test PASSED")


EDIT: Fixed to test multiplication of scalar by vector (m*v vs. v*m).
EDIT: Added some tests for rot_around(...) method to rotate around an arbitrary axis.
Last edited by prestidigitator on Sun Feb 24, 2013 03:55, edited 1 time in total.
 

User avatar
kaeza
Member
 
Posts: 2141
Joined: Thu Oct 18, 2012 05:00
GitHub: kaeza
IRC: kaeza diemartin blaaaaargh
In-game: kaeza

by kaeza » Mon Feb 25, 2013 19:15

I don't know if this would be useful for everyone, but the pixelnodebox() function in my computers mod is an easy way to define node boxes based on a texture (i.e. using pixel (more like texel) coordinates instead of [-0.5 - 0.5]).
Your signature is not the place for a blog post. Please keep it as concise as possible. Thank you!

Check out my stuff! | Donations greatly appreciated! PayPal | BTC: 1DFZAa5VtNG7Levux4oP6BuUzr1e83pJK2
 

4aiman
Member
 
Posts: 1208
Joined: Mon Jul 30, 2012 05:47

by 4aiman » Mon Feb 25, 2013 21:47

Will this be useful:
Your phone or window isn't wide enough to display the code box. If it's a phone, try rotating it to landscape mode.
Code: Select all
-- returna a table with registered users names
function get_registred_players()     
    local list = {}   
    local input = io.open(minetest.get_worldpath().."/auth.txt", "r")
    if input then           
       while true do
          local r = input:read("*l")
          if r == nil then break end
          i = string.find(r, "::")
          r = string.sub(r, 1, i-1)
          table.insert(list,r)     
       end       
       io.close(input)
    end   
    return list
end

?
 

prestidigitator
Member
 
Posts: 632
Joined: Thu Feb 21, 2013 23:54

by prestidigitator » Sat Mar 02, 2013 11:26

FYI, I've cleaned up the above Vec3 code a bit and published it as its own library. I've also created and published a library called ModLib that is solely for loading other libraries included with mods.
 

User avatar
kaeza
Member
 
Posts: 2141
Joined: Thu Oct 18, 2012 05:00
GitHub: kaeza
IRC: kaeza diemartin blaaaaargh
In-game: kaeza

by kaeza » Sat Mar 16, 2013 20:27

prestidigitator wrote:FYI, I've cleaned up the above Vec3 code a bit and published it as its own library. I've also created and published a library called ModLib that is solely for loading other libraries included with mods.

The point in creating a "common library" is that mod developers and users don't have to install/depend-on lots of mods :)
EDIT: Is this still being worked on?
Last edited by kaeza on Sat Mar 16, 2013 20:27, edited 1 time in total.
Your signature is not the place for a blog post. Please keep it as concise as possible. Thank you!

Check out my stuff! | Donations greatly appreciated! PayPal | BTC: 1DFZAa5VtNG7Levux4oP6BuUzr1e83pJK2
 

User avatar
rubenwardy
Member
 
Posts: 4500
Joined: Tue Jun 12, 2012 18:11
GitHub: rubenwardy
IRC: rubenwardy
In-game: rubenwardy

by rubenwardy » Mon Mar 18, 2013 12:48

I have not done much for a while, but it is not dead.
 


Return to WIP Mods

Who is online

Users browsing this forum: No registered users and 7 guests

cron