public void RequestControlUpdate(RailEntityClient entity, RailStateDelta delta) { // Can't infer anything if the delta is an empty frozen update if (delta.IsFrozen) { return; } if (delta.IsRemoving) { if (entity.Controller != null) { localPeer.RevokeControlInternal(entity); } } else if (delta.HasControllerData) { if (entity.Controller == null) { localPeer.GrantControlInternal(entity); } } else { if (entity.Controller != null) { localPeer.RevokeControlInternal(entity); } } }
/// <summary> /// Returns true iff we stored the delta. /// </summary> public bool ProcessDelta(RailStateDelta delta) { if (knownEntities.TryGetValue(delta.EntityId, out RailEntityClient entity) == false) { RailDebug.Assert(delta.IsFrozen == false, "Frozen unknown entity"); if (delta.IsFrozen || delta.IsRemoving) { return(false); } entity = delta.ProduceEntity(Resource) as RailEntityClient; if (entity == null) { throw new TypeAccessException( "Got unexpected instance from RailResource. Internal error in type RailRegistry and/or RailResource."); } entity.AssignId(delta.EntityId); entity.PrimeState(delta); pendingEntities.Add(entity.Id, entity); knownEntities.Add(entity.Id, entity); } // If we're already removing the entity, we don't care about other deltas bool stored = false; if (entity.IsRemoving == false) { stored = entity.ReceiveDelta(delta); } return(stored); }
internal static void EncodeDelta( RailBitBuffer buffer, RailStateDelta delta) { // Write: [EntityId] buffer.WriteEntityId(delta.EntityId); // Write: [IsFrozen] buffer.WriteBool(delta.IsFrozen); if (delta.IsFrozen == false) { // Write: [FactoryType] RailState state = delta.State; buffer.WriteInt(RailState.FactoryTypeCompressor, state.factoryType); // Write: [IsRemoved] buffer.WriteBool(state.RemovedTick.IsValid); if (state.RemovedTick.IsValid) { // Write: [RemovedTick] buffer.WriteTick(state.RemovedTick); // End Write } else { // Write: [HasControllerData] buffer.WriteBool(state.HasControllerData); // Write: [HasImmutableData] buffer.WriteBool(state.HasImmutableData); // Write: [Flags] buffer.Write(state.FlagBits, state.Flags); // Write: [Mutable Data] state.EncodeMutableData(buffer, state.Flags); if (state.HasControllerData) { // Write: [Controller Data] state.EncodeControllerData(buffer); // Write: [Command Ack] buffer.WriteTick(state.CommandAck); } if (state.HasImmutableData) { // Write: [Immutable Data] state.EncodeImmutableData(buffer); } } } }
private void ProduceScoped(Tick serverTick, IEnumerable <RailEntityServer> activeEntities) { // TODO: should be doable without the copy using a LINQ expression. entryList.Clear(); foreach (RailEntityServer entity in activeEntities) { if (entity.IsRemoving) { } // Controlled entities are always in scope to their controller else if (entity.Controller == owner) { entryList.Add(new KeyValuePair <float, RailEntityBase>(float.MinValue, entity)); } else if (GetPriority(entity, serverTick, out float priority)) { entryList.Add(new KeyValuePair <float, RailEntityBase>(priority, entity)); } else if (RailEntityBase.CanFreeze) { // We only want to send a freeze state if we aren't already frozen RailViewEntry latest = ackedByClient.GetLatest(entity.Id); if (latest.IsFrozen == false) { frozenList.Add( RailStateDelta.CreateFrozen(stateCreator, serverTick, entity.Id)); } } } entryList.Sort(priorityComparer); foreach (KeyValuePair <float, RailEntityBase> entry in entryList) { RailViewEntry latest = ackedByClient.GetLatest(entry.Value.Id); RailEntityServer entity = entry.Value as RailEntityServer; // Force a complete update if the entity is frozen so it unfreezes // TODO: Currently if we're unfreezing we force the server to send a // delta with the FULL mutable dataset. There is probably a // less wasteful option, like having clients send back // what tick they last received a non-frozen packetToClient on. // However, this would cause some tedious tick comparison. // Should investigate a smarter way to handle this later. RailStateDelta delta = entity.ProduceDelta( stateCreator, latest.LastReceivedTick, owner, latest.IsFrozen); if (delta != null) { activeList.Add(delta); } } }
/// <summary> /// Creates a delta between a state and a record. If forceUpdate is set /// to false, this function will return null if there is no change between /// the current and basis. /// </summary> internal static RailStateDelta CreateDelta( EntityId entityId, RailState current, RailStateRecord basisRecord, bool includeControllerData, bool includeImmutableData, Tick commandAck, Tick removedTick) { bool shouldReturn = includeControllerData || includeImmutableData || removedTick.IsValid; uint flags = RailState.FLAGS_ALL; if ((basisRecord != null) && (basisRecord.State != null)) { flags = current.CompareMutableData(basisRecord.State); } if ((flags == 0) && (shouldReturn == false)) { return(null); } RailState deltaState = RailState.Create(current.factoryType); deltaState.Flags = flags; deltaState.ApplyMutableFrom(current, deltaState.Flags); deltaState.HasControllerData = includeControllerData; if (includeControllerData) { deltaState.ApplyControllerFrom(current); } deltaState.HasImmutableData = includeImmutableData; if (includeImmutableData) { deltaState.ApplyImmutableFrom(current); } deltaState.RemovedTick = removedTick; deltaState.CommandAck = commandAck; // We don't need to include a tick when sending -- it's in the packet RailStateDelta delta = RailResource.Instance.CreateDelta(); delta.Initialize(Tick.INVALID, entityId, deltaState, false); return(delta); }
public void ApplyDelta(RailStateDelta delta) { RailState deltaState = delta.State; HasImmutableData = delta.HasImmutableData || HasImmutableData; if (deltaState.HasImmutableData) { DataSerializer.ApplyImmutableFrom(deltaState.DataSerializer); } DataSerializer.ApplyMutableFrom(deltaState.DataSerializer, deltaState.Flags); DataSerializer.ResetControllerData(); if (deltaState.HasControllerData) { DataSerializer.ApplyControllerFrom(deltaState.DataSerializer); } HasControllerData = delta.HasControllerData; }
internal void ApplyDelta(RailStateDelta delta) { RailState deltaState = delta.State; this.ApplyMutableFrom(deltaState, deltaState.Flags); this.ResetControllerData(); if (deltaState.HasControllerData) { this.ApplyControllerFrom(deltaState); } this.HasControllerData = delta.HasControllerData; this.HasImmutableData = delta.HasImmutableData || this.HasImmutableData; if (deltaState.HasImmutableData) { this.ApplyImmutableFrom(deltaState); } }
private void UpdateControlStatus(RailEntity entity, RailStateDelta delta) { // Can't infer anything if the delta is an empty frozen update if (delta.IsFrozen) return; if (delta.HasControllerData) { if (entity.Controller == null) this.serverPeer.GrantControl(entity); } else { if (entity.Controller != null) this.serverPeer.RevokeControl(entity); } }
private void ProcessDelta(RailStateDelta delta) { RailEntity entity; if (this.knownEntities.TryGetValue(delta.EntityId, out entity) == false) { RailDebug.Assert(delta.IsFrozen == false, "Frozen unknown entity"); if (delta.IsFrozen) return; entity = delta.ProduceEntity(); entity.AssignId(delta.EntityId); this.pendingEntities.Add(entity.Id, entity); this.knownEntities.Add(entity.Id, entity); } entity.ReceiveDelta(delta); this.UpdateControlStatus(entity, delta); }
internal static RailStateDelta DecodeDelta( RailBitBuffer buffer, Tick packetTick) { RailStateDelta delta = RailResource.Instance.CreateDelta(); RailState state = null; // Read: [EntityId] EntityId entityId = buffer.ReadEntityId(); // Read: [IsFrozen] bool isFrozen = buffer.ReadBool(); if (isFrozen == false) { // Read: [FactoryType] int factoryType = buffer.ReadInt(RailState.FactoryTypeCompressor); state = RailState.Create(factoryType); // Read: [IsRemoved] bool isRemoved = buffer.ReadBool(); if (isRemoved) { // Read: [DestroyedTick] state.RemovedTick = buffer.ReadTick(); // End Read } else { // Read: [HasControllerData] state.HasControllerData = buffer.ReadBool(); // Read: [HasImmutableData] state.HasImmutableData = buffer.ReadBool(); // Read: [Flags] state.Flags = buffer.Read(state.FlagBits); // Read: [Mutable Data] state.DecodeMutableData(buffer, state.Flags); if (state.HasControllerData) { // Read: [Controller Data] state.DecodeControllerData(buffer); // Read: [Command Ack] state.CommandAck = buffer.ReadTick(); } if (state.HasImmutableData) { // Read: [Immutable Data] state.DecodeImmutableData(buffer); } } } delta.Initialize(packetTick, entityId, state, isFrozen); return(delta); }