fastx commited on
Commit
00437a9
·
1 Parent(s): e537fb3

Upload 64 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
data/2.5D Physics.txt ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Introduction
2
+ Using 2.5D Physics you are able to add Height, or thickness depending on your perspective, while still benefiting from most performance advantages available in 2D. N.B.: Use Vertical Transform has to be manually enabled in the SimulationConfig asset's Physics settings.
3
+
4
+ Back To Top
5
+
6
+
7
+ 2.5D Physics With Vertical Data
8
+ StaticCollider2D can have 'thickness' in the 3rd dimension using Quantum's 2.5D physics; simply set the Height:
9
+
10
+ Adding Height to a Static Collider
11
+ Adding Height to a Static Collider.
12
+ For Entities, just add the Transform2DVertical component and set its Height and Position. On a Quantum XZ-oriented game, this adds height on the Y axis, for example. N.B.: Transform2DVertical requires the Transform2D component.
13
+
14
+ var transform2dVertical = new Transform2DVertical();
15
+ transform2dVertical.Height = FP._1;
16
+ transform2dVertical.Position = FP._1;
17
+
18
+ f.Set(entity, transform2dVertical);
19
+ Adding Height to an Entity Prototype
20
+ Adding Height to an Entity Prototype.
21
+ If entities or statics have a 3rd dimension, the physics engine will take into consideration when solving collisions. This allows for 'aerial' entities to fly over 'ground-based' ones, etc.
22
+
23
+ Back To Top
24
+
25
+
26
+ Physics Engine Implications
27
+
28
+ Entity Separation
29
+ Important: When a collision is detected, the collision solver does not use the extra dimension information. This can result in entity bounce when separation is performed on the basic 2D plane of the physics engine.
30
+
31
+ It is possible to simulate 3-dimensional gravity by manually applying speed and forces directly on Transform2DVertical.Position. The physics engine will use that information only for collision detection though.
data/AIAction.cs ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using Photon.Deterministic;
3
+
4
+ namespace Quantum
5
+ {
6
+ public abstract unsafe partial class AIAction
7
+ {
8
+ public string Label;
9
+ public const int NEXT_ACTION_DEFAULT = -1;
10
+
11
+ public abstract void Update(Frame frame, EntityRef entity);
12
+ public virtual int NextAction(Frame frame, EntityRef entity) { return NEXT_ACTION_DEFAULT; }
13
+ }
14
+ }
data/AIAction.qtn ADDED
@@ -0,0 +1 @@
 
 
1
+ asset AIAction;
data/AIBlackboard.cs ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+ using System.Collections.Generic;
4
+
5
+ namespace Quantum
6
+ {
7
+ public unsafe partial class AIBlackboard
8
+ {
9
+ public AIBlackboardEntry[] Entries;
10
+
11
+ [NonSerialized] public Dictionary<String, Int32> Map;
12
+
13
+ public override void Loaded(IResourceManager resourceManager, Native.Allocator allocator)
14
+ {
15
+ base.Loaded(resourceManager, allocator);
16
+
17
+ Map = new Dictionary<string, Int32>();
18
+
19
+ for (Int32 i = 0; i < Entries.Length; i++)
20
+ {
21
+ Map.Add(Entries[i].Key.Key, i);
22
+ }
23
+ }
24
+
25
+ public Int32 GetEntryID(string key)
26
+ {
27
+ Assert.Check(string.IsNullOrEmpty(key) == false, "The Key cannot be empty or null.");
28
+ Assert.Check(Map.ContainsKey(key) == true, $"Key {0} not present in the Blackboard", key);
29
+
30
+ return Map[key];
31
+ }
32
+
33
+ public bool TryGetEntryID(string key, out Int32 id)
34
+ {
35
+ return Map.TryGetValue(key, out id);
36
+ }
37
+
38
+ public string GetEntryName(Int32 id)
39
+ {
40
+ return Entries[id].Key.Key;
41
+ }
42
+
43
+ public bool HasEntry(string key)
44
+ {
45
+ for (int i = 0; i < Entries.Length; i++)
46
+ {
47
+ if (Entries[i].Key.Key == key)
48
+ {
49
+ return true;
50
+ }
51
+ }
52
+
53
+ return false;
54
+ }
55
+
56
+ public AIBlackboardEntry GetEntry(string key)
57
+ {
58
+ for (int i = 0; i < Entries.Length; i++)
59
+ {
60
+ if (Entries[i].Key.Key == key)
61
+ {
62
+ return Entries[i];
63
+ }
64
+ }
65
+
66
+ return default;
67
+ }
68
+ }
69
+ }
data/AIBlackboardComponent.cs ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+ using Quantum.Collections;
4
+
5
+ namespace Quantum
6
+ {
7
+ public unsafe partial struct AIBlackboardComponent
8
+ {
9
+ #region Init/Free
10
+ public void InitializeBlackboardComponent(Frame frame, AIBlackboard blackboardAsset)
11
+ {
12
+ Board = blackboardAsset;
13
+
14
+ var assetEntries = blackboardAsset.Entries;
15
+
16
+ if (Entries.Ptr != default)
17
+ {
18
+ FreeBlackboardComponent(frame);
19
+ }
20
+
21
+ QList<BlackboardEntry> entriesList = frame.AllocateList<BlackboardEntry>(blackboardAsset.Entries.Length);
22
+
23
+ for (int i = 0; i < assetEntries.Length; i++)
24
+ {
25
+ BlackboardValue newValue = CreateValueFromEntry(assetEntries[i]);
26
+ entriesList.Add(new BlackboardEntry { Value = newValue });
27
+ //entriesList.Add(newValue);
28
+ }
29
+
30
+ Entries = entriesList;
31
+ }
32
+
33
+ public void FreeBlackboardComponent(Frame frame)
34
+ {
35
+ if (Entries.Ptr != default)
36
+ {
37
+ frame.FreeList(Entries);
38
+ Entries = default;
39
+ }
40
+ }
41
+
42
+ private BlackboardValue CreateValueFromEntry(AIBlackboardEntry entry)
43
+ {
44
+ BlackboardValue newValue = new BlackboardValue();
45
+
46
+ if (entry.Type == AIBlackboardValueType.Boolean)
47
+ {
48
+ *newValue.BooleanValue = default;
49
+ }
50
+
51
+ if (entry.Type == AIBlackboardValueType.Byte)
52
+ {
53
+ *newValue.ByteValue = default;
54
+ }
55
+
56
+ if (entry.Type == AIBlackboardValueType.Integer)
57
+ {
58
+ *newValue.IntegerValue = default;
59
+ }
60
+
61
+ if (entry.Type == AIBlackboardValueType.FP)
62
+ {
63
+ *newValue.FPValue = default;
64
+ }
65
+
66
+ if (entry.Type == AIBlackboardValueType.Vector2)
67
+ {
68
+ *newValue.FPVector2Value = default;
69
+ }
70
+
71
+ if (entry.Type == AIBlackboardValueType.Vector3)
72
+ {
73
+ *newValue.FPVector3Value = default;
74
+ }
75
+
76
+ if (entry.Type == AIBlackboardValueType.EntityRef)
77
+ {
78
+ *newValue.EntityRefValue = default;
79
+ }
80
+
81
+ return newValue;
82
+ }
83
+ #endregion
84
+
85
+ #region Getters
86
+ public QBoolean GetBoolean(Frame frame, string key)
87
+ {
88
+ var bbValue = GetBlackboardValue(frame, key);
89
+ return *bbValue.BooleanValue;
90
+ }
91
+
92
+ public byte GetByte(Frame frame, string key)
93
+ {
94
+ var bbValue = GetBlackboardValue(frame, key);
95
+ return *bbValue.ByteValue;
96
+ }
97
+
98
+ public Int32 GetInteger(Frame frame, string key)
99
+ {
100
+ var bbValue = GetBlackboardValue(frame, key);
101
+ return *bbValue.IntegerValue;
102
+ }
103
+
104
+ public FP GetFP(Frame frame, string key)
105
+ {
106
+ var bbValue = GetBlackboardValue(frame, key);
107
+ return *bbValue.FPValue;
108
+ }
109
+
110
+ public FPVector2 GetVector2(Frame frame, string key)
111
+ {
112
+ var bbValue = GetBlackboardValue(frame, key);
113
+ return *bbValue.FPVector2Value;
114
+ }
115
+
116
+ public FPVector3 GetVector3(Frame frame, string key)
117
+ {
118
+ var bbValue = GetBlackboardValue(frame, key);
119
+ return *bbValue.FPVector3Value;
120
+ }
121
+
122
+ public EntityRef GetEntityRef(Frame frame, string key)
123
+ {
124
+ var bbValue = GetBlackboardValue(frame, key);
125
+ return *bbValue.EntityRefValue;
126
+ }
127
+ #endregion
128
+
129
+ #region Setters
130
+ public BlackboardEntry* Set(Frame frame, string key, QBoolean value)
131
+ {
132
+ QList<BlackboardEntry> valueList = frame.ResolveList(Entries);
133
+ var ID = GetID(frame, key);
134
+ *valueList.GetPointer(ID)->Value.BooleanValue = value;
135
+
136
+ return valueList.GetPointer(ID);
137
+ }
138
+
139
+ public BlackboardEntry* Set(Frame frame, string key, byte value)
140
+ {
141
+ QList<BlackboardEntry> valueList = frame.ResolveList(Entries);
142
+ var ID = GetID(frame, key);
143
+ *valueList.GetPointer(ID)->Value.ByteValue = value;
144
+
145
+ return valueList.GetPointer(ID);
146
+ }
147
+
148
+ public BlackboardEntry* Set(Frame frame, string key, Int32 value)
149
+ {
150
+ QList<BlackboardEntry> valueList = frame.ResolveList(Entries);
151
+ var ID = GetID(frame, key);
152
+ *valueList.GetPointer(ID)->Value.IntegerValue = value;
153
+
154
+ return valueList.GetPointer(ID);
155
+ }
156
+
157
+ public BlackboardEntry* Set(Frame frame, string key, FP value)
158
+ {
159
+ QList<BlackboardEntry> valueList = frame.ResolveList(Entries);
160
+ var ID = GetID(frame, key);
161
+ *valueList.GetPointer(ID)->Value.FPValue = value;
162
+
163
+ return valueList.GetPointer(ID);
164
+ }
165
+
166
+ public BlackboardEntry* Set(Frame frame, string key, FPVector2 value)
167
+ {
168
+ QList<BlackboardEntry> valueList = frame.ResolveList(Entries);
169
+ var ID = GetID(frame, key);
170
+ *valueList.GetPointer(ID)->Value.FPVector2Value = value;
171
+
172
+ return valueList.GetPointer(ID);
173
+ }
174
+
175
+ public BlackboardEntry* Set(Frame frame, string key, FPVector3 value)
176
+ {
177
+ QList<BlackboardEntry> valueList = frame.ResolveList(Entries);
178
+ var ID = GetID(frame, key);
179
+ *valueList.GetPointer(ID)->Value.FPVector3Value = value;
180
+
181
+ return valueList.GetPointer(ID);
182
+
183
+ }
184
+
185
+ public BlackboardEntry* Set(Frame frame, string key, EntityRef value)
186
+ {
187
+ QList<BlackboardEntry> valueList = frame.ResolveList(Entries);
188
+ var ID = GetID(frame, key);
189
+ *valueList.GetPointer(ID)->Value.EntityRefValue = value;
190
+
191
+ return valueList.GetPointer(ID);
192
+ }
193
+ #endregion
194
+
195
+ #region Helpers
196
+ public BlackboardEntry* GetBlackboardEntry(Frame frame, string key)
197
+ {
198
+ var bbAsset = frame.FindAsset<AIBlackboard>(Board.Id);
199
+ var ID = bbAsset.GetEntryID(key);
200
+ var values = frame.ResolveList(Entries);
201
+ return values.GetPointer(ID);
202
+ }
203
+
204
+ public BlackboardValue GetBlackboardValue(Frame frame, string key)
205
+ {
206
+ Assert.Check(string.IsNullOrEmpty(key) == false, "The Key cannot be empty or null.");
207
+
208
+ var bbAsset = frame.FindAsset<AIBlackboard>(Board.Id);
209
+ var ID = bbAsset.GetEntryID(key);
210
+ var values = frame.ResolveList(Entries);
211
+
212
+ return values[ID].Value;
213
+ }
214
+
215
+ public Int32 GetID(Frame frame, string key)
216
+ {
217
+ Assert.Check(string.IsNullOrEmpty(key) == false, "The Key cannot be empty or null.");
218
+
219
+ var bbAsset = frame.FindAsset<AIBlackboard>(Board.Id);
220
+ var ID = bbAsset.GetEntryID(key);
221
+
222
+ return ID;
223
+ }
224
+
225
+ public bool HasEntry(Frame frame, string key)
226
+ {
227
+ var boardAsset = frame.FindAsset<AIBlackboard>(Board.Id);
228
+ return boardAsset.HasEntry(key);
229
+ }
230
+ #endregion
231
+
232
+ #region BT Specific
233
+ public void RegisterReactiveDecorator(Frame frame, string key, BTDecorator decorator)
234
+ {
235
+ var blackboardEntry = GetBlackboardEntry(frame, key);
236
+
237
+ QList<AssetRefBTDecorator> reactiveDecorators;
238
+ if (blackboardEntry->ReactiveDecorators.Ptr == default)
239
+ {
240
+ reactiveDecorators = frame.AllocateList<AssetRefBTDecorator>();
241
+ }
242
+ else
243
+ {
244
+ reactiveDecorators = frame.ResolveList<AssetRefBTDecorator>(blackboardEntry->ReactiveDecorators);
245
+ }
246
+ reactiveDecorators.Add(decorator);
247
+
248
+ blackboardEntry->ReactiveDecorators = reactiveDecorators;
249
+ }
250
+
251
+ public void UnregisterReactiveDecorator(Frame frame, string key, BTDecorator decorator)
252
+ {
253
+ var blackboardEntry = GetBlackboardEntry(frame, key);
254
+
255
+ if (blackboardEntry->ReactiveDecorators.Ptr != default)
256
+ {
257
+ QList<AssetRefBTDecorator> reactiveDecorators = frame.ResolveList<AssetRefBTDecorator>(blackboardEntry->ReactiveDecorators);
258
+ reactiveDecorators.Remove(decorator);
259
+ blackboardEntry->ReactiveDecorators = reactiveDecorators;
260
+ }
261
+ }
262
+ #endregion
263
+
264
+ #region Debug
265
+ public void Dump(Frame frame)
266
+ {
267
+ string dumpText = "";
268
+ var bbAsset = frame.FindAsset<AIBlackboard>(Board.Id);
269
+ dumpText += "Blackboard Path and ID: " + bbAsset.Path + " | " + Board.Id.Value;
270
+
271
+ var valuesList = frame.ResolveList(Entries);
272
+ for (int i = 0; i < valuesList.Count; i++)
273
+ {
274
+ string value = "NONE";
275
+ if (valuesList[i].Value.Field == BlackboardValue.BOOLEANVALUE) value = valuesList[i].Value.BooleanValue->Value.ToString();
276
+ if (valuesList[i].Value.Field == BlackboardValue.BYTEVALUE) value = valuesList[i].Value.ByteValue->ToString();
277
+ if (valuesList[i].Value.Field == BlackboardValue.INTEGERVALUE) value = valuesList[i].Value.IntegerValue->ToString();
278
+ if (valuesList[i].Value.Field == BlackboardValue.FPVALUE) value = valuesList[i].Value.FPValue->ToString();
279
+ if (valuesList[i].Value.Field == BlackboardValue.FPVECTOR2VALUE) value = valuesList[i].Value.FPVector2Value->ToString();
280
+ if (valuesList[i].Value.Field == BlackboardValue.FPVECTOR3VALUE) value = valuesList[i].Value.FPVector3Value->ToString();
281
+ if (valuesList[i].Value.Field == BlackboardValue.ENTITYREFVALUE) value = valuesList[i].Value.EntityRefValue->ToString();
282
+
283
+ dumpText += "\nName: " + bbAsset.GetEntryName(i) + ", Value: " + value;
284
+ }
285
+
286
+ Log.Info(dumpText);
287
+ }
288
+ #endregion
289
+ }
290
+ }
data/AIBlackboardEntry.cs ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace Quantum
4
+ {
5
+ // This struct is stored on the blackboard asset
6
+ // It is NOT the one used on the Blackboard component
7
+ [Serializable]
8
+ public struct AIBlackboardEntry
9
+ {
10
+ public AIBlackboardValueType Type;
11
+ public AIBlackboardValueKey Key;
12
+ }
13
+ }
data/AIBlackboardInitializer.cs ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+
4
+ namespace Quantum
5
+ {
6
+ public unsafe partial class AIBlackboardInitializer
7
+ {
8
+ [Serializable]
9
+ public struct AIBlackboardInitialValue
10
+ {
11
+ public Boolean AsBoolean;
12
+ public Byte AsByte;
13
+ public Int32 AsInteger;
14
+ public FP AsFP;
15
+ public FPVector2 AsFPVector2;
16
+ public FPVector3 AsFPVector3;
17
+ public EntityRef AsEntityRef;
18
+ }
19
+
20
+ [Serializable]
21
+ public struct AIBlackboardInitialValueEntry
22
+ {
23
+ public string Key;
24
+ public AIBlackboardInitialValue Value;
25
+ }
26
+
27
+ public bool ReportMissingEntries = true;
28
+
29
+ public AssetRefAIBlackboard AIBlackboard;
30
+ public AIBlackboardInitialValueEntry[] InitialValues;
31
+
32
+
33
+ public unsafe static void InitializeBlackboard(Frame frame, AIBlackboardComponent* blackboard, AIBlackboardInitializer blackboardInitializer, AIBlackboardInitialValueEntry[] blackboardOverrides = null)
34
+ {
35
+ AIBlackboard board = frame.FindAsset<AIBlackboard>(blackboardInitializer.AIBlackboard.Id);
36
+
37
+ blackboard->InitializeBlackboardComponent(frame, board);
38
+
39
+ ApplyEntries(frame, blackboard, blackboardInitializer, blackboardInitializer.InitialValues);
40
+ ApplyEntries(frame, blackboard, blackboardInitializer, blackboardOverrides);
41
+ }
42
+
43
+ public unsafe static void ApplyEntries(Frame frame, AIBlackboardComponent* blackboard, AIBlackboardInitializer blackboardInitializer, AIBlackboardInitialValueEntry[] values)
44
+ {
45
+ if (values == null) return;
46
+
47
+ for (int i = 0; i < values.Length; i++)
48
+ {
49
+ string key = values[i].Key;
50
+ if (blackboard->HasEntry(frame, key) == false)
51
+ {
52
+ if (blackboardInitializer.ReportMissingEntries)
53
+ {
54
+ Quantum.Log.Warn($"Blackboard {blackboard->Board} does not have an entry with a key called '{key}'");
55
+ }
56
+ continue;
57
+ }
58
+
59
+ BlackboardValue value = blackboard->GetBlackboardValue(frame, key);
60
+ switch (value.Field)
61
+ {
62
+ case BlackboardValue.BOOLEANVALUE:
63
+ blackboard->Set(frame, key, values[i].Value.AsBoolean);
64
+ break;
65
+ case BlackboardValue.BYTEVALUE:
66
+ blackboard->Set(frame, key, values[i].Value.AsByte);
67
+ break;
68
+ case BlackboardValue.ENTITYREFVALUE:
69
+ blackboard->Set(frame, key, values[i].Value.AsEntityRef);
70
+ break;
71
+ case BlackboardValue.FPVALUE:
72
+ blackboard->Set(frame, key, values[i].Value.AsFP);
73
+ break;
74
+ case BlackboardValue.INTEGERVALUE:
75
+ blackboard->Set(frame, key, values[i].Value.AsInteger);
76
+ break;
77
+ case BlackboardValue.FPVECTOR2VALUE:
78
+ blackboard->Set(frame, key, values[i].Value.AsFPVector2);
79
+ break;
80
+ case BlackboardValue.FPVECTOR3VALUE:
81
+ blackboard->Set(frame, key, values[i].Value.AsFPVector3);
82
+ break;
83
+ }
84
+ }
85
+ }
86
+ }
87
+ }
data/AIBlackboardValueKey.cs ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace Quantum
4
+ {
5
+ // Wrapping the blackboard value key inside a struct gives us a nice way to overload the Unity inspector.
6
+ [Serializable]
7
+ public struct AIBlackboardValueKey
8
+ {
9
+ public String Key;
10
+ }
11
+ }
data/AIBlackboardValueType.cs ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 
2
+ namespace Quantum
3
+ {
4
+ public enum AIBlackboardValueType
5
+ {
6
+ Boolean,
7
+ Byte,
8
+ Integer,
9
+ FP,
10
+ Vector2,
11
+ Vector3,
12
+ EntityRef
13
+ }
14
+ }
data/AIConfig.cs ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+ using System.Collections.Generic;
4
+
5
+ namespace Quantum
6
+ {
7
+ public partial class AIConfig : AssetObject
8
+ {
9
+ public enum EValueType
10
+ {
11
+ None,
12
+ Int,
13
+ Bool,
14
+ Byte,
15
+ FP,
16
+ FPVector2,
17
+ FPVector3,
18
+ String,
19
+ EntityRef,
20
+ }
21
+
22
+ [Serializable]
23
+ public class KeyValuePair
24
+ {
25
+ public string Key;
26
+ public EValueType Type;
27
+ public Value Value;
28
+ }
29
+
30
+ [Serializable]
31
+ public struct Value
32
+ {
33
+ public Int32 Integer;
34
+ public Boolean Boolean;
35
+ public Byte Byte;
36
+ public FP FP;
37
+ public FPVector2 FPVector2;
38
+ public FPVector3 FPVector3;
39
+ public string String;
40
+ public EntityRef EntityRef;
41
+ }
42
+
43
+ public int Count { get { return KeyValuePairs.Count; } }
44
+
45
+ public AssetRefAIConfig DefaultConfig;
46
+ public List<KeyValuePair> KeyValuePairs = new List<KeyValuePair>(32);
47
+
48
+ public KeyValuePair Get(string key)
49
+ {
50
+ for (int i = 0; i < KeyValuePairs.Count; i++)
51
+ {
52
+ if (KeyValuePairs[i].Key == key)
53
+ return KeyValuePairs[i];
54
+ }
55
+
56
+ return null;
57
+ }
58
+
59
+ public void Set<T>(string key, T value)
60
+ {
61
+ if (string.IsNullOrEmpty(key) == true)
62
+ return;
63
+
64
+ KeyValuePair pair = Get(key);
65
+
66
+ if (pair == null)
67
+ {
68
+ pair = new KeyValuePair();
69
+ pair.Key = key;
70
+ KeyValuePairs.Add(pair);
71
+ }
72
+
73
+ Set(pair, value);
74
+ }
75
+
76
+ private void Set<T>(KeyValuePair pair, T value)
77
+ {
78
+ if (value is int intValue)
79
+ {
80
+ pair.Type = EValueType.Int;
81
+ pair.Value.Integer = intValue;
82
+ }
83
+ else if (value is bool boolValue)
84
+ {
85
+ pair.Type = EValueType.Bool;
86
+ pair.Value.Boolean = boolValue;
87
+ }
88
+ else if (value is Byte byteValue)
89
+ {
90
+ pair.Type = EValueType.Byte;
91
+ pair.Value.Byte = byteValue;
92
+ }
93
+ else if (value is FP fpValue)
94
+ {
95
+ pair.Type = EValueType.FP;
96
+ pair.Value.FP = fpValue;
97
+ }
98
+ else if (value is FPVector2 fpVector2Value)
99
+ {
100
+ pair.Type = EValueType.FPVector2;
101
+ pair.Value.FPVector2 = fpVector2Value;
102
+ }
103
+ else if (value is FPVector3 fpVector3Value)
104
+ {
105
+ pair.Type = EValueType.FPVector3;
106
+ pair.Value.FPVector3 = fpVector3Value;
107
+ }
108
+ else if (value is string stringValue)
109
+ {
110
+ pair.Type = EValueType.String;
111
+ pair.Value.String = stringValue;
112
+ }
113
+ else if (value is EntityRef entityRefValue)
114
+ {
115
+ pair.Type = EValueType.EntityRef;
116
+ pair.Value.EntityRef = entityRefValue;
117
+ }
118
+ else
119
+ {
120
+ throw new NotSupportedException(string.Format("AIConfig - Type not supported. Type: {0} Key: {1}", typeof(T), pair.Key));
121
+ }
122
+ }
123
+ }
124
+ }
data/AIConfig.qtn ADDED
@@ -0,0 +1 @@
 
 
1
+ asset AIConfig;
data/AIFunction.qtn ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ asset AIFunctionByte;
2
+ asset AIFunctionBool;
3
+ asset AIFunctionInt;
4
+ asset AIFunctionFP;
5
+ asset AIFunctionFPVector2;
6
+ asset AIFunctionFPVector3;
7
+ asset AIFunctionEntityRef;
data/AIFunctionAND.cs ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace Quantum
2
+ {
3
+ [System.Serializable]
4
+ public unsafe partial class AIFunctionAND : AIFunctionBool
5
+ {
6
+ public AIParamBool ValueA;
7
+ public AIParamBool ValueB;
8
+
9
+ public override bool Execute(Frame frame, EntityRef entity)
10
+ {
11
+ return ValueA.ResolveFunction(frame, entity) && ValueB.ResolveFunction(frame, entity);
12
+ }
13
+ }
14
+ }
data/AIFunctionBool.cs ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace Quantum
2
+ {
3
+ public unsafe abstract partial class AIFunctionBool
4
+ {
5
+ public abstract bool Execute(Frame frame, EntityRef entity);
6
+ }
7
+
8
+ [BotSDKHidden]
9
+ [System.Serializable]
10
+ public unsafe partial class DefaultAIFunctionBool : AIFunctionBool
11
+ {
12
+ public override bool Execute(Frame frame, EntityRef entity)
13
+ {
14
+ return false;
15
+ }
16
+ }
17
+ }
data/AIFunctionByte.cs ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace Quantum
2
+ {
3
+ public unsafe abstract partial class AIFunctionByte
4
+ {
5
+ public abstract byte Execute(Frame frame, EntityRef entity);
6
+ }
7
+
8
+ [BotSDKHidden]
9
+ [System.Serializable]
10
+ public unsafe partial class DefaultAIFunctionByte : AIFunctionByte
11
+ {
12
+ public override byte Execute(Frame frame, EntityRef entity)
13
+ {
14
+ return 0;
15
+ }
16
+ }
17
+ }
data/AIFunctionEntityRef.cs ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace Quantum
2
+ {
3
+ public unsafe abstract partial class AIFunctionEntityRef
4
+ {
5
+ public abstract EntityRef Execute(Frame frame, EntityRef entity);
6
+ }
7
+
8
+ [BotSDKHidden]
9
+ [System.Serializable]
10
+ public unsafe partial class DefaultAIFunctionEntityRef : AIFunctionEntityRef
11
+ {
12
+ public override EntityRef Execute(Frame frame, EntityRef entity)
13
+ {
14
+ return default(EntityRef);
15
+ }
16
+ }
17
+ }
data/AIFunctionFP.cs ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+
3
+ namespace Quantum
4
+ {
5
+ public abstract unsafe partial class AIFunctionFP
6
+ {
7
+ public abstract FP Execute(Frame frame, EntityRef entity);
8
+ }
9
+
10
+ [BotSDKHidden]
11
+ [System.Serializable]
12
+ public unsafe partial class DefaultAIFunctionFP : AIFunctionFP
13
+ {
14
+ public override FP Execute(Frame frame, EntityRef entity)
15
+ {
16
+ return FP._0;
17
+ }
18
+ }
19
+ }
data/AIFunctionFPVector2.cs ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+
3
+ namespace Quantum
4
+ {
5
+ public unsafe abstract partial class AIFunctionFPVector2
6
+ {
7
+ public abstract FPVector2 Execute(Frame frame, EntityRef entity);
8
+ }
9
+
10
+ [BotSDKHidden]
11
+ [System.Serializable]
12
+ public unsafe partial class DefaultAIFunctionFPVector2 : AIFunctionFPVector2
13
+ {
14
+ public override FPVector2 Execute(Frame frame, EntityRef entity)
15
+ {
16
+ return FPVector2.Zero;
17
+ }
18
+ }
19
+ }
data/AIFunctionFPVector3.cs ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+
3
+ namespace Quantum
4
+ {
5
+ public unsafe abstract partial class AIFunctionFPVector3
6
+ {
7
+ public abstract FPVector3 Execute(Frame frame, EntityRef entity);
8
+ }
9
+
10
+ [BotSDKHidden]
11
+ [System.Serializable]
12
+ public unsafe partial class DefaultAIFunctionFPVector3 : AIFunctionFPVector3
13
+ {
14
+ public override FPVector3 Execute(Frame frame, EntityRef entity)
15
+ {
16
+ return FPVector3.Zero;
17
+ }
18
+ }
19
+ }
data/AIFunctionInt.cs ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace Quantum
2
+ {
3
+ public unsafe abstract partial class AIFunctionInt
4
+ {
5
+ public abstract int Execute(Frame frame, EntityRef entity);
6
+ }
7
+
8
+ [BotSDKHidden]
9
+ [System.Serializable]
10
+ public unsafe partial class DefaultAIFunctionInt : AIFunctionInt
11
+ {
12
+ public override int Execute(Frame frame, EntityRef entity)
13
+ {
14
+ return 0;
15
+ }
16
+ }
17
+ }
data/AIFunctionNOT.cs ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace Quantum
2
+ {
3
+ [System.Serializable]
4
+ public unsafe partial class AIFunctionNOT : AIFunctionBool
5
+ {
6
+ public AIParamBool Value;
7
+
8
+ public override bool Execute(Frame frame, EntityRef entity)
9
+ {
10
+ return !Value.ResolveFunction(frame, entity);
11
+ }
12
+ }
13
+ }
data/AIFunctionOR.cs ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace Quantum
2
+ {
3
+ [System.Serializable]
4
+ public unsafe partial class AIFunctionOR : AIFunctionBool
5
+ {
6
+ public AIParamBool ValueA;
7
+ public AIParamBool ValueB;
8
+
9
+ public override bool Execute(Frame frame, EntityRef entity)
10
+ {
11
+ return ValueA.ResolveFunction(frame, entity) || ValueB.ResolveFunction(frame, entity);
12
+ }
13
+ }
14
+ }
data/AIParam.Types.cs ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+
4
+ namespace Quantum
5
+ {
6
+ [System.Serializable]
7
+ public unsafe sealed class AIParamInt : AIParam<int>
8
+ {
9
+ public static implicit operator AIParamInt(int value) { return new AIParamInt() { DefaultValue = value }; }
10
+
11
+ public AssetRefAIFunctionInt FunctionRef;
12
+
13
+ [NonSerialized] private AIFunctionInt _cachedFunction;
14
+
15
+ protected override int GetBlackboardValue(BlackboardValue value)
16
+ {
17
+ return *value.IntegerValue;
18
+ }
19
+
20
+ protected override int GetConfigValue(AIConfig.KeyValuePair configPair)
21
+ {
22
+ return configPair.Value.Integer;
23
+ }
24
+
25
+ protected override int GetFunctionValue(Frame frame, EntityRef entity)
26
+ {
27
+ if (_cachedFunction == null)
28
+ {
29
+ _cachedFunction = frame.FindAsset<AIFunctionInt>(FunctionRef.Id);
30
+ }
31
+
32
+ return _cachedFunction.Execute(frame, entity);
33
+ }
34
+ }
35
+
36
+ [System.Serializable]
37
+ public unsafe sealed class AIParamBool : AIParam<bool>
38
+ {
39
+ public static implicit operator AIParamBool(bool value) { return new AIParamBool() { DefaultValue = value }; }
40
+
41
+ public AssetRefAIFunctionBool FunctionRef;
42
+
43
+ [NonSerialized] private AIFunctionBool _cachedFunction;
44
+
45
+ protected override bool GetBlackboardValue(BlackboardValue value)
46
+ {
47
+ return *value.BooleanValue;
48
+ }
49
+
50
+ protected override bool GetConfigValue(AIConfig.KeyValuePair configPair)
51
+ {
52
+ return configPair.Value.Boolean;
53
+ }
54
+
55
+ protected override bool GetFunctionValue(Frame frame, EntityRef entity)
56
+ {
57
+ if (_cachedFunction == null)
58
+ {
59
+ _cachedFunction = frame.FindAsset<AIFunctionBool>(FunctionRef.Id);
60
+ }
61
+
62
+ return _cachedFunction.Execute(frame, entity);
63
+ }
64
+ }
65
+
66
+ [System.Serializable]
67
+ public unsafe sealed class AIParamByte : AIParam<byte>
68
+ {
69
+ public static implicit operator AIParamByte(byte value) { return new AIParamByte() { DefaultValue = value }; }
70
+
71
+ public AssetRefAIFunctionByte FunctionRef;
72
+
73
+ [NonSerialized] private AIFunctionByte _cachedFunction;
74
+
75
+ protected override byte GetBlackboardValue(BlackboardValue value)
76
+ {
77
+ return *value.ByteValue;
78
+ }
79
+
80
+ protected override byte GetConfigValue(AIConfig.KeyValuePair configPair)
81
+ {
82
+ return configPair.Value.Byte;
83
+ }
84
+
85
+ protected override byte GetFunctionValue(Frame frame, EntityRef entity)
86
+ {
87
+ if (_cachedFunction == null)
88
+ {
89
+ _cachedFunction = frame.FindAsset<AIFunctionByte>(FunctionRef.Id);
90
+ }
91
+
92
+ return _cachedFunction.Execute(frame, entity);
93
+ }
94
+ }
95
+
96
+ [System.Serializable]
97
+ public unsafe sealed class AIParamFP : AIParam<FP>
98
+ {
99
+ public static implicit operator AIParamFP(FP value) { return new AIParamFP() { DefaultValue = value }; }
100
+
101
+ public AssetRefAIFunctionFP FunctionRef;
102
+
103
+ [NonSerialized] private AIFunctionFP _cachedFunction;
104
+
105
+ protected override FP GetBlackboardValue(BlackboardValue value)
106
+ {
107
+ return *value.FPValue;
108
+ }
109
+
110
+ protected override FP GetConfigValue(AIConfig.KeyValuePair configPair)
111
+ {
112
+ return configPair.Value.FP;
113
+ }
114
+
115
+ protected override FP GetFunctionValue(Frame frame, EntityRef entity)
116
+ {
117
+ if (_cachedFunction == null)
118
+ {
119
+ _cachedFunction = frame.FindAsset<AIFunctionFP>(FunctionRef.Id);
120
+ }
121
+
122
+ return _cachedFunction.Execute(frame, entity);
123
+ }
124
+ }
125
+
126
+ [System.Serializable]
127
+ public unsafe sealed class AIParamFPVector2 : AIParam<FPVector2>
128
+ {
129
+ public static implicit operator AIParamFPVector2(FPVector2 value) { return new AIParamFPVector2() { DefaultValue = value }; }
130
+
131
+ public AssetRefAIFunctionFPVector2 FunctionRef;
132
+
133
+ [NonSerialized] private AIFunctionFPVector2 _cachedFunction;
134
+
135
+ protected override FPVector2 GetBlackboardValue(BlackboardValue value)
136
+ {
137
+ return *value.FPVector2Value;
138
+ }
139
+
140
+ protected override FPVector2 GetConfigValue(AIConfig.KeyValuePair configPair)
141
+ {
142
+ return configPair.Value.FPVector2;
143
+ }
144
+
145
+ protected override FPVector2 GetFunctionValue(Frame frame, EntityRef entity)
146
+ {
147
+ if (_cachedFunction == null)
148
+ {
149
+ _cachedFunction = frame.FindAsset<AIFunctionFPVector2>(FunctionRef.Id);
150
+ }
151
+
152
+ return _cachedFunction.Execute(frame, entity);
153
+ }
154
+ }
155
+
156
+ [System.Serializable]
157
+ public unsafe sealed class AIParamFPVector3 : AIParam<FPVector3>
158
+ {
159
+ public static implicit operator AIParamFPVector3(FPVector3 value) { return new AIParamFPVector3() { DefaultValue = value }; }
160
+
161
+ public AssetRefAIFunctionFPVector3 FunctionRef;
162
+
163
+ [NonSerialized] private AIFunctionFPVector3 _cachedFunction;
164
+
165
+ protected override FPVector3 GetBlackboardValue(BlackboardValue value)
166
+ {
167
+ return *value.FPVector3Value;
168
+ }
169
+
170
+ protected override FPVector3 GetConfigValue(AIConfig.KeyValuePair configPair)
171
+ {
172
+ return configPair.Value.FPVector3;
173
+ }
174
+
175
+ protected override FPVector3 GetFunctionValue(Frame frame, EntityRef entity)
176
+ {
177
+ if (_cachedFunction == null)
178
+ {
179
+ _cachedFunction = frame.FindAsset<AIFunctionFPVector3>(FunctionRef.Id);
180
+ }
181
+
182
+ return _cachedFunction.Execute(frame, entity);
183
+ }
184
+ }
185
+
186
+ [System.Serializable]
187
+ public unsafe sealed class AIParamString : AIParam<string>
188
+ {
189
+ public static implicit operator AIParamString(string value) { return new AIParamString() { DefaultValue = value }; }
190
+
191
+ protected override string GetBlackboardValue(BlackboardValue value)
192
+ {
193
+ throw new NotSupportedException("Blackboard variables as strings are not supported.");
194
+ }
195
+
196
+ protected override string GetConfigValue(AIConfig.KeyValuePair configPair)
197
+ {
198
+ return configPair.Value.String;
199
+ }
200
+
201
+ protected override string GetFunctionValue(Frame frame, EntityRef entity)
202
+ {
203
+ return default;
204
+ }
205
+ }
206
+
207
+ [System.Serializable]
208
+ public unsafe sealed class AIParamEntityRef : AIParam<EntityRef>
209
+ {
210
+ public static implicit operator AIParamEntityRef(EntityRef value) { return new AIParamEntityRef() { DefaultValue = value }; }
211
+
212
+ public AssetRefAIFunctionEntityRef FunctionRef;
213
+
214
+ [NonSerialized] private AIFunctionEntityRef _cachedFunction;
215
+
216
+ protected override EntityRef GetBlackboardValue(BlackboardValue value)
217
+ {
218
+ return *value.EntityRefValue;
219
+ }
220
+
221
+ protected override EntityRef GetConfigValue(AIConfig.KeyValuePair configPair)
222
+ {
223
+ return configPair.Value.EntityRef;
224
+ }
225
+
226
+ protected override EntityRef GetFunctionValue(Frame frame, EntityRef entity)
227
+ {
228
+ if (_cachedFunction == null)
229
+ {
230
+ _cachedFunction = frame.FindAsset<AIFunctionEntityRef>(FunctionRef.Id);
231
+ }
232
+
233
+ return _cachedFunction.Execute(frame, entity);
234
+ }
235
+ }
236
+ }
data/AIParam.cs ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace Quantum
4
+ {
5
+ public enum AIParamSource
6
+ {
7
+ None,
8
+ Value,
9
+ Config,
10
+ Blackboard,
11
+ Function,
12
+ }
13
+
14
+ [Serializable]
15
+ public abstract unsafe class AIParam<T>
16
+ {
17
+ public AIParamSource Source = AIParamSource.Value;
18
+ public string Key;
19
+ public T DefaultValue;
20
+
21
+ /// <summary>
22
+ /// Use this to solve the AIParam value when the source of the value is unkown
23
+ /// </summary>
24
+ public T Resolve(Frame frame, EntityRef entity, AIBlackboardComponent* blackboard, AIConfig aiConfig)
25
+ {
26
+ if (Source == AIParamSource.Value || (Source != AIParamSource.Function && string.IsNullOrEmpty(Key) == true))
27
+ return DefaultValue;
28
+
29
+ switch (Source)
30
+ {
31
+ case AIParamSource.Blackboard:
32
+ BlackboardValue blackboardValue = blackboard->GetBlackboardValue(frame, Key);
33
+ return GetBlackboardValue(blackboardValue);
34
+
35
+ case AIParamSource.Config:
36
+ AIConfig.KeyValuePair configPair = aiConfig != null ? aiConfig.Get(Key) : null;
37
+ return configPair != null ? GetConfigValue(configPair) : DefaultValue;
38
+
39
+ case AIParamSource.Function:
40
+ return GetFunctionValue(frame, entity);
41
+ }
42
+
43
+ return default(T);
44
+ }
45
+
46
+ /// <summary>
47
+ /// Use this if the it is known that the AIParam stores specifically a Blackboard value
48
+ /// </summary>
49
+ public unsafe T ResolveBlackboard(Frame frame, AIBlackboardComponent* blackboard)
50
+ {
51
+ BlackboardValue blackboardValue = blackboard->GetBlackboardValue(frame, Key);
52
+ return GetBlackboardValue(blackboardValue);
53
+ }
54
+
55
+ /// <summary>
56
+ /// Use this if the it is known that the AIParam stores specifically a Config value
57
+ /// </summary>
58
+ public unsafe T ResolveConfig(Frame frame, AIConfig aiConfig)
59
+ {
60
+ AIConfig.KeyValuePair configPair = aiConfig != null ? aiConfig.Get(Key) : null;
61
+ return configPair != null ? GetConfigValue(configPair) : DefaultValue;
62
+ }
63
+
64
+ /// <summary>
65
+ /// Use this if the it is known that the AIParam stores specifically a Func
66
+ /// </summary>
67
+ public unsafe T ResolveFunction(Frame frame, EntityRef entity)
68
+ {
69
+ return GetFunctionValue(frame, entity);
70
+ }
71
+
72
+ protected abstract T GetBlackboardValue(BlackboardValue value);
73
+ protected abstract T GetConfigValue(AIConfig.KeyValuePair configPair);
74
+ protected abstract T GetFunctionValue(Frame frame, EntityRef entity);
75
+ }
76
+ }
data/AIParamExtensions.cs ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace Quantum
2
+ {
3
+ public static unsafe partial class AIParamExtensions
4
+ {
5
+ public static T ResolveFromHFSM<T>(this AIParam<T> aiParam, Frame frame, EntityRef entity)
6
+ {
7
+ var aiConfigRef = aiParam.Source == AIParamSource.Config
8
+ ? frame.Unsafe.GetPointer<HFSMAgent>(entity)->Config
9
+ : default;
10
+
11
+ return aiParam.Resolve(frame, entity, aiConfigRef);
12
+ }
13
+
14
+ public static T ResolveFromGOAP<T>(this AIParam<T> aiParam, Frame frame, EntityRef entity)
15
+ {
16
+ var aiConfigRef = aiParam.Source == AIParamSource.Config
17
+ ? frame.Unsafe.GetPointer<GOAPAgent>(entity)->Config
18
+ : default;
19
+
20
+ return aiParam.Resolve(frame, entity, aiConfigRef);
21
+ }
22
+
23
+ public static T ResolveFromBT<T>(this AIParam<T> aiParam, Frame frame, EntityRef entity)
24
+ {
25
+ var aiConfigRef = aiParam.Source == AIParamSource.Config
26
+ ? frame.Unsafe.GetPointer<BTAgent>(entity)->Config
27
+ : default;
28
+
29
+ return aiParam.Resolve(frame, entity, aiConfigRef);
30
+ }
31
+
32
+ public static T Resolve<T>(this AIParam<T> aiParam, Frame frame, EntityRef entity, AssetRefAIConfig aiConfigRef)
33
+ {
34
+ var blackboard = aiParam.Source == AIParamSource.Blackboard
35
+ ? frame.Unsafe.GetPointer<AIBlackboardComponent>(entity)
36
+ : null;
37
+
38
+ var aiConfig = aiParam.Source == AIParamSource.Config
39
+ ? frame.FindAsset<AIConfig>(aiConfigRef.Id)
40
+ : null;
41
+
42
+ return aiParam.Resolve(frame, entity, blackboard, aiConfig);
43
+ }
44
+ }
45
+ }
data/AssemblyInfo.cs ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System.Reflection;
2
+ using System.Runtime.InteropServices;
3
+
4
+ [assembly: AssemblyTitle("quantum.code")]
5
+ [assembly: AssemblyDescription("")]
6
+ [assembly: AssemblyConfiguration("")]
7
+ [assembly: AssemblyCompany("")]
8
+ [assembly: AssemblyProduct("quantum.code")]
9
+ [assembly: AssemblyCopyright("")]
10
+ [assembly: AssemblyTrademark("")]
11
+ [assembly: AssemblyCulture("")]
12
+ [assembly: ComVisible(false)]
13
+ [assembly: Guid("fbf32099-b197-4ab9-8e5a-b44d9d3750bd")]
14
+ [assembly: AssemblyVersion("2.0.0.0")]
15
+ [assembly: AssemblyFileVersion("2.0.0.0")]
16
+ [assembly: AssemblyInformationalVersion("2.0.0 RC2N 501 2.0/develop (99c627e06)")]
17
+
data/BTAbort.cs ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace Quantum
4
+ {
5
+ public enum BTAbort
6
+ {
7
+ None,
8
+ Self,
9
+ LowerPriority,
10
+ Both
11
+ }
12
+
13
+ public static class BTAbortExtensions
14
+ {
15
+ public static Boolean IsSelf(this BTAbort abort)
16
+ {
17
+ return abort == BTAbort.Self || abort == BTAbort.Both;
18
+ }
19
+
20
+ public static Boolean IsLowerPriority(this BTAbort abort)
21
+ {
22
+ return abort == BTAbort.LowerPriority || abort == BTAbort.Both;
23
+ }
24
+ }
25
+ }
data/BTAgent.User.Data.cs ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+
4
+ namespace Quantum
5
+ {
6
+ public unsafe partial struct BTAgent
7
+ {
8
+ #region Int and FP Data
9
+ // Getter / Setters of node FP and Int32 data
10
+ public void AddFPData(Frame frame, FP fpValue)
11
+ {
12
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
13
+ BTDataValue newDataValue = new BTDataValue();
14
+ *newDataValue.FPValue = fpValue;
15
+ nodesDataList.Add(newDataValue);
16
+ }
17
+
18
+ public void AddIntData(Frame frame, Int32 intValue)
19
+ {
20
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
21
+ BTDataValue newDataValue = new BTDataValue();
22
+ *newDataValue.IntValue = intValue;
23
+ nodesDataList.Add(newDataValue);
24
+ }
25
+
26
+ public void SetFPData(Frame frame, FP value, Int32 index)
27
+ {
28
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
29
+ *nodesDataList.GetPointer(index)->FPValue = value;
30
+ }
31
+
32
+ public void SetIntData(Frame frame, Int32 value, Int32 index)
33
+ {
34
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
35
+ *nodesDataList.GetPointer(index)->IntValue = value;
36
+ }
37
+
38
+ public FP GetFPData(Frame frame, Int32 index)
39
+ {
40
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
41
+ return *nodesDataList.GetPointer(index)->FPValue;
42
+ }
43
+
44
+ public Int32 GetIntData(Frame frame, Int32 index)
45
+ {
46
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
47
+ return *nodesDataList.GetPointer(index)->IntValue;
48
+ }
49
+ #endregion
50
+
51
+ // -- THREADSAFE
52
+
53
+ #region THREADSAFE Int and FP Data
54
+ // Getter / Setters of node FP and Int32 data
55
+ public void AddFPData(FrameThreadSafe frame, FP fpValue)
56
+ {
57
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
58
+ BTDataValue newDataValue = new BTDataValue();
59
+ *newDataValue.FPValue = fpValue;
60
+ nodesDataList.Add(newDataValue);
61
+ }
62
+
63
+ public void AddIntData(FrameThreadSafe frame, Int32 intValue)
64
+ {
65
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
66
+ BTDataValue newDataValue = new BTDataValue();
67
+ *newDataValue.IntValue = intValue;
68
+ nodesDataList.Add(newDataValue);
69
+ }
70
+
71
+ public void SetFPData(FrameThreadSafe frame, FP value, Int32 index)
72
+ {
73
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
74
+ *nodesDataList.GetPointer(index)->FPValue = value;
75
+ }
76
+
77
+ public void SetIntData(FrameThreadSafe frame, Int32 value, Int32 index)
78
+ {
79
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
80
+ *nodesDataList.GetPointer(index)->IntValue = value;
81
+ }
82
+
83
+ public FP GetFPData(FrameThreadSafe frame, Int32 index)
84
+ {
85
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
86
+ return *nodesDataList.GetPointer(index)->FPValue;
87
+ }
88
+
89
+ public Int32 GetIntData(FrameThreadSafe frame, Int32 index)
90
+ {
91
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
92
+ return *nodesDataList.GetPointer(index)->IntValue;
93
+ }
94
+ #endregion
95
+ }
96
+ }
data/BTAgent.User.cs ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+
4
+ namespace Quantum
5
+ {
6
+ public unsafe partial struct BTAgent
7
+ {
8
+ // Used to setup info on the Unity debugger
9
+ public string GetTreeAssetName(Frame frame) => frame.FindAsset<BTRoot>(Tree.Id).Path;
10
+
11
+ public bool IsAborting => AbortNodeId != 0;
12
+
13
+ public AIConfig GetConfig(Frame frame)
14
+ {
15
+ return frame.FindAsset<AIConfig>(Config.Id);
16
+ }
17
+
18
+ public void Initialize(Frame frame, EntityRef entityRef, BTAgent* agent, AssetRefBTNode tree, bool force = false)
19
+ {
20
+ if (this.Tree != default && force == false)
21
+ return;
22
+
23
+ // -- Cache the tree
24
+ BTRoot treeAsset = frame.FindAsset<BTRoot>(tree.Id);
25
+ this.Tree = treeAsset;
26
+
27
+ // -- Allocate data
28
+ // Success/Fail/Running
29
+ NodesStatus = frame.AllocateList<Byte>(treeAsset.NodesAmount);
30
+
31
+ // Next tick in which each service shall be updated
32
+ ServicesEndTimes = frame.AllocateList<FP>(4);
33
+
34
+ // Node data, such as FP for timers, Integers for IDs
35
+ BTDataValues = frame.AllocateList<BTDataValue>(4);
36
+
37
+ // The Services contained in the current sub-tree,
38
+ // which should be updated considering its intervals
39
+ ActiveServices = frame.AllocateList<AssetRefBTService>(4);
40
+
41
+ // The Dynamic Composites contained in the current sub-tree,
42
+ // which should be re-checked every tick
43
+ DynamicComposites = frame.AllocateList<AssetRefBTComposite>(4);
44
+
45
+ // -- Cache the Blackboard (if any)
46
+ AIBlackboardComponent* blackboard = null;
47
+ if (frame.Has<AIBlackboardComponent>(entityRef))
48
+ {
49
+ blackboard = frame.Unsafe.GetPointer<AIBlackboardComponent>(entityRef);
50
+ }
51
+
52
+ // -- Initialize the tree
53
+ treeAsset.InitializeTree(frame, agent, blackboard);
54
+
55
+ // -- Trigger the debugging event (mostly for the Unity side)
56
+ BTManager.OnSetupDebugger?.Invoke(entityRef, treeAsset.Path);
57
+ }
58
+
59
+ public void Free(Frame frame)
60
+ {
61
+ Tree = default;
62
+ frame.FreeList<Byte>(NodesStatus);
63
+ frame.FreeList<FP>(ServicesEndTimes);
64
+ frame.FreeList<BTDataValue>(BTDataValues);
65
+ frame.FreeList<AssetRefBTService>(ActiveServices);
66
+ frame.FreeList<AssetRefBTComposite>(DynamicComposites);
67
+ }
68
+
69
+ #region Int and FP Data
70
+ // Getter / Setters of node FP and Int32 data
71
+ public void AddFPData(Frame frame, FP fpValue)
72
+ {
73
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
74
+ BTDataValue newDataValue = new BTDataValue();
75
+ *newDataValue.FPValue = fpValue;
76
+ nodesDataList.Add(newDataValue);
77
+ }
78
+
79
+ public void AddIntData(Frame frame, Int32 intValue)
80
+ {
81
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
82
+ BTDataValue newDataValue = new BTDataValue();
83
+ *newDataValue.IntValue = intValue;
84
+ nodesDataList.Add(newDataValue);
85
+ }
86
+
87
+ public void SetFPData(Frame frame, FP value, Int32 index)
88
+ {
89
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
90
+ *nodesDataList.GetPointer(index)->FPValue = value;
91
+ }
92
+
93
+ public void SetIntData(Frame frame, Int32 value, Int32 index)
94
+ {
95
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
96
+ *nodesDataList.GetPointer(index)->IntValue = value;
97
+ }
98
+
99
+ public FP GetFPData(Frame frame, Int32 index)
100
+ {
101
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
102
+ return *nodesDataList.GetPointer(index)->FPValue;
103
+ }
104
+
105
+ public Int32 GetIntData(Frame frame, Int32 index)
106
+ {
107
+ var nodesDataList = frame.ResolveList<BTDataValue>(BTDataValues);
108
+ return *nodesDataList.GetPointer(index)->IntValue;
109
+ }
110
+ #endregion
111
+
112
+ public void Update(ref BTParams btParams)
113
+ {
114
+ if (btParams.Agent->Current == null)
115
+ {
116
+ btParams.Agent->Current = btParams.Agent->Tree;
117
+ }
118
+
119
+ RunDynamicComposites(btParams);
120
+
121
+ BTNode node = btParams.Frame.FindAsset<BTNode>(btParams.Agent->Current.Id);
122
+ UpdateSubtree(btParams, node);
123
+
124
+ BTManager.ClearBTParams(btParams);
125
+ }
126
+
127
+ // We run the dynamic composites contained on the current sub-tree (if any)
128
+ // If any of them result in "False", we abort the current sub-tree
129
+ // and take the execution back to the topmost decorator so the agent can choose another path
130
+ private void RunDynamicComposites(BTParams btParams)
131
+ {
132
+ var frame = btParams.Frame;
133
+ var dynamicComposites = frame.ResolveList<AssetRefBTComposite>(DynamicComposites);
134
+
135
+ for (int i = 0; i < dynamicComposites.Count; i++)
136
+ {
137
+ var compositeRef = dynamicComposites.GetPointer(i);
138
+ var composite = frame.FindAsset<BTComposite>(compositeRef->Id);
139
+ var dynamicResult = composite.OnDynamicRun(btParams);
140
+
141
+ if (dynamicResult == false)
142
+ {
143
+ btParams.Agent->Current = composite.TopmostDecorator;
144
+ dynamicComposites.Remove(*compositeRef);
145
+ composite.OnReset(btParams);
146
+ return;
147
+ }
148
+ }
149
+ }
150
+
151
+ private void UpdateSubtree(BTParams btParams, BTNode node, bool continuingAbort = false)
152
+ {
153
+ // Start updating the tree from the Current agent's node
154
+ var result = node.RunUpdate(btParams, continuingAbort);
155
+
156
+ // If the current node completes, go up in the tree until we hit a composite
157
+ // Run that one. On success or fail continue going up.
158
+ while (result != BTStatus.Running && node.Parent != null)
159
+ {
160
+ // As we are traversing the tree up, we allow nodes to remove any
161
+ // data that is only needed locally
162
+ node.OnExit(btParams);
163
+
164
+ node = node.Parent;
165
+ if (node.NodeType == BTNodeType.Composite)
166
+ {
167
+ ((BTComposite)node).ChildCompletedRunning(btParams, result);
168
+ result = node.RunUpdate(btParams, continuingAbort);
169
+ }
170
+
171
+ if (node.NodeType == BTNodeType.Decorator)
172
+ {
173
+ ((BTDecorator)node).EvaluateAbortNode(btParams);
174
+ }
175
+ }
176
+
177
+ BTService.TickServices(btParams);
178
+
179
+ if (result != BTStatus.Running)
180
+ {
181
+ BTNode tree = btParams.Frame.FindAsset<BTNode>(btParams.Agent->Tree.Id);
182
+ tree.OnReset(btParams);
183
+ btParams.Agent->Current = btParams.Agent->Tree;
184
+ BTManager.OnTreeCompleted?.Invoke(btParams.Entity);
185
+ //Log.Info("Behaviour Tree completed with result '{0}'. It will re-start from '{1}'", result, btParams.Agent->Current.Id);
186
+ }
187
+ }
188
+
189
+ public unsafe void AbortLowerPriority(BTParams btParams, BTNode node)
190
+ {
191
+ // Go up and find the next interesting node (composite or root)
192
+ var topNode = node;
193
+ while (
194
+ topNode.NodeType != BTNodeType.Composite &&
195
+ topNode.NodeType != BTNodeType.Root)
196
+ {
197
+ topNode = topNode.Parent;
198
+ }
199
+
200
+ if (topNode.NodeType == BTNodeType.Root)
201
+ {
202
+ return;
203
+ }
204
+
205
+ var nodeAsComposite = (topNode as BTComposite);
206
+ nodeAsComposite.AbortNodes(btParams, nodeAsComposite.GetCurrentChild(btParams.Frame, btParams.Agent) + 1);
207
+ }
208
+
209
+ // Used to react to blackboard changes which are observed by Decorators
210
+ // This is triggered by the Blackboard Entry itself, which has a list of Decorators that observes it
211
+ public unsafe void OnDecoratorReaction(BTParams btParams, BTNode node, BTAbort abort, out bool abortSelf, out bool abortLowerPriotity)
212
+ {
213
+ abortSelf = false;
214
+ abortLowerPriotity = false;
215
+
216
+ var status = node.GetStatus(btParams.Frame, btParams.Agent);
217
+
218
+ if (abort.IsSelf() && (status == BTStatus.Running || status == BTStatus.Inactive))
219
+ {
220
+ // Check condition again
221
+ if (node.DryRun(btParams) == false)
222
+ {
223
+ abortSelf = true;
224
+ node.OnAbort(btParams);
225
+ }
226
+ }
227
+
228
+ if (abort.IsLowerPriority())
229
+ {
230
+ AbortLowerPriority(btParams, node);
231
+ abortLowerPriotity = true;
232
+ }
233
+ }
234
+ }
235
+ }
data/BTBlackboardCompare.cs ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace Quantum
4
+ {
5
+ /// <summary>
6
+ /// Reactive Decorator sample. Listens to changes on two Blackboard entries.
7
+ /// </summary>
8
+ [Serializable]
9
+ public unsafe class BTBlackboardCompare : BTDecorator
10
+ {
11
+ // We let the user define, on the Visual Editor, which Blackboard entries
12
+ // shall be observed by this Decorator
13
+ public AIBlackboardValueKey BlackboardKeyA;
14
+ public AIBlackboardValueKey BlackboardKeyB;
15
+
16
+ public override void OnEnter(BTParams btParams)
17
+ {
18
+ base.OnEnter(btParams);
19
+
20
+ // Whenever we enter this Decorator...
21
+ // We register it as a Reactive Decorator so, whenever the entries are changed,
22
+ // the DryRun is executed again, possibly aborting the current execution
23
+ btParams.Blackboard->RegisterReactiveDecorator(btParams.Frame, BlackboardKeyA.Key, this);
24
+ btParams.Blackboard->RegisterReactiveDecorator(btParams.Frame, BlackboardKeyB.Key, this);
25
+ }
26
+
27
+ public override void OnExit(BTParams btParams)
28
+ {
29
+ base.OnExit(btParams);
30
+ // Whenever the execution goes higher, it means that this Decorator isn't in the current subtree anymore
31
+ // So we unregister this Decorator from the Reactive list. This means that if the Blackboard entries
32
+ // get changed, this Decorator will not react anymore
33
+ btParams.Blackboard->UnregisterReactiveDecorator(btParams.Frame, BlackboardKeyA.Key, this);
34
+ btParams.Blackboard->UnregisterReactiveDecorator(btParams.Frame, BlackboardKeyB.Key, this);
35
+ }
36
+
37
+ // We just check if A is greater than B. If that's the case
38
+ // PS: this gets called in THREE possible situations:
39
+ // 1 - When the execution is goign DOWN on the tree and this Decorator is found
40
+ // 2 - If changes to the observed blackboard entries happen
41
+ // 3 - If this is inside a Dynamic Composite node
42
+ public override Boolean DryRun(BTParams btParams)
43
+ {
44
+ var blackboard = btParams.Blackboard;
45
+ var A = blackboard->GetInteger(btParams.Frame, BlackboardKeyA.Key);
46
+ var B = blackboard->GetInteger(btParams.Frame, BlackboardKeyB.Key);
47
+
48
+ return A > B;
49
+ }
50
+ }
51
+ }
data/BTComposite.cs ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+
4
+ namespace Quantum
5
+ {
6
+ public unsafe abstract partial class BTComposite : BTNode
7
+ {
8
+ public AssetRefBTNode[] Children;
9
+ public AssetRefBTService[] Services;
10
+ [BotSDKHidden] public AssetRefBTNode TopmostDecorator;
11
+
12
+ public BTDataIndex CurrentChildIndex;
13
+
14
+ protected BTNode[] _childInstances;
15
+ protected BTService[] _serviceInstances;
16
+ protected BTNode _topmostDecoratorInstance;
17
+
18
+ public bool IsDynamic;
19
+
20
+ public BTNode[] ChildInstances
21
+ {
22
+ get
23
+ {
24
+ return _childInstances;
25
+ }
26
+ }
27
+
28
+ public BTService[] ServiceInstances
29
+ {
30
+ get
31
+ {
32
+ return _serviceInstances;
33
+ }
34
+ }
35
+
36
+ public override BTNodeType NodeType
37
+ {
38
+ get
39
+ {
40
+ return BTNodeType.Composite;
41
+ }
42
+ }
43
+
44
+ internal Int32 GetCurrentChild(Frame frame, BTAgent* agent)
45
+ {
46
+ Byte currentChild = (Byte)agent->GetIntData(frame, CurrentChildIndex.Index);
47
+ return currentChild;
48
+ }
49
+
50
+ internal void SetCurrentChild(Frame frame, Int32 currentIndex, BTAgent* agent)
51
+ {
52
+ agent->SetIntData(frame, currentIndex, CurrentChildIndex.Index);
53
+ }
54
+
55
+ /// <summary>
56
+ /// When a Composite node is Updated, it only increase the current child updated
57
+ /// when the child results in either FAIL/SUCCESS. So we need this callback
58
+ /// to be used when the child was RUNNING and then had some result, to properly increase the current
59
+ /// child ID
60
+ /// </summary>
61
+ /// <param name="btParams"></param>
62
+ /// <param name="childResult"></param>
63
+ internal virtual void ChildCompletedRunning(BTParams btParams, BTStatus childResult)
64
+ {
65
+ }
66
+
67
+ public override void Init(Frame frame, AIBlackboardComponent* blackboard, BTAgent* agent)
68
+ {
69
+ base.Init(frame, blackboard, agent);
70
+
71
+ agent->AddIntData(frame, 0);
72
+
73
+ for (Int32 i = 0; i < Services.Length; i++)
74
+ {
75
+ BTService service = frame.FindAsset<BTService>(Services[i].Id);
76
+ service.Init(frame, agent, blackboard);
77
+ }
78
+ }
79
+
80
+ public override void OnEnter(BTParams btParams)
81
+ {
82
+ BTManager.OnNodeEnter?.Invoke(btParams.Entity, Guid.Value);
83
+ SetCurrentChild(btParams.Frame, 0, btParams.Agent);
84
+ }
85
+
86
+ public override void OnEnterRunning(BTParams btParams)
87
+ {
88
+ var activeServicesList = btParams.Frame.ResolveList<AssetRefBTService>(btParams.Agent->ActiveServices);
89
+
90
+ for (Int32 i = 0; i < _serviceInstances.Length; i++)
91
+ {
92
+ _serviceInstances[i].OnEnter(btParams);
93
+
94
+ activeServicesList.Add(Services[i]);
95
+ }
96
+
97
+ if (IsDynamic == true)
98
+ {
99
+ var dynamicComposites = btParams.Frame.ResolveList<AssetRefBTComposite>(btParams.Agent->DynamicComposites);
100
+ dynamicComposites.Add(this);
101
+ }
102
+ }
103
+
104
+ public override void OnReset(BTParams btParams)
105
+ {
106
+ base.OnReset(btParams);
107
+
108
+ OnExit(btParams);
109
+
110
+ for (Int32 i = 0; i < _childInstances.Length; i++)
111
+ _childInstances[i].OnReset(btParams);
112
+ }
113
+
114
+ public override void OnExit(BTParams btParams)
115
+ {
116
+ base.OnExit(btParams);
117
+
118
+ BTManager.OnNodeExit?.Invoke(btParams.Entity, Guid.Value);
119
+
120
+ var activeServicesList = btParams.Frame.ResolveList<AssetRefBTService>(btParams.Agent->ActiveServices);
121
+ for (Int32 i = 0; i < _serviceInstances.Length; i++)
122
+ {
123
+ activeServicesList.Remove(Services[i]);
124
+ }
125
+
126
+ if (IsDynamic == true)
127
+ {
128
+ var dynamicComposites = btParams.Frame.ResolveList<AssetRefBTComposite>(btParams.Agent->DynamicComposites);
129
+ dynamicComposites.Remove(this);
130
+ }
131
+ }
132
+
133
+ public override bool OnDynamicRun(BTParams btParams)
134
+ {
135
+ if (_topmostDecoratorInstance != null)
136
+ {
137
+ return _topmostDecoratorInstance.OnDynamicRun(btParams);
138
+ }
139
+
140
+ return true;
141
+ }
142
+
143
+
144
+ public void AbortNodes(BTParams btParams, Int32 firstIndex = 0)
145
+ {
146
+ for (int i = firstIndex; i < _childInstances.Length; i++)
147
+ {
148
+ _childInstances[i].SetStatus(btParams.Frame, BTStatus.Abort, btParams.Agent);
149
+ }
150
+ }
151
+
152
+ public override void Loaded(IResourceManager resourceManager, Native.Allocator allocator)
153
+ {
154
+ base.Loaded(resourceManager, allocator);
155
+
156
+ // Cache the child assets links
157
+ _childInstances = new BTNode[Children.Length];
158
+ for (Int32 i = 0; i < Children.Length; i++)
159
+ {
160
+ _childInstances[i] = (BTNode)resourceManager.GetAsset(Children[i].Id);
161
+ _childInstances[i].Parent = this;
162
+ _childInstances[i].ParentIndex = i;
163
+ }
164
+
165
+ // Cache the service assets links
166
+ _serviceInstances = new BTService[Services.Length];
167
+ for (Int32 i = 0; i < Services.Length; i++)
168
+ {
169
+ _serviceInstances[i] = (BTService)resourceManager.GetAsset(Services[i].Id);
170
+ }
171
+
172
+ if (TopmostDecorator != null)
173
+ {
174
+ _topmostDecoratorInstance = (BTDecorator)resourceManager.GetAsset(TopmostDecorator.Id);
175
+ }
176
+ }
177
+ }
178
+ }
data/BTCooldown.cs ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+
4
+ namespace Quantum
5
+ {
6
+ [Serializable]
7
+ public unsafe partial class BTCooldown : BTDecorator
8
+ {
9
+ // How many time should we wait
10
+ public FP CooldownTime;
11
+
12
+ // An indexer so we know when the time started counting
13
+ public BTDataIndex StartTimeIndex;
14
+
15
+ public override void Init(Frame frame, AIBlackboardComponent* blackboard, BTAgent* agent)
16
+ {
17
+ base.Init(frame, blackboard, agent);
18
+
19
+ // We allocate space on the BTAgent so we can store the Start Time
20
+ agent->AddFPData(frame, 0);
21
+ }
22
+
23
+ protected override BTStatus OnUpdate(BTParams btParams)
24
+ {
25
+ var result = base.OnUpdate(btParams);
26
+
27
+ // We let the time check, which happens on the DryRun, happen
28
+ // If it results in success, then we store on the BTAgent the time value of the moment that it happened
29
+ if (result == BTStatus.Success)
30
+ {
31
+ var currentTime = btParams.Frame.DeltaTime * btParams.Frame.Number;
32
+
33
+ var frame = btParams.Frame;
34
+ var entity = btParams.Entity;
35
+ btParams.Agent->SetFPData(frame, currentTime, StartTimeIndex.Index);
36
+ }
37
+
38
+ return result;
39
+ }
40
+
41
+ // We get the Start Time stored on the BTAgent, then we check if the time + cooldown is already over
42
+ // If it is not over, then we return False, blocking the execution of the children nodes
43
+ public override Boolean DryRun(BTParams btParams)
44
+ {
45
+ var frame = btParams.Frame;
46
+ var entity = btParams.Entity;
47
+ FP startTime = btParams.Agent->GetFPData(frame, StartTimeIndex.Index);
48
+
49
+ var currentTime = btParams.Frame.DeltaTime * btParams.Frame.Number;
50
+
51
+ return currentTime >= startTime + CooldownTime;
52
+ }
53
+ }
54
+ }
data/BTDataIndex.User.cs ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace Quantum
4
+ {
5
+ [BotSDKHidden]
6
+ [Serializable]
7
+ // Used so we can track it easier on the Visual Editor
8
+ partial struct BTDataIndex
9
+ {
10
+ }
11
+ }
data/BTDecorator.cs ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+
3
+ namespace Quantum
4
+ {
5
+ public abstract unsafe partial class BTDecorator : BTNode
6
+ {
7
+ [BotSDKHidden] public AssetRefBTNode Child;
8
+ protected BTNode _childInstance;
9
+ public BTAbort AbortType;
10
+
11
+ public BTNode ChildInstance
12
+ {
13
+ get
14
+ {
15
+ return _childInstance;
16
+ }
17
+ }
18
+
19
+ public override BTNodeType NodeType
20
+ {
21
+ get
22
+ {
23
+ return BTNodeType.Decorator;
24
+ }
25
+ }
26
+
27
+ public override void OnReset(BTParams btParams)
28
+ {
29
+ base.OnReset(btParams);
30
+
31
+ OnExit(btParams);
32
+
33
+ if (_childInstance != null)
34
+ _childInstance.OnReset(btParams);
35
+
36
+ BTManager.OnDecoratorReset?.Invoke(btParams.Entity, Guid.Value);
37
+ }
38
+
39
+ public override void OnExit(BTParams btParams)
40
+ {
41
+ base.OnExit(btParams);
42
+ }
43
+
44
+ protected override BTStatus OnUpdate(BTParams btParams)
45
+ {
46
+ if (DryRun(btParams) == true)
47
+ {
48
+ BTManager.OnDecoratorChecked?.Invoke(btParams.Entity, Guid.Value, true);
49
+
50
+ if (_childInstance != null)
51
+ {
52
+ var childResult = _childInstance.RunUpdate(btParams);
53
+ if (childResult == BTStatus.Abort)
54
+ {
55
+ EvaluateAbortNode(btParams);
56
+ SetStatus(btParams.Frame, BTStatus.Abort, btParams.Agent);
57
+ return BTStatus.Abort;
58
+ }
59
+
60
+ return childResult;
61
+ }
62
+
63
+ return BTStatus.Success;
64
+ }
65
+
66
+ BTManager.OnDecoratorChecked?.Invoke(btParams.Entity, Guid.Value, false);
67
+
68
+ return BTStatus.Failure;
69
+ }
70
+
71
+ public override bool OnDynamicRun(BTParams btParams)
72
+ {
73
+ var result = DryRun(btParams);
74
+ if (result == false)
75
+ {
76
+ return false;
77
+ }
78
+ else if (ChildInstance.NodeType != BTNodeType.Decorator)
79
+ {
80
+ return true;
81
+ }
82
+ else
83
+ {
84
+ return ChildInstance.OnDynamicRun(btParams);
85
+ }
86
+ }
87
+
88
+ public override void Loaded(IResourceManager resourceManager, Native.Allocator allocator)
89
+ {
90
+ base.Loaded(resourceManager, allocator);
91
+
92
+ // Cache the child
93
+ _childInstance = (BTNode)resourceManager.GetAsset(Child.Id);
94
+ _childInstance.Parent = this;
95
+ }
96
+ }
97
+ }
data/BTForceResult.cs ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace Quantum
4
+ {
5
+ [Serializable]
6
+ public unsafe partial class BTForceResult : BTDecorator
7
+ {
8
+ public BTStatus Result;
9
+
10
+ protected override BTStatus OnUpdate(BTParams btParams)
11
+ {
12
+ if (_childInstance != null)
13
+ _childInstance.RunUpdate(btParams);
14
+
15
+ return Result;
16
+ }
17
+
18
+ public override Boolean DryRun(BTParams btParams)
19
+ {
20
+ return true;
21
+ }
22
+ }
23
+ }
data/BTLeaf.cs ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+
4
+ namespace Quantum
5
+ {
6
+ public unsafe abstract partial class BTLeaf : BTNode
7
+ {
8
+ public AssetRefBTService[] Services;
9
+ protected BTService[] _serviceInstances;
10
+ public BTService[] ServiceInstances
11
+ {
12
+ get
13
+ {
14
+ return _serviceInstances;
15
+ }
16
+ }
17
+
18
+ public override BTNodeType NodeType
19
+ {
20
+ get
21
+ {
22
+ return BTNodeType.Leaf;
23
+ }
24
+ }
25
+
26
+ public override unsafe void Init(Frame frame, AIBlackboardComponent* blackboard, BTAgent* agent)
27
+ {
28
+ base.Init(frame, blackboard, agent);
29
+
30
+ for (int i = 0; i < Services.Length; i++)
31
+ {
32
+ BTService service = frame.FindAsset<BTService>(Services[i].Id);
33
+ service.Init(frame, agent, blackboard);
34
+ }
35
+ }
36
+
37
+ public override void OnEnterRunning(BTParams btParams)
38
+ {
39
+ var activeServicesList = btParams.Frame.ResolveList<AssetRefBTService>(btParams.Agent->ActiveServices);
40
+ for (int i = 0; i < _serviceInstances.Length; i++)
41
+ {
42
+ _serviceInstances[i].OnEnter(btParams);
43
+ activeServicesList.Add(Services[i]);
44
+ }
45
+ }
46
+
47
+ public override void OnEnter(BTParams btParams)
48
+ {
49
+ base.OnEnter(btParams);
50
+ BTManager.OnNodeEnter?.Invoke(btParams.Entity, Guid.Value);
51
+ }
52
+
53
+ public override void OnExit(BTParams btParams)
54
+ {
55
+ var activeServicesList = btParams.Frame.ResolveList<AssetRefBTService>(btParams.Agent->ActiveServices);
56
+ for (Int32 i = 0; i < _serviceInstances.Length; i++)
57
+ {
58
+ activeServicesList.Remove(Services[i]);
59
+ }
60
+
61
+ BTManager.OnNodeExit?.Invoke(btParams.Entity, Guid.Value);
62
+ }
63
+
64
+ public override void OnReset(BTParams btParams)
65
+ {
66
+ base.OnReset(btParams);
67
+ OnExit(btParams);
68
+ }
69
+
70
+ public override void Loaded(IResourceManager resourceManager, Native.Allocator allocator)
71
+ {
72
+ base.Loaded(resourceManager, allocator);
73
+
74
+ // Cache the service assets links
75
+ _serviceInstances = new BTService[Services.Length];
76
+ for (int i = 0; i < Services.Length; i++)
77
+ {
78
+ _serviceInstances[i] = (BTService)resourceManager.GetAsset(Services[i].Id);
79
+ }
80
+ }
81
+ }
82
+ }
data/BTLoop.cs ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+
4
+ namespace Quantum
5
+ {
6
+ [Serializable]
7
+ public unsafe partial class BTLoop : BTDecorator
8
+ {
9
+ public Int32 LoopIterations;
10
+ public Boolean LoopForever;
11
+ public FP LoopTimeout = -FP._1;
12
+
13
+ public BTDataIndex StartTimeIndex;
14
+ public BTDataIndex IterationCountIndex;
15
+
16
+ public override void Init(Frame frame, AIBlackboardComponent* blackboard, BTAgent* agent)
17
+ {
18
+ base.Init(frame, blackboard, agent);
19
+
20
+ agent->AddFPData(frame, 0);
21
+ agent->AddIntData(frame, 0);
22
+ }
23
+
24
+ public override void OnEnter(BTParams btParams)
25
+ {
26
+ base.OnEnter(btParams);
27
+
28
+ var frame = btParams.Frame;
29
+ var currentTime = frame.DeltaTime * frame.Number;
30
+
31
+ btParams.Agent->SetFPData(frame, currentTime, StartTimeIndex.Index);
32
+ btParams.Agent->SetIntData(frame, 0, IterationCountIndex.Index);
33
+ }
34
+
35
+ protected override BTStatus OnUpdate(BTParams btParams)
36
+ {
37
+ var frame = btParams.Frame;
38
+
39
+ int iteration = btParams.Agent->GetIntData(frame, IterationCountIndex.Index) + 1;
40
+ btParams.Agent->SetIntData(frame, iteration, IterationCountIndex.Index);
41
+
42
+ if (DryRun(btParams) == false)
43
+ {
44
+ return BTStatus.Success;
45
+ }
46
+
47
+ var childResult = BTStatus.Failure;
48
+ if (_childInstance != null)
49
+ {
50
+ _childInstance.SetStatus(btParams.Frame, BTStatus.Inactive, btParams.Agent);
51
+ childResult = _childInstance.RunUpdate(btParams);
52
+ }
53
+
54
+ return childResult;
55
+ }
56
+
57
+ public override Boolean DryRun(BTParams btParams)
58
+ {
59
+ if (LoopForever && LoopTimeout < FP._0)
60
+ {
61
+ return true;
62
+ }
63
+ else if (LoopForever)
64
+ {
65
+ var frame = btParams.Frame;
66
+ FP startTime = btParams.Agent->GetFPData(frame, StartTimeIndex.Index);
67
+
68
+ var currentTime = frame.DeltaTime * frame.Number;
69
+ if (currentTime < startTime + LoopTimeout)
70
+ {
71
+ return true;
72
+ }
73
+ }
74
+ else
75
+ {
76
+ var frame = btParams.Frame;
77
+ int iteration = btParams.Agent->GetIntData(frame, IterationCountIndex.Index);
78
+ if (iteration <= LoopIterations)
79
+ {
80
+ return true;
81
+ }
82
+ }
83
+
84
+ return false;
85
+ }
86
+ }
87
+ }
data/BTNode.cs ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace Quantum
4
+ {
5
+
6
+ public unsafe abstract partial class BTNode
7
+ {
8
+
9
+ [BotSDKHidden] public String Label;
10
+ [BotSDKHidden] public Int32 Id;
11
+
12
+ [NonSerialized] internal BTNode Parent;
13
+ [NonSerialized] internal Int32 ParentIndex;
14
+
15
+ public abstract BTNodeType NodeType { get; }
16
+
17
+ /// <summary>
18
+ /// Called once, for every Node, when the BT is being initialized
19
+ /// </summary>
20
+ public virtual void Init(Frame frame, AIBlackboardComponent* blackboard, BTAgent* agent)
21
+ {
22
+ var statusList = frame.ResolveList(agent->NodesStatus);
23
+ statusList.Add(0);
24
+ }
25
+
26
+ // -- STATUS --
27
+ public BTStatus GetStatus(Frame frame, BTAgent* agent)
28
+ {
29
+ var nodesAndStatus = frame.ResolveList(agent->NodesStatus);
30
+ return (BTStatus)nodesAndStatus[Id];
31
+ }
32
+
33
+ public void SetStatus(Frame frame, BTStatus status, BTAgent* agent)
34
+ {
35
+ var nodesAndStatus = frame.ResolveList(agent->NodesStatus);
36
+ nodesAndStatus[Id] = (Byte)status;
37
+ }
38
+
39
+ /// <summary>
40
+ /// Called whenever the BT execution includes this node as part of the current context
41
+ /// </summary>
42
+ /// <param name="btParams"></param>
43
+ public virtual void OnEnter(BTParams btParams) { }
44
+
45
+ public virtual void OnEnterRunning(BTParams btParams) { }
46
+
47
+ /// <summary>
48
+ /// Called when traversing the tree upwards and the node is already finished with its job.
49
+ /// Used by Composites and Leafs to remove their Services from the list of active services
50
+ /// as it is not anymore part of the current subtree.
51
+ /// Dynamic Composites also remove themselves
52
+ /// </summary>
53
+ /// <param name="btParams"></param>
54
+ public virtual void OnExit(BTParams btParams) { }
55
+
56
+ public virtual void OnAbort(BTParams btParams)
57
+ {
58
+ }
59
+
60
+ /// <summary>
61
+ /// Called when getting out of a sub-branch and this node is being discarded
62
+ /// </summary>
63
+ /// <param name="btParams"></param>
64
+ public unsafe virtual void OnReset(BTParams btParams)
65
+ {
66
+ SetStatus(btParams.Frame, BTStatus.Inactive, btParams.Agent);
67
+ }
68
+
69
+ public void EvaluateAbortNode(BTParams btParams)
70
+ {
71
+ if (btParams.Agent->AbortNodeId == Id)
72
+ {
73
+ btParams.Agent->AbortNodeId = 0;
74
+ }
75
+ }
76
+
77
+ public BTStatus RunUpdate(BTParams btParams, bool continuingAbort = false)
78
+ {
79
+ var oldStatus = GetStatus(btParams.Frame, btParams.Agent);
80
+
81
+ if (oldStatus == BTStatus.Success || oldStatus == BTStatus.Failure)
82
+ {
83
+ return oldStatus;
84
+ }
85
+
86
+ if (oldStatus == BTStatus.Abort)
87
+ {
88
+ if (btParams.Agent->IsAborting == true)
89
+ {
90
+ EvaluateAbortNode(btParams);
91
+ }
92
+ return oldStatus;
93
+ }
94
+
95
+ // If this node was inactive, this means that we're entering on it for the first time, so we call OnEnter
96
+ // An exception from this rule is when we chose this node to continue an abort process. In that case,
97
+ // we already executed OnEnter before, so we don't repeat it
98
+ if (oldStatus == BTStatus.Inactive && continuingAbort == false)
99
+ {
100
+ OnEnter(btParams);
101
+ }
102
+
103
+ var newStatus = BTStatus.Failure;
104
+ try
105
+ {
106
+ newStatus = OnUpdate(btParams);
107
+
108
+ if (btParams.Agent->IsAborting)
109
+ {
110
+ newStatus = BTStatus.Abort;
111
+ }
112
+
113
+ // Used for debugging purposes
114
+ if (newStatus == BTStatus.Success)
115
+ {
116
+ BTManager.OnNodeSuccess?.Invoke(btParams.Entity, Guid.Value);
117
+ BTManager.OnNodeExit?.Invoke(btParams.Entity, Guid.Value);
118
+ }
119
+
120
+ if (newStatus == BTStatus.Failure)
121
+ {
122
+ BTManager.OnNodeFailure?.Invoke(btParams.Entity, Guid.Value);
123
+ BTManager.OnNodeExit?.Invoke(btParams.Entity, Guid.Value);
124
+ }
125
+ }
126
+ catch (Exception e)
127
+ {
128
+ Log.Error("Exception in Behaviour Tree node '{0}' ({1}) - setting node status to Failure", Label, Guid);
129
+ Log.Exception(e);
130
+ }
131
+
132
+ SetStatus(btParams.Frame, newStatus, btParams.Agent);
133
+
134
+ if ((newStatus == BTStatus.Running || newStatus == BTStatus.Success) &&
135
+ (oldStatus == BTStatus.Failure || oldStatus == BTStatus.Inactive))
136
+ {
137
+ OnEnterRunning(btParams);
138
+ }
139
+
140
+ if (newStatus == BTStatus.Running && NodeType == BTNodeType.Leaf)
141
+ {
142
+ // If we are a leaf, we can store the current node
143
+ // We know that there has only one leaf node running at any time, no parallel branches possible
144
+ // The Run() method also return a tuple <BTStatus, BTNode(CurrentNode)>
145
+ btParams.Agent->Current = this;
146
+ }
147
+
148
+ return newStatus;
149
+ }
150
+
151
+ /// <summary>
152
+ /// Used by Decorators to evaluate if a condition succeeds or not.
153
+ /// Upon success, allow the flow to continue.
154
+ /// Upon failure, blocks the execution so another path is taken
155
+ /// </summary>
156
+ /// <param name="btParams"></param>
157
+ /// <returns></returns>
158
+ public virtual Boolean DryRun(BTParams btParams)
159
+ {
160
+ return false;
161
+ }
162
+
163
+ public virtual Boolean OnDynamicRun(BTParams btParams)
164
+ {
165
+ return true;
166
+ }
167
+
168
+ /// <summary>
169
+ /// Called every tick while this Node is part of the current sub-tree.
170
+ /// Returning "Success/Failure" will make the tree continue its execution.
171
+ /// Returning "Running" will store this Node as the Current Node and re-execute it on the next frame
172
+ /// unless something else interrputs
173
+ /// </summary>
174
+ /// <param name="btParams"></param>
175
+ /// <returns></returns>
176
+ protected abstract BTStatus OnUpdate(BTParams btParams);
177
+ }
178
+ }
data/BTNodeType.cs ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace Quantum
2
+ {
3
+ public enum BTNodeType
4
+ {
5
+ Root,
6
+ Leaf,
7
+ Decorator,
8
+ Composite,
9
+ Service
10
+ }
11
+ }
data/BTParams.cs ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System.Runtime.InteropServices;
2
+
3
+ namespace Quantum
4
+ {
5
+ [StructLayout(LayoutKind.Auto)]
6
+ public unsafe partial struct BTParams
7
+ {
8
+ private Frame _frame;
9
+ private BTAgent* _agent;
10
+ private EntityRef _entity;
11
+ private AIBlackboardComponent* _blackboard;
12
+
13
+ private BTParamsUser _userParams;
14
+
15
+ public Frame Frame { get => _frame; }
16
+ public BTAgent* Agent { get => _agent; }
17
+ public EntityRef Entity { get => _entity; }
18
+ public AIBlackboardComponent* Blackboard { get => _blackboard; }
19
+
20
+ public BTParamsUser UserParams { get => _userParams; set => _userParams = value; }
21
+
22
+ public void SetDefaultParams(Frame frame, BTAgent* agent, EntityRef entity, AIBlackboardComponent* blackboard = null)
23
+ {
24
+ _frame = frame;
25
+ _agent = agent;
26
+ _entity = entity;
27
+ _blackboard = blackboard;
28
+ }
29
+
30
+ public void Reset(Frame frame)
31
+ {
32
+ _frame = default;
33
+ _agent = default;
34
+ _entity = default;
35
+ _blackboard = default;
36
+
37
+ _userParams = default;
38
+ }
39
+ }
40
+
41
+ public partial struct BTParamsUser
42
+ {
43
+ }
44
+ }
data/BTRoot.cs ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+ using System.Collections.Generic;
4
+
5
+ namespace Quantum
6
+ {
7
+ [Serializable]
8
+ public unsafe partial class BTRoot : BTDecorator
9
+ {
10
+ [BotSDKHidden] public Int32 NodesAmount;
11
+
12
+ public override BTNodeType NodeType
13
+ {
14
+ get
15
+ {
16
+ return BTNodeType.Root;
17
+ }
18
+ }
19
+
20
+ protected unsafe override BTStatus OnUpdate(BTParams btParams)
21
+ {
22
+
23
+ btParams.Agent->Current = this;
24
+
25
+ if (_childInstance != null)
26
+ {
27
+ return _childInstance.RunUpdate(btParams);
28
+ }
29
+
30
+ return BTStatus.Success;
31
+ }
32
+
33
+ public void InitializeTree(Frame frame, BTAgent* agent, AIBlackboardComponent* blackboard)
34
+ {
35
+ InitNodesRecursively(frame, this, agent, blackboard);
36
+ }
37
+
38
+ private static void InitNodesRecursively(Frame frame, BTNode node, BTAgent* agent, AIBlackboardComponent* blackboard)
39
+ {
40
+ node.Init(frame, blackboard, agent);
41
+
42
+ if (node is BTDecorator decoratorNode)
43
+ {
44
+ BTNode childNode = frame.FindAsset<BTNode>(decoratorNode.Child.Id);
45
+ InitNodesRecursively(frame, childNode, agent, blackboard);
46
+ }
47
+
48
+ if (node is BTComposite compositeNode)
49
+ {
50
+ foreach (var child in compositeNode.Children)
51
+ {
52
+ BTNode childNode = frame.FindAsset<BTNode>(child.Id);
53
+ InitNodesRecursively(frame, childNode, agent, blackboard);
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
data/BTSelector.cs ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace Quantum
4
+ {
5
+
6
+ /// <summary>
7
+ /// The selector task is similar to an or operation. It will return success as soon as one of its child tasks return success.
8
+ /// If a child task returns failure then it will sequentially run the next task. If no child task returns success then it will return failure.
9
+ /// </summary>
10
+ [Serializable]
11
+ public unsafe partial class BTSelector : BTComposite
12
+ {
13
+ protected override BTStatus OnUpdate(BTParams btParams)
14
+ {
15
+ BTStatus status = BTStatus.Success;
16
+
17
+ while (GetCurrentChild(btParams.Frame, btParams.Agent) < _childInstances.Length)
18
+ {
19
+ var currentChildId = GetCurrentChild(btParams.Frame, btParams.Agent);
20
+ var child = _childInstances[currentChildId];
21
+ status = child.RunUpdate(btParams);
22
+
23
+ if (status == BTStatus.Abort && btParams.Agent->IsAborting == true)
24
+ {
25
+ return BTStatus.Abort;
26
+ }
27
+
28
+ if (status == BTStatus.Failure || status == BTStatus.Abort)
29
+ {
30
+ SetCurrentChild(btParams.Frame, currentChildId + 1, btParams.Agent);
31
+ }
32
+ else
33
+ break;
34
+ }
35
+
36
+ return status;
37
+ }
38
+
39
+ internal override void ChildCompletedRunning(BTParams btParams, BTStatus childResult)
40
+ {
41
+ if (childResult == BTStatus.Abort)
42
+ {
43
+ return;
44
+ }
45
+
46
+ if (childResult == BTStatus.Failure)
47
+ {
48
+ var currentChild = GetCurrentChild(btParams.Frame, btParams.Agent);
49
+ SetCurrentChild(btParams.Frame, currentChild + 1, btParams.Agent);
50
+ }
51
+ else
52
+ {
53
+ SetCurrentChild(btParams.Frame, _childInstances.Length, btParams.Agent);
54
+
55
+ // If the child succeeded, then we already know that this sequence succeeded, so we can force it
56
+ SetStatus(btParams.Frame, BTStatus.Success, btParams.Agent);
57
+
58
+ // Trigger the debugging callbacks
59
+ BTManager.OnNodeSuccess?.Invoke(btParams.Entity, Guid.Value);
60
+ BTManager.OnNodeExit?.Invoke(btParams.Entity, Guid.Value);
61
+ }
62
+ }
63
+ }
64
+ }
data/BTSequence.cs ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace Quantum
4
+ {
5
+ /// <summary>
6
+ /// The sequence task is similar to an and operation. It will return failure as soon as one of its child tasks return failure.
7
+ /// If a child task returns success then it will sequentially run the next task. If all child tasks return success then it will return success.
8
+ /// </summary>
9
+ [Serializable]
10
+ public unsafe partial class BTSequence : BTComposite
11
+ {
12
+ protected override BTStatus OnUpdate(BTParams btParams)
13
+ {
14
+ BTStatus status = BTStatus.Success;
15
+
16
+ while (GetCurrentChild(btParams.Frame, btParams.Agent) < _childInstances.Length)
17
+ {
18
+ var currentChildId = GetCurrentChild(btParams.Frame, btParams.Agent);
19
+ var child = _childInstances[currentChildId];
20
+ status = child.RunUpdate(btParams);
21
+
22
+ if (status == BTStatus.Abort)
23
+ {
24
+ if (btParams.Agent->IsAborting == true)
25
+ {
26
+ return BTStatus.Abort;
27
+ }
28
+ else
29
+ {
30
+ return BTStatus.Failure;
31
+ }
32
+ }
33
+
34
+ if (status == BTStatus.Success)
35
+ {
36
+ SetCurrentChild(btParams.Frame, currentChildId + 1, btParams.Agent);
37
+ }
38
+ else
39
+ {
40
+ break;
41
+ }
42
+ }
43
+
44
+ return status;
45
+ }
46
+
47
+ internal override void ChildCompletedRunning(BTParams btParams, BTStatus childResult)
48
+ {
49
+ if (childResult == BTStatus.Abort)
50
+ {
51
+ return;
52
+ }
53
+
54
+ if (childResult == BTStatus.Failure)
55
+ {
56
+ SetCurrentChild(btParams.Frame, _childInstances.Length, btParams.Agent);
57
+
58
+ // If the child failed, then we already know that this sequence failed, so we can force it
59
+ SetStatus(btParams.Frame, BTStatus.Failure, btParams.Agent);
60
+
61
+ // Trigger the debugging callbacks
62
+ BTManager.OnNodeFailure?.Invoke(btParams.Entity, Guid.Value);
63
+ BTManager.OnNodeExit?.Invoke(btParams.Entity, Guid.Value);
64
+ }
65
+ else
66
+ {
67
+ var currentChild = GetCurrentChild(btParams.Frame, btParams.Agent);
68
+ SetCurrentChild(btParams.Frame, currentChild + 1, btParams.Agent);
69
+ }
70
+ }
71
+ }
72
+ }
data/BTService.cs ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+
4
+ namespace Quantum
5
+ {
6
+ public unsafe abstract partial class BTService
7
+ {
8
+ public FP IntervalInSec;
9
+
10
+ [BotSDKHidden] public Int32 Id;
11
+
12
+ public virtual void Init(Frame frame, BTAgent* agent, AIBlackboardComponent* blackboard)
13
+ {
14
+ var endTimesList = frame.ResolveList<FP>(agent->ServicesEndTimes);
15
+ endTimesList.Add(0);
16
+ }
17
+
18
+ public void SetEndTime(Frame frame, BTAgent* agent)
19
+ {
20
+ var endTimesList = frame.ResolveList<FP>(agent->ServicesEndTimes);
21
+ endTimesList[Id] = frame.BotSDKGameTime + IntervalInSec;
22
+ }
23
+
24
+ public FP GetEndTime(Frame frame, BTAgent* agent)
25
+ {
26
+ var endTime = frame.ResolveList(agent->ServicesEndTimes);
27
+ return endTime[Id];
28
+ }
29
+
30
+ public virtual void RunUpdate(BTParams btParams)
31
+ {
32
+ var endTime = GetEndTime(btParams.Frame, btParams.Agent);
33
+ if (btParams.Frame.BotSDKGameTime >= endTime)
34
+ {
35
+ OnUpdate(btParams);
36
+ SetEndTime(btParams.Frame, btParams.Agent);
37
+ }
38
+ }
39
+
40
+ public virtual void OnEnter(BTParams btParams)
41
+ {
42
+ SetEndTime(btParams.Frame, btParams.Agent);
43
+ }
44
+
45
+ /// <summary>
46
+ /// Called whenever the Service is part of the current subtree
47
+ /// and its waiting time is already over
48
+ /// </summary>
49
+ protected abstract void OnUpdate(BTParams btParams);
50
+
51
+ public static void TickServices(BTParams btParams)
52
+ {
53
+ var activeServicesList = btParams.Frame.ResolveList<AssetRefBTService>(btParams.Agent->ActiveServices);
54
+
55
+ for (int i = 0; i < activeServicesList.Count; i++)
56
+ {
57
+ var service = btParams.Frame.FindAsset<BTService>(activeServicesList[i].Id);
58
+ try
59
+ {
60
+ service.RunUpdate(btParams);
61
+ }
62
+ catch (Exception e)
63
+ {
64
+ Log.Error("Exception in Behaviour Tree service '{0}' ({1}) - setting node status to Failure", service.GetType().ToString(), service.Guid);
65
+ Log.Exception(e);
66
+ }
67
+ }
68
+ }
69
+ }
70
+ }
data/BTStatus.cs ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ namespace Quantum
2
+ {
3
+ public enum BTStatus
4
+ {
5
+ Inactive,
6
+ Success,
7
+ Failure,
8
+ Running,
9
+ Abort
10
+ }
11
+ }
data/BallPoolSpec.cs ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+ using Photon.Deterministic;
3
+
4
+ namespace Quantum
5
+ {
6
+ unsafe partial class BallPoolSpec
7
+ {
8
+ public FP SpinMultiplier;
9
+ public FP EndOfMovementVelocityThreshold;
10
+ public Int32 EndOfMovementWaitingInTicks;
11
+
12
+ public Int32 Layer { get; set; }
13
+ }
14
+ }
data/BehaviourTree.Manager.cs ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Photon.Deterministic;
2
+ using System;
3
+
4
+ namespace Quantum
5
+ {
6
+ public static unsafe partial class BTManager
7
+ {
8
+ public static Action<EntityRef, string> OnSetupDebugger;
9
+
10
+ public static Action<EntityRef, long> OnNodeEnter;
11
+ public static Action<EntityRef, long> OnNodeExit;
12
+ public static Action<EntityRef, long> OnNodeSuccess;
13
+ public static Action<EntityRef, long> OnNodeFailure;
14
+ public static Action<EntityRef, long, bool> OnDecoratorChecked;
15
+ public static Action<EntityRef, long> OnDecoratorReset;
16
+ public static Action<EntityRef> OnTreeCompleted;
17
+
18
+ /// <summary>
19
+ /// Call this once, to initialize the BTAgent.
20
+ /// This method internally looks for a Blackboard Component on the entity
21
+ /// and passes it down the pipeline.
22
+ /// </summary>
23
+ /// <param name="frame"></param>
24
+ /// <param name="entity"></param>
25
+ /// <param name="root"></param>
26
+ public static void Init(Frame frame, EntityRef entity, BTRoot root)
27
+ {
28
+ if (frame.Unsafe.TryGetPointer(entity, out BTAgent* agent))
29
+ {
30
+ agent->Initialize(frame, entity, agent, root, true);
31
+ }
32
+ else
33
+ {
34
+ Log.Error("[Bot SDK] Tried to initialize an entity which has no BTAgent component");
35
+ }
36
+ }
37
+
38
+ /// <summary>
39
+ /// Made for internal use only.
40
+ /// </summary>
41
+ public static void ClearBTParams(BTParams btParams)
42
+ {
43
+ btParams.Reset(btParams.Frame);
44
+ }
45
+
46
+ /// <summary>
47
+ /// Call this method every frame to update your BT Agent.
48
+ /// You can optionally pass a Blackboard Component to it, if your Agent use it
49
+ /// </summary>
50
+ public static void Update(Frame frame, EntityRef entity, AIBlackboardComponent* blackboard = null)
51
+ {
52
+ var agent = frame.Unsafe.GetPointer<BTAgent>(entity);
53
+ BTParams btParams = new BTParams();
54
+ btParams.SetDefaultParams(frame, agent, entity, blackboard);
55
+
56
+ agent->Update(ref btParams);
57
+ }
58
+
59
+ /// <summary>
60
+ /// CAUTION: Use this overload with care.<br/>
61
+ /// It allows the definition of custom parameters which are passed through the entire BT pipeline, for easy access.<br/>
62
+ /// The user parameters struct needs to be created from scratch every time BEFORE calling the BT Update method.<br/>
63
+ /// Make sure to also implement BTParamsUser.ClearUser(frame).
64
+ /// </summary>
65
+ /// <param name="userParams">Used to define custom user data. It needs to be created from scratch every time before calling this method.</param>
66
+ public static void Update(Frame frame, EntityRef entity, ref BTParamsUser userParams, AIBlackboardComponent* blackboard = null)
67
+ {
68
+ var agent = frame.Unsafe.GetPointer<BTAgent>(entity);
69
+ BTParams btParams = new BTParams();
70
+ btParams.SetDefaultParams(frame, agent, entity, blackboard);
71
+ btParams.UserParams = userParams;
72
+
73
+ agent->Update(ref btParams);
74
+ }
75
+ }
76
+ }
data/Blackboard.qtn ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ asset AIBlackboard;
2
+ asset AIBlackboardInitializer;
3
+
4
+ union BlackboardValue {
5
+ QBoolean BooleanValue;
6
+ byte ByteValue;
7
+ Int32 IntegerValue;
8
+ FP FPValue;
9
+ FPVector2 FPVector2Value;
10
+ FPVector3 FPVector3Value;
11
+ entity_ref EntityRefValue;
12
+ }
13
+
14
+ component AIBlackboardComponent {
15
+ asset_ref<AIBlackboard> Board;
16
+ list<BlackboardEntry> Entries;
17
+ }
18
+
19
+
20
+ struct BlackboardEntry{
21
+ BlackboardValue Value;
22
+ list<AssetRefBTDecorator> ReactiveDecorators;
23
+ }
data/BlackboardEntry.cs ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using Quantum.Collections;
2
+
3
+ namespace Quantum
4
+ {
5
+ public unsafe partial struct BlackboardEntry
6
+ {
7
+ /// <summary>
8
+ /// Iterate through all Decorators that watches this Blackboard entry
9
+ /// Re-check the Decorators so it can check if an abort is needed
10
+ /// </summary>
11
+ /// <param name="btParams"></param>
12
+ public void TriggerDecorators(BTParams btParams)
13
+ {
14
+ var frame = btParams.Frame;
15
+
16
+ // If the reactive decorators list was already allocated...
17
+ if (ReactiveDecorators.Ptr != default)
18
+ {
19
+ // Solve it and trigger the decorators checks
20
+ var reactiveDecorators = frame.ResolveList(ReactiveDecorators);
21
+ for (int i = 0; i < reactiveDecorators.Count; i++)
22
+ {
23
+ var reactiveDecoratorRef = reactiveDecorators[i];
24
+ var decoratorInstance = frame.FindAsset<BTDecorator>(reactiveDecoratorRef.Id);
25
+ btParams.Agent->OnDecoratorReaction(btParams, decoratorInstance, decoratorInstance.AbortType, out bool abortSelf, out bool abortLowerPriority);
26
+
27
+ // If at least one Decorator resulted in abort, we stop and return already
28
+ if (abortSelf == true)
29
+ {
30
+ btParams.Agent->AbortNodeId = decoratorInstance.Id;
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ }
data/BlackboardValue.cs ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ using System;
2
+
3
+ namespace Quantum
4
+ {
5
+ public unsafe partial struct BlackboardValue
6
+ {
7
+ public String ValueToString()
8
+ {
9
+ switch (Field)
10
+ {
11
+ case BlackboardValue.BOOLEANVALUE: return string.Format("{0}", _BooleanValue);
12
+ case BlackboardValue.BYTEVALUE: return string.Format("{0}", _ByteValue);
13
+ case BlackboardValue.INTEGERVALUE: return string.Format("{0}", _IntegerValue);
14
+ case BlackboardValue.FPVALUE: return string.Format("{0}", _FPValue);
15
+ case BlackboardValue.FPVECTOR2VALUE: return string.Format("{0}", _FPVector2Value);
16
+ case BlackboardValue.FPVECTOR3VALUE: return string.Format("{0}", _FPVector3Value);
17
+ case BlackboardValue.ENTITYREFVALUE: return string.Format("{0}", _EntityRefValue);
18
+ }
19
+
20
+ return base.ToString();
21
+ }
22
+ }
23
+
24
+ public unsafe partial struct BlackboardValue
25
+ {
26
+ public String TypeToString()
27
+ {
28
+ switch (Field)
29
+ {
30
+ case BlackboardValue.BOOLEANVALUE: return "Boolean";
31
+ case BlackboardValue.BYTEVALUE: return "Byte";
32
+ case BlackboardValue.INTEGERVALUE: return "Integer";
33
+ case BlackboardValue.FPVALUE: return "FP";
34
+ case BlackboardValue.FPVECTOR2VALUE: return "Vector2";
35
+ case BlackboardValue.FPVECTOR3VALUE: return "Vector3";
36
+ case BlackboardValue.ENTITYREFVALUE: return "EntityRef";
37
+ }
38
+
39
+ return base.ToString();
40
+ }
41
+ }
42
+ }