View Single Post
  #10  
Unread 06-10-2013, 11:03 AM
Lynx3d Lynx3d is offline
The Undefeated
Interface Author - Click to view interfaces
 
Join Date: May 2013
Posts: 7
Seems like I won't get around this stuff either...

Thurallor, I can't reproduce the problem of Vindar's code returning number indices as string indices. Are you sure you converted the saved data back?
But in any case it only solves the locale problem partially, it will still save numbers as "1,234" and hence still fails converting back at loading when switching client language.
Also I'm not sure why he needs that metatable and other "black magic", I'm pretty sure references to the same table will be lost anyway.

Thurallor's solution is certainly interesting, it basically does the same as Turbine's own I/O method by converting it to Lua-code. Only problem is that you need to wrap the result in a single huge string which makes pretty unreadable files, and I'm not too sure that you won't eventually run into any line-length limitation of the interpreter or underlying file I/O.

I decided to mix the solutions, I just write out numbers as string and parse them back with loadstring(), and prefix the strings so know if it was was number or not:
Code:
function convSave(obj)
	if type(obj) == "number" then
		local text = "n:" .. tostring(obj);
		return string.gsub(text, ",", ".");
	elseif type(obj) == "string" then
		return "s:" .. obj;
	elseif type(obj) == "boolean" then
		return obj;
	elseif type(obj) == "table" then
		local newt = {};
		for k, v in pairs(obj) do
			if type(k) ~= "number" and type(k) ~= "string" then
				-- unsupported keys
			else
				newt[convSave(k)] = convSave(v);
			end
		end
		return newt;
	end
end

function convLoad(obj)
	if type(obj) == "string" then
		obj_id = string.sub(obj, 1, 2);
		if obj_id == "n:" then
			-- need to run it through interpreter, since tonumber() may only accept ","
			local readnum = loadstring("return " .. string.sub(obj, 3));
			return readnum and readnum();
		elseif obj_id == "s:" then
			return string.sub(obj, 3)
		end
	elseif type(obj) == "boolean" then
		return obj;
	elseif type(obj) == "table" then
		local newt = {}
		for k, v in pairs(obj) do
			local key = convLoad(k);
			if key ~= nil then
				newt[key] = convLoad(v);
			end
		end
		return newt;
	end
end
So a table like
{ [5] = 1.23, ["foo"] = "bar"}
becomes
{ ["n:5"] = "n:1.23", ["s:foo"] = "s:bar" }
which can be converted back in all locales.

I could also check for current locale and use gsub again and use tonumber() instead of loadstring() for numbers, and I haven't investigated if Lotro can handle non-printable characters or if I should use string.format("%q", ...) too...
Reply With Quote