Lua

Context aware Lua Macros

February 18th, 2010 0 Comments

Will automatically detect locals as well as global variables.

Usage: Macro “text ${Lua Code} more text”

local _mtg = getmetatable(_G) or {}
function _mtg.__index(self, k)
	return rawget(self,k.."___macro")
end
setmetatable(_G,_mtg)

function string.escape(text)
	local str = ""
	for i=1, #text do
		local chr = text:sub(i,i)
		local escape = ""
		if isIn(chr, {"(", ")"}) then escape = "%" end
		str = str .. escape..chr
	end
	return str
end

function isIn(obj, table)
	for _,v in ipairs(table) do
		if obj == v then return true end
	end
end

function get_locals(func)
     local n = 1
     local locals = {}
     func = (type(func) == "number") and func + 1 or func
     while true do
          local lname, lvalue = debug.getlocal(func, n)
          if lname == nil then break end
          if lvalue == nil then lvalue = mynil end
          locals[lname] = lvalue
          n = n + 1
     end
     return locals
end

Macro = setmetatable({}, {__call=function(self, ...) return self:init(...) end})
function Macro:init(...)
	--We want to retain processing capability even after declaration
	local args = {...}
	local __string = ""
	for _,obj in ipairs(args) do
		__string = __string .. tostring(obj)
	end
	local members = {
		__string = __string,
		type="Macro"
	}
	local methods = {
		__tostring__ = function(self, n)
			--Actual Processing Logic goes here
			local str = self.__string
			local match = "${.-[^\\]}"
			--Check if str has ${statement}
			local indices = {str:find(match)}
			while #indices > 0 do
				local sub = str:sub(indices[1]+2, indices[2]-1)
				local repl = str:sub(unpack(indices))
				local final = ""
				local locals = get_locals(3+n)
				for k,_ in pairs(locals) do
					rawset(_G,k.."___macro",_)
				end
				--Evaluate
				local _fn, e = loadstring(sub)
				if not _fn then
					_fn, e = loadstring("return "..sub)
				end
				if not _fn then
					final = " "..e.." "
				else
					final = tostring(_fn() or " ")
				end
				for k,_ in pairs(locals) do
					rawset(_G,k.."___macro",nil)
				end
				str = str:gsub(repl:escape(), final)
				indices = {str:find(match)}
			end
			return str
		end,
		__tostring = function(self)
			return getmetatable(self).__tostring__(self, 2)
		end,
		__call = function(self)
			return getmetatable(self).__tostring__(self, 0)
		end
	}
	return setmetatable(members, methods)
end

test = Macro "Hello ${jack} ${'Bauer'}"

function test1()
	local jack = "Jack"
	print(test)
end

test1()

function test2()
	local jack = "No One"
	print(test)
end

test2()

function test3()
	local test = Macro "Hello ${world}"
	local world = "World"
	print(test())
end

test3()

function test4()
	local test = Macro "Hello ${print('asdf'); return 'World'}"
	local world = "World"
	print(test)
end

test4()

Lua Tutorials -> Luatut.com

February 1st, 2010 0 Comments

A new set of Lua Tutorials are coming out.

Lua Tutorial

http://luatut.com/

[Lua] MapParser (High Level API)

October 25th, 2009 0 Comments

This is a Map parser library for CS2D's lua engine. Benchmarked to process 6,000 tiles per second. (A 2,000% improvement over the older parser). This also demonstrates that it is possible to have object-orientation within a lua script and to work with CTypes.

Code/Download:
http://pastebin.com/f33323412
MapParser
Future implementations will also add caching.

API:

Map:new(mapfile)
Creates a new instance of the Map object
IE: map = Map:new("maps/de_dust.map")

Map:invert(table)
Inverts the x and the y of a given table (must be in matrix form)
IE: dumpable = map:invert(map.tiles)

Map:dumpMeta()
Creates a dump of all of the meta-information stored in a map
IE: map:dumpMeta()
Output:
[Table:(Anonymous)]
code = 8100x79$123225%4595857
loadtime = 1.77
header = Unreal Software's Counter-Strike 2D Map File (max)
...

