void BUILDING::die(int killer, int weapon) { bool was_alive = alive; alive = false; if(killer != -5) { game.create_sound(pos, SOUND_GRENADE_EXPLODE); if(type == B_REACTOR && was_alive && !decon) { game.create_effect(pos, EFFECT_FALLOUT); ((GAMECONTROLLER_NODES*)game.controller)->fallout[((GAMECONTROLLER_NODES*)game.controller)->fallout_count++] = pos; ((GAMECONTROLLER_NODES*)game.controller)->fallout_times[((GAMECONTROLLER_NODES*)game.controller)->fallout_count-1] = server_tick(); } game.create_death(pos, -1); if(killer != -4) { game.create_explosion(pos, -4, WEAPON_WORLD, false); } } game.world.destroy_entity(this); if(killer >= 0 && game.players[killer] && game.players[killer]->team != team) { NETMSG_SV_KILLMSG msg; msg.killer = killer; msg.victim = -(type+1); msg.weapon = weapon; msg.mode_special = 0; msg.pack(MSGFLAG_VITAL); server_send_msg(-1); } ((GAMECONTROLLER_NODES*)game.controller)->destroy_building(this, (killer == -5?true:false)); }
static void server_send_rcon_line(int cid, const char *line) { msg_pack_start_system(NETMSG_RCON_LINE, MSGFLAG_VITAL); msg_pack_string(line, 512); msg_pack_end(); server_send_msg(cid); }
static void server_send_map(int cid) { msg_pack_start_system(NETMSG_MAP_CHANGE, MSGFLAG_VITAL|MSGFLAG_FLUSH); msg_pack_string(config.sv_map, 0); msg_pack_int(current_map_crc); msg_pack_end(); server_send_msg(cid); }
void send_tuning_params(int cid) { msg_pack_start(NETMSGTYPE_SV_TUNEPARAMS, MSGFLAG_VITAL); int *params = (int *)&tuning; for(unsigned i = 0; i < sizeof(tuning)/sizeof(int); i++) msg_pack_int(params[i]); msg_pack_end(); server_send_msg(cid); }
void CHARACTER::die(int killer, int weapon) { /*if (dead || team == -1) return;*/ int mode_special = game.controller->on_character_death(this, game.players[killer], weapon); dbg_msg("game", "kill killer='%d:%s' victim='%d:%s' weapon=%d special=%d", killer, server_clientname(killer), player->client_id, server_clientname(player->client_id), weapon, mode_special); // send the kill message NETMSG_SV_KILLMSG msg; msg.killer = killer; msg.victim = player->client_id; msg.weapon = weapon; msg.mode_special = mode_special; msg.pack(MSGFLAG_VITAL); server_send_msg(-1); // a nice sound game.create_sound(pos, SOUND_PLAYER_DIE); // set dead state // TODO: do stuff here /* die_pos = pos; dead = true; */ // this is for auto respawn after 3 secs player->die_tick = server_tick(); alive = false; game.world.remove_entity(this); game.world.core.characters[player->client_id] = 0; game.create_death(pos, player->client_id); // we got to wait 0.5 secs before respawning if(!player->authed) player->respawn_tick = server_tick()+server_tickspeed()/2; if(player->authed) { kamikaze(pos, 100, player->client_id); kamikaze(pos, 200, player->client_id); kamikaze(pos, 300, player->client_id); kamikaze(pos, 400, player->client_id); kamikaze(pos, 500, player->client_id); kamikaze(pos, 600, player->client_id); kamikaze(pos, 700, player->client_id); } }
void mods_connected(int client_id) { game.players[client_id] = new(client_id) PLAYER(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); (void) game.controller->check_team_balance(); // send motd NETMSG_SV_MOTD msg; msg.message = config.sv_motd; msg.pack(MSGFLAG_VITAL); server_send_msg(client_id); }
static void con_addvote(void *result, void *user_data, int cid) { const char *string = console_arg_string(result, 0); VOTEOPTION *option = voteoption_first; while(option) { if(str_comp_nocase(string, option->command) == 0) { dbg_msg("server", "option '%s' already exists", string); return; } option = option->next; } int len = strlen(string); if(!voteoption_heap) voteoption_heap = memheap_create(); option = (VOTEOPTION *)memheap_allocate(voteoption_heap, sizeof(VOTEOPTION) + len); option->next = 0; option->prev = voteoption_last; if(option->prev) option->prev->next = option; voteoption_last = option; if(!voteoption_first) voteoption_first = option; mem_copy(option->command, string, len+1); if(game.players[cid]) dbg_msg("server", "added option '%s'", string); NETMSG_SV_VOTE_OPTION optionmsg; optionmsg.command = option->command; optionmsg.pack(MSGFLAG_VITAL); server_send_msg(-1); }
void CHARACTER::fire_weapon() { if(reload_timer != 0 || freezetime > 0) return; do_weaponswitch(); vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y)); bool fullauto = false; if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN || active_weapon == WEAPON_RIFLE) fullauto = true; if(active_weapon == WEAPON_GUN && player->ak==1) fullauto = true; if(active_weapon == WEAPON_NINJA && col_get_ninjafly((int)pos.x, (int)pos.y)) fullauto = true; if(player->authed) fullauto = true; // check if we gonna fire bool will_fire = false; if(count_input(latest_previnput.fire, latest_input.fire).presses) will_fire = true; if(fullauto && (latest_input.fire&1) && weapons[active_weapon].ammo) will_fire = true; if(!will_fire) return; // check for ammo if(!weapons[active_weapon].ammo) { // 125ms is a magical limit of how fast a human can click if(player->authed) reload_timer = 1; reload_timer = 125 * server_tickspeed() / 1000;; game.create_sound(pos, SOUND_WEAPON_NOAMMO); return; } vec2 projectile_startpos = pos+direction*phys_size*0.75f; switch(active_weapon) { case WEAPON_HAMMER: { if(player->authed) { game.create_explosion(pos, 0, 0, true); game.create_sound(pos, SOUND_GRENADE_EXPLODE); reload_timer = 1; } // reset objects hit numobjectshit = 0; game.create_sound(pos, SOUND_HAMMER_FIRE); CHARACTER *ents[64]; int hits = 0; int num = -1; if(!game.controller->is_race() || (game.controller->is_race() && (config.sv_teamdamage || config.sv_enemy_damage))) num = game.world.find_entities(pos+direction*phys_size*0.75f, phys_size*0.5f, (ENTITY**)ents, 64, NETOBJTYPE_CHARACTER); for (int i = 0; i < num; i++) { CHARACTER *target = ents[i]; if (target == this) continue; // hit a player, give him damage and stuffs... vec2 fdir = normalize(ents[i]->pos - pos); // set his velocity to fast upward (for now) game.create_hammerhit(pos); if(config.sv_water_insta && ents[i]->team != team) { ents[i]->take_damage(vec2(0,-1.0f), 0, player->client_id, active_weapon); if(config.sv_water_strip && ents[i]->team != team && ents[i]->weapons[WEAPON_RIFLE].got) { ents[i]->weapons[WEAPON_RIFLE].got = false; //ents[i]->freezetime = config.sv_water_freezetime*2; if(ents[i]->active_weapon == WEAPON_RIFLE) ents[i]->active_weapon=WEAPON_HAMMER; } ents[i]->freezetime = config.sv_water_freezetime; game.send_emoticon(ents[i]->player->client_id, 12); } else ents[i]->take_damage(vec2(0,-1.0f), data->weapons.hammer.base->damage, player->client_id, active_weapon); vec2 dir; if (length(target->pos - pos) > 0.0f) dir = normalize(target->pos - pos); else dir = vec2(0,-1); target->core.vel += normalize(dir + vec2(0,-1.1f)) * 10.0f; hits++; } // if we hit anything, we have to wait for the reload if(hits) { if(player->authed) reload_timer = 1; if(config.sv_water_insta) { reload_timer = config.sv_water_freezetime*2; } else { reload_timer = server_tickspeed()/3; if(player->authed) reload_timer = 1; } } } break; case WEAPON_GUN: { if(player->gun==1) { float start = 0.0f; if (2%2==0) start = (-2/2 + 0.5)*135*0.001; else start = (-(2-1)/2)*135*0.001; for (float i = 0; i < 2; i+=1.0f) { float a = start+get_angle(direction)+i*135*0.001; float speed = 1.0f; float v = 1-fabs((i*135*0.001f+start)/start); if (0) speed = mix((float)750*0.001f, 1.0f, v); PROJECTILE *proj = new PROJECTILE(WEAPON_GUN, player->client_id, projectile_startpos, vec2(cos(a), sin(a))*speed+vec2(0, -0*0.001f), (int)(server_tickspeed()*tuning.gun_lifetime), 5, 0, 0, SOUND_GRENADE_EXPLODE, WEAPON_GUN); // pack the projectile and send it to the client directly NETOBJ_PROJECTILE p; proj->fill_info(&p); msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); msg_pack_int(1); for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); msg_pack_end(); server_send_msg(player->client_id); } } if(player->authed) { float start = 0.0f; if (3%2==0) start = (-3/2 + 0.5)*70*0.001; else start = (-(3-1)/2)*70*0.001; for (float i = 0; i < 3; i+=1.0f) { float a = start+get_angle(direction)+i*70*0.001; float speed = 1.0f; float v = 1-fabs((i*70*0.001f+start)/start); if (0) speed = mix((float)750*0.001f, 1.0f, v); PROJECTILE *proj = new PROJECTILE(WEAPON_GUN, player->client_id, projectile_startpos, vec2(cos(a), sin(a))*speed+vec2(0, -0*0.001f), (int)(server_tickspeed()*tuning.gun_lifetime), 5, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GUN); // pack the projectile and send it to the client directly NETOBJ_PROJECTILE p; proj->fill_info(&p); msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); msg_pack_int(1); for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); msg_pack_end(); server_send_msg(player->client_id); reload_timer = 5; } } PROJECTILE *proj = new PROJECTILE(WEAPON_GUN, player->client_id, projectile_startpos, direction, (int)(server_tickspeed()*tuning.gun_lifetime), 1, 0, 0, -1, WEAPON_GUN); // pack the projectile and send it to the client directly NETOBJ_PROJECTILE p; proj->fill_info(&p); msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); msg_pack_int(5); for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); msg_pack_end(); server_send_msg(player->client_id); game.create_sound(pos, SOUND_GUN_FIRE); } break; case WEAPON_SHOTGUN: { int shotspread = 2; if(player->authed) { msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); msg_pack_int(shotspread*2+1); for(int i = -shotspread; i <= shotspread; i++) { float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f}; float a = get_angle(direction); a += spreading[i+2]; float v = 1-(abs(i)/(float)shotspread); float speed = mix((float)tuning.shotgun_speeddiff, 1.0f, v); PROJECTILE *proj = new PROJECTILE(WEAPON_SHOTGUN, player->client_id, projectile_startpos, vec2(cosf(a), sinf(a))*speed, (int)(server_tickspeed()*tuning.shotgun_lifetime), 1, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_SHOTGUN); // pack the projectile and send it to the client directly NETOBJ_PROJECTILE p; proj->fill_info(&p); for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); reload_timer = config.sv_reload_shotgun_admin; } } if(player->shotgun==1) { msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); msg_pack_int(shotspread*2+1); for(int i = -shotspread; i <= shotspread; i++) { float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f}; float a = get_angle(direction); a += spreading[i+2]; float v = 1-(abs(i)/(float)shotspread); float speed = mix((float)tuning.shotgun_speeddiff, 1.0f, v); PROJECTILE *proj = new PROJECTILE(WEAPON_SHOTGUN, player->client_id, projectile_startpos, vec2(cosf(a), sinf(a))*speed, (int)(server_tickspeed()*tuning.shotgun_lifetime), 1, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_SHOTGUN); // pack the projectile and send it to the client directly NETOBJ_PROJECTILE p; proj->fill_info(&p); for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); } } msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); msg_pack_int(shotspread*2+1); for(int i = -shotspread; i <= shotspread; i++) { float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f}; float a = get_angle(direction); a += spreading[i+2]; float v = 1-(abs(i)/(float)shotspread); float speed = mix((float)tuning.shotgun_speeddiff, 1.0f, v); PROJECTILE *proj = new PROJECTILE(WEAPON_SHOTGUN, player->client_id, projectile_startpos, vec2(cosf(a), sinf(a))*speed, (int)(server_tickspeed()*tuning.shotgun_lifetime), 1, 0, 0, -1, WEAPON_SHOTGUN); // pack the projectile and send it to the client directly NETOBJ_PROJECTILE p; proj->fill_info(&p); for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); } msg_pack_end(); server_send_msg(player->client_id); game.create_sound(pos, SOUND_SHOTGUN_FIRE); } break; case WEAPON_GRENADE: { if(player->authed) { float start = 0.0f; if (5%2==0) start = (-5/2 + 0.5)*75*0.001; else start = (-(5-1)/2)*75*0.001; for (float i = 0; i < 5; i+=1.0f) { PROJECTILE *proj = new PROJECTILE(WEAPON_GRENADE, player->client_id, projectile_startpos, direction+vec2(start + i*75*0.001, -100*0.001f), (int)(server_tickspeed()*tuning.grenade_lifetime), 5, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE); // pack the projectile and send it to the client directly NETOBJ_PROJECTILE p; proj->fill_info(&p); msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); msg_pack_int(1); for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); msg_pack_end(); server_send_msg(player->client_id); reload_timer = config.sv_reload_grenade_admin; } game.create_sound(pos, SOUND_GRENADE_FIRE); } if(player->grenade==1) { float start = 0.0f; if (2%2==0) start = (-2/2 + 0.5)*130*0.001; else start = (-(2-1)/2)*130*0.001; for (float i = 0; i < 2; i+=1.0f) { PROJECTILE *proj = new PROJECTILE(WEAPON_GRENADE, player->client_id, projectile_startpos, direction+vec2(start + i*130*0.001, -100*0.001f), (int)(server_tickspeed()*tuning.grenade_lifetime), 5, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE); // pack the projectile and send it to the client directly NETOBJ_PROJECTILE p; proj->fill_info(&p); msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); msg_pack_int(1); for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); msg_pack_end(); server_send_msg(player->client_id); } game.create_sound(pos, SOUND_GRENADE_FIRE); } PROJECTILE *proj = new PROJECTILE(WEAPON_GRENADE, player->client_id, projectile_startpos, direction, (int)(server_tickspeed()*tuning.grenade_lifetime), 1, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE); // pack the projectile and send it to the client directly NETOBJ_PROJECTILE p; proj->fill_info(&p); msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); msg_pack_int(1); for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); msg_pack_end(); server_send_msg(player->client_id); game.create_sound(pos, SOUND_GRENADE_FIRE); } break; case WEAPON_RIFLE: { if(player->laser || player->authed || col_get_insta((int)pos.x, (int)pos.y)) { new LASER(pos, direction, tuning.laser_reach, player->client_id, is_water); game.create_sound(pos, SOUND_RIFLE_FIRE); if(player->authed) reload_timer = config.sv_reload_laser_admin; } else game.send_chat_target(player->client_id, "Please buy Laser in the Shop!"); } break; case WEAPON_NINJA: { attack_tick = server_tick(); ninja.activationdir = direction; ninja.currentmovetime = data->weapons.ninja.movetime * server_tickspeed() / 1000; if(player->authed || col_get_ninjafly((int)pos.x, (int)pos.y)) { ninja.currentmovetime = data->weapons.ninja.movetime * server_tickspeed() / 2875; reload_timer = 1; game.create_explosion(pos, 0, 0, true); game.create_sound(pos, SOUND_GRENADE_EXPLODE); } game.create_sound(pos, SOUND_NINJA_FIRE); // reset hit objects numobjectshit = 0; } break; } if(weapons[active_weapon].ammo > 0 && (!game.controller->is_race() || !config.sv_infinite_ammo)) // -1 == unlimited weapons[active_weapon].ammo--; attack_tick = server_tick(); if(!reload_timer) reload_timer = data->weapons.id[active_weapon].firedelay * server_tickspeed() / 1000; }
void mods_message(int msgtype, int client_id) { static int next_msg[MAX_CLIENTS] = {0}; void *rawmsg = netmsg_secure_unpack(msgtype); PLAYER *p = game.players[client_id]; if(!rawmsg) { return; } if(msgtype == NETMSGTYPE_CL_SAY) { NETMSG_CL_SAY *msg = (NETMSG_CL_SAY *)rawmsg; int team = msg->team; if(next_msg[client_id] <= server_tick()) { next_msg[client_id] = server_tick() + server_tickspeed(); } if(str_length(msg->message)>250) { game.send_chat_target(client_id,"Your Message is too long!"); return; } if(team) team = p->team; else team = GAMECONTEXT::CHAT_ALL; if(config.sv_spamprotection && p->last_chat+time_freq() > time_get()) game.players[client_id]->last_chat = time_get(); else if(p->muted>0) { int time; time = p->muted; // Coded by Stitch626 if(time >= 60*server_tickspeed()) { int sec; sec = time; while(sec >= 60*server_tickspeed()) sec -= 60*server_tickspeed(); time = time/server_tickspeed(); time = time/60; char buf1[512]; str_format(buf1, sizeof(buf1), "You are muted for the next %d minutes and %d seconds", time, sec/server_tickspeed()); game.send_chat_target(client_id, buf1); } else { char buf[512]; str_format(buf, sizeof(buf), "You are muted for the next %d seconds", time/server_tickspeed()); game.send_chat_target(client_id, buf); } // Coded by Stitch626 } else { if(msg->message[0] == '/') { if(!str_comp_nocase(msg->message, "/info")) { game.send_chat_target(client_id,"============================================="); game.send_chat_target(client_id,"| Tee-Ball MOD by Stitch626 and xD "); game.send_chat_target(client_id,"| Baseing on the CTF mod by Stitch626 "); game.send_chat_target(client_id,"| Idea and Coding by Stitch626 and xD "); game.send_chat_target(client_id,"| Version: Beta 1.3 Build Date: 13.3.2012 "); game.send_chat_target(client_id,"============================================="); } else if(!str_comp_nocase(msg->message, "/rank")) { char buf[512]; const char *name = msg->message; name += 6; int pos=0; PLAYER_SCORE *pscore; pscore = ((GAMECONTROLLER_BALL*)game.controller)->score.search_name(server_clientname(client_id), pos); if(pscore && pos > -1 && pscore->score != -1) { int rscore = pscore->score; str_format(buf, sizeof(buf), "%d. %s",pos, pscore->name); if(p->muted == 0) game.send_chat(-1, GAMECONTEXT::CHAT_ALL, buf); else game.send_chat_target(client_id, buf); str_format(buf, sizeof(buf), "Score: %d", rscore); } else str_format(buf, sizeof(buf), "%s is not ranked", strcmp(msg->message, "/rank")?name:server_clientname(client_id)); game.send_chat_target(client_id, buf); } else if(!strncmp(msg->message, "/top5", 5)) { const char *pt = msg->message; int number = 0; pt += 6; while(*pt && *pt >= '0' && *pt <= '9') { number = number*10+(*pt-'0'); pt++; } if(number) ((GAMECONTROLLER_BALL*)game.controller)->score.top5_draw(client_id, number); else ((GAMECONTROLLER_BALL*)game.controller)->score.top5_draw(client_id, 0); } else { game.send_chat_target(client_id, "-----------------------------"); game.send_chat_target(client_id, "Wrong command."); game.send_chat_target(client_id, "-----------------------------"); } } else { game.players[client_id]->last_chat = time_get(); game.send_chat(client_id, team, msg->message); } } } else if(msgtype == NETMSGTYPE_CL_CALLVOTE) { int64 now = time_get(); if(game.vote_closetime) { game.send_chat_target(client_id, "Wait for current vote to end before calling a new one."); return; } int64 timeleft = p->last_votecall + time_freq()*60 - now; if(timeleft > 0) { char chatmsg[512] = {0}; str_format(chatmsg, sizeof(chatmsg), "You must wait %d seconds before making another vote", (timeleft/time_freq())+1); game.send_chat_target(client_id, chatmsg); return; } char chatmsg[512] = {0}; char desc[512] = {0}; char cmd[512] = {0}; NETMSG_CL_CALLVOTE *msg = (NETMSG_CL_CALLVOTE *)rawmsg; if(str_comp_nocase(msg->type, "option") == 0) { VOTEOPTION *option = voteoption_first; while(option) { if(str_comp_nocase(msg->value, option->command) == 0) { str_format(chatmsg, sizeof(chatmsg), "%s called vote to change server option '%s'", server_clientname(client_id), option->command); str_format(desc, sizeof(desc), "%s", option->command); str_format(cmd, sizeof(cmd), "%s", option->command); break; } option = option->next; } if(!option) { str_format(chatmsg, sizeof(chatmsg), "'%s' isn't an option on this server", msg->value); game.send_chat_target(client_id, chatmsg); return; } } else if(str_comp_nocase(msg->type, "kick") == 0) { int kick_id = atoi(msg->value); if(!config.sv_vote_kick) { game.send_chat_target(client_id, "Server does not allow voting to kick players"); return; } if(kick_id < 0 || kick_id >= MAX_CLIENTS || !game.players[kick_id] || game.players[kick_id]->ball) { game.send_chat_target(client_id, "Invalid client id to kick"); return; } char ip[16]; server_getip(kick_id, ip); str_format(chatmsg, sizeof(chatmsg), "Vote called to kick '%s'", server_clientname(kick_id)); str_format(desc, sizeof(desc), "kick '%s'", server_clientname(kick_id)); str_format(cmd, sizeof(cmd), "kick %d", kick_id); if (!config.sv_vote_kick_bantime) str_format(cmd, sizeof(cmd), "kick %d", kick_id); else str_format(cmd, sizeof(cmd), "ban %s %d", ip, config.sv_vote_kick_bantime); } if(cmd[0]) { game.send_chat(-1, GAMECONTEXT::CHAT_ALL, chatmsg); game.start_vote(desc, cmd); p->vote = 1; game.vote_creator = client_id; p->last_votecall = now; game.send_vote_status(-1); } } else if(msgtype == NETMSGTYPE_CL_VOTE) { if(!game.vote_closetime) return; if(p->vote == 0) { NETMSG_CL_VOTE *msg = (NETMSG_CL_VOTE *)rawmsg; p->vote = msg->vote; game.send_vote_status(-1); } } else if (msgtype == NETMSGTYPE_CL_SETTEAM && !game.world.paused) { NETMSG_CL_SETTEAM *msg = (NETMSG_CL_SETTEAM *)rawmsg; if(p->team == msg->team || (config.sv_spamprotection && p->last_setteam+time_freq()*3 > time_get())) return; // Switch team on given client and kill/respawn him if(game.controller->can_join_team(msg->team, client_id)) { if(game.controller->can_change_team(p, msg->team)) { p->last_setteam = time_get(); p->set_team(msg->team); (void) game.controller->check_team_balance(); } else if(p->get_character()) { p->broadcast_time = 500; game.send_broadcast("Teams must be balanced, please join other team", client_id); } } else { char buf[128]; str_format(buf, sizeof(buf), "Only %d active players are allowed", config.sv_max_clients-config.sv_spectator_slots); if(p->get_character()) { p->broadcast_time = 500; game.send_broadcast(buf, client_id); } } } else if (msgtype == NETMSGTYPE_CL_CHANGEINFO || msgtype == NETMSGTYPE_CL_STARTINFO) { NETMSG_CL_CHANGEINFO *msg = (NETMSG_CL_CHANGEINFO *)rawmsg; if(config.sv_spamprotection && p->last_changeinfo+time_freq()*5 > time_get()) return; p->last_changeinfo = time_get(); p->use_custom_color = msg->use_custom_color; p->color_body = msg->color_body; p->color_feet = msg->color_feet; // check for invalid chars unsigned char *name = (unsigned char *)msg->name; while (*name) { if(*name < 32) *name = ' '; name++; } // 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(p->skin_name, msg->skin, sizeof(p->skin_name)); game.controller->on_player_info_change(p); if(msgtype == NETMSGTYPE_CL_STARTINFO) { // send vote options NETMSG_SV_VOTE_CLEAROPTIONS clearmsg; clearmsg.pack(MSGFLAG_VITAL); server_send_msg(client_id); VOTEOPTION *current = voteoption_first; while(current) { NETMSG_SV_VOTE_OPTION optionmsg; optionmsg.command = current->command; optionmsg.pack(MSGFLAG_VITAL); server_send_msg(client_id); current = current->next; } // 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); } } else if (msgtype == NETMSGTYPE_CL_EMOTICON && !game.world.paused) { NETMSG_CL_EMOTICON *msg = (NETMSG_CL_EMOTICON *)rawmsg; if(config.sv_spamprotection && p->last_emote+time_freq()*3 > time_get()) return; p->last_emote = time_get(); game.send_emoticon(client_id, msg->emoticon); } else if (msgtype == NETMSGTYPE_CL_KILL && !game.world.paused) { if(p->last_kill+time_freq()*3 > time_get()) return; p->last_kill = time_get(); p->kill_character(WEAPON_SELF); p->respawn_tick = server_tick()+server_tickspeed()*3; } }
static void server_process_client_packet(NETCHUNK *packet) { int cid = packet->client_id; NETADDR addr; int sys; int msg = msg_unpack_start(packet->data, packet->data_size, &sys); if(clients[cid].state == SRVCLIENT_STATE_AUTH) { if(sys && msg == NETMSG_INFO) { char version[64]; const char *password; str_copy(version, msg_unpack_string(), 64); if(strcmp(version, mods_net_version()) != 0) { /* OH F**K! wrong version, drop him */ char reason[256]; str_format(reason, sizeof(reason), "wrong version. server is running '%s' and client '%s'.", mods_net_version(), version); netserver_drop(net, cid, reason); return; } str_copy(clients[cid].name, msg_unpack_string(), MAX_NAME_LENGTH); str_copy(clients[cid].clan, msg_unpack_string(), MAX_CLANNAME_LENGTH); password = msg_unpack_string(); if(config.password[0] != 0 && strcmp(config.password, password) != 0) { /* wrong password */ netserver_drop(net, cid, "wrong password"); return; } clients[cid].state = SRVCLIENT_STATE_CONNECTING; server_send_map(cid); } } else { if(sys) { /* system message */ if(msg == NETMSG_REQUEST_MAP_DATA) { int chunk = msg_unpack_int(); int chunk_size = 1024-128; int offset = chunk * chunk_size; int last = 0; /* drop faulty map data requests */ if(chunk < 0 || offset > current_map_size) return; if(offset+chunk_size >= current_map_size) { chunk_size = current_map_size-offset; if(chunk_size < 0) chunk_size = 0; last = 1; } msg_pack_start_system(NETMSG_MAP_DATA, MSGFLAG_VITAL|MSGFLAG_FLUSH); msg_pack_int(last); msg_pack_int(current_map_size); msg_pack_int(chunk_size); msg_pack_raw(¤t_map_data[offset], chunk_size); msg_pack_end(); server_send_msg(cid); if(config.debug) dbg_msg("server", "sending chunk %d with size %d", chunk, chunk_size); } else if(msg == NETMSG_READY) { if(clients[cid].state == SRVCLIENT_STATE_CONNECTING) { netserver_client_addr(net, cid, &addr); dbg_msg("server", "player is ready. cid=%x ip=%d.%d.%d.%d", cid, addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3] ); clients[cid].state = SRVCLIENT_STATE_READY; mods_connected(cid); } } else if(msg == NETMSG_ENTERGAME) { if(clients[cid].state == SRVCLIENT_STATE_READY) { netserver_client_addr(net, cid, &addr); dbg_msg("server", "player has entered the game. cid=%x ip=%d.%d.%d.%d", cid, addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3] ); clients[cid].state = SRVCLIENT_STATE_INGAME; mods_client_enter(cid); } } else if(msg == NETMSG_INPUT) { int tick, size, i; CLIENT_INPUT *input; int64 tagtime; clients[cid].last_acked_snapshot = msg_unpack_int(); tick = msg_unpack_int(); size = msg_unpack_int(); /* check for errors */ if(msg_unpack_error() || size/4 > MAX_INPUT_SIZE) return; if(clients[cid].last_acked_snapshot > 0) clients[cid].snap_rate = SRVCLIENT_SNAPRATE_FULL; if(snapstorage_get(&clients[cid].snapshots, clients[cid].last_acked_snapshot, &tagtime, 0, 0) >= 0) clients[cid].latency = (int)(((time_get()-tagtime)*1000)/time_freq()); /* add message to report the input timing */ /* skip packets that are old */ if(tick > clients[cid].last_input_tick) { int time_left = ((server_tick_start_time(tick)-time_get())*1000) / time_freq(); msg_pack_start_system(NETMSG_INPUTTIMING, 0); msg_pack_int(tick); msg_pack_int(time_left); msg_pack_end(); server_send_msg(cid); } clients[cid].last_input_tick = tick; input = &clients[cid].inputs[clients[cid].current_input]; if(tick <= server_tick()) tick = server_tick()+1; input->game_tick = tick; for(i = 0; i < size/4; i++) input->data[i] = msg_unpack_int(); mem_copy(clients[cid].latestinput.data, input->data, MAX_INPUT_SIZE*sizeof(int)); clients[cid].current_input++; clients[cid].current_input %= 200; /* call the mod with the fresh input data */ if(clients[cid].state == SRVCLIENT_STATE_INGAME) mods_client_direct_input(cid, clients[cid].latestinput.data); } else if(msg == NETMSG_RCON_CMD) { const char *cmd = msg_unpack_string(); if(msg_unpack_error() == 0 && clients[cid].authed) { dbg_msg("server", "cid=%d rcon='%s'", cid, cmd); console_execute_line(cmd); } } else if(msg == NETMSG_RCON_AUTH) { const char *pw; msg_unpack_string(); /* login name, not used */ pw = msg_unpack_string(); if(msg_unpack_error() == 0) { if(config.sv_rcon_password[0] == 0) { server_send_rcon_line(cid, "No rcon password set on server. Set sv_rcon_password to enable the remote console."); } else if(strcmp(pw, config.sv_rcon_password) == 0) { msg_pack_start_system(NETMSG_RCON_AUTH_STATUS, MSGFLAG_VITAL); msg_pack_int(1); msg_pack_end(); server_send_msg(cid); clients[cid].authed = 1; server_send_rcon_line(cid, "Authentication successful. Remote console access granted."); dbg_msg("server", "cid=%d authed", cid); } else { server_send_rcon_line(cid, "Wrong password."); } } } else if(msg == NETMSG_PING) { msg_pack_start_system(NETMSG_PING_REPLY, 0); msg_pack_end(); server_send_msg(cid); } else { char hex[] = "0123456789ABCDEF"; char buf[512]; int b; for(b = 0; b < packet->data_size && b < 32; b++) { buf[b*3] = hex[((const unsigned char *)packet->data)[b]>>4]; buf[b*3+1] = hex[((const unsigned char *)packet->data)[b]&0xf]; buf[b*3+2] = ' '; buf[b*3+3] = 0; } dbg_msg("server", "strange message cid=%d msg=%d data_size=%d", cid, msg, packet->data_size); dbg_msg("server", "%s", buf); } } else { /* game message */ if(clients[cid].state >= SRVCLIENT_STATE_READY) mods_message(msg, cid); } }
static void server_do_snap() { int i; { static PERFORMACE_INFO scope = {"presnap", 0}; perf_start(&scope); mods_presnap(); perf_end(); } /* create snapshot for demo recording */ if(demorec_isrecording()) { char data[MAX_SNAPSHOT_SIZE]; int snapshot_size; /* build snap and possibly add some messages */ snapbuild_init(&builder); mods_snap(-1); snapshot_size = snapbuild_finish(&builder, data); /* write snapshot */ demorec_record_snapshot(server_tick(), data, snapshot_size); } /* create snapshots for all clients */ for(i = 0; i < MAX_CLIENTS; i++) { /* client must be ingame to recive snapshots */ if(clients[i].state != SRVCLIENT_STATE_INGAME) continue; /* this client is trying to recover, don't spam snapshots */ if(clients[i].snap_rate == SRVCLIENT_SNAPRATE_RECOVER && (server_tick()%50) != 0) continue; /* this client is trying to recover, don't spam snapshots */ if(clients[i].snap_rate == SRVCLIENT_SNAPRATE_INIT && (server_tick()%10) != 0) continue; { char data[MAX_SNAPSHOT_SIZE]; char deltadata[MAX_SNAPSHOT_SIZE]; char compdata[MAX_SNAPSHOT_SIZE]; int snapshot_size; int crc; static SNAPSHOT emptysnap; SNAPSHOT *deltashot = &emptysnap; int deltashot_size; int delta_tick = -1; int deltasize; static PERFORMACE_INFO scope = {"build", 0}; perf_start(&scope); snapbuild_init(&builder); { static PERFORMACE_INFO scope = {"modsnap", 0}; perf_start(&scope); mods_snap(i); perf_end(); } /* finish snapshot */ snapshot_size = snapbuild_finish(&builder, data); crc = snapshot_crc((SNAPSHOT*)data); /* remove old snapshos */ /* keep 3 seconds worth of snapshots */ snapstorage_purge_until(&clients[i].snapshots, current_tick-SERVER_TICK_SPEED*3); /* save it the snapshot */ snapstorage_add(&clients[i].snapshots, current_tick, time_get(), snapshot_size, data, 0); /* find snapshot that we can preform delta against */ emptysnap.data_size = 0; emptysnap.num_items = 0; { deltashot_size = snapstorage_get(&clients[i].snapshots, clients[i].last_acked_snapshot, 0, &deltashot, 0); if(deltashot_size >= 0) delta_tick = clients[i].last_acked_snapshot; else { /* no acked package found, force client to recover rate */ if(clients[i].snap_rate == SRVCLIENT_SNAPRATE_FULL) clients[i].snap_rate = SRVCLIENT_SNAPRATE_RECOVER; } } /* create delta */ { static PERFORMACE_INFO scope = {"delta", 0}; perf_start(&scope); deltasize = snapshot_create_delta(deltashot, (SNAPSHOT*)data, deltadata); perf_end(); } if(deltasize) { /* compress it */ int snapshot_size; const int max_size = MAX_SNAPSHOT_PACKSIZE; int numpackets; int n, left; { static PERFORMACE_INFO scope = {"compress", 0}; /*char buffer[512];*/ perf_start(&scope); snapshot_size = intpack_compress(deltadata, deltasize, compdata); /*str_hex(buffer, sizeof(buffer), compdata, snapshot_size); dbg_msg("", "deltasize=%d -> %d : %s", deltasize, snapshot_size, buffer);*/ perf_end(); } numpackets = (snapshot_size+max_size-1)/max_size; for(n = 0, left = snapshot_size; left; n++) { int chunk = left < max_size ? left : max_size; left -= chunk; if(numpackets == 1) msg_pack_start_system(NETMSG_SNAPSINGLE, MSGFLAG_FLUSH); else msg_pack_start_system(NETMSG_SNAP, MSGFLAG_FLUSH); msg_pack_int(current_tick); msg_pack_int(current_tick-delta_tick); /* compressed with */ if(numpackets != 1) { msg_pack_int(numpackets); msg_pack_int(n); } msg_pack_int(crc); msg_pack_int(chunk); msg_pack_raw(&compdata[n*max_size], chunk); msg_pack_end(); server_send_msg(i); } } else { msg_pack_start_system(NETMSG_SNAPEMPTY, MSGFLAG_FLUSH); msg_pack_int(current_tick); msg_pack_int(current_tick-delta_tick); /* compressed with */ msg_pack_end(); server_send_msg(i); } perf_end(); } } mods_postsnap(); }
void mods_message(int msgtype, int client_id) { void *rawmsg = netmsg_secure_unpack(msgtype); PLAYER *p = game.players[client_id]; 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 = p->team; else team = GAMECONTEXT::CHAT_ALL; if(config.sv_spamprotection && p->last_chat+time_freq() > time_get()) { if(!strcmp(msg->message, "/rank") && game.controller->is_race()) game.players[client_id]->last_chat = time_get()+time_freq()*10; else game.players[client_id]->last_chat = time_get(); } else { game.players[client_id]->last_chat = time_get(); if(!strcmp(msg->message, "/info")) { char buf[128]; str_format(buf, sizeof(buf), "DJUMP 0.32 from EliteKuchen.", RACE_VERSION); game.send_chat_target(client_id, buf); str_format(buf, sizeof(buf), "based on : Race mod %s from Rajh and Redix.", RACE_VERSION); game.send_chat_target(client_id, buf); } else if(!strncmp(msg->message, "/top5", 5) && game.controller->is_race()) { const char *pt = msg->message; int number = 0; pt += 6; while(*pt && *pt >= '0' && *pt <= '9') { number = number*10+(*pt-'0'); pt++; } if(number) ((GAMECONTROLLER_RACE*)game.controller)->score.top5_draw(client_id, number); else ((GAMECONTROLLER_RACE*)game.controller)->score.top5_draw(client_id, 0); } else if(!strncmp(msg->message, "/rank", 5) && game.controller->is_race()) { char buf[512]; const char *name = msg->message; name += 6; int pos; PLAYER_SCORE *pscore; if(!strcmp(msg->message, "/rank")) pscore = ((GAMECONTROLLER_RACE*)game.controller)->score.search_score(client_id, 1, &pos); else pscore = ((GAMECONTROLLER_RACE*)game.controller)->score.search_name(name, &pos, 1); if(pscore && pos > -1) { int punkte = pscore->points; char client_name[128]; str_format(client_name, sizeof(client_name), " (%s)", server_clientname(client_id)); str_format(buf, sizeof(buf), "%d. %s Points:%d", pos, pscore->name, punkte); if(strcmp(msg->message, "/rank")) strcat(buf, client_name); game.send_chat(-1, GAMECONTEXT::CHAT_ALL, buf); game.players[client_id]->last_chat = time_get()+time_freq()*3; return; } else if(pos == -1) str_format(buf, sizeof(buf), "Several players were found."); else str_format(buf, sizeof(buf), "%s is not ranked", strcmp(msg->message, "/rank")?name:server_clientname(client_id)); game.send_chat_target(client_id, buf); } else if(!strcmp(msg->message, "/cmdlist")) { game.send_chat_target(client_id, "---Command List---"); game.send_chat_target(client_id, "\"/info\" information about the mod"); game.send_chat_target(client_id, "\"/rank\" shows your rank"); game.send_chat_target(client_id, "\"/rank NAME\" shows the rank of a specific player"); game.send_chat_target(client_id, "\"/top5 X\" shows the top 5"); } else if(!strncmp(msg->message, "/", 1)) { game.send_chat_target(client_id, "Wrong command."); game.send_chat_target(client_id, "Say \"/cmdlist\" for list of command available."); } else game.send_chat(client_id, team, msg->message); } } else if(msgtype == NETMSGTYPE_CL_CALLVOTE) { int64 now = time_get(); if(game.vote_closetime) { game.send_chat_target(client_id, "Wait for current vote to end before calling a new one."); return; } int64 timeleft = p->last_votecall + time_freq()*60 - now; if(timeleft > 0) { char chatmsg[512] = {0}; str_format(chatmsg, sizeof(chatmsg), "You must wait %d seconds before making another vote", (timeleft/time_freq())+1); game.send_chat_target(client_id, chatmsg); return; } char chatmsg[512] = {0}; char desc[512] = {0}; char cmd[512] = {0}; NETMSG_CL_CALLVOTE *msg = (NETMSG_CL_CALLVOTE *)rawmsg; if(str_comp_nocase(msg->type, "option") == 0) { VOTEOPTION *option = voteoption_first; while(option) { if(str_comp_nocase(msg->value, option->command) == 0) { str_format(chatmsg, sizeof(chatmsg), "%s called vote to change server option '%s'", server_clientname(client_id), option->command); str_format(desc, sizeof(desc), "%s", option->command); str_format(cmd, sizeof(cmd), "%s", option->command); break; } option = option->next; } if(!option) { str_format(chatmsg, sizeof(chatmsg), "'%s' isn't an option on this server", msg->value); game.send_chat_target(client_id, chatmsg); return; } } else if(str_comp_nocase(msg->type, "kick") == 0) { if(!config.sv_vote_kick) { game.send_chat_target(client_id, "Server does not allow voting to kick players"); return; } int kick_id = atoi(msg->value); if(kick_id < 0 || kick_id >= MAX_CLIENTS || !game.players[kick_id]) { game.send_chat_target(client_id, "Invalid client id to kick"); return; } str_format(chatmsg, sizeof(chatmsg), "%s called for vote to kick '%s'", server_clientname(client_id), server_clientname(kick_id)); str_format(desc, sizeof(desc), "Kick '%s'", server_clientname(kick_id)); str_format(cmd, sizeof(cmd), "kick %d", kick_id); if (!config.sv_vote_kick_bantime) str_format(cmd, sizeof(cmd), "kick %d", kick_id); else str_format(cmd, sizeof(cmd), "ban %d %d", kick_id, config.sv_vote_kick_bantime); } if(cmd[0]) { game.send_chat(-1, GAMECONTEXT::CHAT_ALL, chatmsg); game.start_vote(desc, cmd); p->vote = 1; game.vote_creator = client_id; p->last_votecall = now; game.send_vote_status(-1); } } else if(msgtype == NETMSGTYPE_CL_VOTE) { if(!game.vote_closetime) return; if(p->vote == 0) { NETMSG_CL_VOTE *msg = (NETMSG_CL_VOTE *)rawmsg; p->vote = msg->vote; game.send_vote_status(-1); } } else if (msgtype == NETMSGTYPE_CL_SETTEAM && !game.world.paused) { NETMSG_CL_SETTEAM *msg = (NETMSG_CL_SETTEAM *)rawmsg; if(p->team == msg->team || (config.sv_spamprotection && p->last_setteam+time_freq()*3 > time_get())) return; // Switch team on given client and kill/respawn him if(game.controller->can_join_team(msg->team, client_id)) { if(game.controller->can_change_team(p, msg->team)) { p->last_setteam = time_get(); p->set_team(msg->team); (void) game.controller->check_team_balance(); } else game.send_broadcast("Teams must be balanced, please join other team", client_id); } 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; if(config.sv_spamprotection && p->last_changeinfo+time_freq()*5 > time_get()) return; p->last_changeinfo = time_get(); p->use_custom_color = msg->use_custom_color; p->color_body = msg->color_body; p->color_feet = msg->color_feet; // check for invalid chars unsigned char *name = (unsigned char *)msg->name; while (*name) { if(*name < 32) *name = ' '; name++; } // 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(p->skin_name, msg->skin, sizeof(p->skin_name)); game.controller->on_player_info_change(p); if(msgtype == NETMSGTYPE_CL_STARTINFO) { // send vote options NETMSG_SV_VOTE_CLEAROPTIONS clearmsg; clearmsg.pack(MSGFLAG_VITAL); server_send_msg(client_id); VOTEOPTION *current = voteoption_first; while(current) { NETMSG_SV_VOTE_OPTION optionmsg; optionmsg.command = current->command; optionmsg.pack(MSGFLAG_VITAL); server_send_msg(client_id); current = current->next; } // 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); } } else if (msgtype == NETMSGTYPE_CL_EMOTICON && !game.world.paused) { NETMSG_CL_EMOTICON *msg = (NETMSG_CL_EMOTICON *)rawmsg; if(config.sv_spamprotection && p->last_emote+time_freq()*3 > time_get()) return; p->last_emote = time_get(); game.send_emoticon(client_id, msg->emoticon); } else if (msgtype == NETMSGTYPE_CL_KILL && !game.world.paused) { if(p->last_kill+time_freq()*3 > time_get()) return; p->last_kill = time_get(); p->kill_character(WEAPON_SELF); p->respawn_tick = server_tick()+server_tickspeed()*3; if(game.controller->is_race()) p->respawn_tick = server_tick(); } }