/* * 'c' is the attackers color. * kingx and kingy is the target king location. */ static bool IsCheckmatedBy(BOARD b, COLOR c, int kingx, int kingy) { struct timeval tv; gettimeofday(&tv, NULL); COLOR defender = GetOppositeColor(c); PIECE *p; // for each piece on the board that is defending for (int x = 0; x < 8; ++x) for (int y = 0; y < 8; ++y) { p = GetPieceAt(b, x, y); if (p->color != defender) { continue; } // for each tile on the board, see if that piece can move there for (int j = 0; j < 8; ++j) for (int i = 0; i < 8; ++i) { if (PieceCanAttack(b, p->color, p->type, x, y, i, j) == true && GetPieceAt(b, i, j)->color != p->color) { PIECE old_p = *GetPieceAt(b, x, y); PIECE old_t = *GetPieceAt(b, i, j); // temporarily make the move SetPieceAt(b, x, y, COLOR_NONE, TYPE_NONE); SetPieceAt(b, i, j, old_p.color, old_p.type); // see if the move cancels check bool is_mate = true; int kx, ky; FindKing(b, defender, &kx, &ky); if (IsCoordAttackedBy(b, c, kx, ky) == false) { is_mate = false; } // revert the pieces SetPieceAt(b, x, y, old_p.color, old_p.type); SetPieceAt(b, i, j, old_t.color, old_t.type); if (is_mate == false) { struct timeval tv2; gettimeofday(&tv2, NULL); LogFmt(OP_MOD, "Checkmate Calculation: %lu.%06lu", tv2.tv_sec - tv.tv_sec, tv2.tv_usec - tv.tv_usec); return false; } } } } struct timeval tv2; gettimeofday(&tv2, NULL); LogFmt(OP_MOD, "Checkmate Calculation: %lu.%06lu", tv2.tv_sec - tv.tv_sec, tv2.tv_usec - tv.tv_usec); return true; }
void StopBot(char *reason) { THREAD_DATA *td = get_thread_data(); LogFmt(OP_MOD, "Shutting down: %s", reason ? reason : "Unspecified"); td->running = -1; }
void go(THREAD_DATA *td, SHIP ship, char *arena) { strlcpy(td->arena_change_request, arena ? arena : td->login->arenaname, 16); LogFmt(OP_REF, "Changing arenas: %s", td->arena_change_request); pkt_send_arena_login(ship, td->arena_change_request); player_simulate_player_leaves(td, true); }
/* * Queue a packet 'p' with sending priority 'priority'. 'p' must point * to a packet allocated with allocate_packet(). */ void queue_packet(PACKET *p, int priority) { assert(p->len <= 255); THREAD_DATA::net_t *n = get_thread_data()->net; if (priority == SP_HIGH) n->queues->h_prio->push_back(p); else if (priority == SP_NORMAL) n->queues->n_prio->push_back(p); else if (priority == SP_DEFERRED) { LogFmt(OP_HSMOD, "Upgrading unreliable deferred packet to reliable"); n->queues->d_prio->push_back(p); } }
/* * Check the get_file() queue and if there are entries, initiate * a file transfer. */ void try_get_next_file(THREAD_DATA *td) { THREAD_DATA::net_t *n = td->net; THREAD_DATA::net_t::chunk_in_t *ci = n->chunk_i; if (ci->in_use == 0 && ci->file_list->empty() == false) { DOWNLOAD_ENTRY *fe = &*ci->file_list->begin(); LogFmt(OP_SMOD, "Initiating file download: %s", fe->name); if (strlen(fe->initiator) > 0) { RmtMessageFmt(fe->initiator, "Initiating file download: %s", fe->name); } PubMessageFmt("*getfile %s", fe->name); strlcpy(ci->initiator, fe->initiator, 24); ci->file_list->erase(ci->file_list->begin()); ci->in_use = 1; } }
/* * The format of streams is: * * [0x00][0x0A][content length][data chunk ...] * Conforming to format string "AACZ" * Content length is the size of all data chunks combined (not * including headers) * * It is repeated for the entire size of the file. * * The format of file transfers is: * [0x16][char filename[16][data] * Format is "AZ16Z" * It is written as one giant packet encoded in a stream. * This can transfer up to 20mb files. */ int queue_send_file(THREAD_DATA *td, const char *filename, const char *initiator) { THREAD_DATA::net_t::send_file_data_t *sfd = td->net->send_file_data; if (strlen(filename) > 15) return 0; UPLOAD_DATA *ud = (UPLOAD_DATA*)xmalloc(sizeof(UPLOAD_DATA)); strlcpy(ud->filename, filename, 64); strlcpy(ud->initiator, initiator ? initiator : "", 24); LogFmt(OP_SMOD, "Queued file upload: %s", filename); sfd->upload_list->push_back(ud); try_send_next_file(td); return 1; }
int queue_get_file(THREAD_DATA *td, const char *filename, const char *initiator) { THREAD_DATA::net_t::chunk_in_t *ci = td->net->chunk_i; if (strlen(filename) > 15) return 0; DOWNLOAD_ENTRY f; strlcpy(f.name, filename, 16); strlwr(f.name); strlcpy(f.initiator, initiator ? initiator : "", 24); ci->file_list->push_back(f); LogFmt(OP_SMOD, "Queued file download: %s", filename); try_get_next_file(td); return 1; }
void try_send_next_file(THREAD_DATA *td) { THREAD_DATA::net_t::send_file_data_t *sfd = td->net->send_file_data; if (sfd->in_use == 0 && !sfd->upload_list->empty()) { UPLOAD_DATA *ud = *sfd->upload_list->begin(); sfd->in_use = 1; strlcpy(sfd->cur_initiator, ud->initiator, 64); strlcpy(sfd->cur_filename, ud->filename, 24); PubMessageFmt("*putfile %s", sfd->cur_filename); LogFmt(OP_SMOD, "Initiated file upload: %s", sfd->cur_filename); if (strlen(sfd->cur_initiator) > 0) { RmtMessageFmt(sfd->cur_initiator, "Initiated file upload: %s", sfd->cur_filename); } sfd->upload_list->erase(sfd->upload_list->begin()); free(ud); } }
static void mainloop(THREAD_DATA *td) { THREAD_DATA::net_t *n = td->net; ticks_ms_t acc, ticks, lticks; /* accumulator, current ticks, last iteration ticks */ int pktl; /* packet length */ uint8_t pkt[MAX_PACKET]; /* buffer space for a packet */ if (connect_to_server(td) != 0) { free_thread_data(td); LogFmt(OP_MOD, "Error performing initial connect"); return; } acc = 0; ticks = get_ticks_ms(); lticks = ticks; ticks_ms_t last_botman_checkin = ticks; ticks_ms_t last_botman_stopcheck = ticks; ticks_ms_t last_config_mtime_check = ticks; while (td->running >= 0) { ticks = get_ticks_ms(); acc += ticks - lticks; lticks = ticks; /* check in with the bot manager */ if (ticks - last_botman_checkin >= BOTMAN_CHECKIN_INTERVAL) { botman_bot_checkin(td->botman_handle); last_botman_checkin = ticks; } if (ticks - last_botman_stopcheck >= BOTMAN_STOPCHECK_INTERVAL) { if (botman_bot_shouldstop(td->botman_handle)) { td->running = -1; } last_botman_stopcheck = ticks; } /* flush out tick events to bots */ if (acc >= STEP_INTERVAL) { libman_expire_timers(td); while(acc >= STEP_INTERVAL) { /* event_tick */ libman_export_event(td, EVENT_TICK, NULL); acc -= STEP_INTERVAL; } } /* if the bot is disconnected, see if it is time to reconnect */ if (n->state == NS_DISCONNECTED) { if (ticks - n->ticks->disconnected > 60000) { free_thread_data(td); init_thread_data(td); connect_to_server(td); } else { usleep(50000); /* 50ms */ continue; } } /* see if the config file has been modified and if so send a reread event */ if (ticks - last_config_mtime_check >= CONFIG_MTIME_POLL_INTERVAL) { struct stat attr; memset(&attr, 0, sizeof(struct stat)); if (stat(td->config->filename, &attr) == 0) { if (td->config->last_modified_time != attr.st_mtime) { libman_export_event(td, EVENT_CONFIG_CHANGE, NULL); td->config->last_modified_time = attr.st_mtime; } } last_config_mtime_check = ticks; } /* use up to STEP_INTERVAL ms for the db thread */ ticks_ms_t ticks_taken = get_ticks_ms() - ticks; ticks_ms_t db_ticks = ticks_taken > STEP_INTERVAL ? STEP_INTERVAL : STEP_INTERVAL - ticks_taken; db_instance_export_events(db_ticks); /* read a packet or wait for a timeout */ ticks_taken = get_ticks_ms() - ticks; ticks_ms_t timeout = ticks_taken > STEP_INTERVAL ? 0 : STEP_INTERVAL - ticks_taken; while (poll(n->pfd, 1, (int)timeout) > 0) { /* process incoming packet, data is waiting */ pktl = (int)read(n->fd, pkt, MAX_PACKET); if (pktl >= 0) { ++n->stats->packets_read; n->ticks->last_pkt_received = get_ticks_ms(); if (n->encrypt->use_encryption) { if (pkt[0] == 0x00) { if (pktl >= 2) { decrypt_buffer(td, &pkt[2], pktl-2); } } else { decrypt_buffer(td, &pkt[1], pktl-1); } } if (td->debug->spew_packets) { spew_packet(pkt, pktl, DIR_INCOMING); } process_incoming_packet(td, pkt, pktl); } ticks_taken = get_ticks_ms() - ticks; timeout = timeout > ticks_taken ? timeout - ticks_taken : 0; } /* update the tick count after potential sleeping in poll() */ ticks = get_ticks_ms(); /* network state specfic actions */ if (n->state == NS_CONNECTING) { /* retransmit connection request if it was lost */ if (ticks - n->ticks->last_connection_request > 15000) { pkt_send_client_key(n->encrypt->client_key); n->ticks->last_connection_request = ticks; } } else if (ticks - n->ticks->last_pkt_received > 30*1000) { /* disconnect if no packets have been received for 30 seconds */ Log(OP_MOD, "No data received for 30 seconds, reconnecting..."); disconnect_from_server(td); continue; } /* transmit player position update if necessary */ if (n->state == NS_CONNECTED && td->in_arena) { if ((ticks - n->ticks->last_pos_update_sent > 100 && td->bot_ship != SHIP_SPECTATOR) || (ticks - n->ticks->last_pos_update_sent > 1000 && td->bot_ship == SHIP_SPECTATOR)) { pkt_send_position_update(td->bot_pos->x, td->bot_pos->y, td->bot_vel->x, td->bot_vel->y); n->ticks->last_pos_update_sent = ticks; } } /* send periodic info/einfo */ if (n->state == NS_CONNECTED) { // subtract 10000 to offset this by 10 seconds from *einfo to avoid filling buffers with commands/responses if (td->periodic->info && ticks - (td->periodic->last_info - 10000U) >= td->periodic->info) { int nhere = player_get_phere(td); PLAYER *parray = player_get_parray(td); for (int i = 0; i < nhere; ++i) { if (parray[i].here && td->enter->send_info) { PrivMessage(&parray[i], "*info"); } } td->periodic->last_info = ticks; } if (td->periodic->einfo && ticks - td->periodic->last_einfo >= td->periodic->einfo) { int nhere = player_get_phere(td); PLAYER *parray = player_get_parray(td); for (int i = 0; i < nhere; ++i) { if (parray[i].here && td->enter->send_einfo) { PrivMessage(&parray[i], "*einfo"); } } td->periodic->last_einfo = ticks; } } /* retransmit reliable packets that have not been acked */ rpacket_list_t *l = n->rel_o->queue; rpacket_list_t::iterator iter = l->begin(); while (iter != l->end()) { RPACKET *rp = *iter; if (ticks - rp->ticks > RELIABLE_RETRANSMIT_INTERVAL) { PACKET *p = allocate_packet(rp->len); memcpy(p->data, rp->data, rp->len); /* update packets retransmit tick */ rp->ticks = ticks; queue_packet(p, SP_HIGH); } ++iter; } /* free absent players if its time */ ticks_ms_t flush_check_interval = 60 * 60 * 1000; if (ticks - td->arena->ticks->last_player_flush > flush_check_interval) { player_free_absent_players(td, flush_check_interval, true); td->arena->ticks->last_player_flush = ticks; } /* write packets generated during loop iteration */ send_outgoing_packets(td); } /* while td->running != 0 */ }
void do_send_file(THREAD_DATA *td) { THREAD_DATA::net_t::send_file_data_t *sfd = td->net->send_file_data; char *filename = sfd->cur_filename; const char *initiator = (strlen(sfd->cur_initiator) > 0) ? sfd->cur_initiator : NULL; char full_filename[64]; snprintf(full_filename, 64, "files/%s", filename); initiator = initiator ? initiator : ""; FILE *f = fopen(full_filename, "rb"); if (f == NULL) { LogFmt(OP_SMOD, "Couldn't open file for sending: %s", filename); if (initiator) { RmtMessageFmt(initiator, "Couldn't open file for sending: %s", filename); } sfd->in_use = 0; return; } struct stat s; memset(&s, 0, sizeof(s)); fstat(fileno(f), &s); int bufl = s.st_size + 17; uint8_t *buf = (uint8_t*)xmalloc(bufl); if (fread(&buf[17], bufl - 17, 1, f) != 1) { LogFmt(OP_SMOD, "Couldn't read file for sending: %s", filename); if (initiator) { RmtMessageFmt(initiator, "Couldn't read file for sending: %s", filename); } fclose(f); free(buf); sfd->in_use = 0; return; } /* add file transfer header */ buf[0] = 0x16; strlcpy((char*)&buf[1], filename, 16); int bytes_left = bufl; /* send initial stream start */ while (bytes_left > 0) { int nout = MIN(bytes_left, 220); // must fit into a cluster header PACKET *p = allocate_packet(6 + nout); build_packet(p->data, "AACZ", 0x00, 0x0A, bufl, &buf[bufl - bytes_left], nout); bytes_left -= nout; queue_packet_reliable(p, SP_DEFERRED); } free(buf); }
/* * Spawns the initial bot process and waits for them all to exit. */ int main(int argc, char *argv[]) { char *pythonpath = getenv("PYTHONPATH"); if (pythonpath) { char *str = (char*)xzmalloc(strlen(pythonpath) + strlen(":") + strlen("./libs") + 1); sprintf(str, "%s:%s", "./libs", pythonpath); setenv("PYTHONPATH", str, 1); free(str); } else { setenv("PYTHONPATH", "./libs", 1); } Py_Initialize(); init_opencore(); PyObject *sysPath = PySys_GetObject("path"); PyObject *libDir = PyString_FromString("."); PyList_Append(sysPath, libDir); Py_DECREF(libDir); if (pthread_key_create(&g_tls_key, NULL) != 0) { Log(OP_SMOD, "Error creating thread-specific storage"); exit(-1); } pthread_setspecific(g_tls_key, NULL); /* make directories */ mkdir("files", 0700); /* setup packet handlers */ for (int i = 0; i < 256; ++i) { g_pkt_core_handlers[i] = null_handler; g_pkt_game_handlers[i] = null_handler; } g_pkt_core_handlers[0x02] = pkt_handle_core_0x02; g_pkt_core_handlers[0x03] = pkt_handle_core_0x03; g_pkt_core_handlers[0x04] = pkt_handle_core_0x04; g_pkt_core_handlers[0x05] = pkt_handle_core_0x05; g_pkt_core_handlers[0x06] = pkt_handle_core_0x06; g_pkt_core_handlers[0x07] = pkt_handle_core_0x07; g_pkt_core_handlers[0x08] = pkt_handle_core_0x08_0x09; g_pkt_core_handlers[0x09] = pkt_handle_core_0x08_0x09; g_pkt_core_handlers[0x0A] = pkt_handle_core_0x0A; g_pkt_core_handlers[0x0E] = pkt_handle_core_0x0E; g_pkt_game_handlers[0x02] = pkt_handle_game_0x02; g_pkt_game_handlers[0x03] = pkt_handle_game_0x03; g_pkt_game_handlers[0x04] = pkt_handle_game_0x04; g_pkt_game_handlers[0x07] = pkt_handle_game_0x07; g_pkt_game_handlers[0x06] = pkt_handle_game_0x06; g_pkt_game_handlers[0x0A] = pkt_handle_game_0x0A; g_pkt_game_handlers[0x0D] = pkt_handle_game_0x0D; g_pkt_game_handlers[0x0E] = pkt_handle_game_0x0E; g_pkt_game_handlers[0x14] = pkt_handle_game_0x14; g_pkt_game_handlers[0x19] = pkt_handle_game_0x19; g_pkt_game_handlers[0x1C] = pkt_handle_game_0x1C; g_pkt_game_handlers[0x1D] = pkt_handle_game_0x1D; g_pkt_game_handlers[0x27] = pkt_handle_game_0x27; g_pkt_game_handlers[0x28] = pkt_handle_game_0x28; g_pkt_game_handlers[0x29] = pkt_handle_game_0x29; g_pkt_game_handlers[0x2E] = pkt_handle_game_0x2E; g_pkt_game_handlers[0x2F] = pkt_handle_game_0x2F; g_pkt_game_handlers[0x31] = pkt_handle_game_0x31; struct utsname uts; bzero(&uts, sizeof(struct utsname)); uname(&uts); uint64_t hash = hash_buf(&uts, sizeof(struct utsname)); g_machineid = gen_valid_mid(hash & 0xFFFFFFFF); g_permissionid = hash >> 32; load_op_file(); static const char* const masterconfig = "types/master.conf"; log_init(); db_init(masterconfig); botman_init(); /* run the master bot */ char arenaname[32] = { '\0' }; config_get_string("login.masterarena", arenaname, sizeof(arenaname), "#master", masterconfig); LogFmt(OP_MOD, "Starting master into %s", arenaname); char *err = StartBot("master", arenaname, NULL); if (err) { LogFmt(OP_MOD, "Error starting master bot: %s", err); return -1; } /* become the bot management thread and loop */ botman_mainloop(); botman_shutdown(); db_shutdown(); log_shutdown(); pthread_key_delete(g_tls_key); Py_Finalize(); return 0; }