protected override void OnCreate()
    {
        commandBufferSystem = World.GetOrCreateSystem <BeginInitializationEntityCommandBufferSystem>();
        effectSystem        = World.GetOrCreateSystem <EffectRequestSystem>();

        // get entities that define players
        players = GetEntityQuery(new EntityQueryDesc {
            All = new ComponentType[] {
                ComponentType.ReadOnly <Translation>(),
                ComponentType.ReadOnly <Rotation>(),
                ComponentType.ReadOnly <PlayerShoot>()
            }
        });

        waterBullets = GetEntityQuery(new EntityQueryDesc {
            All = new ComponentType[] {
                typeof(Translation),
                typeof(Scale),
                ComponentType.ReadOnly <WaterShootIndex>(),
                typeof(PhysicsCollider),
                typeof(BulletDamage)
            }
        });

        ScheduleWeapon none = (PlayerShootJobData jobData, JobHandle deps) => deps;

        weaponSchedulers.Add(PlayerStats.WeaponTypes.Basic, ScheduleBasicWeapon);
        weaponSchedulers.Add(PlayerStats.WeaponTypes.Water, ScheduleWaterWeapon);
        weaponSchedulers.Add(PlayerStats.WeaponTypes.Basic | PlayerStats.WeaponTypes.Water,
                             ScheduleBoostBasicWaterWeapon);
    }
    protected override void OnCreate()
    {
        // get other systems
        commandBufferSystem = World.GetOrCreateSystem <BeginInitializationEntityCommandBufferSystem>();
        effectSystem        = World.GetOrCreateSystem <EffectRequestSystem>();
        buildPhysWorld      = World.GetOrCreateSystem <BuildPhysicsWorld>();
        stepPhysWorld       = World.GetOrCreateSystem <StepPhysicsWorld>();

        int numTypes = Enum.GetValues(typeof(ObjectType)).Length;

        groups = new EntityQuery[numTypes];
        groups[(int)ObjectType.Player] = GetEntityQuery(new EntityQueryDesc {
            All = new ComponentType[] {
                ComponentType.ReadOnly <Player>(),
                typeof(Health),
                ComponentType.ReadOnly <Translation>()
            }
        });
        groups[(int)ObjectType.Enemy] = GetEntityQuery(new EntityQueryDesc {
            All = new ComponentType[] {
                ComponentType.ReadOnly <Enemy>(),
                typeof(Health),
                ComponentType.ReadOnly <Translation>()
            }
        });
        groups[(int)ObjectType.PlayerBullet] = GetEntityQuery(new EntityQueryDesc {
            All = new ComponentType[] {
                ComponentType.ReadOnly <PlayerBullet>(),
                ComponentType.ReadOnly <BulletDamage>()
            }
        });
        groups[(int)ObjectType.EnemyBullet] = GetEntityQuery(new EntityQueryDesc {
            All = new ComponentType[] {
                ComponentType.ReadOnly <EnemyBullet>(),
                ComponentType.ReadOnly <BulletDamage>()
            }
        });

        // TODO: update with more flexible way of looking up physics layers
        masks = new uint[numTypes];
        masks[(int)ObjectType.Player]       = 1 << 3;
        masks[(int)ObjectType.Enemy]        = 1 << 1;
        masks[(int)ObjectType.PlayerBullet] = 1 << 2;
        masks[(int)ObjectType.EnemyBullet]  = 1 << 0;

        // init slots in the dictionaries
        collisions.Add(ObjectType.Player, new NativeMultiHashMap <Entity, CollisionInfo>());
        collisions.Add(ObjectType.Enemy, new NativeMultiHashMap <Entity, CollisionInfo>());
        damageMaps.Add(ObjectType.PlayerBullet, new NativeHashMap <Entity, BulletDamage>());
        damageMaps.Add(ObjectType.EnemyBullet, new NativeHashMap <Entity, BulletDamage>());
    }