public void HandleMessage(VMNetClient client, VMNetMessage message) { var cmd = new VMNetCommand(); try { using (var reader = new BinaryReader(new MemoryStream(message.Data))) { if (!cmd.TryDeserialize(reader, false)) { return; //ignore things that should never be sent to the server } } } catch (Exception e) { //corrupt commands are currently a death sentence for the client. nothing should be corrupt over TCP except in rare cases. client.FatalDCMessage = "RECEIVED BAD COMMAND: " + e.ToString(); ClientsToDC.Add(client); return; } if (cmd.Type == VMCommandType.SimJoin) { //note: currently avatars no longer send sim join commands, the server does when it gets the database info. if (SandboxBans.Contains(client.RemoteIP)) { SendGenericMessage(client, "Banned", "You have been banned from this sandbox server!"); ClientsToDC.Add(client); return; } else if (((VMNetSimJoinCmd)cmd.Command).Version != VMNetSimJoinCmd.CurVer) { SendGenericMessage(client, "Version Mismatch", "Your game version does not match the server's. Please update your game."); ClientsToDC.Add(client); return; } SendCommand(cmd.Command); //just go for it. will start the avatar retrieval process. return; } else if (cmd.Type == VMCommandType.RequestResync) { lock (ClientsToSync) { //todo: throttle ProblemTick = ((VMRequestResyncCmd)cmd.Command).TickID; ResyncClients.Add(client); //under clientstosync lock } } else if (cmd.Type != VMCommandType.ChatParameters) { client.InactivityTicks = 0; } cmd.Command.ActorUID = client.PersistID; SendCommand(cmd.Command); }
public override void OnPacket(NetworkClient client, ProcessedPacket packet) { var cmd = new VMNetCommand(); try { using (var reader = new BinaryReader(packet)) { cmd.Deserialize(reader); } } catch (Exception) { ClientsToDC.Add(client); return; } if (cmd.Type == VMCommandType.SimJoin) { if (SandboxBans.Contains(client.RemoteIP)) { SendGenericMessage(client, "Banned", "You have been banned from this sandbox server!"); ClientsToDC.Add(client); return; } else if (((VMNetSimJoinCmd)cmd.Command).Version != VMNetSimJoinCmd.CurVer) { SendGenericMessage(client, "Version Mismatch", "Your game version does not match the server's. Please update your game."); ClientsToDC.Add(client); return; } ((VMNetSimJoinCmd)cmd.Command).Ticket = client.RemoteIP + ":" + ((VMNetSimJoinCmd)cmd.Command).Name; ((VMNetSimJoinCmd)cmd.Command).Client = client; //remember client so we can bind it to persist id later SendCommand(cmd.Command); //just go for it. will start the avatar retrieval process. return; } else if (cmd.Type == VMCommandType.RequestResync) { lock (ClientsToSync) { //todo: throttle ClientsToSync.Add(client); } } lock (ClientToUID) { if (!ClientToUID.ContainsKey(client)) { return; //client hasn't registered yet } cmd.Command.ActorUID = ClientToUID[client]; } SendCommand(cmd.Command); }
private void SendState(VM vm) { if (ClientsToSync.Count == 0) { return; } var watch = new Stopwatch(); watch.Start(); var state = vm.Save(); var statecmd = new VMStateSyncCmd { State = state }; #if VM_DESYNC_DEBUG statecmd.Trace = vm.Trace.GetTick(ProblemTick); #endif var cmd = new VMNetCommand(statecmd); //currently just hack this on the tick system. might switch later var ticks = new VMNetTickList { Ticks = new List <VMNetTick> { new VMNetTick { Commands = new List <VMNetCommand> { cmd }, RandomSeed = 0, //will be restored by client from cmd TickID = TickID } } }; byte[] data; using (var stream = new MemoryStream()) { using (var writer = new BinaryWriter(stream)) { ticks.SerializeInto(writer); } data = stream.ToArray(); } foreach (var client in ClientsToSync) { Send(client, new VMNetMessage(VMNetMessageType.BroadcastTick, data)); } ClientsToSync.Clear(); watch.Stop(); }
private void SendState(VM vm) { if (ClientsToSync.Count == 0) { return; } var state = vm.Save(); var cmd = new VMNetCommand(new VMStateSyncCmd { State = state }); //currently just hack this on the tick system. will change when we switch to not gonzonet var ticks = new VMNetTickList { Ticks = new List <VMNetTick> { new VMNetTick { Commands = new List <VMNetCommand> { cmd }, RandomSeed = 0, //will be restored by client from cmd TickID = TickID } } }; byte[] data; using (var stream = new MemoryStream()) { using (var writer = new BinaryWriter(stream)) { ticks.SerializeInto(writer); } data = stream.ToArray(); } byte[] packet; using (var stream = new PacketStream((byte)PacketType.VM_PACKET, 0)) { stream.WriteHeader(); stream.WriteInt32(data.Length + (int)PacketHeaders.UNENCRYPTED); stream.WriteBytes(data); packet = stream.ToArray(); } foreach (var client in ClientsToSync) { client.Send(packet); } ClientsToSync.Clear(); }
public void SendDirectCommand(VMNetClient client, VMNetCommandBodyAbstract acmd) { var cmd = new VMNetCommand(acmd); byte[] data; using (var stream = new MemoryStream()) { using (var writer = new BinaryWriter(stream)) { cmd.SerializeInto(writer); } data = stream.ToArray(); } Send(client, new VMNetMessage(VMNetMessageType.Direct, data)); }
private void HandleServerMessage(VMNetMessage message) { if (message.Type == VMNetMessageType.Direct) { var cmd = new VMNetCommand(); try { using (var reader = new BinaryReader(new MemoryStream(message.Data))) { cmd.Deserialize(reader); } cmd.Command.Execute(VMHook, VMHook.GetAvatarByPersist(cmd.Command.ActorUID)); } catch (Exception e) { CloseReason = VMCloseNetReason.NetExceptionDirect; CloseString = "An exception occurred while running a direct tick from the server, so the lot connection was terminated: \n\n" + e.ToString(); Shutdown(); return; } } else { var tick = new VMNetTickList(); try { using (var reader = new BinaryReader(new MemoryStream(message.Data))) { tick.Deserialize(reader); } } catch (Exception e) { CloseReason = VMCloseNetReason.NetException; CloseString = "An exception occurred while running a broadcast tick from the server, so the lot connection was terminated: \n\n" + e.ToString(); Shutdown(); return; } for (int i = 0; i < tick.Ticks.Count; i++) { tick.Ticks[i].ImmediateMode = tick.ImmediateMode; TickBuffer.Enqueue(tick.Ticks[i]); } } }
private void SendToServer(VMNetCommandBodyAbstract cmd) { byte[] data; using (var stream = new MemoryStream()) { var cmd2 = new VMNetCommand(cmd); using (var writer = new BinaryWriter(stream)) { cmd2.SerializeInto(writer); } data = stream.ToArray(); } if (OnClientCommand != null) { OnClientCommand(data); } }
private void HandleServerMessage(VMNetMessage message) { if (message.Type == VMNetMessageType.Direct) { var cmd = new VMNetCommand(); try { using (var reader = new BinaryReader(new MemoryStream(message.Data))) { cmd.Deserialize(reader); } cmd.Command.Execute(VMHook); } catch (Exception e) { Shutdown(); return; } } else { var tick = new VMNetTickList(); try { using (var reader = new BinaryReader(new MemoryStream(message.Data))) { tick.Deserialize(reader); } } catch (Exception e) { Shutdown(); return; } for (int i = 0; i < tick.Ticks.Count; i++) { tick.Ticks[i].ImmediateMode = tick.ImmediateMode; TickBuffer.Enqueue(tick.Ticks[i]); } } }
private void SendToServer(VMNetCommandBodyAbstract cmd) { byte[] data; using (var stream = new MemoryStream()) { var cmd2 = new VMNetCommand(cmd); using (var writer = new BinaryWriter(stream)) { cmd2.SerializeInto(writer); } data = stream.ToArray(); } using (var stream = new PacketStream((byte)PacketType.VM_PACKET, 0)) { stream.WriteHeader(); stream.WriteInt32(data.Length + (int)PacketHeaders.UNENCRYPTED); stream.WriteBytes(data); Client.Send(stream.ToArray()); } }
public override void OnPacket(NetworkClient client, ProcessedPacket packet) { var cmd = new VMNetCommand(); try { using (var reader = new BinaryReader(packet)) { cmd.Deserialize(reader); } } catch (Exception) { ClientsToDC.Add(client); return; } if (cmd.Type == VMCommandType.SimJoin) { if (((VMNetSimJoinCmd)cmd.Command).Version != VMNetSimJoinCmd.CurVer) { ClientsToDC.Add(client); return; } lock (UIDs) { UIDs.Add(client, ((VMNetSimJoinCmd)cmd.Command).SimID); } } else if (cmd.Type == VMCommandType.RequestResync) { lock (ClientsToSync) { //todo: throttle ClientsToSync.Add(client); } } SendCommand(cmd.Command); }
public void SendDirectCommand(VMNetClient client, VMNetCommandBodyAbstract acmd) { if (client.RemoteIP == "local") { //just breaking sandbox a little SendCommand(acmd); return; } var cmd = new VMNetCommand(acmd); byte[] data; using (var stream = new MemoryStream()) { using (var writer = new BinaryWriter(stream)) { cmd.SerializeInto(writer); } data = stream.ToArray(); } Send(client, new VMNetMessage(VMNetMessageType.Direct, data)); }
private void SendState(VM vm) { if (ResyncClients.Count != 0 && LastSync == null && !SyncSerializing) { //only add resync clients when we can give them a (near) clean sync. if (TickID - LastDesyncTick > DESYNC_LOOP_FREQ) { LastDesyncPcts.Clear(); } LastDesyncTick = TickID; LastDesyncPcts.Add(ResyncClients.Count / (float)vm.Context.ObjectQueries.AvatarsByPersist.Count); foreach (var cli in ResyncClients) //under clientstosync lock { ClientsToSync.Add(cli); } ResyncClients.Clear(); } if (ClientsToSync.Count == 0) { return; } if (LastSync == null && !SyncSerializing) { SyncSerializing = true; TicksSinceSync = new List <byte[]>(); //start saving a history. var state = vm.Save(); //must be saved on lot thread. we can serialize elsewhere tho. var statecmd = new VMStateSyncCmd { State = state }; if (vm.Trace != null) { statecmd.Traces = vm.Trace.History; } var cmd = new VMNetCommand(statecmd); //currently just hack this on the tick system. might switch later var ticks = new VMNetTickList { Ticks = new List <VMNetTick> { new VMNetTick { Commands = new List <VMNetCommand> { cmd }, RandomSeed = 0, //will be restored by client from cmd TickID = TickID } } }; Task.Run(() => { byte[] data; using (var stream = new MemoryStream()) { using (var writer = new BinaryWriter(stream)) { ticks.SerializeInto(writer); } data = stream.ToArray(); } LastSync = data; SyncSerializing = false; }); } else if (LastSync != null) { foreach (var client in ClientsToSync) { Send(client, new VMNetMessage(VMNetMessageType.BroadcastTick, LastSync)); foreach (var tick in TicksSinceSync) //catch this client up with what happened since the last state was created. { Send(client, new VMNetMessage(VMNetMessageType.BroadcastTick, tick)); } } ClientsToSync.Clear(); NewClients.Clear(); //note that the lock for clientstosync is valid for newclients too. //don't clear last sync and history, since it can be used again if someone wants to join soon. } //if neither of the above happen, we're waiting for the serialization to complete (in the task) }
private void SendState(VM vm) { if (ClientsToSync.Count == 0) { return; } //Console.WriteLine("== SERIAL: Sending State to Client... =="); var watch = new Stopwatch(); watch.Start(); var state = vm.Save(); //Console.WriteLine("== STATE: Intermediate - after save... " + watch.ElapsedMilliseconds + " ms. =="); var cmd = new VMNetCommand(new VMStateSyncCmd { State = state }); //currently just hack this on the tick system. will change when we switch to not gonzonet var ticks = new VMNetTickList { Ticks = new List <VMNetTick> { new VMNetTick { Commands = new List <VMNetCommand> { cmd }, RandomSeed = 0, //will be restored by client from cmd TickID = TickID } } }; byte[] data; using (var stream = new MemoryStream()) { //Console.WriteLine("== STATE: Intermediate - before serialize... " + watch.ElapsedMilliseconds + " ms. =="); using (var writer = new BinaryWriter(stream)) { ticks.SerializeInto(writer); } //Console.WriteLine("== STATE: Intermediate - before toArray... " + watch.ElapsedMilliseconds + " ms. =="); data = stream.ToArray(); } //Console.WriteLine("== STATE: Intermediate - before send... " + watch.ElapsedMilliseconds + " ms. =="); byte[] packet; using (var stream = new PacketStream((byte)ProtocolAbstractionLibraryD.PacketType.VM_PACKET, 0)) { stream.WriteHeader(); stream.WriteInt32(data.Length + (int)PacketHeaders.UNENCRYPTED); stream.WriteBytes(data); packet = stream.ToArray(); } foreach (var client in ClientsToSync) { client.Send(packet); } ClientsToSync.Clear(); watch.Stop(); //Console.WriteLine("== SERIAL: DONE! State send took "+watch.ElapsedMilliseconds+" ms. =="); }
public bool AsyncBreak; //if protected void InternalTick(VM vm, VMNetTick tick) { CurrentTick = tick.TickID; if (CurrentTick > GreatestTick) { GreatestTick = CurrentTick; } if (!tick.ImmediateMode && (tick.Commands.Count == 0 || !(tick.Commands[0].Command is VMStateSyncCmd)) && vm.Context.RandomSeed != tick.RandomSeed) { if (DesyncCooldown == 0) { System.Console.WriteLine("DESYNC - Requested state from host"); if (DesyncTick == 0) { DesyncTick = CurrentTick - 1; } vm.SendCommand(new VMRequestResyncCmd()); DesyncCooldown = 30 * 30; } else { System.Console.WriteLine("WARN - DESYNC - Expected " + tick.RandomSeed + ", was at " + vm.Context.RandomSeed); } } if (RecordStream != null) { RecordTick(tick); } vm.Context.RandomSeed = tick.RandomSeed; AsyncBreak = false; bool doTick = !tick.ImmediateMode; foreach (var cmd in tick.Commands) { if (cmd.Command is VMStateSyncCmd && ((VMStateSyncCmd)cmd.Command).Run) { if (LastTick + 1 != tick.TickID) { System.Console.WriteLine("Jump to tick " + tick.TickID); } if (!(this is VMFSORDriver)) { doTick = false; //something weird here. this can break loading from saves casually - but must not be active for resyncs. } //disable just for fsor playback } var caller = vm.GetAvatarByPersist(cmd.Command.ActorUID); Executing = cmd; cmd.Command.Execute(vm, caller); Executing = null; if (vm.FSOVAsyncLoading) { tick.Commands.Remove(cmd); //don't worry about modifying an enumerated collection - we are exiting anyways. AsyncBreak = true; return; } } if (tick.TickID < LastTick) { System.Console.WriteLine("Tick wrong! Got " + tick.TickID + ", Missed " + ((int)tick.TickID - (LastTick + 1))); } else if (doTick && vm.Context.Ready) { if (tick.TickID > LastTick + 1) { System.Console.WriteLine("Tick wrong! Got " + tick.TickID + ", Missed " + ((int)tick.TickID - (LastTick + 1))); } vm.Trace?.NewTick(tick.TickID); vm.InternalTick(tick.TickID); if (DesyncCooldown > 0) { DesyncCooldown--; } } LastTick = tick.TickID; }