active-logic / activelogic-cs Goto Github PK
View Code? Open in Web Editor NEWBehavior Trees and Case Logic for C#7
License: GNU Affero General Public License v3.0
Behavior Trees and Case Logic for C#7
License: GNU Affero General Public License v3.0
Many md links are currently broken
AL_BEST_PERF
does not have a practical use; using AL with this flag turned on is not sane, and simple profiling (along with performance guidelines) will suffice.
Considering:
status Step() => Sequence()[
and ? A :
and ? B : repeat] && Wait(1f);
In this and related cases, even if A and B return done immediately, the ordered sequence still requires 2 frames to complete. This will then introduce a discontinuity that resets the Wait decorator, potentially causing a freeze.
NOTE: for the repeat
terminal see #36
This is because Wait needs a reset after use, which isn't convenient, and may be unexpected
Covering reset management and concurrency operators may be good.
Would prefer doing this around a concrete example, perhaps from Kabuki?
Currently time related decorators (Wait, Cooldown, Timeout, ...) use Unity engine time or default to System (.NET) time. This is not welcoming to other game engines.
Also does not help when a different time representation is used; in a TBS for example, a 'turn' may be the high level time unit, used alongside "game time".
Likely the overhead of an indirection here would not be significant.
Other than inheriting MonoBehaviour
there is no difference between Task
and UTask
; imp. - perhaps adding a Howl feature?
With a sequence A && B && C, whereas stateless evaluation will move to B without delay if A is done
, the equivalent ordered sequence will only evaluate A, leaving further evaluation to the next frame.
This conflicts with the RoR feature (#35); RoR leniency patches the issue, however this is not ideal.
Fixing this requires changing the ordered composite syntax.
While coverage issue is being investigated alt configs are disabled. Re-enable them after fixing coverage issues
Quick-start looks broken in places and should refer updated ordered composite syntax
For logging purposes status constants (done, cont, fail) are postfixed with a ()
which may optionally include logging information:
return done(log && "All caught up");
Without disregarding #28, test-oriented workflows are less dependent on logging and, overall, an option to use plain status constants would be welcome.
Still unclear whether both plain and annotated status constants may coexist in the same class (it only looks impossible). That isn't really a problem though.
Also, marginal performance gains with raw constants.
Semantics for certainties are too complex.
status
naming convention - done
, cont
, fail
UTask
supports hashing composites; not seeing a TaskComposites
equiv.
Needed, even though the library is self contained and does not require anything special
Reset-on-Resume (RoR) is a relatively new feature in Active Logic. Experiments show that Reset-on-Resume is not dependable enough, since it may cause issues when repeating tasks seamlessly (see #37)
Reset-on-Exit is safer, and may be implemented as follows:
roe DoSomething() => `cx() && Wait(0.5) && ... ;
Or
roe DoSomething(){
// some preliminary work
return cx() && Once()?[ task ] ... ;
}
Above syntax is primarily attractive because it does not require delimiters; other syntaxes are possible; this may come with a few desirable features:
cx()
and roe
are interdependent, so one cannot accidentally be used without another (compile check)In places, AL has object-context functions looking like:
action Do(object arg){ return @void(); }
These functions serve no purpose other than integrating (mostly assignment calls) with expression bodied members, however they are still useful. As part of updating certainties, it would be nice to look into this.
Considerations:
status
static context, making them widely available (DRY).Do
is correctly formulated as an action, design-wise likely as not we want done
or cont
.Do
and Run
as separate functions may be good since it clarifies the return type better than prefixing a unary op.Try
function may be nice.A while back drafted a utility to help with Mecanim integration; want a common interface covering legacy and Mecanim, for simple animation needs
Avoid having to convert certainties to status
before applying unary ops.
After the next Asset Store release a dev branch will be needed. This is because APIs are still evolving, along with documentation; on master, doc should reflect what is available in the Asset Store.
Stateful constructs: most decorators; ordered composites, mutable composites
Reset on resume: if control has not entered a branch for one or more frames, upon re-entry the stateful construct should reset.
Benefit
With many stateful constructs the expectation when an agent dropped the associate task for a while, is that state related to said task should revert to its default state. Invoking Reset() manually is possible, however manually managing decorator state is not desirable.
Now that RoR is in place, a simple wait statement should be possible
After updating certainties undef()
does not support convert to pending/impending anymore. If this is really useful, fix it; otherwise, remove.
Decorator related log data may be conflated.
Does not impact functionality, but we have 2-3 implementations of gate and status ref which are very closely related.
Right now it is not obvious whether this can be done or not, because null-conditional decorators rely on typing, and how far generification can help with this is unclear.
Generic gate:
namespace Active.Core{
public readonly struct Gate<T> where T : AbstractDecorator{
readonly T owner; readonly LogData logData;
internal Gate(T owner, LogData logData)
{ this.owner = owner; this.logData = logData; }
public StatusRef this[status s]{ get{
#if !AL_OPTIMIZE
owner.target = s.targetScope;
#endif
owner.OnStatus(s);
return new StatusRef(s, logData);
}}
}}
Works when moving target
and a couple other things to AbstractDecorator
, however type dependency on StatusRef
, which may be touchier.
This is to track current work towards automating log-traces.
Found some success setting up AspectInjector but this is not easy to integrate with Unity. Having a look at Mono.Cecil (which AspectInjector at least partially relies on) as it's likely a faster way to investigate related issues, and may suffice for the purpose.
Originally Once
was implemented as a (thread safe) conditional. As such it returns:
cont
until the decorated task succeeds or fails (good)done
or fail
upon task completion (good)fail
throughout later iterations, and until reset (bad)In the third case, Once
should retain and return the final status of the decorated task.
There isn't a solution here that's going to be compatible with thread pooling but, thread safety is on a best effort basis, not a requirement across the board.
Rarely used the Once
decorator until recently. Seems a good alternative to ordered composites in a typical workflow, where stateless by default works well, and stateful nodes are ~1/10.
In the near future, all certainties (loop
, pending
, impending
, ...) will be implicitly convertible to status as we take a more integer approach to the certainties API.
Current approach, where a certainty is convertible to status via labeling (loop.forever && status
) is a wooden shield. It does not actively prevent errors, only expose contradiction semantically. With that, conversions still occur, so the referred limitations already apply.
Pedantic &
forms (such as the current action & status
in lieu of action && status
) will be dropped. Although logically correct this creates a situation where a single &
, used accidentally and causing unwanted pseudo-parallelism, does not really stand out.
Could be just me but scanning the readme I see "explicit data structures" and "visual programming" which is pretty much the opposite of what this library does.
Commonly known composites effect the next task if the prior task has succeeded (sequence) or failed (selector); although I initially did not see a use for this the alternative effects the next task while the prior task is running.
For example:
1 - play an animation (walk) @while
moving forward.
2 - keep a light on while there is power
So, in some cases the result of A ⨀ B is independent of B, in others, such as when B represents a needed resource, failing B will also fail A.
Ideally this would implementing using shorting operators. With C# shorting operators are exhausted (there are 2); decorators may be used.
Implicit conversion from bool has the disadvantage that little logging info is provided in this case (other than "it came from bool").
Still, explicit conversion from bool is too much hassle.
RoR decorators reset on re-entry. That is, an RoR-enabled decorator will reset if control skips ticking the decorator for one frame or more.
This is somewhat different from the conventional reset on exit behavior seen in some BT libraries.
With cycling tasks, RoR may cause unexpected results:
status Step() => Once()?[ A ] && B
Repeating invocations of Step
do not cycle A and B. This is because the Once
decorator is ticked at every frame.
AL does not enforce a "parent node" concept; investigating.
Currently there isn't a decorator for applying an action to a list of target objects.
For example, if we had an IEnumerable list of waypoints, we may wish to visit all waypoints in turn; maybe something like:
@for(waypoints)?[ Reach ] // Reach: Func<T, status>
@forall
would do the same assuming parallelism.
Ordered composites have the end
and loop
terminals.
end
finalizes the state of a composite, in that an ended sequence will always return done
, whereas an ended selector will always return fail
, until the underlying ordered composite is reset.cont
, also resetting the underlying task iterator.Currently we lack a repeat
mode allowing a composite to reset the task iterator on success/failure. This is inconvenient because many tasks are repeatable.
Considering Coverlet, likely integrated with Coveralls
The plan is to do this via Travis, as seen here. Also relevant: ms doc for publishing NuGet packages
Need to formulate business/indie/personal licenses.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.