Map:mapogram()
Prints out a graphical display of the collision gradients
IE: map:mapogram() -- See above for output

Map.tiles[x][y]
A table of tile data, accessed through map.tiles[x][y]
IE: tile_3_4 = map.tiles[3][4] -- stores the tile at 3,4 into tile_3_4

Map.modes[x][y]
A table of the tile modes, accessed through map.modes[x][y], note here that modes will tell you whether a tile is a wall or not
IE: mode_20_32 = map.modes[20][32]

Map.entities[id]
A table of the individual entities, accessed through map.entities[id]
IE: entity_3 = map.entities[3]

Map.collisions[x][y]
A table of walls and obstacles. 0 if not an obstacle, 1 through 4 if it is.
IE: map.collisions[7][8]

Map.gradient, Map.antigradient - use ipairs
Table of collisions and non-collisions that can be iterated via ipairs(), stored in {x, y, mode} format
IE: for _i, coordinate in ipairs(map.gradient) do blahblah() end

Example implementation of http://unrealsoftware.de/lab_cat.php?ca ... =#entry499

dofile(core_dir.."map.lua")
current_map = Map:new("maps/"..map("name")..".map")

function tile(x,y,prop)
     local args = {}

     args.entity = current_map.entities [x] [y]
     args.tile = current_map.tiles[x] [y]
     args.mode= current_map.modes[x] [y]
     args.collision= current_map.collisions[x] [y]

     if args.collision == 0 then args.collision = false end

     if prop then
               if args[prop] then return args[prop] end
     end

     return args
end

if tile(12,30,"collision") then
     --Custom Code Here.
end

Notices
Requires the struct.lua, string.lua, and table.lua libraries. (Look inside amx2d/core)

Overcomplicated Hello World example in Lua

July 14th, 2009 0 Comments

As we all know, writing a hello world script in Lua consists of no more and no less then the simple use of print(“Hello World!”). However, given the simplicity of such a task, I set out to create something much much more complicated then one would ever care for. Introducing – Hello World in Lua implementing C-Types, Basic Encryption, and Dynamic Loading. Basically, we’re trying to go from

HelloWorld = [[
`}„„‡o‡Š„|[‘ˆ€}Š8U8:HOKIHKIIIIIJIINHKPHQLIIQIJKIIPIIIHLM:"ˆŠ†Œ@:[qh`]jc]q8`}„„‡o‡Š„|[‘ˆ€}Š8U8:FF`}„„‡o‡Š„|[‘ˆ€}ŠA]]

back to

“Hello World!”

How are we going to do this? Simply with the Overly Complicated Hello World demo

Below are the full enc and h string which is where we start off with the encryption process

