All pastes #553694 Raw Edit

jlulian38

public text v1 · immutable
·published 2007-06-09 21:01 UTC
rendered paste body
--No shared for brevity so we have to rethrow crap in.
--Constants
FLG_NEWSTREAM = 0
FLG_DATA = 1
FLG_CLOSE = 4
FLG_RESET = 5
TYP_NUM = 105
TYP_STR = 106
TYP_PTR_STR = 107
TYP_PTR_TAB = 108
MAX_STR = 128

DEBUG = true

--Variables
stream = {}
streamc = {}
filter = {}
streams = {}

function debugMsg(s)
	if DEBUG then Msg(s.."\n") end
end

function Stream(name,scp)
 --starts a new container stream and shits it all up and ready.
 	local strm = startStream(name)
	debugMsg("New master-stream ("..name..")")
	table.insert(scp.strmindex,name)
	strm.queue = {}
	for _,v in pairs(scp:GetPlayers()) do
		strm:AddStream(startStreamPlayer(name,v))
		debugMsg("Adding sub-stream for ("..tostring(v)..")")
	end
	return strm
end

function StreamAdd(name,ply)
 --o_O
	streams[name]:AddStream(ply)
end

function startStream(name)
	--this is a container
	local o = {}
	for k,v in pairs(streamc) do o[k]=v end
	o.streams = {} --individual player streams
	streams[name] = o
	return o
end

function streamc:AddStream(strm)
 --adds an internal stream to a containers table, and links it's queue
	table.insert(self.streams,strm)
	strm.queue = self.queue
end

function streamc:Run()
 --runs a stream internal thingy
	for _,v in pairs(self.streams) do
		v:Run()
	end
end

function startStreamPlayer(name,ply) 
	local o = {}
	--really dumb way to do this
	for k,v in pairs(stream) do o[k]=v end
	o.data = {} --holds local copy of data.
	o.sync = {} --holds sync info (what to send etc etc)
	o.name = name --stream name
	o.rcp = RecipientFilter()
	o.rcp:AddPlayer(ply)
	o.qPos = 1
	o.wait = 10
	o.hook = 0
	o:Start()
	return o;
end

function streamFilter()
	return filter:New()
end

function stream:Start()
	--notifies client of new stream (internal)
	self:Send(FLG_NEWSTREAM,self.name,TYP_PTR)
end

function stream:Send(flag,name,typ,id,pid,data)
 //this all around function sends all data
 //it sends the queue shit or FLAGS and what not 
//(flags like Closer and Reseter'r) 
        umsg.Start("stream_umsg")
		umsg.Short(flag)
		umsg.String(self.name)
		if (flag == FLG_DATA) then
            /*debugMsg("\nSending data!")
            debugMsg("Stream:"..self.name)
            debugMsg("Name:"..name)
            debugMsg("Type:"..typ)
            debugMsg("ID:"..id)
            debugMsg("PID:"..pid)  
            if data then
                debugMsg("Data:"..data)
            end
            debugMsg("This should show up on the client now!\n")*/   
			umsg.Short(typ) //hurr I forgot this...
			umsg.Long(id)
			umsg.Long(pid)
			if (typ == TYP_NUM) then
				umsg.Long(data)
			elseif (typ == TYP_STR) then
				umsg.String(data)
			end --num,string or nothing (pointer)
			umsg.String(name)
		end
	umsg.End()
end

