void C4Playback::Strip() { // Strip what? const bool fStripPlayers = false; const bool fStripSyncChecks = false; const bool fStripDebugRec = true; const bool fCheckCheat = false; const bool fStripMessages = true; // const bool fCheckEMControl = true; const int32_t iEndFrame = -1; // Iterate over chunk list for (chunks_t::iterator i = chunks.begin(); i != chunks.end();) { // Strip rest of record? if (iEndFrame >= 0 && i->Frame > iEndFrame) { // Remove this and all remaining chunks while (i != chunks.end()) { i->Delete(); i = chunks.erase(i); } // Push new End-Chunk C4RecordChunk EndChunk; EndChunk.Frame = iEndFrame; EndChunk.Type = RCT_End; chunks.push_back(EndChunk); // Done break; } switch (i->Type) { case RCT_Ctrl: { // Iterate over controls C4Control *pCtrl = i->pCtrl; for (C4IDPacket *pPkt = pCtrl->firstPkt(), *pNext; pPkt; pPkt = pNext) { pNext = pCtrl->nextPkt(pPkt); switch (pPkt->getPktType()) { // Player join: Strip player file (if possible) case CID_JoinPlr: if (fStripPlayers) { C4ControlJoinPlayer *pJoinPlr = static_cast<C4ControlJoinPlayer *>(pPkt->getPkt()); pJoinPlr->Strip(); } break; // EM commands: May be cheats, so log them case CID_Script: case CID_EMMoveObj: case CID_EMDrawTool: if (fCheckCheat) Log(DecompileToBuf<StdCompilerINIWrite>( mkNamingAdapt(*pPkt, FormatString("Frame %d", i->Frame) .getData())).getData()); break; // Strip sync check case CID_SyncCheck: if (fStripSyncChecks) { i->pCtrl->Remove(pPkt); } break; } } // Strip empty control lists (always) if (!pCtrl->firstPkt()) { i->Delete(); i = chunks.erase(i); } else i++; } break; case RCT_CtrlPkt: { bool fStripThis = false; switch (i->pPkt->getPktType()) { // EM commands: May be cheats, so log them case CID_Script: case CID_EMMoveObj: case CID_EMDrawTool: if (fCheckCheat) Log(DecompileToBuf<StdCompilerINIWrite>( mkNamingAdapt(*i->pPkt, FormatString("Frame %d", i->Frame) .getData())).getData()); break; // Strip some stuff case CID_SyncCheck: if (fStripSyncChecks) fStripThis = true; break; case CID_Message: if (fStripMessages) fStripThis = true; break; } if (fStripThis) { i->Delete(); i = chunks.erase(i); } else i++; } break; case RCT_End: i++; break; default: // Strip debugrec if (fStripDebugRec) { i->Delete(); i = chunks.erase(i); } else i++; } } }
bool C4Network2IO::HandlePacket(const C4NetIOPacket &rPacket, C4Network2IOConnection *pConn, bool fThread) { // security: add connection reference if (!pConn) return false; pConn->AddRef(); // accept only PID_Conn and PID_Ping on non-accepted connections if(!pConn->isHalfAccepted()) if(rPacket.getStatus() != PID_Conn && rPacket.getStatus() != PID_Ping && rPacket.getStatus() != PID_ConnRe) return false; // unpack packet (yet another no-idea-why-it's-needed-cast) C4IDPacket Pkt; C4PacketBase &PktB = Pkt; try { PktB.unpack(rPacket); } catch (StdCompiler::Exception *pExc) { Application.InteractiveThread.ThreadLog("Network: error: Failed to unpack packet id %02x: %s", rPacket.getStatus(), pExc->Msg.getData()); delete pExc; #ifndef _DEBUG pConn->Close(); #endif return false; } // dump packet (network thread only) #if(C4NET2IO_DUMP_LEVEL > 0) if (Config.Network.PacketLogging && fThread && Pkt.getPktType() != PID_Ping && Pkt.getPktType() != PID_Pong && Pkt.getPktType() != PID_NetResData) { // StdStrBuf PacketDump = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdaptrPacket); StdStrBuf PacketHeader = FormatString("HandlePacket: %s by %s:%d (%lu bytes, counter %d)", C4TimeMilliseconds::Now().AsString().getData(), inet_ntoa(pConn->getPeerAddr().sin_addr), htons(pConn->getPeerAddr().sin_port), static_cast<unsigned long>(rPacket.getSize()), pConn->getInPacketCounter()); StdStrBuf Dump = DecompileToBuf<StdCompilerINIWrite>(mkNamingAdapt(Pkt, PacketHeader.getData())); // Put it directly. The standard functions behind StdBuf.Format seem to choke when you pass them too much data. Application.InteractiveThread.PushEvent(Ev_LogSilent, Dump.GrabPointer()); } #endif // search packet handling data bool fSendToMainThread = false, fHandled = false; for (const C4PktHandlingData *pHData = PktHandlingData; pHData->ID != PID_None; pHData++) if (pHData->ID == rPacket.getStatus()) { // correct thread? if (!pHData->ProcByThread == !fThread) { // connection accepted? if (pHData->AcceptedOnly || pConn->isAccepted() || pConn->isClosed()) { fHandled = true; #if(C4NET2IO_DUMP_LEVEL > 2) C4TimeMilliseconds tStart = C4TimeMilliseconds::Now(); #endif // call handler(s) CallHandlers(pHData->HandlerID, &Pkt, pConn, fThread); #if(C4NET2IO_DUMP_LEVEL > 2) uint32_t iBlockedTime = C4TimeMilliseconds::Now() - tStart; if (fThread && iBlockedTime > 100) { Application.InteractiveThread.ThreadLogS("HandlePacket: ... blocked for %u ms!", iBlockedTime); } #endif } } // transfer to main thread? else if (!pHData->ProcByThread && fThread) { fHandled = true; fSendToMainThread = true; } } // send to main thread? if (fSendToMainThread) { // create data NetEvPacketData *pEvData = new NetEvPacketData; pEvData->Packet.Take(rPacket.Duplicate()); pEvData->Conn = pConn; pConn->AddRef(); // trigger event if (!Application.InteractiveThread.PushEvent(Ev_Net_Packet, pEvData)) Application.InteractiveThread.ThreadLogS("...push event "); } // unhandled? if (!fHandled && !pConn->isClosed()) Application.InteractiveThread.ThreadLog("Network: Unhandled packet (status %02x)", rPacket.getStatus()); // remove connection reference pConn->DelRef(); return fHandled; }