WinstonHartnett / recs

Archetypal ECS
MIT License
0 stars 0 forks source link

Dependency tracking #3

Open WinstonHartnett opened 2 years ago

WinstonHartnett commented 2 years ago

With parallel systems, we can't allow unrestricted component access, so I need some mechanism of scoping resources in systems. Something like:

cmap @(Read, Read, Write) (\(MkPosition (a, b), MkFlying, MkWhatever _) -> undefined)

or with a snazzy ecstasy-like API:

emap $ do
  p <- get @Position
  v <- get @Velocity
  if v ^. #x >= 50
    then do
      _ <- get @Whatever
     set MkFlying
    else pure ()

shortened to

emap $ do
  (p, v) <- liftA2 (,) (get @Position) (get @Velocity)
  if v ^. #x >= 50 then get @Whatever >> set MkFlying else pure ()

and the underlying type stores the read & write union... <- this is the hard part

TODO

WinstonHartnett commented 2 years ago

This design works well AFAICT:

mySystem =
  emap (optional @Whatever @IO <..> write @(Velocity, Flying, VelocityUpdated))
    (do
      MkVelocity v <- with
      if v >= 50
        then branch @(Whatever, VelocityUpdated) >> tag MkFlying >> untag @VelocityUpdated
        else tag (MkVelocity $ v + 1.0)

The first argument to emap is a Query x m a type that tracks (1) store access rights in its type and (2) specifies the filtering routine for runtime archetype graph traversal. Theoretically, you could run some code in the Query itself but that might be a tad dangerous. The <..> is a dummy helper that joins two queries.~

The do block is a System x m a. The x parameter makes sure the system only accesses components that have been declared. branch is a helper that short-circuits when the optional target components are not attached to an entity.

The above posted example is, equivalently:

emap (read @(Position, Velocity) <..> optional @Whatever <..> write @Flying) $ do
  MkVelocity v <- with
  when (v.x >= 50) (branch @Whatever >> set MkFlying)

Question: (see above TODO) Any way to infer x without explicit dependencies? Maybe a typechecker plugin?