예제 #1
0
/**
 * @brief Sets the @c cls.state to @c ca_disconnected and informs the server
 * @sa CL_Drop
 * @note Goes from a connected state to disconnected state
 * Sends a disconnect message to the server
 * This is also called on @c Com_Error, so it shouldn't cause any errors
 */
void CL_Disconnect (void)
{
	if (cls.state < ca_connecting)
		return;

	Com_Printf("Disconnecting...\n");

	/* send a disconnect message to the server */
	if (!Com_ServerState()) {
		dbuffer msg;
		NET_WriteByte(&msg, clc_stringcmd);
		NET_WriteString(&msg, NET_STATE_DISCONNECT "\n");
		NET_WriteMsg(cls.netStream, msg);
		/* make sure, that this is send */
		NET_Wait(0);
	}

	NET_StreamFinished(cls.netStream);
	cls.netStream = nullptr;

	CL_ClearState();

	S_Stop();

	R_ShutdownModels(false);
	R_FreeWorldImages();

	CL_SetClientState(ca_disconnected);
	CL_ClearBattlescapeEvents();
	GAME_EndBattlescape();
}
예제 #2
0
/**
 * @note Both client and server can use this, and it will
 * do the appropriate things.
 */
void Com_Error (int code, const char* fmt, ...)
{
	va_list argptr;
	static char msg[MAXPRINTMSG];
	static bool recursive = false;

	if (recursive)
		Sys_Error("recursive error after: %s", msg);
	recursive = true;

	va_start(argptr, fmt);
	Q_vsnprintf(msg, sizeof(msg), fmt, argptr);
	va_end(argptr);

	switch (code) {
	case ERR_DISCONNECT:
		Com_Printf("%s\n", msg);
		CL_Drop();
		recursive = false;
		Com_Drop();
	case ERR_DROP:
		Com_Printf("********************\n");
		Com_Printf("ERROR: %s\n", msg);
		Com_Printf("********************\n");
		Sys_Backtrace();
		SV_Shutdown("Server crashed.", false);
		CL_Drop();
		recursive = false;
		Com_Drop();
	default:
		Com_Printf("%s\n", msg);
		SV_Shutdown("Server fatal crashed", false);

		/* send an receive net messages a last time */
		NET_Wait(0);

		FS_CloseFile(&logfile);
		if (pipefile.f != nullptr) {
			FS_CloseFile(&pipefile);
			FS_RemoveFile(va("%s/%s", FS_Gamedir(), pipefile.name));
		}

		CL_Shutdown();
		Qcommon_Shutdown();
		Sys_Error("Shutdown");
	}
}
예제 #3
0
/**
 * Both client and server can use this, and it will
 * do the appropriate things.
 */
void Com_Quit (void)
{
#ifdef DEDICATED_ONLY
	Com_WriteConfigToFile("dedconfig.cfg");
#else
	Com_WriteConfigToFile("config.cfg");
#endif

	SV_Shutdown("Server quit.", false);
	SV_Clear();
	CL_Shutdown();

	/* send an receive net messages a last time */
	NET_Wait(0);
	FS_CloseFile(&logfile);
	if (pipefile.f != nullptr) {
		FS_CloseFile(&pipefile);
		FS_RemoveFile(va("%s/%s", FS_Gamedir(), pipefile.name));
	}
	Sys_Quit();
}
예제 #4
0
/**
 * @brief Used by SV_Shutdown to send a final message to all
 * connected clients before the server goes down.
 * @sa SV_Shutdown
 */
static void SV_FinalMessage (const char *message, bool reconnect)
{
	client_t *cl;
	dbuffer msg(2 + strlen(message));

	if (reconnect)
		NET_WriteByte(&msg, svc_reconnect);
	else
		NET_WriteByte(&msg, svc_disconnect);
	NET_WriteString(&msg, message);

	cl = NULL;
	while ((cl = SV_GetNextClient(cl)) != NULL)
		if (cl->state >= cs_connected) {
			NET_WriteConstMsg(cl->stream, msg);
			NET_StreamFinished(cl->stream);
			cl->stream = NULL;
		}

	/* make sure, that this is send */
	NET_Wait(0);
}
예제 #5
0
/**
 * @brief This is the function that is called directly from main()
 * @sa main
 * @sa Qcommon_Init
 * @sa Qcommon_Shutdown
 * @sa SV_Frame
 * @sa CL_Frame
 */
void Qcommon_Frame (void)
{
	try {
		/* If the next event is due... */
		ScheduleEventPtr event = Dequeue_Event(Sys_Milliseconds());
		if (event) {
			/* Dispatch the event */
			event->func(event->when, event->data);
		}
	} catch (comRestart_t const& restart) {
		SV_Shutdown("Restart.", false);
		CL_Shutdown();
		Qcommon_Shutdown();
		CL_FilterEventQueue(&Event_FilterAll);
		if (restart.gamedir != nullptr) {
			const char* restartArgv[] = {"", "+set", "fs_gamedir", restart.gamedir};
			Qcommon_Init(4, const_cast<char** >(restartArgv));
		} else {
			Qcommon_Init(0, nullptr);
		}
	} catch (comDrop_t const&) {
		return;
	}

	/* Now we spend time_to_next milliseconds working on whatever
	 * IO is ready (but always try at least once, to make sure IO
	 * doesn't stall) */
	int time_to_next;
	do {
		time_to_next = !eventQueue.empty() ? (eventQueue.begin()->get()->when - Sys_Milliseconds()) : 1000;
		if (time_to_next < 0)
			time_to_next = 0;

		NET_Wait(time_to_next);
	} while (time_to_next > 0);
}