diff options
| author | Magnus Auvinen <magnus.auvinen@gmail.com> | 2008-08-14 18:42:47 +0000 |
|---|---|---|
| committer | Magnus Auvinen <magnus.auvinen@gmail.com> | 2008-08-14 18:42:47 +0000 |
| commit | 78c089c0eae503822c7f1025aefcf02529b13723 (patch) | |
| tree | 10c8767ef1006a09c9ca228770f1ce86b45cbccb /src/game/server | |
| parent | a420eb543f8206730aebb80e60a625f7204694e4 (diff) | |
| download | zcatch-78c089c0eae503822c7f1025aefcf02529b13723.tar.gz zcatch-78c089c0eae503822c7f1025aefcf02529b13723.zip | |
last of the game server clean up. now it's done
Diffstat (limited to 'src/game/server')
| -rw-r--r-- | src/game/server/entities/character.cpp | 6 | ||||
| -rw-r--r-- | src/game/server/entities/laser.cpp | 2 | ||||
| -rw-r--r-- | src/game/server/entities/pickup.cpp | 2 | ||||
| -rw-r--r-- | src/game/server/entities/projectile.cpp | 2 | ||||
| -rw-r--r-- | src/game/server/entity.cpp | 28 | ||||
| -rw-r--r-- | src/game/server/eventhandler.cpp | 49 | ||||
| -rw-r--r-- | src/game/server/gamecontext.cpp | 232 | ||||
| -rw-r--r-- | src/game/server/gamecontext.hpp | 43 | ||||
| -rw-r--r-- | src/game/server/gamecontroller.cpp | 5 | ||||
| -rw-r--r-- | src/game/server/gameworld.cpp | 215 | ||||
| -rw-r--r-- | src/game/server/gameworld.hpp | 7 | ||||
| -rw-r--r-- | src/game/server/gs_common.hpp | 51 | ||||
| -rw-r--r-- | src/game/server/gs_server.cpp | 887 | ||||
| -rw-r--r-- | src/game/server/hooks.cpp | 382 | ||||
| -rw-r--r-- | src/game/server/player.hpp | 7 |
15 files changed, 973 insertions, 945 deletions
diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 160e080a..ee6dcb17 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -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; diff --git a/src/game/server/entities/laser.cpp b/src/game/server/entities/laser.cpp index cedf7850..226d52a9 100644 --- a/src/game/server/entities/laser.cpp +++ b/src/game/server/entities/laser.cpp @@ -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" ////////////////////////////////////////////////// diff --git a/src/game/server/entities/pickup.cpp b/src/game/server/entities/pickup.cpp index a4a3a2c9..e9997733 100644 --- a/src/game/server/entities/pickup.cpp +++ b/src/game/server/entities/pickup.cpp @@ -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" ////////////////////////////////////////////////// diff --git a/src/game/server/entities/projectile.cpp b/src/game/server/entities/projectile.cpp index d258e69e..adcd8977 100644 --- a/src/game/server/entities/projectile.cpp +++ b/src/game/server/entities/projectile.cpp @@ -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" diff --git a/src/game/server/entity.cpp b/src/game/server/entity.cpp new file mode 100644 index 00000000..2cc7c8f7 --- /dev/null +++ b/src/game/server/entity.cpp @@ -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); +} diff --git a/src/game/server/eventhandler.cpp b/src/game/server/eventhandler.cpp new file mode 100644 index 00000000..8f50da1e --- /dev/null +++ b/src/game/server/eventhandler.cpp @@ -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]); + } + } + } +} diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp new file mode 100644 index 00000000..dfea7e91 --- /dev/null +++ b/src/game/server/gamecontext.cpp @@ -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); + } +} diff --git a/src/game/server/gamecontext.hpp b/src/game/server/gamecontext.hpp index c4035b3f..85414183 100644 --- a/src/game/server/gamecontext.hpp +++ b/src/game/server/gamecontext.hpp @@ -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 diff --git a/src/game/server/gamecontroller.cpp b/src/game/server/gamecontroller.cpp index aeab559c..30cc6e78 100644 --- a/src/game/server/gamecontroller.cpp +++ b/src/game/server/gamecontroller.cpp @@ -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() { diff --git a/src/game/server/gameworld.cpp b/src/game/server/gameworld.cpp new file mode 100644 index 00000000..60b276d3 --- /dev/null +++ b/src/game/server/gameworld.cpp @@ -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; +} diff --git a/src/game/server/gameworld.hpp b/src/game/server/gameworld.hpp index 76b39d23..de441f8d 100644 --- a/src/game/server/gameworld.hpp +++ b/src/game/server/gameworld.hpp @@ -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 diff --git a/src/game/server/gs_common.hpp b/src/game/server/gs_common.hpp deleted file mode 100644 index 37bb2638..00000000 --- a/src/game/server/gs_common.hpp +++ /dev/null @@ -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 -}; diff --git a/src/game/server/gs_server.cpp b/src/game/server/gs_server.cpp deleted file mode 100644 index 1d981ea5..00000000 --- a/src/game/server/gs_server.cpp +++ /dev/null @@ -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; } diff --git a/src/game/server/hooks.cpp b/src/game/server/hooks.cpp new file mode 100644 index 00000000..43563483 --- /dev/null +++ b/src/game/server/hooks.cpp @@ -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; } diff --git a/src/game/server/player.hpp b/src/game/server/player.hpp index c1866f85..e7af0573 100644 --- a/src/game/server/player.hpp +++ b/src/game/server/player.hpp @@ -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 |