private void ThreadWorker(Object parameters) { // Thread cache items ThreadParamInfo setupInfo; Address serverAddress = new Address(); Host serverENetHost; Event serverENetEvent; Peer[] serverPeerArray; // Grab the setup information. if (parameters.GetType() == typeof(ThreadParamInfo)) { setupInfo = (ThreadParamInfo)parameters; } else { return; } // Attempt to initialize ENet inside the thread. if (Library.Initialize()) { } else { return; } // Configure the server address. serverAddress.SetHost(setupInfo.Address); serverAddress.Port = (ushort)setupInfo.Port; serverPeerArray = new Peer[setupInfo.Peers]; using (serverENetHost = new Host()) { // Create the server object. serverENetHost.Create(serverAddress, setupInfo.Peers, setupInfo.Channels); // Loop until we're told to cease operations. while (!CeaseOperation) { // Intermission: Command Handling while (Commands.TryDequeue(out IgnoranceCommandPacket commandPacket)) { switch (commandPacket.Type) { default: break; // Boot a Peer off the Server. case IgnoranceCommandType.ServerKickPeer: uint targetPeer = commandPacket.PeerId; if (!serverPeerArray[targetPeer].IsSet) { continue; } IgnoranceConnectionEvent iced = new IgnoranceConnectionEvent() { WasDisconnect = true, NativePeerId = targetPeer }; DisconnectionEvents.Enqueue(iced); // Disconnect and reset the peer array's entry for that peer. serverPeerArray[targetPeer].DisconnectNow(0); serverPeerArray[targetPeer] = default; break; } } // Step One: // ---> Sending to peers while (Outgoing.TryDequeue(out IgnoranceOutgoingPacket outgoingPacket)) { // Only create a packet if the server knows the peer. if (serverPeerArray[outgoingPacket.NativePeerId].IsSet) { int ret = serverPeerArray[outgoingPacket.NativePeerId].Send(outgoingPacket.Channel, ref outgoingPacket.Payload); } else { // A peer might have disconnected, this is OK - just log the packet if set to paranoid. } } // Step 2 // <--- Receiving from peers bool pollComplete = false; while (!pollComplete) { Packet incomingPacket; Peer incomingPeer; int incomingPacketLength; // Any events happening? if (serverENetHost.CheckEvents(out serverENetEvent) <= 0) { // If service time is met, break out of it. if (serverENetHost.Service(setupInfo.PollTime, out serverENetEvent) <= 0) { break; } pollComplete = true; } // Setup the packet references. incomingPeer = serverENetEvent.Peer; switch (serverENetEvent.Type) { // Idle. case EventType.None: default: break; // Connection Event. case EventType.Connect: IgnoranceConnectionEvent ice = new IgnoranceConnectionEvent() { NativePeerId = incomingPeer.ID, IP = incomingPeer.IP, Port = incomingPeer.Port }; ConnectionEvents.Enqueue(ice); // Assign a reference to the Peer. serverPeerArray[incomingPeer.ID] = incomingPeer; break; // Disconnect/Timeout. Mirror doesn't care if it's either, so we lump them together. case EventType.Disconnect: case EventType.Timeout: if (!serverPeerArray[incomingPeer.ID].IsSet) { break; } IgnoranceConnectionEvent iced = new IgnoranceConnectionEvent() { WasDisconnect = true, NativePeerId = incomingPeer.ID }; DisconnectionEvents.Enqueue(iced); // Reset the peer array's entry for that peer. serverPeerArray[incomingPeer.ID] = default; break; case EventType.Receive: // Receive event type usually includes a packet; so cache its reference. incomingPacket = serverENetEvent.Packet; if (!incomingPacket.IsSet) { break; } incomingPacketLength = incomingPacket.Length; // Firstly check if the packet is too big. If it is, do not process it - drop it. if (incomingPacketLength > setupInfo.PacketSizeLimit) { incomingPacket.Dispose(); break; } IgnoranceIncomingPacket incomingQueuePacket = new IgnoranceIncomingPacket { Channel = serverENetEvent.ChannelID, NativePeerId = incomingPeer.ID, Payload = incomingPacket, }; // Enqueue. Incoming.Enqueue(incomingQueuePacket); break; } } } // Cleanup and flush everything. serverENetHost.Flush(); // Kick everyone. for (int i = 0; i < serverPeerArray.Length; i++) { if (!serverPeerArray[i].IsSet) { continue; } serverPeerArray[i].DisconnectNow(0); } } // Flush again to ensure ENet gets those Disconnection stuff out. // May not be needed; better to err on side of caution Library.Deinitialize(); }
private void ThreadWorker(Object parameters) { if (Verbosity > 0) { Debug.Log("Ignorance Server: Initializing. Please stand by..."); } // Thread cache items ThreadParamInfo setupInfo; Address serverAddress = new Address(); Host serverENetHost; Event serverENetEvent; Peer[] serverPeerArray; // Grab the setup information. if (parameters.GetType() == typeof(ThreadParamInfo)) { setupInfo = (ThreadParamInfo)parameters; } else { Debug.LogError("Ignorance Server: Startup failure; Invalid thread parameters. Aborting."); return; } // Attempt to initialize ENet inside the thread. if (Library.Initialize()) { Debug.Log("Ignorance Server: ENet Native successfully initialized."); } else { Debug.LogError("Ignorance Server: Failed to initialize ENet Native. This threads' f****d."); return; } // Configure the server address. serverAddress.SetHost(setupInfo.Address); serverAddress.Port = (ushort)setupInfo.Port; serverPeerArray = new Peer[setupInfo.Peers]; using (serverENetHost = new Host()) { // Create the server object. serverENetHost.Create(serverAddress, setupInfo.Peers, setupInfo.Channels); // Loop until we're told to cease operations. while (!CeaseOperation) { // Intermission: Command Handling while (Commands.TryDequeue(out IgnoranceCommandPacket commandPacket)) { switch (commandPacket.Type) { default: break; // Boot a Peer off the Server. case IgnoranceCommandType.ServerKickPeer: uint targetPeer = commandPacket.PeerId; if (!serverPeerArray[targetPeer].IsSet) { continue; } if (setupInfo.Verbosity > 0) { Debug.Log($"Ignorance Server: Booting ENet Peer {targetPeer} off this server instance."); } IgnoranceConnectionEvent iced = new IgnoranceConnectionEvent { EventType = 0x01, NativePeerId = targetPeer }; DisconnectionEvents.Enqueue(iced); // Disconnect and reset the peer array's entry for that peer. serverPeerArray[targetPeer].DisconnectNow(0); serverPeerArray[targetPeer] = default; break; } } // Step One: // ---> Sending to peers while (Outgoing.TryDequeue(out IgnoranceOutgoingPacket outgoingPacket)) { // Only create a packet if the server knows the peer. if (serverPeerArray[outgoingPacket.NativePeerId].IsSet) { int ret = serverPeerArray[outgoingPacket.NativePeerId].Send(outgoingPacket.Channel, ref outgoingPacket.Payload); if (ret < 0 && setupInfo.Verbosity > 0) { Debug.LogWarning($"Ignorance Server: ENet error {ret} while sending packet to Peer {outgoingPacket.NativePeerId}."); } } else { // A peer might have disconnected, this is OK - just log the packet if set to paranoid. if (setupInfo.Verbosity > 1) { Debug.LogWarning("Ignorance Server: Can't send packet, a native peer object is not set. This may be normal if the Peer has disconnected before this send cycle."); } } } // Step 2 // <--- Receiving from peers bool pollComplete = false; while (!pollComplete) { Packet incomingPacket; Peer incomingPeer; int incomingPacketLength; // Any events happening? if (serverENetHost.CheckEvents(out serverENetEvent) <= 0) { // If service time is met, break out of it. if (serverENetHost.Service(setupInfo.PollTime, out serverENetEvent) <= 0) { break; } pollComplete = true; } // Setup the packet references. incomingPeer = serverENetEvent.Peer; // What type are you? switch (serverENetEvent.Type) { // Idle. case EventType.None: default: break; // Connection Event. case EventType.Connect: if (setupInfo.Verbosity > 1) { Debug.Log($"Ignorance Server: Hello new peer with ID {incomingPeer.ID}!"); } IgnoranceConnectionEvent ice = new IgnoranceConnectionEvent() { NativePeerId = incomingPeer.ID, IP = incomingPeer.IP, Port = incomingPeer.Port }; ConnectionEvents.Enqueue(ice); // Assign a reference to the Peer. serverPeerArray[incomingPeer.ID] = incomingPeer; break; // Disconnect/Timeout. Mirror doesn't care if it's either, so we lump them together. case EventType.Disconnect: case EventType.Timeout: if (!serverPeerArray[incomingPeer.ID].IsSet) { break; } if (setupInfo.Verbosity > 1) { Debug.Log($"Ignorance Server: Bye bye Peer {incomingPeer.ID}; They have disconnected."); } IgnoranceConnectionEvent iced = new IgnoranceConnectionEvent { EventType = 0x01, NativePeerId = incomingPeer.ID }; DisconnectionEvents.Enqueue(iced); // Reset the peer array's entry for that peer. serverPeerArray[incomingPeer.ID] = default; break; case EventType.Receive: // Receive event type usually includes a packet; so cache its reference. incomingPacket = serverENetEvent.Packet; if (!incomingPacket.IsSet) { if (setupInfo.Verbosity > 0) { Debug.LogWarning($"Ignorance Server: A receive event did not supply us with a packet to work with. This should never happen."); } break; } incomingPacketLength = incomingPacket.Length; // Firstly check if the packet is too big. If it is, do not process it - drop it. if (incomingPacketLength > setupInfo.PacketSizeLimit) { if (setupInfo.Verbosity > 0) { Debug.LogWarning($"Ignorance Server: Incoming packet is too big. My limit is {setupInfo.PacketSizeLimit} byte(s) whilest this packet is {incomingPacketLength} bytes."); } incomingPacket.Dispose(); break; } IgnoranceIncomingPacket incomingQueuePacket = new IgnoranceIncomingPacket { Channel = serverENetEvent.ChannelID, NativePeerId = incomingPeer.ID, Payload = incomingPacket, }; // Enqueue. Incoming.Enqueue(incomingQueuePacket); break; } } } if (Verbosity > 0) { Debug.Log("Ignorance Server: Thread shutdown commencing. Flushing connections."); } // Cleanup and flush everything. serverENetHost.Flush(); // Kick everyone. for (int i = 0; i < serverPeerArray.Length; i++) { if (!serverPeerArray[i].IsSet) { continue; } serverPeerArray[i].DisconnectNow(0); } } if (setupInfo.Verbosity > 0) { Debug.Log("Ignorance Server: Shutdown complete."); } Library.Deinitialize(); }