lots of cool new features :D new master server

This commit is contained in:
Magnus Auvinen 2007-07-21 18:07:27 +00:00
parent f0e8502050
commit 9e4aea97bd
23 changed files with 872 additions and 917 deletions

View file

@ -238,6 +238,16 @@ weapons {
reloadtime 100
visual_size 96
}
rocket_backpack {
sprite_body sprites.weapons.weapon_hammer_body
sprite_cursor sprites.weapons.weapon_hammer_cursor
sprite_proj sprites.weapons.weapon_hammer_proj
recoil 10
reloadtime 100
visual_size 64
}
}
sprites {

View file

@ -91,43 +91,57 @@ function DataCompile(datafile, scriptfile, headerfile, sourcefile, outputdatafil
return {data = outputdatafile, header=headerfile, source=sourcefile}
end
--baselib = Import("src/baselib/baselib.bam")
baselib = Import("../baselib/baselib.bam")
config_name = "debug"
config_ext = ""
settings = NewSettings()
settings.cc.output = function(input, extention)
return Path("objs/" .. PathFilename(input) .. config_ext .. extention)
end
baselib_options = {}
baselib_options.settings = settings
baselib = Import("../baselib/baselib.bam", baselib_options)
baselib.apply(settings, "all")
server_settings = NewSettings()
baselib.apply(server_settings, "network")
settings.cc.debug = 1
settings.cc.optimize = 0
if family == "windows" then
settings.cc.flags = "/wd4244"
else
settings.cc.flags = "-Wall"
end
settings.cc.includes:add("src")
settings.cc.includes:add("../baselib/src/external/zlib")
serverdata = DataCompile("datasrc/teewars.ds", "datasrc/server.dts", "src/game/server/data.h", "src/game/server/data/data.cpp", "data/server.dat")
clientdata = DataCompile("datasrc/teewars.ds", "datasrc/client.dts", "src/game/client/data.h", "src/game/client/data/data.cpp", "data/client.dat")
serverdata = DataCompile("datasrc/teewars.ds", "datasrc/server.dts", "src/game/server/data.h", "src/game/server/data/server_data.cpp", "data/server.dat")
clientdata = DataCompile("datasrc/teewars.ds", "datasrc/client.dts", "src/game/client/data.h", "src/game/client/data/client_data.cpp", "data/client.dat")
engine = Compile(settings, Collect("src/engine/*.cpp"))
client = Compile(settings, Collect("src/engine/client/*.cpp", "src/engine/client/pnglite/*.c"))
server = Compile(settings, Collect("src/engine/server/*.cpp"))
game_shared = Compile(settings, Collect("src/game/*.cpp"))
game_client = Compile(settings, Collect("src/game/client/*.cpp"), clientdata.source)
game_server = Compile(settings, Collect("src/game/server/*.cpp"), serverdata.source)
editor = Compile(settings, Collect("src/editor/*.cpp"))
function build(config)
engine = Compile(settings, Collect("src/engine/*.cpp"))
client = Compile(settings, Collect("src/engine/client/*.cpp", "src/engine/client/pnglite/*.c"))
server = Compile(settings, Collect("src/engine/server/*.cpp"))
masterserver = Compile(settings, Collect("src/mastersrv/*.cpp"))
game_shared = Compile(settings, Collect("src/game/*.cpp"))
game_client = Compile(settings, Collect("src/game/client/*.cpp"), clientdata.source)
game_server = Compile(settings, Collect("src/game/server/*.cpp"), serverdata.source)
editor = Compile(settings, Collect("src/editor/*.cpp"))
crapnet = Compile(settings, Collect("src/crapnet/*.cpp"))
crapnet = Compile(settings, Collect("src/crapnet/*.cpp"))
client_exe = Link(settings, "teewars", engine, client, editor, game_shared, game_client)
server_exe = Link(server_settings, "teewars_srv", engine, server, game_shared, game_server)
-- editor_exe = Link(settings, "editor", engine, game_shared, editor)
crapnet_exe = Link(server_settings, "crapnet", crapnet)
client_exe = Link(settings, "teewars"..config_ext, engine, client, editor, game_shared, game_client)
server_exe = Link(server_settings, "teewars_srv"..config_ext, engine, server, game_shared, game_server)
masterserver_exe = Link(server_settings, "mastersrv"..config_ext, masterserver, engine)
-- editor_exe = Link(settings, "editor", engine, game_shared, editor)
crapnet_exe = Link(server_settings, "crapnet"..config_ext, crapnet)
Target(PseudoTarget("client", client_exe, clientdata.data))
Target(PseudoTarget("server", server_exe, serverdata.data))
Target(PseudoTarget("tools", crapnet_exe))
-- Target(PseudoTarget("editor", editor_exe))
Target(PseudoTarget("client", client_exe, clientdata.data))
Target(PseudoTarget("server", server_exe, serverdata.data))
Target(PseudoTarget("masterserver", masterserver_exe))
Target(PseudoTarget("tools", crapnet_exe))
-- Target(PseudoTarget("editor", editor_exe))
end
build("debug")

View file

@ -1,18 +0,0 @@
baselib = Import("../../baselib/baselib.bam")
--scheme = Import("scheme/scheme.bam")
settings = NewSettings()
baselib.use(settings)
--scheme.use(settings)
settings.cc.includes:add("include")
--settings.cc.includes:add("include/python")
--settings.cc.frameworks:add("Python")
--//settings.linker.libs:add("/opt/local/lib/python2.5/config/libpython2.5.a")
--settings.linker.frameworks:add("Python")
src = Collect("src/*.cpp")
objs = Compile(settings, src)
exe = Link(settings, "server", objs)
--Target(baselib.lib)
Target(exe)

View file

@ -1,6 +0,0 @@
#ifndef _COMMON_H
#define _COMMON_H
typedef int int32;
#endif

View file

@ -1,48 +0,0 @@
#ifndef _MASTERSERVER_H
#define _MASTERSERVER_H
#include <baselib/network.h>
#include "serverinfo.h"
using namespace baselib;
#define HEARTBEAT_SIZE 216
#define HEARTBEAT_SIGNATURE 'TWHB'
#define HEARTBEAT_LIFETIME 10
#define MAXSERVERS 1024
#define SERVERINFOOUT_SIZE 212
#define SERVERINFOHEADER_SIZE 12
#define MASTERSERVER_VERSION 0
class CMasterServer
{
CServerInfo m_Servers[MAXSERVERS];
int m_ServerCount;
socket_udp4 m_UDPSocket;
socket_tcp4 m_TCPSocket;
int m_CurrentTime;
char m_ServerListPacket[MAXSERVERS * SERVERINFOOUT_SIZE + SERVERINFOHEADER_SIZE];
int m_ServerListPacketSize;
bool m_ServerListPacketIsOld;
void ListenForServerListPolls();
void BuildServerListPacket();
void ListenForHeartBeats();
void ProcessHeartBeat(CServerInfo info);
CServerInfo *FindServerInfo(int32 ip, int32 port);
CServerInfo *GetUnusedSlot();
void CleanUpServerList();
public:
CMasterServer()
{
m_ServerCount = 0;
m_ServerListPacketIsOld = true;
}
void Init(int port);
void Shutdown();
void Tick();
};
#endif

View file

@ -1,13 +0,0 @@
#ifndef _NETWORK_H
#define _NETWORK_H
#include <cstring>
#include "common.h"
char *WriteInt32(char *buffer, int32 value);
char *WriteFixedString(char *buffer, const char *string, int strlen);
char *ReadInt32(char *buffer, int32 *value);
char *ReadFixedString(char *buffer, char *string, int strlen);
#endif

View file

@ -1,69 +0,0 @@
#ifndef _SERVERINFO_H
#define _SERVERINFO_H
#include <baselib/network.h>
#include "common.h"
#include "network.h"
class CServerInfo
{
int32 m_Version;
int32 m_IP;
int32 m_Port;
int32 m_Players;
int32 m_MaxPlayers;
char m_Name[128];
char m_Map[64];
int m_LastRefresh;
public:
int32 IP() const { return m_IP; }
int32 Port() const { return m_Port; }
int32 Players() const { return m_Players; }
int32 MaxPlayers() const { return m_MaxPlayers; };
const char *Name() const { return m_Name; }
const char *Map() const { return m_Map; }
void Refresh(int time) { m_LastRefresh = time; }
int LastRefresh() { return m_LastRefresh; }
void SetAddress(baselib::netaddr4 *addr)
{
m_IP = addr->ip[0] << 24;
m_IP |= addr->ip[1] << 16;
m_IP |= addr->ip[2] << 8;
m_IP |= addr->ip[3];
m_Port = addr->port;
}
char *Serialize(char *buffer) const
{
buffer = WriteInt32(buffer, m_Version);
buffer = WriteInt32(buffer, m_IP);
buffer = WriteInt32(buffer, m_Port);
buffer = WriteInt32(buffer, m_Players);
buffer = WriteInt32(buffer, m_MaxPlayers);
buffer = WriteFixedString(buffer, m_Name, sizeof(m_Name));
buffer = WriteFixedString(buffer, m_Map, sizeof(m_Map));
return buffer;
}
char *Deserialize(char *buffer)
{
buffer = ReadInt32(buffer, &m_Version);
buffer = ReadInt32(buffer, &m_IP);
buffer = ReadInt32(buffer, &m_Port);
buffer = ReadInt32(buffer, &m_Players);
buffer = ReadInt32(buffer, &m_MaxPlayers);
buffer = ReadFixedString(buffer, m_Name, sizeof(m_Name));
buffer = ReadFixedString(buffer, m_Map, sizeof(m_Map));
return buffer;
}
};
#endif

View file

@ -1,29 +0,0 @@
#include <cstdio>
#include <cstdlib>
#include "masterserver.h"
int main(int argc, char *argv[])
{
if (argc != 2)
{
puts("Usage: masterserver <port> (this will bind the server to the port specified (both udp and tcp).");
return -1;
}
int port = atoi(argv[1]);
CMasterServer masterServer;
masterServer.Init(port);
while (1)
{
masterServer.Tick();
thread_sleep(10);
}
masterServer.Shutdown();
return 0;
}

View file

@ -1,176 +0,0 @@
#include <ctime>
#include "masterserver.h"
void CMasterServer::Init(int port)
{
netaddr4 addr(0, 0, 0, 0, port);
addr.port = port;
net_init();
m_UDPSocket.open(port);
m_TCPSocket.open(&addr);
m_TCPSocket.set_non_blocking();
m_TCPSocket.listen();
}
void CMasterServer::Shutdown()
{
m_UDPSocket.close();
}
void CMasterServer::Tick()
{
m_CurrentTime = time(NULL);
ListenForHeartBeats();
ListenForServerListPolls();
CleanUpServerList();
}
void CMasterServer::ListenForHeartBeats()
{
netaddr4 from;
char data[1024];
int dataSize;
// read udp data while there is data to read :)
while ((dataSize = m_UDPSocket.recv(&from, (char *)data, sizeof(data))) > 0)
{
// compare the received data size to the expected size
if (dataSize == HEARTBEAT_SIZE)
{
char *d = data;
int32 signature;
d = ReadInt32(d, &signature);
// make sure the signature is correct
if (signature == HEARTBEAT_SIGNATURE)
{
CServerInfo info;
info.Deserialize(d);
from.port = 8303;
info.SetAddress(&from);
dbg_msg("got heartbeat", "IP: %i.%i.%i.%i:%i", (int)from.ip[0], (int)from.ip[1], (int)from.ip[2], (int)from.ip[3], from.port);
dbg_msg("refresh", "okay. server count: %i", m_ServerCount);
ProcessHeartBeat(info);
}
else
{} // unexpected signature
}
else
{} // unknown data received
}
}
void CMasterServer::ProcessHeartBeat(CServerInfo info)
{
// find the corresponding server info
CServerInfo *serverInfo = FindServerInfo(info.IP(), info.Port());
// if it isn't in the list already, try to get an unused slot
if (!serverInfo)
serverInfo = GetUnusedSlot();
// if we STILL don't have one, we're out of luck.
if (!serverInfo)
return;
*serverInfo = info;
serverInfo->Refresh(m_CurrentTime);
// mark the server list packet as old
m_ServerListPacketIsOld = true;
}
CServerInfo *CMasterServer::FindServerInfo(int32 ip, int32 port)
{
// for now, just loop over the array
for (int i = 0; i < m_ServerCount; i++)
{
CServerInfo *info = &m_Servers[i];
if (info->IP() == ip && info->Port() == port)
return info;
}
return 0x0;
}
CServerInfo *CMasterServer::GetUnusedSlot()
{
if (m_ServerCount == MAXSERVERS)
return 0x0;
else
return &m_Servers[m_ServerCount++];
}
void CMasterServer::CleanUpServerList()
{
for (int i = 0; i < m_ServerCount; i++)
{
CServerInfo *serverInfo = &m_Servers[i];
// check if it's time to remove it from the list
if (serverInfo->LastRefresh() + HEARTBEAT_LIFETIME < m_CurrentTime)
{
if (i + 1 == m_ServerCount)
{
// if we're at the last one, just decrease m_ServerCount
--m_ServerCount;
}
else
{
// otherwise, copy the last slot here and then decrease i and m_ServerCount
*serverInfo = m_Servers[m_ServerCount - 1];
--i;
--m_ServerCount;
}
// mark the server list packet as old and outdated
m_ServerListPacketIsOld = true;
}
}
}
void CMasterServer::ListenForServerListPolls()
{
socket_tcp4 client;
// accept clients while there are clients to be accepted
while (m_TCPSocket.accept(&client))
{
// maybe we've prepared the packet already... it'd be silly to do it twice
if (m_ServerListPacketIsOld)
{
BuildServerListPacket();
}
// send the server list and then close the socket
client.send(m_ServerListPacket, m_ServerListPacketSize);
client.close();
}
}
void CMasterServer::BuildServerListPacket()
{
char *d = m_ServerListPacket;
d = WriteInt32(d, 'TWSL');
d = WriteInt32(d, MASTERSERVER_VERSION);
d = WriteInt32(d, m_ServerCount);
for (int i = 0; i < m_ServerCount; i++)
{
CServerInfo *info = &m_Servers[i];
d = info->Serialize(d);
}
m_ServerListPacketSize = d - m_ServerListPacket;
m_ServerListPacketIsOld = false;
}

View file

@ -1,39 +0,0 @@
#include <cstring>
#include "common.h"
#include "network.h"
char *WriteInt32(char *buffer, int32 value)
{
buffer[0] = value >> 24;
buffer[1] = value >> 16;
buffer[2] = value >> 8;
buffer[3] = value;
return buffer + sizeof(int32);
}
char *WriteFixedString(char *buffer, const char *string, int strlen)
{
memcpy(buffer, string, strlen);
return buffer + strlen;
}
char *ReadInt32(char *buffer, int32 *value)
{
*value = buffer[0] << 24;
*value |= buffer[1] << 16;
*value |= buffer[2] << 8;
*value |= buffer[3];
return buffer + sizeof(int32);
}
char *ReadFixedString(char *buffer, char *string, int strlen)
{
memcpy(string, buffer, strlen);
return buffer + strlen;
}

View file

@ -476,7 +476,7 @@ class translator:
#include <stdio.h>
#include <stdlib.h>
void patch_ptr(char **ptr, char *base)
static void patch_ptr(char **ptr, char *base)
{
*ptr = base+(size_t)(*ptr);
}

View file

@ -20,6 +20,8 @@
#include <engine/config.h>
#include <engine/network.h>
#include <mastersrv/mastersrv.h>
using namespace baselib;
// --- input wrappers ---
@ -156,15 +158,92 @@ int client_send_msg()
return 0;
}
static struct
{
server_info infos[MAX_SERVERS];
int64 request_times[MAX_SERVERS];
netaddr4 addresses[MAX_SERVERS];
int num;
} servers;
static netaddr4 master_server;
int client_serverbrowse_getlist(server_info **serverlist)
{
*serverlist = servers.infos;
return servers.num;
}
void client_serverbrowse_refresh()
{
dbg_msg("client", "requesting server list");
NETPACKET packet;
packet.client_id = -1;
packet.address = master_server;
packet.flags = PACKETFLAG_CONNLESS;
packet.data_size = sizeof(SERVERBROWSE_GETLIST);
packet.data = SERVERBROWSE_GETLIST;
net.send(&packet);
// reset the list
servers.num = 0;
}
enum
{
STATE_OFFLINE,
STATE_CONNECTING,
STATE_LOADING,
STATE_ONLINE,
STATE_BROKEN,
STATE_QUIT,
};
static netaddr4 server_address;
static int state;
static int get_state() { return state; }
static void set_state(int s)
{
dbg_msg("game", "state change. last=%d current=%d", state, s);
state = s;
}
void client_connect(const char *server_address_str)
{
char buf[512];
strncpy(buf, server_address_str, 512);
const char *port_str = 0;
for(int k = 0; buf[k]; k++)
{
if(buf[k] == ':')
{
port_str = &(buf[k+1]);
buf[k] = 0;
break;
}
}
int port = 8303;
if(port_str)
port = atoi(port_str);
if(net_host_lookup(buf, port, &server_address) != 0)
dbg_msg("client", "could not find the address of %s, connecting to localhost", buf);
net.connect(&server_address);
set_state(STATE_CONNECTING);
}
// --- client ---
// TODO: remove this class
class client
{
public:
//socket_udp4 socket;
//connection conn;
int64 reconnect_timer;
int info_request_begin;
int info_request_end;
int snapshot_part;
@ -173,24 +252,6 @@ public:
// data to hold three snapshots
// previous,
enum
{
STATE_OFFLINE,
STATE_CONNECTING,
STATE_LOADING,
STATE_ONLINE,
STATE_BROKEN,
STATE_QUIT,
};
int state;
int get_state() { return state; }
void set_state(int s)
{
dbg_msg("game", "state change. last=%d current=%d", state, s);
state = s;
}
void send_info()
{
recived_snapshots = 0;
@ -242,12 +303,6 @@ public:
map_unload();
}
void connect(netaddr4 *server_address)
{
net.connect(server_address);
set_state(STATE_CONNECTING);
}
bool load_data()
{
debug_font = gfx_load_texture("data/debug_font.png");
@ -293,13 +348,11 @@ public:
}
else if (get_state() != STATE_CONNECTING && get_state() != STATE_LOADING)
{
netaddr4 server_address;
int status = modmenu_render(&server_address);
//netaddr4 server_address;
int status = modmenu_render();
if (status == -1)
set_state(STATE_QUIT);
else if (status)
connect(&server_address);
}
else if (get_state() == STATE_CONNECTING || get_state() == STATE_LOADING)
{
@ -332,7 +385,7 @@ public:
}
}
void run(netaddr4 *server_address)
void run(const char *direct_connect_server)
{
local_start_time = time_get();
snapshot_part = 0;
@ -356,20 +409,16 @@ public:
// init menu
modmenu_init();
net.open(0);
// open socket
/*
if(!socket.open(0))
{
dbg_msg("network/client", "failed to open socket");
return;
}*/
net.open(0, 0);
//
net_host_lookup(MASTERSERVER_ADDRESS, MASTERSERVER_PORT, &master_server);
// connect to the server if wanted
if(server_address)
connect(server_address);
if(direct_connect_server)
client_connect(direct_connect_server);
//int64 inputs_per_second = 50;
//int64 time_per_input = time_freq()/inputs_per_second;
int64 game_starttime = time_get();
@ -413,6 +462,9 @@ public:
// pump the network
pump_network();
// update the server browser
serverbrowse_update();
// render
render();
@ -457,146 +509,235 @@ public:
send_error(msg);
set_state(STATE_BROKEN);
}
void serverbrowse_request(int id)
{
dbg_msg("client", "requesting server info from %d.%d.%d.%d:%d",
servers.addresses[id].ip[0], servers.addresses[id].ip[1], servers.addresses[id].ip[2],
servers.addresses[id].ip[3], servers.addresses[id].port);
NETPACKET packet;
packet.client_id = -1;
packet.address = servers.addresses[id];
packet.flags = PACKETFLAG_CONNLESS;
packet.data_size = sizeof(SERVERBROWSE_GETINFO);
packet.data = SERVERBROWSE_GETINFO;
net.send(&packet);
servers.request_times[id] = time_get();
}
void serverbrowse_update()
{
int64 timeout = time_freq();
int64 now = time_get();
int max_requests = 10;
// timeout old requests
while(info_request_begin < servers.num && info_request_begin < info_request_end)
{
if(now > servers.request_times[info_request_begin]+timeout)
info_request_begin++;
else
break;
}
// send new requests
while(info_request_end < servers.num && info_request_end-info_request_begin < max_requests)
{
serverbrowse_request(info_request_end);
info_request_end++;
}
}
void process_packet(NETPACKET *packet)
{
int sys;
int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
if(sys)
if(packet->client_id == -1)
{
// system message
if(msg == NETMSG_MAP)
// connectionlesss
if(packet->data_size >= (int)sizeof(SERVERBROWSE_LIST) &&
memcmp(packet->data, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST)) == 0)
{
const char *map = msg_unpack_string();
dbg_msg("client/network", "connection accepted, map=%s", map);
set_state(STATE_LOADING);
if(map_load(map))
// server listing
int size = packet->data_size-sizeof(SERVERBROWSE_LIST);
mem_copy(servers.addresses, (char*)packet->data+sizeof(SERVERBROWSE_LIST), size);
servers.num = size/sizeof(NETADDR4);
info_request_begin = 0;
info_request_end = 0;
for(int i = 0; i < servers.num; i++)
{
modc_entergame();
send_entergame();
dbg_msg("client/network", "loading done");
// now we will wait for two snapshots
// to finish the connection
}
else
{
error("failure to load map");
servers.infos[i].num_players = 0;
servers.infos[i].max_players = 0;
servers.infos[i].latency = 999;
sprintf(servers.infos[i].address, "%d.%d.%d.%d:%d",
servers.addresses[i].ip[0], servers.addresses[i].ip[1], servers.addresses[i].ip[2],
servers.addresses[i].ip[3], servers.addresses[i].port);
}
}
else if(msg == NETMSG_SNAP || msg == NETMSG_SNAPSMALL || msg == NETMSG_SNAPEMPTY)
if(packet->data_size >= (int)sizeof(SERVERBROWSE_INFO) &&
memcmp(packet->data, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO)) == 0)
{
//dbg_msg("client/network", "got snapshot");
int game_tick = msg_unpack_int();
int delta_tick = game_tick-msg_unpack_int();
int num_parts = 1;
int part = 0;
int part_size = 0;
// we got ze info
data_unpacker unpacker;
unpacker.reset((unsigned char*)packet->data+sizeof(SERVERBROWSE_INFO), packet->data_size-sizeof(SERVERBROWSE_INFO));
if(msg == NETMSG_SNAP)
for(int i = 0; i < servers.num; i++)
{
num_parts = msg_unpack_int();
part = msg_unpack_int();
}
if(msg != NETMSG_SNAPEMPTY)
part_size = msg_unpack_int();
if(snapshot_part == part)
{
// TODO: clean this up abit
const char *d = (const char *)msg_unpack_raw(part_size);
mem_copy((char*)snapshots[SNAP_INCOMMING] + part*MAX_SNAPSHOT_PACKSIZE, d, part_size);
snapshot_part++;
if(snapshot_part == num_parts)
if(net_addr4_cmp(&servers.addresses[i], &packet->address) == 0)
{
snapshot *tmp = snapshots[SNAP_PREV];
snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
snapshots[SNAP_CURRENT] = tmp;
current_tick = game_tick;
// decompress snapshot
void *deltadata = snapshot_empty_delta();
int deltasize = sizeof(int)*3;
unsigned char tmpbuffer[MAX_SNAPSHOT_SIZE];
unsigned char tmpbuffer2[MAX_SNAPSHOT_SIZE];
if(part_size)
{
int compsize = zerobit_decompress(snapshots[SNAP_INCOMMING], part_size, tmpbuffer);
int intsize = intpack_decompress(tmpbuffer, compsize, tmpbuffer2);
deltadata = tmpbuffer2;
deltasize = intsize;
}
// find snapshot that we should use as delta
static snapshot emptysnap;
emptysnap.data_size = 0;
emptysnap.num_items = 0;
snapshot *deltashot = &emptysnap;
int deltashot_size;
if(delta_tick >= 0)
{
void *delta_data;
deltashot_size = snapshots_new.get(delta_tick, &delta_data);
if(deltashot_size >= 0)
{
deltashot = (snapshot *)delta_data;
}
else
{
// TODO: handle this
dbg_msg("client", "error, couldn't find the delta snapshot");
}
}
int snapsize = snapshot_unpack_delta(deltashot, (snapshot*)snapshots[SNAP_CURRENT], deltadata, deltasize);
//snapshot *shot = (snapshot *)snapshots[SNAP_CURRENT];
// purge old snapshots
snapshots_new.purge_until(delta_tick);
snapshots_new.purge_until(game_tick-50); // TODO: change this to server tickrate
// add new
snapshots_new.add(game_tick, snapsize, snapshots[SNAP_CURRENT]);
// apply snapshot, cycle pointers
recived_snapshots++;
snapshot_start_time = time_get();
// we got two snapshots until we see us self as connected
if(recived_snapshots == 2)
{
local_start_time = time_get();
set_state(STATE_ONLINE);
}
if(recived_snapshots > 2)
modc_newsnapshot();
snapshot_part = 0;
// ack snapshot
msg_pack_start_system(NETMSG_SNAPACK, 0);
msg_pack_int(game_tick);
msg_pack_end();
client_send_msg();
strncpy(servers.infos[i].name, unpacker.get_string(), 128);
strncpy(servers.infos[i].map, unpacker.get_string(), 128);
servers.infos[i].max_players = unpacker.get_int();
servers.infos[i].num_players = unpacker.get_int();
servers.infos[i].latency = ((time_get() - servers.request_times[i])*1000)/time_freq();
dbg_msg("client", "got server info");
break;
}
}
else
{
dbg_msg("client", "snapshot reset!");
snapshot_part = 0;
}
}
}
else
{
// game message
modc_message(msg);
int sys;
int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
if(sys)
{
// system message
if(msg == NETMSG_MAP)
{
const char *map = msg_unpack_string();
dbg_msg("client/network", "connection accepted, map=%s", map);
set_state(STATE_LOADING);
if(map_load(map))
{
modc_entergame();
send_entergame();
dbg_msg("client/network", "loading done");
// now we will wait for two snapshots
// to finish the connection
}
else
{
error("failure to load map");
}
}
else if(msg == NETMSG_SNAP || msg == NETMSG_SNAPSMALL || msg == NETMSG_SNAPEMPTY)
{
//dbg_msg("client/network", "got snapshot");
int game_tick = msg_unpack_int();
int delta_tick = game_tick-msg_unpack_int();
int num_parts = 1;
int part = 0;
int part_size = 0;
if(msg == NETMSG_SNAP)
{
num_parts = msg_unpack_int();
part = msg_unpack_int();
}
if(msg != NETMSG_SNAPEMPTY)
part_size = msg_unpack_int();
if(snapshot_part == part)
{
// TODO: clean this up abit
const char *d = (const char *)msg_unpack_raw(part_size);
mem_copy((char*)snapshots[SNAP_INCOMMING] + part*MAX_SNAPSHOT_PACKSIZE, d, part_size);
snapshot_part++;
if(snapshot_part == num_parts)
{
snapshot *tmp = snapshots[SNAP_PREV];
snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
snapshots[SNAP_CURRENT] = tmp;
current_tick = game_tick;
// decompress snapshot
void *deltadata = snapshot_empty_delta();
int deltasize = sizeof(int)*3;
unsigned char tmpbuffer[MAX_SNAPSHOT_SIZE];
unsigned char tmpbuffer2[MAX_SNAPSHOT_SIZE];
if(part_size)
{
int compsize = zerobit_decompress(snapshots[SNAP_INCOMMING], part_size, tmpbuffer);
int intsize = intpack_decompress(tmpbuffer, compsize, tmpbuffer2);
deltadata = tmpbuffer2;
deltasize = intsize;
}
// find snapshot that we should use as delta
static snapshot emptysnap;
emptysnap.data_size = 0;
emptysnap.num_items = 0;
snapshot *deltashot = &emptysnap;
int deltashot_size;
if(delta_tick >= 0)
{
void *delta_data;
deltashot_size = snapshots_new.get(delta_tick, &delta_data);
if(deltashot_size >= 0)
{
deltashot = (snapshot *)delta_data;
}
else
{
// TODO: handle this
dbg_msg("client", "error, couldn't find the delta snapshot");
}
}
int snapsize = snapshot_unpack_delta(deltashot, (snapshot*)snapshots[SNAP_CURRENT], deltadata, deltasize);
//snapshot *shot = (snapshot *)snapshots[SNAP_CURRENT];
// purge old snapshots
snapshots_new.purge_until(delta_tick);
snapshots_new.purge_until(game_tick-50); // TODO: change this to server tickrate
// add new
snapshots_new.add(game_tick, snapsize, snapshots[SNAP_CURRENT]);
// apply snapshot, cycle pointers
recived_snapshots++;
snapshot_start_time = time_get();
// we got two snapshots until we see us self as connected
if(recived_snapshots == 2)
{
local_start_time = time_get();
set_state(STATE_ONLINE);
}
if(recived_snapshots > 2)
modc_newsnapshot();
snapshot_part = 0;
// ack snapshot
msg_pack_start_system(NETMSG_SNAPACK, 0);
msg_pack_int(game_tick);
msg_pack_end();
client_send_msg();
}
}
else
{
dbg_msg("client", "snapshot reset!");
snapshot_part = 0;
}
}
}
else
{
// game message
modc_message(msg);
}
}
}
@ -636,11 +777,8 @@ int main(int argc, char **argv)
config_reset();
config_load("teewars.cfg");
const char *direct_connect_server = 0x0;
snd_set_master_volume(config.volume / 255.0f);
netaddr4 server_address(127, 0, 0, 1, 8303);
//const char *name = "nameless jerk";
bool connect_at_once = false;
bool editor = false;
// init network, need to be done first so we can do lookups
@ -653,24 +791,7 @@ int main(int argc, char **argv)
{
// -c SERVER:PORT
i++;
const char *port_str = 0;
for(int k = 0; argv[i][k]; k++)
{
if(argv[i][k] == ':')
{
port_str = &(argv[i][k+1]);
argv[i][k] = 0;
break;
}
}
int port = 8303;
if(port_str)
port = atoi(port_str);
if(net_host_lookup(argv[i], port, &server_address) != 0)
dbg_msg("main", "could not find the address of %s, connecting to localhost", argv[i]);
else
connect_at_once = true;
direct_connect_server = argv[i];
}
else if(argv[i][0] == '-' && argv[i][1] == 'n' && argv[i][2] == 0 && argc - i > 1)
{
@ -695,7 +816,7 @@ int main(int argc, char **argv)
{
// start the client
client c;
c.run(connect_at_once ? &server_address : 0x0);
c.run(direct_connect_server);
}
return 0;
}

