Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- print(pcall(hooks.ShutDown.streams))
- require'vstruct'
- local senddata
- timer.Create("asd",0.1,0,function()
- if not senddata then return end
- local fmt={"i1"}
- local count=0
- local data={}
- for k,v in pairs(player.GetHumans()) do
- fmt[#fmt+1]="u4 f8 f8 f8"
- local pos=v:GetPos()
- table.insert(data,v:UserID())
- table.insert(data,pos.x)
- table.insert(data,pos.y)
- table.insert(data,pos.z)
- count=count+1
- end
- --print(count)
- table.insert(data,1,count)
- fmt=table.concat(fmt," ")
- local str=vstruct.pack(fmt,data)
- senddata:Send(str)
- end)
- require'socket'
- require'vstruct'
- pcall(require,'cares')
- local Tag="streams"
- module (Tag,package.seeall)
- function dbg(...)
- Msg("[Streams] ") print(...)
- end
- function isip(ip)
- assert(not ip:find":","IPv6 or port in ip not supported")
- return ip:match("^%d%d?%d?.%d%d?%d?.%d%d?%d?.%d%d?%d?$")
- end
- ---------------------------------------------------------
- -- Stream logic here
- ---------------------------------------------------------
- local clients={}
- _M.clients=clients
- local CLM={}
- function CLM:created()
- dbg("New stream from",self.ip)
- senddata=self
- end
- function CLM:proc(gotdata,data)
- assert(self.closed!=true,"still processing even when closed")
- if not gotdata then
- dbg("procerr",self.ip,data)
- return true -- close
- end
- local ok,err=pcall(procdata,data)
- if not ok then
- dbg("procdata err",err)
- end
- end
- function CLM:Send(data)
- if self.closed then error"closed" end
- self.sendbuff=(self.sendbuff or "")..data
- end
- local function CL(tbl)
- tbl = tbl or {}
- tbl.i=0
- setmetatable(tbl,{__index=CLM})
- return tbl
- end
- ---------------------------------------------------------
- -- Connecting to somenoe
- ---------------------------------------------------------
- local dnscache={--[[ domain=ip ]]}
- function ConnectStream(ip,port,cb) -- Must match with the recursive call signature below
- -- DNS Resolving
- ip=dnscache[ip] or ip
- if not isip(ip) then
- if not cares then return false end
- cares.Resolve(ip,function(identifier,errored,err,domain)
- if errored then
- if cb then cb(false,err) else
- dbg("Resolve error",err) end
- return
- end
- local resolved=err
- if not resolved or not isip(resolved) then
- if cb then cb(false,"resolved to wrong type",resolved) else
- dbg("resolved to wrong type",resolved) end
- return
- end
- --dbg("resolved",resolved)
- dnscache[ip]=resolved
- ConnectStream(ip,port,cb) -- Must match with SendMessage parameters above
- end)
- return
- end
- -- Sending and receiving
- local sock=socket.tcp()
- sock:settimeout(0)
- port=port or 37477
- local connected,err=sock:connect(ip,port)
- if not connected and err~='timeout' then
- if cb then cb(connected,err) else
- dbg("SendMessage failed",connected,err) end
- return false
- end
- timer.Create(sock,0,0,function()
- local ok,err=sock:connect(ip,port)
- if not ok and (err=='timeout' or (err and err:find"progress")) then return end
- if not ok then
- if cb then cb(ok,err) else
- dbg("Sock connect failed: ",err) end
- timer.Remove(sock)
- sock:close()
- return
- end
- local clid=#clients+1
- assert(not clients[clid])
- clients[clid]=CL{clid=clid,socket=sock,ip=ip,port=port,new=true}
- cb(sock,true)
- timer.Remove(sock)
- end)
- return sock
- end
- function Connect(ip,port)
- ConnectStream(ip,port,function(sock,err)
- if not sock then
- dbg("Connect",sock,err)
- return
- end
- end)
- end
- ---------------------------------------------------------
- -- Accepting, receiving, etc
- ---------------------------------------------------------
- local acceptor
- function ProcessConnection(client,db)
- local close
- if db.new then
- close = db:created()
- end
- if close!=nil then return close end
- if db.sendbuff and #db.sendbuff>0 then
- local data=db.sendbuff
- local ok,err,sent=client:send(data)
- if ok then
- db.sendbuff=false
- else
- if err=='timeout' then
- if sent==0 then
- dbg("sent nothing??")
- end
- assert(sent<#data)
- db.sendbuff=data:sub(sent+1,-1)
- else
- close=close or db:proc(false,err)
- end
- end
- end
- local ok,err,data=client:receive(db.receivemode or 1024)
- if not ok and err=='timeout' then
- if not data or #data==0 then
- return
- end
- -- timeout but we got data. Let's hack this up.
- ok=data
- err=nil
- data=nil
- end
- if ok then
- assert(type(data)~="string")
- data=ok
- end
- if data then
- assert(type(data)=="string")
- close=close or db:proc(true,data)
- end
- if not ok then
- close=close or db:proc(false,err)
- end
- return close
- end
- function Think()
- if not acceptor then return end
- local newclient,err=acceptor:accept()
- if not newclient and err=='closed' then
- error"acceptor socket closed"
- end
- if not newclient and err!='timeout' then
- error("FATAL socket error: "..tostring(err))
- end
- if newclient then
- newclient:settimeout(0)
- local ip,port=newclient:getpeername()
- /*if not whitelist[ip] and not hook.Call("tcpcommok",nil,ip) then
- dbg("Non whitelisted connection from",ip)
- newclient:close()
- return -- dos possibility here, can you see it? C:
- end*/
- dbg("New connection",newclient,"from",ip)
- local clid=#clients+1
- assert(not clients[clid])
- clients[clid]=CL{clid=clid,socket=newclient,ip=ip,port=port,new=true}
- end
- for clid,db in pairs(clients) do
- if ProcessConnection(db.socket,db)==true then
- db.socket:close()
- db.closed=true
- clients[clid]=nil
- end
- if db.new then db.new=false end
- end
- end
- function StartServer()
- acceptor=socket.tcp()
- acceptor:settimeout(0)
- acceptor:setoption('reuseaddr',true) -- we need this.
- assert(acceptor:bind("*",37477))
- assert(acceptor:listen(8))
- hook.Add("Think",Tag,Think)
- end
- timer.Simple(0,function()
- local ok,err=pcall(StartServer)
- if not ok then
- dbg("Failed to bind ("..err.."), retrying in 30 seconds.")
- timer.Simple(123,StartServer) -- I heard 2 minutes is how long the kernel keeps the address reserved :c
- end
- end)
- hook.Add("ShutDown",Tag,function()
- if acceptor then
- acceptor:close()
- end
- for _,v in pairs(clients) do
- local client=v.socket
- v.closed=true
- if client then
- client:close()
- end
- end
- table.Empty(clients)
- clients=nil
- hook.Remove("Think",Tag)
- end)
- --- AAAHHHHAAA
- local dats={}
- _M.dats=dats
- timer.Create("qq",1,0,function()
- for k,v in pairs(dats) do
- if v.timeout<SysTime() then
- print("removing uid",k)
- dats[k]=nil
- if IsValid(v.ent) then
- v.ent:Remove()
- end
- end
- end
- end)
- function procdata(str)
- local count=vstruct.unpack("i1",str)[1]
- --print(count)
- local fmt={"x1"}
- for i=1,count do
- fmt[#fmt+1]="u4 f8 f8 f8"
- end
- fmt=table.concat(fmt," ")
- local data=vstruct.unpack(fmt,str)
- local t={}
- --PrintTable(data)
- for i=0,count-1 do
- i=i*4+1
- local uid=data[i]
- local x=data[i+1]
- local y=data[i+2]
- local z=data[i+3]
- t[uid]=Vector(x,y,z)
- end
- for uid,pos in pairs(t) do
- local dd=dats[uid]
- if not dd then
- dd={}
- dats[uid]=dd
- dd.ent=ents.Create'prop_dynamic'
- if IsValid(dd.ent) then
- dd.ent:SetModel"models/props_trainstation/trainstation_post001.mdl"
- dd.ent:Spawn()
- end
- print("created uid",uid)
- end
- if IsValid(dd.ent) then
- dd.ent:SetPos(pos)
- dd.timeout=SysTime()+10
- end
- end
- end
Add Comment
Please, Sign In to add comment