⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 syncdebugger.cpp

📁 这是整套横扫千军3D版游戏的源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
				ClientSendBlockResponse(*(unsigned short*)&inbuf[1]);
				logger.AddLine("Client: block response sent for block %d", *(unsigned short*)&inbuf[1]);
				// simple progress indication
				logOutput.Print("[SD] Client: %d / %d", *(unsigned short*)&inbuf[3], *(unsigned short*)&inbuf[5]);
			}
			length = 7;
			break;
		case NETMSG_SD_RESET:
			logger.CloseSession();
			logOutput.Print("[SD] Client: Done!");
// 			disable_history = false;
			may_enable_history = true;
			if (gu->autoQuit) {
				logOutput.Print("[SD] Client: Automatical quit enforced from commandline");
				globalQuit = true;
			}
			length = 1;
			break;
		default:
			logOutput.Print("[SD] Client: invalid msg");
			length = 0;
			break;
	}
	return length;
}


/**
 * @brief first step after desync
 *
 * Called by server to trigger sync error handling.
 * It pauses the game and sends a checksum request to all clients.
 */
void CSyncDebugger::ServerTriggerSyncErrorHandling(int serverframenum)
{
	if (!disable_history) {
		//this will set disable_history = true once received so only one sync errors is handled at a time.
		serverNet->SendPause(gu->myPlayerNum, true);
		serverNet->SendData< int >(NETMSG_SD_CHKREQUEST, serverframenum);
	}
}


/**
 * @brief second step after desync
 *
 * Called by client to send a response to a checksum request.
 */
void CSyncDebugger::ClientSendChecksumResponse()
{
	std::vector<unsigned> checksums;
	for (unsigned i = 0; i < HISTORY_SIZE; ++i) {
		unsigned checksum = 0;
		for (unsigned j = 0; j < BLOCK_SIZE; ++j) {
			if (historybt)
				checksum = 33 * checksum + historybt[BLOCK_SIZE * i + j].chk;
			else  checksum = 33 * checksum + history[BLOCK_SIZE * i + j].chk;
		}
		checksums.push_back(checksum);
	}
	net->SendSTLData< unsigned char, Uint64, std::vector<unsigned> >(NETMSG_SD_CHKRESPONSE, gu->myPlayerNum, flop, checksums);
}


/**
 * @brief third step after desync
 *
 * Called by server after all checksum responses have been received.
 * Compares the checksumResponses and figures out which blocks are out of sync
 * (have different checksum). For these blocks requests are queued which will
 * be send next frames (one request at a time, see
 * CSyncDebugger::ServerHandlePendingBlockRequests()).
 */
void CSyncDebugger::ServerQueueBlockRequests()
{
	Uint64 correctFlop = 0;
	for (int j = 0; j < gs->activeTeams; ++j) {
		if (correctFlop) {
			if (remoteFlop[j] != correctFlop)
				logger.AddLine("Server: bad flop# %llu instead of %llu for player %d", remoteFlop[j], correctFlop, j);
		} else {
			correctFlop = remoteFlop[j];
		}
	}
	unsigned i = ((unsigned)(correctFlop % (HISTORY_SIZE * BLOCK_SIZE)) / BLOCK_SIZE) + 1, c = 0;
	for (; c < HISTORY_SIZE; ++i, ++c) {
		unsigned correctChecksum = 0;
		if (i == HISTORY_SIZE) i = 0;
		for (int j = 0; j < gs->activeTeams; ++j) {
			if (correctChecksum && checksumResponses[j][i] != correctChecksum) {
				pendingBlocksToRequest.push_back(i);
				break;
			}
			correctChecksum = checksumResponses[j][i];
		}
	}
	if (!pendingBlocksToRequest.empty()) {
		logger.AddLine("Server: blocks: %u equal, %u not equal", HISTORY_SIZE - pendingBlocksToRequest.size(), pendingBlocksToRequest.size());
		requestedBlocks = pendingBlocksToRequest;
		// we know the first FPU bug occured in block # ii, so we send out a block request for it.
// 		serverNet->SendData<unsigned> (NETMSG_SD_BLKREQUEST, ii);
	} else {
		logger.AddLine("Server: huh, all blocks equal?!?");
		serverNet->SendData(NETMSG_SD_RESET);
	}
	//cleanup
	for (int j = 0; j < MAX_PLAYERS; ++j)
		checksumResponses[j].clear();
}


