public void Update(double time, float3 playerPosition, float3 targetPosition, bool testing = false)
        {
            var unit = testing ? fetch_random(time) : fetch_input(time, playerPosition, targetPosition);

            if (_buffer.Length < _buffer.Capacity)
            {
                _buffer.Add(unit);
            }
            if (Input.GetButtonDown("Submit"))
            {
                var filename = "controller.bin";
                Debug.Log("dump file to:" + filename);
                ControllerBuffer.Save(_buffer, filename);
                Debug.Log("done.");
            }

            if (!unit.Toward && _buffer.Length >= 2)
            {
                for (var i = _buffer.Length - 2; i >= 0; --i)
                {
                    var oldUnit = _buffer[i];
                    if (oldUnit.Toward)
                    {
                        oldUnit.Condition = unit.Condition;
                        _buffer[i]        = oldUnit;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            _currentUnit = unit;
        }
        public void ControllerManater_replay()
        {
            var random = new Random();

            random.InitState(1234567);

            using (var buffer = new NativeList <ControllerUnit>(ControllerBuffer.MaxFrames, Allocator.Persistent)) {
                const int NUM    = 10;
                double    time   = 0;
                var       device = new ControllerDevice(buffer);
                for (var i = 0; i < NUM; ++i)
                {
                    var ppos = new float3(1000, 1000, 1000);
                    var tpos = new float3(0, 0, 0);
                    device.Update(time, ppos, tpos, true /* testing */);
                    time += 1.0 / 60.0;
                }
                Assert.AreEqual(NUM, buffer.Length);

                var filename = "test2.bin";
                ControllerBuffer.Save(buffer, filename);

                using (var buffer2 = ControllerBuffer.Load <ControllerUnit>(filename)) {
                    //var replay = new ControllerReplay();
                    for (var i = 0; i < NUM; ++i)
                    {
                        var ppos  = new float3(1000, 1000, 1000);
                        var tpos  = new float3(0, 0, 0);
                        var unitA = buffer[i];
                        var unitB = buffer2[i];
                        Assert.AreEqual(unitA, unitB);
                    }
                }
            }
        }
        protected override void OnCreate()
        {
            _entityCommandBufferSystem = World.GetOrCreateSystem <BeginInitializationEntityCommandBufferSystem>();
            _buildPhysicsWorldSystem   = World.GetOrCreateSystem <BuildPhysicsWorld>();

            _query = GetEntityQuery(new EntityQueryDesc()
            {
                All = new ComponentType[] {
                    ComponentType.ReadOnly <Translation>(),
                    ComponentType.ReadOnly <Rotation>(),
                    typeof(PhysicsVelocity),
                    ComponentType.ReadOnly <PhysicsMass>(),
                    typeof(FighterComponent),
                },
            });
            _targetableQuery = GetEntityQuery(new EntityQueryDesc()
            {
                All = new ComponentType[] {
                    ComponentType.ReadOnly <FighterTargetable>(),
                },
            });

#if SEARCHING
            cast_collider_ = SphereCollider.Create(new float3(0, 0, 0) /* center */,
                                                   1f /* radius */,
                                                   new CollisionFilter {
                BelongsTo    = ~0u,
                CollidesWith = ~0u,
            },
                                                   null /* material */);

            // create approximate hexagonal directions.
            //      2
            //   6     4
            //      0
            //   5     3
            //      1
            local_search_rotations_    = new NativeArray <quaternion>(FighterConfig.SEARCH_NUM, Allocator.Persistent);
            local_search_rotations_[0] = quaternion.Euler(0, 0, 0);
            local_search_rotations_[1] = quaternion.Euler(math.radians(10f), 0, 0);
            local_search_rotations_[2] = quaternion.Euler(math.radians(-10f), 0, 0);
            local_search_rotations_[3] = quaternion.Euler(math.radians(5f), math.radians(5f * 1.7320508f), 0);
            local_search_rotations_[4] = quaternion.Euler(math.radians(-5f), math.radians(5f * 1.7320508f), 0);
            local_search_rotations_[5] = quaternion.Euler(math.radians(5f), math.radians(-5f * 1.7320508f), 0);
            local_search_rotations_[6] = quaternion.Euler(math.radians(-5f), math.radians(-5f * 1.7320508f), 0);
#endif

            _lastPrimaryFighterPos = new NativeArray <float3>(1, Allocator.Persistent);
            _lastPrimaryTargetPos  = new NativeArray <float3>(1, Allocator.Persistent);
        #if RECORDING
            controller_buffer_ = new NativeList <ControllerUnit>(ControllerBuffer.MAX_FRAMES, Allocator.Persistent);
            controller_device_ = new ControllerDevice(controller_buffer_);
            controller_device_.start(Time.GetCurrent());
        #else
            _controllerBuffer = ControllerBuffer.Load <ControllerUnit>("controller.bin");
        #endif
        }