hecs icon indicating copy to clipboard operation
hecs copied to clipboard

Scoped alternative to World API with granular dynamic borrow checking

Open kabergstrom opened this issue 3 years ago • 4 comments

This PR implements a scoped API that mirrors much of the World API, but does component-level borrow checking at runtime instead of relying on static borrow checking. See ErgoScope.

Still have a few improvements to do, and I hope to expand the API to include queries, but hopefully I can get some feedback on the design and implementation.

The primary use for this is more straight-forward gameplay code by avoiding mutable borrows on World, but also

  • Supporting arbitrarily deep callbacks that can modify any world state, while having ComponentRefs active
  • Supporting interacting with World from languages that don't support compile time borrow checking

kabergstrom avatar Jan 22 '22 22:01 kabergstrom

I recently realized that with the indirection for data access that exists, it'd be possible to keep component references around between scopes, and just patch up the data pointer on scope exit/enter. Of course, actual access when a scope isn't active would panic. I imagine this could be nice as a way of storing persistent component references in scripts for example. What do you think @Ralith ?

kabergstrom avatar Feb 04 '22 08:02 kabergstrom

It's an intersecting prospect. Off the cuff, I'm concerned that it would be very easy to capture pseudo-references that might be unpredictably invalidated while the scope is inactive. For example, if you have a script/task that gets a component, then waits, then manipulates that component, it would be prone to panicing if the associated entity was despawned for any reason. Would this be too large a footgun?

Ralith avatar Feb 04 '22 22:02 Ralith

I think we can provide try_read/try_write functions for borrowing, so that errors can be propagated within the scripting environment as opposed to panicking. This would be equivalent to a null reference exception in Unity's C# for example, where the behaviour is similar to what you're talking about. Game objects & components can be destroyed between wait points of coroutines, in which case a null reference exception is thrown on access.

For what it's worth, in a game, you often can't define lifetimes of objects statically. Coroutines do have to handle dynamic conditions like objects being destroyed between wait points, as it can be the reality of the gameplay rules.

kabergstrom avatar Feb 05 '22 12:02 kabergstrom

I wrote a small simulation to test how it is to use the API

https://github.com/kabergstrom/cogito/blob/master/src/main.rs

kabergstrom avatar Aug 14 '22 01:08 kabergstrom