From 414241463db87d6f678ae6e85aa37e9b387dff59 Mon Sep 17 00:00:00 2001
From: dg <dg@51575b47-30f0-44d4-a5cc-537603b46e54>
Date: Sat, 28 Aug 2010 16:01:33 +0000
Subject: [PATCH] Changed lua table.sort() function to accept any index as a
 second parameter, if not a function it will assume the items to sort are
 tables and sort them by the given index Improved the integrated lua profiler
 (only works when luajit is disabled) Greatly improved performance when moving
 around the map. Map:checkAllEntities() is now much faster, FOV code is also
 faster

git-svn-id: http://svn.net-core.org/repos/t-engine4@1092 51575b47-30f0-44d4-a5cc-537603b46e54
---
 game/engine/Map.lua                | 22 +++++++++++++----
 game/engine/interface/ActorFOV.lua |  6 +++--
 game/modules/tome/class/NPC.lua    |  7 +++++-
 game/modules/tome/class/Player.lua | 12 +++++++---
 src/core_lua.c                     |  4 ++--
 src/lua/ltablib.c                  | 38 ++++++++++++++++++++++++++++--
 src/luajit/ltablib.c               | 17 +++++++++++--
 src/luaprofiler/core_profiler.c    | 12 +++++-----
 src/luaprofiler/lua50_profiler.c   |  8 +++----
 9 files changed, 100 insertions(+), 26 deletions(-)

