Last active
July 20, 2020 03:46
-
-
Save lazalong/0710e58e890f9636c42d28816008c156 to your computer and use it in GitHub Desktop.
C# version of NetDynamics (https://github.com/nxrighthere/NetDynamics)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/****************************** Module Header ******************************\ | |
* Module Name: NetDynamics_CS.cs | |
* Project: NetDynamics_CS | |
* Copyright (c) 2020 Steven 'lazalong' Gay | |
* | |
* C# version of https://github.com/nxrighthere/NetDynamics | |
* | |
* Data-oriented networking playground for the reliable UDP transports | |
* | |
* This source is subject to the Microsoft Public License. | |
* See https://opensource.org/licenses/MS-PL | |
* All other rights reserved. | |
* | |
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, | |
* EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED | |
* WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. | |
\***************************************************************************/ | |
using System; | |
using Raylib_cs; | |
using ENet; | |
using System.Numerics; | |
using NetStack.Serialization; | |
struct Settings | |
{ | |
public uint resolutionWidth; | |
public uint resolutionHeight; | |
public uint framerateLimit; | |
public ushort vsync; | |
public ushort transport; | |
public string ip; | |
public ushort port; | |
public float sendRate; | |
public Int32 redundantBytes; | |
public int maxClients; | |
public int maxChannels; | |
public uint incomingBandwith; | |
public uint outgoingBandwith; | |
public int bufferSize; | |
public int maxEntities; | |
public int nbEntitiesSpawn; | |
public float maxMovementSpeed; | |
public void SetDefault() | |
{ | |
resolutionWidth = 640; | |
resolutionHeight = 480; | |
framerateLimit = 60; | |
vsync = 0; | |
transport = 1; | |
ip = "::1"; | |
port = 5000; | |
sendRate = 20; | |
redundantBytes = 0; | |
// ENet | |
maxClients = 32; | |
maxChannels = 0; | |
incomingBandwith = 0; | |
outgoingBandwith = 0; | |
bufferSize = 1024 * 1024; | |
maxEntities = 100000; | |
nbEntitiesSpawn = 10; | |
maxMovementSpeed = 80f; | |
} | |
}; | |
internal unsafe struct Buffer | |
{ | |
public const int bufferSize = 1024 * 1024; | |
public fixed byte redundantBuffer[bufferSize]; | |
} | |
enum OpCode | |
{ | |
NONE = 0, | |
SPAWN, | |
MOVE, | |
DESTROY | |
} | |
static class Program | |
{ | |
static Settings settings; | |
static int nbEntities; | |
static float[] position_x; | |
static float[] position_y; | |
static float[] speed_x; | |
static float[] speed_y; | |
static float[] destination_x; | |
static float[] destination_y; | |
static Color[] color; // hexadecimal's RGB color value convverted to long i.e. 9C4A4A = 10242634 | |
// white = 16777215 = xFFFFFF black = 0 | |
// https://answers.unity.com/questions/812240/convert-hex-int-to-colorcolor32.html | |
static byte[] data = new byte[128]; | |
static Random rand = new Random(); | |
#if SERVER | |
static float sendTime = 0.0f; | |
#endif | |
public static void Main() | |
{ | |
Buffer buffer = default; | |
Peer peer = default; | |
Texture2D texture; | |
Font font = default; | |
string status = "Not initialised"; | |
int fps = 0; | |
int counter = 0; | |
int refreshRate = 20; | |
ENet.Event netEvent = default; | |
settings.SetDefault(); | |
// -------- Set Window ---------- | |
string title = GetTitle(); | |
Console.WriteLine("---- " + title + " ----"); | |
SetRaylib(title, ref font); | |
// ------ Serialisation ------------- | |
// LATER: add own allocator, binn type | |
if (settings.redundantBytes > 0) | |
{ | |
if (settings.redundantBytes > Buffer.bufferSize) // ? sizeof(buffer.redundantBuffer)) | |
{ | |
Console.WriteLine("RedundantBytes exceeds buffer: scaling back to " + Buffer.bufferSize); | |
settings.redundantBytes = Buffer.bufferSize; | |
} | |
for (int i = 0; i < settings.redundantBytes; i++) | |
{ | |
unsafe | |
{ | |
buffer.redundantBuffer[i] = 0; // ??? i % sizeof(uint8_t); isn't this alwyas 0? | |
//Console.WriteLine(i % 8); | |
} | |
} | |
} | |
#region --------- Set Network ----------- | |
if (!Library.Initialize()) // TODO alloc callbacks | |
{ | |
Console.WriteLine("ENet library initialisation failed"); | |
return; | |
} | |
Address address = new Address(); | |
address.Port = settings.port; | |
Host host = new Host(); | |
#if SERVER | |
host.Create(address, settings.maxClients, settings.maxChannels, settings.incomingBandwith, | |
settings.outgoingBandwith, settings.bufferSize); | |
status = "Server listening"; | |
#else | |
host.Create(null, 1, settings.maxChannels, settings.incomingBandwith, | |
settings.outgoingBandwith, settings.bufferSize); | |
if (!address.SetIP(settings.ip)) | |
{ | |
Console.WriteLine("Couldn't set ip"); | |
return; | |
} | |
peer = host.Connect(address, settings.maxChannels, 0); | |
status = peer.State.ToString(); | |
#endif | |
#endregion | |
#region ----------- Set Data ------------------- | |
nbEntities = 0; | |
position_x = new float[settings.maxEntities]; | |
position_y = new float[settings.maxEntities]; | |
speed_x = new float[settings.maxEntities]; | |
speed_y = new float[settings.maxEntities]; | |
destination_x = new float[settings.maxEntities]; | |
destination_y = new float[settings.maxEntities]; | |
color = new Color[settings.maxEntities]; | |
texture = Raylib.LoadTexture("neon_circle.png"); | |
#if CLIENT | |
destination_x = new float[settings.maxEntities]; | |
destination_y = new float[settings.maxEntities]; | |
uint rtt = 0; | |
#else | |
float sendInterval = 1.0f / settings.sendRate; | |
#endif | |
#endregion | |
// ---------- MAIN LOOP ---------------------- | |
while (!Raylib.WindowShouldClose()) | |
{ | |
float deltaTime = Raylib.GetFrameTime(); | |
#region ---------- Systems ---------- | |
bool polled = false; | |
while (!polled) | |
{ | |
if (host.CheckEvents(out netEvent) <= 0) | |
{ | |
if (host.Service(0, out netEvent) <= 0) | |
break; | |
polled = true; | |
} | |
switch (netEvent.Type) | |
{ | |
case EventType.None: | |
break; | |
case EventType.Connect: | |
#if SERVER | |
netEvent.Peer.PingInterval(250); | |
for (int i = 0; i < nbEntities; i++) | |
{ | |
// Test send opcode | |
//Packet packet = default; | |
//// Sends an int32, to read use: int opcode = Marshal.ReadInt32(netEvent.Packet.Data); | |
//data[0] = (byte)(i & 0x000000FF); | |
//data[1] = (byte)((i & 0x0000FF00) >> 8); | |
//data[2] = (byte)((i & 0x00FF0000) >> 16); | |
//data[3] = (byte)((i & 0xFF000000) >> 24); | |
//packet.Create(data, 4); | |
//netEvent.Peer.Send(0, ref packet); | |
Peer peer2 = netEvent.Peer; | |
SendMsg(ref peer2, OpCode.SPAWN, i); | |
} | |
#else | |
status = "Connected"; | |
#endif | |
break; | |
case EventType.Disconnect: | |
#if SERVER | |
Console.WriteLine("Disconnection of peer " + netEvent.Peer.ID + " ip= " + netEvent.Peer.IP); | |
#else | |
status = "Disconnected"; | |
EntityFlush(); // ! | |
#endif | |
break; | |
case EventType.Receive: | |
// Test receive opcode | |
//int opcode = Marshal.ReadInt32(netEvent.Packet.Data); | |
//Console.WriteLine("Opcode: " + opcode); | |
int id = ReceiveMsg(ref netEvent); | |
#if SERVER | |
if (id == (int) OpCode.SPAWN) | |
{ | |
// Send the new nbEntitiesSpawn's entities ) | |
for (int i = nbEntities - settings.nbEntitiesSpawn; i < nbEntities; i++) | |
{ | |
SendToAll(ref host, OpCode.SPAWN, i); | |
} | |
} | |
else if (id == (int) OpCode.DESTROY) | |
{ | |
int nb = nbEntities - settings.nbEntitiesSpawn; | |
if (nb < 0) | |
nb = 0; | |
nbEntities = nb; | |
SendToAll(ref host, OpCode.DESTROY, 0); | |
} | |
#endif | |
netEvent.Packet.Dispose(); | |
break; | |
case EventType.Timeout: | |
#if SERVER | |
Console.WriteLine("Timeout from " + netEvent.Peer.ID + " ip= " + netEvent.Peer.IP); | |
#endif | |
break; | |
} | |
} | |
#if CLIENT | |
rtt = peer.RoundTripTime; | |
#endif | |
#endregion | |
#region ---------- Timer ---------- | |
#if SERVER | |
sendTime += deltaTime; | |
#endif | |
#endregion | |
#region ---------- Input Mgr = Spawn ---------- | |
if (Raylib.IsMouseButtonDown(MouseButton.MOUSE_LEFT_BUTTON)) | |
{ | |
#if SERVER | |
Vector2 pos = Raylib.GetMousePosition(); | |
Entity_Spawn(pos.X, pos.Y, settings.nbEntitiesSpawn); | |
if (host.PeersCount > 0) | |
{ | |
host.Flush(); // <---------- why??? | |
for (int i = nbEntities - settings.nbEntitiesSpawn; i < nbEntities; i++) | |
{ | |
SendToAll(ref host, OpCode.SPAWN, i); | |
} | |
} | |
#else | |
if (peer.State == PeerState.Connected) | |
{ | |
host.Flush(); // <---------- why?? | |
SendMsg(ref peer, OpCode.SPAWN, 0); | |
} | |
#endif | |
} | |
#endregion | |
#region ---------- Move ---------- | |
if (nbEntities>0) | |
{ | |
#if SERVER | |
MoveEntity(deltaTime); | |
if (sendTime >= sendInterval) | |
{ | |
sendTime -= sendInterval; | |
if (host.PeersCount > 0) | |
{ | |
host.Flush(); // <---------- why??? | |
for (int i = 0; i < nbEntities; i++) | |
{ | |
SendToAll(ref host, OpCode.MOVE, i); | |
} | |
} | |
} | |
#else | |
for (int i = 0; i < nbEntities; i++) | |
{ | |
// needed? if (destination[i].x == 0.0f && destination[i].y == 0.0f) | |
// continue; | |
MoveEntity(i, deltaTime); | |
} | |
#endif | |
} | |
#endregion | |
#region ---------- Destroy ---------- | |
if (nbEntities > 0) | |
{ | |
if (Raylib.IsMouseButtonDown(MouseButton.MOUSE_RIGHT_BUTTON)) | |
{ | |
#if SERVER | |
int nb = nbEntities - settings.nbEntitiesSpawn; | |
if (nb < 0) | |
nb = 0; | |
nbEntities = nb; | |
SendToAll(ref host, OpCode.DESTROY, 0); | |
#else | |
host.Flush(); // <---------- why?? | |
SendMsg(ref peer, OpCode.DESTROY, 0); | |
#endif | |
} | |
} | |
#endregion | |
#region ---------- Render ---------- | |
Raylib.BeginDrawing(); | |
Raylib.ClearBackground(Color.LIGHTGRAY); | |
// if (error != null) | |
// Raylib.DrawTextEx(font, "Error " + error, new System.Numerics.Vector2(12, 30), 20, 0, Color.WHITE); | |
// else | |
// ------- Render Entities ---------------- | |
if (nbEntities > 0) | |
{ | |
for (int i = 0; i < nbEntities; i++) | |
{ | |
Raylib.DrawTexture(texture, (int)position_x[i], (int)position_y[i], color[i]); | |
} | |
} | |
// ------ Render Stats ------------ | |
if (counter < refreshRate) | |
{ | |
counter++; | |
} | |
else | |
{ | |
fps = Raylib.GetFPS(); | |
refreshRate = fps; | |
counter = 0; | |
} | |
Raylib.DrawText("NetDynamics C# - " + title, 10, 10, 20, Color.WHITE); | |
Raylib.DrawText("FPS " + fps, 10, 35, 20, Color.BLACK); | |
Raylib.DrawText("Entities " + nbEntities, 10, 70, 20, Color.BLACK); | |
Raylib.DrawText("Status " + status, 10, 100, 20, Color.BLACK); | |
#if SERVER | |
Raylib.DrawText("Nb Peers " + host.PeersCount, 10, 125, 20, Color.BLACK); | |
Raylib.DrawText("Send Rate " + settings.sendRate, 10, 150, 20, Color.BLACK); | |
float mps = host.PeersCount * nbEntities * settings.sendRate; | |
Raylib.DrawText("MSG Per Sec: Target " + mps, 10, 175, 20, Color.BLACK); | |
//Raylib.DrawText("MSG Per Sec: Measures " + fps, 10, 200, 20, Color.BLACK); | |
#else | |
Raylib.DrawText("RTT " + peer.RoundTripTime, 10, 125, 20, Color.BLACK); | |
#endif | |
#if CLIENT | |
Raylib.DrawText("Byte Sent " + peer.BytesSent.ToString(), 10, 150, 20, Color.BLACK); | |
Raylib.DrawText("Packet Sent " + peer.PacketsSent.ToString(), 10, 175, 20, Color.BLACK); | |
Raylib.DrawText("Byte Received " + peer.BytesReceived.ToString(), 10, 200, 20, Color.BLACK); | |
Raylib.DrawText("Packet Lost " + peer.PacketsLost.ToString(), 10, 225, 20, Color.BLACK); | |
#else | |
Raylib.DrawText("Byte Sent " + host.BytesSent.ToString(), 10, 225, 20, Color.BLACK); | |
Raylib.DrawText("Packet Sent " + host.PacketsSent.ToString(), 10, 250, 20, Color.BLACK); | |
Raylib.DrawText("Byte Received " + host.BytesReceived.ToString(), 10, 275, 20, Color.BLACK); | |
#endif | |
Raylib.EndDrawing(); | |
#endregion // Render | |
} // main loop | |
#region -------- Closure ---------------- | |
if (host != null && host.IsSet) | |
{ | |
#if CLIENT | |
peer.DisconnectNow(0); | |
#else | |
for (int i = 0; i < host.PeersCount; i++) | |
{ | |
// TODO peers[i].disconnectNow(0); | |
} | |
#endif | |
host.Flush(); | |
host.Dispose(); | |
} | |
Library.Deinitialize(); | |
Raylib.UnloadFont(font); | |
Raylib.UnloadTexture(texture); | |
Raylib.CloseWindow(); | |
#endregion | |
// Console.WriteLine("\nType key to quit"); | |
// Console.ReadKey(); | |
} | |
static void SetRaylib(string title, ref Font font) | |
{ | |
if (settings.vsync > 0) | |
Raylib.SetConfigFlags(ConfigFlag.FLAG_VSYNC_HINT); | |
Raylib.InitWindow((int)settings.resolutionWidth, (int)settings.resolutionHeight, title); | |
Raylib.SetTargetFPS((int)settings.framerateLimit); | |
font = Raylib.LoadFontEx("share_tech.ttf", 25, null, 0); // ?? why are both last param empty... see later. | |
Raylib.SetTextureFilter(font.texture, TextureFilterMode.FILTER_POINT); // TODO I don't see it used... | |
} | |
static string GetTitle() | |
{ | |
string str; | |
#if CLIENT | |
#if DEBUG | |
str = "Debug Client"; | |
#else | |
str = "Release Client"; | |
#endif | |
#elif SERVER | |
#if DEBUG | |
str = "Debug Server"; | |
#else | |
str = "Release Server"; | |
#endif | |
#else | |
Console.WriteLine("No SERVER or CLIENT preprocessor. Aborting"); | |
throw new Exception("No SERVER or CLIENT preprocessor. Aborting"); | |
#endif | |
return str; | |
} | |
static void EntityFlush() | |
{ | |
position_x[0] = 0; | |
position_y[0] = 0; | |
speed_x[0] = 0; | |
speed_y[0] = 0; | |
destination_x[0] = 0; | |
destination_y[0] = 0; | |
} | |
static class BufferPool | |
{ | |
[ThreadStatic] | |
private static BitBuffer bitBuffer; | |
public static BitBuffer GetBitBuffer() | |
{ | |
if (bitBuffer == null) | |
bitBuffer = new BitBuffer(1024); | |
return bitBuffer; | |
} | |
} | |
static void SendMsg(ref Peer peer, OpCode opcode, int id) | |
{ | |
bool reliable = false; | |
Packet packet = default(Packet); | |
BitBuffer buffer = BufferPool.GetBitBuffer(); | |
buffer.Clear(); | |
Span<byte> span = new Span<byte>(data); | |
if (opcode == OpCode.SPAWN) | |
{ | |
reliable = true; | |
buffer.AddInt((int)opcode); | |
#if SERVER | |
buffer.AddInt(id) | |
.AddLong(((long)(position_x[id] * 100000f))) | |
.AddLong(((long)(position_y[id] * 100000f))) | |
.AddLong(((long)(speed_x[id] * 100000f))) | |
.AddLong(((long)(speed_y[id] * 100000f))) | |
.AddByte(color[id].r) | |
.AddByte(color[id].g) | |
.AddByte(color[id].b) | |
.AddByte(color[id].a) | |
.ToSpan(ref span); | |
//Console.WriteLine(">>>>>>>>> x " + position_x[id] + " " + (long)(position_x[id] * 100000f)); | |
#else | |
Vector2 mousePosition = Raylib.GetMousePosition(); | |
//Console.WriteLine(" Mouse " + mousePosition.X + " " + mousePosition.Y); | |
//Console.WriteLine(" " + mousePosition.X * 100000f + " " + mousePosition.Y * 100000f); | |
//Console.WriteLine(" " + (long)(mousePosition.X * 100000f) + " " + (long)(mousePosition.Y * 100000f)); | |
buffer.AddLong((long)(mousePosition.X * 100000f)) | |
.AddLong((long)(mousePosition.Y * 100000f)); | |
#endif | |
} | |
else if (opcode == OpCode.DESTROY) | |
{ | |
reliable = true; | |
buffer.AddInt((int)opcode); | |
} | |
else | |
{ | |
return; | |
} | |
if (settings.redundantBytes > 0) | |
{ | |
for (int i = 0; i < settings.redundantBytes; i++) | |
{ | |
buffer.AddByte(0); | |
} | |
} | |
buffer.ToSpan(ref span); | |
data = span.ToArray(); | |
packet.Create(data, buffer.Length, reliable ? PacketFlags.Reliable : PacketFlags.None); | |
peer.Send(0, ref packet); | |
} | |
static int ReceiveMsg(ref ENet.Event netEvent) | |
{ | |
ReadOnlySpan<byte> span; | |
unsafe | |
{ | |
span = new ReadOnlySpan<byte>((byte*)netEvent.Packet.Data, netEvent.Packet.Length); | |
} | |
BitBuffer bitBuffer = BufferPool.GetBitBuffer(); | |
bitBuffer.Clear(); | |
bitBuffer.FromSpan(ref span, netEvent.Packet.Length); // LATER opcode as short hence 2 | |
int opcode = bitBuffer.ReadInt(); | |
if (opcode == (int)OpCode.NONE) | |
{ | |
Console.WriteLine("Received empty msg..."); | |
return 0; | |
} | |
else if (opcode == (int)OpCode.SPAWN) | |
{ | |
#if SERVER | |
float px = ((float)bitBuffer.ReadLong()) / 100000f; | |
float py = ((float)bitBuffer.ReadLong()) / 100000f; | |
//Console.WriteLine("px " + px + " py " + py); | |
Entity_Spawn(px, py, settings.nbEntitiesSpawn); | |
// entity_spawn((Vector2) { binn_list_float(data, 2), binn_list_float(data, 3) }, NET_MAX_ENTITY_SPAWN); | |
#else | |
int id = bitBuffer.ReadInt(); | |
float px = ((float)bitBuffer.ReadLong()) / 100000f; | |
float py = ((float)bitBuffer.ReadLong()) / 100000f; | |
float sx = ((float)bitBuffer.ReadLong()) / 100000f; | |
float sy = ((float)bitBuffer.ReadLong()) / 100000f; | |
Color col = new Color( | |
bitBuffer.ReadByte(), | |
bitBuffer.ReadByte(), | |
bitBuffer.ReadByte(), | |
bitBuffer.ReadByte()); | |
Entity_Spawn(id, px, py, sx, sy, col); | |
// entity_spawn((Entity)binn_list_uint32(data, 2), (Vector2) { binn_list_float(data, 3), binn_list_float(data, 4) }, (Vector2) { binn_list_float(data, 5), binn_list_float(data, 6) }, (Color) { binn_list_uint8(data, 7), binn_list_uint8(data, 8), binn_list_uint8(data, 9), 255 }); | |
#endif | |
} | |
else if (opcode == (int)OpCode.MOVE) | |
{ | |
#if CLIENT | |
int id = bitBuffer.ReadInt(); | |
float px = ((float)bitBuffer.ReadLong()) / 100000f; | |
float py = ((float)bitBuffer.ReadLong()) / 100000f; | |
float sx = ((float)bitBuffer.ReadLong()) / 100000f; | |
float sy = ((float)bitBuffer.ReadLong()) / 100000f; | |
MoveEntity(id, px, py, sx, sy); | |
#endif | |
} | |
else if (opcode == (int)OpCode.DESTROY) | |
{ | |
#if CLIENT | |
int nb = nbEntities - settings.nbEntitiesSpawn; | |
if (nb < 0) | |
nb = 0; | |
nbEntities = nb; | |
#endif | |
} | |
return opcode; | |
} | |
static void Entity_Spawn(float x, float y, int nbEntitiesToSpawn) | |
{ | |
if ((nbEntities + nbEntitiesToSpawn) > settings.maxEntities) | |
{ | |
Console.WriteLine("Max nb entities reached"); | |
return; | |
} | |
int firstEntity = nbEntities; | |
nbEntities += nbEntitiesToSpawn; | |
for (int i = firstEntity; i < nbEntities; i++) | |
{ | |
position_x[i] = x; | |
position_y[i] = y; | |
speed_x[i] = (float)rand.NextDouble() - 0.5f; | |
speed_y[i] = (float) rand.NextDouble() - 0.5f; | |
destination_x[i] = x; | |
destination_y[i] = y; | |
// Unity use: int col = (int) (rand.NextDouble() * 16777215.0d); | |
color[i] = new Color( | |
(byte)rand.Next(255), | |
(byte)rand.Next(255), | |
(byte)rand.Next(255), | |
(byte)rand.Next(255)); | |
//Console.WriteLine("id2: " + i + " <" + x + "," + y + "> <" + speed_x[i] + "," + speed_y[i] + ">"); | |
} | |
} | |
static void Entity_Spawn(int entity, float px, float py, float sx, float sy, Color col) | |
{ | |
//Console.WriteLine("id: " + entity + " <" + px + "," + py + "> <" + sx + "," + sy + ">"); | |
position_x[entity] = px; | |
position_y[entity] = py; | |
speed_x[entity] = sx; | |
speed_y[entity] = sy; | |
destination_x[entity] = px; | |
destination_y[entity] = py; | |
color[entity] = col; // Unity use: (int) (rand.NextDouble() * 16777215.0d); | |
nbEntities++; | |
} | |
static void SendToAll(ref Host host, OpCode opcode, int id) | |
{ | |
bool reliable = false; | |
Packet packet = default(Packet); | |
BitBuffer buffer = BufferPool.GetBitBuffer(); | |
buffer.Clear(); | |
Span<byte> span = new Span<byte>(data); | |
buffer.AddInt((int)opcode); | |
if (opcode == OpCode.SPAWN) | |
{ | |
reliable = true; | |
buffer.AddInt(id) | |
.AddLong((long)(position_x[id] * 100000f)) | |
.AddLong((long)(position_y[id] * 100000f)) | |
.AddLong((long)(speed_x[id] * 100000f)) | |
.AddLong((long)(speed_y[id] * 100000f)) | |
.AddByte(color[id].r) | |
.AddByte(color[id].g) | |
.AddByte(color[id].b) | |
.AddByte(color[id].a); | |
//Console.WriteLine("server id: " + id + " <" + position_x[id] + "," + position_y[id] + "> <" + speed_x[id] + "," + speed_y[id] + ">"); | |
//Console.WriteLine(" id: " + id + " <" + (long)(position_x[id] * 100000f) + "," + (long)(position_y[id] * 100000f) + "> <" + (long)(speed_x[id] * 100000f) + "," + (long)(speed_y[id] * 100000f) + ">"); | |
} | |
else if (opcode == OpCode.MOVE) | |
{ | |
buffer.AddInt(id) | |
.AddLong((long)(position_x[id] * 100000f)) | |
.AddLong((long)(position_y[id] * 100000f)) | |
.AddLong((long)(speed_x[id] * 100000f)) | |
.AddLong((long)(speed_y[id] * 100000f)); | |
} | |
else if (opcode == OpCode.DESTROY) | |
{ | |
reliable = true; | |
buffer.AddInt(id); | |
} | |
if (settings.redundantBytes > 0) | |
{ | |
for (int i = 0; i < settings.redundantBytes; i++) | |
{ | |
buffer.AddByte(0); | |
} | |
} | |
buffer.ToSpan(ref span); | |
data = span.ToArray(); | |
packet.Create(data, buffer.Length, reliable ? PacketFlags.Reliable : PacketFlags.None); | |
host.Broadcast(0, ref packet); | |
} | |
static void MoveEntity(int id, float deltaTime) | |
{ | |
float to_x = destination_x[id] - position_x[id]; | |
float to_y = destination_y[id] - position_y[id]; | |
float sqrtDist = to_x * to_x + to_y * to_y; | |
float maxDistanceDelta = (float) Math.Sqrt(speed_x[id] * speed_x[id] + speed_y[id] * speed_y[id]); | |
float step = maxDistanceDelta * settings.maxMovementSpeed * deltaTime; | |
if (sqrtDist == 0f || (step >= 0f && sqrtDist <= step*step)) | |
{ | |
position_x[id] = destination_x[id]; | |
position_y[id] = destination_y[id]; | |
return; | |
} | |
float distance = (float) Math.Sqrt(sqrtDist); | |
position_x[id] = position_x[id] + to_x / distance * step; | |
position_y[id] = position_y[id] + to_y / distance * step; | |
} | |
static void MoveEntity(float deltaTime) | |
{ | |
float speed = settings.maxMovementSpeed; | |
for (int i = 0; i < nbEntities; i++) | |
{ | |
position_x[i] += speed_x[i] * speed * deltaTime; | |
position_y[i] += speed_y[i] * speed * deltaTime; | |
if (position_x[i] > settings.resolutionWidth || position_x[i] < 0) | |
speed_x[i] *= -1f; | |
if (position_y[i] > settings.resolutionHeight|| position_y[i] < 0) | |
speed_y[i] *= -1f; | |
} | |
} | |
static void MoveEntity(int id, float px, float py, float sx, float sy) | |
{ | |
destination_x[id] = px; | |
destination_y[id] = py; | |
speed_x[id] = sx; | |
speed_y[id] = sy; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In debug 500'000 messages per seconds
