using System; using System.Net; using System.Net.Sockets; using System.Net.NetworkInformation; namespace RoboidControl { /// /// A site server is a participant which provides a shared simulated environment /// public class SiteServer : ParticipantUDP { #region Init /// /// Create a new site server /// /// The port of which to receive the messages 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 /// /// Close the site /// 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 } }