diff --git a/game/engine/Map.lua b/game/engine/Map.lua
index e54abfd326..cbc26706fe 100644
--- a/game/engine/Map.lua
+++ b/game/engine/Map.lua
@@ -211,6 +211,8 @@ end
 --- Serialization
 function _M:save()
 	return class.save(self, {
+		_check_entities = true,
+		_check_entities_store = true,
 		_map = true,
 		_fovcache = true,
 		surface = true,
@@ -309,6 +311,9 @@ function _M:loaded()
 	setmetatable(self.remembers, {__call = mapremember})
 	setmetatable(self.attrs, {__call = mapattrs})
 
+	self._check_entities = {}
+	self._check_entities_store = {}
+
 	self.surface = core.display.newSurface(self.viewport.width, self.viewport.height)
 	self.changed = true
 	self.finished = true
@@ -397,6 +402,18 @@ function _M:updateMap(x, y)
 		p:getMapObjects(self.tiles, mos, 13)
 	end
 
+	-- Update entities checker for this spot
+	-- This is to improve speed, we create a function for each spot that checks entities it knows are there
+	-- This avoid a costly for iteration over a pairs() and this allows luajit to compile only code that is needed
+	local ce = {}
+	local fstr = [[p = m[%s]:check(what, x, y, ...) if p then return p end ]]
+	ce[#ce+1] = [[return function(self, x, y, what, ...) local p local m = self.map[x + y * self.w] ]]
+	for idx, e in pairs(self.map[x + y * self.w]) do ce[#ce+1] = fstr:format(idx) end
+	ce[#ce+1] = [[end]]
+	local ce = table.concat(ce)
+	self._check_entities[x + y * self.w] = self._check_entities_store[ce] or loadstring(ce)()
+	self._check_entities_store[ce] = self._check_entities[x + y * self.w]
+
 	-- Cache the map objects in the C map
 	self._map:setGrid(x, y, mm, mos)
 
@@ -562,10 +579,7 @@ end
 function _M:checkAllEntities(x, y, what, ...)
 	if x < 0 or x >= self.w or y < 0 or y >= self.h then return end
 	if self.map[x + y * self.w] then
-		for _, e in pairs(self.map[x + y * self.w]) do
-			local p = e:check(what, x, y, ...)
-			if p then return p end
-		end
+		return self._check_entities[x + y * self.w](self, x, y, what, ...)
 	end
 end
 
diff --git a/game/engine/interface/ActorFOV.lua b/game/engine/interface/ActorFOV.lua
index 5ff5f7f116..d26bf033b0 100644
--- a/game/engine/interface/ActorFOV.lua
+++ b/game/engine/interface/ActorFOV.lua
@@ -80,14 +80,16 @@ function _M:computeFOV(radius, block, apply, force, no_store, cache)
 				local t = {x=x,y=y, dx=dx, dy=dy, sqdist=sqdist}
 				fov.actors[a] = t
 				fov.actors_dist[#fov.actors_dist+1] = a
+				a.__sqdist = sqdist
 				a:check("seen_by", self)
 				a:updateFOV(self, t.sqdist)
 			end
 		end, cache and game.level.map._fovcache[block])
 
 		-- Sort actors by distance (squared but we do not care)
-		table.sort(fov.actors_dist, function(a, b) return fov.actors[a].sqdist < fov.actors[b].sqdist end)
-		for i = 1, #fov.actors_dist do fov.actors_dist[i].i = i end
+		table.sort(fov.actors_dist, "__sqdist")
+--		table.sort(fov.actors_dist, function(a, b) return a.__sqdist < b.__sqdist end)
+--		for i = 1, #fov.actors_dist do fov.actors_dist[i].i = i end
 --		print("Computed FOV for", self.uid, self.name, ":: seen ", #fov.actors_dist, "actors closeby")
 
 		self.fov = fov
diff --git a/game/modules/tome/class/NPC.lua b/game/modules/tome/class/NPC.lua
index c87b1c97f6..71a4cdc4df 100644
--- a/game/modules/tome/class/NPC.lua
+++ b/game/modules/tome/class/NPC.lua
@@ -39,7 +39,12 @@ function _M:act()
 --	print("lite", self.name, self.lite)
 --		self:computeFOV(self.lite, "block_sight", function(x, y, dx, dy, sqdist) game.level.map:applyLite(x, y) end, true, true)
 --	end
-	self:computeFOV(self.sight or 20)
+	-- If the actor has no special vision we can use the default cache
+	if not self.special_vision then
+		self:computeFOV(self.sight or 20, "block_sight", nil, nil, nil, true)
+	else
+		self:computeFOV(self.sight or 20, "block_sight")
+	end
 
 	-- Let the AI think .... beware of Shub !
 	-- If AI did nothing, use energy anyway
diff --git a/game/modules/tome/class/Player.lua b/game/modules/tome/class/Player.lua
index 4b21b744d4..90daf0455d 100644
--- a/game/modules/tome/class/Player.lua
+++ b/game/modules/tome/class/Player.lua
@@ -182,22 +182,28 @@ function _M:act()
 	end
 end
 
+-- Precompute FOV form
+local fovdist = {}
+for i = 0, 30 * 30 do
+	fovdist[i] = math.max((20 - math.sqrt(i)) / 14, 0.6)
+end
+
 function _M:playerFOV()
 	-- Clean FOV before computing it
 	game.level.map:cleanFOV()
 	-- Compute ESP FOV, using cache
-	if not game.zone.wilderness then self:computeFOV(self.esp.range or 10, "block_esp", function(x, y) game.level.map:applyESP(x, y) end, true, true) end
+	if not game.zone.wilderness then self:computeFOV(self.esp.range or 10, "block_esp", function(x, y) game.level.map:applyESP(x, y) end, true, true, true) end
 
 	if not self:attr("blind") then
 		-- Compute both the normal and the lite FOV, using cache
 		if game.zone.wilderness_see_radius then
 			self:computeFOV(self.sight or 20, "block_sight", function(x, y, dx, dy, sqdist)
-				game.level.map:apply(x, y, math.max((20 - math.sqrt(sqdist)) / 14, 0.6))
+					game.level.map:apply(x, y, fovdist[sqdist])
 			end, true, false, true)
 			self:computeFOV(game.zone.wilderness_see_radius, "block_sight", function(x, y, dx, dy, sqdist) game.level.map:applyLite(x, y) end, true, true, true)
 		else
 			self:computeFOV(self.sight or 20, "block_sight", function(x, y, dx, dy, sqdist)
-				game.level.map:apply(x, y, math.max((20 - math.sqrt(sqdist)) / 14, 0.6))
+				game.level.map:apply(x, y, fovdist[sqdist])
 			end, true, false, true)
 			if self.lite <= 0 then game.level.map:applyLite(self.x, self.y)
 			else self:computeFOV(self.lite, "block_sight", function(x, y, dx, dy, sqdist) game.level.map:applyLite(x, y) end, true, true, true) end
diff --git a/src/core_lua.c b/src/core_lua.c
index 0fbc691dd1..1920d62686 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -170,14 +170,14 @@ static int lua_fov_calc_circle(lua_State *L)
 	}
 	fov.apply_ref = luaL_ref(L, LUA_REGISTRYINDEX);
 	fov.opaque_ref = luaL_ref(L, LUA_REGISTRYINDEX);
-//	int i= SDL_GetTicks();
+
 	fov_settings_init(&(fov.fov_settings));
 	fov_settings_set_opacity_test_function(&(fov.fov_settings), map_opaque);
 	fov_settings_set_apply_lighting_function(&(fov.fov_settings), map_seen);
 	fov_circle(&(fov.fov_settings), &fov, NULL, x, y, radius+1);
 	map_seen(&fov, x, y, 0, 0, radius, NULL);
 	fov_settings_free(&(fov.fov_settings));
-//	printf("map display ticks %d\n",SDL_GetTicks()-i);
+
 	luaL_unref(L, LUA_REGISTRYINDEX, fov.apply_ref);
 	luaL_unref(L, LUA_REGISTRYINDEX, fov.opaque_ref);
 	if (fov.cache_ref != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, fov.cache_ref);
diff --git a/src/lua/ltablib.c b/src/lua/ltablib.c
index b6d9cb4ac7..61e88922dd 100644
--- a/src/lua/ltablib.c
+++ b/src/lua/ltablib.c
@@ -169,6 +169,27 @@ static int tconcat (lua_State *L) {
 **  Addison-Wesley, 1993.)
 */
 
+static void stackDump (lua_State *L) {
+	int i=lua_gettop(L);
+	printf(" ----------------  Stack Dump ----------------\n" );
+	while(  i   ) {
+		int t = lua_type(L, i);
+		switch (t) {
+		case LUA_TSTRING:
+			printf("%d:`%s'\n", i, lua_tostring(L, i));
+			break;
+		case LUA_TBOOLEAN:
+			printf("%d: %s\n",i,lua_toboolean(L, i) ? "true" : "false");
+			break;
+		case LUA_TNUMBER:
+			printf("%d: %g\n",  i, lua_tonumber(L, i));
+			break;
+		default: printf("%d: %s\n", i, lua_typename(L, t)); break;
+		}
+		i--;
+	}
+	printf("--------------- Stack Dump Finished ---------------\n" );
+}
 
 static void set2 (lua_State *L, int i, int j) {
   lua_rawseti(L, 1, i);
@@ -176,7 +197,7 @@ static void set2 (lua_State *L, int i, int j) {
 }
 
 static int sort_comp (lua_State *L, int a, int b) {
-  if (!lua_isnil(L, 2)) {  /* function? */
+  if (lua_isfunction(L, 2)) {  /* function? */
     int res;
     lua_pushvalue(L, 2);
     lua_pushvalue(L, a-1);  /* -1 to compensate function */
@@ -186,6 +207,17 @@ static int sort_comp (lua_State *L, int a, int b) {
     lua_pop(L, 1);
     return res;
   }
+  else if (!lua_isnil(L, 2)) {  /* index? */
+    int res;
+    lua_pushvalue(L, 2);
+    lua_gettable(L, a-1);
+
+    lua_pushvalue(L, 2);
+    lua_gettable(L, b-2);
+    res = lua_lessthan(L, -2, -1);
+    lua_pop(L, 2);
+    return res;
+  }
   else  /* a < b? */
     return lua_lessthan(L, a, b);
 }
@@ -257,7 +289,9 @@ static int sort (lua_State *L) {
   int n = aux_getn(L, 1);
   luaL_checkstack(L, 40, "");  /* assume array is smaller than 2^40 */
   if (!lua_isnoneornil(L, 2))  /* is there a 2nd argument? */
-    luaL_checktype(L, 2, LUA_TFUNCTION);
+  {
+//    if (luaL_checktype(L, 2, LUA_TFUNCTION);
+  }
   lua_settop(L, 2);  /* make sure there is two arguments */
   auxsort(L, 1, n);
   return 0;
diff --git a/src/luajit/ltablib.c b/src/luajit/ltablib.c
index b6d9cb4ac7..e6bdb90fa1 100644
--- a/src/luajit/ltablib.c
+++ b/src/luajit/ltablib.c
@@ -176,7 +176,7 @@ static void set2 (lua_State *L, int i, int j) {
 }
 
 static int sort_comp (lua_State *L, int a, int b) {
-  if (!lua_isnil(L, 2)) {  /* function? */
+  if (lua_isfunction(L, 2)) {  /* function? */
     int res;
     lua_pushvalue(L, 2);
     lua_pushvalue(L, a-1);  /* -1 to compensate function */
@@ -186,6 +186,17 @@ static int sort_comp (lua_State *L, int a, int b) {
     lua_pop(L, 1);
     return res;
   }
+  else if (!lua_isnil(L, 2)) {  /* index? */
+    int res;
+    lua_pushvalue(L, 2);
+    lua_gettable(L, a-1);
+
+    lua_pushvalue(L, 2);
+    lua_gettable(L, b-2);
+    res = lua_lessthan(L, -2, -1);
+    lua_pop(L, 2);
+    return res;
+  }
   else  /* a < b? */
     return lua_lessthan(L, a, b);
 }
@@ -257,7 +268,9 @@ static int sort (lua_State *L) {
   int n = aux_getn(L, 1);
   luaL_checkstack(L, 40, "");  /* assume array is smaller than 2^40 */
   if (!lua_isnoneornil(L, 2))  /* is there a 2nd argument? */
-    luaL_checktype(L, 2, LUA_TFUNCTION);
+  {
+//    if (luaL_checktype(L, 2, LUA_TFUNCTION);
+  }
   lua_settop(L, 2);  /* make sure there is two arguments */
   auxsort(L, 1, n);
   return 0;
diff --git a/src/luaprofiler/core_profiler.c b/src/luaprofiler/core_profiler.c
index 0f70fba106..0e15072040 100644
--- a/src/luaprofiler/core_profiler.c
+++ b/src/luaprofiler/core_profiler.c
@@ -79,7 +79,7 @@ static void formats(char *s) {
 
 
 /* computes new stack and new timer */
-void lprofP_callhookIN(lprofP_STATE* S, char *func_name, char *file, int linedefined, int currentline) {	
+void lprofP_callhookIN(lprofP_STATE* S, char *func_name, char *file, int linedefined, int currentline) {
   S->stack_level++;
   lprofM_enter_function(S, file, func_name, linedefined, currentline);
 }
@@ -103,8 +103,8 @@ int lprofP_callhookOUT(lprofP_STATE* S) {
   info->total_time += function_call_time;
   formats(info->file_defined);
   formats(info->function_name);
-  output("%d\t%s\t%s\t%d\t%d\t%f\t%f\n", S->stack_level, info->file_defined,
-	 info->function_name, 
+  output("%d\t%s\t%s:%d:%s\t%d\t%d\t%f\t%f\n", S->stack_level, info->file_defined,
+	 info->function_name, info->line_defined, info->file_defined,
 	 info->line_defined, info->current_line,
 	 info->local_time, info->total_time);
   /* ... now it's ok to resume the timer */
@@ -128,7 +128,7 @@ lprofP_STATE* lprofP_init_core_profiler(const char *_out_filename, int isto_prin
 
   function_call_time = _function_call_time;
   out_filename = (_out_filename) ? (_out_filename):(OUT_FILENAME);
-        
+
   /* the random string to build the logname is extracted */
   /* from 'tmpnam()' (the '/tmp/' part is deleted)     */
   randstr = tmpnam(NULL);
@@ -155,7 +155,7 @@ lprofP_STATE* lprofP_init_core_profiler(const char *_out_filename, int isto_prin
     fclose(outf);
     return 0;
   }
-    
+
   return S;
 }
 
@@ -174,7 +174,7 @@ lprofP_STATE* lprofP_create_profiler(float _function_call_time) {
   if(!S) {
     return 0;
   }
-    
+
   return S;
 }
 
diff --git a/src/luaprofiler/lua50_profiler.c b/src/luaprofiler/lua50_profiler.c
index 54533425c3..0a0a3dde17 100644
--- a/src/luaprofiler/lua50_profiler.c
+++ b/src/luaprofiler/lua50_profiler.c
@@ -42,7 +42,7 @@ static void callhook(lua_State *L, lua_Debug *ar) {
     lua_getinfo(L, "l", &previous_ar);
     currentline = previous_ar.currentline;
   }
-      
+
   lua_getinfo(L, "nS", ar);
 
   if (!ar->event) {
@@ -90,7 +90,7 @@ static int coroutine_create(lua_State *L) {
   lua_pushlightuserdata(L, S);
   lua_settable(L, LUA_REGISTRYINDEX);
   lua_sethook(NL, (lua_Hook)callhook, LUA_MASKCALL | LUA_MASKRET, 0);
-  return 1;	
+  return 1;
 }
 #endif
 
@@ -134,7 +134,7 @@ static int profiler_init(lua_State *L) {
   lua_pushlightuserdata(L, &profstate_id);
   lua_pushlightuserdata(L, S);
   lua_settable(L, LUA_REGISTRYINDEX);
-	
+
   /* use our own exit function instead */
   lua_getglobal(L, "os");
   lua_pushlightuserdata(L, &exit_id);
@@ -158,7 +158,7 @@ static int profiler_init(lua_State *L) {
   /* as a library.                                                     */
 
   lprofP_callhookIN(S, "profiler_init", "(C)", -1, -1);
-	
+
   lua_pushboolean(L, 1);
   return 1;
 }
-- 
GitLab