aboutsummaryrefslogtreecommitdiff
path: root/src/script.cpp
blob: 1925ea701554ffdcc0f5ed86fc2de8ad2af3d767 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
Minetest-c55
Copyright (C) 2011 celeron55, Perttu Ahola <celeron55@gmail.com>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "script.h"
#include <cstdarg>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include "log.h"
#include <iostream>

extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}

LuaError::LuaError(lua_State *L, const std::string &s)
{
	m_s = "LuaError: ";
	m_s += s + "\n";
	m_s += script_get_backtrace(L);
}

std::string script_get_backtrace(lua_State *L)
{
	std::string s;
	lua_getfield(L, LUA_GLOBALSINDEX, "debug");
	if(lua_istable(L, -1)){
		lua_getfield(L, -1, "traceback");
		if(lua_isfunction(L, -1)){
			lua_call(L, 0, 1);
			if(lua_isstring(L, -1)){
				s += lua_tostring(L, -1);
			}
			lua_pop(L, 1);
		}
		else{
			lua_pop(L, 1);
		}
	}
	lua_pop(L, 1);
	return s;
}

void script_error(lua_State *L, const char *fmt, ...)
{
	va_list argp;
	va_start(argp, fmt);
	char buf[10000];
	vsnprintf(buf, 10000, fmt, argp);
	va_end(argp);
	//errorstream<<"SCRIPT ERROR: "<<buf;
	throw LuaError(L, buf);
}

int luaErrorHandler(lua_State *L) {
	lua_getfield(L, LUA_GLOBALSINDEX, "debug");
	if (!lua_istable(L, -1)) {
		lua_pop(L, 1);
		return 1;
	}
	lua_getfield(L, -1, "traceback");
	if (!lua_isfunction(L, -1)) {
		lua_pop(L, 2);
		return 1;
	}
	lua_pushvalue(L, 1);
	lua_pushinteger(L, 2);
	lua_call(L, 2, 1);
	return 1;
}

bool script_load(lua_State *L, const char *path)
{
	verbosestream<<"Loading and running script from "<<path<<std::endl;

	lua_pushcfunction(L, luaErrorHandler);
	int errorhandler = lua_gettop(L);

	int ret = luaL_loadfile(L, path) || lua_pcall(L, 0, 0, errorhandler);
	if(ret){
		errorstream<<"Failed to load and run script from "<<path<<":"<<std::endl;
		errorstream<<"[LUA] "<<std::endl;
		errorstream<<"[LUA] "<<lua_tostring(L, -1)<<std::endl;
		errorstream<<"[LUA] "<<std::endl;
		lua_pop(L, 1); // Pop error message from stack
		lua_pop(L, 1); // Pop the error handler from stack
		return false;
	}
	lua_pop(L, 1); // Pop the error handler from stack
	return true;
}

lua_State* script_init()
{
	lua_State *L = luaL_newstate();
	luaL_openlibs(L);
	return L;
}

void script_deinit(lua_State *L)
{
	lua_close(L);
}


