All pastes #526733 Raw Edit

Something

public lua v1 · immutable
#526733 ·published 2007-05-31 22:51 UTC
rendered paste body
/*---------------------------------------------------------   Name:	table.serialise( tbl, size )		table.deserialise( str, ... )   Desc:	Converts an arbitrary table containing vectors, angles, bools, players, entities, etc  to & from a compact string.      Notes:	Pass a second integer argument to table.serialise and it'll automatically split the resultant strings into chunks and return them as seperate values		Strings can't currently contain the characters:   { } = ;         Need to look at lines 10 & 34 and encode/decode delimiter characters.---------------------------------------------------------*/// Helper function for table.serialiselocal function SerialiseChunk( chunk, tables )	// get the data type	local type = type( chunk )	//see what data type this chunk represents and return the proper value	if		type == "number"  then return 'N:'..chunk	elseif	type == "string"  then return string.format('S:%q', chunk )   // todo escape/encode delimiter characters	elseif	type == "boolean" then return 'B:'..tostring( chunk ):sub( 1,1 )	elseif	type == "Entity"  then if chunk == GetWorldEntity() then return 'E:W' elseif chunk == NULL then return 'E:N' else return 'E:'..chunk:EntIndex()  end	elseif	type == "Vector"  then return string.format( "V:%g,%g,%g", chunk.x, chunk.y, chunk.z )	elseif	type == "Angle"   then return string.format( "A:%g,%g,%g", chunk.pitch, chunk.yaw, chunk.roll )	elseif	type == "Player"  then return 'P:'..chunk:UniqueID()	elseif	type == "table"	 then		local ID = tostring( chunk ):sub( 8 )		// tables[ID] must exist before the table is serialised else we could end up with an infinite loop.		if !tables[ID] then tables[ID] = true tables[ID] = SerialiseTableKeyValues( chunk, tables ) end		return 'T:'..ID	endend// Helper function for table.serialiselocal function DeSerialiseChunk( chunk, tables )	// get the data type and value	local type,val = chunk:match("(.):(.+)")		//see what data type this chunk represents and return the proper value	if		type == "N" then return val	elseif	type == "S" then return val:sub(2, -2)  // todo de-escape/de-encode delimiter characters	elseif	type == "B" then return val == "t"	elseif	type == "E" then if val == "W" then return GetWorldEntity() elseif val == "N" then return NULL else return Entity( val )  end	elseif	type == "V" then return Vector( val:match("(.-),(.-),(.+)") )	elseif	type == "A" then return Angle(  val:match("(.-),(.-),(.+)") )	elseif	type == "P" then return player.GetByUniqueID( val )	elseif	type == "T" then 		local t = {}		if !tables[ val ] then tables[ val ] = {} end		table.insert( tables[ val ], t )		return t	endend// Helper function for table.serialisefunction SerialiseTableKeyValues( tbl, tables )	local temp = {}	local DoKeys = !table.IsSequential( tbl )   // we don't need to save table keys if the table is sequential	for k,v in pairs( tbl ) do		local str = SerialiseChunk( v, tables )		if DoKeys && str then str = SerialiseChunk( k, tables ) .."=".. str end		table.insert( temp, str )	end	return tempend/*---------------------------------------------------------   Name:	table.serialise( tbl, size )		table.deserialise( str, ... )   Desc:	Converts an arbitrary table containing vectors, angles, bools, players, entities, etc  to & from a compact string.      Notes:	Pass a second integer argument to table.serialise and it'll automatically split the resultant strings into chunks and return them as seperate values		Strings can't currently contain the characters:   { } = ;         Need to look at lines 10 & 34 and encode/decode delimiter characters.---------------------------------------------------------*/function table.serialise( t,len )	local tables	= {}	local str		= ""	local strings	= {}	local len		= len	local headID = tostring(t):sub(8)	local head	 = SerialiseTableKeyValues( t, tables )	// distinguish the main table from nested tables	tables[headID] = nil	tables["H"..headID] = head		for k,v in pairs( tables ) do		// concat key values for each table		str = str..k.."{".. table.concat( v, ";" ) ..";}"		// if string is too long split it and start a new one		if ( len && #str >= len ) then			table.insert( strings, str:sub(1,len) )			str = str:sub( len+1 )		end			end		table.insert( strings, str )	// unpack strings and return them as seperate values	return unpack(strings)end// Pass this function the output from the previous onefunction table.deserialise( ... )	//re-combine all strings we got passed	local block		= table.concat( unpack( arg ) )	local tables	= {}	local subtables	= {}	local head		= nil	// I'm not too good at regex, so there's probably a more efficient way of doing lines 120,127,129	for ID,chunk in block:gmatch('(%w+){(.-)}') do  // Get each table chunk		// check if this table is the trunk		if ID:sub(1,1)== "H" then ID = ID:sub(2); head = ID end		tables[ID] = {}		for kv in chunk:gmatch('(.-);') do			// Split each table block into k/v pairs					local k,v = kv:match('(.-)=(.+)')		// deserialise each k/v pair and add to the new table			// if the table keys are sequential digits they won't be included in the string, so check for that.			if !k then				v = DeSerialiseChunk( kv, subtables )				table.insert( tables[ID], v)			else				k = DeSerialiseChunk( k, subtables )				v = DeSerialiseChunk( v, subtables )				tables[ID][k] = v			end		end	end	// Restore table references	for ID,tbls in pairs( subtables ) do		for _,tbl in pairs( tbls ) do					table.Merge( tbl, tables[ID] )		end	end	return tables[ head ]end