147 lines
5.5 KiB
C#
147 lines
5.5 KiB
C#
using System;
|
|
using System.Net;
|
|
using System.Net.Sockets;
|
|
using System.Net.NetworkInformation;
|
|
|
|
namespace RoboidControl {
|
|
|
|
/// <summary>
|
|
/// A site server is a participant which provides a shared simulated environment
|
|
/// </summary>
|
|
public class SiteServer : ParticipantUDP {
|
|
|
|
#region Init
|
|
|
|
/// <summary>
|
|
/// Create a new site server
|
|
/// </summary>
|
|
/// <param name="port">The port of which to receive the messages</param>
|
|
public SiteServer(int port = 7681) : base(port) {
|
|
this.name = "Site Server";
|
|
|
|
// Determine local IP address
|
|
IPAddress localIpAddress = null;
|
|
IPAddress subnetMask = null;
|
|
using (Socket socket = new(AddressFamily.InterNetwork, SocketType.Dgram, 0)) {
|
|
// Connect to a remote endpoint — we won't actually send anything
|
|
socket.Connect("1.1.1.1", 65530);
|
|
if (socket.LocalEndPoint is IPEndPoint endPoint) {
|
|
localIpAddress = endPoint.Address;
|
|
this.ipAddress = localIpAddress.ToString();
|
|
}
|
|
}
|
|
// Find subnet mask
|
|
foreach (NetworkInterface nwInterface in NetworkInterface.GetAllNetworkInterfaces()) {
|
|
if (nwInterface.OperationalStatus != OperationalStatus.Up)
|
|
continue;
|
|
|
|
foreach (UnicastIPAddressInformation unicastAddress in nwInterface.GetIPProperties().UnicastAddresses) {
|
|
if (unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork && unicastAddress.Address.Equals(localIpAddress)
|
|
) {
|
|
subnetMask = unicastAddress.IPv4Mask;
|
|
}
|
|
}
|
|
}
|
|
if (localIpAddress != null && subnetMask != null)
|
|
GetBroadcastAddress(localIpAddress, subnetMask);
|
|
|
|
Console.Write($"Prepare receive on port {port}");
|
|
this.endPoint = new IPEndPoint(IPAddress.Any, port);
|
|
this.udpClient = new UdpClient(port);
|
|
this.udpClient.BeginReceive(new AsyncCallback(result => ReceiveUDP(result)), null);
|
|
|
|
}
|
|
|
|
#endregion Init
|
|
|
|
/// <summary>
|
|
/// Close the site
|
|
/// </summary>
|
|
public void Close() {
|
|
this.udpClient?.Close();
|
|
}
|
|
|
|
#region Update
|
|
|
|
protected override void UpdateMyThings(ulong currentTimeMS) {
|
|
// We don't use foreach to prevent the 'Collection was modified' error
|
|
int n = this.things.Count;
|
|
for (int ix = 0; ix < n; ix++) {
|
|
Thing thing = this.things[ix];
|
|
|
|
if (thing == null)
|
|
continue;
|
|
|
|
thing.Update(currentTimeMS, false);
|
|
|
|
if (this.isIsolated == false) {
|
|
// Send to all other participants
|
|
//foreach (Participant participant in Participant.participants) {
|
|
for (int participantIx = 0; participantIx < Participant.participants.Count; participantIx++) {
|
|
Participant participant = Participant.participants[participantIx];
|
|
if (participant == null || participant == this)
|
|
continue;
|
|
|
|
// PoseMsg poseMsg = new(thing.owner.networkId, thing);
|
|
// this.Send(participant, poseMsg);
|
|
// BinaryMsg binaryMsg = new(thing.owner.networkId, thing);
|
|
// this.Send(participant, binaryMsg);
|
|
participant.Send(new PoseMsg(thing.owner.networkId, thing));
|
|
participant.Send(new BinaryMsg(thing.owner.networkId, thing));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion Update
|
|
|
|
#region Receive
|
|
|
|
protected override void Process(Participant sender, ParticipantMsg msg) {
|
|
base.Process(sender, msg);
|
|
if (msg.networkId != sender.networkId) {
|
|
//Console.WriteLine($"{this.name} received New Participant -> {sender.networkId}");
|
|
// this.Send(sender, new NetworkIdMsg(sender.networkId));
|
|
sender.Send(new NetworkIdMsg(sender.networkId));
|
|
UpdateEvent e = new() {
|
|
messageId = ParticipantMsg.Id,
|
|
participant = sender
|
|
};
|
|
this.updateQueue.Enqueue(e);
|
|
}
|
|
}
|
|
|
|
protected override void Process(Participant sender, NetworkIdMsg msg) { }
|
|
|
|
protected override void Process(Participant sender, ThingMsg msg) {
|
|
Console.WriteLine($"{this.name}: Process thing [{msg.networkId}/{msg.thingId}] {msg.thingType} {msg.parentId} ");
|
|
|
|
Thing thing = sender.Get(msg.thingId);
|
|
if (thing == null) {
|
|
switch (msg.thingType) {
|
|
case (byte)Thing.Type.TouchSensor:
|
|
new TouchSensor(sender, msg.thingId);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (thing == null)
|
|
thing = new Thing(sender, msg.thingType, msg.thingId);
|
|
|
|
if (msg.parentId != 0) {
|
|
thing.parent = sender.Get(msg.parentId);
|
|
if (thing.parent == null)
|
|
Console.WriteLine($"Could not find parent [{msg.networkId}/{msg.parentId}]");
|
|
}
|
|
else {
|
|
// Console.Write($"Dropped {thing.id}");
|
|
thing.parent = null;
|
|
}
|
|
}
|
|
|
|
|
|
#endregion Receive
|
|
|
|
}
|
|
|
|
} |