1 //**************************************************************************
3 //** ## ## ## ## ## #### #### ### ###
4 //** ## ## ## ## ## ## ## ## ## ## #### ####
5 //** ## ## ## ## ## ## ## ## ## ## ## ## ## ##
6 //** ## ## ######## ## ## ## ## ## ## ## ### ##
7 //** ### ## ## ### ## ## ## ## ## ##
8 //** # ## ## # #### #### ## ##
10 //** Copyright (C) 1999-2006 Jānis Legzdiņš
11 //** Copyright (C) 2018-2023 Ketmar Dark
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.
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.
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/>.
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 // ////////////////////////////////////////////////////////////////////////// //
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
;
50 //typedef chacha20_ctx ChaCha20Ctx;
54 ChaCha20NonceSize
= 4,
55 ChaCha20CheckSumSize
= 4,
56 ChaCha20HeaderSize
= ChaCha20KeySize
+ChaCha20NonceSize
+ChaCha20CheckSumSize
,
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
83 static int DecryptInfoPacket (vuint8 key
[ChaCha20KeySize
], void *destbuf
, const void *srcbuf
, int srclen
) noexcept
;
91 NET_PROTOCOL_VERSION_HI
= 7,
92 NET_PROTOCOL_VERSION_LO
= 17,
97 MAX_RELIABLE_BUFFER
= 128,
112 // separate messages from packets, so we can fragment and reassemble one message with several packets
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
,
128 CHANIDX_ThinkersStart
,
132 // used in level channel
133 struct VNetClientServerInfo
{
143 // network message classes
146 class VNetConnection
;
149 // ////////////////////////////////////////////////////////////////////////// //
150 // public interface of a network socket
151 class VSocketPublic
: public VInterface
{
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
191 TArray
<VStr
> WadFiles
;
194 vint32 DeathMatch
; // dm mode
196 Flag_GoodProtocol
= 1u<<0,
197 Flag_GoodWadList
= 1u<<1,
198 Flag_PasswordProtected
= 1u<<2,
204 // ////////////////////////////////////////////////////////////////////////// //
205 // structure returned to progs
207 enum { SF_InProgress
= 0x01 };
215 // ////////////////////////////////////////////////////////////////////////// //
216 // public networking driver interface
217 class VNetworkPublic
: public VInterface
{
219 // statistic counters
220 int UnreliableMessagesSent
;
221 int UnreliableMessagesReceived
;
225 int receivedDuplicateCount
;
226 int shortPacketCount
;
227 int droppedDatagrams
;
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
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
;
267 static VNetworkPublic
*Create ();
271 // ////////////////////////////////////////////////////////////////////////// //
272 // base class for network channels that are responsible for sending and receiving of the data.
275 VNetConnection
*Connection
;
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`)
290 inline static const char *GetChanTypeName (vuint8 type
) noexcept
{
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 ();
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
;
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
{
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
{
408 struct VBodyQueueTrInfo
{
417 rep_sector_t
*Sectors
;
418 rep_polyobj_t
*PolyObjs
;
419 TArray
<VCameraTextureInfo
> CameraTextures
;
420 TArray
<TArray
<VTextureTranslation::VTransCmd
> > Translations
;
421 TArray
<VBodyQueueTrInfo
> BodyQueueTrans
;
424 VNetClientServerInfo csi
;
426 int StaticLightsNext
;
428 // build by `BuildUpdateSets()`
429 TMapNC
<vint32
, bool> UpdatedLines
;
430 TMapNC
<vint32
, bool> UpdatedSides
;
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
);
472 PhaseWaitingMapLoaded
,
479 double MapLoadingStartTime
;
482 void SendServerInfo ();
483 void WaitForMapLoaded ();
484 void SendStaticLights ();
485 void SendPreRender ();
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 ();
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
{
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
520 // set by the client when it gets `Origin` update
522 vuint32 LastUpdateFrame
; // see `UpdateFrameCounter` in VNetConnection
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
*);
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
{
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
;
557 VField
*GameTimeField
;
558 // set at the client side after we got `MO.Origin`
559 // reset on player reset, or when MO disappears
563 // sets flags, calls methods, etc.
564 void CheckPlayerMO ();
567 VPlayerChannel (VNetConnection
*, vint32
, vuint8
= true);
568 virtual ~VPlayerChannel () override
;
570 void SetPlayer (VBasePlayer
*);
571 void EvalCondValues (VObject
*, VClass
*, vuint8
*);
574 // call this when new level is loaded
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
{
590 bool needOpenMessage
; // valid only for local channel (sender)
591 // names are compressed, because we usually have a lot (around 400kb)
593 vint32 cprBufferSize
;
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
;
602 vuint8 serverReplicationHash
[K8VNET_DIGEST_SIZE
];
605 void UpdateSendPBar ();
606 void UpdateRecvPBar (bool forced
);
608 void ClearCprBuffer ();
609 void CompressNames ();
610 void DecompressNames ();
613 void BuildNetFieldsHash (vuint8 hash
[K8VNET_DIGEST_SIZE
]);
615 // this sends new names
618 void LiveParse (VMessageIn
&Msg
);
621 VObjectMapChannel (VNetConnection
*AConnection
, vint32 AIndex
, vuint8 AOpenedLocally
);
622 virtual ~VObjectMapChannel () override
;
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 // ////////////////////////////////////////////////////////////////////////// //
643 // ////////////////////////////////////////////////////////////////////////// //
644 // network connection class, responsible for sending and receiving network
645 // packets and managing of channels.
646 class VNetConnection
{
648 VSocketPublic
*NetCon
;
651 struct ThinkerSortInfo
{
655 // everything that is behind this is behind our back
658 inline ThinkerSortInfo () noexcept
{}
659 ThinkerSortInfo (VBasePlayer
*Owner
) noexcept
;
665 LNFO_SENT_INPROGRESS
, // we're still have something to send
666 LNFO_SENT_COMPLETE
, // we're sending static lights
670 VNetworkPublic
*Driver
;
671 VNetContext
*Context
;
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
;
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
;
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?
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
;
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
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
;
738 VField
*DataGameTimeField
;
746 // hash tables, to speed up various updates
747 // built with fat PVS
748 TMapNC
<vint32
, bool> UpdatedSubsectors
;
749 TMapNC
<vint32
, bool> UpdatedSectors
;
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
);
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
); }
778 // WARNING! this can change channel list!
779 void AckEverythingEverywhere ();
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
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);
846 inline void PutOneAckForced (vuint32 ackId
) { const int res
= PutOneAck(ackId
, true); vassert(res
== 0); }
847 // resend all acks from `AcksToResend`, and clears `AcksToResend`
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
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
871 void SendServerInfo ();
872 void LoadedNewLevel ();
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 ();
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
);
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
906 VField
*RemoteRoleField
;
911 VNetConnection
*ServerConnection
; // non-nullptr for clients (only)
912 TArray
<VNetConnection
*> ClientConnections
; // known clients for servers
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
*);
925 void KeepaliveTick ();
929 // ////////////////////////////////////////////////////////////////////////// //
930 // a client side network context
931 class VClientNetContext
: public VNetContext
{
933 // VNetContext interface
934 virtual VLevel
*GetLevel () override
;
938 // ////////////////////////////////////////////////////////////////////////// //
939 // server side network context
940 class VServerNetContext
: public VNetContext
{
942 // VNetContext interface
943 virtual VLevel
*GetLevel () override
;
947 // ////////////////////////////////////////////////////////////////////////// //
948 class VNetObjectsMap
: public VNetObjectsMapBase
{
950 TArray
<VName
> NameLookup
;
953 TArray
<VClass
*> ClassLookup
;
954 TMap
<VClass
*, vuint32
> ClassMap
;
957 VNetConnection
*Connection
;
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
);
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
{
990 float NextPacketTime
;
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
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
{
1010 VDemoRecordingNetConnection (VSocketPublic
*, VNetContext
*, VBasePlayer
*);
1012 // VNetConnection interface
1013 virtual int GetRawPacket (void *dest
, size_t destSize
) override
;
1017 // ////////////////////////////////////////////////////////////////////////// //
1018 class VDemoRecordingSocket
: public VSocketPublic
{
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
;