View file

@ -689,7 +689,7 @@ void modmenu_shutdown();
Function: modmenu_render
Called every frame to let the menu render it self.
*/
int modmenu_render(void *server_address);
int modmenu_render();
@ -752,9 +752,19 @@ float gfx_pretty_text_width(float size, const char *text);
void mods_message(int msg, int client_id);
void modc_message(int msg);
#define MASTER_SERVER_ADDRESS "master.teewars.com"
#define MASTER_SERVER_PORT 8300
struct server_info
{
int max_players;
int num_players;
int latency; // in ms
char name[128];
char map[128];
char address[128];
};
void client_connect(const char *address);
void client_serverbrowse_refresh();
int client_serverbrowse_getlist(server_info **servers);
#endif

View file

@ -18,20 +18,6 @@
unsigned char crc[2]; 6
*/
// move
static int net_addr4_cmp(const NETADDR4 *a, const NETADDR4 *b)
{
if( a->ip[0] != b->ip[0] ||
a->ip[1] != b->ip[1] ||
a->ip[2] != b->ip[2] ||
a->ip[3] != b->ip[3] ||
a->port != b->port
)
return 1;
return 0;
}
enum
{
NETWORK_VERSION = 1,
@ -51,7 +37,7 @@ enum
NETWORK_PACKETFLAG_CLOSE=0x04,
NETWORK_PACKETFLAG_VITAL=0x08,
NETWORK_PACKETFLAG_RESEND=0x10,
//NETWORK_PACKETFLAG_STATELESS=0x20,
NETWORK_PACKETFLAG_CONNLESS=0x20,
};
struct NETPACKETDATA
@ -208,7 +194,7 @@ static void conn_send(NETCONNECTION *conn, int flags, int data_size, const void
p.data_size = data_size;
p.data = (unsigned char *)data;
p.first_send_time = time_get();
if(flags&NETWORK_PACKETFLAG_VITAL)
{
// save packet if we need to resend
@ -321,7 +307,7 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETDATA *p, NETADDR4 *addr)
static void conn_update(NETCONNECTION *conn)
{
if(conn->state == NETWORK_CONNSTATE_ERROR)
if(conn->state == NETWORK_CONNSTATE_OFFLINE || conn->state == NETWORK_CONNSTATE_ERROR)
return;
// check for timeout
@ -479,58 +465,71 @@ int net_server_recv(NETSERVER *s, NETPACKET *packet)
int r = check_packet(s->recv_buffer, bytes, &data);
if(r == 0)
{
// ok packet, process it
if(data.flags == NETWORK_PACKETFLAG_CONNECT)
if(data.flags&NETWORK_PACKETFLAG_CONNLESS)
{
int found = 0;
// check if we already got this client
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
{
if(s->slots[i].conn.state != NETWORK_CONNSTATE_OFFLINE &&
net_addr4_cmp(&s->slots[i].conn.peeraddr, &addr) == 0)
{
found = 1; // silent ignore.. we got this client already
break;
}
}
// client that wants to connect
if(!found)
{
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
{
if(s->slots[i].conn.state == NETWORK_CONNSTATE_OFFLINE)
{
conn_feed(&s->slots[i].conn, &data, &addr);
found = 1;
break;
}
}
}
if(!found)
{
// TODO: send error
}
// connection less packets
packet->client_id = -1;
packet->address = addr;
packet->flags = PACKETFLAG_CONNLESS;
packet->data_size = data.data_size;
packet->data = data.data;
return 1;
}
else
{
// find matching slot
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
// ok packet, process it
if(data.flags == NETWORK_PACKETFLAG_CONNECT)
{
if(net_addr4_cmp(&s->slots[i].conn.peeraddr, &addr) == 0)
int found = 0;
// check if we already got this client
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
{
if(conn_feed(&s->slots[i].conn, &data, &addr))
if(s->slots[i].conn.state != NETWORK_CONNSTATE_OFFLINE &&
net_addr4_cmp(&s->slots[i].conn.peeraddr, &addr) == 0)
{
if(data.data_size)
found = 1; // silent ignore.. we got this client already
break;
}
}
// client that wants to connect
if(!found)
{
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
{
if(s->slots[i].conn.state == NETWORK_CONNSTATE_OFFLINE)
{
packet->client_id = i;
packet->address = addr;
packet->flags = 0;
packet->data_size = data.data_size;
packet->data = data.data;
return 1;
conn_feed(&s->slots[i].conn, &data, &addr);
found = 1;
break;
}
}
}
if(!found)
{
// TODO: send error
}
}
else
{
// find matching slot
for(int i = 0; i < NETWORK_MAX_CLIENTS; i++)
{
if(net_addr4_cmp(&s->slots[i].conn.peeraddr, &addr) == 0)
{
if(conn_feed(&s->slots[i].conn, &data, &addr))
{
if(data.data_size)
{
packet->client_id = i;
packet->address = addr;
packet->flags = 0;
packet->data_size = data.data_size;
packet->data = data.data;
return 1;
}
}
}
}
@ -540,6 +539,7 @@ int net_server_recv(NETSERVER *s, NETPACKET *packet)
else
{
// errornous packet, drop it
dbg_msg("server", "crazy packet");
}
// read header
@ -551,10 +551,27 @@ int net_server_recv(NETSERVER *s, NETPACKET *packet)
int net_server_send(NETSERVER *s, NETPACKET *packet)
{
// TODO: insert stuff for stateless stuff
dbg_assert(packet->client_id >= 0, "errornous client id");
dbg_assert(packet->client_id < NETWORK_MAX_CLIENTS, "errornous client id");
conn_send(&s->slots[packet->client_id].conn, 0, packet->data_size, packet->data);
if(packet->flags&PACKETFLAG_CONNLESS)
{
// send connectionless packet
NETPACKETDATA p;
p.ID[0] = 'T';
p.ID[1] = 'W';
p.version = NETWORK_VERSION;
p.flags = NETWORK_PACKETFLAG_CONNLESS;
p.seq = 0;
p.ack = 0;
p.crc = 0;
p.data_size = packet->data_size;
p.data = (unsigned char *)packet->data;
send_packet(s->socket, &packet->address, &p);
}
else
{
dbg_assert(packet->client_id >= 0, "errornous client id");
dbg_assert(packet->client_id < NETWORK_MAX_CLIENTS, "errornous client id");
conn_send(&s->slots[packet->client_id].conn, 0, packet->data_size, packet->data);
}
return 0;
}
@ -574,11 +591,11 @@ void net_server_stats(NETSERVER *s, NETSTATS *stats)
}
//
NETCLIENT *net_client_open(int flags)
NETCLIENT *net_client_open(int port, int flags)
{
NETCLIENT *client = (NETCLIENT *)mem_alloc(sizeof(NETCLIENT), 1);
mem_zero(client, sizeof(NETCLIENT));
client->socket = net_udp4_create(0);
client->socket = net_udp4_create(port);
conn_init(&client->conn, client->socket);
return client;
}
@ -626,23 +643,37 @@ int net_client_recv(NETCLIENT *c, NETPACKET *packet)
NETPACKETDATA data;
int r = check_packet(c->recv_buffer, bytes, &data);
if(r == 0 && conn_feed(&c->conn, &data, &addr))
{
// fill in packet
packet->client_id = 0;
packet->address = addr;
packet->flags = 0;
packet->data_size = data.data_size;
packet->data = data.data;
return 1;
}
else
{
// errornous packet, drop it
}
// read header
// do checksum
if(r == 0)
{
if(data.flags&NETWORK_PACKETFLAG_CONNLESS)
{
// connection less packets
packet->client_id = -1;
packet->address = addr;
packet->flags = PACKETFLAG_CONNLESS;
packet->data_size = data.data_size;
packet->data = data.data;
return 1;
}
else
{
if(conn_feed(&c->conn, &data, &addr))
{
// fill in packet
packet->client_id = 0;
packet->address = addr;
packet->flags = 0;
packet->data_size = data.data_size;
packet->data = data.data;
return 1;
}
else
{
// errornous packet, drop it
}
}
}
}
return 0;
@ -650,9 +681,27 @@ int net_client_recv(NETCLIENT *c, NETPACKET *packet)
int net_client_send(NETCLIENT *c, NETPACKET *packet)
{
// TODO: insert stuff for stateless stuff
dbg_assert(packet->client_id == 0, "errornous client id");
conn_send(&c->conn, 0, packet->data_size, packet->data);
if(packet->flags&PACKETFLAG_CONNLESS)
{
// send connectionless packet
NETPACKETDATA p;
p.ID[0] = 'T';
p.ID[1] = 'W';
p.version = NETWORK_VERSION;
p.flags = NETWORK_PACKETFLAG_CONNLESS;
p.seq = 0;
p.ack = 0;
p.crc = 0;
p.data_size = packet->data_size;
p.data = (unsigned char *)packet->data;
send_packet(c->socket, &packet->address, &p);
}
else
{
// TODO: insert stuff for stateless stuff
dbg_assert(packet->client_id == 0, "errornous client id");
conn_send(&c->conn, 0, packet->data_size, packet->data);
}
return 0;
}

View file

@ -28,6 +28,7 @@ enum
{
NETFLAG_ALLOWSTATELESS=1,
PACKETFLAG_VITAL=1,
PACKETFLAG_CONNLESS=2,
NETSTATE_OFFLINE=0,
NETSTATE_CONNECTING,
@ -46,7 +47,7 @@ int net_server_delclient(NETSERVER *s); // -1 when no more, else, client id
void net_server_stats(NETSERVER *s, NETSTATS *stats);
// client side
NETCLIENT *net_client_open(int flags);
NETCLIENT *net_client_open(int port, int flags);
int net_client_disconnect(NETCLIENT *c, const char *reason);
int net_client_connect(NETCLIENT *c, NETADDR4 *addr);
int net_client_recv(NETCLIENT *c, NETPACKET *packet);
@ -88,7 +89,7 @@ public:
net_client() : ptr(0) {}
~net_client() { close(); }
int open(int flags) { ptr = net_client_open(flags); return ptr != 0; }
int open(int port, int flags) { ptr = net_client_open(port, flags); return ptr != 0; }
int close() { int r = net_client_close(ptr); ptr = 0; return r; }
int connect(NETADDR4 *addr) { return net_client_connect(ptr, addr); }

View file

@ -15,6 +15,7 @@
#include <engine/network.h>
#include <engine/config.h>
#include <mastersrv/mastersrv.h>
namespace baselib {}
using namespace baselib;
@ -162,11 +163,14 @@ public:
//for(int i = 0; i < MAX_CLIENTS; i++)
//dbg_msg("network/server", "\t%d: %d", i, clients[i].state);
if (net_host_lookup(MASTER_SERVER_ADDRESS, MASTER_SERVER_PORT, &master_server) != 0)
if (net_host_lookup(MASTERSERVER_ADDRESS, MASTERSERVER_PORT, &master_server) != 0)
{
// TODO: fix me
//master_server = netaddr4(0, 0, 0, 0, 0);
}
dbg_msg("server", "masterserver = %d.%d.%d.%d:%d",
master_server.ip[0], master_server.ip[1], master_server.ip[2], master_server.ip[3], master_server.port);
mods_init();
@ -178,13 +182,15 @@ public:
lastheartbeat = 0;
int64 reporttime = time_get();
int64 reportinterval = time_freq()*3;
int reportinterval = 3;
//int64 reportinterval = time_freq()*3;
int64 simulationtime = 0;
int64 snaptime = 0;
int64 networktime = 0;
int64 totaltime = 0;
while(1)
while(true)
{
int64 t = time_get();
if(t-lasttick > time_per_tick)
@ -204,23 +210,11 @@ public:
lasttick += time_per_tick;
}
if(send_heartbeats)
//if(send_heartbeats)
{
if (t > lastheartbeat+time_per_heartbeat)
{
if (master_server.port != 0)
{
int players = 0;
for (int i = 0; i < MAX_CLIENTS; i++)
if (!clients[i].is_empty())
players++;
// TODO: fix me
netaddr4 me(127, 0, 0, 0, 8303);
//send_heartbeat(0, &me, players, MAX_CLIENTS, server_name, mapname);
}
send_heartbeat();
lastheartbeat = t+time_per_heartbeat;
}
}
@ -233,37 +227,21 @@ public:
if(reporttime < time_get())
{
int64 totaltime = simulationtime+snaptime+networktime;
dbg_msg("server/report", "sim=%.02fms snap=%.02fms net=%.02fms total=%.02fms load=%.02f%%",
simulationtime/(float)reportinterval*1000,
snaptime/(float)reportinterval*1000,
networktime/(float)reportinterval*1000,
totaltime/(float)reportinterval*1000,
(simulationtime+snaptime+networktime)/(float)reportinterval*100.0f);
unsigned sent_total=0, recv_total=0;
/*
for (int i = 0; i < MAX_CLIENTS; i++)
if (!clients[i].is_empty())
{
unsigned s,r;
clients[i].conn.counter_get(&s,&r);
clients[i].conn.counter_reset();
sent_total += s;
recv_total += r;
}
*/
dbg_msg("server/report", "biggestsnap=%d send=%d recv=%d",
biggest_snapshot, sent_total/3, recv_total/3);
(simulationtime/reportinterval)/(double)time_freq()*1000,
(snaptime/reportinterval)/(double)time_freq()*1000,
(networktime/reportinterval)/(double)time_freq()*1000,
(totaltime/reportinterval)/(double)time_freq()*1000,
(totaltime)/reportinterval/(double)time_freq()*100.0f);
simulationtime = 0;
snaptime = 0;
networktime = 0;
totaltime = 0;
reporttime += reportinterval;
reporttime += time_freq()*reportinterval;
}
totaltime += time_get()-t;
thread_sleep(1);
}
@ -382,6 +360,18 @@ public:
msg_pack_end();
server_send_msg(cid);
}
void send_heartbeat()
{
dbg_msg("server", "sending heartbeat");
NETPACKET packet;
packet.client_id = -1;
packet.address = master_server;
packet.flags = PACKETFLAG_CONNLESS;
packet.data_size = sizeof(SERVERBROWSE_HEARTBEAT);
packet.data = SERVERBROWSE_HEARTBEAT;
net.send(&packet);
}
void drop(int cid, const char *reason)
{
@ -450,6 +440,27 @@ public:
drop(clientId, "client timedout");
}
void send_serverinfo(NETADDR4 *addr)
{
dbg_msg("server", "sending heartbeat");
NETPACKET packet;
data_packer packer;
packer.reset();
packer.add_raw(SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO));
packer.add_string(server_name, 128);
packer.add_string(map_name, 128);
packer.add_int(8); // max_players
packer.add_int(0); // num_players
packet.client_id = -1;
packet.address = *addr;
packet.flags = PACKETFLAG_CONNLESS;
packet.data_size = packer.size();
packet.data = packer.data();
net.send(&packet);
}
void pump_network()
{
net.update();
@ -458,10 +469,16 @@ public:
NETPACKET packet;
while(net.recv(&packet))
{
if(packet.client_id == -1)
{
// stateless
if(packet.data_size == sizeof(SERVERBROWSE_GETINFO) &&
memcmp(packet.data, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0)
{
dbg_msg("server", "info requested");
send_serverinfo(&packet.address);
}
}
else
process_client_packet(&packet);

View file

@ -201,7 +201,7 @@ public:
{
i->pos = pos;
i->life = 0.75f;
i->dir = dir;
i->dir = dir*-1;
i->startangle = (( (float)rand()/(float)RAND_MAX) - 1.0f) * 2.0f * pi;
}
}
@ -382,7 +382,7 @@ void modc_init()
{
// load the data container
data = load_data_container("data/client.dat");
// load sounds
for(int s = 0; s < data->num_sounds; s++)
for(int i = 0; i < data->sounds[s].num_sounds; i++)
@ -505,15 +505,17 @@ static void render_projectile(obj_projectile *prev, obj_projectile *current)
gfx_quads_begin();
select_sprite(data->weapons[current->type%data->num_weapons].sprite_proj);
vec2 vel(current->vx, current->vy);
vec2 vel = mix(vec2(prev->vx, prev->vy), vec2(current->vx, current->vy), client_intratick());
vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick());
// TODO: interpolare angle aswell
if(length(vel) > 0.00001f)
gfx_quads_setrotation(get_angle(vel));
else
gfx_quads_setrotation(0);
vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick());
// TODO: do this, but nice
//temp_system.new_particle(pos, vec2(0,0), 0.3f, 14.0f, 0, 0.95f);
gfx_quads_draw(pos.x, pos.y,32,32);
gfx_quads_setrotation(0);
gfx_quads_end();
@ -898,7 +900,8 @@ void modc_render()
if(mouse_pos.x < 0)
a = a+pi;
input.angle = (int)(a*256.0f);
input.target_x = (int)mouse_pos.x; //(int)(a*256.0f);
input.target_y = (int)mouse_pos.y; //(int)(a*256.0f);
input.activeweapon = -1;
if(!chat_active)
@ -912,10 +915,8 @@ void modc_render()
input.blink = inp_key_pressed('S');
// Weapon switching
input.activeweapon = inp_key_pressed('1') ? 0 : input.activeweapon;
input.activeweapon = inp_key_pressed('2') ? 1 : input.activeweapon;
input.activeweapon = inp_key_pressed('3') ? 2 : input.activeweapon;
input.activeweapon = inp_key_pressed('4') ? 3 : input.activeweapon;
for(int i = 0; i < 8; i++)
input.activeweapon = inp_key_pressed('1'+i) ? i : input.activeweapon;
}
snap_input(&input, sizeof(input));

View file

@ -11,6 +11,7 @@
#include <baselib/system.h>
#include <baselib/input.h>
#include <baselib/network.h>
#include <baselib/math.h>
#include <engine/interface.h>
#include <engine/versions.h>
@ -22,6 +23,7 @@
#include <engine/config.h>
#include "data.h"
#include <mastersrv/mastersrv.h>
extern data_container *data;
@ -234,6 +236,7 @@ void draw_teewars_button(void *id, const char *text, int checked, float x, float
ui_do_label(x + w/2 - text_width/2, y, text, 46);
}
/*
struct server_info
{
int version;
@ -242,11 +245,10 @@ struct server_info
netaddr4 address;
char name[129];
char map[65];
};
};*/
struct server_list
{
server_info infos[10];
int active_count, info_count;
int scroll_index;
int selected_index;
@ -555,7 +557,7 @@ int do_scroll_bar_vert(void *id, float x, float y, float height, int steps, int
return r;
}
static int do_server_list(server_list *list, float x, float y, int visible_items)
static int do_server_list(float x, float y, int *scroll_index, int *selected_index, int visible_items)
{
const float spacing = 3.f;
const float item_height = 28;
@ -563,22 +565,27 @@ static int do_server_list(server_list *list, float x, float y, int visible_items
const float real_width = item_width + 20;
const float real_height = item_height * visible_items + spacing * (visible_items - 1);
server_info *servers;
int num_servers = client_serverbrowse_getlist(&servers);
int r = -1;
for (int i = 0; i < visible_items; i++)
{
int item_index = i + list->scroll_index;
if (item_index >= list->active_count);
int item_index = i + *scroll_index;
if (item_index >= num_servers)
;
//ui_do_image(empty_item_texture, x, y + i * item_height + i * spacing, item_width, item_height);
else
{
server_info *item = &list->infos[item_index];
server_info *item = &servers[item_index];
bool clicked = false;
clicked = ui_do_button(item, item->name, 0, x, y + i * item_height + i * spacing, item_width, item_height, draw_menu_button, (list->selected_index == item_index) ? (void *)1 : 0);
clicked = ui_do_button(item, item->name, 0, x, y + i * item_height + i * spacing, item_width, item_height,
draw_menu_button, (*selected_index == item_index) ? (void *)1 : 0);
char temp[64]; // plenty of extra room so we don't get sad :o
sprintf(temp, "%i/%i", item->players, item->max_players);
sprintf(temp, "%i/%i %3d", item->num_players, item->max_players, item->latency);
ui_do_label(x + 600, y + i * item_height + i * spacing, temp, item_height);
ui_do_label(x + 360, y + i * item_height + i * spacing, item->map, item_height);
@ -586,136 +593,17 @@ static int do_server_list(server_list *list, float x, float y, int visible_items
if (clicked)
{
r = item_index;
list->selected_index = item_index;
*selected_index = item_index;
}
}
}
list->scroll_index = do_scroll_bar_vert(&list->scroll_index, x + real_width - 16, y, real_height, list->active_count - visible_items, list->scroll_index);
*scroll_index = do_scroll_bar_vert(scroll_index, x + real_width - 16, y, real_height,
min(num_servers - visible_items, 0), *scroll_index);
return r;
}
static char *read_int(char *buffer, int *value)
{
*value = buffer[0] << 24;
*value |= buffer[1] << 16;
*value |= buffer[2] << 8;
*value |= buffer[3];
return buffer + 4;
}
static char *read_netaddr(char *buffer, netaddr4 *addr)
{
addr->ip[0] = *buffer++;
addr->ip[1] = *buffer++;
addr->ip[2] = *buffer++;
addr->ip[3] = *buffer++;
int port;
buffer = read_int(buffer, &port);
addr->port = port;
return buffer;
}
static void refresh_list(server_list *list)
{
netaddr4 addr;
netaddr4 me(0, 0, 0, 0, 0);
list->selected_index = -1;
if (net_host_lookup(MASTER_SERVER_ADDRESS, MASTER_SERVER_PORT, &addr) == 0)
{
socket_tcp4 sock;
sock.open(&me);
//sock.set_non_blocking();
// try and connect with a timeout of 1 second
if (sock.connect_non_blocking(&addr))
{
char data[256];
int total_received = 0;
int received;
int master_server_version = -1;
int server_count = -1;
// read header
while (total_received < 12 && (received = sock.recv(data + total_received, 12 - total_received)) > 0)
total_received += received;
// see if we have the header
if (total_received == 12)
{
int signature;
read_int(data, &signature);
// check signature
if(signature == 'TWSL')
{
read_int(data + 4, &master_server_version);
read_int(data + 8, &server_count);
// TODO: handle master server version O.o
const int server_info_size = 212;
list->active_count = 0;
for (int i = 0; i < server_count; i++)
{
total_received = 0;
// read data for a server
while (sock.is_connected() && total_received < server_info_size && (received = sock.recv(data + total_received, server_info_size - total_received)) > 0)
total_received += received;
// check if we got enough data
if (total_received == server_info_size)
{
char *d = data;
server_info *info = &list->infos[i];
d = read_int(d, &info->version);
d = read_netaddr(d, &info->address);
//dbg_msg("menu/got_serverinfo", "IP: %i.%i.%i.%i:%i", (int)info->address.ip[0], (int)info->address.ip[1], (int)info->address.ip[2], (int)info->address.ip[3], info->address.port);
d = read_int(d, &info->players);
d = read_int(d, &info->max_players);
memcpy(info->name, d, 128);
d += 128;
memcpy(info->map, d, 64);
// let's be safe.
info->name[128] = 0;
info->map[64] = 0;
++list->active_count;
}
else
break;
}
if (list->scroll_index >= list->active_count)
list->scroll_index = list->active_count - 1;
if (list->scroll_index < 0)
list->scroll_index = 0;
}
}
sock.close();
}
}
}
enum
{
SCREEN_MAIN,
@ -737,41 +625,45 @@ const float row2_y = row1_y + 40;
const float row3_y = row2_y + 40;
const float row4_y = row3_y + 40;
static int main_render(netaddr4 *server_address)
static int main_render()
{
static server_list list;
static bool inited = false;
if (!inited)
{
/*
list.info_count = 256;
list.scroll_index = 0;
list.selected_index = -1;
*/
inited = true;
refresh_list(&list);
client_serverbrowse_refresh();
}
do_server_list(&list, 20, 160, 8);
static int scoll_index = 0, selected_index = -1;
do_server_list(20, 160, &scoll_index, &selected_index, 8);
static int refresh_button, join_button, quit_button;
if (ui_do_button(&refresh_button, "Refresh", 0, 440, 420, 170, 48, draw_teewars_button))
{
refresh_list(&list);
}
client_serverbrowse_refresh();
if (list.selected_index == -1)
if (selected_index == -1)
{
ui_do_button(&join_button, "Join", 0, 620, 420, 128, 48, draw_teewars_button, (void *)1);
}
else if (ui_do_button(&join_button, "Join", 0, 620, 420, 128, 48, draw_teewars_button))
{
*server_address = list.infos[list.selected_index].address;
// *server_address = list.infos[list.selected_index].address;
server_info *servers;
int num_servers = client_serverbrowse_getlist(&servers);
dbg_msg("menu/join_button", "IP: %i.%i.%i.%i:%i", (int)server_address->ip[0], (int)server_address->ip[1], (int)server_address->ip[2], (int)server_address->ip[3], server_address->port);
client_connect(servers[selected_index].address);
//dbg_msg("menu/join_button", "IP: %i.%i.%i.%i:%i", (int)server_address->ip[0], (int)server_address->ip[1], (int)server_address->ip[2], (int)server_address->ip[3], server_address->port);
return 1;
}
@ -1123,7 +1015,7 @@ static int kerning_render()
return 0;
}
static int menu_render(netaddr4 *server_address)
static int menu_render()
{
// background color
gfx_clear(0.65f,0.78f,0.9f);
@ -1147,7 +1039,7 @@ static int menu_render(netaddr4 *server_address)
switch (screen)
{
case SCREEN_MAIN: return main_render(server_address);
case SCREEN_MAIN: return main_render();
case SCREEN_SETTINGS_GENERAL:
case SCREEN_SETTINGS_CONTROLS:
case SCREEN_SETTINGS_VIDEO:
@ -1176,7 +1068,7 @@ void modmenu_shutdown()
{
}
int modmenu_render(void *ptr)
int modmenu_render()
{
static int mouse_x = 0;
static int mouse_y = 0;
@ -1187,8 +1079,6 @@ int modmenu_render(void *ptr)
music_menu_id = snd_play(music_menu, SND_LOOP);
}
netaddr4 *server_address = (netaddr4 *)ptr;
// handle mouse movement
float mx, my;
{
@ -1214,7 +1104,7 @@ int modmenu_render(void *ptr)
}
//int r = menu_render(server_address, str, max_len);
int r = menu_render(server_address);
int r = menu_render();
// render butt ugly mouse cursor
// TODO: render nice cursor

View file

@ -58,7 +58,10 @@ struct player_input
{
int left;
int right;
int angle;
int target_x;
int target_y;
int jump;
int fire;
int hook;

View file

@ -464,7 +464,8 @@ void projectile::tick()
lifespan--;
// check player intersection as well
entity *targetplayer = (entity*)intersect_player(oldpos, pos, oldpos, powner);
vec2 new_pos;
entity *targetplayer = (entity*)intersect_player(oldpos, pos, new_pos, powner);
if(targetplayer || lifespan < 0 || col_check_point((int)pos.x, (int)pos.y))
{
if (lifespan >= 0)
@ -489,6 +490,74 @@ void projectile::snap(int snapping_client)
proj->type = type;
}
//////////////////////////////////////////////////
// projectile_backpackrocket
//////////////////////////////////////////////////
projectile_backpackrocket::projectile_backpackrocket(baselib::vec2 pos, baselib::vec2 target, int owner, entity* powner)
: projectile(WEAPON_PROJECTILETYPE_ROCKET, owner, pos, vec2(0,0), 100, powner, 0, 0, 0, -1, WEAPON_ROCKET_BACKPACK)
{
stage = 0;
start_tick = server_tick();
vel = vec2(0,-10.0f);
this->target = target;
start = pos;
midpoint = pos;
midpoint.y = target.y;
direction = normalize(target-midpoint);
deply_ticks = (int)( distance(start, midpoint)/(float)server_tickspeed() * 5.0f );
dbg_msg("rocket_bp", "%f %d", distance(start, midpoint), deply_ticks);
}
void projectile_backpackrocket::tick()
{
lifespan--;
if(!lifespan)
world.destroy_entity(this);
vec2 oldpos = pos;
if(stage == 0)
{
float time = (server_tick()-start_tick)/(float)(deply_ticks);
if(midpoint.y > start.y)
pos.y = mix(start.y, midpoint.y, 1-sinf((1-time)*pi/2));
else
pos.y = mix(start.y, midpoint.y, sinf(time*pi/2));
float a = (server_tick()-start_tick)/(float)server_tickspeed()*pi*7.5f;
vel.x = sinf(a)*30.0f;
vel.y = cosf(a)*30.0f;
if(server_tick() > start_tick+deply_ticks)
{
pos = midpoint;
direction = normalize(target-pos);
vel = vec2(0,0);
stage = 1;
}
}
else if(stage == 1)
{
vel += direction*1.5f;
vel.x = clamp(vel.x, -20.0f, 20.0f);
pos += vel;
}
// check player intersection as well
vec2 new_pos;
entity *targetplayer = (entity*)intersect_player(oldpos, pos, new_pos, powner);
if(targetplayer || lifespan < 0 || col_check_point((int)pos.x, (int)pos.y))
{
if (lifespan >= 0)
create_sound(pos, sound_impact);
create_explosion(oldpos, owner, weapon, false);
world.destroy_entity(this);
}
}
//////////////////////////////////////////////////
// player
//////////////////////////////////////////////////
@ -556,6 +625,11 @@ void player::respawn()
weapons[WEAPON_HAMMER].ammo = -1;
weapons[WEAPON_GUN].got = true;
weapons[WEAPON_GUN].ammo = 10;
// TEMP DEBUG
weapons[WEAPON_ROCKET_BACKPACK].got = true;
weapons[WEAPON_ROCKET_BACKPACK].ammo = 10;
active_weapon = WEAPON_GUN;
reload_timer = 0;
@ -620,7 +694,7 @@ void player::handle_weapons()
break;
case WEAPON_GUN:
new projectile(WEAPON_PROJECTILETYPE_GUN,
new projectile(projectile::WEAPON_PROJECTILETYPE_GUN,
client_id,
pos+vec2(0,0),
direction*30.0f,
@ -630,7 +704,7 @@ void player::handle_weapons()
create_sound(pos, SOUND_GUN_FIRE);
break;
case WEAPON_ROCKET:
new projectile(WEAPON_PROJECTILETYPE_ROCKET,
new projectile(projectile::WEAPON_PROJECTILETYPE_ROCKET,
client_id,
pos+vec2(0,0),
direction*15.0f,
@ -644,7 +718,7 @@ void player::handle_weapons()
{
float a = get_angle(direction);
a += i*0.075f;
new projectile(WEAPON_PROJECTILETYPE_SHOTGUN,
new projectile(projectile::WEAPON_PROJECTILETYPE_SHOTGUN,
client_id,
pos+vec2(0,0),
vec2(cosf(a), sinf(a))*25.0f,
@ -655,6 +729,13 @@ void player::handle_weapons()
}
create_sound(pos, SOUND_SHOTGUN_FIRE);
break;
case WEAPON_ROCKET_BACKPACK:
new projectile_backpackrocket(
pos+vec2(0,0),
pos+vec2(input.target_x,input.target_y),
client_id,
this);
break;
}
weapons[active_weapon].ammo--;
@ -662,10 +743,11 @@ void player::handle_weapons()
else
{
// click!!! click
// TODO: make sound here
}
attack_tick = server_tick();
reload_timer = 10; // make this variable depending on weapon
reload_timer = 10; // TODO: make this variable depending on weapon
}
}
}
@ -685,7 +767,7 @@ void player::tick()
// fetch some info
bool grounded = is_grounded();
direction = get_direction(input.angle);
direction = normalize(vec2(input.target_x, input.target_y));
float max_speed = grounded ? ground_control_speed : air_control_speed;
float accel = grounded ? ground_control_accel : air_control_accel;
@ -950,8 +1032,13 @@ void player::snap(int snaping_client)
player->hook_active = hook_state>0?1:0;
player->hook_x = (int)hook_pos.x;
player->hook_y = (int)hook_pos.y;
float a = atan((float)input.target_y/(float)input.target_x);
if(input.target_x < 0)
a = a+pi;
player->angle = input.angle;
player->angle = (int)(a*256.0f);
player->score = score;
}
@ -1079,15 +1166,17 @@ void create_explosion(vec2 p, int owner, int weapon, bool bnodamage)
// deal damage
entity *ents[64];
const float radius = 128.0f;
const float innerradius = 42.0f;
int num = world.find_entities(p, radius, ents, 64);
for(int i = 0; i < num; i++)
{
vec2 diff = ents[i]->pos - p;
vec2 forcedir(0,1);
if (length(diff))
forcedir = normalize(diff);
float l = length(diff);
float dmg = 5 * (1 - (l/radius));
if(l)
forcedir = normalize(diff);
l = 1-clamp((l-innerradius)/(radius-innerradius), 0.0f, 1.0f);
float dmg = 6 * l;
if((int)dmg)
ents[i]->take_damage(forcedir*dmg*2, (int)dmg, owner, weapon);
}

View file

@ -146,6 +146,10 @@ public:
enum
{
PROJECTILE_FLAGS_EXPLODE = 1 << 0,
WEAPON_PROJECTILETYPE_GUN = 0,
WEAPON_PROJECTILETYPE_ROCKET = 1,
WEAPON_PROJECTILETYPE_SHOTGUN = 2,
};
baselib::vec2 vel;
@ -166,19 +170,26 @@ public:
virtual void snap(int snapping_client);
};
class projectile_backpackrocket : public projectile
{
int stage;
int start_tick;
int deply_ticks;
baselib::vec2 target;
baselib::vec2 start;
baselib::vec2 midpoint;
baselib::vec2 direction;
public:
projectile_backpackrocket(baselib::vec2 pos, baselib::vec2 target, int owner, entity* powner);
virtual void tick();
};
// player entity
class player : public entity
{
public:
static const int phys_size = 28;
enum // what are these?
{
WEAPON_PROJECTILETYPE_GUN = 0,
WEAPON_PROJECTILETYPE_ROCKET = 1,
WEAPON_PROJECTILETYPE_SHOTGUN = 2,
};
// weapon info
struct weaponstat
{

118
src/mastersrv/mastersrv.cpp Normal file
View file

@ -0,0 +1,118 @@
#include <string.h>
#include <baselib/system.h>
#include <engine/network.h>
#include "mastersrv.h"
enum {
MTU = 1400,
EXPIRE_TIME = 90
};
static struct packet_data
{
unsigned char header[sizeof(SERVERBROWSE_LIST)];
NETADDR4 servers[MAX_SERVERS];
} data;
static int64 server_expire[MAX_SERVERS];
static int num_servers = 0;
static net_client net;
void add_server(NETADDR4 *info)
{
// see if server already exists in list
int i;
for(i = 0; i < num_servers; i++)
{
if(net_addr4_cmp(&data.servers[i], info) == 0)
{
dbg_msg("mastersrv", "updated: %d.%d.%d.%d:%d",
info->ip[0], info->ip[1], info->ip[2], info->ip[3], info->port);
server_expire[i] = time_get()+time_freq()*EXPIRE_TIME;
return;
}
}
// add server
if(num_servers == MAX_SERVERS)
{
dbg_msg("mastersrv", "error: mastersrv is full");
return;
}
dbg_msg("mastersrv", "added: %d.%d.%d.%d:%d",
info->ip[0], info->ip[1], info->ip[2], info->ip[3], info->port);
data.servers[num_servers] = *info;
server_expire[num_servers] = time_get()+time_freq()*EXPIRE_TIME;
num_servers++;
}
void purge_servers()
{
int64 now = time_get();
int i = 0;
while(i < num_servers)
{
if(server_expire[i] < now)
{
// remove server
dbg_msg("mastersrv", "expired: %d.%d.%d.%d:%d",
data.servers[i].ip[0], data.servers[i].ip[1],
data.servers[i].ip[2], data.servers[i].ip[3], data.servers[i].port);
data.servers[i] = data.servers[num_servers-1];
server_expire[i] = server_expire[num_servers-1];
num_servers--;
}
else
i++;
}
}
int main(int argc, char **argv)
{
net.open(MASTERSERVER_PORT, 0);
// TODO: check socket for errors
mem_copy(data.header, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST));
dbg_msg("mastersrv", "started");
while(1)
{
net.update();
// process packets
NETPACKET packet;
while(net.recv(&packet))
{
if(packet.data_size == sizeof(SERVERBROWSE_HEARTBEAT) &&
memcmp(packet.data, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT)) == 0)
{
// add it
add_server(&packet.address);
}
else if(packet.data_size == sizeof(SERVERBROWSE_GETLIST) &&
memcmp(packet.data, SERVERBROWSE_GETLIST, sizeof(SERVERBROWSE_GETLIST)) == 0)
{
// someone requested the list
dbg_msg("mastersrv", "requested, responding with %d servers", num_servers);
NETPACKET p;
p.client_id = -1;
p.address = packet.address;
p.flags = PACKETFLAG_CONNLESS;
p.data_size = num_servers*sizeof(NETADDR4)+sizeof(SERVERBROWSE_LIST);
p.data = &data;
net.send(&p);
}
}
// TODO: shouldn't be done every fuckin frame
purge_servers();
// be nice to the CPU
thread_sleep(1);
}
return 0;
}

19
src/mastersrv/mastersrv.h Normal file
View file

@ -0,0 +1,19 @@
static const char *MASTERSERVER_ADDRESS = "localhost";
static const int MASTERSERVER_PORT = 8383;
static const int MAX_SERVERS = 200;
/*enum {
SERVERBROWSE_NULL=0,
SERVERBROWSE_HEARTBEAT,
SERVERBROWSE_GETLIST,
SERVERBROWSE_LIST,
SERVERBROWSE_GETINFO,
SERVERBROWSE_INFO,
};*/
static const unsigned char SERVERBROWSE_HEARTBEAT[] = {255, 255, 255, 255, 'b', 'e', 'a', 't'};
static const unsigned char SERVERBROWSE_GETLIST[] = {255, 255, 255, 255, 'r', 'e', 'q', 't'};
static const unsigned char SERVERBROWSE_LIST[] = {255, 255, 255, 255, 'l', 'i', 's', 't'};
static const unsigned char SERVERBROWSE_GETINFO[] = {255, 255, 255, 255, 'g', 'i', 'e', 'f'};
static const unsigned char SERVERBROWSE_INFO[] = {255, 255, 255, 255, 'i', 'n', 'f', 'o'};