--[[ This file is part of Ice Lua Components. Ice Lua Components is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Ice Lua Components is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Ice Lua Components. If not, see . ]] print("pkg/base/main_server.lua starting") print(...) if common.version == nil then error("You must have at least version 0.0-1 to run this server!" .." iceballfornoobs-004 is FAR TOO OLD!" .." If you are using an old git version, PLEASE UPDATE!") end dofile("pkg/base/common.lua") client_list = {fdlist={}} function slot_add(sockfd, tidx, wpn, name) local i for i=1,players.max do if not players[i] then if tidx < 0 or tidx > 1 then -- TODO: actually balance this properly! tidx = (i-1) % 2 end players[i] = new_player({ name = name, --[[squad = squads[(i-1) % 2][ (math.floor((i-1)/2) % 4)+1],]] squad = nil, team = tidx, -- 0 == blue, 1 == green weapon = WPN_RIFLE, pid = i, }) return i end end return nil end function net_broadcast(sockfd, msg) local i for i=1,#(client_list.fdlist) do if client_list.fdlist[i] ~= sockfd then --print("to", client_list.fdlist[i], type(msg)) common.net_send(client_list.fdlist[i], msg) end end end function net_broadcast_team(tidx, msg) local i for i=1,#(client_list.fdlist) do local cli = client_list[client_list.fdlist[i]] local plr = cli and players[cli.plrid] if plr and plr.team == tidx then --print("to", client_list.fdlist[i], type(msg)) common.net_send(client_list.fdlist[i], msg) end end end function server.hook_file(sockfd, ftype, fname) print("hook_file:", sockfd, ftype, fname) if (ftype == "icemap" or ftype == "map") and (fname == "pkg/MAP" or fname == "*MAP") then -- pkg/MAP is a hackish workaround so iceballfornoobs-004 still works -- once -004 support is dropped, please remove that approach! return map_loaded end return true end function server.hook_connect(sockfd, addrinfo) -- TODO: enforce bans client_list.fdlist[#(client_list.fdlist)+1] = sockfd client_list[sockfd] = { fdidx = #(client_list.fdlist), addrinfo = addrinfo, plrid = nil } print("connect:", sockfd, addrinfo.proto, addrinfo.addr and addrinfo.addr.sport, addrinfo.addr and addrinfo.addr.ip, addrinfo.addr and addrinfo.addr.cport) local ss = (sockfd == true and "(local)") or sockfd --[[net_broadcast(nil, common.net_pack("BIz", 0x0E, 0xFF800000, "Connected: player on sockfd "..ss))]] print("Connected: player on sockfd "..ss) common.net_send(sockfd, common.net_pack("Bz", 0xE0, map_fname)) end function server.hook_disconnect(sockfd, server_force, reason) -- just in case we get any stray disconnect messages if not client_list[sockfd] then return end local plrid = client_list[sockfd].plrid local plr = players[plrid] local fdidx = client_list[sockfd].fdidx local cli2 = client_list[client_list.fdlist[#(client_list.fdlist)]] cli2.fdidx = fdidx client_list.fdlist[fdidx] = client_list.fdlist[#(client_list.fdlist)] client_list.fdlist[#(client_list.fdlist)] = nil client_list[sockfd] = nil print("disconnect:", sockfd, server_force, reason) local ss = (sockfd == true and "(local)") or sockfd --[[net_broadcast(nil, common.net_pack("BIz", 0x0E, 0xFF800000, "Disconnected: player on sockfd "..ss))]] print("Disconnected: player on sockfd "..ss) if plr then plr.intel_drop() net_broadcast(nil, common.net_pack("BIz", 0x0E, 0xFF800000, "* Player "..plr.name.." disconnected")) net_broadcast(sockfd, common.net_pack("BB", 0x07, plrid)) -- TODO fix crash bug --plr.free() players[plrid] = nil end end function server.hook_tick(sec_current, sec_delta) --print("tick",sec_current,sec_delta) local xlen,ylen,zlen xlen,ylen,zlen = common.map_get_dims() local pkt, sockfd while true do pkt, sockfd = common.net_recv() if not pkt then break end local cli = client_list[sockfd] local plr = cli and players[cli.plrid] local cid cid, pkt = common.net_unpack("B", pkt) --print("in",sockfd,cid) if cid == 0x03 and plr then -- TODO: throttle this local pid, x2, y2, z2 pid, x2, y2, z2, pkt = common.net_unpack("Bhhh", pkt) local x = x2/32.0 local y = y2/32.0 local z = z2/32.0 plr.set_pos_recv(x, y, z) net_broadcast(sockfd, common.net_pack("BBhhh", 0x03, cli.plrid, x2, y2, z2)) --print("03.") elseif cid == 0x04 and plr then -- TODO: throttle this local pid, ya2, xa2, keys pid, ya2, xa2, keys = common.net_unpack("BbbB", pkt) local ya = ya2*math.pi/128 local xa = xa2*math.pi/256 plr.set_orient_recv(ya, xa, keys) net_broadcast(sockfd, common.net_pack("BBbbB", 0x04, cli.plrid, ya2, xa2, keys)) --print("04.") elseif cid == 0x08 and plr then local x,y,z,cb,cg,cr,ct x,y,z,cb,cg,cr,ct,pkt = common.net_unpack("HHHBBBB", pkt) if x >= 0 and x < xlen and z >= 0 and z < zlen then if y >= 0 and y <= ylen-3 then if plr.blocks > 0 then plr.blocks = plr.blocks - 1 map_block_set(x,y,z,ct,cr,cg,cb) net_broadcast(nil, common.net_pack("BHHHBBBB", 0x08,x,y,z,cb,cg,cr,ct)) else plr.blocks = 0 end if plr.blocks == 0 then net_broadcast(nil, common.net_pack("BBB", 0x19, cli.plrid, 0)) else -- to prevent desyncing issues. common.net_send(sockfd, common.net_pack("BBB", 0x19, cli.plrid, plr.blocks)) end end end elseif cid == 0x09 and plr then local x,y,z x,y,z = common.net_unpack("HHH", pkt) if x >= 0 and x < xlen and z >= 0 and z < zlen then if y >= 0 and y <= ylen-3 then if map_block_break(x,y,z) then net_broadcast(nil, common.net_pack("BHHH", 0x09,x,y,z)) if plr.tool == TOOL_SPADE then local oblocks = plr.blocks plr.blocks = plr.blocks + 1 if plr.blocks > 100 then plr.blocks = 100 end if oblocks == 0 then net_broadcast(nil, common.net_pack("BBB", 0x19, cli.plrid, plr.blocks)) else common.net_send(sockfd, common.net_pack("BBB", 0x19, cli.plrid, plr.blocks)) end end end end end elseif cid == 0x0A and plr then local x,y,z x,y,z = common.net_unpack("HHH", pkt) if x >= 0 and x < xlen and z >= 0 and z < zlen then local i for i=-1,1 do if y+i >= 0 and y+i <= ylen-3 then map_block_break(x,y+i,z) net_broadcast(nil, common.net_pack("BHHH", 0x09,x,y+i,z)) end end end elseif cid == 0x0C and plr then -- chat local msg msg, pkt = common.net_unpack("z", pkt) local s = nil local usage_colour = 0xFFDDDDFF if string.sub(msg,1,1) == "/" then --TODO: Better parameter parsing (param1 "param two" "param \"three\"") local params = string.split(string.sub(msg,2), " ") if params[1] == "me" then s = "* "..plr.name.." "..string.sub(msg,5) elseif params[1] == "squad" then --TODO: local s = string.sub(msg,8) if s ~= "" then if s == "none" then plr.squad = nil else plr.squad = s end plr.update_score() end elseif params[1] == "kill" then plr.set_health_damage(0, 0xFF800000, plr.name.." shuffled off this mortal coil", plr) elseif params[1] == "teleport" or params[1] == "tp" then if table.getn(params) == 4 then --TODO: Actually teleport player to (tonumber(params[2]), tonumber(params[3]), tonumber(params[4])) else net_broadcast(nil, common.net_pack("BIz", 0x0E, usage_colour, "Usage: /teleport x y z")) end end else s = plr.name.." ("..teams[plr.team].name.."): "..msg end if s then net_broadcast(nil, common.net_pack("BIz", 0x0E, 0xFFFFFFFF, s)) end elseif cid == 0x0D and plr then -- teamchat local msg msg, pkt = common.net_unpack("z", pkt) local s = nil if string.sub(msg,1,4) == "/me " then s = "* "..plr.name.." "..string.sub(msg,5) else s = plr.name..": "..msg end if s then local cb = teams[plr.team].color_chat local c = argb_split_to_merged(cb[1],cb[2],cb[3]) net_broadcast_team(plr.team, common.net_pack("BIz", 0x0E, c, s)) end elseif cid == 0x11 and plr then local tidx, wpn, name tidx, wpn, name, pkt = common.net_unpack("bbz", pkt) name = (name ~= "" and name) or name_generate() plr.set_health_damage(0, 0xFF800000, plr.name.." changed teams", nil) plr.team = tidx net_broadcast(nil, common.net_pack("BBBBhhhzz", 0x05, plr.pid, plr.team, plr.weapon, plr.score, plr.kills, plr.deaths, plr.name, plr.squad)) net_broadcast(nil, common.net_pack("BIz", 0x0E, 0xFF800000, "* Player "..plr.name.." has joined the "..teams[plr.team].name.." team")) elseif cid == 0x11 and not plr then local tidx, wpn, name tidx, wpn, name, pkt = common.net_unpack("bbz", pkt) name = (name ~= "" and name) or name_generate() cli.plrid = slot_add(sockfd, tidx, wpn, name) if not cli.plrid then print("* server full") -- TODO: kick somehow! else plr = players[cli.plrid] print("* "..name.." joined team "..tidx..".") -- relay other players to this player local i for i=1,players.max do local plr = players[i] if plr then common.net_send(sockfd, common.net_pack("BBBBhhhzz", 0x05, i, plr.team, plr.weapon, plr.score, plr.kills, plr.deaths, plr.name, plr.squad)) common.net_send(sockfd, common.net_pack("BBfffBB", 0x10, i, plr.x, plr.y, plr.z, plr.angy*128/math.pi, plr.angx*256/math.pi)) common.net_send(sockfd, common.net_pack("BBB", 0x17, i, plr.tool)) common.net_send(sockfd, common.net_pack("BBBBB", 0x18, i, plr.blk_color[1],plr.blk_color[2],plr.blk_color[3])) end end -- relay intels/tents to this player for i=1,4 do local f,x,y,z x,y,z = intent[i].get_pos() f = intent[i].get_flags() common.net_send(sockfd, common.net_pack("BHhhhB", 0x12, i, x, y, z, f)) local plr = intent[i].player if plr then common.net_send(sockfd, common.net_pack("BHB", 0x16, i, plr.pid)) end end -- relay this player to everyone net_broadcast(nil, common.net_pack("BBBBhhhzz", 0x05, cli.plrid, plr.team, plr.weapon, plr.score, plr.kills, plr.deaths, plr.name, plr.squad)) net_broadcast(nil, common.net_pack("BBfffBB", 0x10, cli.plrid, plr.x, plr.y, plr.z, plr.angy*128/math.pi, plr.angx*256/math.pi)) -- set player ID common.net_send(sockfd, common.net_pack("BB", 0x06, cli.plrid)) net_broadcast(nil, common.net_pack("BIz", 0x0E, 0xFF800000, "* Player "..name.." has joined the "..teams[plr.team].name.." team")) end elseif cid == 0x13 and plr then local tpid, styp tpid, styp, pkt = common.net_unpack("BB", pkt) --print("hit", tpid, styp) local tplr = players[tpid] if tplr then if plr.tool == TOOL_GUN and plr.wpn and styp >= 1 and styp <= 3 then local dmg = plr.wpn.cfg.dmg[({"head","body","legs"})[styp]] --print("dmg",dmg,tplr.wpn.cfg.dmg) tplr.gun_damage(styp, dmg, plr) elseif plr.tool == TOOL_SPADE then tplr.spade_damage(0, 1000, plr) end end if plr.tool == TOOL_GUN then -- we don't want the spade spewing tracers! net_broadcast(sockfd, common.net_pack("BB", 0x1A, cli.plrid)) end elseif cid == 0x17 and plr then local tpid, tool tpid, tool, pkt = common.net_unpack("BB", pkt) if plr and tool >= 0 and tool <= 3 then plr.tool = tool net_broadcast(sockfd, common.net_pack("BBB" , 0x17, cli.plrid, tool)) end elseif cid == 0x18 and plr then local tpid, cr,cg,cb tpid, cr,cg,cb, pkt = common.net_unpack("BBBB", pkt) if plr then plr.blk_color = {cr,cg,cb} net_broadcast(sockfd, common.net_pack("BBBBB" , 0x18, cli.plrid, cr, cg, cb)) end elseif cid == 0x1B and plr and plr.grenades > 0 then plr.grenades = plr.grenades - 1 local x,y,z,vx,vy,vz,fuse x,y,z,vx,vy,vz,fuse, pkt = common.net_unpack("hhhhhhH", pkt) local n = new_nade({ x = x/32, y = y/32, z = z/32, vx = vx/256, vy = vy/256, vz = vz/256, fuse = fuse/100, pid = cli.plrid }) nade_add(n) net_broadcast(sockfd, common.net_pack("BhhhhhhH", 0x1B,x,y,z,vx,vy,vz,fuse)) elseif cid == 0x1D and plr then -- TODO: actually reload with serverside counts net_broadcast(sockfd, common.net_pack("BB", 0x1D, cli.plrid)) end -- TODO! end local i for i=1,players.max do local plr = players[i] if plr then plr.tick(sec_current, sec_delta) end end for i=nades.head,nades.tail do if nades[i] then nades[i].tick(sec_current, sec_delta) end end nade_prune(sec_current) for i=1,#intent do intent[i].tick(sec_current, sec_delta) end return 0.005 end -- parse arguments local loose, user_toggles, user_settings = parse_commandline_options({...}) -- load map map_fname = loose[1] map_fname = map_fname or MAP_DEFAULT map_loaded = common.map_load(map_fname, "auto") common.map_set(map_loaded) intent[#intent+1] = new_intel({team = 0, iid = #intent+1}) intent[#intent+1] = new_tent({team = 0, iid = #intent+1}) intent[#intent+1] = new_intel({team = 1, iid = #intent+1}) intent[#intent+1] = new_tent({team = 1, iid = #intent+1}) do local i for i=1,4 do intent[i].spawn() end end print("pkg/base/main_server.lua loaded.")