, drives_on)--in order prev,mid,return local mid=advtrains.round_vector_floor_y(midreal) local midnode_ok, middir1, middir2, midrely1, midrely2=advtrains.get_rail_info_at(mid, drives_on) if not midnode_ok then return nil end local next, chkdir, chkrely, y_offset y_offset=0 --atprint(" in order mid1,mid2",middir1,middir2) --try if it is dir1 local cor1=advtrains.dirCoordSet(mid, middir2)--<<<< if cor1.x==prev.x and cor1.z==prev.z then--this was previous next=advtrains.dirCoordSet(mid, middir1) if midrely1>=1 then next.y=next.y+1 --atprint("found midrely1 to be >=1: next is now "..(next and minetest.pos_to_string(next) or "nil")) y_offset=1 end chkdir=middir1 chkrely=midrely1 --atprint("dir2 applied next pos:",minetest.pos_to_string(next),"(chkdir is ",chkdir,")") end --dir2??? local cor2=advtrains.dirCoordSet(mid, middir1)--<<<< if math.floor(cor2.x+0.5)==math.floor(prev.x+0.5) and math.floor(cor2.z+0.5)==math.floor(prev.z+0.5) then next=advtrains.dirCoordSet(mid, middir2)--dir2 wird überprüft, alles gut. if midrely2>=1 then next.y=next.y+1 --atprint("found midrely2 to be >=1: next is now "..(next and minetest.pos_to_string(next) or "nil")) y_offset=1 end chkdir=middir2 chkrely=midrely2 --atprint(" dir2 applied next pos:",minetest.pos_to_string(next),"(chkdir is ",chkdir,")") end --atprint("dir applied next pos: "..(next and minetest.pos_to_string(next) or "nil").."(chkdir is "..(chkdir or "nil")..", y-offset "..y_offset..")") --is there a next if not next then --atprint("in conway: no next rail(nil), returning!") return nil end local nextnode_ok, nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(next), drives_on) --is it a rail? if(not nextnode_ok) then --atprint("in conway: next "..minetest.pos_to_string(next).." not a rail, trying one node below!") next.y=next.y-1 y_offset=y_offset-1 nextnode_ok, nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(next), drives_on) if(not nextnode_ok) then --atprint("in conway: one below "..minetest.pos_to_string(next).." is not a rail either, returning!") return nil end end --is this next rail connecting to the mid? if not ( (((nextdir1+8)%16)==chkdir and nextrely1==chkrely-y_offset) or (((nextdir2+8)%16)==chkdir and nextrely2==chkrely-y_offset) ) then --atprint("in conway: next "..minetest.pos_to_string(next).." not connecting, trying one node below!") next.y=next.y-1 y_offset=y_offset-1 nextnode_ok, nextdir1, nextdir2, nextrely1, nextrely2, nextrailheight=advtrains.get_rail_info_at(advtrains.round_vector_floor_y(next), drives_on) if(not nextnode_ok) then --atprint("in conway: (at connecting if check again) one below "..minetest.pos_to_string(next).." is not a rail either, returning!") return nil end if not ( (((nextdir1+8)%16)==chkdir and nextrely1==chkrely) or (((nextdir2+8)%16)==chkdir and nextrely2==chkrely) ) then --atprint("in conway: one below "..minetest.pos_to_string(next).." rail not connecting, returning!") --atprint(" in order mid1,2,next1,2,chkdir "..middir1.." "..middir2.." "..nextdir1.." "..nextdir2.." "..chkdir) return nil end end --atprint("conway found rail.") return vector.add(advtrains.round_vector_floor_y(next), {x=0, y=nextrailheight, z=0}), chkdir end --TODO use this function advtrains.oppd(dir) return ((dir+8)%16) end function advtrains.round_vector_floor_y(vec) return {x=math.floor(vec.x+0.5), y=math.floor(vec.y), z=math.floor(vec.z+0.5)} end function advtrains.yawToDirection(yaw, conn1, conn2) if not conn1 or not conn2 then error("given nil to yawToDirection: conn1="..(conn1 or "nil").." conn2="..(conn1 or "nil")) end local yaw1=math.pi*(conn1/4) local yaw2=math.pi*(conn2/4) if advtrains.minAngleDiffRad(yaw, yaw1)<advtrains.minAngleDiffRad(yaw, yaw2) then--change to > if weird behavior return conn2 else return conn1 end end function advtrains.minAngleDiffRad(r1, r2) local try1=r2-r1 local try2=(r2+2*math.pi)-r1 local try3=r2-(r1+2*math.pi) if math.min(math.abs(try1), math.abs(try2), math.abs(try3))==math.abs(try1) then return try1 end if math.min(math.abs(try1), math.abs(try2), math.abs(try3))==math.abs(try2) then return try2 end if math.min(math.abs(try1), math.abs(try2), math.abs(try3))==math.abs(try3) then return try3 end end function advtrains.dumppath(path) if not path then atprint("dumppath: no path(nil)") return end local min=advtrains.minN(path) local max=advtrains.maxN(path) for i=min, max do atprint("["..i.."] "..(path[i] and minetest.pos_to_string(path[i]) or "nil")) end end function advtrains.merge_tables(a, ...) local new={} for _,t in ipairs({a,...}) do for k,v in pairs(t) do new[k]=v end end return new end function advtrains.yaw_from_3_positions(prev, curr, next) local pts=minetest.pos_to_string --atprint("p3 "..pts(prev)..pts(curr)..pts(next)) local prev2curr=math.atan2((curr.x-prev.x), (prev.z-curr.z)) local curr2next=math.atan2((next.x-curr.x), (curr.z-next.z)) --atprint("y3 "..(prev2curr*360/(2*math.pi)).." "..(curr2next*360/(2*math.pi))) return prev2curr+(advtrains.minAngleDiffRad(prev2curr, curr2next)/2) end function advtrains.get_wagon_yaw(front, first, second, back, pct) local pts=minetest.pos_to_string --atprint("p "..pts(front)..pts(first)..pts(second)..pts(back)) local y2=advtrains.yaw_from_3_positions(second, first, front) local y1=advtrains.yaw_from_3_positions(back, second, first) --atprint("y "..(y1*360/(2*math.pi)).." "..(y2*360/(2*math.pi))) return y1+advtrains.minAngleDiffRad(y1, y2)*pct end function advtrains.get_real_index_position(path, index) if not path or not index then return end local first_pos=path[math.floor(index)] local second_pos=path[math.floor(index)+1] if not first_pos or not second_pos then return nil end local factor=index-math.floor(index) local actual_pos={x=first_pos.x-(first_pos.x-second_pos.x)*factor, y=first_pos.y-(first_pos.y-second_pos.y)*factor, z=first_pos.z-(first_pos.z-second_pos.z)*factor,} return actual_pos end function advtrains.pos_median(pos1, pos2) return {x=pos1.x-(pos1.x-pos2.x)*0.5, y=pos1.y-(pos1.y-pos2.y)*0.5, z=pos1.z-(pos1.z-pos2.z)*0.5} end function advtrains.abs_ceil(i) return math.ceil(math.abs(i))*math.sign(i) end function advtrains.serialize_inventory(inv) local ser={} local liszts=inv:get_lists() for lisztname, liszt in pairs(liszts) do ser[lisztname]={} for idx, item in ipairs(liszt) do local istring=item:to_string() if istring~="" then ser[lisztname][idx]=istring end end end return minetest.serialize(ser) end function advtrains.deserialize_inventory(sers, inv) local ser=minetest.deserialize(sers) if ser then inv:set_lists(ser) return true end return false end --is_protected wrapper that checks for protection_bypass privilege function advtrains.is_protected(pos, name) if not name then error("advtrains.is_protected() called without name parameter!") end if minetest.check_player_privs(name, {protection_bypass=true}) then --player can bypass protection return false end return minetest.is_protected(pos, name) end