move to github

This commit is contained in:
Magnus von Wachenfeldt
2015-12-04 10:23:49 +01:00
commit 2a9d8ce416
252 changed files with 45041 additions and 0 deletions

View File

@@ -0,0 +1,10 @@

* The NetBuffer object is gone; instead there are NetOutgoingMessage and NetIncomingMessage objects
* No need to allocate a read buffer before calling ReadMessage

View File

@@ -0,0 +1,113 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<style type="text/css">
body
{
font-family: Verdana, Geneva, Arial, sans-serif;
font-size: small;
margin-left: 20px;
background-color: #dddddd;
}
td
{
font-family: Verdana, Geneva, Arial, sans-serif;
font-size: small;
}
.page
{
width: 700px;
}
.cf
{
font-family: Courier New;
font-size: 10pt;
color: black;
background: white;
padding: 16px;
border: 1px solid black;
}
.cl
{
margin: 0px;
}
.cb1
{
color: green;
}
.cb2
{
color: #2b91af;
}
.cb3
{
color: blue;
}
.cb4
{
color: #a31515;
}
</style>
<title>Peer/server discovery</title>
</head>
<body>
<table>
<tr>
<td class="page">
<h1>Peer/server discovery</h1>
<p>
Peer discovery is the process of clients detecting what servers are available. Discovery requests can be made in two ways;
locally as a broadcast, which will send a signal to all peers on your subnet. Secondly you can contact an ip address directly
and query it if a server is running.
</p>
<p>Responding to discovery requests are done in the same way regardless of how the request is made.</p>
<p>Here's how to do on the client side; ie. the side which makes a request:</p>
<div class="cf">
<pre class="cl"><span class="cb1">// Enable DiscoveryResponse messages</span></pre>
<pre class="cl">config.EnableMessageType(<span class="cb2">NetIncomingMessageType</span>.DiscoveryResponse);</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl"><span class="cb1">// Emit a discovery signal</span></pre>
<pre class="cl">Client.DiscoverLocalPeers(14242);</pre>
</div>
<p>This will send a discovery signal to your subnet; Here's how to receive the signal on the server side, and send a response back to the client:</p>
<div class="cf">
<pre class="cl"><span class="cb1">// Enable DiscoveryRequest messages</span></pre>
<pre class="cl">config.EnableMessageType(<span class="cb2">NetIncomingMessageType</span>.DiscoveryRequest);</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl"><span class="cb1">// Standard message reading loop</span></pre>
<pre class="cl"><span class="cb3">while</span> ((inc = Server.ReadMessage()) != <span class="cb1">null</span>)</pre>
<pre class="cl">{</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; <span class="cb3">switch</span> (inc.MessageType)</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; {</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">case</span> <span class="cb2">NetIncomingMessageType</span>.DiscoveryRequest:</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb1">// Create a response and write some example data to it</span></pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb2">NetOutgoingMessage</span> response = Server.CreateMessage();</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; response.Write(<span class="cb4">&quot;My server name&quot;</span>);</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb1">// Send the response to the sender of the request</span></pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Server.SendDiscoveryResponse(response, inc.SenderEndpoint);</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">break</span>;</pre>
</div>
<p>When the response then reaches the client, you can read the data you wrote on the server:</p>
<div class="cf">
<pre class="cl"><span class="cb1">// Standard message reading loop</span></pre>
<pre class="cl"><span class="cb3">while</span> ((inc = Client.ReadMessage()) != <span class="cb1">null</span>)</pre>
<pre class="cl">{</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; <span class="cb3">switch</span> (inc.MessageType)</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; {</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">case</span> <span class="cb2">NetIncomingMessageType</span>.DiscoveryResponse:</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb2">Console</span>.WriteLine(<span class="cb4">&quot;Found server at &quot;</span> + inc.SenderEndpoint + <span class="cb4">&quot; name: &quot;</span> + inc.ReadString());</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">break</span>;</pre>
</div>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -0,0 +1,22 @@

Improvements over last version of library:
* New delivery type: Reliable sequenced (Lost packets are resent but late arrivals are dropped)
* Disconnects and shutdown requests are now queued properly, so calling shutdown will still send any queued messages before shutting down
* All messages are pooled/recycled for zero garbage
* Reduced CPU usage and lower latencies (in the <1 ms range, but still) due to better socket polling
* All public members of NetPeer/NetConnection are completely thread safe
* Larger number of delivery channels
* More exact roundtrip measurement
* Method serialize entire objects via reflection
* Unique identifier now exists for all peers/connections
* More flexible peer discovery; filters possible and arbitrary data can be sent with response
* Much better protection against malformed messages crashing the app
API enhancements:
* NetPeerConfiguration immutable properties now locked once NetPeer is initialized
* Messages cannot be send twice by accident
* Impossible to confuse sending and receiving buffers since they're different classes
* No more confusion if user should create a buffer or preallocate and reuse

View File

@@ -0,0 +1,17 @@

PER MESSAGE:
7 bits - NetMessageType
1 bit - Is a message fragment?
[8 bits NetMessageLibraryType, if NetMessageType == Library]
[16 bits sequence number, if NetMessageType >= UserSequenced]
8/16 bits - Payload length in bits (variable size ushort)
[16 bits fragments group id, if fragmented]
[16 bits fragments total count, if fragmented]
[16 bits fragment number, if fragmented]
[x - Payload] if length > 0

View File

@@ -0,0 +1,115 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<style type="text/css">
body
{
font-family: Verdana, Geneva, Arial, sans-serif;
font-size: small;
margin-left: 20px;
background-color: #dddddd;
}
td
{
font-family: Verdana, Geneva, Arial, sans-serif;
font-size: small;
}
.cf
{
font-family: Courier New;
font-size: 10pt;
color: black;
background: white;
padding: 16px;
border: 1px solid black;
}
.cl
{
margin: 0px;
}
.cb1
{
color: green;
}
.cb2
{
color: #2b91af;
}
.cb3
{
color: blue;
}
.cb4
{
color: #a31515;
}
</style>
<title>Lidgren tutorial</title>
</head>
<body>
<table>
<tr>
<td width="700">
<h1>Simulating bad network conditions</h1>
<p>
On the internet, your packets are likely to run in to all kinds of trouble. They will be delayed and lost and they might even arrive multiple times at the destination. Lidgren has a few option to simulate how your application or game will react when this happens.<br />
They are all configured using the NetPeerConfiguration class - these properties exists:</p>
<p>
<div class="cf">
<table>
<tr>
<td valign="top">
<b>SimulatedLoss</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
This is a float which simulates lost packets. A value of 0 will disable this feature, a value of 0.5f will make half of your sent packets disappear, chosen randomly. Note that packets may contain several messages - this is the amount of packets lost.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td valign="top">
<b>SimulatedDuplicatesChance</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
This is a float which determines the chance that a packet will be duplicated at the destination. 0 means no packets will be duplicated, 0.5f means that on average, every other packet will be duplicated.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td valign="top">
<b>SimulatedMinimumLatency</b><br />
<b>SimulatedRandomLatency</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
These two properties control simulating delay of packets in seconds (not milliseconds, use 0.05 for 50 ms of lag). They work on top of the actual network delay and the total delay will be:<br />
Actual one way latency + SimulatedMinimumLatency + [Randomly per packet 0 to SimulatedRandomLatency seconds]
</td>
</tr>
</table>
</div>
<p>It's recommended to assume symmetric condtions and configure server and client with the same simulation settings.</p>
<p>Simulating bad network conditions only works in DEBUG builds.</p>
</td>
</tr>
</table>
</body>
</html>

View File

@@ -0,0 +1,17 @@

Completed features:
* Message coalescing
* Peer, connection statistics
* Lag, loss and duplication simulation for testing
* Connection approval
* Throttling
* Clock synchronization to detect jitter per packet (NetTime.RemoteNow)
* Peer discovery
* Message fragmentation
Missing features:
* Receipts 25% done, need design
* More realistic lag/loss (lumpy)
* Detect estimated packet loss
* More advanced ack packet

View File

@@ -0,0 +1,206 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<style type="text/css">
body
{
font-family: Verdana, Geneva, Arial, sans-serif;
font-size: small;
margin-left: 20px;
background-color: #dddddd;
}
td
{
font-family: Verdana, Geneva, Arial, sans-serif;
font-size: small;
}
.cf
{
font-family: Courier New;
font-size: 10pt;
color: black;
background: white;
padding: 16px;
border: 1px solid black;
}
.cl
{
margin: 0px;
}
.cb1
{
color: green;
}
.cb2
{
color: #2b91af;
}
.cb3
{
color: blue;
}
.cb4
{
color: #a31515;
}
</style>
<title>Lidgren basics tutorial</title>
</head>
<body>
<table>
<tr>
<td width="700">
<h1>
Lidgren basics</h1>
<p>
Lidgren network library is all about messages. There are two types of messages:</p>
<li>Library messages telling you things like a peer has connected or diagnostics messages (warnings, errors) when unexpected things happen.</li>
<li>Data messages which is data sent from a remote (connected or unconnected) peer.</li>
<p>
The base class for establishing connections, receiving and sending message are the NetPeer class. Using it you can make a peer-to-peer network, but if you are creating a server/client topology there are special classes called NetServer and NetClient. They inherit NetPeer but sets some defaults and includes some helper methods/properties.</p>
<p>
Here's how to set up a NetServer:</p>
<div class="cf">
<pre class="cl"><span class="cb2">NetPeerConfiguration</span> config = <span class="cb3">new</span> <span class="cb2">NetPeerConfiguration</span>(<span class="cb4">&quot;MyExampleName&quot;</span>);</pre>
<pre class="cl">config.Port = 14242;</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl"><span class="cb2">NetServer</span> server = <span class="cb3">new</span> <span class="cb2">NetServer</span>(config);</pre>
<pre class="cl">server.Start();</pre>
</div>
<p>
The code above first creates a configuration. It has lots of properties you can change, but the default values should be pretty good for most applications. The string you provide in the constructor (MyExampleName) is an identifier to distinquish it from other applications using the lidgren library. Just make sure you use the same string in both server and client - or you will be unable to communicate between them.</p>
<p>
Secondly we've set the local port the server should listen to. This is the port number we tell the client(s) what port number to connect to. The local port can be set for a client too, but it's not needed and not recommended.</p>
<p>
Thirdly we create our server object and fourth we Start() it. Starting the server will create a new network thread and bind to a socket and start listening for connections.</p>
<p>
Early on we spoke about messages; now is the time to start receiving and sending some. Here's a code snippet for receiving messages:</p>
<div class="cf">
<pre class="cl"><span class="cb2">NetIncomingMessage</span> msg;</pre>
<pre class="cl"><span class="cb3">while</span> ((msg = server.ReadMessage()) != <span class="cb3">null</span>)</pre>
<pre class="cl">{</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; <span class="cb3">switch</span> (msg.MessageType)</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; {</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">case</span> <span class="cb2">NetIncomingMessageType</span>.VerboseDebugMessage:</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">case</span> <span class="cb2">NetIncomingMessageType</span>.DebugMessage:</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">case</span> <span class="cb2">NetIncomingMessageType</span>.WarningMessage:</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">case</span> <span class="cb2">NetIncomingMessageType</span>.ErrorMessage:</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb2">Console</span>.WriteLine(msg.ReadString());</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">break</span>;</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">default</span>:</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb2">Console</span>.WriteLine(<span class="cb4">&quot;Unhandled type: &quot;</span> + msg.MessageType);</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span class="cb3">break</span>;</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; }</pre>
<pre class="cl">&nbsp;&nbsp;&nbsp; server.Recycle(msg);</pre>
<pre class="cl">}</pre>
</div>
<p>
So, lets dissect the above code. First we declare a NetIncomingMessage, which is the type of incoming messages. Then we read a message and handles it, looping back as long as there are messages to fetch. For each message we find, we switch on sometime called MessageType - it's a description what the message contains. In this code example we only catch messages of type VerboseDebugMessage, DebugMessage, WarningMessage and ErrorMessage. All those four types are emitted by the library to inform about various events. They all contains a single string, so we use the method ReadString() to extract a copy of that string and print it in the console.</p>
<p>
Reading data will increment the internal message pointer so you can read subsequent data using the Read*() methods.</p>
<p>
For all other message type we just print that it's currently unhandled.</p>
<p>
Finally, we recycle the message after we're done with it - this will enable the library to reuse the object and create less garbage.</p>
<p>
Sending messages are even easier:</p>
<div class="cf">
<pre class="cl"><span class="cb2">NetOutgoingMessage</span> sendMsg = server.CreateMessage();</pre>
<pre class="cl">sendMsg.Write(<span class="cb4">&quot;Hello&quot;</span>);</pre>
<pre class="cl">sendMsg.Write(42);</pre>
<pre class="cl">&nbsp;</pre>
<pre class="cl">server.SendMessage(sendMsg, recipient, <span class="cb2">NetDeliveryMethod</span>.ReliableOrdered);</pre>
</div>
<p>
The above code first creates a new message, or uses a recycled message, which is why it's not possible to just create a message using new(). It then writes a string ("Hello") and an integer (System.Int32, 4 bytes in size) to the message.</p>
<p>
Then the message is sent using the SendMessage() method. The first argument is the message to send, the second argument is the recipient connection - which we'll not go into detail about just yet - and the third argument are HOW to deliver the message, or rather how to behave if network conditions are bad and a packet gets lost, duplicated or reordered.</p>
<p>
There are five delivery methods available:</p>
<div class="cf">
<table>
<tr>
<td valign="top">
<b>Unreliable</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
This is just UDP. Messages can be lost, received more than once and messages sent after other messages may be received before them.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td valign="top">
<b>UnreliableSequenced</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
Using this delivery method messages can still be lost; but you're protected against duplicated messages and if a message arrives late; that is, if a message sent after this one has already been received - it will be dropped. This means you will never receive "older" data than what you already have received.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td valign="top">
<b>ReliableUnordered</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
This delivery method ensures that every message sent will be received eventually. It does not however guarantee what order they will be received; late messages may be delivered before older ones.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td valign="top">
<b>ReliableSequenced</b>
</td>
<td>
&nbsp;
</td>
<td valign="top">
This delivery method is similar to UnreliableSequenced; except that is guarantees that SOME messages will be received - if you only send one message - it will be received. If you sent two messages quickly, and they get reordered in transit, only the newest message will be received - but at least ONE of them will be received guaranteed.
</td>
</tr>
<tr>
<td colspan="3">
&nbsp;
</td>
</tr>
<tr>
<td valign="top"><b>ReliableOrdered</b></td>
<td>&nbsp;</td>
<td valign="top">
This delivery method guarantees that messages will always be received in the exact order they were sent.
</td>
</tr>
</table>
</div>
<p>
Here's how to read and decode the message above:</p>
<div class="cf">
<pre class="cl"><span class="cb2">NetIncomingMessage</span> incMsg = server.ReadMessage();</pre>
<pre class="cl"><span class="cb3">string</span> str = incMsg.ReadString();</pre>
<pre class="cl"><span class="cb3">int</span> a = incMsg.ReadInt32();</pre>
</div>
</td>
</tr>
</table>
</body>
</html>