예제 #1
0
static
void
start_rabbit_game(CORE_DATA *cd, PLAYER *p, int bty, int special)
{
	/* store rabbit's pid in user data */
	ud(cd)->rabbit_pid = p->pid;

	/* announce the game to the arena */
	ArenaMessageFmt("%s is now the rabbit!", p->name);
	ArenaMessageFmt("%s is now the rabbit!", p->name);
	ArenaMessageFmt("%s is now the rabbit!", p->name);

	/* announce the game to the player */
	PrivMessageFmt(p, "You are now the rabbit! The game will end if you enter safe!");

	/* prize the bounty/special */
	PrivMessageFmt(p, "*prize %d", bty);
	if (special)
		PrivMessageFmt(p, "*prize #%d", special);

	/*
	 * send *where to get rabbits location and set the bot to parse messages looking
	 * for the response
	 */
	PrivMessage(p, "*where");
	ud(cd)->expecting_where = 1;

	/* set the timer for the next *where to be sent */
	ud(cd)->where_timer = SetTimer(SPAM_INTERVAL_MS, 0, 0);

	/* set the timer that signifies the game's end */
	ud(cd)->gameover_timer = SetTimer(GAME_LENGTH_MS, 0, 0);
}
예제 #2
0
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 */
}
예제 #3
0
void
GameEvent(CORE_DATA *cd)
{
	switch (cd->event) {
	case EVENT_START:
		RegisterPlugin(OPENCORE_VERSION, "rabbit", "cycad", "1.0", __DATE__, __TIME__, "A rabbit bot", sizeof(USER_DATA), 0);

		/* set rabbit pid to nobody */
		ud(cd)->rabbit_pid = PID_NONE;

		/* register rabbit command */
		RegisterCommand(COMMAND_RABBIT, "!rabbit", "Rabbit", 2, CMD_PRIVATE, "<name>:<bounty>[:<special>]", "Start the rabbit game", NULL); break;
	case EVENT_LOGIN:
		/* set the bot's location to center */
		SetPosition(16 * 512, 16 * 512, 0, 0);
		break;
	case EVENT_COMMAND:
		switch (cd->cmd_id) {
		case COMMAND_RABBIT: {
			int show_usage = 0;

			PLAYER_ID rpid = ud(cd)->rabbit_pid;

			if (rpid == PID_NONE) {	/* rabbit game is not runnig */
				if (cd->cmd_argc <= 1) {
					show_usage = 1;
				} else {
					char *cmd = cd->cmd_argr[1];
					int nargs = ArgCount(cmd, ':');

					if (nargs != 2 && nargs != 3) {
						show_usage = 1;
					} else {	/* args to command are valid */
						/* copy name out of command */
						char rname[20];
						DelimArgs(rname, sizeof(rname), cmd, 0, ':', 0);

						/* copy bounty out of command */
						int bty = AtoiArg(cmd, 1, ':');

						/* copy special out of command if it was specified */
						int special = 0;
						if (nargs == 3)
							special = AtoiArg(cmd, 2, ':');

						/* find the player specified on the command line */
						PLAYER *rabbit = FindPlayerName(rname, MATCH_HERE | MATCH_PREFIX);
						if (rabbit) {
							/* player found, start the game */
							start_rabbit_game(cd, rabbit, bty, special);
						} else {
							RmtMessageFmt(cd->cmd_name, "Player not found: %s", rname);
						}
					}
				}
			} else {
				/* rabbit game is already running */
				PLAYER *p = FindPlayerPid(rpid, MATCH_HERE);

				RmtMessageFmt(cd->cmd_name, "Rabbit is already running (%s is the rabbit)",
				    p ? p->name : "**UNKNOWN**");
			}

			/* display usage if necessary */
			if (show_usage) RmtMessageFmt(cd->cmd_name, "Usage: %s <name>:<bounty>[:<special>]", cd->cmd_argv[0]);
		}
		default: break;
		}
		break;
	case EVENT_UPDATE:
		if (ud(cd)->rabbit_pid == cd->p1->pid) {	/* if the update is for the rabbit */
			if (cd->p1->status & STATUS_SAFE) {	/* check if the rabbit is in safe */
				/* the rabbit entered safe, end the game */
				ArenaMessageFmt("%s has lost the rabbit game by entering safe!", cd->p1->name);
				ud(cd)->rabbit_pid = PID_NONE;
			}
		}
		break;
	case EVENT_TIMER:
		if (ud(cd)->rabbit_pid != PID_NONE) {	/* if the rabbit game is running */
			/* find the rabbit */
			PLAYER *p = FindPlayerPid(ud(cd)->rabbit_pid, MATCH_HERE);
			if (p) {
				if (ud(cd)->where_timer == cd->timer_id) {
					/* a *where timer expired, send the next one and look for response */
					PrivMessage(p, "*where");
					ud(cd)->expecting_where = 1;
				} else if (ud(cd)->gameover_timer == cd->timer_id) {
					/* the game over timer expired, the rabbit didnt die and he won */
					ArenaMessageFmt("%s wins the rabbit game by staying alive!", p->name);
					ud(cd)->rabbit_pid = PID_NONE;
				}
			} else {
				/* rabbit not found, this should never happen! */
			}
		}
	case EVENT_MESSAGE:
		/*
		 * Only look for a response of the game is running, the bot is expecting *where,
		 * and the message type is an arena message.
		 */
		if (ud(cd)->rabbit_pid != PID_NONE && ud(cd)->expecting_where && 
		    cd->msg_type == MSG_ARENA) {
			/* message is a possible *where response */

			/* find the rabbit */
			PLAYER *p = FindPlayerPid(ud(cd)->rabbit_pid, MATCH_HERE);
			if (p) {
				char where_prefix[32];
				snprintf(where_prefix, 32, "%s: ", p->name);
				where_prefix[32 - 1] = '\0';

				/*
				 * Verify that this is *where output by looking for "rabbit: " at the
				 * beginning of the string.
				 */
				if (strncasecmp(where_prefix, cd->msg, strlen(where_prefix)) == 0) {
					/* this must be a *where response, process it */
					char loc[4];
					snprintf(loc, 4, "%s", &cd->msg[strlen(where_prefix)]);
					loc[4 - 1] = '\0';

					/* announce the rabbits location */
					ArenaMessageFmt(">>> Rabbit %s is at %-3s <<<", p->name, loc);

					/* set the next *where timer */
					ud(cd)->where_timer = SetTimer(30 * 1000, 0, 0);

					/*
					 * The bot wont be looking for *where responses until the
					 * next time it sends the command, so turn parsing off
					 * for now.
					 */
					ud(cd)->expecting_where = 0;
				}
			}
		}
		break;
	case EVENT_KILL:
		if (cd->p1->pid == ud(cd)->rabbit_pid) {
			/* the rabbit died */
			ArenaMessageFmt("%s wins the rabbit game by killing Rabbit %s!", cd->p2->name, cd->p1->name);
			ud(cd)->rabbit_pid = PID_NONE;
		}
		break;
	case EVENT_LEAVE:
		if (ud(cd)->rabbit_pid == cd->p1->pid) {
			/* the rabbit left */
			ArenaMessageFmt("%s has lost the rabbit game by leaving the arena!", cd->p1->name);
			ud(cd)->rabbit_pid = PID_NONE;
		}
		break;
	case EVENT_CHANGE:
		if (ud(cd)->rabbit_pid == cd->p1->pid) {
			/* the rabbit changed ship */
			ArenaMessageFmt("%s has lost the rabbit game by changing ship/freq!", cd->p1->name);
			ud(cd)->rabbit_pid = PID_NONE;
		}
		break;
	}
}