function streamc:Queue(name,data,pid) //parses and queues up data. 
	local typ = type(data)           //(no return, tables in internal streams are linked to the container's
	local pid = pid or 0
	if (typ == "number") then
		table.insert(self.queue,{name=name,typ=TYP_NUM,data=data,pid=pid,data=data})
		local id = #self.queue
		local tab = self.queue[id]
		tab.id=id
		tab.pid=pid
		tab.name=name
	elseif (typ == "table") then
		table.insert(self.queue,{name=name,typ=TYP_PTR_TAB,id=#self.queue+1,pid=pid})
		self:TableParse(data,#self.queue) 
	elseif (typ == "string") then
		if #data > MAX_STR then //this chunk loops infintely, we need to fix that...
			table.insert(self.queue,{name=name,typ=TYP_PTR_STR,id=#self.queue+1,pid=pid})
			local sid = #self.queue
			local chk = true
			while (chk) do
				if #data > MAX_STR then
					local addStr=data:sub(0,127)
					data = data:gsub(addStr,'')
					self:Queue("",addStr,sid)
				else
					chk=false
				end
			end
		else
			table.insert(self.queue,{name=name,typ=TYP_STR,id=#self.queue+1,pid=pid,data=data})
		end
	end
end

function streamc:TableParse(t, tid)
	for i,v in pairs(t) do
		self:Queue(i,v,tid)
	end
end
function stream:Run()
 //runs all the streaming bits, gets tables data and sends it with the umsg'r
	self.hook = self.hook + 1
	if self.hook > self.wait then
		if (self.qPos <= #self.queue) then //only send data if the queue is bigger than
			local qTab = self.queue[self.qPos] //our current position (has new data)
			local typ = qTab.typ 
			local id = qTab.id
			local pid = qTab.pid
			local data = qTab.data or false
			local name = qTab.name or ""
			self:Send(FLG_DATA,name,typ,id,pid,data) //send with data flag and all info.
			self.qPos = self.qPos + 1
		end
		self.hook = 0
	end
end --called by container (I was gonna hook this >.>)

function stream:Close() --internal stream close
	self:Send(FLG_CLOSE)
end

function streamc:Close() --closes all child streams and deletes itself(!)
	for k,v in pairs(self.streams) do
		v:Close()
	end	
	streams[self.name] = nil --bam!
end

function streamc:Reset() --makes a constainer call all it's child streams and resets them.
	self.queue = {}
	for _,v in pairs(self.streams) do
		v.qPos = 1
		self:Send(FLG_RESET)
	end
end


function filter:New()
 --this is a weird work around to the lack of getting players from a recipient filter, lets me do crazy shit.
	local o = {}
	for k,v in pairs(filter) do o[k]=v end
	o.strmindex = {}
	o.players = {}
	o.playerhook = function (ply) if self.all then self:AddPlayer(ply) for k,v in pairs(self.strmindex) do StreamAdd(v,ply) end end end
	hook.Add("PlayerInitialSpawn","weird thing"..math.random(1,10000),o.playerhook)
	return o
end

function filter:AddPlayer(ply)
	table.insert(self.players,ply)
end

function filter:AddAllPlayers(ply)
	self.all = true -- we're sending to all make sure of that
	local a = player.GetAll()
	for _,v in pairs(a) do
		self:AddPlayer(v)
	end
end

function filter:GetPlayers()
	return self.players
end

function streamHook()
	for _,v in pairs(streams) do
		v:Run()
	end
end
hook.Add("Think","server side stream hook",streamHook)

--test code
myFil = streamFilter()
myFil:AddAllPlayers()
mStream = Stream("test_stream",myFil) --have to self populate...

timer.Simple(15,function () tStream = startStreamPlayer("test_stream",player.GetByID(1)) tStream:Start() mStream:AddStream(tStream) tStream.wait = 2 end)
test_tab = {}
for i=1,100 do
	test_tab[i]=(i+1)/2^3
end
for i=1,100 do
	test_tab[math.random(1,100)]="THIS IS RANDOM OLOL?"
end
mStream:Queue("test_data",test_tab)

--Clientside
--No shared for brevity so we have to rethrow crap in.
--Constants
FLG_NEWSTREAM = 0 
FLG_DATA = 1 --Data is being sent
FLG_CLOSE = 4
FLG_RESET = 5
TYP_NUM = 105
TYP_STR = 106
TYP_PTR_STR = 107
TYP_PTR_TAB = 108

DEBUG = true --for awhile, keep it this way.

--Variables
stream = {}
strTable = {} --holds all streams.

function debugMsg(s)
	if DEBUG then Msg(s.."\n") end
end

function streamHook(data)
	--shorts are friggen long, I was hoping for like flag passing, this could do fuckin' math.	
	local flags = data:ReadShort() --first short, is ALWAYS, the flags.
	local name = data:ReadString() --first string is the stream name
	debugMsg("Stream:"..name)
	debugMsg("Flags:"..tostring(flags))
	if (flags == FLG_NEWSTREAM) then
		stream:New(name)
	elseif (flags == FLG_DATA) then
		local sndtype = data:ReadShort() --second short is type
		local sndid = data:ReadLong() --first long is this ones id
		local sndpid = data:ReadLong() --2nd long is a pointer id (itself if not applicable)
		debugMsg("Data Sent!")
		debugMsg("Type:"..sndtype)
		debugMsg("ID:"..sndid)
		debugMsg("Pointer:"..sndpid)
		local snddata
		if (sndtype == TYP_NUM) then
			snddata = data:ReadLong()
		elseif (sndtype == TYP_STR) then
			snddata = data:ReadString() --a part of a string probably
		elseif (sndtype == TYP_PTR_STR or sndtype == TYP_PTR_TAB) then
			snddata = false --PTR is a table or string (they're cut up into chunks)
		end
		local sndname = data:ReadString() --name
		debugMsg("Name:"..sndname)
		if snddata then debugMsg("Data:"..snddata.."\n\n") end
		--chuck all that into our function
		if not strTable[name] then debugMsg("No stream ("..name..")") return end
		strTable[name]:RecievePacket(sndname,sndtype,sndid,sndpid,snddata)
	elseif (flags == FLG_CLOSE) then
		strTable[name] = nil --gets rid of our stream
	elseif (flags == FLG_RESET) then --clears data and reset the queue (server and client side)
		strTable[name].queue = {}
		strTable[name].data = {}
	end
end
usermessage.Hook("stream_umsg",streamHook)

function stream:New(name)
	local o = {}
	for k,v in pairs(self) do o[k]=v end
	o.queue = {}
	o.data = {}
	o.name = name
	strTable[name] = o
end

function stream:GetTable()
	return self.data
end

function stream:RecievePacket(name,stype,id,pid,data)
	local tab = self.queue
	if (pid ~= 0) then
		if (tab[pid] ~= nil) then
			if (tab[pid].type == TYP_PTR_TAB) then
				tab = tab[pid].ptr
			elseif (tab[pid].type == TYP_PTR_STR) then
				self.queue[pid].ptr[name]=self.queue[pid].ptr[name]..data //crazy line of code o_O
				return
			end
		end
	end
	if (tab == self.queue) then
		tab = self.data //if we haven't changed to another table, change to self.data
	end
	if (stype == TYP_PTR_TAB) then
	   debugMsg("New Table pointer: ("..name..")")
		tab[name] = {}
		self.queue[id] = {}
		self.queue[id].ptr = tab[name]
		self.queue[id].type = stype
	elseif (stype == TYP_PTR_STR) then
		tab[name] = ""
		self.queue[id] = {}
		self.queue[id].ptr = tab
		self.queue[id].name = name
		self.queue[id].type = stype
	else
	   tab[name]=data //short and sweet (finally)
	end
end