ProjectsWhat's NewDownloadsCommunitySupportCompany
Forum Index » S.T.A.L.K.E.R.: Clear Sky Forum » Mod discussion
Modified LuaJIT library

« Previous 10 events | 1 2 3 4 5 6 | Next 10 events »| All Messages
Posted by/on
Question/AnswerMake Newest Up Sort by Descending
  08:50:30  17 February 2014
profilee-mailreply Message URLTo the Top
Xetrill
(Senior)
 
On forum: 07/08/2008
 

Message edited by:
Xetrill
02/18/2014 21:23:21
Messages: 129

---QUOTATION---
Thank you, Xetrill. Your work is appreciated by many.
---END QUOTATION---


There are literally dozens of us!

Uhm, I forgot to copy the updated test cases, so new link (http://bit.ly/1oNN4K6).
No actual code changes, just forget to update a file that some modders might be interested in which shows how to use the new APIs.
  01:51:40  22 February 2014
profilee-mailreply Message URLTo the Top
Alundaio
Sad Clown
(Resident)

 

 
On forum: 04/05/2010
 

Message edited by:
Alundaio
02/22/2014 4:31:09
Messages: 2230
I found an error in your xs_utils.script:

function toEnumTable(...)
	local l = select('#', ...)
	local table = {}
	for i = 1, l do
		table[v] = i
	end
	return toReadOnlyTable(table)
end



'v' will be nil
I fix this for my self, but I thought I would point it out. Really some useful utility functions here, thanks.



Also I had an issue with error reporting when using the latest LuaJIT dll in Call of Pripyat. Here is the specific error I had:


ForbiddenNPCs[squad:section_name()]



squad was nil. This lead to an empty error log with your newest dll. I had restored to the original luaJIT dll and it gave a proper FATAL ERROR crash log. It correctly pointed out that squad was nil. Seems that sometimes with some errors that the new dll will not allow xrEngine to spit out a crash log.

A have a question that is lua specific. If I create a read-only table and look up a key that does not exist I get 'loop in gettable' error. Do you know a workaround for this?
  09:48:14  22 February 2014
profilee-mailreply Message URLTo the Top
Xetrill
(Senior)
 
On forum: 07/08/2008
Messages: 129

---QUOTATION---
I found an error in your xs_utils.script...
---END QUOTATION---


Thanks, also there are other issues as well. Issues that are fixed in the C versions of the same functions. Specifically, when iterating a table you should never create new keys. Because there is no guarantee that it will work/do what you want -- this behavior is undefined.
It's nothing special really, pretty much every iterator implementation in pretty much every language behaves just like that. But I missed it when I wrote them.


---QUOTATION---
Also I had an issue with error reporting when using the latest LuaJIT dll in Call of Pripyat...
---END QUOTATION---


That's not so good... will need to investigate, thanks for the info.

I can guess it relates to me trying to create and attach a stack representation in case of errors. Well at least I have some idea where to start from.


---QUOTATION---
...If I create a read-only table and look up a key that does not exist I get 'loop in gettable' error. Do you know a workaround for this?
---END QUOTATION---


Well, since the idea of read-only tables is to never create new keys, doing that itself is an error.

Makes the think that toEnumTable and toFlagsTable should not make use of toReadOnlyTable. Maybe I was to hard trying to enforce proper behavior.

Anyway, to answer your question. Yes, there is a workaround, you can bypass the metatable with rawget.
  11:39:53  22 February 2014
profilee-mailreply Message URLTo the Top
Alundaio
Sad Clown
(Resident)

 

 
On forum: 04/05/2010
 

Message edited by:
Alundaio
02/22/2014 12:00:42
Messages: 2230

---QUOTATION---
Well, since the idea of read-only tables is to never create new keys, doing that itself is an error.
---END QUOTATION---



I don't want to create new elements in the table. I simply wanted to check if one existed without error. But anyway I'll just use read-only on tables that I know what is being looked up. For example I use toEnumTable for group_id_by_levels in sim_board.script. The reason I asked for a workaround was because level.name() returns "nil" on level load. But I found a solution by getting the current level name by getting the level name from the actor's game graph level id. So every key being checked is indeed valid now.

I thought it didn't matter in lua if you change a table while iterating as long as it is a set. If it's an array you need to copy the table with the stuff you want removed.
  12:34:49  22 February 2014
profilee-mailreply Message URLTo the Top
Xetrill
(Senior)
 
On forum: 07/08/2008
 

Message edited by:
Xetrill
02/22/2014 12:35:23
Messages: 129

---QUOTATION---
I don't want to create new elements in the table....
---END QUOTATION---


Okay, I just tested the implementation from the Lua manual and it works...

Looking at it now...FFS of course it crashes! I made t reference itself. Proper implementation:

function toReadOnlyTable(t)
	local proxy = {}
	local mt = {
		__index = t,
		__newindex = function (t,k,v)
			abort("Illegal attempt to modify a read-only table. [key: '%s', value = '%s']",
				  tostring(k), tostring(v)
			)
		end,
		__metatable = "read only table"
	}
	setmetatable(proxy, mt)
	return proxy
end


Ya well, that happens whenever I don't write test code. *Sigh* I wonder how many bugs are in xs_transmutation.script (from my pastebin).


---QUOTATION---
I thought it didn't matter in lua if you change a table while iterating as long as it is a set. If it's an array you need to copy the table with the stuff you want removed or I have done a for #table, 1 do to pop off the last elements and delete them in order just fine.
---END QUOTATION---


Changing values is perfectly fine, regardless it the entries are stored in the array or hashtable part, but creating new entries is undefined behavior.

As for removing entries from an array, well first, removing entries from a table means setting the value to nil; that is what table.remove does as well.
But it also ensures the array sequence remains intact (no gaps), which can be avoided if entries are removed from the end.
If gaps are created, Lua switches storage to the hashtable part from the first gap onwards. And the main benefit of array's gets lost, the tight and predictable memory layout.
  05:22:23  12 March 2014
profilee-mailreply Message URLTo the Top
Alundaio
Sad Clown
(Resident)

 

 
On forum: 04/05/2010
Messages: 2230
I'm loving the marshal library. Is it possible to use it to serialize engine classes, like CTime?
  15:44:46  12 March 2014
profilee-mailreply Message URLTo the Top
Xetrill
(Senior)
 
On forum: 07/08/2008
 

Message edited by:
Xetrill
03/12/2014 19:22:22
Messages: 129

---QUOTATION---
I'm loving the marshal library. Is it possible to use it to serialize engine classes, like CTime?
---END QUOTATION---


It's pretty good, albeit not perfect. I'd like it to take a FILE* struct (io.open) as input, and write directly to disk, instead of returning a buffer/string. But, well it wasn't really designed with that in mind.

To answer your question, generally no, but possibly yes. You can make it serialize if you provide a __persist hook.
The hook function needs to be added to the to-be-hooked userdata object's metatable -- getmetatable(game.get_game_time()).
There add a __persist function, that returns a closure which returns a CTime instance. Meaning the closure is a simple generator function, taking the current CTime's value and capturing it too re-create another instance of it later.
It's works just like Lua iterators (pairs, ipairs).

Note that userdata objects share a common metatable, so you'll only have to add the hook once.

Complete hook example: https://github.com/richardhundt/lua-marshal#hooks

Update:
Yeah, it works and here's how:

do
	begin_region('marshal CTime')

	do
		game.CTime.__size = 4 * 9 -- guess based on ctime.h tm; most likely wrong

		function game_CTime___persist(self)
			local Y, M, D, h, m, s, ms
				= self:get(Y, M, D, h, m, s, ms)
			return function ()
				local t = game.CTime()
				t:set(Y, M, D, h, m, s, ms)
				return t
			end
		end

		local t = game.CTime()
		printfln('type(t): %s', type(t)); flush()

		local m = getmetatable(t)
		m.__persist = game_CTime___persist
		dump(m, 3, 'm')

		debug.hexdump(t, game.CTime.__size, 't (default)'); flush()
		t:set(2014, 3, 12, 1, 2, 3, 4)
		debug.hexdump(t, game.CTime.__size, 't (today)'); flush()

		local s = marshal.encode(t)
		debug.hexdump(s, #s, 's'); flush()

		local x = marshal.decode(s)
		printfln('type(x): %s', type(x)); flush()
	end

	end_region()
end


(output @ http://pastebin.com/d3N8QTpk)

I haven't checked what CTime:set() returns, maybe it returns self which means the local s can be removed. And the hexdump of s suggests it's a double pointer, because it doesn't change after calling CTime:set() or it's (much) larger than 4*9 bytes (?!).
Could also be that CTime:set() does nothing.
  12:47:35  13 March 2014
profilee-mailreply Message URLTo the Top
Alundaio
Sad Clown
(Resident)

 

 
On forum: 04/05/2010
Messages: 2230
Thank you, I appreciate the example. I've seen his hook examples but was unsure how to apply them here.

What game version is your xs_save.script written for? It makes a reference to travel_manager.level_changing which doesn't exist in CS or CoP. I currently have to check if actor is next to a level_changer to guess if the level is changing; would be nice to find a better way, sometimes saves are unreliable when it comes to creating level transitioned autosaves. I wish I found your scripts sooner I made my own saving implementation a few months back but your method is superior and now marshal is even better. Opens up a lot of possibilities.
  16:50:26  13 March 2014
profilee-mailreply Message URLTo the Top
Xetrill
(Senior)
 
On forum: 07/08/2008
 

Message edited by:
Xetrill
03/13/2014 19:40:51
Messages: 129
Neither really, it was written for TFW; the mod which brought my interest back to STALKER in the first place.
Anyway, I noticed the dependency on travel_manager.level_changing too and opted to move that 'knowledge' to xs_save directly.

And this is what I ended up with; all credit goes to smog2:

function SaveManager:levelChanging()
	local sim = alife()
	local act = game_graph():vertex(sim:actor().m_game_vertex_id)
	return act:level_id() ~= sim:level_id()
end



I haven't updated my pastebin's yet as I didn't test whether my changes actually work, I also don't understand why/how that levelChanging function works. But smog2's safe system works, so.

My xs_save and xs_storage (which is Lua Table Persistence) was, I thought, the best improvement I could provide the community. Because, really the vanilla save system is horrible, way to verbose/inconvenient and then not even fast.
  02:38:14  14 March 2014
profilee-mailreply Message URLTo the Top
Alundaio
Sad Clown
(Resident)

 

 
On forum: 04/05/2010
 

Message edited by:
Alundaio
03/14/2014 2:41:17
Messages: 2230
Everything works perfectly now, thanks again. Finally people can enjoy my mod without duplicating objects on level transition. The reason I like marshal is because it plugs very easily into my previous method of saving (Which was writing hex strings to file.) Yes, the vanilla system is very bad; It's prone to corruption - Like xr_logic pstor.
 
Each word should be at least 3 characters long.
Search:    
Search conditions:    - spaces as AND    - spaces as OR   
 
Forum Index » S.T.A.L.K.E.R.: Clear Sky Forum » Mod discussion
 

All short dates are in Month-Day-Year format.


 

Copyright © 1995-2019 GSC Game World. All rights reserved.
This site is best viewed in Internet Explorer 4.xx and up and Javascript enabled. Webmaster.
Opera Software products are not supported.
If any problem concerning the site functioning under Opera Software appears apply
to Opera Software technical support service.