-- Server network messages
net.recv = {}

function GAME:NetRecv(uid,msg)
	local id = msg:bin(1)
	if net.recv[id]
		net.recv[id](uid,msg:sub(2))
	else
		console.print("WARNING: Unhandled message type "..(NETMSG[id] or id).." recieved!")
	end
end

net.recv[NETMSG.TITLE] = function(uid,msg)
	local player = players[uid]
	if not player.title
		return
	end
	player.title = false
	GAME:Start(player,msg:bin(1) ~= 0,true)
end

net.recv[NETMSG.CL_ANIM] = function(uid,msg)
	-- Checking an area? Find an NPC to trigger!
	local player = players[uid]
	local x = msg:bin(1,4)
	local y = msg:bin(5,4)
	player.x = x
	player.y = y
	for k,v in pairs(player.events)
		if v.flags & NPCF.CHECK_EVENT == 0
			continue
		end
		local b = NPC[v.type].collision
		if x >= v.x - b[BBOX.LEFT] and x <= v.x + b[BBOX.RIGHT]
		and y >= v.y - b[BBOX.TOP] and y <= v.y + b[BBOX.BOTTOM]
			tsc.start(player,v.event)
			return
		end
	end
end

net.recv[NETMSG.CL_MOVE] = function(uid,msg)
	local player = players[uid]
	player.x = msg:bin(1,4)
	player.y = msg:bin(5,4)
	player.mx = msg:bin(9,2)
	player.my = msg:bin(11,2)
	player.anim = msg:bin(13)
	player.flip = msg:bin(14) ~= 0
end

net.recv[NETMSG.TSC_TEXT] = function(uid,msg)
	local player = players[uid]
	if player.tsc and player.tsc.wait == "text"
		player.tsc.wait = nil
	end
end

net.recv[NETMSG.TSC_NOD] = function(uid,msg)
	local player = players[uid]
	if player.intro
		tsc.cmd.END(player)
		return
	end
	if player.tsc and player.tsc.wait == "nod"
		player.tsc.wait = nil
	end
end

function net.send_console(text)
	net.send(0,string.num(NETMSG.CHAT) .. text)
end

function net.send_map(uid,map)
	local player = players[uid]
	if player.stage
		player.stage.players[player.id] = nil
		player.spawned = false
	end
	player.stage = stages[map]
	player.tsc = nil
	player.ents = {}
	player.events = {}
	net.send(player.id,string.num(NETMSG.MAP) .. map,NET.GUARANTEED|NET.ORDERED)
	if stages[map]
		stages[map].players[player.id] = player
		for i,v in ipairs(stages[map].ents)
			net.ent_spawn(uid,v)
		end
		for k,v in pairs(stages[map].players)
			if v.spawned
				net.cl_spawn(uid,v)
			end
		end
	end
end

function net.send_title(uid)
	local player = players[uid]
	player.title = true
	net.send(player.id,string.num(NETMSG.TITLE),NET.GUARANTEED)
end

function net.spawn_client(player,pos)
	player.x, player.y = (pos[1] or 0)*16+8, (pos[2] or 0)*16+8
	player.mx, player.my = 0, 0
	player.anim = ANIM.STAND
	player.spawned = true
	player.damage = false
	for k,v in pairs(player.stage.players)
		net.cl_spawn(k,player)
	end
end

function net.cl_spawn(uid,player)
	local id = player.id
	if uid == id
		id = 0
	end
	local x = math.floor(player.x)
	local y = math.floor(player.y)
	local flip = 0
	if player.flip
		flip = 2
	end
	-- TODO: Add the client's user name somewhere so it can be shown as floating text?
	net.send(uid,string.num(NETMSG.CL_SPAWN) .. string.num(id) .. string.num(x,4) .. string.num(y,4) .. string.num(player.anim) .. string.num(flip) .. player.skin.name)
end