/**
 * @brief helper for the third step
 *
 * Must be called by the server in GameServer.cpp once every frame to handle
 * queued block requests (see CSyncDebugger::ServerQueueBlockRequests()).
 */
void CSyncDebugger::ServerHandlePendingBlockRequests()
{
	if (!pendingBlocksToRequest.empty() && !waitingForBlockResponse) {
		// last two shorts are for progress indication
		serverNet->SendData<unsigned short, unsigned short, unsigned short> (NETMSG_SD_BLKREQUEST, pendingBlocksToRequest.front(), requestedBlocks.size() - pendingBlocksToRequest.size() + 1, requestedBlocks.size());
		waitingForBlockResponse = true;
	}
}


/**
 * @brief fourth step after desync
 *
 * Called by client to send a response to a block request.
 */
void CSyncDebugger::ClientSendBlockResponse(int block)
{
	std::vector<unsigned> checksums;
	for (unsigned i = 0; i < BLOCK_SIZE; ++i) {
		if (historybt)
			checksums.push_back(historybt[BLOCK_SIZE * block + i].chk);
		else  checksums.push_back(history[BLOCK_SIZE * block + i].chk);
	}
	net->SendSTLData< unsigned char, std::vector<unsigned> >(NETMSG_SD_BLKRESPONSE, gu->myPlayerNum, checksums);
}


/**
 * @brief fifth step after desync
 *
 * Called each time a set of blockResponses (one for every client) is received.
 * If there are no more pendingBlocksToRequest, it triggers the sixth step,
 * ServerDumpStack().
 */
void CSyncDebugger::ServerReceivedBlockResponses()
{
	pendingBlocksToRequest.pop_front();
	waitingForBlockResponse = false;
	// analyse data and reset if this was the last block response
	if (pendingBlocksToRequest.empty())
		ServerDumpStack();
}


/**
 * @brief sixth step after desync
 *
 * Called by server once all blockResponses are received. It dumps a backtrace
 * to the logger for every checksum mismatch in the block which was out of
 * sync. The backtraces are passed to the logger in a fairly simple form
 * consisting basically only of hexadecimal addresses. The logger class
 * resolves those to function, filename & line number.
 */
