mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 01:58:19 +00:00
last of the game server clean up. now it's done
This commit is contained in:
parent
a420eb543f
commit
78c089c0ea
|
@ -1,7 +1,7 @@
|
|||
#include <new>
|
||||
#include <engine/e_server_interface.h>
|
||||
#include <engine/e_config.h>
|
||||
#include <game/server/gs_common.hpp>
|
||||
#include <game/server/gamecontext.hpp>
|
||||
|
||||
#include "character.hpp"
|
||||
#include "laser.hpp"
|
||||
|
@ -892,7 +892,7 @@ void PLAYER::on_disconnect()
|
|||
|
||||
char buf[512];
|
||||
str_format(buf, sizeof(buf), "%s has left the game", server_clientname(client_id));
|
||||
game.send_chat(-1, CHAT_ALL, buf);
|
||||
game.send_chat(-1, GAMECONTEXT::CHAT_ALL, buf);
|
||||
|
||||
dbg_msg("game", "leave player='%d:%s'", client_id, server_clientname(client_id));
|
||||
|
||||
|
@ -952,7 +952,7 @@ void PLAYER::set_team(int new_team)
|
|||
|
||||
char buf[512];
|
||||
str_format(buf, sizeof(buf), "%s joined the %s", server_clientname(client_id), game.controller->get_team_name(new_team));
|
||||
game.send_chat(-1, CHAT_ALL, buf);
|
||||
game.send_chat(-1, GAMECONTEXT::CHAT_ALL, buf);
|
||||
|
||||
kill_character();
|
||||
team = new_team;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
|
||||
#include <engine/e_server_interface.h>
|
||||
#include <game/generated/g_protocol.hpp>
|
||||
#include <game/server/gs_common.hpp>
|
||||
#include <game/server/gamecontext.hpp>
|
||||
#include "laser.hpp"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <engine/e_server_interface.h>
|
||||
#include <game/generated/g_protocol.hpp>
|
||||
#include <game/server/gs_common.hpp>
|
||||
#include <game/server/gamecontext.hpp>
|
||||
#include "pickup.hpp"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <engine/e_server_interface.h>
|
||||
#include <game/generated/g_protocol.hpp>
|
||||
#include <game/server/gs_common.hpp>
|
||||
#include <game/server/gamecontext.hpp>
|
||||
#include "projectile.hpp"
|
||||
|
||||
|
||||
|
|
28
src/game/server/entity.cpp
Normal file
28
src/game/server/entity.cpp
Normal file
|
@ -0,0 +1,28 @@
|
|||
|
||||
#include <engine/e_server_interface.h>
|
||||
#include "entity.hpp"
|
||||
#include "gamecontext.hpp"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Entity
|
||||
//////////////////////////////////////////////////
|
||||
ENTITY::ENTITY(int objtype)
|
||||
{
|
||||
this->objtype = objtype;
|
||||
pos = vec2(0,0);
|
||||
proximity_radius = 0;
|
||||
|
||||
marked_for_destroy = false;
|
||||
id = snap_new_id();
|
||||
|
||||
next_entity = 0;
|
||||
prev_entity = 0;
|
||||
prev_type_entity = 0;
|
||||
next_type_entity = 0;
|
||||
}
|
||||
|
||||
ENTITY::~ENTITY()
|
||||
{
|
||||
game.world.remove_entity(this);
|
||||
snap_free_id(id);
|
||||
}
|
49
src/game/server/eventhandler.cpp
Normal file
49
src/game/server/eventhandler.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
#include "eventhandler.hpp"
|
||||
#include "gamecontext.hpp"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Event handler
|
||||
//////////////////////////////////////////////////
|
||||
EVENTHANDLER::EVENTHANDLER()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void *EVENTHANDLER::create(int type, int size, int mask)
|
||||
{
|
||||
if(num_events == MAX_EVENTS)
|
||||
return 0;
|
||||
if(current_offset+size >= MAX_DATASIZE)
|
||||
return 0;
|
||||
|
||||
void *p = &data[current_offset];
|
||||
offsets[num_events] = current_offset;
|
||||
types[num_events] = type;
|
||||
sizes[num_events] = size;
|
||||
client_masks[num_events] = mask;
|
||||
current_offset += size;
|
||||
num_events++;
|
||||
return p;
|
||||
}
|
||||
|
||||
void EVENTHANDLER::clear()
|
||||
{
|
||||
num_events = 0;
|
||||
current_offset = 0;
|
||||
}
|
||||
|
||||
void EVENTHANDLER::snap(int snapping_client)
|
||||
{
|
||||
for(int i = 0; i < num_events; i++)
|
||||
{
|
||||
if(cmask_is_set(client_masks[i], snapping_client))
|
||||
{
|
||||
NETEVENT_COMMON *ev = (NETEVENT_COMMON *)&data[offsets[i]];
|
||||
if(distance(game.players[snapping_client].view_pos, vec2(ev->x, ev->y)) < 1500.0f)
|
||||
{
|
||||
void *d = snap_new_item(types[i], i, sizes[i]);
|
||||
mem_copy(d, &data[offsets[i]], sizes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
232
src/game/server/gamecontext.cpp
Normal file
232
src/game/server/gamecontext.cpp
Normal file
|
@ -0,0 +1,232 @@
|
|||
#include <engine/e_server_interface.h>
|
||||
#include "gamecontext.hpp"
|
||||
|
||||
GAMECONTEXT game;
|
||||
|
||||
GAMECONTEXT::GAMECONTEXT()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void GAMECONTEXT::clear()
|
||||
{
|
||||
// reset all players
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
players[i].init(-1);
|
||||
}
|
||||
|
||||
|
||||
void GAMECONTEXT::create_damageind(vec2 p, float angle, int amount)
|
||||
{
|
||||
float a = 3 * 3.14159f / 2 + angle;
|
||||
//float a = get_angle(dir);
|
||||
float s = a-pi/3;
|
||||
float e = a+pi/3;
|
||||
for(int i = 0; i < amount; i++)
|
||||
{
|
||||
float f = mix(s, e, float(i+1)/float(amount+2));
|
||||
NETEVENT_DAMAGEIND *ev = (NETEVENT_DAMAGEIND *)events.create(NETEVENTTYPE_DAMAGEIND, sizeof(NETEVENT_DAMAGEIND));
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
ev->angle = (int)(f*256.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GAMECONTEXT::create_explosion(vec2 p, int owner, int weapon, bool bnodamage)
|
||||
{
|
||||
// create the event
|
||||
NETEVENT_EXPLOSION *ev = (NETEVENT_EXPLOSION *)events.create(NETEVENTTYPE_EXPLOSION, sizeof(NETEVENT_EXPLOSION));
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
}
|
||||
|
||||
if (!bnodamage)
|
||||
{
|
||||
// deal damage
|
||||
CHARACTER *ents[64];
|
||||
float radius = 128.0f;
|
||||
float innerradius = 42.0f;
|
||||
int num = game.world.find_entities(p, radius, (ENTITY**)ents, 64, NETOBJTYPE_CHARACTER);
|
||||
for(int i = 0; i < num; i++)
|
||||
{
|
||||
vec2 diff = ents[i]->pos - p;
|
||||
vec2 forcedir(0,1);
|
||||
float l = length(diff);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void create_smoke(vec2 p)
|
||||
{
|
||||
// create the event
|
||||
EV_EXPLOSION *ev = (EV_EXPLOSION *)events.create(EVENT_SMOKE, sizeof(EV_EXPLOSION));
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
}
|
||||
}*/
|
||||
|
||||
void GAMECONTEXT::create_playerspawn(vec2 p)
|
||||
{
|
||||
// create the event
|
||||
NETEVENT_SPAWN *ev = (NETEVENT_SPAWN *)events.create(NETEVENTTYPE_SPAWN, sizeof(NETEVENT_SPAWN));
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
}
|
||||
}
|
||||
|
||||
void GAMECONTEXT::create_death(vec2 p, int cid)
|
||||
{
|
||||
// create the event
|
||||
NETEVENT_DEATH *ev = (NETEVENT_DEATH *)events.create(NETEVENTTYPE_DEATH, sizeof(NETEVENT_DEATH));
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
ev->cid = cid;
|
||||
}
|
||||
}
|
||||
|
||||
void GAMECONTEXT::create_sound(vec2 pos, int sound, int mask)
|
||||
{
|
||||
if (sound < 0)
|
||||
return;
|
||||
|
||||
// create a sound
|
||||
NETEVENT_SOUNDWORLD *ev = (NETEVENT_SOUNDWORLD *)events.create(NETEVENTTYPE_SOUNDWORLD, sizeof(NETEVENT_SOUNDWORLD), mask);
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)pos.x;
|
||||
ev->y = (int)pos.y;
|
||||
ev->soundid = sound;
|
||||
}
|
||||
}
|
||||
|
||||
void GAMECONTEXT::create_sound_global(int sound, int target)
|
||||
{
|
||||
if (sound < 0)
|
||||
return;
|
||||
|
||||
NETMSG_SV_SOUNDGLOBAL msg;
|
||||
msg.soundid = sound;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
server_send_msg(target);
|
||||
}
|
||||
|
||||
void GAMECONTEXT::send_chat(int chatter_cid, int team, const char *text)
|
||||
{
|
||||
if(chatter_cid >= 0 && chatter_cid < MAX_CLIENTS)
|
||||
dbg_msg("chat", "%d:%d:%s: %s", chatter_cid, team, server_clientname(chatter_cid), text);
|
||||
else
|
||||
dbg_msg("chat", "*** %s", text);
|
||||
|
||||
if(team == CHAT_ALL)
|
||||
{
|
||||
NETMSG_SV_CHAT msg;
|
||||
msg.team = 0;
|
||||
msg.cid = chatter_cid;
|
||||
msg.message = text;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
server_send_msg(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
NETMSG_SV_CHAT msg;
|
||||
msg.team = 1;
|
||||
msg.cid = chatter_cid;
|
||||
msg.message = text;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(game.players[i].client_id != -1 && game.players[i].team == team)
|
||||
server_send_msg(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GAMECONTEXT::send_info(int who, int to_who)
|
||||
{
|
||||
NETMSG_SV_SETINFO msg;
|
||||
msg.cid = who;
|
||||
msg.name = server_clientname(who);
|
||||
msg.skin = players[who].skin_name;
|
||||
msg.use_custom_color = players[who].use_custom_color;
|
||||
msg.color_body = players[who].color_body;
|
||||
msg.color_feet = players[who].color_feet;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
|
||||
server_send_msg(to_who);
|
||||
}
|
||||
|
||||
void GAMECONTEXT::send_emoticon(int cid, int emoticon)
|
||||
{
|
||||
NETMSG_SV_EMOTICON msg;
|
||||
msg.cid = cid;
|
||||
msg.emoticon = emoticon;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
server_send_msg(-1);
|
||||
}
|
||||
|
||||
void GAMECONTEXT::send_weapon_pickup(int cid, int weapon)
|
||||
{
|
||||
NETMSG_SV_WEAPONPICKUP msg;
|
||||
msg.weapon = weapon;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
server_send_msg(cid);
|
||||
}
|
||||
|
||||
|
||||
void GAMECONTEXT::send_broadcast(const char *text, int cid)
|
||||
{
|
||||
NETMSG_SV_BROADCAST msg;
|
||||
msg.message = text;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
server_send_msg(cid);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GAMECONTEXT::tick()
|
||||
{
|
||||
world.core.tuning = tuning;
|
||||
world.tick();
|
||||
|
||||
//if(world.paused) // make sure that the game object always updates
|
||||
controller->tick();
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(players[i].client_id != -1)
|
||||
players[i].tick();
|
||||
}
|
||||
}
|
||||
|
||||
void GAMECONTEXT::snap(int client_id)
|
||||
{
|
||||
world.snap(client_id);
|
||||
controller->snap(client_id);
|
||||
events.snap(client_id);
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(players[i].client_id != -1)
|
||||
players[i].snap(client_id);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,32 @@
|
|||
#ifndef GAME_SERVER_GAMECONTEXT_H
|
||||
#define GAME_SERVER_GAMECONTEXT_H
|
||||
|
||||
#include "eventhandler.hpp"
|
||||
#include "gamecontroller.hpp"
|
||||
#include "gameworld.hpp"
|
||||
#include "player.hpp"
|
||||
|
||||
/*
|
||||
Tick
|
||||
Game Context (GAMECONTEXT::tick)
|
||||
Game World (GAMEWORLD::tick)
|
||||
Reset world if requested (GAMEWORLD::reset)
|
||||
All entities in the world (ENTITY::tick)
|
||||
All entities in the world (ENTITY::tick_defered)
|
||||
Remove entities marked for deletion (GAMEWORLD::remove_entities)
|
||||
Game Controller (GAMECONTROLLER::tick)
|
||||
All players (PLAYER::tick)
|
||||
|
||||
|
||||
Snap
|
||||
Game Context (GAMECONTEXT::snap)
|
||||
Game World (GAMEWORLD::snap)
|
||||
All entities in the world (ENTITY::snap)
|
||||
Game Controller (GAMECONTROLLER::snap)
|
||||
Events handler (EVENT_HANDLER::snap)
|
||||
All players (PLAYER::snap)
|
||||
|
||||
*/
|
||||
|
||||
class GAMECONTEXT
|
||||
{
|
||||
|
@ -27,6 +52,15 @@ public:
|
|||
void create_sound(vec2 pos, int sound, int mask=-1);
|
||||
void create_sound_global(int sound, int target=-1);
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
CHAT_ALL=-2,
|
||||
CHAT_SPEC=-1,
|
||||
CHAT_RED=0,
|
||||
CHAT_BLUE=1
|
||||
};
|
||||
|
||||
// network
|
||||
void send_chat(int cid, int team, const char *text);
|
||||
void send_emoticon(int cid, int emoticon);
|
||||
|
@ -36,3 +70,12 @@ public:
|
|||
};
|
||||
|
||||
extern GAMECONTEXT game;
|
||||
|
||||
// MISC stuff, move to a better place later on
|
||||
|
||||
extern TUNING_PARAMS tuning;
|
||||
inline int cmask_all() { return -1; }
|
||||
inline int cmask_one(int cid) { return 1<<cid; }
|
||||
inline int cmask_all_except_one(int cid) { return 0x7fffffff^cmask_one(cid); }
|
||||
inline bool cmask_is_set(int mask, int cid) { return (mask&cmask_one(cid)) != 0; }
|
||||
#endif
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
#include <engine/e_config.h>
|
||||
#include <engine/e_server_interface.h>
|
||||
#include <game/g_mapitems.hpp>
|
||||
#include "gs_common.hpp"
|
||||
|
||||
#include <game/generated/g_protocol.hpp>
|
||||
|
||||
#include "entities/pickup.hpp"
|
||||
#include "gamecontroller.hpp"
|
||||
#include "gamecontext.hpp"
|
||||
|
||||
GAMECONTROLLER::GAMECONTROLLER()
|
||||
{
|
||||
|
|
215
src/game/server/gameworld.cpp
Normal file
215
src/game/server/gameworld.cpp
Normal file
|
@ -0,0 +1,215 @@
|
|||
|
||||
#include "gameworld.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "gamecontext.hpp"
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// game world
|
||||
//////////////////////////////////////////////////
|
||||
GAMEWORLD::GAMEWORLD()
|
||||
{
|
||||
paused = false;
|
||||
reset_requested = false;
|
||||
first_entity = 0x0;
|
||||
for(int i = 0; i < NUM_ENT_TYPES; i++)
|
||||
first_entity_types[i] = 0;
|
||||
}
|
||||
|
||||
GAMEWORLD::~GAMEWORLD()
|
||||
{
|
||||
// delete all entities
|
||||
while(first_entity)
|
||||
delete first_entity;
|
||||
}
|
||||
|
||||
ENTITY *GAMEWORLD::find_first(int type)
|
||||
{
|
||||
return first_entity_types[type];
|
||||
}
|
||||
|
||||
|
||||
int GAMEWORLD::find_entities(vec2 pos, float radius, ENTITY **ents, int max, int type)
|
||||
{
|
||||
int num = 0;
|
||||
for(ENTITY *ent = (type<0) ? first_entity : first_entity_types[type];
|
||||
ent; ent = (type<0) ? ent->next_entity : ent->next_type_entity)
|
||||
{
|
||||
if(distance(ent->pos, pos) < radius+ent->proximity_radius)
|
||||
{
|
||||
ents[num] = ent;
|
||||
num++;
|
||||
if(num == max)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
void GAMEWORLD::insert_entity(ENTITY *ent)
|
||||
{
|
||||
ENTITY *cur = first_entity;
|
||||
while(cur)
|
||||
{
|
||||
dbg_assert(cur != ent, "err");
|
||||
cur = cur->next_entity;
|
||||
}
|
||||
|
||||
// insert it
|
||||
if(first_entity)
|
||||
first_entity->prev_entity = ent;
|
||||
ent->next_entity = first_entity;
|
||||
ent->prev_entity = 0x0;
|
||||
first_entity = ent;
|
||||
|
||||
// into typelist aswell
|
||||
if(first_entity_types[ent->objtype])
|
||||
first_entity_types[ent->objtype]->prev_type_entity = ent;
|
||||
ent->next_type_entity = first_entity_types[ent->objtype];
|
||||
ent->prev_type_entity = 0x0;
|
||||
first_entity_types[ent->objtype] = ent;
|
||||
}
|
||||
|
||||
void GAMEWORLD::destroy_entity(ENTITY *ent)
|
||||
{
|
||||
ent->marked_for_destroy = true;
|
||||
}
|
||||
|
||||
void GAMEWORLD::remove_entity(ENTITY *ent)
|
||||
{
|
||||
// not in the list
|
||||
if(!ent->next_entity && !ent->prev_entity && first_entity != ent)
|
||||
return;
|
||||
|
||||
// remove
|
||||
if(ent->prev_entity)
|
||||
ent->prev_entity->next_entity = ent->next_entity;
|
||||
else
|
||||
first_entity = ent->next_entity;
|
||||
if(ent->next_entity)
|
||||
ent->next_entity->prev_entity = ent->prev_entity;
|
||||
|
||||
if(ent->prev_type_entity)
|
||||
ent->prev_type_entity->next_type_entity = ent->next_type_entity;
|
||||
else
|
||||
first_entity_types[ent->objtype] = ent->next_type_entity;
|
||||
if(ent->next_type_entity)
|
||||
ent->next_type_entity->prev_type_entity = ent->prev_type_entity;
|
||||
|
||||
ent->next_entity = 0;
|
||||
ent->prev_entity = 0;
|
||||
ent->next_type_entity = 0;
|
||||
ent->prev_type_entity = 0;
|
||||
}
|
||||
|
||||
//
|
||||
void GAMEWORLD::snap(int snapping_client)
|
||||
{
|
||||
for(ENTITY *ent = first_entity; ent; ent = ent->next_entity)
|
||||
ent->snap(snapping_client);
|
||||
}
|
||||
|
||||
void GAMEWORLD::reset()
|
||||
{
|
||||
// reset all entities
|
||||
for(ENTITY *ent = first_entity; ent; ent = ent->next_entity)
|
||||
ent->reset();
|
||||
remove_entities();
|
||||
|
||||
game.controller->post_reset();
|
||||
remove_entities();
|
||||
|
||||
reset_requested = false;
|
||||
}
|
||||
|
||||
void GAMEWORLD::remove_entities()
|
||||
{
|
||||
// destroy objects marked for destruction
|
||||
ENTITY *ent = first_entity;
|
||||
while(ent)
|
||||
{
|
||||
ENTITY *next = ent->next_entity;
|
||||
if(ent->marked_for_destroy)
|
||||
{
|
||||
remove_entity(ent);
|
||||
ent->destroy();
|
||||
}
|
||||
ent = next;
|
||||
}
|
||||
}
|
||||
|
||||
void GAMEWORLD::tick()
|
||||
{
|
||||
if(reset_requested)
|
||||
reset();
|
||||
|
||||
if(!paused)
|
||||
{
|
||||
// update all objects
|
||||
for(ENTITY *ent = first_entity; ent; ent = ent->next_entity)
|
||||
ent->tick();
|
||||
|
||||
for(ENTITY *ent = first_entity; ent; ent = ent->next_entity)
|
||||
ent->tick_defered();
|
||||
}
|
||||
|
||||
remove_entities();
|
||||
}
|
||||
|
||||
|
||||
// TODO: should be more general
|
||||
CHARACTER *GAMEWORLD::intersect_character(vec2 pos0, vec2 pos1, float radius, vec2& new_pos, ENTITY *notthis)
|
||||
{
|
||||
// Find other players
|
||||
float closest_len = distance(pos0, pos1) * 100.0f;
|
||||
vec2 line_dir = normalize(pos1-pos0);
|
||||
CHARACTER *closest = 0;
|
||||
|
||||
CHARACTER *p = (CHARACTER *)game.world.find_first(NETOBJTYPE_CHARACTER);
|
||||
for(; p; p = (CHARACTER *)p->typenext())
|
||||
{
|
||||
if(p == notthis)
|
||||
continue;
|
||||
|
||||
vec2 intersect_pos = closest_point_on_line(pos0, pos1, p->pos);
|
||||
float len = distance(p->pos, intersect_pos);
|
||||
if(len < CHARACTER::phys_size+radius)
|
||||
{
|
||||
if(len < closest_len)
|
||||
{
|
||||
new_pos = intersect_pos;
|
||||
closest_len = len;
|
||||
closest = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
|
||||
CHARACTER *GAMEWORLD::closest_character(vec2 pos, float radius, ENTITY *notthis)
|
||||
{
|
||||
// Find other players
|
||||
float closest_range = radius*2;
|
||||
CHARACTER *closest = 0;
|
||||
|
||||
CHARACTER *p = (CHARACTER *)game.world.find_first(NETOBJTYPE_CHARACTER);
|
||||
for(; p; p = (CHARACTER *)p->typenext())
|
||||
{
|
||||
if(p == notthis)
|
||||
continue;
|
||||
|
||||
float len = distance(pos, p->pos);
|
||||
if(len < CHARACTER::phys_size+radius)
|
||||
{
|
||||
if(len < closest_range)
|
||||
{
|
||||
closest_range = len;
|
||||
closest = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
|
@ -1,4 +1,9 @@
|
|||
#ifndef GAME_SERVER_GAMEWORLD_H
|
||||
#define GAME_SERVER_GAMEWORLD_H
|
||||
|
||||
#include <game/g_game.hpp>
|
||||
|
||||
class ENTITY;
|
||||
class CHARACTER;
|
||||
|
||||
/*
|
||||
|
@ -124,3 +129,5 @@ public:
|
|||
*/
|
||||
void tick();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
|
||||
#include "../g_game.hpp"
|
||||
#include "../generated/gs_data.hpp"
|
||||
|
||||
extern TUNING_PARAMS tuning;
|
||||
|
||||
inline int cmask_all() { return -1; }
|
||||
inline int cmask_one(int cid) { return 1<<cid; }
|
||||
inline int cmask_all_except_one(int cid) { return 0x7fffffff^cmask_one(cid); }
|
||||
inline bool cmask_is_set(int mask, int cid) { return (mask&cmask_one(cid)) != 0; }
|
||||
|
||||
/*
|
||||
Tick
|
||||
Game Context (GAMECONTEXT::tick)
|
||||
Game World (GAMEWORLD::tick)
|
||||
Reset world if requested (GAMEWORLD::reset)
|
||||
All entities in the world (ENTITY::tick)
|
||||
All entities in the world (ENTITY::tick_defered)
|
||||
Remove entities marked for deletion (GAMEWORLD::remove_entities)
|
||||
Game Controller (GAMECONTROLLER::tick)
|
||||
All players (PLAYER::tick)
|
||||
|
||||
|
||||
Snap
|
||||
Game Context (GAMECONTEXT::snap)
|
||||
Game World (GAMEWORLD::snap)
|
||||
All entities in the world (ENTITY::snap)
|
||||
Game Controller (GAMECONTROLLER::snap)
|
||||
Events handler (EVENT_HANDLER::snap)
|
||||
All players (PLAYER::snap)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "eventhandler.hpp"
|
||||
|
||||
#include "entity.hpp"
|
||||
|
||||
|
||||
#include "gamecontroller.hpp"
|
||||
#include "entities/character.hpp"
|
||||
#include "player.hpp"
|
||||
#include "gamecontext.hpp"
|
||||
|
||||
enum
|
||||
{
|
||||
CHAT_ALL=-2,
|
||||
CHAT_SPEC=-1,
|
||||
CHAT_RED=0,
|
||||
CHAT_BLUE=1
|
||||
};
|
|
@ -1,887 +0,0 @@
|
|||
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <base/math.hpp>
|
||||
|
||||
#include <engine/e_config.h>
|
||||
#include <engine/e_server_interface.h>
|
||||
#include <game/g_version.hpp>
|
||||
#include <game/g_collision.hpp>
|
||||
#include <game/g_layers.hpp>
|
||||
#include "gs_common.hpp"
|
||||
|
||||
#include "gamemodes/dm.hpp"
|
||||
#include "gamemodes/tdm.hpp"
|
||||
#include "gamemodes/ctf.hpp"
|
||||
|
||||
TUNING_PARAMS tuning;
|
||||
GAMECONTEXT game;
|
||||
|
||||
void GAMECONTEXT::send_chat(int chatter_cid, int team, const char *text)
|
||||
{
|
||||
if(chatter_cid >= 0 && chatter_cid < MAX_CLIENTS)
|
||||
dbg_msg("chat", "%d:%d:%s: %s", chatter_cid, team, server_clientname(chatter_cid), text);
|
||||
else
|
||||
dbg_msg("chat", "*** %s", text);
|
||||
|
||||
if(team == CHAT_ALL)
|
||||
{
|
||||
NETMSG_SV_CHAT msg;
|
||||
msg.team = 0;
|
||||
msg.cid = chatter_cid;
|
||||
msg.message = text;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
server_send_msg(-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
NETMSG_SV_CHAT msg;
|
||||
msg.team = 1;
|
||||
msg.cid = chatter_cid;
|
||||
msg.message = text;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(game.players[i].client_id != -1 && game.players[i].team == team)
|
||||
server_send_msg(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GAMECONTEXT::send_info(int who, int to_who)
|
||||
{
|
||||
NETMSG_SV_SETINFO msg;
|
||||
msg.cid = who;
|
||||
msg.name = server_clientname(who);
|
||||
msg.skin = players[who].skin_name;
|
||||
msg.use_custom_color = players[who].use_custom_color;
|
||||
msg.color_body = players[who].color_body;
|
||||
msg.color_feet = players[who].color_feet;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
|
||||
server_send_msg(to_who);
|
||||
}
|
||||
|
||||
void GAMECONTEXT::send_emoticon(int cid, int emoticon)
|
||||
{
|
||||
NETMSG_SV_EMOTICON msg;
|
||||
msg.cid = cid;
|
||||
msg.emoticon = emoticon;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
server_send_msg(-1);
|
||||
}
|
||||
|
||||
void GAMECONTEXT::send_weapon_pickup(int cid, int weapon)
|
||||
{
|
||||
NETMSG_SV_WEAPONPICKUP msg;
|
||||
msg.weapon = weapon;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
server_send_msg(cid);
|
||||
}
|
||||
|
||||
|
||||
void GAMECONTEXT::send_broadcast(const char *text, int cid)
|
||||
{
|
||||
NETMSG_SV_BROADCAST msg;
|
||||
msg.message = text;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
server_send_msg(cid);
|
||||
}
|
||||
|
||||
void send_tuning_params(int cid)
|
||||
{
|
||||
/*
|
||||
msg_pack_start(NETMSGTYPE_SV_TUNE_PARAMS, MSGFLAG_VITAL);
|
||||
int *params = (int *)&tuning;
|
||||
for(unsigned i = 0; i < sizeof(tuning_params)/sizeof(int); i++)
|
||||
msg_pack_int(params[i]);
|
||||
msg_pack_end();
|
||||
server_send_msg(cid);
|
||||
*/
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Event handler
|
||||
//////////////////////////////////////////////////
|
||||
EVENTHANDLER::EVENTHANDLER()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void *EVENTHANDLER::create(int type, int size, int mask)
|
||||
{
|
||||
if(num_events == MAX_EVENTS)
|
||||
return 0;
|
||||
if(current_offset+size >= MAX_DATASIZE)
|
||||
return 0;
|
||||
|
||||
void *p = &data[current_offset];
|
||||
offsets[num_events] = current_offset;
|
||||
types[num_events] = type;
|
||||
sizes[num_events] = size;
|
||||
client_masks[num_events] = mask;
|
||||
current_offset += size;
|
||||
num_events++;
|
||||
return p;
|
||||
}
|
||||
|
||||
void EVENTHANDLER::clear()
|
||||
{
|
||||
num_events = 0;
|
||||
current_offset = 0;
|
||||
}
|
||||
|
||||
void EVENTHANDLER::snap(int snapping_client)
|
||||
{
|
||||
for(int i = 0; i < num_events; i++)
|
||||
{
|
||||
if(cmask_is_set(client_masks[i], snapping_client))
|
||||
{
|
||||
NETEVENT_COMMON *ev = (NETEVENT_COMMON *)&data[offsets[i]];
|
||||
if(distance(game.players[snapping_client].view_pos, vec2(ev->x, ev->y)) < 1500.0f)
|
||||
{
|
||||
void *d = snap_new_item(types[i], i, sizes[i]);
|
||||
mem_copy(d, &data[offsets[i]], sizes[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Entity
|
||||
//////////////////////////////////////////////////
|
||||
ENTITY::ENTITY(int objtype)
|
||||
{
|
||||
this->objtype = objtype;
|
||||
pos = vec2(0,0);
|
||||
proximity_radius = 0;
|
||||
|
||||
marked_for_destroy = false;
|
||||
id = snap_new_id();
|
||||
|
||||
next_entity = 0;
|
||||
prev_entity = 0;
|
||||
prev_type_entity = 0;
|
||||
next_type_entity = 0;
|
||||
}
|
||||
|
||||
ENTITY::~ENTITY()
|
||||
{
|
||||
game.world.remove_entity(this);
|
||||
snap_free_id(id);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// game world
|
||||
//////////////////////////////////////////////////
|
||||
GAMEWORLD::GAMEWORLD()
|
||||
{
|
||||
paused = false;
|
||||
reset_requested = false;
|
||||
first_entity = 0x0;
|
||||
for(int i = 0; i < NUM_ENT_TYPES; i++)
|
||||
first_entity_types[i] = 0;
|
||||
}
|
||||
|
||||
GAMEWORLD::~GAMEWORLD()
|
||||
{
|
||||
// delete all entities
|
||||
while(first_entity)
|
||||
delete first_entity;
|
||||
}
|
||||
|
||||
ENTITY *GAMEWORLD::find_first(int type)
|
||||
{
|
||||
return first_entity_types[type];
|
||||
}
|
||||
|
||||
|
||||
int GAMEWORLD::find_entities(vec2 pos, float radius, ENTITY **ents, int max, int type)
|
||||
{
|
||||
int num = 0;
|
||||
for(ENTITY *ent = (type<0) ? first_entity : first_entity_types[type];
|
||||
ent; ent = (type<0) ? ent->next_entity : ent->next_type_entity)
|
||||
{
|
||||
if(distance(ent->pos, pos) < radius+ent->proximity_radius)
|
||||
{
|
||||
ents[num] = ent;
|
||||
num++;
|
||||
if(num == max)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
void GAMEWORLD::insert_entity(ENTITY *ent)
|
||||
{
|
||||
ENTITY *cur = first_entity;
|
||||
while(cur)
|
||||
{
|
||||
dbg_assert(cur != ent, "err");
|
||||
cur = cur->next_entity;
|
||||
}
|
||||
|
||||
// insert it
|
||||
if(first_entity)
|
||||
first_entity->prev_entity = ent;
|
||||
ent->next_entity = first_entity;
|
||||
ent->prev_entity = 0x0;
|
||||
first_entity = ent;
|
||||
|
||||
// into typelist aswell
|
||||
if(first_entity_types[ent->objtype])
|
||||
first_entity_types[ent->objtype]->prev_type_entity = ent;
|
||||
ent->next_type_entity = first_entity_types[ent->objtype];
|
||||
ent->prev_type_entity = 0x0;
|
||||
first_entity_types[ent->objtype] = ent;
|
||||
}
|
||||
|
||||
void GAMEWORLD::destroy_entity(ENTITY *ent)
|
||||
{
|
||||
ent->marked_for_destroy = true;
|
||||
}
|
||||
|
||||
void GAMEWORLD::remove_entity(ENTITY *ent)
|
||||
{
|
||||
// not in the list
|
||||
if(!ent->next_entity && !ent->prev_entity && first_entity != ent)
|
||||
return;
|
||||
|
||||
// remove
|
||||
if(ent->prev_entity)
|
||||
ent->prev_entity->next_entity = ent->next_entity;
|
||||
else
|
||||
first_entity = ent->next_entity;
|
||||
if(ent->next_entity)
|
||||
ent->next_entity->prev_entity = ent->prev_entity;
|
||||
|
||||
if(ent->prev_type_entity)
|
||||
ent->prev_type_entity->next_type_entity = ent->next_type_entity;
|
||||
else
|
||||
first_entity_types[ent->objtype] = ent->next_type_entity;
|
||||
if(ent->next_type_entity)
|
||||
ent->next_type_entity->prev_type_entity = ent->prev_type_entity;
|
||||
|
||||
ent->next_entity = 0;
|
||||
ent->prev_entity = 0;
|
||||
ent->next_type_entity = 0;
|
||||
ent->prev_type_entity = 0;
|
||||
}
|
||||
|
||||
//
|
||||
void GAMEWORLD::snap(int snapping_client)
|
||||
{
|
||||
for(ENTITY *ent = first_entity; ent; ent = ent->next_entity)
|
||||
ent->snap(snapping_client);
|
||||
}
|
||||
|
||||
void GAMEWORLD::reset()
|
||||
{
|
||||
// reset all entities
|
||||
for(ENTITY *ent = first_entity; ent; ent = ent->next_entity)
|
||||
ent->reset();
|
||||
remove_entities();
|
||||
|
||||
game.controller->post_reset();
|
||||
remove_entities();
|
||||
|
||||
reset_requested = false;
|
||||
}
|
||||
|
||||
void GAMEWORLD::remove_entities()
|
||||
{
|
||||
// destroy objects marked for destruction
|
||||
ENTITY *ent = first_entity;
|
||||
while(ent)
|
||||
{
|
||||
ENTITY *next = ent->next_entity;
|
||||
if(ent->marked_for_destroy)
|
||||
{
|
||||
remove_entity(ent);
|
||||
ent->destroy();
|
||||
}
|
||||
ent = next;
|
||||
}
|
||||
}
|
||||
|
||||
void GAMEWORLD::tick()
|
||||
{
|
||||
if(reset_requested)
|
||||
reset();
|
||||
|
||||
if(!paused)
|
||||
{
|
||||
// update all objects
|
||||
for(ENTITY *ent = first_entity; ent; ent = ent->next_entity)
|
||||
ent->tick();
|
||||
|
||||
for(ENTITY *ent = first_entity; ent; ent = ent->next_entity)
|
||||
ent->tick_defered();
|
||||
}
|
||||
|
||||
remove_entities();
|
||||
}
|
||||
|
||||
GAMECONTEXT::GAMECONTEXT()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void GAMECONTEXT::clear()
|
||||
{
|
||||
// reset all players
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
players[i].init(-1);
|
||||
}
|
||||
|
||||
|
||||
void GAMECONTEXT::create_damageind(vec2 p, float angle, int amount)
|
||||
{
|
||||
float a = 3 * 3.14159f / 2 + angle;
|
||||
//float a = get_angle(dir);
|
||||
float s = a-pi/3;
|
||||
float e = a+pi/3;
|
||||
for(int i = 0; i < amount; i++)
|
||||
{
|
||||
float f = mix(s, e, float(i+1)/float(amount+2));
|
||||
NETEVENT_DAMAGEIND *ev = (NETEVENT_DAMAGEIND *)events.create(NETEVENTTYPE_DAMAGEIND, sizeof(NETEVENT_DAMAGEIND));
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
ev->angle = (int)(f*256.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GAMECONTEXT::create_explosion(vec2 p, int owner, int weapon, bool bnodamage)
|
||||
{
|
||||
// create the event
|
||||
NETEVENT_EXPLOSION *ev = (NETEVENT_EXPLOSION *)events.create(NETEVENTTYPE_EXPLOSION, sizeof(NETEVENT_EXPLOSION));
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
}
|
||||
|
||||
if (!bnodamage)
|
||||
{
|
||||
// deal damage
|
||||
CHARACTER *ents[64];
|
||||
float radius = 128.0f;
|
||||
float innerradius = 42.0f;
|
||||
int num = game.world.find_entities(p, radius, (ENTITY**)ents, 64, NETOBJTYPE_CHARACTER);
|
||||
for(int i = 0; i < num; i++)
|
||||
{
|
||||
vec2 diff = ents[i]->pos - p;
|
||||
vec2 forcedir(0,1);
|
||||
float l = length(diff);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void create_smoke(vec2 p)
|
||||
{
|
||||
// create the event
|
||||
EV_EXPLOSION *ev = (EV_EXPLOSION *)events.create(EVENT_SMOKE, sizeof(EV_EXPLOSION));
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
}
|
||||
}*/
|
||||
|
||||
void GAMECONTEXT::create_playerspawn(vec2 p)
|
||||
{
|
||||
// create the event
|
||||
NETEVENT_SPAWN *ev = (NETEVENT_SPAWN *)events.create(NETEVENTTYPE_SPAWN, sizeof(NETEVENT_SPAWN));
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
}
|
||||
}
|
||||
|
||||
void GAMECONTEXT::create_death(vec2 p, int cid)
|
||||
{
|
||||
// create the event
|
||||
NETEVENT_DEATH *ev = (NETEVENT_DEATH *)events.create(NETEVENTTYPE_DEATH, sizeof(NETEVENT_DEATH));
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)p.x;
|
||||
ev->y = (int)p.y;
|
||||
ev->cid = cid;
|
||||
}
|
||||
}
|
||||
|
||||
void GAMECONTEXT::create_sound(vec2 pos, int sound, int mask)
|
||||
{
|
||||
if (sound < 0)
|
||||
return;
|
||||
|
||||
// create a sound
|
||||
NETEVENT_SOUNDWORLD *ev = (NETEVENT_SOUNDWORLD *)events.create(NETEVENTTYPE_SOUNDWORLD, sizeof(NETEVENT_SOUNDWORLD), mask);
|
||||
if(ev)
|
||||
{
|
||||
ev->x = (int)pos.x;
|
||||
ev->y = (int)pos.y;
|
||||
ev->soundid = sound;
|
||||
}
|
||||
}
|
||||
|
||||
void GAMECONTEXT::create_sound_global(int sound, int target)
|
||||
{
|
||||
if (sound < 0)
|
||||
return;
|
||||
|
||||
NETMSG_SV_SOUNDGLOBAL msg;
|
||||
msg.soundid = sound;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
server_send_msg(target);
|
||||
}
|
||||
|
||||
// TODO: should be more general
|
||||
CHARACTER *GAMEWORLD::intersect_character(vec2 pos0, vec2 pos1, float radius, vec2& new_pos, ENTITY *notthis)
|
||||
{
|
||||
// Find other players
|
||||
float closest_len = distance(pos0, pos1) * 100.0f;
|
||||
vec2 line_dir = normalize(pos1-pos0);
|
||||
CHARACTER *closest = 0;
|
||||
|
||||
CHARACTER *p = (CHARACTER *)game.world.find_first(NETOBJTYPE_CHARACTER);
|
||||
for(; p; p = (CHARACTER *)p->typenext())
|
||||
{
|
||||
if(p == notthis)
|
||||
continue;
|
||||
|
||||
vec2 intersect_pos = closest_point_on_line(pos0, pos1, p->pos);
|
||||
float len = distance(p->pos, intersect_pos);
|
||||
if(len < CHARACTER::phys_size+radius)
|
||||
{
|
||||
if(len < closest_len)
|
||||
{
|
||||
new_pos = intersect_pos;
|
||||
closest_len = len;
|
||||
closest = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
|
||||
CHARACTER *GAMEWORLD::closest_character(vec2 pos, float radius, ENTITY *notthis)
|
||||
{
|
||||
// Find other players
|
||||
float closest_range = radius*2;
|
||||
CHARACTER *closest = 0;
|
||||
|
||||
CHARACTER *p = (CHARACTER *)game.world.find_first(NETOBJTYPE_CHARACTER);
|
||||
for(; p; p = (CHARACTER *)p->typenext())
|
||||
{
|
||||
if(p == notthis)
|
||||
continue;
|
||||
|
||||
float len = distance(pos, p->pos);
|
||||
if(len < CHARACTER::phys_size+radius)
|
||||
{
|
||||
if(len < closest_range)
|
||||
{
|
||||
closest_range = len;
|
||||
closest = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
|
||||
void GAMECONTEXT::tick()
|
||||
{
|
||||
world.core.tuning = tuning;
|
||||
world.tick();
|
||||
|
||||
//if(world.paused) // make sure that the game object always updates
|
||||
controller->tick();
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(players[i].client_id != -1)
|
||||
players[i].tick();
|
||||
}
|
||||
}
|
||||
|
||||
void GAMECONTEXT::snap(int client_id)
|
||||
{
|
||||
world.snap(client_id);
|
||||
controller->snap(client_id);
|
||||
events.snap(client_id);
|
||||
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(players[i].client_id != -1)
|
||||
players[i].snap(client_id);
|
||||
}
|
||||
}
|
||||
|
||||
// Server hooks
|
||||
void mods_client_direct_input(int client_id, void *input)
|
||||
{
|
||||
if(!game.world.paused)
|
||||
game.players[client_id].on_direct_input((NETOBJ_PLAYER_INPUT *)input);
|
||||
|
||||
/*
|
||||
if(i->fire)
|
||||
{
|
||||
msg_pack_start(MSG_EXTRA_PROJECTILE, 0);
|
||||
msg_pack_end();
|
||||
server_send_msg(client_id);
|
||||
}*/
|
||||
}
|
||||
|
||||
void mods_client_predicted_input(int client_id, void *input)
|
||||
{
|
||||
if(!game.world.paused)
|
||||
game.players[client_id].on_predicted_input((NETOBJ_PLAYER_INPUT *)input);
|
||||
|
||||
/*
|
||||
{
|
||||
|
||||
on_predicted_input()
|
||||
if (memcmp(&game.players[client_id].input, input, sizeof(NETOBJ_PLAYER_INPUT)) != 0)
|
||||
game.players[client_id].last_action = server_tick();
|
||||
|
||||
//game.players[client_id].previnput = game.players[client_id].input;
|
||||
game.players[client_id].input = *(NETOBJ_PLAYER_INPUT*)input;
|
||||
game.players[client_id].num_inputs++;
|
||||
|
||||
if(game.players[client_id].input.target_x == 0 && game.players[client_id].input.target_y == 0)
|
||||
game.players[client_id].input.target_y = -1;
|
||||
}*/
|
||||
}
|
||||
|
||||
// Server hooks
|
||||
void mods_tick()
|
||||
{
|
||||
game.tick();
|
||||
}
|
||||
|
||||
void mods_snap(int client_id)
|
||||
{
|
||||
game.snap(client_id);
|
||||
}
|
||||
|
||||
void mods_client_enter(int client_id)
|
||||
{
|
||||
//game.world.insert_entity(&game.players[client_id]);
|
||||
game.players[client_id].respawn();
|
||||
dbg_msg("game", "join player='%d:%s'", client_id, server_clientname(client_id));
|
||||
|
||||
|
||||
char buf[512];
|
||||
str_format(buf, sizeof(buf), "%s entered and joined the %s", server_clientname(client_id), game.controller->get_team_name(game.players[client_id].team));
|
||||
game.send_chat(-1, CHAT_ALL, buf);
|
||||
|
||||
dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), game.players[client_id].team);
|
||||
}
|
||||
|
||||
void mods_connected(int client_id)
|
||||
{
|
||||
game.players[client_id].init(client_id);
|
||||
//game.players[client_id].client_id = client_id;
|
||||
|
||||
// Check which team the player should be on
|
||||
if(config.sv_tournament_mode)
|
||||
game.players[client_id].team = -1;
|
||||
else
|
||||
game.players[client_id].team = game.controller->get_auto_team(client_id);
|
||||
|
||||
// send motd
|
||||
NETMSG_SV_MOTD msg;
|
||||
msg.message = config.sv_motd;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
server_send_msg(client_id);
|
||||
}
|
||||
|
||||
void mods_client_drop(int client_id)
|
||||
{
|
||||
game.players[client_id].on_disconnect();
|
||||
|
||||
}
|
||||
|
||||
void mods_message(int msgtype, int client_id)
|
||||
{
|
||||
void *rawmsg = netmsg_secure_unpack(msgtype);
|
||||
if(!rawmsg)
|
||||
{
|
||||
dbg_msg("server", "dropped weird message '%s' (%d), failed on '%s'", netmsg_get_name(msgtype), msgtype, netmsg_failed_on());
|
||||
return;
|
||||
}
|
||||
|
||||
if(msgtype == NETMSGTYPE_CL_SAY)
|
||||
{
|
||||
NETMSG_CL_SAY *msg = (NETMSG_CL_SAY *)rawmsg;
|
||||
int team = msg->team;
|
||||
if(team)
|
||||
team = game.players[client_id].team;
|
||||
else
|
||||
team = CHAT_ALL;
|
||||
|
||||
if(config.sv_spamprotection && game.players[client_id].last_chat+time_freq() > time_get())
|
||||
{
|
||||
// consider this as spam
|
||||
}
|
||||
else
|
||||
{
|
||||
game.players[client_id].last_chat = time_get();
|
||||
game.send_chat(client_id, team, msg->message);
|
||||
}
|
||||
}
|
||||
else if (msgtype == NETMSGTYPE_CL_SETTEAM)
|
||||
{
|
||||
NETMSG_CL_SETTEAM *msg = (NETMSG_CL_SETTEAM *)rawmsg;
|
||||
|
||||
// Switch team on given client and kill/respawn him
|
||||
if(game.controller->can_join_team(msg->team, client_id))
|
||||
game.players[client_id].set_team(msg->team);
|
||||
else
|
||||
{
|
||||
char buf[128];
|
||||
str_format(buf, sizeof(buf), "Only %d active players are allowed", config.sv_max_clients-config.sv_spectator_slots);
|
||||
game.send_broadcast(buf, client_id);
|
||||
}
|
||||
}
|
||||
else if (msgtype == NETMSGTYPE_CL_CHANGEINFO || msgtype == NETMSGTYPE_CL_STARTINFO)
|
||||
{
|
||||
NETMSG_CL_CHANGEINFO *msg = (NETMSG_CL_CHANGEINFO *)rawmsg;
|
||||
game.players[client_id].use_custom_color = msg->use_custom_color;
|
||||
game.players[client_id].color_body = msg->color_body;
|
||||
game.players[client_id].color_feet = msg->color_feet;
|
||||
|
||||
// check for invalid chars
|
||||
/*
|
||||
unsigned char *p = (unsigned char *)name;
|
||||
while (*p)
|
||||
{
|
||||
if(*p < 32)
|
||||
*p = ' ';
|
||||
p++;
|
||||
}*/
|
||||
|
||||
// copy old name
|
||||
char oldname[MAX_NAME_LENGTH];
|
||||
str_copy(oldname, server_clientname(client_id), MAX_NAME_LENGTH);
|
||||
|
||||
server_setclientname(client_id, msg->name);
|
||||
if(msgtype == NETMSGTYPE_CL_CHANGEINFO && strcmp(oldname, server_clientname(client_id)) != 0)
|
||||
{
|
||||
char chattext[256];
|
||||
str_format(chattext, sizeof(chattext), "%s changed name to %s", oldname, server_clientname(client_id));
|
||||
game.send_chat(-1, CHAT_ALL, chattext);
|
||||
}
|
||||
|
||||
// set skin
|
||||
str_copy(game.players[client_id].skin_name, msg->skin, sizeof(game.players[client_id].skin_name));
|
||||
|
||||
game.controller->on_player_info_change(&game.players[client_id]);
|
||||
|
||||
if(msgtype == NETMSGTYPE_CL_STARTINFO)
|
||||
{
|
||||
// a client that connected!
|
||||
|
||||
// send all info to this client
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(game.players[i].client_id != -1)
|
||||
game.send_info(i, client_id);
|
||||
}
|
||||
|
||||
// send tuning parameters to client
|
||||
send_tuning_params(client_id);
|
||||
|
||||
//
|
||||
NETMSG_SV_READYTOENTER m;
|
||||
m.pack(MSGFLAG_VITAL|MSGFLAG_FLUSH);
|
||||
server_send_msg(client_id);
|
||||
}
|
||||
|
||||
game.send_info(client_id, -1);
|
||||
}
|
||||
else if (msgtype == NETMSGTYPE_CL_EMOTICON)
|
||||
{
|
||||
NETMSG_CL_EMOTICON *msg = (NETMSG_CL_EMOTICON *)rawmsg;
|
||||
game.send_emoticon(client_id, msg->emoticon);
|
||||
}
|
||||
else if (msgtype == NETMSGTYPE_CL_KILL)
|
||||
{
|
||||
//PLAYER *pplayer = get_player(client_id);
|
||||
game.players[client_id].kill_character(); //(client_id, -1);
|
||||
}
|
||||
}
|
||||
|
||||
static void con_tune_param(void *result, void *user_data)
|
||||
{
|
||||
const char *param_name = console_arg_string(result, 0);
|
||||
float new_value = console_arg_float(result, 1);
|
||||
|
||||
if(tuning.set(param_name, new_value))
|
||||
{
|
||||
dbg_msg("tuning", "%s changed to %.2f", param_name, new_value);
|
||||
send_tuning_params(-1);
|
||||
}
|
||||
else
|
||||
console_print("No such tuning parameter");
|
||||
}
|
||||
|
||||
static void con_tune_reset(void *result, void *user_data)
|
||||
{
|
||||
TUNING_PARAMS p;
|
||||
tuning = p;
|
||||
send_tuning_params(-1);
|
||||
console_print("tuning reset");
|
||||
}
|
||||
|
||||
static void con_tune_dump(void *result, void *user_data)
|
||||
{
|
||||
for(int i = 0; i < tuning.num(); i++)
|
||||
{
|
||||
float v;
|
||||
tuning.get(i, &v);
|
||||
dbg_msg("tuning", "%s %.2f", tuning.names[i], v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void con_restart(void *result, void *user_data)
|
||||
{
|
||||
if(console_arg_num(result))
|
||||
game.controller->do_warmup(console_arg_int(result, 0));
|
||||
else
|
||||
game.controller->startround();
|
||||
}
|
||||
|
||||
static void con_broadcast(void *result, void *user_data)
|
||||
{
|
||||
game.send_broadcast(console_arg_string(result, 0), -1);
|
||||
}
|
||||
|
||||
static void con_say(void *result, void *user_data)
|
||||
{
|
||||
game.send_chat(-1, CHAT_ALL, console_arg_string(result, 0));
|
||||
}
|
||||
|
||||
static void con_set_team(void *result, void *user_data)
|
||||
{
|
||||
int client_id = clamp(console_arg_int(result, 0), 0, (int)MAX_CLIENTS);
|
||||
int team = clamp(console_arg_int(result, 1), -1, 1);
|
||||
|
||||
dbg_msg("", "%d %d", client_id, team);
|
||||
|
||||
if(game.players[client_id].client_id != client_id)
|
||||
return;
|
||||
|
||||
game.players[client_id].set_team(team);
|
||||
}
|
||||
|
||||
void mods_console_init()
|
||||
{
|
||||
MACRO_REGISTER_COMMAND("tune", "si", con_tune_param, 0);
|
||||
MACRO_REGISTER_COMMAND("tune_reset", "", con_tune_reset, 0);
|
||||
MACRO_REGISTER_COMMAND("tune_dump", "", con_tune_dump, 0);
|
||||
|
||||
MACRO_REGISTER_COMMAND("restart", "?i", con_restart, 0);
|
||||
MACRO_REGISTER_COMMAND("broadcast", "r", con_broadcast, 0);
|
||||
MACRO_REGISTER_COMMAND("say", "r", con_say, 0);
|
||||
MACRO_REGISTER_COMMAND("set_team", "ii", con_set_team, 0);
|
||||
}
|
||||
|
||||
void mods_init()
|
||||
{
|
||||
//if(!data) /* only load once */
|
||||
//data = load_data_from_memory(internal_data);
|
||||
|
||||
for(int i = 0; i < NUM_NETOBJTYPES; i++)
|
||||
snap_set_staticsize(i, netobj_get_size(i));
|
||||
|
||||
layers_init();
|
||||
col_init();
|
||||
|
||||
// reset everything here
|
||||
//world = new GAMEWORLD;
|
||||
//players = new PLAYER[MAX_CLIENTS];
|
||||
|
||||
// select gametype
|
||||
if(strcmp(config.sv_gametype, "ctf") == 0)
|
||||
game.controller = new GAMECONTROLLER_CTF;
|
||||
else if(strcmp(config.sv_gametype, "tdm") == 0)
|
||||
game.controller = new GAMECONTROLLER_TDM;
|
||||
else
|
||||
game.controller = new GAMECONTROLLER_DM;
|
||||
|
||||
// setup core world
|
||||
//for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
// game.players[i].core.world = &game.world.core;
|
||||
|
||||
// create all entities from the game layer
|
||||
MAPITEM_LAYER_TILEMAP *tmap = layers_game_layer();
|
||||
TILE *tiles = (TILE *)map_get_data(tmap->data);
|
||||
|
||||
/*
|
||||
num_spawn_points[0] = 0;
|
||||
num_spawn_points[1] = 0;
|
||||
num_spawn_points[2] = 0;
|
||||
*/
|
||||
|
||||
for(int y = 0; y < tmap->height; y++)
|
||||
{
|
||||
for(int x = 0; x < tmap->width; x++)
|
||||
{
|
||||
int index = tiles[y*tmap->width+x].index - ENTITY_OFFSET;
|
||||
vec2 pos(x*32.0f+16.0f, y*32.0f+16.0f);
|
||||
game.controller->on_entity(index, pos);
|
||||
}
|
||||
}
|
||||
|
||||
//game.world.insert_entity(game.controller);
|
||||
|
||||
if(config.dbg_dummies)
|
||||
{
|
||||
for(int i = 0; i < config.dbg_dummies ; i++)
|
||||
{
|
||||
mods_connected(MAX_CLIENTS-i-1);
|
||||
mods_client_enter(MAX_CLIENTS-i-1);
|
||||
if(game.controller->gametype != GAMETYPE_DM)
|
||||
game.players[MAX_CLIENTS-i-1].team = i&1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mods_shutdown()
|
||||
{
|
||||
delete game.controller;
|
||||
game.controller = 0;
|
||||
}
|
||||
|
||||
void mods_presnap() {}
|
||||
void mods_postsnap()
|
||||
{
|
||||
game.events.clear();
|
||||
}
|
||||
|
||||
extern "C" const char *mods_net_version() { return GAME_NETVERSION; }
|
||||
extern "C" const char *mods_version() { return GAME_VERSION; }
|
382
src/game/server/hooks.cpp
Normal file
382
src/game/server/hooks.cpp
Normal file
|
@ -0,0 +1,382 @@
|
|||
/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <base/math.hpp>
|
||||
|
||||
#include <engine/e_config.h>
|
||||
#include <engine/e_server_interface.h>
|
||||
#include <game/g_version.hpp>
|
||||
#include <game/g_collision.hpp>
|
||||
#include <game/g_layers.hpp>
|
||||
|
||||
|
||||
#include <game/g_game.hpp>
|
||||
|
||||
#include "gamecontext.hpp"
|
||||
#include "gamemodes/dm.hpp"
|
||||
#include "gamemodes/tdm.hpp"
|
||||
#include "gamemodes/ctf.hpp"
|
||||
|
||||
TUNING_PARAMS tuning;
|
||||
|
||||
|
||||
void send_tuning_params(int cid)
|
||||
{
|
||||
/*
|
||||
msg_pack_start(NETMSGTYPE_SV_TUNE_PARAMS, MSGFLAG_VITAL);
|
||||
int *params = (int *)&tuning;
|
||||
for(unsigned i = 0; i < sizeof(tuning_params)/sizeof(int); i++)
|
||||
msg_pack_int(params[i]);
|
||||
msg_pack_end();
|
||||
server_send_msg(cid);
|
||||
*/
|
||||
}
|
||||
|
||||
// Server hooks
|
||||
void mods_client_direct_input(int client_id, void *input)
|
||||
{
|
||||
if(!game.world.paused)
|
||||
game.players[client_id].on_direct_input((NETOBJ_PLAYER_INPUT *)input);
|
||||
|
||||
/*
|
||||
if(i->fire)
|
||||
{
|
||||
msg_pack_start(MSG_EXTRA_PROJECTILE, 0);
|
||||
msg_pack_end();
|
||||
server_send_msg(client_id);
|
||||
}*/
|
||||
}
|
||||
|
||||
void mods_client_predicted_input(int client_id, void *input)
|
||||
{
|
||||
if(!game.world.paused)
|
||||
game.players[client_id].on_predicted_input((NETOBJ_PLAYER_INPUT *)input);
|
||||
|
||||
/*
|
||||
{
|
||||
|
||||
on_predicted_input()
|
||||
if (memcmp(&game.players[client_id].input, input, sizeof(NETOBJ_PLAYER_INPUT)) != 0)
|
||||
game.players[client_id].last_action = server_tick();
|
||||
|
||||
//game.players[client_id].previnput = game.players[client_id].input;
|
||||
game.players[client_id].input = *(NETOBJ_PLAYER_INPUT*)input;
|
||||
game.players[client_id].num_inputs++;
|
||||
|
||||
if(game.players[client_id].input.target_x == 0 && game.players[client_id].input.target_y == 0)
|
||||
game.players[client_id].input.target_y = -1;
|
||||
}*/
|
||||
}
|
||||
|
||||
// Server hooks
|
||||
void mods_tick()
|
||||
{
|
||||
game.tick();
|
||||
}
|
||||
|
||||
void mods_snap(int client_id)
|
||||
{
|
||||
game.snap(client_id);
|
||||
}
|
||||
|
||||
void mods_client_enter(int client_id)
|
||||
{
|
||||
//game.world.insert_entity(&game.players[client_id]);
|
||||
game.players[client_id].respawn();
|
||||
dbg_msg("game", "join player='%d:%s'", client_id, server_clientname(client_id));
|
||||
|
||||
|
||||
char buf[512];
|
||||
str_format(buf, sizeof(buf), "%s entered and joined the %s", server_clientname(client_id), game.controller->get_team_name(game.players[client_id].team));
|
||||
game.send_chat(-1, GAMECONTEXT::CHAT_ALL, buf);
|
||||
|
||||
dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), game.players[client_id].team);
|
||||
}
|
||||
|
||||
void mods_connected(int client_id)
|
||||
{
|
||||
game.players[client_id].init(client_id);
|
||||
//game.players[client_id].client_id = client_id;
|
||||
|
||||
// Check which team the player should be on
|
||||
if(config.sv_tournament_mode)
|
||||
game.players[client_id].team = -1;
|
||||
else
|
||||
game.players[client_id].team = game.controller->get_auto_team(client_id);
|
||||
|
||||
// send motd
|
||||
NETMSG_SV_MOTD msg;
|
||||
msg.message = config.sv_motd;
|
||||
msg.pack(MSGFLAG_VITAL);
|
||||
server_send_msg(client_id);
|
||||
}
|
||||
|
||||
void mods_client_drop(int client_id)
|
||||
{
|
||||
game.players[client_id].on_disconnect();
|
||||
|
||||
}
|
||||
|
||||
void mods_message(int msgtype, int client_id)
|
||||
{
|
||||
void *rawmsg = netmsg_secure_unpack(msgtype);
|
||||
if(!rawmsg)
|
||||
{
|
||||
dbg_msg("server", "dropped weird message '%s' (%d), failed on '%s'", netmsg_get_name(msgtype), msgtype, netmsg_failed_on());
|
||||
return;
|
||||
}
|
||||
|
||||
if(msgtype == NETMSGTYPE_CL_SAY)
|
||||
{
|
||||
NETMSG_CL_SAY *msg = (NETMSG_CL_SAY *)rawmsg;
|
||||
int team = msg->team;
|
||||
if(team)
|
||||
team = game.players[client_id].team;
|
||||
else
|
||||
team = GAMECONTEXT::CHAT_ALL;
|
||||
|
||||
if(config.sv_spamprotection && game.players[client_id].last_chat+time_freq() > time_get())
|
||||
{
|
||||
// consider this as spam
|
||||
}
|
||||
else
|
||||
{
|
||||
game.players[client_id].last_chat = time_get();
|
||||
game.send_chat(client_id, team, msg->message);
|
||||
}
|
||||
}
|
||||
else if (msgtype == NETMSGTYPE_CL_SETTEAM)
|
||||
{
|
||||
NETMSG_CL_SETTEAM *msg = (NETMSG_CL_SETTEAM *)rawmsg;
|
||||
|
||||
// Switch team on given client and kill/respawn him
|
||||
if(game.controller->can_join_team(msg->team, client_id))
|
||||
game.players[client_id].set_team(msg->team);
|
||||
else
|
||||
{
|
||||
char buf[128];
|
||||
str_format(buf, sizeof(buf), "Only %d active players are allowed", config.sv_max_clients-config.sv_spectator_slots);
|
||||
game.send_broadcast(buf, client_id);
|
||||
}
|
||||
}
|
||||
else if (msgtype == NETMSGTYPE_CL_CHANGEINFO || msgtype == NETMSGTYPE_CL_STARTINFO)
|
||||
{
|
||||
NETMSG_CL_CHANGEINFO *msg = (NETMSG_CL_CHANGEINFO *)rawmsg;
|
||||
game.players[client_id].use_custom_color = msg->use_custom_color;
|
||||
game.players[client_id].color_body = msg->color_body;
|
||||
game.players[client_id].color_feet = msg->color_feet;
|
||||
|
||||
// check for invalid chars
|
||||
/*
|
||||
unsigned char *p = (unsigned char *)name;
|
||||
while (*p)
|
||||
{
|
||||
if(*p < 32)
|
||||
*p = ' ';
|
||||
p++;
|
||||
}*/
|
||||
|
||||
// copy old name
|
||||
char oldname[MAX_NAME_LENGTH];
|
||||
str_copy(oldname, server_clientname(client_id), MAX_NAME_LENGTH);
|
||||
|
||||
server_setclientname(client_id, msg->name);
|
||||
if(msgtype == NETMSGTYPE_CL_CHANGEINFO && strcmp(oldname, server_clientname(client_id)) != 0)
|
||||
{
|
||||
char chattext[256];
|
||||
str_format(chattext, sizeof(chattext), "%s changed name to %s", oldname, server_clientname(client_id));
|
||||
game.send_chat(-1, GAMECONTEXT::CHAT_ALL, chattext);
|
||||
}
|
||||
|
||||
// set skin
|
||||
str_copy(game.players[client_id].skin_name, msg->skin, sizeof(game.players[client_id].skin_name));
|
||||
|
||||
game.controller->on_player_info_change(&game.players[client_id]);
|
||||
|
||||
if(msgtype == NETMSGTYPE_CL_STARTINFO)
|
||||
{
|
||||
// a client that connected!
|
||||
|
||||
// send all info to this client
|
||||
for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if(game.players[i].client_id != -1)
|
||||
game.send_info(i, client_id);
|
||||
}
|
||||
|
||||
// send tuning parameters to client
|
||||
send_tuning_params(client_id);
|
||||
|
||||
//
|
||||
NETMSG_SV_READYTOENTER m;
|
||||
m.pack(MSGFLAG_VITAL|MSGFLAG_FLUSH);
|
||||
server_send_msg(client_id);
|
||||
}
|
||||
|
||||
game.send_info(client_id, -1);
|
||||
}
|
||||
else if (msgtype == NETMSGTYPE_CL_EMOTICON)
|
||||
{
|
||||
NETMSG_CL_EMOTICON *msg = (NETMSG_CL_EMOTICON *)rawmsg;
|
||||
game.send_emoticon(client_id, msg->emoticon);
|
||||
}
|
||||
else if (msgtype == NETMSGTYPE_CL_KILL)
|
||||
{
|
||||
//PLAYER *pplayer = get_player(client_id);
|
||||
game.players[client_id].kill_character(); //(client_id, -1);
|
||||
}
|
||||
}
|
||||
|
||||
static void con_tune_param(void *result, void *user_data)
|
||||
{
|
||||
const char *param_name = console_arg_string(result, 0);
|
||||
float new_value = console_arg_float(result, 1);
|
||||
|
||||
if(tuning.set(param_name, new_value))
|
||||
{
|
||||
dbg_msg("tuning", "%s changed to %.2f", param_name, new_value);
|
||||
send_tuning_params(-1);
|
||||
}
|
||||
else
|
||||
console_print("No such tuning parameter");
|
||||
}
|
||||
|
||||
static void con_tune_reset(void *result, void *user_data)
|
||||
{
|
||||
TUNING_PARAMS p;
|
||||
tuning = p;
|
||||
send_tuning_params(-1);
|
||||
console_print("tuning reset");
|
||||
}
|
||||
|
||||
static void con_tune_dump(void *result, void *user_data)
|
||||
{
|
||||
for(int i = 0; i < tuning.num(); i++)
|
||||
{
|
||||
float v;
|
||||
tuning.get(i, &v);
|
||||
dbg_msg("tuning", "%s %.2f", tuning.names[i], v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void con_restart(void *result, void *user_data)
|
||||
{
|
||||
if(console_arg_num(result))
|
||||
game.controller->do_warmup(console_arg_int(result, 0));
|
||||
else
|
||||
game.controller->startround();
|
||||
}
|
||||
|
||||
static void con_broadcast(void *result, void *user_data)
|
||||
{
|
||||
game.send_broadcast(console_arg_string(result, 0), -1);
|
||||
}
|
||||
|
||||
static void con_say(void *result, void *user_data)
|
||||
{
|
||||
game.send_chat(-1, GAMECONTEXT::CHAT_ALL, console_arg_string(result, 0));
|
||||
}
|
||||
|
||||
static void con_set_team(void *result, void *user_data)
|
||||
{
|
||||
int client_id = clamp(console_arg_int(result, 0), 0, (int)MAX_CLIENTS);
|
||||
int team = clamp(console_arg_int(result, 1), -1, 1);
|
||||
|
||||
dbg_msg("", "%d %d", client_id, team);
|
||||
|
||||
if(game.players[client_id].client_id != client_id)
|
||||
return;
|
||||
|
||||
game.players[client_id].set_team(team);
|
||||
}
|
||||
|
||||
void mods_console_init()
|
||||
{
|
||||
MACRO_REGISTER_COMMAND("tune", "si", con_tune_param, 0);
|
||||
MACRO_REGISTER_COMMAND("tune_reset", "", con_tune_reset, 0);
|
||||
MACRO_REGISTER_COMMAND("tune_dump", "", con_tune_dump, 0);
|
||||
|
||||
MACRO_REGISTER_COMMAND("restart", "?i", con_restart, 0);
|
||||
MACRO_REGISTER_COMMAND("broadcast", "r", con_broadcast, 0);
|
||||
MACRO_REGISTER_COMMAND("say", "r", con_say, 0);
|
||||
MACRO_REGISTER_COMMAND("set_team", "ii", con_set_team, 0);
|
||||
}
|
||||
|
||||
void mods_init()
|
||||
{
|
||||
//if(!data) /* only load once */
|
||||
//data = load_data_from_memory(internal_data);
|
||||
|
||||
for(int i = 0; i < NUM_NETOBJTYPES; i++)
|
||||
snap_set_staticsize(i, netobj_get_size(i));
|
||||
|
||||
layers_init();
|
||||
col_init();
|
||||
|
||||
// reset everything here
|
||||
//world = new GAMEWORLD;
|
||||
//players = new PLAYER[MAX_CLIENTS];
|
||||
|
||||
// select gametype
|
||||
if(strcmp(config.sv_gametype, "ctf") == 0)
|
||||
game.controller = new GAMECONTROLLER_CTF;
|
||||
else if(strcmp(config.sv_gametype, "tdm") == 0)
|
||||
game.controller = new GAMECONTROLLER_TDM;
|
||||
else
|
||||
game.controller = new GAMECONTROLLER_DM;
|
||||
|
||||
// setup core world
|
||||
//for(int i = 0; i < MAX_CLIENTS; i++)
|
||||
// game.players[i].core.world = &game.world.core;
|
||||
|
||||
// create all entities from the game layer
|
||||
MAPITEM_LAYER_TILEMAP *tmap = layers_game_layer();
|
||||
TILE *tiles = (TILE *)map_get_data(tmap->data);
|
||||
|
||||
/*
|
||||
num_spawn_points[0] = 0;
|
||||
num_spawn_points[1] = 0;
|
||||
num_spawn_points[2] = 0;
|
||||
*/
|
||||
|
||||
for(int y = 0; y < tmap->height; y++)
|
||||
{
|
||||
for(int x = 0; x < tmap->width; x++)
|
||||
{
|
||||
int index = tiles[y*tmap->width+x].index - ENTITY_OFFSET;
|
||||
vec2 pos(x*32.0f+16.0f, y*32.0f+16.0f);
|
||||
game.controller->on_entity(index, pos);
|
||||
}
|
||||
}
|
||||
|
||||
//game.world.insert_entity(game.controller);
|
||||
|
||||
if(config.dbg_dummies)
|
||||
{
|
||||
for(int i = 0; i < config.dbg_dummies ; i++)
|
||||
{
|
||||
mods_connected(MAX_CLIENTS-i-1);
|
||||
mods_client_enter(MAX_CLIENTS-i-1);
|
||||
if(game.controller->gametype != GAMETYPE_DM)
|
||||
game.players[MAX_CLIENTS-i-1].team = i&1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mods_shutdown()
|
||||
{
|
||||
delete game.controller;
|
||||
game.controller = 0;
|
||||
}
|
||||
|
||||
void mods_presnap() {}
|
||||
void mods_postsnap()
|
||||
{
|
||||
game.events.clear();
|
||||
}
|
||||
|
||||
extern "C" const char *mods_net_version() { return GAME_NETVERSION; }
|
||||
extern "C" const char *mods_version() { return GAME_VERSION; }
|
|
@ -1,3 +1,8 @@
|
|||
#ifndef GAME_SERVER_PLAYER_H
|
||||
#define GAME_SERVER_PLAYER_H
|
||||
|
||||
// this include should perhaps be removed
|
||||
#include "entities/character.hpp"
|
||||
|
||||
// player object
|
||||
class PLAYER
|
||||
|
@ -53,3 +58,5 @@ public:
|
|||
void on_predicted_input(NETOBJ_PLAYER_INPUT *new_input);
|
||||
void on_disconnect();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue