public MyReplicationClient(IReplicationClientCallback callback, MyClientStateBase clientState) : base(false) { m_callback = callback; ClientState = clientState; m_eventHandler = base.ProcessEvent; }
private MyEventContext(EndpointId sender, MyClientStateBase clientState, bool validate) { Sender = sender; ClientState = clientState; IsValidationRequired = validate; m_validationFailed = false; }
public void Serialize(BitStream stream, MyClientStateBase forClient, byte packetId, int maxBitPosition) { SmallBitField dirtyFlags; if (stream.Writing) { var data = m_clientData[forClient]; dirtyFlags = data.DirtyProperties; stream.WriteUInt64(dirtyFlags.Bits, m_properties.Count); } else { dirtyFlags.Bits = stream.ReadUInt64(m_properties.Count); } for (int i = 0; i < m_properties.Count; i++) { if (dirtyFlags[i]) { m_properties[i].Serialize(stream, false); // Received from server, don't validate if (stream.Reading) // Received from server, it's no longer dirty m_dirtyProperties[i] = false; } } if (stream.Writing && stream.BitPosition <= maxBitPosition) { var data = m_clientData[forClient]; data.PacketId = packetId; data.SentProperties.Bits = data.DirtyProperties.Bits; data.DirtyProperties.Bits = 0; } }
public void OnClientReady(EndpointId endpointId, MyClientStateBase clientState) { Debug.Assert(!m_clientStates.ContainsKey(endpointId), "Client entry already exists, bad call to OnClientJoined?"); clientState.EndpointId = endpointId; m_clientStates.Add(endpointId, new ClientData(clientState, m_eventQueueSender)); SendServerData(endpointId); }
protected override float GetGroupPriority(int frameCountWithoutSync, MyClientStateBase client, PrioritySettings settings) { if (IsSlaveGrid()) return 0; return base.GetGroupPriority(frameCountWithoutSync, client, settings); }
public MyReplicationClient(IReplicationClientCallback callback, MyClientStateBase clientState, float simulationTimeStep) : base(false) { m_simulationTimeStep = simulationTimeStep; m_callback = callback; ClientState = clientState; m_eventHandler = base.ProcessEvent; m_isBlockedHandler = this.IsBlocked; }
protected override float GetGroupPriority(int frameCountWithoutSync, MyClientStateBase client, PrioritySettings settings) { const float HighQualityDistance = 8; // under 8m, character physics sync gets high priority to have smooth movement var clientPos = ((MyClientState)client).Position; var characterPos = Entity.PositionComp.GetPosition(); bool isHighQuality = Vector3D.DistanceSquared(clientPos, characterPos) < HighQualityDistance * HighQualityDistance; isHighQuality = isHighQuality && !Entity.IsDead; return base.GetGroupPriority(frameCountWithoutSync, client, isHighQuality ? m_highQuality : settings); }
public void DestroyClientData(MyClientStateBase forClient) { if (m_serverClientData != null) { m_serverClientData.Remove(forClient.EndpointId.Value); } if (m_clientUpdateFlag != null) { m_clientUpdateFlag.Remove(forClient.EndpointId.Value); } }
/// <summary> /// Takes into account: /// Static body (zero priority for static), /// ResponsibilityForUpdate by client (zero priority for not responsible), /// otherwise returns OwnerReplicable priority. /// </summary> protected float GetBasicPhysicsPriority(MyClientStateBase client) { // Called only on server if (Entity.Physics.IsStatic) return 0; // TODO: Rewrite and move 'ResponsibleForUpdate' to this class (when on trunk) var sync = (MySyncEntity)Entity.SyncObject; if (sync.ResponsibleForUpdate(client.GetClient())) return 0; return OwnerReplicable.GetPriority(client); }
public void CreateClientData(MyClientStateBase forClient) { if(m_serverClientData == null) { m_serverClientData = new Dictionary<ulong, ClientData>(); } if (m_clientUpdateFlag == null) { m_clientUpdateFlag = new Dictionary<ulong, bool>(); } m_clientUpdateFlag[forClient.EndpointId.Value] = false; }
public void CreateClientData(MyClientStateBase forClient) { if (m_clientInventoryUpdate == null) { m_clientInventoryUpdate = new Dictionary<ulong, InventoryClientData>(); } InventoryClientData data; if (m_clientInventoryUpdate.TryGetValue(forClient.EndpointId.Value, out data) == false) { m_clientInventoryUpdate[forClient.EndpointId.Value] = new InventoryClientData(); } m_clientInventoryUpdate[forClient.EndpointId.Value].Dirty = true; }
public static bool IsRelevant(this IMyReplicable obj, MyClientStateBase state, out float priority) { priority = obj.GetPriority(state); return(priority > 0); }
public float GetPriority(MyClientStateBase client) { return GetPriorityStateGroup(client); }
public void CreateClientData(MyClientStateBase forClient) { m_clientData.Add(forClient.EndpointId, new ClientData()); m_clientData[forClient.EndpointId].DirtyProperties.Reset(true); }
public void DestroyClientData(MyClientStateBase forClient) { }
public static Token Set(EndpointId endpoint, MyClientStateBase client, bool validate) { return new Token(new MyEventContext(endpoint, client, validate)); }
public static bool IsRelevant(this IMyReplicable obj, MyClientStateBase state) { return(obj.GetPriority(state) > 0); }
/// <summary> /// Reads arguments from stream and invokes event. Returns false when validation failed, otherwise true. /// </summary> public bool Invoke(CallSite callSite, BitStream stream, object obj, EndpointId source, MyClientStateBase clientState, bool validate) { using (MySerializerNetObject.Using(this)) using (MyEventContext.Set(source, clientState, validate)) { return(callSite.Invoke(stream, obj, validate) && !(validate && MyEventContext.Current.HasValidationFailed)); } }
public void DestroyClientData(MyClientStateBase forClient) { if (m_clientInventoryUpdate != null) { m_clientInventoryUpdate.Remove(forClient.EndpointId.Value); } }
public void DestroyClientData(MyClientStateBase forClient) { m_clientData.Remove(forClient); }
public ClientData(MyClientStateBase emptyState, Action <BitStream, EndpointId> sender) { State = emptyState; EventQueue = new MyPacketQueue(512, sender); }
public void CreateClientData(MyClientStateBase forClient) { m_clientData.Add(forClient, new ClientData()); }
public bool IsDirty(MyClientStateBase forClient) { return m_clientData[forClient].DirtyProperties.Bits != 0; }
public void OnAck(MyClientStateBase forClient, byte packetId, bool delivered) { var data = m_clientData[forClient]; Debug.Assert(data.PacketId == packetId, "Packet ID does not match, error in replication server, reporting ACK for something invalid"); if (delivered) { data.SentProperties.Bits = 0; // Nothing sent now } else { // Not delivered, add sent to dirty data.DirtyProperties.Bits |= data.SentProperties.Bits; } data.PacketId = null; }
public float GetPriorityStateGroup(MyClientStateBase client) { MyClientState state = client as MyClientState; if (state.Context == Sandbox.Engine.Multiplayer.MyClientState.MyContextKind.Inventory || state.Context == Sandbox.Engine.Multiplayer.MyClientState.MyContextKind.Production) { if (state.ContextEntity != null) { MyCubeGrid parent = state.ContextEntity.GetTopMostParent() as MyCubeGrid; if (parent != null) { foreach (var block in parent.GridSystems.TerminalSystem.Blocks) { if (block == m_owner) { if (state.Context == Sandbox.Engine.Multiplayer.MyClientState.MyContextKind.Production && (block is MyAssembler) == false) { continue; } return 1.0f; } } } } } return 0; }
public void CreateClientData(MyClientStateBase forClient) { if (m_clientInventoryUpdate == null) { m_clientInventoryUpdate = new Dictionary<ulong, InventoryClientData>(); } InventoryClientData data; if (m_clientInventoryUpdate.TryGetValue(forClient.EndpointId.Value, out data) == false) { m_clientInventoryUpdate[forClient.EndpointId.Value] = new InventoryClientData(); data = m_clientInventoryUpdate[forClient.EndpointId.Value]; } data.Dirty = false; List<MyPhysicalInventoryItem> items = Inventory.GetItems(); foreach (var serverItem in items) { MyFixedPoint amount = serverItem.Amount; var gasItem = serverItem.Content as MyObjectBuilder_GasContainerObject; if (gasItem != null) { amount = (MyFixedPoint)gasItem.GasLevel; } ClientInvetoryData item = new ClientInvetoryData() { Item = serverItem, Amount = amount }; data.ClientItemsSorted[serverItem.ItemId] = item; data.ClientItems.Add(item); } }
public override void Serialize(BitStream stream, MyClientStateBase forClient, byte packetId, int maxBitPosition) { // Client does not care about slave grids, he always synced group through controlled object Debug.Assert(stream.Reading || !Sync.IsServer || Entity == GetMasterGrid(Entity), "Writing data from SlaveGrid!"); bool apply = !IsControlledLocally; bool moving = false; if (stream.Writing) { moving = IsMoving(Entity); stream.WriteBool(moving); } else { moving = stream.ReadBool(); } // Serialize this grid apply = SerializeTransform(stream, Entity, null, m_lowPrecisionOrientation, apply,moving, m_positionValidation, MoveHandler); SerializeVelocities(stream, Entity, EffectiveSimulationRatio, apply, moving,VelocityHandler); // Serialize other grids in group Vector3D basePos = Entity.WorldMatrix.Translation; if (stream.Writing) { UpdateGridMaxSpeed(Entity, Sync.IsServer); var g = MyCubeGridGroups.Static.PhysicalDynamic.GetGroup(Entity); if (g == null) { stream.WriteByte(0); } else { m_groups.Clear(); int i= -1; foreach (var node in g.Nodes) { i++; if(i < m_currentSentPosition) { continue; } if (i == m_currentSentPosition + NUM_NODES_TO_SEND_ALL) { break; } var target = MyMultiplayer.Static.ReplicationLayer.GetProxyTarget((IMyEventProxy)node.NodeData); if (node.NodeData != Entity && !node.NodeData.IsStatic && target != null) { m_groups.Add(node.NodeData); } } m_currentSentPosition = i; if (m_currentSentPosition >= g.Nodes.Count-1) { m_currentSentPosition = 0; } stream.WriteByte((byte)m_groups.Count); // Ignoring self foreach (var node in m_groups) { var target = MyMultiplayer.Static.ReplicationLayer.GetProxyTarget((IMyEventProxy)node); // ~26.5 bytes per grid, not bad NetworkId networkId = MyMultiplayer.Static.ReplicationLayer.GetNetworkIdByObject(target); stream.WriteNetworkId(networkId); // ~2 bytes moving = IsMoving(node); stream.WriteBool(moving); SerializeTransform(stream, node, basePos, true, apply, moving,null, null); // 12.5 bytes SerializeVelocities(stream, node, EffectiveSimulationRatio, apply, moving); // 12 byte UpdateGridMaxSpeed(node, Sync.IsServer); } } SerializeRopeData(stream, apply, gridsGroup: m_groups); } else { UpdateGridMaxSpeed(Entity, !Sync.IsServer); byte numRecords = stream.ReadByte(); for (int i = 0; i < numRecords; i++) { NetworkId networkId = stream.ReadNetworkId(); // ~2 bytes MyCubeGridReplicable replicable = MyMultiplayer.Static.ReplicationLayer.GetObjectByNetworkId(networkId) as MyCubeGridReplicable; MyCubeGrid grid = replicable != null ? replicable.Grid : null; moving = stream.ReadBool(); SerializeTransform(stream, grid, basePos, true, apply && grid != null,moving, null, null); // 12.5 bytes SerializeVelocities(stream, grid, EffectiveSimulationRatio, apply && grid != null, moving); // 12 bytes UpdateGridMaxSpeed(grid,!Sync.IsServer); } SerializeRopeData(stream, apply); } }
public void ForceSend(MyClientStateBase clientData) { }
public void OnAck(MyClientStateBase forClient, byte packetId, bool delivered) { if (!VRage.Game.MyFinalBuildConstants.IS_OFFICIAL) Console.WriteLine(String.Format("delivery: {0}, {1}", packetId, delivered)); InventoryClientData clientData = m_clientInventoryUpdate[forClient.EndpointId.Value]; InventoryDeltaInformation packetInfo; if (clientData.SendPackets.TryGetValue(packetId, out packetInfo)) { if (delivered == false) { clientData.FailedIncompletePackets.Add(packetInfo); } clientData.SendPackets.Remove(packetId); } }
private void SendStateSync(MyClientStateBase state) { var now = m_timeFunc(); ClientData clientData; if (m_clientStates.TryGetValue(state.EndpointId, out clientData)) { if (clientData.StateGroups.Count == 0) { return; } EndpointId endpointId = state.EndpointId; // TODO: Limit events clientData.EventQueue.Send(); using (m_tmpSortEntries) { foreach (var entry in clientData.StateGroups.Values) { // No state sync for pending or sleeping replicables if (!clientData.Replicables[entry.Owner].HasActiveStateSync) { continue; } entry.FramesWithoutSync++; entry.Priority = entry.Group.GetGroupPriority(entry.FramesWithoutSync, state); if (entry.Priority > 0) { m_tmpSortEntries.Add(entry); } } m_tmpSortEntries.Sort(MyStateDataEntryComparer.Instance); byte firstWaitingPacket = (byte)(clientData.LastReceivedAckId - m_outOfOrderAcceptThreshold); byte nextPacketId = (byte)(clientData.StateSyncPacketId + 1); if (clientData.WaitingForReset || nextPacketId == firstWaitingPacket) { clientData.WaitingForReset = true; return; } clientData.StateSyncPacketId++; m_sendStream.ResetWrite(); m_sendStream.WriteByte(clientData.StateSyncPacketId); int MTUBytes = (int)m_callback.GetMTUSize(endpointId); int messageBitSize = 8 * (MTUBytes - 8 - 1); // MTU - headers // TODO: Rewrite int maxToSend = MTUBytes / 8; // lets assume the shortest message is 8 Bytes long int sent = 0; // TODO:SK limit to N in panic entries per packet foreach (var entry in m_tmpSortEntries) { var oldWriteOffset = m_sendStream.BitPosition; m_sendStream.WriteNetworkId(entry.GroupId); entry.Group.Serialize(m_sendStream, state, clientData.StateSyncPacketId, messageBitSize); if (m_sendStream.BitPosition > oldWriteOffset && m_sendStream.BitPosition <= messageBitSize) { clientData.PendingStateSyncAcks[clientData.StateSyncPacketId].Add(entry.Group); sent++; entry.FramesWithoutSync = 0; } else { // When serialize returns false, restore previous bit position m_sendStream.SetBitPositionWrite(oldWriteOffset); } if (sent >= maxToSend) { break; } } m_callback.SendStateSync(m_sendStream, endpointId); //Server.SendMessage(m_sendStream, guid, PacketReliabilityEnum.UNRELIABLE, PacketPriorityEnum.MEDIUM_PRIORITY, MyChannelEnum.StateDataSync); } } }
public void OnAck(MyClientStateBase forClient, byte packetId, bool delivered) { }
private void SendStateSync(MyClientStateBase state) { var now = m_timeFunc(); ClientData clientData; if (m_clientStates.TryGetValue(state.EndpointId, out clientData)) { if (clientData.StateGroups.Count == 0) return; EndpointId endpointId = state.EndpointId; // TODO: Limit events clientData.EventQueue.Send(); using (m_tmpSortEntries) { foreach (var entry in clientData.StateGroups.Values) { // No state sync for pending or sleeping replicables if (!clientData.Replicables[entry.Owner].HasActiveStateSync) continue; entry.FramesWithoutSync++; entry.Priority = entry.Group.GetGroupPriority(entry.FramesWithoutSync, state); if (entry.Priority > 0) m_tmpSortEntries.Add(entry); } m_tmpSortEntries.Sort(MyStateDataEntryComparer.Instance); byte firstWaitingPacket = (byte)(clientData.LastReceivedAckId - m_outOfOrderAcceptThreshold); byte nextPacketId = (byte)(clientData.StateSyncPacketId + 1); if (clientData.WaitingForReset || nextPacketId == firstWaitingPacket) { clientData.WaitingForReset = true; return; } clientData.StateSyncPacketId++; m_sendStream.ResetWrite(); m_sendStream.WriteByte(clientData.StateSyncPacketId); int MTUBytes = (int)m_callback.GetMTUSize(endpointId); int messageBitSize = 8 * (MTUBytes - 8 - 1); // MTU - headers // TODO: Rewrite int maxToSend = MTUBytes / 8; // lets assume the shortest message is 8 Bytes long int sent = 0; // TODO:SK limit to N in panic entries per packet foreach (var entry in m_tmpSortEntries) { var oldWriteOffset = m_sendStream.BitPosition; m_sendStream.WriteNetworkId(entry.GroupId); entry.Group.Serialize(m_sendStream, state, clientData.StateSyncPacketId, messageBitSize); if (m_sendStream.BitPosition > oldWriteOffset && m_sendStream.BitPosition <= messageBitSize) { clientData.PendingStateSyncAcks[clientData.StateSyncPacketId].Add(entry.Group); sent++; entry.FramesWithoutSync = 0; } else { // When serialize returns false, restore previous bit position m_sendStream.SetBitPositionWrite(oldWriteOffset); } if (sent >= maxToSend) { break; } } m_callback.SendStateSync(m_sendStream, endpointId); //Server.SendMessage(m_sendStream, guid, PacketReliabilityEnum.UNRELIABLE, PacketPriorityEnum.MEDIUM_PRIORITY, MyChannelEnum.StateDataSync); } } }
public abstract float GetPriority(MyClientStateBase client);
public void CreateClientData(MyClientStateBase forClient) { }
public static Token Set(EndpointId endpoint, MyClientStateBase client, bool validate) { return(new Token(new MyEventContext(endpoint, client, validate))); }
public void OnClientJoined(EndpointId endpointId,MyClientStateBase clientState) { OnClientConnected(endpointId,clientState); }
public ClientData(MyClientStateBase emptyState, Action<BitStream, EndpointId> sender) { State = emptyState; EventQueue = new MyPacketQueue(512, sender); }