public async void Send(DataFrameState state, bool urgent)
    {
        // только изменения бит и пинг
        if (!urgent && DateTime.UtcNow - _time < _delay)
        {
            return;
        }

        // только изменения бит
        //if (!urgent)
        //{
        //	return;
        //}

        _time      = DateTime.UtcNow;
        state.Time = _time.ToBinary();
        var handle = GCHandle.Alloc(_bufferFrameOut, GCHandleType.Pinned);

        Marshal.StructureToPtr(state, handle.AddrOfPinnedObject(), false);
        handle.Free();

        await _netSocket.SendMatchStateAsync(
            _netMatch.Id,
            OP_CODE_STATE,
            Convert.ToBase64String(_bufferFrameOut));
    }
 public void PushRemote(DataFrameState frame)
 {
     lock (_framesRemote)
     {
         var indexNext = (_indexCurrent + 1) % _framesRemote.Length;
         _framesRemote[indexNext] = frame;
         _indexCurrent            = indexNext;
     }
 }
    public static void FrameSwap(ref DataFrameState container)
    {
        var temp = new DataFrameState();

        // local to local
        temp.PaddleLocalSpeed             = container.PaddleLocalSpeed;
        temp.PaddleLocalPosition          = container.PaddleLocalPosition;
        temp.PaddleLocalReflectorOffset   = container.PaddleLocalReflectorOffset;
        temp.PaddleLocalReflectorHalfSize = container.PaddleLocalReflectorHalfSize;
        // remote to local
        container.PaddleLocalSpeed             = container.PaddleRemoteSpeed;
        container.PaddleLocalPosition          = container.PaddleRemotePosition;
        container.PaddleLocalReflectorOffset   = container.PaddleRemoteReflectorOffset;
        container.PaddleLocalReflectorHalfSize = container.PaddleRemoteReflectorHalfSize;
        // local to remote
        container.PaddleRemoteSpeed             = temp.PaddleLocalSpeed;
        container.PaddleRemotePosition          = temp.PaddleLocalPosition;
        container.PaddleRemoteReflectorOffset   = temp.PaddleLocalReflectorOffset;
        container.PaddleRemoteReflectorHalfSize = temp.PaddleLocalReflectorHalfSize;
    }
    public bool ApplyCorrection(ref DataFrameState state)
    {
        var delta = _timeTarget - DateTime.FromBinary(state.Time);

        if (delta.TotalSeconds > 0)
        {
            return(true);
        }

        // must full path increment sequence (this approx)
        _targetBallPos += _targetBallSpeed * (float)delta.TotalSeconds;

        state.BallPositionX = _targetBallPos.x;
        state.BallPositionY = _targetBallPos.y;
        state.BallSpeedX    = _targetBallSpeed.x;
        state.BallSpeedY    = _targetBallSpeed.y;

        Debug.Log("apply correction");

        return(false);
    }
    public ControllerSimPhase(DataFrameState stateFrame, DataBallState stateBall, IObstacle[] obstacles)
    {
        Debug.Log("predicting");

        var maxPath      = Mathf.Sqrt(1f + Composition.DataMeta.CourtRatio) * 2f;
        var currentSpeed = stateBall.Speed.magnitude;

        stateBall.DeltaTime = maxPath / currentSpeed;
        var bounce = stateBall;

        if (FindBounce(ref bounce, obstacles))
        {
            _timeTarget      = DateTime.FromBinary(stateFrame.Time) + TimeSpan.FromSeconds(bounce.DeltaTime);
            _targetBallPos   = bounce.Position;
            _targetBallSpeed = bounce.Speed;

            Debug.DrawLine(_targetBallPos, stateBall.Position, Color.red, 20f);
        }
        else
        {
            throw new Exception("undef");
        }
    }
 public ControllerSim()
 {
     _frame = Composition.FrameConsent(
         Composition.DataMeta,
         Composition.NetState);
 }
 public void SetTimeStamp(ref DataFrameState target)
 {
     target.Time = IsLead
                     ? DateTime.UtcNow.ToBinary()
                     : (DateTime.UtcNow + _approxClockLag).ToBinary();
 }