function net.ent_spawn(uid,e)
	local net_flags = 0
	if e.flags & NPCF.IF_FLAG ~= 0 and not players[uid].eventflags[e.flagnum]
		return
	elseif e.flags & NPCF.IF_NOFLAG ~= 0 and players[uid].eventflags[e.flagnum]
		return
	end
	if e.flags & NPCF.CHECK_EVENT
		players[uid].events[e.id] = e
	end
	local important_flags = e.flags & (NPCF.BLOCKING|NPCF.BLOCK_SHOTS|NPCF.TOPBOUNCE|NPCF.SHOOTABLE|NPCF.SOLID|NPCF.RIDE|NPCF.TOUCH_EVENT|NPCF.CHECK_EVENT)
	if important_flags ~= 0
		if e.type ~= 0 or important_flags & (~(NPCF.TOUCH_EVENT|NPCF.CHECK_EVENT)) ~= 0
			net_flags = NET.GUARANTEED
		end
	end
	local flags = e.flags & (~NPCF.SERVER_ONLY)
	players[uid].ents[e.id] = {
		net_flags = net_flags,
		x = math.floor(e.x), y = math.floor(e.y),
		mx = 0, my = 0,
		type = e.type,
		flags = flags,
		anim = e.anim
	}
	net.send(uid,string.num(NETMSG.ENT_SPAWN) .. string.num(e.id) .. string.num(e.type,2) .. string.num(math.floor(e.x),4) .. string.num(math.floor(e.y),4) .. string.num(flags,4) .. string.num(e.anim),net_flags)
end

function net.ent_anim(uid,e)
	local pe = players[uid].ents[e.id]
	pe.x = math.floor(e.x)
	pe.y = math.floor(e.y)
	pe.anim = e.anim
	pe.flags = (pe.flags & (~NPCF.FLIP)) | (e.flags & NPCF.FLIP)
	net.send(uid,string.num(NETMSG.ENT_ANIM) .. string.num(e.id) .. string.num(e.x,4) .. string.num(e.y,4) .. string.num(e.anim) .. string.num(e.flags & NPCF.FLIP ~= 0),pe.net_flags)
end

function net.ent_move(uid,e)
	local pe = players[uid].ents[e.id]
	pe.x = math.floor(e.x)
	pe.y = math.floor(e.y)
	pe.mx = math.floor(e.mx*0x200)
	pe.my = math.floor(e.my*0x200)
	pe.anim = e.anim
	net.send(uid,string.num(NETMSG.ENT_MOVE) .. string.num(e.id) .. string.num(pe.x,4) .. string.num(pe.y,4) .. string.num(pe.mx,2) .. string.num(pe.my,2) .. string.num(e.anim),pe.net_flags)
end

function net.ent_remove(uid,e)
	players[uid].ents[e.id] = nil
	net.send(uid,string.num(NETMSG.ENT_REMOVE) .. string.num(e.id),NET.GUARANTEED)
end

function net.tsc_end(uid)
	net.send(uid,string.num(NETMSG.TSC_END),NET.GUARANTEED)
end

function net.tsc_keylock(uid)
	if not players[uid].spawned
		return
	end
	local keylock = 0
	if players[uid].tsc
		keylock = players[uid].tsc.keylock or 0
	end
	net.send(uid,string.num(NETMSG.TSC_KEY) .. string.num(keylock),NET.GUARANTEED)
end

function net.tsc_fai(uid,dir)
	net.send(uid,string.num(NETMSG.TSC_FAI) .. string.num(dir),NET.GUARANTEED)
end

function net.tsc_fao(uid,dir)
	net.send(uid,string.num(NETMSG.TSC_FAO) .. string.num(dir))
end

function net.tsc_msg(uid)
	local msg
	if not players[uid].tsc or not players[uid].tsc.msg
		msg = 0
	else
		msg = players[uid].tsc.msg
	end
	net.send(uid,string.num(NETMSG.TSC_MSG) .. string.num(msg),NET.GUARANTEED)
end

function net.tsc_text(uid,text)
	local tur = 0
	if players[uid].tsc and players[uid].tsc.tur
		tur = 1 -- tur or cat is 1
		if players[uid].tsc.tur == "sat"
			tur = 2 -- sat is 2
		end
	end
	net.send(uid,string.num(NETMSG.TSC_TEXT) .. string.num(tur) .. text,NET.GUARANTEED|NET.ORDERED)
end

function net.tsc_nod(uid)
	net.send(uid,string.num(NETMSG.TSC_NOD),NET.GUARANTEED|NET.ORDERED)
end

function net.tsc_clr(uid)
	net.send(uid,string.num(NETMSG.TSC_CLR),NET.GUARANTEED|NET.ORDERED)
end