--ENC: Contains the algorithm for decoding the h string
enc = [[
hwpevkqp"gpet{rvkqp0vqgpe*hkng+nqecn"p"?"%hkng=nqecn"z"?"$$=nqecn"t"?"3=hqt"k"?"3."p."3"fqkh"t"@"72"vjgp"t"?"3"gpfz"?"z00fkikvu*TgcfD{vg*hkng+-t."5+=t"?"t"-"3=gpftgvwtp"z."tgpfhwpevkqp"gpet{rvkqp0vqfge*hkng+nqecn"p"?"%hkng=nqecn"z"?"$$=nqecn"t"?"3=hqt"k"?"3."p15."3"fqkh"t"@"72"vjgp"t"?"3"gpfnqecn"u"?"TgcfUvtkpi*hkng."5+=z"?"z00YtkvgD{vg*vqpwodgt*u+/t+=t"?"t"-"3=gpftgvwtp"z."tgpf]]

--H: Contains the bits needed to actually output "Hello World!"

h = [[
`}„„‡o‡Š„|[‘ˆ€}Š8U8:HOKIHKIIIIIJIINHKPHQLIIQIJKIIPIIIHLM:"ˆŠ†Œ@:[qh`]jc]q8`}„„‡o‡Š„|[‘ˆ€}Š8U8:FF`}„„‡o‡Š„|[‘ˆ€}ŠA]]

Wordfilter in Lua

June 23rd, 2009 0 Comments

I’ve been getting bored lately so I’ve decided to create a wordfilter in Lua, it’s really basic actually, but useful. The concept goes something like this. You take a list of naughty words, and filter them out of the text. :D

This filter goes out a bit more advanced then that however. It’s punctuation aware and have a few wildcard filter rules. For example, say we want to filter the word boo out of the text, we have several distinct filter rules that we can use.

Here’s the texts to be filtered.
“boo… text”
“oboo… text”
“booo… text”
“obooo… text”

Rule 1:
Filter:”boo” => Will only return true if the word boo is found in the text.
Result:

  1. “boo… text” – True
  2. “oboo… text” – False
  3. “booo… text” – False
  4. “obooo… text” – False

Rule 2:
Filter:”*boo” => Will only return true if the substring boo is found at the end of a word in the text.
Result:

  1. “boo… text” – True
  2. “oboo… text” – True
  3. “booo… text” – False
  4. “obooo… text” – False

Rule 3:
Filter:”boo*” => Will only return true if the substring boo is found at the begining of a word in the text.
Result:

  1. “boo… text” – True
  2. “oboo… text” – False
  3. “booo… text” – True
  4. “obooo… text” – False

Rule 4:
Filter:”*boo*” => Will only return true if the substring boo is found anywhere in the text.
Result:

  1. “boo… text” – True
  2. “oboo… text” – True
  3. “booo… text” – True
  4. “obooo… text” – True

Usage:

  1. Add the filter rules in the badwords.txt file, remember to close each rule with a comma
  2. Put dofile(“filter.lua”) in your file, remember to put filter.lua, string.lua, table.lua, and badwords.txt in the same directory.
  3. Use filter(Text) as the filter function, it will return either true or false. If it returns true, then the filter will have detected naughty words in the text

Download: http://6.dot.ch/filter.zip

if not string.trim then dofile("string.lua") end
if not table.find then dofile("table.lua") end

puns = {"'",
		"\"",
		",",
		".",
		"/",
		";",
		":",
		"?",
		"!",
		"*"}
wildcard = "*"
wordfile = "badwords.txt"

wopen = io.open(wordfile)

wordlist = table.trim(string.split((wopen:read("*a")), ","))

wopen:close()

function string.trimpun(t)
	local letters = t:letters()
	local first = letters[1]
	local last = letters[#letters]
	while (first:inside(puns)) do
		t = t:sub(2)
		first = t:sub(1, 1)
	end
	while (last:inside(puns)) do
		t = t:sub(1, #t-1)
		last = t:sub(#t, #t)
	end

	return t
end

function string.getwordfrom(t, i)
	--Rule: space
	t = t:split()
	local n = 0
	local s = 1
	while n < i do
		n = n + #t[s] + 1

		s = s+1
	end
	return (t[s-1]:trim():trimpun())
end

function table.overlap(t1, t2)
	local common = {}
	for k, v in pairs(t1) do
		if table.find(t2, v) then table.insert(common, v) end
	end
	if #common == 0 then return false end
	return common
end

function filter(text, words)
	if not words then words = wordlist end
	local match = ""..wildcard..""
	_text = text:split()
	for i,w in ipairs(_text) do
		_text[i] = w:trimpun()
	end
	if table.overlap(_text, words) then return true end
	for i,word in ipairs(words) do
		if word:find(match) then
			local index = word:index(match)
			word = word:translate(wildcard)
			if text:find(word) then
				--Wildcard Syntax.
				--Both - Anywhere in text
				if #index >= 2 then return true end
				--End - Only at the begining of a WORD
				if index[1] > 1 then
					local i = text:index(word)
					for k, v in ipairs(i) do
						local w = text:getwordfrom(v)
						if w:sub(1, #word) == word then return true end
					end
				end
				--Begining - Only at the end of a WORD
				if index[1] == 1 then
					local i = text:index(word)
					for k, v in ipairs(i) do
						local w = text:getwordfrom(v)
						if w:sub(#w-#word+1, #w) == word then return true end
					end
				end
			end
		end
	end

	return false
end