void CSyncDebugger::ServerDumpStack()
{
	// first calculate start iterator...
	unsigned posInHistory = (unsigned)(remoteFlop[0] % (HISTORY_SIZE * BLOCK_SIZE));
	logger.AddLine("Server: position in history: %u", posInHistory);
	unsigned blockNr = posInHistory / BLOCK_SIZE;
	unsigned virtualBlockNr = 0; // block nr in remoteHistory (which skips unchanged blocks)
	for (; virtualBlockNr < requestedBlocks.size() && requestedBlocks[virtualBlockNr] != blockNr; ++virtualBlockNr) {}
	unsigned virtualPosInHistory = (virtualBlockNr * BLOCK_SIZE) + (posInHistory % BLOCK_SIZE) + 1;
	unsigned virtualHistorySize = remoteHistory[0].size();
	if (virtualBlockNr >= requestedBlocks.size())
		virtualPosInHistory = virtualHistorySize;
	unsigned ndif = 0; // number of differences
	assert(virtualPosInHistory <= virtualHistorySize);

	// we make a pool of backtraces (to merge identical ones)
	unsigned curBacktrace = 0;
	std::map<unsigned, unsigned> checksumToIndex;
	std::map<unsigned, unsigned> indexToHistPos;

	// then loop from virtualPosInHistory to virtualHistorySize and from 0 to virtualPosInHistory.
	for (unsigned i = virtualPosInHistory, c = 0; c < virtualHistorySize; ++i, ++c) {
		unsigned correctChecksum = 0;
		if (i == virtualHistorySize) i = 0;
		bool err = false;
		for (int j = 0; j < gs->activeTeams; ++j) {
			if (correctChecksum && remoteHistory[j][i] != correctChecksum) {
				if (historybt) {
					virtualBlockNr = i / BLOCK_SIZE;
					blockNr = requestedBlocks[virtualBlockNr];
					unsigned histPos = blockNr * BLOCK_SIZE + i % BLOCK_SIZE;
					unsigned checksum = GetBacktraceChecksum(histPos);
					std::map<unsigned, unsigned>::iterator it = checksumToIndex.find(checksum);
					if (it == checksumToIndex.end()) {
						++curBacktrace;
						checksumToIndex[checksum] = curBacktrace;
						indexToHistPos[curBacktrace] = histPos;
					}
					logger.AddLine("Server: chk %08X, %15.8e instead of %08X, %15.8e, frame %06u, backtrace %u in \"%s\"", remoteHistory[j][i], *(float*)&remoteHistory[j][i], correctChecksum, *(float*)&correctChecksum, historybt[histPos].frameNum, checksumToIndex[checksum], historybt[histPos].op);
				} else {
					logger.AddLine("Server: chk %08X, %15.8e instead of %08X, %15.8e", remoteHistory[j][i], *(float*)&remoteHistory[j][i], correctChecksum, *(float*)&correctChecksum);
				}
				err = true;
			} else {
				correctChecksum = remoteHistory[j][i];
			}
		}
		if (err) {
			++ndif;
		}
	}
	if (ndif)
		logger.AddLine("Server: chks: %d equal, %d not equal", virtualHistorySize - ndif, ndif);
	else
		// This is impossible (internal error).
		// Server first finds there are differing blocks, then all checksums equal??
		logger.AddLine("Server: huh, all checksums equal?!? (INTERNAL ERROR)");

	//cleanup
	for (int j = 0; j < MAX_PLAYERS; ++j)
		remoteHistory[j].clear();

	if (historybt) {
		// output backtraces we collected earlier this function
		for (std::map<unsigned, unsigned>::iterator it = indexToHistPos.begin(); it != indexToHistPos.end(); ++it) {
			logger.AddLine("Server: === Backtrace %u ===", it->first);
			Backtrace(it->second, "Server: ");
		}
	}

	// and reset
	serverNet->SendData(NETMSG_SD_RESET);
	logger.AddLine("Server: Done!");
	logger.CloseSession();
	logOutput.Print("[SD] Server: Done!");
}


/**
 * @brief helper network plugin function
 *
 * @return the size of the sync debugger related net message in inbuf
 * at index 0 (if any), zero otherwise.
 */
int CSyncDebugger::GetMessageLength(const unsigned char* inbuf) const
{
	switch (inbuf[0]) {
		case NETMSG_SD_CHKREQUEST:
			return 5;
		case NETMSG_SD_BLKREQUEST:
			return 7;
		case NETMSG_SD_CHKRESPONSE:
		case NETMSG_SD_BLKRESPONSE:
			return *(short*)&inbuf[1];
		case NETMSG_SD_RESET:
			return 1;
		default:
			return 0;
	}
}


/**
 * @brief re-enable the history
 *
 * Restart the sync debugger lifecycle, so it can be used again (if the sync
 * errors are resolved somehow or you were just testing it using .fakedesync).
 *
 * Called after typing '.reset' in chat area.
 */
void CSyncDebugger::Reset()
{
	if (may_enable_history)
		disable_history = false;
}

#endif // SYNCDEBUG

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -