You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
SQA-Homework/gcov&lcov/server.cpp

2799 lines
93 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <arpa/inet.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <cstdarg>
#include <csignal>
#include <cstring>
#include <cctype>
#include <ctime>
#include <cmath>
#include <vector>
#include <list>
#include <set>
#include "constants.h"
#include "server.h"
#include "common.h"
#include "func.h"
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <queue>
//#define REGISTERED_USER_LIST_SIZE 100
#define REGISTERED_USER_LIST_SIZE 10
#define REGISTERED_USER_FILE "userlists.log"
using std::multiset;
using std::vector;
pthread_mutex_t userlist_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t sessions_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t battles_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t default_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t items_lock[USER_CNT];
int server_fd = 0, port = 50000, port_range = 100;
void check_user_status(int uid);
void wrap_recv(int conn, client_message_t* pcm);
void wrap_send(int conn, server_message_t* psm);
void send_to_client(int uid, int message);
void send_to_client(int uid, int message, char* str);
void say_to_client(int uid, char* message);
void send_to_client_with_username(int uid, int message, char* user_name);
void close_session(int conn, int message);
void terminate_process(int recved_signal);
void load_user_list();
void save_user_list();
void save_user(int i);
int query_session_built(uint32_t uid);
void inform_all_user_battle_player(int bid);
void user_quit_battle(uint32_t bid, uint32_t uid);
void user_join_battle_common_part(uint32_t bid, uint32_t uid, uint32_t joined_state);
void user_join_battle(uint32_t bid, uint32_t uid);
void user_invited_to_join_battle(uint32_t bid, uint32_t uid);
int find_uid_by_user_name(const char* user_name);
int get_unalloced_battle();
int get_unused_session();
void inform_friends(int uid, int message);
//void forced_generate_items(int bid, int x, int y, int kind, int count, int uid = -1);
void random_generate_items(int bid);
void move_bullets(int bid);
void check_user_status(int uid);
void check_all_user_status(int bid);
void check_who_is_dead(int bid);
void clear_items(int bid);
void render_map_for_user(int uid, server_message_t* psm);
void inform_all_user_battle_state(int bid);
void* battle_ruler(void* args);
int check_user_registered(char* user_name, char* password);
void launch_battle(int bid);
int admin_set_admin(int argc, char** argv);
int admin_set_energy(int argc, char** argv);
int admin_set_hp(int argc, char** argv);
int admin_set_pos(int argc, char** argv);
int admin_ban_user(int argc, char** argv);
int client_command_admin_control(int uid);
int client_message_fatal(int uid);
void init_handler();
void* session_start(void* args);
void* run_battle(void* args);
int server_start();
void terminate_process(int signum);
void terminate_entrance(int signum);
void list_all_users(server_message_t* psm);
int invite_friend_to_battle(int bid, int uid, char* friend_name);
int client_command_user_login(int uid);
int client_command_user_register(int uid);
int client_command_launch_battle(int uid);
int client_command_quit_battle(int uid);
int client_command_invite_user(int uid);
int client_command_send_message(int uid);
int client_command_create_ffa(int uid);
int client_command_launch_ffa(int uid);
int client_command_accept_battle(int uid);
int client_command_reject_battle(int uid);
int client_command_quit(int uid);
int client_command_move_up(int uid);
int client_command_move_down(int uid);
int client_command_move_left(int uid);
int client_command_move_right(int uid);
int client_command_put_landmine(int uid);
int client_command_fire(int uid, int delta_x, int delta_y, int dir);
int client_command_fire_up(int uid);
int client_command_fire_down(int uid);
int client_command_fire_left(int uid);
int client_command_fire_right(int uid);
int client_command_fire_up_left(int uid);
int client_command_fire_up_right(int uid);
int client_command_fire_down_left(int uid);
int client_command_fire_down_right(int uid);
int client_command_fire_aoe(int uid, int dir);
int client_command_fire_aoe_up(int uid);
int client_command_fire_aoe_down(int uid);
int client_command_fire_aoe_left(int uid);
int client_command_fire_aoe_right(int uid);
int client_command_melee(int uid);
int client_command_user_logout(int uid);
int client_command_fetch_all_users(int uid);
int client_command_fetch_all_friends(int uid);
static int user_list_size = 0;
//static uint64_t sum_delay_time = 0, prev_time;
struct {
char user_name[USERNAME_SIZE];
char password[PASSWORD_SIZE];
} registered_user_list[REGISTERED_USER_LIST_SIZE];
struct session_t {
char user_name[USERNAME_SIZE];
char ip_addr[IPADDR_SIZE];
int conn;
int state;
int is_admin;
int score;
int kill;
int death;
uint32_t bid;
uint32_t inviter_id;
client_message_t cm;
} sessions[USER_CNT];
struct session_args_t {
int conn;
char ip_addr[IPADDR_SIZE];
};
typedef struct session_args_t session_args_t;
class item_t { public:
int id;
int dir;
int owner;
uint64_t time;
int count;
int kind;
pos_t pos;
item_t(const item_t &it) : id(it.id),
dir(it.dir),
owner(it.owner),
time(it.time),
count(it.count),
kind(it.kind),
pos(it.pos)
{}
item_t() {
id = 0;
dir = owner = time = count = kind = 0;
pos.x = pos.y = 0;
}
friend const bool operator < (const item_t it1, const item_t it2) {
return it1.time < it2.time;
}
};
class battle_t { public:
int is_alloced;
size_t alive_users;
size_t all_users;
class user_t { public:
int battle_state;
int energy;
int dir;
int life;
int killby;
pos_t pos;
pos_t last_pos;
} users[USER_CNT];
int num_of_other; // number of other alloced item except for bullet
int item_count;
uint64_t global_time;
std::list<item_t> items;
void reset() {
is_alloced = all_users = alive_users = num_of_other = item_count = 0;
global_time = 0;
items.clear();
}
battle_t() {
reset();
}
} battles[USER_CNT];
void load_user_list() {
FILE* userlist = fopen(REGISTERED_USER_FILE, "r");
if (userlist == NULL) {
log("can not find " REGISTERED_USER_FILE "");
return;
}
#define LOAD_FAIL \
log("failed to load users, try to delete " REGISTERED_USER_FILE "."), \
user_list_size = 0, memset(registered_user_list, 0, sizeof(registered_user_list)), \
fclose(userlist);
for (int i = 0; i < REGISTERED_USER_LIST_SIZE; i++) {
cout<<"asdad:"<<i<<endl;
if (fgets(registered_user_list[i].user_name, USERNAME_SIZE, userlist) != NULL) {
registered_user_list[i].user_name[strlen(registered_user_list[i].user_name) - 1] = 0;
for (int j = 0; j < i; j++) {
if (strncmp(registered_user_list[i].user_name, registered_user_list[j].user_name, USERNAME_SIZE - 1) != 0)
continue;
LOAD_FAIL;
return;
}
user_list_size++;
} else {
break;
}
if (fgets(registered_user_list[i].password, PASSWORD_SIZE, userlist) == NULL) {
LOAD_FAIL;
return;
}
registered_user_list[i].password[strlen(registered_user_list[i].password) - 1] = 0;
}
#undef LOAD_FAIL
//for (int i = 0; i < user_list_size; i++) {
// log("loaded user %s", registered_user_list[i].user_name);
//}
log("loaded %d user(s) from " REGISTERED_USER_FILE ".", user_list_size);
fclose(userlist);
}
void save_user_list() {
FILE* userlist = fopen(REGISTERED_USER_FILE, "w");
for (int i = 0; i < user_list_size; i++) {
fprintf(userlist, "%s\n", registered_user_list[i].user_name);
fprintf(userlist, "%s\n", registered_user_list[i].password);
}
log("saved %d users to " REGISTERED_USER_FILE ".", user_list_size);
fclose(userlist);
}
void save_user(int i) {
FILE* userlist = fopen(REGISTERED_USER_FILE, "a");
fprintf(userlist, "%s\n", registered_user_list[i].user_name);
fprintf(userlist, "%s\n", registered_user_list[i].password);
log("saved users %s to " REGISTERED_USER_FILE ".", registered_user_list[i].user_name);
fclose(userlist);
}
int client_command_user_register(int uid) {
int ul_index = -1;
char* user_name = sessions[uid].cm.user_name;
char* password = sessions[uid].cm.password;
log("user %s tries to register with password %s", user_name, password);
for (int i = 0; i < REGISTERED_USER_LIST_SIZE; i++) {
if (strncmp(user_name, registered_user_list[i].user_name, USERNAME_SIZE - 1) != 0)
continue;
log("user %s&%s has been registered", user_name, password);
send_to_client(uid, SERVER_RESPONSE_YOU_HAVE_REGISTERED);
return 0;
}
pthread_mutex_lock(&userlist_lock);
if (user_list_size < REGISTERED_USER_LIST_SIZE)
ul_index = user_list_size++;
pthread_mutex_unlock(&userlist_lock);
log("fetch empty user list index #%d", ul_index);
if (ul_index == -1) {
log("user %s registers fail", user_name);
send_to_client(uid, SERVER_RESPONSE_REGISTER_FAIL);
} else {
log("user %s registers success", user_name);
strncpy(registered_user_list[ul_index].user_name,
user_name, USERNAME_SIZE - 1);
strncpy(registered_user_list[ul_index].password,
password, PASSWORD_SIZE - 1);
send_to_client(uid, SERVER_RESPONSE_REGISTER_SUCCESS);
save_user(ul_index);
}
return 0;
}
int client_command_user_login(int uid) {
int is_dup = 0;
client_message_t* pcm = &sessions[uid].cm;
char* user_name = pcm->user_name;
char* password = pcm->password;
char* ip_addr = sessions[uid].ip_addr;
log("user #%d %s\033[2m(%s)\033[0m try to login", uid, user_name, ip_addr);
int message = check_user_registered(user_name, password);
if (query_session_built(uid)) {
log("user #%d %s\033[2m(%s)\033[0m has logined", uid, sessions[uid].user_name, sessions[uid].ip_addr);
send_to_client(uid, SERVER_RESPONSE_YOU_HAVE_LOGINED);
return 0;
}
for (int i = 0; i < USER_CNT; i++) {
if (query_session_built(i)) {
logi("check dup user id: %s vs. %s", user_name, sessions[i].user_name);
if (strncmp(user_name, sessions[i].user_name, USERNAME_SIZE - 1) == 0) {
log("user #%d %s duplicate with %dth user %s\033[2m(%s)\033[0m", uid, user_name, i, sessions[i].user_name, sessions[i].ip_addr);
is_dup = 1;
break;
}
}
}
// no duplicate user ids found
cout<<"dup: "<<is_dup<<endl;
if (is_dup) {
log("send fail dup id message to client.");
send_to_client(uid, SERVER_RESPONSE_LOGIN_FAIL_DUP_USERID);
sessions[uid].state = USER_STATE_NOT_LOGIN;
} else if (message == SERVER_RESPONSE_LOGIN_SUCCESS) {
log("user %s login success", user_name);
sessions[uid].state = USER_STATE_LOGIN;
send_to_client(
uid,
SERVER_RESPONSE_LOGIN_SUCCESS,
sformat("Welcome to multiplayer shooting game! server \033[0;32m%s%s", version, color_s[0]));
strncpy(sessions[uid].user_name, user_name, USERNAME_SIZE - 1);
inform_friends(uid, SERVER_MESSAGE_FRIEND_LOGIN);
} else {
send_to_client(uid, message);
}
return 0;
}
int client_command_user_logout(int uid) {
if (sessions[uid].state == USER_STATE_BATTLE
|| sessions[uid].state == USER_STATE_WAIT_TO_BATTLE) {
log("user #%d %s\033[2m(%s)\033[0m tries to logout was in battle", uid, sessions[uid].user_name, sessions[uid].ip_addr);
user_quit_battle(sessions[uid].bid, uid);
}
log("user #%d %s\033[2m(%s)\033[0m logout", uid, sessions[uid].user_name, sessions[uid].ip_addr);
sessions[uid].state = USER_STATE_NOT_LOGIN;
inform_friends(uid, SERVER_MESSAGE_FRIEND_LOGOUT);
return 0;
}
int query_session_built(uint32_t uid) {
//assert(uid < USER_CNT);
if (sessions[uid].state == USER_STATE_UNUSED
|| sessions[uid].state == USER_STATE_NOT_LOGIN) {
return false;
} else {
return true;
}
}
void inform_all_user_battle_player(int bid);
void user_quit_battle(uint32_t bid, uint32_t uid) {
//assert(bid < USER_CNT && uid < USER_CNT);
log("user %s\033[2m(%s)\033[0m quit from battle %d(%ld/%ld users)", sessions[uid].user_name, sessions[uid].ip_addr, bid, battles[bid].alive_users, battles[bid].all_users);
battles[bid].all_users--;
if (battles[bid].users[uid].battle_state == BATTLE_STATE_LIVE) {
battles[bid].alive_users--;
if (battles[bid].alive_users != 0) {
sessions[uid].score = max(sessions[uid].score - 5, 0);
sessions[uid].death ++;
}
}
battles[bid].users[uid].battle_state = BATTLE_STATE_UNJOINED;
sessions[uid].state = USER_STATE_LOGIN;
if (battles[bid].all_users == 0) {
// disband battle
log("disband battle %d", bid);
battles[bid].reset();
} else {
server_message_t sm;
sm.message = SERVER_MESSAGE_USER_QUIT_BATTLE;
strncpy(sm.friend_name, sessions[uid].user_name, USERNAME_SIZE - 1);
for (int i = 0; i < USER_CNT; i++) {
if (battles[bid].users[i].battle_state != BATTLE_STATE_UNJOINED) {
//wrap_send(sessions[i].conn, &sm);
}
}
}
}
void user_join_battle_common_part(uint32_t bid, uint32_t uid, uint32_t joined_state) {
log("user %s\033[2m(%s)\033[0m join in battle %d", sessions[uid].user_name, sessions[uid].ip_addr, bid);
if (joined_state == USER_STATE_BATTLE) {
battles[bid].all_users++;
battles[bid].alive_users++;
log("now %ld alive of %ld users", battles[bid].alive_users, battles[bid].all_users);
battles[bid].users[uid].battle_state = BATTLE_STATE_LIVE;
} else if (joined_state == USER_STATE_WAIT_TO_BATTLE) {
battles[bid].users[uid].battle_state = BATTLE_STATE_UNJOINED;
} else {
loge("check here, other joined_state:%d", joined_state);
}
battles[bid].users[uid].life = INIT_LIFE;
battles[bid].users[uid].energy = INIT_BULLETS;
sessions[uid].state = joined_state;
sessions[uid].bid = bid;
}
void user_join_battle(uint32_t bid, uint32_t uid) {
int ux = (rand() & 0x7FFF) % BATTLE_W;
int uy = (rand() & 0x7FFF) % BATTLE_H;
battles[bid].users[uid].pos.x = ux;
battles[bid].users[uid].pos.y = uy;
log("alloc position (%hhu, %hhu) for launcher #%d %s",
ux, uy, uid, sessions[uid].user_name);
sessions[uid].state = USER_STATE_BATTLE;
if (battles[bid].users[uid].battle_state == BATTLE_STATE_UNJOINED) {
user_join_battle_common_part(bid, uid, USER_STATE_BATTLE);
}
}
void user_invited_to_join_battle(uint32_t bid, uint32_t uid) {
if (sessions[uid].state == USER_STATE_WAIT_TO_BATTLE
&& bid != sessions[uid].bid) {
log("user #%d %s\033[2m(%s)\033[0m rejects old battle #%d since he was invited to a new battle",
uid, sessions[uid].user_name, sessions[uid].ip_addr, sessions[uid].bid);
send_to_client_with_username(sessions[uid].inviter_id, SERVER_MESSAGE_FRIEND_REJECT_BATTLE, sessions[uid].user_name);
}
user_join_battle_common_part(bid, uid, USER_STATE_WAIT_TO_BATTLE);
}
int find_uid_by_user_name(const char* user_name) {
int ret_uid = -1;
log("find user %s", user_name);
for (int i = 0; i < USER_CNT; i++) {
if (query_session_built(i)) {
if (strncmp(user_name, sessions[i].user_name, USERNAME_SIZE - 1) == 0) {
ret_uid = i;
break;
}
}
}
if (ret_uid == -1) {
logi("fail");
} else {
logi("found: #%d %s\033[2m(%s)\033[0m", ret_uid, sessions[ret_uid].user_name, sessions[ret_uid].ip_addr);
}
return ret_uid;
}
int get_unalloced_battle() {
int ret_bid = -1;
pthread_mutex_lock(&battles_lock);
for (int i = 1; i < USER_CNT; i++) {
if (battles[i].is_alloced == false) {
battles[i].reset();
battles[i].is_alloced = true;
ret_bid = i;
break;
}
}
pthread_mutex_unlock(&battles_lock);
if (ret_bid == -1) {
loge("check here, returned battle id should not be -1");
} else {
log("alloc unalloced battle id #%d", ret_bid);
}
return ret_bid;
}
int get_unused_session() {
int ret_uid = -1;
pthread_mutex_lock(&sessions_lock);
for (int i = 0; i < USER_CNT; i++) {
if (sessions[i].state == USER_STATE_UNUSED) {
memset(&sessions[i], 0, sizeof(struct session_t));
sessions[i].conn = -1;
sessions[i].state = USER_STATE_NOT_LOGIN;
ret_uid = i;
break;
}
}
pthread_mutex_unlock(&sessions_lock);
if (ret_uid == -1) {
log("fail to alloc session id");
} else {
log("alloc unused session id #%d", ret_uid);
}
return ret_uid;
}
void inform_friends(int uid, int message) {
server_message_t sm;
char* user_name = sessions[uid].user_name;
memset(&sm, 0, sizeof(server_message_t));
sm.message = message;
for (int i = 0; i < USER_CNT; i++) {
if (i == uid || !query_session_built(i))
continue;
strncpy(sm.friend_name, user_name, USERNAME_SIZE - 1);
//wrap_send(sessions[i].conn, &sm);
}
}
void forced_generate_items(int bid, int x, int y, int kind, int count, int uid = -1) {
//if (battles[bid].num_of_other >= MAX_OTHER) return;
if (x < 0 || x >= BATTLE_W) return; //60
if (y < 0 || y >= BATTLE_H) return; //21
battles[bid].item_count++;
item_t new_item;
new_item.id = battles[bid].item_count;
new_item.kind = kind;
new_item.pos.x = x;
new_item.pos.y = y;
new_item.time = battles[bid].global_time + count;
new_item.owner = uid;
if (kind == ITEM_MAGMA) {
new_item.count = MAGMA_INIT_TIMES;
}
/*
battles[bid].items.push_back(new_item);
log("new %s #%d (%d,%d)",
item_s[new_item.kind],
new_item.id,
new_item.pos.x,
new_item.pos.y);
*/
}
void random_generate_items(int bid) {
int random_kind;
//if (!probability(1, 100)) return; // rand 退出
if (battles[bid].num_of_other >= MAX_OTHER) return;
/* delete
random_kind = rand() % (ITEM_END - 1) + 1;
if (random_kind == ITEM_BLOOD_VIAL && probability(1, 2))
random_kind = ITEM_MAGAZINE;
*/
random_kind = ITEM_MAGAZINE;
battles[bid].item_count++;
item_t new_item;
new_item.id = battles[bid].item_count;
new_item.kind = random_kind;
new_item.pos.x = (rand() & 0x7FFF) % BATTLE_W;
new_item.pos.y = (rand() & 0x7FFF) % BATTLE_H;
new_item.time = battles[bid].global_time + OTHER_ITEM_LASTS_TIME;
battles[bid].num_of_other++;
/* delete
log("new %s #%d (%d,%d)",
item_s[new_item.kind],
new_item.id,
new_item.pos.x,
new_item.pos.y);
*/
/* delete
if (random_kind == ITEM_MAGMA) {
new_item.count = MAGMA_INIT_TIMES;
}
*/
//battles[bid].items.push_back(new_item); //delete
//for (int i = 0; i < USER_CNT; i++) {
// if (battles[bid].users[i].battle_state != BATTLE_STATE_LIVE)
// continue;
// check_user_status(i);
//}
}
void move_bullets(int bid) {
for (auto& cur : battles[bid].items) {
//for (int i = 0; i < MAX_ITEM; i++) {
if (cur.kind != ITEM_BULLET)
continue;
// log("try to move bullet %d with dir %d", i, cur.dir);
switch (cur.dir) {
case DIR_UP: {
if (cur.pos.y > 0) {
(cur.pos.y)--;
break;
}
else {
cur.dir = DIR_DOWN;
break;
}
}
case DIR_DOWN: {
if (cur.pos.y < BATTLE_H - 1) {
(cur.pos.y)++;
break;
}
else {
cur.dir = DIR_UP;
break;
}
}
case DIR_LEFT: {
if (cur.pos.x > 0) {
(cur.pos.x)--;
break;
}
else {
cur.dir = DIR_RIGHT;
break;
}
}
case DIR_RIGHT: {
if (cur.pos.x < BATTLE_W - 1) {
(cur.pos.x)++;
break;
}
else {
cur.dir = DIR_LEFT;
break;
}
}
case DIR_UP_LEFT: {
if (cur.pos.y > 0) {
(cur.pos.y)--;
}
else {
cur.dir = DIR_DOWN_LEFT;
break;
}
if (cur.pos.x > 1) {
(cur.pos.x) -= 2;
}
else {
cur.dir = DIR_UP_RIGHT;
break;
}
break;
}
case DIR_UP_RIGHT: {
if (cur.pos.y > 0) {
(cur.pos.y)--;
}
else {
cur.dir = DIR_DOWN_RIGHT;
break;
}
if (cur.pos.x < BATTLE_W - 2) {
(cur.pos.x) += 2;
}
else {
cur.dir = DIR_UP_LEFT;
break;
}
break;
}
case DIR_DOWN_LEFT: {
if (cur.pos.y < BATTLE_H - 2) {
(cur.pos.y)++;
}
else {
cur.dir = DIR_UP_LEFT;
break;
}
if (cur.pos.x > 1) {
(cur.pos.x) -= 2;
}
else {
cur.dir = DIR_DOWN_RIGHT;
break;
}
break;
}
case DIR_DOWN_RIGHT: {
if (cur.pos.y < BATTLE_H - 2) {
(cur.pos.y)++;
}
else {
cur.dir = DIR_UP_RIGHT;
break;
}
if (cur.pos.x < BATTLE_W - 2) {
(cur.pos.x) += 2;
}
else {
cur.dir = DIR_DOWN_LEFT;
break;
}
break;
}
}
}
}
void check_user_status(int uid) {
//log("checking...");
//auto start_time = myclock();
int bid = sessions[uid].bid;
int ux = battles[bid].users[uid].pos.x;
int uy = battles[bid].users[uid].pos.y;
//for (int i = 0; i < MAX_ITEM; i++) {
auto& items = battles[bid].items;
if (battles[bid].users[uid].battle_state != BATTLE_STATE_LIVE) {
return;
}
for (auto it = items.begin(); it != items.end(); it++) {
//next = std::next(it);, next = std::next(it) => it++
int ix = it->pos.x;
int iy = it->pos.y;
if (ix == ux && iy == uy) {
switch (it->kind) {
case ITEM_MAGAZINE: {
battles[bid].users[uid].energy += BULLETS_PER_MAGAZINE;
//log("user #%d %s\033[2m(%s)\033[0m is got magazine", uid, sessions[uid].user_name, sessions[uid].ip_addr);
if (battles[bid].users[uid].energy > MAX_BULLETS) {
//log("user #%d %s\033[2m(%s)\033[0m 's bullets exceeds max value", uid, sessions[uid].user_name, sessions[uid].ip_addr);
battles[bid].users[uid].energy = MAX_BULLETS;
}
//send_to_client(uid, SERVER_MESSAGE_YOU_GOT_MAGAZINE);
it = items.erase(it);
//log("current item size: %ld", items.size());
break;
}
case ITEM_MAGMA: {
if (it->owner != uid) {
battles[bid].users[uid].life = max(battles[bid].users[uid].life - 1, 0);
battles[bid].users[uid].killby = it->owner;
it->count--;
//log("user #%d %s\033[2m(%s)\033[0m is trapped in magma", uid, sessions[uid].user_name, sessions[uid].ip_addr);
//send_to_client(uid, SERVER_MESSAGE_YOU_ARE_TRAPPED_IN_MAGMA);
if (it->count <= 0) {
//log("magma #%d is exhausted", it->id);
battles[bid].num_of_other--;
it = items.erase(it);
//log("current item size: %ld", items.size());
}
}
break;
}
case ITEM_BLOOD_VIAL: {
battles[bid].users[uid].life += LIFE_PER_VIAL;
//log("user #%d %s\033[2m(%s)\033[0m got blood vial", uid, sessions[uid].user_name, sessions[uid].ip_addr);
if (battles[bid].users[uid].life > MAX_LIFE) {
//log("user #%d %s\033[2m(%s)\033[0m life exceeds max value", uid, sessions[uid].user_name, sessions[uid].ip_addr);
battles[bid].users[uid].life = MAX_LIFE;
}
//log("current item size: %ld", items.size());
battles[bid].num_of_other--;
//send_to_client(uid, SERVER_MESSAGE_YOU_GOT_BLOOD_VIAL);
it = items.erase(it);
break;
}
case ITEM_BULLET: {
if (it->owner != uid) {
battles[bid].users[uid].life = max(battles[bid].users[uid].life - 1, 0);
battles[bid].users[uid].killby = it->owner;
//log("user #%d %s\033[2m(%s)\033[0m is shooted", uid, sessions[uid].user_name, sessions[uid].ip_addr);
//log("current item size: %ld", items.size());
//send_to_client(uid, SERVER_MESSAGE_YOU_ARE_SHOOTED);
it = items.erase(it);
break;
}
break;
}
case ITEM_LANDMINE: {
if (it->owner != uid) {
it->time = battles[bid].global_time;
forced_generate_items(bid, ix, iy, ITEM_MAGMA, 7, it->owner);
forced_generate_items(bid, ix - 1, iy, ITEM_MAGMA, 7, it->owner);
forced_generate_items(bid, ix + 1, iy, ITEM_MAGMA, 7, it->owner);
forced_generate_items(bid, ix, iy - 1, ITEM_MAGMA, 7, it->owner);
forced_generate_items(bid, ix, iy + 1, ITEM_MAGMA, 7, it->owner);
}
break;
}
}
}
}
//auto end_time = myclock();
//log("completed.");
}
void check_all_user_status(int bid) {
//for (int i = 0; i < MAX_ITEM; i++) {
//log("checking...");
//log("completed.");
for (int i = 0; i < USER_CNT; i++) {
if (battles[bid].users[i].battle_state != BATTLE_STATE_LIVE) continue;
check_user_status(i);
}
}
void check_who_is_dead(int bid) {
for (int i = 0; i < USER_CNT; i++) {
if (battles[bid].users[i].battle_state == BATTLE_STATE_LIVE
&& battles[bid].users[i].life <= 0) {
log("user #%d %s\033[2m(%s)\033[0m is dead", i, sessions[i].user_name, sessions[i].ip_addr);
battles[bid].users[i].battle_state = BATTLE_STATE_DEAD;
battles[bid].alive_users--;
log("send dead info to user #%d %s\033[2m(%s)\033[0m", i, sessions[i].user_name, sessions[i].ip_addr);
send_to_client(i, SERVER_MESSAGE_YOU_ARE_DEAD);
sessions[i].death++;
log("death of user #%d %s\033[2m(%s)\033[0m: %d", i, sessions[i].user_name, sessions[i].ip_addr, sessions[i].death);
if (battles[bid].users[i].killby != -1) {
int by = battles[bid].users[i].killby;
sessions[by].kill++;
log("kill of user #%d %s\033[2m(%s)\033[0m: %d", i, sessions[by].user_name, sessions[by].ip_addr, sessions[by].kill);
double delta = (double)sessions[i].score / sessions[by].score;
delta = delta * delta;
if (delta > 4) delta = 4;
if (delta < 0.2) delta = 0.2;
int d = min(round(5. * delta), sessions[i].score);
sessions[i].score -= d;
sessions[by].score += d;
battles[bid].users[by].energy += battles[bid].users[i].energy;
} else {
sessions[i].score = max(sessions[i].score - 5, 0);
}
} else if (battles[bid].users[i].battle_state == BATTLE_STATE_DEAD) {
battles[bid].users[i].battle_state = BATTLE_STATE_WITNESS;
battles[bid].users[i].energy = 0;
battles[bid].users[i].life = 0;
}
}
}
void clear_items(int bid) {
//log("call func %s", __func__);
//for (int i = 0; i < MAX_ITEM; i++) {
// if (battles[bid].items[i].times) {
// battles[bid].items[i].times--;
// if (!battles[bid].items[i].times) {
// log("free item #%d", i);
// battles[bid].items[i].is_used = false;
// if (battles[bid].items[i].kind < ITEM_END) {
// battles[bid].num_of_other--;
// }
// //battles[bid].items[i].kind = ITEM_BLANK;
// }
// }
//}
//log("check completed...");
auto& items = battles[bid].items;
size_t cnt[ITEM_SIZE] = {0};
// 有修改 可能会有bug
for (auto cur = items.begin(); cur != items.end(); cur++) {
//next = std::next(cur); , next = std::next(cur)
if (cur->time <= battles[bid].global_time) {
if (cur->kind < ITEM_END) {
battles[bid].num_of_other--;
}
cnt[cur->kind]++;
//next = battles[bid].items.erase(cur);
cur = battles[bid].items.erase(cur);
}
}
//int cleared = 0;
for (int i = 0; i < ITEM_SIZE; i++) {
if (cnt[i]) {
//log("clear %ld %s(s)", cnt[i], item_s[i]);
//cleared = 1;
}
}
//if (cleared) log("current item size: %ld", items.size());
}
void render_map_for_user(int uid, server_message_t* psm) {
int bid = sessions[uid].bid;
int map[BATTLE_H][BATTLE_W] = {0};
int cur, x, y;
//for (int i = 0, x, y; i < MAX_ITEM; i++) {
for (auto it : battles[bid].items) {
x = it.pos.x;
y = it.pos.y;
switch (it.kind) {
case ITEM_BULLET: {
if (it.owner == uid) {
map[y][x] = max(map[y][x], MAP_ITEM_MY_BULLET);
} else {
map[y][x] = max(map[y][x], MAP_ITEM_OTHER_BULLET);
}
break;
}
case ITEM_LANDMINE: {
if (it.owner != uid) break;
map[y][x] = max(map[y][x], item_to_map[ITEM_LANDMINE]);
}
default: {
cur = item_to_map[it.kind];
map[y][x] = max(map[y][x], cur);
}
}
//sm.item_kind[i] = it.kind;
//sm.item_pos[i].x = it.pos.x;
//sm.item_pos[i].y = it.pos.y;
}
for (int i = 0; i < BATTLE_H; i++) {
for (int j = 0; j < BATTLE_W; j += 2) {
//psm->map[i][j] = map[i][j];
//if (psm->map[i][j] != 0) log("set item #%d", psm->map[i][j]);
psm->map[i][j >> 1] = (map[i][j]) | (map[i][j + 1] << 4);
}
}
}
void inform_all_user_battle_player(int bid) {
server_message_t sm;
sm.message = SERVER_MESSAGE_BATTLE_PLAYER;
for (int i = 0; i < USER_CNT; i++) {
if (battles[bid].users[i].battle_state == BATTLE_STATE_LIVE &&
battles[bid].users[i].life > 0) {
strncpy(sm.users[i].name, sessions[i].user_name, USERNAME_SIZE - 1);
sm.users[i].namecolor = i % color_s_size + 1;
sm.users[i].life = battles[bid].users[i].life;
sm.users[i].score = sessions[i].score;
sm.users[i].death = sessions[i].death;
sm.users[i].kill = sessions[i].kill;
} else {
strcpy(sm.users[i].name, (char*)"");
sm.users[i].namecolor = 0;
sm.users[i].life = 0;
sm.users[i].score = 0;
sm.users[i].death = 0;
sm.users[i].kill = 0;
}
}
for (int i = 0; i < USER_CNT; i++) {
for (int j = i + 1; j < USER_CNT; j++) {
if (sm.users[i].score < sm.users[j].score) {
std::swap(sm.users[i], sm.users[j]);
}
}
}
for (int i = 0; i < USER_CNT; i++) {
if (battles[bid].users[i].battle_state != BATTLE_STATE_UNJOINED) {
//wrap_send(sessions[i].conn, &sm);
//log("inform user #%d %s\033[2m(%s)\033[0m", i, sessions[i].user_name, sessions[i].ip_addr);
}
}
}
void inform_all_user_battle_state(int bid) {
server_message_t sm;
sm.message = SERVER_MESSAGE_BATTLE_INFORMATION;
for (int i = 0; i < USER_CNT; i++) {
if (battles[bid].users[i].battle_state == BATTLE_STATE_LIVE) {
sm.user_pos[i].x = battles[bid].users[i].pos.x;
sm.user_pos[i].y = battles[bid].users[i].pos.y;
sm.user_color[i] = i % color_s_size + 1;
} else {
sm.user_pos[i].x = -1;
sm.user_pos[i].y = -1;
sm.user_color[i] = 0;
}
}
for (int i = 0; i < USER_CNT; i++) {
if (battles[bid].users[i].battle_state != BATTLE_STATE_UNJOINED) {
render_map_for_user(i, &sm);
sm.index = i;
sm.life = battles[bid].users[i].life;
sm.bullets_num = battles[bid].users[i].energy;
sm.color = i % color_s_size + 1;
//wrap_send(sessions[i].conn, &sm);
}
}
}
void* battle_ruler(void* args) {
int bid = (int)(uintptr_t)args;
//log("battle ruler for battle #%d", bid);
// FIXME: battle re-alloced before exiting loop
for (int i = 0; i < INIT_GRASS; i++) {
forced_generate_items(bid,
(rand() & 0x7FFF) % BATTLE_W,
(rand() & 0x7FFF) % BATTLE_H,
ITEM_GRASS,
10000);
}
uint64_t t[2];
while (battles[bid].is_alloced) {
battles[bid].global_time++;
t[0] = myclock();
move_bullets(bid);
check_all_user_status(bid);
//check_who_is_dead(bid);
inform_all_user_battle_state(bid);
if (battles[bid].global_time % 10 == 0) {
inform_all_user_battle_player(bid);
}
clear_items(bid);
random_generate_items(bid);
t[1] = myclock();
/* 时间种子 不测
if (t[1] - t[0] >= 5)
//logw("current delay %lums", t[1] - t[0]);
//sum_delay_time += t[1] - t[0];
while (myclock() < t[0] + GLOBAL_SPEED)
usleep(1000);
*/
}
return NULL;
}
int check_user_registered(char* user_name, char* password) {
for (int i = 0; i < REGISTERED_USER_LIST_SIZE; i++) {
if (strncmp(user_name, registered_user_list[i].user_name, USERNAME_SIZE - 1) != 0)
continue;
if (strncmp(password, registered_user_list[i].password, PASSWORD_SIZE - 1) != 0) {
logi("user name %s sent error password", user_name);
return SERVER_RESPONSE_LOGIN_FAIL_ERROR_PASSWORD;
} else {
return SERVER_RESPONSE_LOGIN_SUCCESS;
}
}
logi("user name %s hasn't been registered", user_name);
return SERVER_RESPONSE_LOGIN_FAIL_UNREGISTERED_USERID;
}
void launch_battle(int bid) {
pthread_t thread;
pthread_create(&thread, NULL, battle_ruler, (void*)(uintptr_t)bid);
/*
log("try to create battle_ruler thread");
if (pthread_create(&thread, NULL, battle_ruler, (void*)(uintptr_t)bid) == -1) {
eprintf("fail to launch battle");
}
*/
}
void list_all_users(server_message_t* psm) {
for (int i = 0; i < USER_CNT; i++) {
if (query_session_built(i)) {
//log("%s: found %s %s", __func__, sessions[i].user_name,
//sessions[i].state == USER_STATE_BATTLE ? "in battle" : "");
psm->all_users[i].user_state = sessions[i].state;
strncpy(psm->all_users[i].user_name, sessions[i].user_name, USERNAME_SIZE - 1);
}
}
}
int client_command_fetch_all_users(int uid) {
char* user_name = sessions[uid].user_name;
//log("user #%d %s\033[2m(%s)\033[0m tries to fetch all users's info", uid, user_name, sessions[uid].user_name);
if (!query_session_built(uid)) {
//logi("user #%d %s\033[2m(%s)\033[0m who tries to list users hasn't login", uid, user_name, sessions[uid].user_name);
//send_to_client(uid, SERVER_RESPONSE_YOU_HAVE_NOT_LOGIN);
return 0;
}
server_message_t sm;
memset(&sm, 0, sizeof(server_message_t));
//list_all_users(&sm);
sm.response = SERVER_RESPONSE_ALL_USERS_INFO;
//wrap_send(sessions[uid].conn, &sm);
return 0;
}
int client_command_fetch_all_friends(int uid) {
char *user_name = sessions[uid].user_name;
//log("user %s tries to fetch info", user_name);
if (!query_session_built(uid)) {
//logi("user %s who tries to list users hasn't login", user_name);
//send_to_client(uid, SERVER_RESPONSE_YOU_HAVE_NOT_LOGIN);
return 0;
}
server_message_t sm;
memset(&sm, 0, sizeof(server_message_t));
list_all_users(&sm);
sm.all_users[uid].user_state = USER_STATE_UNUSED;
sm.response = SERVER_RESPONSE_ALL_FRIENDS_INFO;
//wrap_send(sessions[uid].conn, &sm);
return 0;
}
int invite_friend_to_battle(int bid, int uid, char* friend_name) {
int friend_id = find_uid_by_user_name(friend_name);
if (friend_id == -1) {
// fail to find friend
logi("friend %s hasn't login", friend_name);
send_to_client(uid, SERVER_MESSAGE_FRIEND_NOT_LOGIN);
} else if (friend_id == uid) {
logi("launch battle %d for %s", bid, sessions[uid].user_name);
sessions[uid].inviter_id = uid;
send_to_client(uid, SERVER_RESPONSE_INVITATION_SENT);
} else if (sessions[friend_id].state == USER_STATE_BATTLE) {
// friend already in battle
logi("friend %s already in battle", friend_name);
send_to_client(uid, SERVER_MESSAGE_FRIEND_ALREADY_IN_BATTLE);
} else {
// invite friend
logi("friend #%d %s found", friend_id, friend_name);
user_invited_to_join_battle(bid, friend_id);
// WARNING: can't move this statement
sessions[friend_id].inviter_id = uid;
send_to_client_with_username(friend_id, SERVER_MESSAGE_INVITE_TO_BATTLE, sessions[uid].user_name);
}
return 0;
}
int client_command_launch_battle(int uid) {
if (sessions[uid].state == USER_STATE_BATTLE) {
log("user %s who tries to launch battle has been in battle", sessions[uid].user_name);
send_to_client(uid, SERVER_RESPONSE_YOURE_ALREADY_IN_BATTLE);
return 0;
} else {
log("user %s tries to launch battle", sessions[uid].user_name);
}
int bid = get_unalloced_battle();
client_message_t* pcm = &sessions[uid].cm;
log("%s launch battle with %s", sessions[uid].user_name, pcm->user_name);
if (bid == -1) {
loge("fail to create battle for %s and %s", sessions[uid].user_name, pcm->user_name);
send_to_client(uid, SERVER_RESPONSE_LAUNCH_BATTLE_FAIL);
return 0;
} else {
logi("launch battle %d for %s, invite %s", bid, sessions[uid].user_name, pcm->user_name);
user_join_battle(bid, uid);
cout<<"test:"<<pcm->user_name<<endl;
if (strcmp(pcm->user_name, ""))
invite_friend_to_battle(bid, uid, pcm->user_name);
launch_battle(bid);
send_to_client(uid, SERVER_RESPONSE_LAUNCH_BATTLE_SUCCESS);
}
return 0;
}
int client_command_quit_battle(int uid) {
log("user %s tries to quit battle", sessions[uid].user_name);
if (sessions[uid].state != USER_STATE_BATTLE) {
logi("but he hasn't join battle");
send_to_client(uid, SERVER_RESPONSE_YOURE_NOT_IN_BATTLE);
} else {
logi("call user_quit_battle to quit");
user_quit_battle(sessions[uid].bid, uid);
}
return 0;
}
int client_command_invite_user(int uid) {
client_message_t* pcm = &sessions[uid].cm;
int bid = sessions[uid].bid;
int friend_id = find_uid_by_user_name(pcm->user_name);
log("user #%d %s\033[2m(%s)\033[0m tries to invite friend", uid, sessions[uid].user_name, sessions[uid].ip_addr);
if (sessions[uid].state != USER_STATE_BATTLE) {
log("user %s\033[2m(%s)\033[0m who invites friend %s wasn't in battle", sessions[uid].user_name, sessions[uid].ip_addr, pcm->user_name);
send_to_client(uid, SERVER_RESPONSE_YOURE_NOT_IN_BATTLE);
} else {
logi("invite user %s\033[2m(%s)\033[0m to battle #%d", sessions[friend_id].user_name, sessions[uid].ip_addr, bid);
invite_friend_to_battle(bid, uid, pcm->user_name);
}
return 0;
}
int client_command_send_message(int uid) {
client_message_t* pcm = &sessions[uid].cm;
server_message_t sm;
memset(&sm, 0, sizeof(server_message_t));
sm.message = SERVER_MESSAGE_FRIEND_MESSAGE;
strncpy(sm.from_user, sessions[uid].user_name, USERNAME_SIZE);
strncpy(sm.msg, pcm->message, MSG_SIZE);
if (pcm->user_name[0] == '\0') {
//logi("user %d:%s\033[2m(%s)\033[0m yells at all users: %s", uid, sessions[uid].user_name, sessions[uid].ip_addr, pcm->message);
int i;
for (i = 0; i < USER_CNT; i++) {
if (uid == i)
continue;
//wrap_send(sessions[i].conn, &sm);
int w = -1; // test
}
}
else {
return 0; // test
/*
int friend_id = find_uid_by_user_name(pcm->user_name);
if (friend_id == -1 || friend_id == uid) {
logi("user %d:%s\033[2m(%s)\033[0m fails to speak to %s:`%s`", uid, sessions[uid].user_name, sessions[uid].ip_addr, pcm->user_name, pcm->message);
} else {
logi("user %d:%s\033[2m(%s)\033[0m speaks to %d:%s : `%s`", uid, sessions[uid].user_name, sessions[uid].ip_addr, friend_id, pcm->user_name, pcm->message);
wrap_send(sessions[friend_id].conn, &sm);
}
*/
}
return 0;
}
int client_command_create_ffa(int uid) {
if (sessions[uid].state == USER_STATE_BATTLE) {
log("user %s who tries to launch battle has been in battle", sessions[uid].user_name);
send_to_client(uid, SERVER_RESPONSE_YOURE_ALREADY_IN_BATTLE);
return 0;
} else {
log("user %s tries to create ffa sessions #0", sessions[uid].user_name);
}
int bid = 0;
client_message_t* pcm = &sessions[uid].cm;
log("%s launch battle with %s", sessions[uid].user_name, pcm->user_name);
cout<<"state: "<<battles[bid].is_alloced<<endl;
if (battles[bid].is_alloced) {
loge("fail to create battle for %s and %s", sessions[uid].user_name, pcm->user_name);
send_to_client(uid, SERVER_RESPONSE_LAUNCH_BATTLE_FAIL);
return 0;
} else {
logi("launch battle #0 for ffa");
battles[bid].is_alloced = true;
user_join_battle(bid, uid);
if (strcmp(pcm->user_name, ""))
invite_friend_to_battle(bid, uid, pcm->user_name);
launch_battle(bid);
send_to_client(uid, SERVER_RESPONSE_LAUNCH_BATTLE_SUCCESS);
}
return 0;
}
int client_command_launch_ffa(int uid) {
log("user %s\033[2m(%s)\033[0m try ffa", sessions[uid].user_name, sessions[uid].ip_addr);
if (sessions[uid].state == USER_STATE_BATTLE) {
logi("already in battle");
send_to_client(uid, SERVER_RESPONSE_YOURE_ALREADY_IN_BATTLE);
} else {
int bid = 0;
if (battles[bid].is_alloced) {
user_join_battle(bid, uid);
logi("accept success");
} else {
logi("user %s created ffa session #0", sessions[uid].user_name);
client_command_create_ffa(uid);
}
}
return 0;
}
int client_command_accept_battle(int uid) {
log("user %s\033[2m(%s)\033[0m accept battle #%d", sessions[uid].user_name, sessions[uid].ip_addr, sessions[uid].bid);
if (sessions[uid].state == USER_STATE_BATTLE) {
logi("already in battle");
send_to_client(uid, SERVER_RESPONSE_YOURE_ALREADY_IN_BATTLE);
} else if (sessions[uid].state == USER_STATE_WAIT_TO_BATTLE) {
int inviter_id = sessions[uid].inviter_id;
int bid = sessions[uid].bid;
if (battles[bid].is_alloced) {
send_to_client_with_username(inviter_id, SERVER_MESSAGE_FRIEND_ACCEPT_BATTLE, sessions[inviter_id].user_name);
user_join_battle(bid, uid);
logi("accept success");
} else {
logi("user %s\033[2m(%s)\033[0m accept battle which didn't exist", sessions[uid].user_name, sessions[uid].ip_addr);
send_to_client(uid, SERVER_RESPONSE_YOURE_ALREADY_IN_BATTLE);
}
} else {
logi("hasn't been invited");
send_to_client(uid, SERVER_RESPONSE_NOBODY_INVITE_YOU);
}
return 0;
}
int client_command_reject_battle(int uid) {
log("user %s\033[2m(%s)\033[0m reject battle #%d", sessions[uid].user_name, sessions[uid].ip_addr, sessions[uid].bid);
if (sessions[uid].state == USER_STATE_BATTLE) {
logi("user already in battle");
send_to_client(uid, SERVER_RESPONSE_YOURE_ALREADY_IN_BATTLE);
} else if (sessions[uid].state == USER_STATE_WAIT_TO_BATTLE) {
logi("reject success");
int bid = sessions[uid].bid;
send_to_client(sessions[uid].inviter_id, SERVER_MESSAGE_FRIEND_REJECT_BATTLE);
sessions[uid].state = USER_STATE_LOGIN;
battles[bid].users[uid].battle_state = BATTLE_STATE_UNJOINED;
} else {
logi("hasn't been invited");
send_to_client(uid, SERVER_RESPONSE_NOBODY_INVITE_YOU);
}
return 0;
}
int client_command_quit(int uid) {
int conn = sessions[uid].conn;
if (sessions[uid].state == USER_STATE_BATTLE
|| sessions[uid].state == USER_STATE_WAIT_TO_BATTLE) {
log("user #%d %s tries to quit client was in battle", uid, sessions[uid].user_name);
user_quit_battle(sessions[uid].bid, uid);
}
if (sessions[uid].conn >= 0) {
sessions[uid].conn = -1;
log("user #%d %s quit", uid, sessions[uid].user_name);
sessions[uid].state = USER_STATE_UNUSED;
close(conn);
}
return -1;
}
int client_command_move_up(int uid) {
log("user #%d %s\033[2m(%s)\033[0m move up", uid, sessions[uid].user_name, sessions[uid].ip_addr);
int bid = sessions[uid].bid;
battles[bid].users[uid].dir = DIR_UP;
if (battles[bid].users[uid].pos.y > 0) {
battles[bid].users[uid].pos.y--;
check_user_status(uid);
}
return 0;
}
int client_command_move_down(int uid) {
log("user #%d %s\033[2m(%s)\033[0m move down", uid, sessions[uid].user_name, sessions[uid].ip_addr);
int bid = sessions[uid].bid;
battles[bid].users[uid].dir = DIR_DOWN;
if (battles[bid].users[uid].pos.y < BATTLE_H - 1) {
battles[bid].users[uid].pos.y++;
check_user_status(uid);
}
return 0;
}
int client_command_move_left(int uid) {
log("user #%d %s\033[2m(%s)\033[0m move left", uid, sessions[uid].user_name, sessions[uid].ip_addr);
int bid = sessions[uid].bid;
battles[bid].users[uid].dir = DIR_LEFT;
if (battles[bid].users[uid].pos.x > 0) {
battles[bid].users[uid].pos.x--;
check_user_status(uid);
}
return 0;
}
int client_command_move_right(int uid) {
log("user #%d %s\033[2m(%s)\033[0m move right", uid, sessions[uid].user_name, sessions[uid].ip_addr);
int bid = sessions[uid].bid;
battles[bid].users[uid].dir = DIR_RIGHT;
if (battles[bid].users[uid].pos.x < BATTLE_W - 1) {
battles[bid].users[uid].pos.x++;
check_user_status(uid);
}
return 0;
}
int client_command_put_landmine(int uid) {
int bid = sessions[uid].bid;
if (battles[bid].users[uid].energy < LANDMINE_COST) {
//send_to_client(uid, SERVER_MESSAGE_YOUR_MAGAZINE_IS_EMPTY);
return 0;
}
int x = battles[bid].users[uid].pos.x;
int y = battles[bid].users[uid].pos.y;
/*
if (x < 0 || x >= BATTLE_W) return 1;
if (y < 0 || y >= BATTLE_H) return 1;
*/
if ( x >= BATTLE_W) return 1;
if ( y >= BATTLE_H) return 1;
//log("user #%d %s\033[2m(%s)\033[0m put at (%d, %d)", uid, sessions[uid].user_name, sessions[uid].ip_addr, x, y);
item_t new_item;
new_item.id = ++battles[bid].item_count;
new_item.kind = ITEM_LANDMINE;
new_item.owner = uid;
new_item.pos.x = x;
new_item.pos.y = y;
new_item.time = battles[bid].global_time + INF;
battles[bid].users[uid].energy -= LANDMINE_COST;
//battles[bid].items.push_back(new_item);
//log("current item size: %ld", battles[bid].items.size());
return 0;
}
int client_command_fire(int uid, int delta_x, int delta_y, int dir) {
int bid = sessions[uid].bid;
if (battles[bid].users[uid].energy <= 0) {
//send_to_client(uid, SERVER_MESSAGE_YOUR_MAGAZINE_IS_EMPTY);
return 0;
}
int x = battles[bid].users[uid].pos.x + delta_x;
int y = battles[bid].users[uid].pos.y + delta_y;
if (x < 0 || x >= BATTLE_W) return 1;
if (y < 0 || y >= BATTLE_H) return 1;
//log("user #%d %s\033[2m(%s)\033[0m fire %s", uid, sessions[uid].user_name, sessions[uid].ip_addr, dir_s[dir]);
item_t new_item;
new_item.id = ++battles[bid].item_count;
new_item.kind = ITEM_BULLET;
new_item.dir = dir;
new_item.owner = uid;
new_item.pos.x = x;
new_item.pos.y = y;
new_item.time = battles[bid].global_time + BULLETS_LASTS_TIME;
battles[bid].users[uid].energy--;
//battles[bid].items.push_back(new_item); // 奇怪的分支 先注释掉
//log("current item size: %ld", battles[bid].items.size());
return 0;
}
int client_command_fire_up(int uid) {
logi("client_command_fire");
client_command_fire(uid, 0, 0, DIR_UP);
return 0;
}
int client_command_fire_down(int uid) {
logi("client_command_fire");
client_command_fire(uid, 0, 0, DIR_DOWN);
return 0;
}
int client_command_fire_left(int uid) {
logi("client_command_fire");
client_command_fire(uid, 0, 0, DIR_LEFT);
return 0;
}
int client_command_fire_right(int uid) {
logi("client_command_fire");
client_command_fire(uid, 0, 0, DIR_RIGHT);
return 0;
}
int client_command_fire_up_left(int uid) {
logi("client_command_fire");
client_command_fire(uid, 0, 0, DIR_UP_LEFT);
return 0;
}
int client_command_fire_up_right(int uid) {
logi("client_command_fire");
client_command_fire(uid, 0, 0, DIR_UP_RIGHT);
return 0;
}
int client_command_fire_down_left(int uid) {
logi("client_command_fire");
client_command_fire(uid, 0, 0, DIR_DOWN_LEFT);
return 0;
}
int client_command_fire_down_right(int uid) {
logi("client_command_fire");
client_command_fire(uid, 0, 0, DIR_DOWN_RIGHT);
return 0;
}
int client_command_fire_aoe(int uid, int dir) {
log("user #%d %s\033[2m(%s)\033[0m fire(aoe) %s", uid, sessions[uid].user_name, sessions[uid].ip_addr, dir_s[dir]);
logi("call client_command_fire");
int limit = battles[sessions[uid].bid].users[uid].energy / 2, cnt = 0;
for (int i = 0; limit; i++) {
for (int j = -i; j <= i && limit; j++) {
switch (dir) {
case DIR_UP: {
if (client_command_fire(uid, j, -i + abs(j), dir) == 0) cnt++;
break;
}
case DIR_DOWN: {
if (client_command_fire(uid, j, i - abs(j), dir) == 0) cnt++;
break;
}
case DIR_LEFT: {
if (client_command_fire(uid, -i + abs(j), j, dir) == 0) cnt++;
break;
}
case DIR_RIGHT: {
if (client_command_fire(uid, i - abs(j), j, dir) == 0) cnt++;
break;
}
}
limit--;
}
}
log("created %d bullets", cnt);
return 0;
}
int client_command_fire_aoe_up(int uid) {
logi("call client_command_fire_aoe");
return client_command_fire_aoe(uid, DIR_UP);
}
int client_command_fire_aoe_down(int uid) {
logi("call client_command_fire_aoe");
return client_command_fire_aoe(uid, DIR_DOWN);
}
int client_command_fire_aoe_left(int uid) {
logi("call client_command_fire_aoe");
return client_command_fire_aoe(uid, DIR_LEFT);
}
int client_command_fire_aoe_right(int uid) {
logi("call client_command_fire_aoe");
return client_command_fire_aoe(uid, DIR_RIGHT);
}
int client_command_melee(int uid) {
int bid = sessions[uid].bid;
if (battles[bid].users[uid].life <= 0) return 0;
int dir = battles[bid].users[uid].dir;
int x = battles[bid].users[uid].pos.x;
int y = battles[bid].users[uid].pos.y;
log("user #%d %s\033[2m(%s)\033[0m melee %s", uid, sessions[uid].user_name, sessions[uid].ip_addr, dir_s[dir]);
for (int i = 1; i <= 3; i++) {
forced_generate_items(bid,
x + dir_offset[dir].x * i,
y + dir_offset[dir].y * i,
ITEM_MAGMA,
3,
uid);
}
return 0;
}
int admin_set_admin(int argc, char** argv) {
if (argc < 3) return -1;
cout<<"username: "<<argv[1]<<" status: "<<atoi(argv[2])<<" uid:";
cout<<find_uid_by_user_name(argv[1])<<endl;
int uid = find_uid_by_user_name(argv[1]),status = atoi(argv[2]);
if (uid < 0 ||
// uid >= USER_CNT ||
sessions[uid].conn < 0) {
return -1;
}
if (status)
log("admin set user #%d admin", uid);
else
log("admin set user #%d non-admin", uid);
sessions[uid].is_admin = status;
for (int i = 0; i < USER_CNT; i++) {
if (sessions[i].conn >= 0) {
if (status) {
say_to_client(i, sformat("admin set user #%d %s to admin", uid, sessions[uid].user_name));
} else {
say_to_client(i, sformat("admin set user #%d %s to non-admin", uid, sessions[uid].user_name));
}
}
}
return 0;
}
int admin_set_energy(int argc, char** argv) {
if (argc < 3) return -1;
int uid = find_uid_by_user_name(argv[1]), energy = atoi(argv[2]);
log("admin set user #%d's energy", uid);
cout<<"uid:"<<uid<<" conn:"<<sessions[uid].conn<<" energy:"<<energy<<endl;
if (uid < 0 || //uid >= USER_CNT ||
sessions[uid].conn < 0 ||
energy < 0) {
return -1;
}
log("admin set user #%d %s's energy to %d", uid, sessions[uid].user_name, energy);
battles[sessions[uid].bid].users[uid].energy = energy;
for (int i = 0; i < USER_CNT; i++) {
if (sessions[i].conn >= 0) {
say_to_client(i, sformat("admin set user #%d %s's energy to %d", uid, sessions[uid].user_name, energy));
}
}
return 0;
}
int admin_set_hp(int argc, char** argv) {
if (argc < 3) return -1;
int uid = find_uid_by_user_name(argv[1]), hp = atoi(argv[2]);
if (uid < 0 || //uid >= USER_CNT||
sessions[uid].conn < 0 ||
hp < 0) {
return -1;
}
log("admin set user #%d %s's hp to %d", uid, sessions[uid].user_name, hp);
battles[sessions[uid].bid].users[uid].life = hp;
for (int i = 0; i < USER_CNT; i++) {
if (sessions[i].conn >= 0) {
say_to_client(i, sformat("admin set user #%d %s's hp to %d", uid, sessions[uid].user_name, hp));
}
}
return 0;
}
int admin_set_pos(int argc, char** argv) {
if (argc < 4) return -1;
int uid = find_uid_by_user_name(argv[1]);
int x = atoi(argv[2]), y = atoi(argv[3]);
cout<<"x:"<<atoi(argv[2])<<"y:"<<atoi(argv[3])<<endl;
cout<<"uid: "<<uid<<"conn: "<<sessions[uid].conn<<endl;
if (uid < 0 || //uid >= USER_CNT ||
sessions[uid].conn < 0) {
return -1;
}
cout<<"x:"<<x<<"y:"<<y<<endl;
if (x < 0 || x >= BATTLE_W) return -1;
if (y < 0 || y >= BATTLE_H) return -1;
log("admin set user #%d %s's pos to (%d, %d)", uid, sessions[uid].user_name, x, y);
battles[sessions[uid].bid].users[uid].pos.x = x;
battles[sessions[uid].bid].users[uid].pos.y = y;
return 0;
}
int admin_ban_user(int argc, char** argv) {
if (argc < 2) return -1;
int uid = find_uid_by_user_name(argv[1]);
log("admin ban user #%d", uid);
if (uid < 0 // || uid >= USER_CNT
) {
logi("fail");
return -1;
}
if (sessions[uid].conn >= 0) {
log("admin banned user #%d %s\033[2m(%s)\033[0m", uid, sessions[uid].user_name, sessions[uid].ip_addr);
send_to_client(
uid, SERVER_STATUS_QUIT,
(char*)" (you were banned by admin)");
client_command_quit(uid);
for (int i = 0; i < USER_CNT; i++) {
if (sessions[i].conn >= 0) {
say_to_client(i, sformat("admin banned user #%d %s\033[2m(%s)\033[0m", uid, sessions[uid].user_name, sessions[uid].ip_addr));
}
}
}
return 0;
}
static struct {
const char* cmd;
int (*func)(int argc, char** argv);
} admin_handler[] = {
{"ban", admin_ban_user},
{"eng", admin_set_energy},
{"energy", admin_set_energy},
{"hp", admin_set_hp},
{"setadmin", admin_set_admin},
{"pos", admin_set_pos},
};
#define NR_HANDLER ((int)sizeof(admin_handler) / (int)sizeof(admin_handler[0]))
int client_command_admin_control(int uid) {
if (!sessions[uid].is_admin) {
//say_to_client(uid, (char*)"you are not admin");
return 0;
}
client_message_t* pcm = &sessions[uid].cm;
char *buff = (char*)pcm->message;
//log("analysis command `%s`", buff);
/*
char *go = buff, *argv[ADMIN_COMMAND_LEN];
int argc = 0;
while (*go != 0) {
if (!isspace(*go)) {
argv[argc] = go;
argc++;
char c = (*go == '"') ? '"' : ' ';
while ((*go != 0) && (*go != c)) go++;
if (*go == 0) break;
*go = 0;
}
go++;
}
if (argc) {
argv[argc] = NULL;
for (int i = 0; i < NR_HANDLER; i++) {
if (strcmp(argv[0], admin_handler[i].cmd) == 0) {
if (admin_handler[i].func(argc, argv)) {
int s = 0;
//say_to_client(uid, (char*)"invalid command!");
}
return 0;
}
}
}
*/
//say_to_client(uid, (char*)"invalid command!");
return 0;
}
int client_message_fatal(int uid) {
loge("received FATAL from user #%d %s\033[2m(%s)\033[0m ", uid, sessions[uid].user_name, sessions[uid].ip_addr);
for (int i = 0; i < USER_CNT; i++) {
if (sessions[i].conn >= 0) {
send_to_client(i, SERVER_STATUS_FATAL);
log("send FATAL to user #%d %s\033[2m(%s)\033[0m", i, sessions[i].user_name, sessions[i].ip_addr);
}
}
//terminate_process(0);
return 0;
}
static int (*handler[256])(int);
void init_handler() {
handler[CLIENT_MESSAGE_FATAL] = client_message_fatal,
handler[CLIENT_COMMAND_USER_QUIT] = client_command_quit,
handler[CLIENT_COMMAND_USER_REGISTER] = client_command_user_register,
handler[CLIENT_COMMAND_USER_LOGIN] = client_command_user_login,
handler[CLIENT_COMMAND_USER_LOGOUT] = client_command_user_logout,
handler[CLIENT_COMMAND_FETCH_ALL_USERS] = client_command_fetch_all_users,
handler[CLIENT_COMMAND_FETCH_ALL_FRIENDS] = client_command_fetch_all_friends,
handler[CLIENT_COMMAND_LAUNCH_BATTLE] = client_command_launch_battle,
handler[CLIENT_COMMAND_QUIT_BATTLE] = client_command_quit_battle,
handler[CLIENT_COMMAND_ACCEPT_BATTLE] = client_command_accept_battle,
handler[CLIENT_COMMAND_LAUNCH_FFA] = client_command_launch_ffa,
handler[CLIENT_COMMAND_REJECT_BATTLE] = client_command_reject_battle,
handler[CLIENT_COMMAND_INVITE_USER] = client_command_invite_user,
handler[CLIENT_COMMAND_SEND_MESSAGE] = client_command_send_message,
handler[CLIENT_COMMAND_MOVE_UP] = client_command_move_up,
handler[CLIENT_COMMAND_MOVE_DOWN] = client_command_move_down,
handler[CLIENT_COMMAND_MOVE_LEFT] = client_command_move_left,
handler[CLIENT_COMMAND_MOVE_RIGHT] = client_command_move_right,
handler[CLIENT_COMMAND_PUT_LANDMINE] = client_command_put_landmine,
handler[CLIENT_COMMAND_MELEE] = client_command_melee,
handler[CLIENT_COMMAND_FIRE_UP] = client_command_fire_up,
handler[CLIENT_COMMAND_FIRE_DOWN] = client_command_fire_down,
handler[CLIENT_COMMAND_FIRE_LEFT] = client_command_fire_left,
handler[CLIENT_COMMAND_FIRE_RIGHT] = client_command_fire_right,
handler[CLIENT_COMMAND_FIRE_UP_LEFT] = client_command_fire_up_left,
handler[CLIENT_COMMAND_FIRE_UP_RIGHT] = client_command_fire_up_right,
handler[CLIENT_COMMAND_FIRE_DOWN_LEFT] = client_command_fire_down_left,
handler[CLIENT_COMMAND_FIRE_DOWN_RIGHT] = client_command_fire_down_right,
handler[CLIENT_COMMAND_FIRE_AOE_UP] = client_command_fire_aoe_up,
handler[CLIENT_COMMAND_FIRE_AOE_DOWN] = client_command_fire_aoe_down,
handler[CLIENT_COMMAND_FIRE_AOE_LEFT] = client_command_fire_aoe_left,
handler[CLIENT_COMMAND_FIRE_AOE_RIGHT] = client_command_fire_aoe_right;
handler[CLIENT_COMMAND_ADMIN_CONTROL] = client_command_admin_control;
}
/*
void wrap_recv(int conn, client_message_t* pcm) {
size_t total_len = 0;
while (total_len < sizeof(client_message_t)) {
size_t len = recv(conn, pcm + total_len, sizeof(client_message_t) - total_len, 0);
if (len < 0) {
loge("broken pipe");
}
total_len += len;
}
}
void wrap_send(int conn, server_message_t* psm) {
size_t total_len = 0;
while (total_len < sizeof(server_message_t)) {
size_t len = send(conn, psm + total_len, sizeof(server_message_t) - total_len, 0);
if (len < 0) {
loge("broken pipe");
}
total_len += len;
}
}
*/
void send_to_client(int uid, int message) {
int conn = sessions[uid].conn;
if (conn < 0) return;
server_message_t sm;
memset(&sm, 0, sizeof(server_message_t));
sm.response = message;
//wrap_send(conn, &sm);
}
void send_to_client(int uid, int message, char* str) {
int conn = sessions[uid].conn;
if (conn < 0) return;
server_message_t sm;
memset(&sm, 0, sizeof(server_message_t));
sm.response = message;
strncpy(sm.msg, str, MSG_SIZE - 1);
//wrap_send(conn, &sm);
}
void say_to_client(int uid, char *message) {
//log("say `%s` to user #%d %s", message, uid, sessions[uid].user_name);
int conn = sessions[uid].conn;
if (conn < 0) {
//logi("fail");
return; }
server_message_t sm;
memset(&sm, 0, sizeof(server_message_t));
sm.message = SERVER_MESSAGE;
strncpy(sm.msg, message, MSG_SIZE - 1);
//wrap_send(conn, &sm);
}
void send_to_client_with_username(int uid, int message, char* user_name) {
int conn = sessions[uid].conn;
if (conn < 0) return;
server_message_t sm;
memset(&sm, 0, sizeof(server_message_t));
sm.response = message;
strncpy(sm.friend_name, user_name, USERNAME_SIZE - 1);
//wrap_send(conn, &sm);
}
void close_session(int conn, int message) {
send_to_client(conn, message);
close(conn);
}
void* session_start(void* args) {
int uid = -1;
session_args_t info = *(session_args_t*)(uintptr_t)args;
client_message_t* pcm = NULL;
/*
if ((uid = get_unused_session()) < 0) {
close_session(info.conn, SERVER_RESPONSE_LOGIN_FAIL_SERVER_LIMITS);
return NULL;
} else {
*/
uid = 0;
sessions[uid].conn = info.conn;
strncpy(sessions[uid].user_name, "<unknown>", USERNAME_SIZE - 1);
strncpy(sessions[uid].ip_addr, info.ip_addr, IPADDR_SIZE - 1);
if (strncmp(sessions[uid].ip_addr, "", IPADDR_SIZE) == 0) {
strncpy(sessions[uid].ip_addr, "unknown", IPADDR_SIZE - 1);
}
pcm = &sessions[uid].cm;
memset(pcm, 0, sizeof(client_message_t));
//log("build session #%d", uid);
if (strncmp(info.ip_addr, "127.0.0.1", IPADDR_SIZE) == 0) {
//log("admin login!");
sessions[uid].is_admin = 1;
}
sessions[uid].death = sessions[uid].kill = 0;
sessions[uid].score = 50;
//}
/*
while (1) {
//wrap_recv(info.conn, pcm);
if (pcm->command >= CLIENT_COMMAND_END)
continue;
int ret_code = handler[pcm->command](uid);
if (ret_code < 0) {
//log("close session #%d", uid);
break;
}}
*/
return NULL;
}
void* run_battle(void* args) {
// TODO:
return NULL;
}
int server_start() {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
/*
if (sockfd < 0) {
eprintf("create Socket Failed!");
}
*/
struct sockaddr_in servaddr;
bool binded = false;
for (int cur_port = port; cur_port <= port + port_range; cur_port++) {
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(cur_port);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
/*
if (bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1) {
logw("can not bind to port %d!", cur_port);
} else {
binded = true;
port = cur_port;
break;
}
}
if (!binded) {
eprintf("can not start server.");
}
if (listen(sockfd, USER_CNT) == -1) {
eprintf("fail to listen on socket.");
} else {
log("listen on port %d.", port);
}
*/
bind(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
}
return sockfd;
}
void terminate_process(int signum) {
for (int i = 0; i < USER_CNT; i++) {
if (sessions[i].conn >= 0) {
log("send quit to user #%d %s\033[2m(%s)\033[0m", i, sessions[i].user_name, sessions[i].ip_addr);
if (signum) {
send_to_client(
i, SERVER_STATUS_QUIT,
sformat(" (runtime error: %s)", signal_name_s[signum]));
} else {
send_to_client(i, SERVER_STATUS_QUIT);
}
log("close conn:%d", sessions[i].conn);
//close(sessions[i].conn);
sessions[i].conn = -1;
}
}
if (server_fd) {
//close(server_fd);
log("close server fd:%d", server_fd);
}
pthread_mutex_destroy(&sessions_lock);
pthread_mutex_destroy(&battles_lock);
for (int i = 0; i < USER_CNT; i++) {
pthread_mutex_destroy(&items_lock[i]);
}
log("exit(%d)", signum);
//exit(signum);
}
void terminate_entrance(int signum) {
loge("received signal %s, terminate.", signal_name_s[signum]);
terminate_process(signum == SIGINT ? 0 : signum);
}
void init_handlers(char* url) {
handler[CLIENT_MESSAGE_FATAL] = client_message_fatal,
handler[CLIENT_COMMAND_USER_QUIT] = client_command_quit,
handler[CLIENT_COMMAND_USER_REGISTER] = client_command_user_register,
handler[CLIENT_COMMAND_USER_LOGIN] = client_command_user_login,
handler[CLIENT_COMMAND_USER_LOGOUT] = client_command_user_logout,
handler[CLIENT_COMMAND_FETCH_ALL_USERS] = client_command_fetch_all_users,
handler[CLIENT_COMMAND_FETCH_ALL_FRIENDS] = client_command_fetch_all_friends,
handler[CLIENT_COMMAND_LAUNCH_BATTLE] = client_command_launch_battle,
handler[CLIENT_COMMAND_QUIT_BATTLE] = client_command_quit_battle,
handler[CLIENT_COMMAND_ACCEPT_BATTLE] = client_command_accept_battle,
handler[CLIENT_COMMAND_LAUNCH_FFA] = client_command_launch_ffa,
handler[CLIENT_COMMAND_REJECT_BATTLE] = client_command_reject_battle,
handler[CLIENT_COMMAND_INVITE_USER] = client_command_invite_user,
handler[CLIENT_COMMAND_SEND_MESSAGE] = client_command_send_message,
handler[CLIENT_COMMAND_MOVE_UP] = client_command_move_up,
handler[CLIENT_COMMAND_MOVE_DOWN] = client_command_move_down,
handler[CLIENT_COMMAND_MOVE_LEFT] = client_command_move_left,
handler[CLIENT_COMMAND_MOVE_RIGHT] = client_command_move_right,
handler[CLIENT_COMMAND_PUT_LANDMINE] = client_command_put_landmine,
handler[CLIENT_COMMAND_MELEE] = client_command_melee,
handler[CLIENT_COMMAND_FIRE_UP] = client_command_fire_up,
handler[CLIENT_COMMAND_FIRE_DOWN] = client_command_fire_down,
handler[CLIENT_COMMAND_FIRE_LEFT] = client_command_fire_left,
handler[CLIENT_COMMAND_FIRE_RIGHT] = client_command_fire_right,
handler[CLIENT_COMMAND_FIRE_UP_LEFT] = client_command_fire_up_left,
handler[CLIENT_COMMAND_FIRE_UP_RIGHT] = client_command_fire_up_right,
handler[CLIENT_COMMAND_FIRE_DOWN_LEFT] = client_command_fire_down_left,
handler[CLIENT_COMMAND_FIRE_DOWN_RIGHT] = client_command_fire_down_right,
handler[CLIENT_COMMAND_FIRE_AOE_UP] = client_command_fire_aoe_up,
handler[CLIENT_COMMAND_FIRE_AOE_DOWN] = client_command_fire_aoe_down,
handler[CLIENT_COMMAND_FIRE_AOE_LEFT] = client_command_fire_aoe_left,
handler[CLIENT_COMMAND_FIRE_AOE_RIGHT] = client_command_fire_aoe_right;
handler[CLIENT_COMMAND_ADMIN_CONTROL] = client_command_admin_control;
}
void init_constant() {
item_s[ITEM_NONE] = (char*)"none";
item_s[ITEM_MAGAZINE] = (char*)"magazine";
item_s[ITEM_MAGMA] = (char*)"magma";
item_s[ITEM_GRASS] = (char*)"grass";
item_s[ITEM_BLOOD_VIAL] = (char*)"blood_vial";
item_s[ITEM_END] = (char*)"end";
item_s[ITEM_BULLET] = (char*)"bullet";
item_s[ITEM_LANDMINE] = (char*)"landmine";
dir_s[DIR_UP] = (char*)"up";
dir_s[DIR_DOWN] = (char*)"down";
dir_s[DIR_LEFT] = (char*)"left";
dir_s[DIR_RIGHT] = (char*)"right";
dir_s[DIR_UP_LEFT] = (char*)"up&left";
dir_s[DIR_UP_RIGHT] = (char*)"up&right";
dir_s[DIR_DOWN_LEFT] = (char*)"down&left";
dir_s[DIR_DOWN_RIGHT] = (char*)"down&right";
map_s[MAP_ITEM_NONE] = (char*)" ";
map_s[MAP_ITEM_MAGAZINE] = (char*)"+";
map_s[MAP_ITEM_MAGMA] = (char*)"X";
map_s[MAP_ITEM_GRASS] = (char*)"\033[2;37m█\033[0m";
map_s[MAP_ITEM_BLOOD_VIAL] = (char*)"*";
map_s[MAP_ITEM_MY_BULLET] = (char*)".";
map_s[MAP_ITEM_OTHER_BULLET] = (char*)".";
map_s[MAP_ITEM_USER] = (char*)"A";
map_s[MAP_ITEM_LANDMINE] = (char*)"o";
map_s[MAP_ITEM_END] = (char*)" ";
item_to_map[ITEM_NONE] = MAP_ITEM_NONE;
item_to_map[ITEM_MAGAZINE] = MAP_ITEM_MAGAZINE;
item_to_map[ITEM_MAGMA] = MAP_ITEM_MAGMA;
item_to_map[ITEM_GRASS] = MAP_ITEM_GRASS;
item_to_map[ITEM_BLOOD_VIAL] = MAP_ITEM_BLOOD_VIAL;
item_to_map[ITEM_LANDMINE] = MAP_ITEM_LANDMINE;
item_to_map[ITEM_END] = MAP_ITEM_END;
signal_name_s[SIGHUP ] = (char*)"SIGHUP";
signal_name_s[SIGINT ] = (char*)"SIGINT";
signal_name_s[SIGQUIT ] = (char*)"SIGQUIT";
signal_name_s[SIGILL ] = (char*)"SIGILL" ;
signal_name_s[SIGABRT ] = (char*)"SIGABRT";
signal_name_s[SIGFPE ] = (char*)"SIGFPE" ;
signal_name_s[SIGKILL ] = (char*)"SIGKILL";
signal_name_s[SIGSEGV ] = (char*)"SIGSEGV";
signal_name_s[SIGPIPE ] = (char*)"SIGPIPE";
signal_name_s[SIGALRM ] = (char*)"SIGALRM";
signal_name_s[SIGTERM ] = (char*)"SIGTERM";
signal_name_s[SIGUSR1 ] = (char*)"SIGUSR1";
signal_name_s[SIGUSR2 ] = (char*)"SIGUSR2";
signal_name_s[SIGCHLD ] = (char*)"SIGCHLD";
signal_name_s[SIGCONT ] = (char*)"SIGCONT";
signal_name_s[SIGSTOP ] = (char*)"SIGSTOP";
signal_name_s[SIGTSTP ] = (char*)"SIGTSTP";
signal_name_s[SIGTTIN ] = (char*)"SIGTTIN";
signal_name_s[SIGTTOU ] = (char*)"SIGTTOU";
signal_name_s[SIGBUS ] = (char*)"SIGBUS" ;
signal_name_s[SIGPOLL ] = (char*)"SIGPOLL";
signal_name_s[SIGPROF ] = (char*)"SIGPROF";
signal_name_s[SIGSYS ] = (char*)"SIGSYS" ;
signal_name_s[SIGTRAP ] = (char*)"SIGTRAP";
signal_name_s[SIGURG ] = (char*)"SIGURG" ;
signal_name_s[SIGVTALRM] = (char*)"SIGVTALRM";
signal_name_s[SIGXCPU ] = (char*)"SIGXCPU";
signal_name_s[SIGXFSZ ] = (char*)"SIGXFSZ";
color_s[0] = (char*)NONE;
color_s[1] = (char*)L_GREEN;
color_s[2] = (char*)L_RED;
color_s[3] = (char*)YELLOW;
color_s[4] = (char*)L_BLUE;
color_s[5] = (char*)L_PURPLE;
color_s[6] = (char*)L_CYAN;
color_s[7] = (char*)(RED UNDERLINE);
color_s[8] = (char*)(GREEN UNDERLINE);
color_s[9] = (char*)(BROWN UNDERLINE);
color_s[10] = (char*)(BLUE UNDERLINE);
color_s[11] = (char*)(PURPLE UNDERLINE);
color_s[12] = (char*)(CYAN UNDERLINE);
color_s_size = 12;
}
/*
int main0(int argc, char* argv[]) {
init_constants();
init_handler();
if (argc == 2) {
port = atoi(argv[1]);
}
srand(time(NULL));
pthread_t thread;
if (signal(SIGINT, terminate_entrance) == SIG_ERR) {
eprintf("an error occurred while setting a signal handler.");
}
if (signal(SIGSEGV, terminate_entrance) == SIG_ERR) {
eprintf("an error occurred while setting a signal handler.");
}
if (signal(SIGABRT, terminate_entrance) == SIG_ERR) {
eprintf("an error occurred while setting a signal handler.");
}
if (signal(SIGTERM, terminate_entrance) == SIG_ERR) {
eprintf("an error occurred while setting a signal handler.");
}
if (signal(SIGTRAP, terminate_entrance) == SIG_ERR) {
eprintf("an error occurred while setting a signal handler.");
}
for (int i = 0; i < USER_CNT; i++) {
pthread_mutex_init(&items_lock[i], NULL);
}
log("server %s", version);
if (sizeof(server_message_t) >= 1000)
logw("message_size = %ldB", sizeof(server_message_t));
server_fd = server_start();
load_user_list();
for (int i = 0; i < USER_CNT; i++)
sessions[i].conn = -1;
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
while (1) {
static session_args_t info;
info.conn = accept(server_fd, (struct sockaddr*)&client_addr, &length);
strncpy(info.ip_addr, inet_ntoa(client_addr.sin_addr), IPADDR_SIZE - 1);
log("connected by %s:%d , conn:%d", info.ip_addr, client_addr.sin_port, info.conn);
if (info.conn < 0) {
loge("fail to accept client.");
} else if (pthread_create(&thread, NULL, session_start, (void*)(uintptr_t)&info) != 0) {
loge("fail to create thread.");
}
logi("bind thread #%lu", thread);
}
return 0;
}
*/
int EightQueen(int n) { //函数返回八皇后问题的解法个数
int *p = new int[n]; //p[8]用来存储八皇后的位置,下标表示行号,数值表示列号
//例如p[2]=3表示落在(2,3)这个点上行号列号均为0~8
memset(p, 0, n * sizeof(int));//初始化所有p[i]=0
int k = 0; //k用来记录行号
int count = 0; //count用来记录解法个数函数最终返回该值
while (k >= 0) { //最后一次回溯k=-1跳出循环从而找到全部解法
while (p[k] < n) {
int i;
for (i = 0; i < k; i++)//找一下K行之前的几行有没有与p[k]在同一列或者同一对角线上
if (p[i] == p[k] ||
p[i] - p[k] == i - k ||
p[i] - p[k] == k - i)
break; //如果有就跳出循环此时i<k否则i=k
if (i < k)p[k]++; //p[k]不满足条件p[k]++再次进入循环与前几行对比直至p[k]满足条件此时p[0]到p[k]之间都满足条件了
else break; //p[k]满足条件,跳出 while(p[k]<n) 循环
}
if (p[k] < n) { //如果p[k]<n,即合法的话,进入下面代码
if (k < n - 1)k++; //如果还没到最后一行的话就k++,进入下一行如果k=7到了最后一行的话就表明找到一组解进入else开始输出
else { //以下为打印函数,可以不看
for (int i = 0; i < n; i++) {//i为行号
for (int j = 0; j < p[i]; j++)
cout << "|--"; //输出此行皇后之前的格子
cout << "O"; //输出皇后O
for (int j = 0; j < n - p[i] - 1; j++)
cout << "--|";//输出此行皇后之后的格子
cout << endl;
}
cout << "……………………………" << endl;
for (int i = 0; i < n; i++)cout << p[i] + 1; cout << endl;//输出此组解法
cout << "……………………………" << endl;
count++; //解法数加一
p[k]++; //把p[7]++ 重新开始找下一个解法
}
}
else { //p[k]=8,此行找不到解,需要回溯,更改上一行的解法
p[k] = 0; //重新初始化k行
k--; //回到上一行
if (k >= 0)p[k]++; //如果还没到最后的解法即如果不是0行找不到解的话就可以开始回溯将上一行的位置++
}
}
return count; //函数返回count解法数量
}
int data[ 8 ][ 8 ]; //chess(double dimensional array)
int a[ 8 ]; //column(列)
int b[ 15 ]; //主对角线(左上至右下)
int c[ 15 ]; //从对角线(右上至左下)
int cnt = 0;
void eightQueens( int );
void output( const int [][ 8 ], int );
int EightQueen1()
{
int i, j;
for( i = 0; i < 15; ++i ) //主、从对角线
b[ i ] = c[ i ] = 0; //表示安全
for( i = 0; i < 8; ++i )//chess
{
a[ i ] = 0; //i列安全
for( j = 0; j < 8; ++j )
data[ i ][ j ] = 0;
}
eightQueens( 0 );
cout << "/ncount = " << cnt << endl;
return 0;
}
void eightQueens( int line )
{
if( 8 == line )//八个皇后安置就位,输出
{
output( data, 8 );
cout << endl;
return;
}
for( int column = 0; column < 8; ++column )
{
if( 0 == a[ column ] && 0 == b[ line - column + 7 ] && 0 == c[ line + column ] )
{
data[ line ][ column ] = 1; //安置皇后
a[ column ] = 1; //此列被占
b[ line - column + 7 ] = 1; //主对角线被占
c[ line + column ] = 1; //从对角线被占
eightQueens( line + 1 ); //下一个皇后
//重置
data[ line ][ column ] = 0;
a[ column ] = 0;
b[ line - column + 7 ] = 0;
c[ line + column ] = 0;
}
}
}
//output chess
void output( const int data[][ 8 ], int size )
{
for( int i = 0; i < size; ++i )
{
for( int j = 0; j < size; ++j )
cout << data[ i ][ j ] << ' ';
cout << endl;
}
++cnt;
}
namespace floyd_algorithm{
#include<stdio.h>
#include<malloc.h>
#define MAXV 7 //最大顶点个数
#define INF 32767 //定义 ∞
//∞ == 32767 ,int 型的最大范围2位= 2^(2*8-1)TC告诉我们int占用2个字节而VC和LGCC告诉我们int占用4个字节
//图Graph
//顶点Vertex
//邻接Adjacency
//矩阵Matrix
//表List
//边Edge
typedef struct vertex {
int number; //顶点的编号
}VertexType; //别名,顶点的类型
typedef struct matrix {
int n; //顶点个数
int e; //边数
int adjMat[MAXV][MAXV]; //邻接矩阵数组
VertexType ver[MAXV]; //存放顶点信息
}MatGraph; //别名,完整的图邻接矩阵类型
typedef struct eNode {
int adjVer; //该边的邻接点编号
int weiLGht; //该边的的信息,如权值
struct eNode* nextEdLGe; //指向下一条边的指针
}EdgeNode; //别名,边结点的类型
typedef struct vNode {
EdgeNode* firstEdLGe; //指向第一个边结点
}VNode; //别名,邻接表的头结点类型
typedef struct list {
int n; //顶点个数
int e; //边数
VNode adjList[MAXV]; //邻接表的头结点数组
}ListGraph; //别名,完整的图邻接表类型
//创建图的邻接表
void createAdjListGraph(ListGraph*& LG, int A[MAXV][MAXV], int n, int e) {
int i, j;
EdgeNode* p;
LG = (ListGraph*)malloc(sizeof(ListGraph));
for (i = 0; i < n; i++) {
LG->adjList[i].firstEdLGe = NULL; //给邻接表中所有头结点指针域置初值
}
for (i = 0; i < n; i++) { //检查邻接矩阵中的每个元素
for (j = n - 1; j >= 0; j--) {
if (A[i][j] != 0) { //存在一条边
p = (EdgeNode*)malloc(sizeof(EdgeNode)); //申请一个结点内存
p->adjVer = j; //存放邻接点
p->weiLGht = A[i][j]; //存放权值
p->nextEdLGe = NULL;
p->nextEdLGe = LG->adjList[i].firstEdLGe; //头插法
LG->adjList[i].firstEdLGe = p;
}
}
}
LG->n = n;
LG->e = e;
}
//输出邻接表
void displayAdjList(ListGraph* LG) {
int i;
EdgeNode* p;
for (i = 0; i < MAXV; i++) {
p = LG->adjList[i].firstEdLGe;
printf("%d:", i);
while (p != NULL) {
if (p->weiLGht != 32767) {
printf("%2d[%d]->", p->adjVer, p->weiLGht);
}
p = p->nextEdLGe;
}
printf(" NULL\n");
}
}
//输出邻接矩阵
void displayAdjMat(MatGraph MG) {
int i, j;
for (i = 0; i < MAXV; i++) {
for (j = 0; j < MAXV; j++) {
if (MG.adjMat[i][j] == 0) {
printf("%4s", "0");
}
else if (MG.adjMat[i][j] == 32767) {
printf("%4s", "");
}
else {
printf("%4d", MG.adjMat[i][j]);
}
}
printf("\n");
}
}
//邻接表转换为邻接矩阵
void ListToMat(ListGraph* LG, MatGraph& MG) {
int i, j;
EdgeNode* p;
for (i = 0; i < MAXV; i++) {
for (j = 0; j < MAXV; j++) {
MG.adjMat[i][j] = 0;
}
}
for (i = 0; i < LG->n; i++) {
p = LG->adjList[i].firstEdLGe;
while (p != NULL) {
MG.adjMat[i][p->adjVer] = p->weiLGht;
p = p->nextEdLGe;
}
}
MG.n = LG->n;
MG.e = LG->e;
}
//输出多源最短路径
void displayPath(MatGraph MG, int A[MAXV][MAXV], int path[MAXV][MAXV]) {
int i, j, k;
int s;
int aPath[MAXV]; //存放一条最短路径(逆向)
int d; //顶点个数
for (i = 0; i < MG.n; i++) {
for (j = 0; j < MG.n; j++) {
if (A[i][j] != INF && i != j) { //若顶点 i 和 顶点 j 之间存在路径
//printf("从 %d 到 %d 的路径为:", i, j);
k = path[i][j];
d = 0;
aPath[d] = j; //路径上添加终点
while (//k != -1 &&
k != i) { //路劲上添加中间点
d++;
aPath[d] = k;
k = path[i][k];
}
d++;
aPath[d] = i; //路径上添加起点
//printf("%d", aPath[d]); //输出起点
for (s = d - 1; s >= 0; s--) { //输出路径上其他顶点
//printf("->%d", aPath[s]);
}
//printf("\t\t");
//printf("路径长度为:%d\n", A[i][j]);
}
}
}
}
//Floyd算法
void Floyd(MatGraph MG) {
int i, j, k;
int A[MAXV][MAXV];
int path[MAXV][MAXV];
for (i = 0; i < MG.n; i++) {
for (j = 0; j < MG.n; j++) {
A[i][j] = MG.adjMat[i][j];
if (i != j && MG.adjMat[i][j] < INF) {
path[i][j] = i; //顶点 i 到顶点 j 有边时
}
else {
path[i][j] = -1; //顶点 i 到顶点 j 无边时
}
}
}
for (k = 0; k < MG.n; k++) { //一次考察所有顶点
for (i = 0; i < MG.n; i++) {
for (j = 0; j < MG.n; j++) {
if (A[i][j] > A[i][k] + A[k][j]) {
A[i][j] = A[i][k] + A[k][j]; //修改最短路径长度
path[i][j] = path[k][j]; //修改最短路径
}
}
}
}
displayPath(MG, A, path); //输出最短路径
}
int floyd() {
ListGraph* LG;
MatGraph MG;
int array[MAXV][MAXV] = {
{ 0, 4, 6, 6,INF,INF,INF},
{INF, 0, 1,INF, 7,INF,INF},
{INF,INF, 0,INF, 6, 4,INF},
{INF,INF, 2, 0,INF, 5,INF},
{INF,INF,INF,INF, 0,INF, 6},
{INF,INF,INF,INF, 1, 0, 8},
{INF,INF,INF,INF,INF,INF, 0}
};
int e = 12;
createAdjListGraph(LG, array, MAXV, e);
//displayAdjList(LG);
//printf("\n");
ListToMat(LG, MG);
//displayAdjMat(MG);
//printf("\n");
Floyd(MG);
//printf("\n");
return 0;
}
}
namespace __floyd{
#include<stdio.h>
#include<malloc.h>
#define MAXV 7 //最大顶点个数
#define INF 32767 //定义 ∞
//∞ == 32767 ,int 型的最大范围2位= 2^(2*8-1)TC告诉我们int占用2个字节而VC和LGCC告诉我们int占用4个字节
//图Graph
//顶点Vertex
//邻接Adjacency
//矩阵Matrix
//表List
//边Edge
typedef struct vertex {
int number; //顶点的编号
}VertexType; //别名,顶点的类型
typedef struct matrix {
int n; //顶点个数
int e; //边数
int adjMat[MAXV][MAXV]; //邻接矩阵数组
VertexType ver[MAXV]; //存放顶点信息
}MatGraph; //别名,完整的图邻接矩阵类型
typedef struct eNode {
int adjVer; //该边的邻接点编号
int weiLGht; //该边的的信息,如权值
struct eNode* nextEdLGe; //指向下一条边的指针
}EdgeNode; //别名,边结点的类型
typedef struct vNode {
EdgeNode* firstEdLGe; //指向第一个边结点
}VNode; //别名,邻接表的头结点类型
typedef struct list {
int n; //顶点个数
int e; //边数
VNode adjList[MAXV]; //邻接表的头结点数组
}ListGraph; //别名,完整的图邻接表类型
//创建图的邻接表
void createAdjListGraph(ListGraph*& LG, int A[MAXV][MAXV], int n, int e) {
int i, j;
EdgeNode* p;
LG = (ListGraph*)malloc(sizeof(ListGraph));
for (i = 0; i < n; i++) {
LG->adjList[i].firstEdLGe = NULL; //给邻接表中所有头结点指针域置初值
}
for (i = 0; i < n; i++) { //检查邻接矩阵中的每个元素
for (j = n - 1; j >= 0; j--) {
if (A[i][j] != 0) { //存在一条边
p = (EdgeNode*)malloc(sizeof(EdgeNode)); //申请一个结点内存
p->adjVer = j; //存放邻接点
p->weiLGht = A[i][j]; //存放权值
p->nextEdLGe = NULL;
p->nextEdLGe = LG->adjList[i].firstEdLGe; //头插法
LG->adjList[i].firstEdLGe = p;
}
}
}
LG->n = n;
LG->e = e;
}
//输出邻接表
void displayAdjList(ListGraph* LG) {
int i;
EdgeNode* p;
for (i = 0; i < MAXV; i++) {
p = LG->adjList[i].firstEdLGe;
printf("%d:", i);
while (p != NULL) {
if (p->weiLGht != 32767) {
printf("%2d[%d]->", p->adjVer, p->weiLGht);
}
p = p->nextEdLGe;
}
printf(" NULL\n");
}
}
//输出邻接矩阵
void displayAdjMat(MatGraph MG) {
int i, j;
for (i = 0; i < MAXV; i++) {
for (j = 0; j < MAXV; j++) {
if (MG.adjMat[i][j] == 0) {
printf("%4s", "0");
}
else if (MG.adjMat[i][j] == 32767) {
printf("%4s", "");
}
else {
printf("%4d", MG.adjMat[i][j]);
}
}
printf("\n");
}
}
//邻接表转换为邻接矩阵
void ListToMat(ListGraph* LG, MatGraph& MG) {
int i, j;
EdgeNode* p;
for (i = 0; i < MAXV; i++) {
for (j = 0; j < MAXV; j++) {
MG.adjMat[i][j] = 0;
}
}
for (i = 0; i < LG->n; i++) {
p = LG->adjList[i].firstEdLGe;
while (p != NULL) {
MG.adjMat[i][p->adjVer] = p->weiLGht;
p = p->nextEdLGe;
}
}
MG.n = LG->n;
MG.e = LG->e;
}
//输出多源最短路径
void displayPath(MatGraph MG, int A[MAXV][MAXV], int path[MAXV][MAXV]) {
int i, j, k;
int s;
int aPath[MAXV]; //存放一条最短路径(逆向)
int d; //顶点个数
for (i = 0; i < MG.n; i++) {
for (j = 0; j < MG.n; j++) {
if (A[i][j] != INF
&& i != j) { //若顶点 i 和 顶点 j 之间存在路径
//printf("从 %d 到 %d 的路径为:", i, j);
k = path[i][j];
d = 0;
aPath[d] = j; //路径上添加终点
while (//k != -1 &&
k != i) { //路劲上添加中间点
d++;
aPath[d] = k;
k = path[i][k];
}
d++;
aPath[d] = i; //路径上添加起点
//printf("%d", aPath[d]); //输出起点
for (s = d - 1; s >= 0; s--) { //输出路径上其他顶点
//printf("->%d", aPath[s]);
}
//printf("\t\t");
//printf("路径长度为:%d\n", A[i][j]);
}
}
}
}
//Floyd算法
void Floyd(MatGraph MG) {
int i, j, k;
int A[MAXV][MAXV];
int path[MAXV][MAXV];
for (i = 0; i < MG.n; i++) {
for (j = 0; j < MG.n; j++) {
A[i][j] = MG.adjMat[i][j];
if (i != j &&
MG.adjMat[i][j] < INF) {
path[i][j] = i; //顶点 i 到顶点 j 有边时
}
else {
path[i][j] = -1; //顶点 i 到顶点 j 无边时
}
}
}
for (k = 0; k < MG.n; k++) { //一次考察所有顶点
for (i = 0; i < MG.n; i++) {
for (j = 0; j < MG.n; j++) {
if (A[i][j] > A[i][k] + A[k][j]) {
A[i][j] = A[i][k] + A[k][j]; //修改最短路径长度
path[i][j] = path[k][j]; //修改最短路径
}
}
}
}
displayPath(MG, A, path); //输出最短路径
}
int floyd() {
ListGraph* LG;
MatGraph MG;
int array[MAXV][MAXV] = {
{ 0, 4, 6, 6,INF,INF,INF},
{INF, 0, 1,INF, 7,INF,INF},
{INF,INF, 0,INF, 6, 4,INF},
{INF,INF, 2, 0,INF, 5,INF},
{INF,INF,INF,INF, 0,INF, 6},
{INF,INF,INF,INF, 1, 0, 8},
{INF,INF,INF,INF,INF,INF, 0}
};
int e = 12;
createAdjListGraph(LG, array, MAXV, e);
//displayAdjList(LG);
//printf("\n");
ListToMat(LG, MG);
//displayAdjMat(MG);
//printf("\n");
Floyd(MG);
//printf("\n");
return 0;
}
}
namespace Queue{
int data[ 8 ][ 8 ]; //chess(double dimensional array)
int a[ 8 ]; //column(列)
int b[ 15 ]; //主对角线(左上至右下)
int c[ 15 ]; //从对角线(右上至左下)
int cnt = 0;
void eightQueens( int );
void output( const int [][ 8 ], int );
int EightQueen1()
{
int i, j;
for( i = 0; i < 15; ++i ) //主、从对角线
b[ i ] = c[ i ] = 0; //表示安全
for( i = 0; i < 8; ++i )//chess
{
a[ i ] = 0; //i列安全
for( j = 0; j < 8; ++j )
data[ i ][ j ] = 0;
}
eightQueens( 0 );
cout << "/ncount = " << cnt << endl;
return 0;
}
void eightQueens( int line )
{
if( 8 == line )//八个皇后安置就位,输出
{
output( data, 8 );
cout << endl;
return;
}
for( int column = 0; column < 8; ++column )
{
if( 0 == a[ column ] && 0 == b[ line - column + 7 ] && 0 == c[ line + column ] )
{
data[ line ][ column ] = 1; //安置皇后
a[ column ] = 1; //此列被占
b[ line - column + 7 ] = 1; //主对角线被占
c[ line + column ] = 1; //从对角线被占
eightQueens( line + 1 ); //下一个皇后
//重置
data[ line ][ column ] = 0;
a[ column ] = 0;
b[ line - column + 7 ] = 0;
c[ line + column ] = 0;
}
}
}
//output chess
void output( const int data[][ 8 ], int size )
{
for( int i = 0; i < size; ++i )
{
for( int j = 0; j < size; ++j )
cout << data[ i ][ j ] << ' ';
cout << endl;
}
++cnt;
}
}