fixed ticket [f9c074e766ade1bd] (pickups should not be infinitely tall) (i hope ;-)
[k8vavoom.git] / source / net / network.h
blob751048f19d9ea614906df8083d8eba90a6818f2b
1 //**************************************************************************
2 //**
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
9 //**
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
12 //**
13 //** This program is free software: you can redistribute it and/or modify
14 //** it under the terms of the GNU General Public License as published by
15 //** the Free Software Foundation, version 3 of the License ONLY.
16 //**
17 //** This program is distributed in the hope that it will be useful,
18 //** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 //** GNU General Public License for more details.
21 //**
22 //** You should have received a copy of the GNU General Public License
23 //** along with this program. If not, see <http://www.gnu.org/licenses/>.
24 //**
25 //**************************************************************************
26 #ifndef VAVOOM_NETWORK_HEADER
27 #define VAVOOM_NETWORK_HEADER
29 #include "../level/beamclip.h"
32 // ////////////////////////////////////////////////////////////////////////// //
33 // 32 bytes; the actual hash function is BLAKE2b from Monocypher
34 #define K8VNET_DIGEST_SIZE (32)
37 // ////////////////////////////////////////////////////////////////////////// //
38 struct VNetUtils {
39 static void TVMsecs (timeval *dest, int msecs) noexcept;
41 // start with 0, continuous
42 static vuint32 CRC32C (vuint32 crc32, const void *buf, size_t length) noexcept;
44 // // ChaCha20 // //
46 struct ChaCha20Ctx {
47 vuint32 input[16];
50 //typedef chacha20_ctx ChaCha20Ctx;
52 enum {
53 ChaCha20KeySize = 32,
54 ChaCha20NonceSize = 4,
55 ChaCha20CheckSumSize = 4,
56 ChaCha20HeaderSize = ChaCha20KeySize+ChaCha20NonceSize+ChaCha20CheckSumSize,
58 // for real setups
59 ChaCha20RealNonceSize = 8,
62 /* encrypts or decrypts a full message */
63 /* cypher is symmetric, so `ciphertextdata` and `plaintextdata` can point to the same address */
64 static void ChaCha20XCrypt (const vuint8 keydata[ChaCha20KeySize], const vuint32 nonce,
65 void *ciphertextdata, const void *plaintextdata, vuint32 msglen) noexcept;
67 // generate ChaCha20 encryption key
68 static void GenerateKey (vuint8 key[ChaCha20KeySize]) noexcept;
70 // derive public key from secret one
71 static void DerivePublicKey (vuint8 mypk[ChaCha20KeySize], const vuint8 mysk[ChaCha20KeySize]);
73 // derive shared secret from our secret and their public
74 static void DeriveSharedKey (vuint8 sharedk[ChaCha20KeySize], const vuint8 mysk[ChaCha20KeySize], const vuint8 theirpk[ChaCha20KeySize]);
76 // WARNING! cannot do it in-place
77 // needs 24 extra bytes (key, nonce, crc)
78 // returns new length or -1 on error
79 static int EncryptInfoPacket (void *destbuf, const void *srcbuf, int srclen, const vuint8 key[ChaCha20KeySize]) noexcept;
80 // it can decrypt in-place
81 // returns new length or -1 on error
82 // also sets key
83 static int DecryptInfoPacket (vuint8 key[ChaCha20KeySize], void *destbuf, const void *srcbuf, int srclen) noexcept;
87 class VNetContext;
89 // sent on handshake
90 enum {
91 NET_PROTOCOL_VERSION_HI = 7,
92 NET_PROTOCOL_VERSION_LO = 17,
95 enum {
96 MAX_CHANNELS = 1024,
97 MAX_RELIABLE_BUFFER = 128,
100 enum EChannelType {
101 CHANNEL_Control = 1,
102 CHANNEL_Level,
103 CHANNEL_Player,
104 CHANNEL_Thinker,
105 CHANNEL_ObjectMap,
107 CHANNEL_MAX,
110 //FIXME!
111 //TODO!
112 // separate messages from packets, so we can fragment and reassemble one message with several packets
113 enum {
114 MAX_DGRAM_SIZE = 1400, // max length of a datagram; fuck off, ipshit6
116 MAX_PACKET_HEADER_BITS = 32*2, // packet id, crc32
118 // including message header
119 MAX_MSG_SIZE_BITS = MAX_DGRAM_SIZE*8-MAX_PACKET_HEADER_BITS,
123 enum EChannelIndex {
124 CHANIDX_General,
125 CHANIDX_Player,
126 CHANIDX_Level,
127 CHANIDX_ObjectMap,
128 CHANIDX_ThinkersStart,
132 // used in level channel
133 struct VNetClientServerInfo {
134 VStr mapname;
135 VStr maphash;
136 vuint32 modhash;
137 VStr sinfo;
138 int maxclients;
139 int deathmatch;
143 // network message classes
144 class VMessageIn;
145 class VMessageOut;
146 class VNetConnection;
149 // ////////////////////////////////////////////////////////////////////////// //
150 // public interface of a network socket
151 class VSocketPublic : public VInterface {
152 public:
153 VStr Address;
154 // this is the key we'll use for communication
155 vuint8 AuthKey[VNetUtils::ChaCha20KeySize];
156 // this is the key we got from the client
157 vuint8 ClientKey[VNetUtils::ChaCha20KeySize];
159 double ConnectTime = 0;
160 double LastMessageTime = 0;
162 vuint64 bytesSent = 0;
163 vuint64 bytesReceived = 0;
164 vuint64 bytesRejected = 0;
165 unsigned minimalSentPacket = 0;
166 unsigned maximalSentPacket = 0;
168 virtual bool IsLocalConnection () const noexcept = 0;
169 // dest should be at least `MAX_DGRAM_SIZE+4` (just in case)
170 // returns number of bytes received, 0 for "no message", -1 for error
171 // if the message is too big for a buffer, return -1
172 virtual int GetMessage (void *dest, size_t destSize) = 0;
173 virtual int SendMessage (const vuint8 *, vuint32) = 0;
175 virtual void UpdateSentStats (vuint32 length) noexcept;
176 virtual void UpdateReceivedStats (vuint32 length) noexcept;
177 virtual void UpdateRejectedStats (vuint32 length) noexcept;
179 virtual void DumpStats ();
181 static VStr u64str (vuint64 v, bool comatose=true) noexcept;
185 // ////////////////////////////////////////////////////////////////////////// //
186 // an entry into a hosts cache table
187 struct hostcache_t {
188 VStr Name;
189 VStr Map;
190 VStr CName;
191 TArray<VStr> WadFiles;
192 vint32 Users;
193 vint32 MaxUsers;
194 vint32 DeathMatch; // dm mode
195 enum {
196 Flag_GoodProtocol = 1u<<0,
197 Flag_GoodWadList = 1u<<1,
198 Flag_PasswordProtected = 1u<<2,
200 vuint32 Flags;
204 // ////////////////////////////////////////////////////////////////////////// //
205 // structure returned to progs
206 struct slist_t {
207 enum { SF_InProgress = 0x01 };
208 vuint32 Flags;
209 hostcache_t *Cache;
210 vint32 Count;
211 VStr ReturnReason;
215 // ////////////////////////////////////////////////////////////////////////// //
216 // public networking driver interface
217 class VNetworkPublic : public VInterface {
218 public:
219 // statistic counters
220 int UnreliableMessagesSent;
221 int UnreliableMessagesReceived;
222 int packetsSent;
223 int packetsReSent;
224 int packetsReceived;
225 int receivedDuplicateCount;
226 int shortPacketCount;
227 int droppedDatagrams;
228 vuint64 bytesSent;
229 vuint64 bytesReceived;
230 vuint64 bytesRejected;
231 unsigned minimalSentPacket;
232 unsigned maximalSentPacket;
234 // if set, `Connect()` will call this to check if user aborted the process
235 // return `true` if aborted
236 bool (*CheckUserAbortCB) (void *udata);
237 void *CheckUserAbortUData; // user-managed
239 double CurrNetTime; // cached time
241 public:
242 VNetworkPublic ();
244 inline bool CheckForUserAbort () { return (CheckUserAbortCB ? CheckUserAbortCB(CheckUserAbortUData) : false); }
246 virtual void Init () = 0;
247 virtual void Shutdown () = 0;
248 virtual VSocketPublic *Connect (const char *InHost) = 0;
249 virtual VSocketPublic *CheckNewConnections (bool rconOnly) = 0;
250 virtual void Poll () = 0;
251 virtual void StartSearch (bool) = 0;
252 virtual slist_t *GetSlist () = 0;
253 virtual void UpdateMaster () = 0;
254 virtual void QuitMaster () = 0;
256 // call this to update current network time
257 // used to avoid calls to `Sys_Time()` everywhere
258 // should be called in connection ticker, in context ticker, and in `GetMessages()`
259 void UpdateNetTime () noexcept;
260 double GetNetTime () noexcept;
262 void UpdateSentStats (vuint32 length) noexcept;
263 void UpdateReceivedStats (vuint32 length) noexcept;
264 void UpdateRejectedStats (vuint32 length) noexcept;
266 public:
267 static VNetworkPublic *Create ();
271 // ////////////////////////////////////////////////////////////////////////// //
272 // base class for network channels that are responsible for sending and receiving of the data.
273 class VChannel {
274 public:
275 VNetConnection *Connection;
276 vint32 Index;
277 vuint8 Type;
278 bool OpenedLocally; // `true` if opened locally, `false` if opened by the remote
279 bool OpenAcked; // is open acked? (obviously)
280 bool Closing; // channel sent "close me" message, and is waiting for ack
281 int InListCount; // number of packets in InList
282 int InListBits; // rough estimation, used to limit transfers
283 int OutListCount; // number of packets in OutList
284 int OutListBits; // rough estimation, used to limit transfers
285 VMessageIn *InList; // incoming data with queued dependencies
286 VMessageOut *OutList; // outgoing reliable unacked data
287 bool bSentAnyMessages; // if this is `false`, force `bOpen` flag on the sending message (and set this to `true`)
289 public:
290 inline static const char *GetChanTypeName (vuint8 type) noexcept {
291 switch (type) {
292 case 0: return "<broken0>";
293 case CHANNEL_Control: return "Control";
294 case CHANNEL_Level: return "Level";
295 case CHANNEL_Player: return "Player";
296 case CHANNEL_Thinker: return "Thinker";
297 case CHANNEL_ObjectMap: return "ObjectMap";
298 default: return "<internalerror>";
302 // this unconditionally adds "close" message to the queue, and marks the channel for closing
303 // WARNING! DOES NO CHECKS!
304 void SendCloseMessageForced ();
306 public:
307 VChannel (VNetConnection *AConnection, EChannelType AType, vint32 AIndex, bool AOpenedLocally);
308 virtual ~VChannel ();
310 inline const char *GetTypeName () const noexcept { return GetChanTypeName(Type); }
312 virtual VStr GetName () const noexcept;
313 VStr GetDebugName () const noexcept;
315 inline bool IsThinker () const noexcept { return (Type == CHANNEL_Thinker); }
317 inline int GetSendQueueSize () const noexcept { return OutListCount; }
318 inline int GetRecvQueueSize () const noexcept { return InListCount; }
320 vuint32 GetLastOutSeq () const noexcept;
322 // returns:
323 // -1: oversaturated
324 // 0: ok
325 // 1: full
326 virtual int IsQueueFull () noexcept;
328 // is this channel opened locally?
329 inline bool IsLocalChannel () const noexcept { return OpenedLocally; }
331 // this is called to set `Closing` flag, and can perform some cleanup
332 virtual void SetClosing ();
334 // this is called from `ReceivedAcks()`
335 // the channel will be automatically closed and destroyed, so don't do it here
336 virtual void ReceivedCloseAck ();
338 // this sends reliable "close" message, if the channel in not on closing state yet
339 virtual void Close ();
341 // called by `ReceivedMessage()` to parse new message
342 // this call is sequenced (i.e. the sequence is right)
343 virtual void ParseMessage (VMessageIn &Msg) = 0;
345 // this is called to notify the channel that some messages are lost
346 // normal logic simply retransmit the messages with the given packet id
347 virtual void PacketLost (vuint32 PacketId);
349 // call this periodically to perform various processing
350 // this handler SHOULD NOT DELETE THE CHANNEL!
351 virtual void Tick ();
353 // called by `ReceivedAcks()`, strictly in sequence
354 virtual void OutMessageAcked (VMessageOut &Msg);
356 // WARNING! this method can call `delete this`!
357 // this is called from connection when this channel got some acks
358 void ReceivedAcks ();
360 // returns `true` if this channel killed itself
361 // this is called to process messages in sequence (from `ReceivedMessage()`)
362 bool ProcessInMessage (VMessageIn &Msg);
364 // this is called when new message for this channel is received
365 void ReceivedMessage (VMessageIn &Msg);
367 // sets `PacketId` field in the message, you can use it
368 void SendMessage (VMessageOut *Msg);
370 bool CanSendData () noexcept;
371 bool CanSendClose () noexcept;
373 void SendRpc (VMethod *, VObject *);
374 bool ReadRpc (VMessageIn &Msg, int, VObject *);
376 public: // this interface can be used to split data streams into separate messages
377 // returns `true` if appending `addbits` will overflow the message
378 bool WillOverflowMsg (const VMessageOut *msg, int addbits) const noexcept;
380 // returns `true` if appending `strm` will overflow the message
381 bool WillOverflowMsg (const VMessageOut *msg, const VBitStreamWriter &strm) const noexcept;
383 // *moves* steam to msg (sending previous msg if necessary)
384 // returns `true` if something was flushed
385 bool PutStream (VMessageOut *msg, VBitStreamWriter &strm);
387 // sends message if it is not empty, and clears it
388 // returns `true` if something was flushed
389 bool FlushMsg (VMessageOut *msg);
393 // ////////////////////////////////////////////////////////////////////////// //
394 class VControlChannel : public VChannel {
395 public:
396 VControlChannel (VNetConnection *, vint32, vuint8 = true);
398 // VChannel interface
399 virtual VStr GetName () const noexcept override;
400 virtual void ParseMessage (VMessageIn &) override;
404 // ////////////////////////////////////////////////////////////////////////// //
405 // a channel for updating level data
406 class VLevelChannel : public VChannel {
407 public:
408 struct VBodyQueueTrInfo {
409 vuint8 TranslStart;
410 vuint8 TranslEnd;
411 vint32 Color;
414 VLevel *Level;
415 rep_line_t *Lines;
416 rep_side_t *Sides;
417 rep_sector_t *Sectors;
418 rep_polyobj_t *PolyObjs;
419 TArray<VCameraTextureInfo> CameraTextures;
420 TArray<TArray<VTextureTranslation::VTransCmd> > Translations;
421 TArray<VBodyQueueTrInfo> BodyQueueTrans;
423 VStr serverInfoBuf;
424 VNetClientServerInfo csi;
426 int StaticLightsNext;
428 // build by `BuildUpdateSets()`
429 TMapNC<vint32, bool> UpdatedLines;
430 TMapNC<vint32, bool> UpdatedSides;
432 protected:
433 // connection fat PVS must be built
434 void BuildUpdateSets ();
436 // updaters returns 1 if the stream should be sent, or -1 if we should abort updating
437 // parsers returns `false` on any error
439 int UpdateLine (VMessageOut &Msg, VBitStreamWriter &strm, int lidx);
440 bool ParseLine (VMessageIn &Msg);
442 int UpdateSide (VMessageOut &Msg, VBitStreamWriter &strm, int sidx);
443 bool ParseSide (VMessageIn &Msg);
444 bool ParseSideTexture (VMessageIn &Msg);
445 bool ParseSideTOffset (VMessageIn &Msg);
446 bool ParseSideROffset (VMessageIn &Msg);
447 bool ParseSideScale (VMessageIn &Msg);
449 int UpdateSector (VMessageOut &Msg, VBitStreamWriter &strm, int sidx);
450 bool ParseSector (VMessageIn &Msg);
451 bool ParseSectorTexture (VMessageIn &Msg);
452 bool ParseSectorLight (VMessageIn &Msg);
454 int UpdatePolyObj (VMessageOut &Msg, VBitStreamWriter &strm, int oidx);
455 bool ParsePolyObj (VMessageIn &Msg);
457 int UpdateCameraTexture (VMessageOut &Msg, VBitStreamWriter &strm, int idx);
458 bool ParseCameraTexture (VMessageIn &Msg);
460 int UpdateTranslation (VMessageOut &Msg, VBitStreamWriter &strm, int idx);
461 bool ParseTranslation (VMessageIn &Msg);
463 int UpdateBodyQueueTran (VMessageOut &Msg, VBitStreamWriter &strm, int idx);
464 bool ParseBodyQueueTran (VMessageIn &Msg);
466 int UpdateStaticLight (VMessageOut &Msg, VBitStreamWriter &strm, int idx, bool forced);
467 bool ParseStaticLight (VMessageIn &Msg);
469 protected:
470 enum {
471 PhaseServerInfo,
472 PhaseWaitingMapLoaded,
473 PhaseStaticLights,
474 PhasePrerender,
475 PhaseDone,
478 int Phase;
479 double MapLoadingStartTime;
481 protected:
482 void SendServerInfo ();
483 void WaitForMapLoaded ();
484 void SendStaticLights ();
485 void SendPreRender ();
487 public:
488 VLevelChannel (VNetConnection *, vint32, vuint8 = true);
489 virtual ~VLevelChannel () override;
491 void SetLevel (VLevel *);
492 // returns `false` if there's nothing more to send
493 bool SendLevelData ();
494 void Update ();
495 void ResetLevel ();
497 // used by the client
498 void SendMapLoaded ();
500 // VChannel interface
501 virtual VStr GetName () const noexcept override;
502 virtual void ParseMessage (VMessageIn &) override;
506 // ////////////////////////////////////////////////////////////////////////// //
507 // a channel for updating thinkers
508 class VThinkerChannel : public VChannel {
509 protected:
510 VThinker *Thinker;
511 vuint8 *OldData; // old field data, for creating deltas
512 bool NewObj; // is this a new object?
513 vuint8 *FieldCondValues;
514 // this is used by the thinker updater
515 // if 1/3 of the channel is still full after this time, we'll block any updates until it is completely drained
516 double DrainTime;
517 bool bNeedToDrain;
519 public:
520 // set by the client when it gets `Origin` update
521 bool GotOrigin;
522 vuint32 LastUpdateFrame; // see `UpdateFrameCounter` in VNetConnection
524 public:
525 VThinkerChannel (VNetConnection *AConnection, vint32 AIndex, vuint8 AOpenedLocally=true);
526 virtual ~VThinkerChannel () override;
528 inline VThinker *GetThinker () const noexcept { return Thinker; }
530 void SetThinker (VThinker *);
531 void EvalCondValues (VObject *, VClass *, vuint8 *);
532 void Update ();
533 void RemoveThinkerFromGame ();
535 // VChannel interface
536 virtual VStr GetName () const noexcept override;
537 virtual void ParseMessage (VMessageIn &) override;
538 virtual void SetClosing () override;
539 // limit thinkers by the number of outgoing packets instead
540 virtual int IsQueueFull () noexcept override;
544 // ////////////////////////////////////////////////////////////////////////// //
545 // a channel for updating player data
546 class VPlayerChannel : public VChannel {
547 public:
548 VBasePlayer *Plr;
549 vuint8 *OldData;
550 bool NewObj;
551 vuint8 *FieldCondValues;
552 // some class references may be not sent at the start; repeat 'em while we can
553 TMapNC<VField *, bool> FieldsToResend;
554 // this is used in server, to limit client update rate
555 double NextUpdateTime;
556 vuint32 LastMOSUid;
557 VField *GameTimeField;
558 // set at the client side after we got `MO.Origin`
559 // reset on player reset, or when MO disappears
560 bool GotMOOrigin;
562 protected:
563 // sets flags, calls methods, etc.
564 void CheckPlayerMO ();
566 public:
567 VPlayerChannel (VNetConnection *, vint32, vuint8 = true);
568 virtual ~VPlayerChannel () override;
570 void SetPlayer (VBasePlayer *);
571 void EvalCondValues (VObject *, VClass *, vuint8 *);
572 void Update ();
574 // call this when new level is loaded
575 void ResetLevel ();
577 // VChannel interface
578 virtual VStr GetName () const noexcept override;
579 virtual void SetClosing () override;
580 virtual void ParseMessage (VMessageIn &) override;
584 // ////////////////////////////////////////////////////////////////////////// //
585 // a channel for sending object map at startup
586 class VObjectMapChannel : public VChannel {
587 private:
588 vint32 CurrName;
589 vint32 CurrClass;
590 bool needOpenMessage; // valid only for local channel (sender)
591 // names are compressed, because we usually have a lot (around 400kb)
592 vint32 unpDataSize;
593 vint32 cprBufferSize;
594 vint32 cprBufferPos;
595 vuint8 *cprBuffer;
596 // set when we complete sending initial data (known names and classes)
597 // after we set this one: `CurrName` is next name to receive, or last acked name
598 // `NextNameToSend` is for server only
599 bool InitialDataDone;
600 vint32 NextNameToSend;
601 // for client
602 vuint8 serverReplicationHash[K8VNET_DIGEST_SIZE];
604 protected:
605 void UpdateSendPBar ();
606 void UpdateRecvPBar (bool forced);
608 void ClearCprBuffer ();
609 void CompressNames ();
610 void DecompressNames ();
612 // this fills
613 void BuildNetFieldsHash (vuint8 hash[K8VNET_DIGEST_SIZE]);
615 // this sends new names
616 void LiveUpdate ();
618 void LiveParse (VMessageIn &Msg);
620 public:
621 VObjectMapChannel (VNetConnection *AConnection, vint32 AIndex, vuint8 AOpenedLocally);
622 virtual ~VObjectMapChannel () override;
624 void Update ();
626 // VChannel interface
627 virtual VStr GetName () const noexcept override;
628 virtual void ReceivedCloseAck () override; // sets `ObjMapSent` flag
629 virtual void ParseMessage (VMessageIn &) override;
630 virtual void Tick () override;
631 // slightly higher limits
632 virtual int IsQueueFull () noexcept override;
636 // ////////////////////////////////////////////////////////////////////////// //
637 enum ENetConState {
638 NETCON_Closed,
639 NETCON_Open,
643 // ////////////////////////////////////////////////////////////////////////// //
644 // network connection class, responsible for sending and receiving network
645 // packets and managing of channels.
646 class VNetConnection {
647 protected:
648 VSocketPublic *NetCon;
650 public:
651 struct ThinkerSortInfo {
652 VEntity *MO;
653 TVec ViewOrg;
654 TAVec ViewAngles;
655 // everything that is behind this is behind our back
656 TPlane ViewPlane;
658 inline ThinkerSortInfo () noexcept {}
659 ThinkerSortInfo (VBasePlayer *Owner) noexcept;
662 public:
663 enum {
664 LNFO_UNSENT,
665 LNFO_SENT_INPROGRESS, // we're still have something to send
666 LNFO_SENT_COMPLETE, // we're sending static lights
669 public:
670 VNetworkPublic *Driver;
671 VNetContext *Context;
672 VBasePlayer *Owner;
673 ENetConState State;
674 vuint8 AuthKey[VNetUtils::ChaCha20KeySize];
675 bool NeedsUpdate; // should we call `VNetConnection::UpdateLevel()`? this updates mobjs in sight, and sends new mobj state
676 bool AutoAck; // `true` for demos: autoack all pacekts
677 double LastLevelUpdateTime;
678 double LastThinkersUpdateTime;
679 vuint32 UpdateFrameCounter; // monotonically increasing
680 vuint32 UpdateFingerUId; // see `UpdateThinkers()` for the explanation
682 VNetObjectsMap *ObjMap;
683 bool ObjMapSent;
684 int LevelInfoSent; // see LNFO_*
685 // when we detach a thinker, there's no need to send any updates for it anymore
686 // we cannot have this flag in thinker itself, because new
687 // clients should still get detached thinkers once
688 TMapNC<VThinker *, bool> DetachedThinkers;
689 TMapNC<VThinker *, bool> SimulatedThinkers;
691 // timings, etc.
692 double LastReceiveTime; // last time a packet was received, for timeout checking
693 double LastSendTime; // last time a packet was sent, for keepalives
694 double LastTickTime; // last time when `Tick()` was called (used to estimate bandwidth)
695 int SaturaDepth; // estimation: how much bytes the connection can queue before saturation? (positive means "saturated")
696 bool ForceFlush; // should we force network flush in the next tick?
698 // statistics
699 double LastStatsUpdateTime; // time of last stat update
700 double InRate, OutRate; // rate for last interval
701 double InPackets, OutPackets; // packet counts
702 double InMessages, OutMessages; // message counts
703 double InLoss, OutLoss; // packet loss percent
704 double InOrder, OutOrder; // out of order incoming packets
705 double AvgLag, PrevLag; // average lag, average lag from the previous update
707 // statistics accumulators
708 double LagAcc; // average lag
709 int InLossAcc, OutLossAcc; // packet loss accumulator
710 int InPktAcc, OutPktAcc; // packet accumulator
711 int InMsgAcc, OutMsgAcc; // message accumulator
712 int InByteAcc, OutByteAcc; // byte accumulator
713 int InOrdAcc; // out of order accumulator
714 int LagCount; // counter for lag measurement
715 double LastFrameStartTime, FrameDeltaTime; // monitors frame time
716 double CumulativeTime, AverageFrameTime;
717 int StatsFrameCounter;
719 // current packet
720 VBitStreamWriter Out; // outgoing packet
721 double OutLagTime[256]; // for lag measuring
722 vuint32 OutLagPacketId[256]; // for lag measuring
723 vuint32 InPacketId; // full incoming packet index
724 vuint32 OutPacketId; // most recently sent packet
725 vuint32 OutAckPacketId; // most recently acked outgoing packet
726 vuint32 OutLastWrittenAck; // starts with 0
728 // channel table
729 VChannel *Channels[MAX_CHANNELS];
730 vuint32 OutReliable[MAX_CHANNELS];
731 vuint32 InReliable[MAX_CHANNELS];
732 TArray<vuint32> QueuedAcks;
733 TArray<vuint32> AcksToResend;
734 TArray<VChannel *> OpenChannels;
735 TMapNC<VThinker *, VThinkerChannel *> ThinkerChannels;
737 VField *OriginField;
738 VField *DataGameTimeField;
740 private:
741 // subsectors
742 //vuint8 *UpdatePvs;
743 //int UpdatePvsSize;
745 public:
746 // hash tables, to speed up various updates
747 // built with fat PVS
748 TMapNC<vint32, bool> UpdatedSubsectors;
749 TMapNC<vint32, bool> UpdatedSectors;
751 private:
752 // `LeafPvs` was meant to point to glVIS info, but it is currently disabled
753 const vuint8 *LeafPvs;
754 VViewClipper Clipper;
755 // this is used in `VNetConnection::UpdateLevel()`
756 // temporary buffers, only valid in that method.
757 TArrayNC<VThinker *> PendingThinkers;
758 TArrayNC<VEntity *> PendingGoreEnts;
759 TArrayNC<vint32> AliveGoreChans;
760 TArrayNC<VThinker *> AliveThinkerChans;
762 void CollectAndSortAliveThinkerChans (ThinkerSortInfo *snfo);
764 public:
765 // current estimated message byte size
766 // used to check if we can add given number of bits without flushing
767 inline int CalcEstimatedByteSize (int addBits=0) const noexcept {
768 const int endsize = (Out.GetNumBits() ? 0 : MAX_PACKET_HEADER_BITS)+Out.GetNumBits()+addBits+1;
769 return (endsize+7)>>3;
772 int GetNetSpeed () const noexcept;
774 // used in server context; if `false`, server context will call `SendServerInfo()`
775 inline bool IsLevelInfoSendingComplete () const noexcept { return (LevelInfoSent == LNFO_SENT_COMPLETE); }
777 protected:
778 // WARNING! this can change channel list!
779 void AckEverythingEverywhere ();
781 public:
782 VNetConnection (VSocketPublic *ANetCon, VNetContext *AContext, VBasePlayer *AOwner);
783 virtual ~VNetConnection ();
785 VChannel *CreateChannel (vuint8 Type, vint32 AIndex, vuint8 OpenedLocally/*=true*/);
787 inline VChannel *GetGeneralChannel () noexcept { return Channels[CHANIDX_General]; }
788 inline VPlayerChannel *GetPlayerChannel () noexcept { return (VPlayerChannel *)(Channels[CHANIDX_Player]); }
789 inline VLevelChannel *GetLevelChannel () noexcept { return (VLevelChannel *)(Channels[CHANIDX_Level]); }
791 inline VChannel *GetChannelByIndex (int idx) noexcept { return (idx >= 0 && idx < MAX_CHANNELS ? Channels[idx] : nullptr); }
793 inline VStr GetAddress () const { return (NetCon ? NetCon->Address : VStr()); }
795 inline bool IsOpen () const noexcept { return (State > NETCON_Closed); }
796 inline bool IsClosed () const noexcept { return (State <= NETCON_Closed); }
798 bool IsClient () noexcept;
799 bool IsServer () noexcept;
800 bool IsLocalConnection () const noexcept;
802 // this marks the connection as closed, but doesn't destroy anything
803 void Close ();
805 // call this to process incoming messages
806 // if `asHearbeat` is `true`, update timers, but drop all received messages
807 void GetMessages (bool asHearbeat=false);
809 virtual int GetRawPacket (void *dest, size_t destSize); // used in demos
811 // read and process one incoming message
812 // returns `false` if no message was processed
813 // if `asHearbeat` is `true`, update timers, but drop all received messages
814 bool GetMessage (bool asHearbeat);
816 // this is called when incoming message was read; it should decode and process network packet
817 void ReceivedPacket (VBitStreamReader &Packet);
819 // this is called by channel send/recv methods on fatal queue overflow
820 // you *CANNOT* `delete` channel here, as it is *NOT* guaranteed that call to this
821 // method is followed by `return`!
822 // you CAN call `chan->Close()` here
823 virtual void AbortChannel (VChannel *chan);
825 // sets `PacketId` field in the message, you can use it
826 virtual void SendMessage (VMessageOut *Msg);
828 virtual void SendPacketAck (vuint32 PacketId);
830 virtual void Flush ();
831 virtual void Tick ();
832 // if we're doing only heartbeats, we will silently drop all incoming datagrams
833 // this is requred so the connection won't be timeouted on map i/o, for example
834 virtual void KeepaliveTick ();
836 // this marks connection as "saturated"
837 virtual void Saturate () noexcept;
839 virtual bool CanSendData () const noexcept;
841 // returns argument for `Prepare` if putting the ack will overflow the output buffer.
842 // i.e. if it returned non-zero, ack is not put.
843 // if `forceSend` is `true`, flush the output buffer if necessary (always sends, returns 0).
844 int PutOneAck (vuint32 ackId, bool forceSend=false);
845 // for convenience
846 inline void PutOneAckForced (vuint32 ackId) { const int res = PutOneAck(ackId, true); vassert(res == 0); }
847 // resend all acks from `AcksToResend`, and clears `AcksToResend`
848 void ResendAcks ();
850 // call this to make sure that the output buffer has enough room
851 void Prepare (int addBits);
853 // this is called to notify all channels that some messages are lost
854 // normal logic simply retransmit the messages with the given packet id
855 void PacketLost (vuint32 PacketId);
857 // send console command
858 void SendCommand (VStr Str);
860 // fat PVS should be set up
861 bool IsRelevant (VThinker *th);
863 // inventory is always relevant too
864 // doesn't check PVS
865 // call after `IsRelevant()` returned `true`, because this does much less checks
866 bool IsAlwaysRelevant (VThinker *th);
868 // this is called by server code to send updates to clients
869 void UpdateLevel ();
871 void SendServerInfo ();
872 void LoadedNewLevel ();
873 void ResetLevel ();
875 bool SecCheckFatPVS (const sector_t *Sec);
876 bool CheckFatPVS (const subsector_t *Subsector);
878 // used by client to lower rendering speed
879 // this is hack for my GPU
880 bool IsDangerousTimeout ();
882 protected:
883 void SetupFatPVS ();
884 void SetupPvsSubsector (VLevel *Level, int subnum);
885 void SetupPvsNode (VLevel *Level, int BspNum, const float BBox[6]);
886 void PvsMarkExtra (sector_t *sec);
887 void PvsAddSector (sector_t *sec);
889 protected:
890 // used in `UpdateLevel()`
891 void UpdateThinkers ();
893 // returns `true` if connection timeouted
894 bool IsTimeoutExceeded ();
895 bool IsKeepAliveExceeded ();
897 void ShowTimeoutStats ();
901 // ////////////////////////////////////////////////////////////////////////// //
902 // class that provides access to client or server specific data
903 class VNetContext {
904 public:
905 VField *RoleField;
906 VField *RemoteRoleField;
907 VField *OwnerField;
908 VField *TargetField;
909 VField *TracerField;
910 VField *MasterField;
911 VNetConnection *ServerConnection; // non-nullptr for clients (only)
912 TArray<VNetConnection *> ClientConnections; // known clients for servers
914 public:
915 VNetContext ();
916 virtual ~VNetContext ();
918 inline bool IsClient () const noexcept { return (ServerConnection != nullptr); }
919 inline bool IsServer () const noexcept { return (ServerConnection == nullptr); }
921 // VNetContext interface
922 virtual VLevel *GetLevel() = 0;
923 void ThinkerDestroyed (VThinker *);
924 void Tick ();
925 void KeepaliveTick ();
929 // ////////////////////////////////////////////////////////////////////////// //
930 // a client side network context
931 class VClientNetContext : public VNetContext {
932 public:
933 // VNetContext interface
934 virtual VLevel *GetLevel () override;
938 // ////////////////////////////////////////////////////////////////////////// //
939 // server side network context
940 class VServerNetContext : public VNetContext {
941 public:
942 // VNetContext interface
943 virtual VLevel *GetLevel () override;
947 // ////////////////////////////////////////////////////////////////////////// //
948 class VNetObjectsMap : public VNetObjectsMapBase {
949 private:
950 TArray<VName> NameLookup;
951 TArray<int> NameMap;
953 TArray<VClass *> ClassLookup;
954 TMap<VClass *, vuint32> ClassMap;
956 public:
957 VNetConnection *Connection;
959 public:
960 VNetObjectsMap ();
961 VNetObjectsMap (VNetConnection *AConnection);
962 virtual ~VNetObjectsMap ();
964 void SetupClassLookup ();
965 bool CanSerialiseObject (VObject *Obj);
967 // called on name receiving
968 void SetNumberOfKnownNames (int newlen);
969 // called on reading
970 void ReceivedName (int index, VName Name);
972 // this is for initial class sending
973 // out stream may be dropped, so we need to defer name internalising here
974 bool SerialiseNameNoIntern (VStream &Strm, VName &Name);
976 void AckNameWithIndex (int index);
978 virtual bool SerialiseName (VStream &, VName &) override;
979 virtual bool SerialiseObject (VStream &, VObject *&) override;
980 virtual bool SerialiseClass (VStream &, VClass *&) override;
981 virtual bool SerialiseState (VStream &, VState *&) override;
983 friend class VObjectMapChannel;
987 // ////////////////////////////////////////////////////////////////////////// //
988 class VDemoPlaybackNetConnection : public VNetConnection {
989 public:
990 float NextPacketTime;
991 bool bTimeDemo;
992 VStream *Strm;
993 int td_lastframe; // to meter out one message a frame
994 int td_startframe; // host_framecount at start
995 double td_starttime; // realtime at second frame of timedemo
997 public:
998 VDemoPlaybackNetConnection (VNetContext *, VBasePlayer *, VStream *, bool);
999 virtual ~VDemoPlaybackNetConnection () override;
1001 // VNetConnection interface
1002 virtual int GetRawPacket (void *dest, size_t destSize) override;
1003 virtual void SendMessage (VMessageOut *Msg) override;
1007 // ////////////////////////////////////////////////////////////////////////// //
1008 class VDemoRecordingNetConnection : public VNetConnection {
1009 public:
1010 VDemoRecordingNetConnection (VSocketPublic *, VNetContext *, VBasePlayer *);
1012 // VNetConnection interface
1013 virtual int GetRawPacket (void *dest, size_t destSize) override;
1017 // ////////////////////////////////////////////////////////////////////////// //
1018 class VDemoRecordingSocket : public VSocketPublic {
1019 public:
1020 VDemoRecordingSocket ();
1021 virtual bool IsLocalConnection () const noexcept override;
1022 virtual int GetMessage (void *dest, size_t destSize) override;
1023 virtual int SendMessage (const vuint8 *, vuint32) override;
1027 // ////////////////////////////////////////////////////////////////////////// //
1028 // global access to the low-level networking services
1029 extern VNetworkPublic *GNet;
1030 extern VNetContext *GDemoRecordingContext;
1033 #endif