Spaces:
Runtime error
Runtime error
Upload 84 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- data/CameraBehavior.cs +25 -0
- data/CameraFollow.cs +161 -0
- data/CardManager.cs +176 -0
- data/CardManager.qtn +36 -0
- data/CardManagerSystem.cs +38 -0
- data/CardSettings.cs +14 -0
- data/Chain.User.cs +40 -0
- data/ChainItem.cs +41 -0
- data/ChainItemSystem.cs +20 -0
- data/ChainSystem.cs +72 -0
- data/CheckIndicatorView.cs +34 -0
- data/ChecksumVerification.cs +52 -0
- data/ChessViewUpdater.cs +148 -0
- data/CodeGen.cs +1995 -0
- data/CommandSetup.Legacy.cs +12 -0
- data/CommandSetup.User.cs +15 -0
- data/CommandSetup.cs +31 -0
- data/CommandSystem.cs +41 -0
- data/ConfigAssets.cs +8 -0
- data/ConfigAssetsHelper.cs +34 -0
- data/Configuration Files.txt +191 -0
- data/Consideration.cs +164 -0
- data/Core.cs +0 -0
- data/DSL.txt +502 -0
- data/DeadPieceSlot.cs +8 -0
- data/DebugAction.cs +13 -0
- data/DebugLeaf.cs +23 -0
- data/DebugService.cs +14 -0
- data/EffectArea.cs +81 -0
- data/EffectArea.qtn +42 -0
- data/EffectAreaBehavior.cs +30 -0
- data/EffectAreaBehavior_Buff.cs +16 -0
- data/EffectAreaBehavior_Damage.cs +31 -0
- data/EffectAreaSettings.cs +18 -0
- data/EffectAreaSystem.cs +13 -0
- data/Fixed Point.txt +256 -0
- data/Frame.User.cs +11 -0
- data/FrameContext.User.cs +7 -0
- data/GOAP.User.cs +10 -0
- data/GOAP.qtn +39 -0
- data/GOAPAStar.cs +311 -0
- data/GOAPAction.cs +53 -0
- data/GOAPBackValidation.cs +28 -0
- data/GOAPDefaultAction.cs +122 -0
- data/GOAPDefaultGoal.cs +113 -0
- data/GOAPDefaultHeuristic.cs +45 -0
- data/GOAPGoal.cs +66 -0
- data/GOAPHeap.cs +162 -0
- data/GOAPHeuristic.cs +45 -0
- data/GOAPManager.cs +450 -0
data/CameraBehavior.cs
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System.Collections;
|
2 |
+
using System.Collections.Generic;
|
3 |
+
using UnityEngine;
|
4 |
+
using Quantum;
|
5 |
+
|
6 |
+
public class CameraBehavior : QuantumCallbacks
|
7 |
+
{
|
8 |
+
private bool _isInverted = false;
|
9 |
+
|
10 |
+
public override void OnUpdateView(QuantumGame game)
|
11 |
+
{
|
12 |
+
var player = game.Session.LocalPlayerIndices[0];
|
13 |
+
if (player != 0 && !_isInverted)
|
14 |
+
{
|
15 |
+
transform.eulerAngles = new Vector3(transform.eulerAngles.x, transform.eulerAngles.y +180, transform.eulerAngles.z);
|
16 |
+
|
17 |
+
for (int i = 0; i < ChessViewUpdater.Instance.Pieces.Length; i++)
|
18 |
+
{
|
19 |
+
var p = ChessViewUpdater.Instance.Pieces[i];
|
20 |
+
p.transform.eulerAngles = new Vector3(p.transform.eulerAngles.x, p.transform.eulerAngles.y, p.transform.eulerAngles.z + 180);
|
21 |
+
}
|
22 |
+
_isInverted = true;
|
23 |
+
}
|
24 |
+
}
|
25 |
+
}
|
data/CameraFollow.cs
ADDED
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using Photon.Deterministic;
|
2 |
+
using System.Collections;
|
3 |
+
using System.Collections.Generic;
|
4 |
+
using UnityEngine;
|
5 |
+
|
6 |
+
[RequireComponent(typeof(Camera))]
|
7 |
+
public class CameraFollow : MonoBehaviour
|
8 |
+
{
|
9 |
+
public Transform Target;
|
10 |
+
public Quantum.LayerMask OcclusionQueryMask = -1;
|
11 |
+
[SerializeField, Range(2f, 15f)]
|
12 |
+
float distance = 5f;
|
13 |
+
[SerializeField, Range(0.1f, 5f)]
|
14 |
+
float scrollSpeed = 1f;
|
15 |
+
[SerializeField, Min(0f)]
|
16 |
+
float focusRadius = 1f;
|
17 |
+
[SerializeField, Range(0f, 1f)]
|
18 |
+
float focusCentering = 0.5f;
|
19 |
+
|
20 |
+
[SerializeField, Range(1f, 360f)]
|
21 |
+
float rotationSpeed = 90f;
|
22 |
+
[SerializeField, Range(-30f, 89f)]
|
23 |
+
float minVerticalAngle = -30f, maxVerticalAngle = 60f;
|
24 |
+
|
25 |
+
Vector3 focusPoint;
|
26 |
+
Vector2 orbitAngles = new Vector2(45f, 0f);
|
27 |
+
|
28 |
+
private Camera _camera;
|
29 |
+
void Awake()
|
30 |
+
{
|
31 |
+
//focusPoint = focus.position;
|
32 |
+
transform.localRotation = Quaternion.Euler(orbitAngles);
|
33 |
+
_camera = GetComponent<Camera>();
|
34 |
+
}
|
35 |
+
void LateUpdate()
|
36 |
+
{
|
37 |
+
if (Target == null) return;
|
38 |
+
UpdateDistance();
|
39 |
+
UpdateFocusPoint();
|
40 |
+
Quaternion lookRotation;
|
41 |
+
if (ManualRotation())
|
42 |
+
{
|
43 |
+
ConstrainAngles();
|
44 |
+
lookRotation = Quaternion.Euler(orbitAngles);
|
45 |
+
}
|
46 |
+
else
|
47 |
+
{
|
48 |
+
lookRotation = transform.localRotation;
|
49 |
+
}
|
50 |
+
|
51 |
+
Vector3 lookDirection = lookRotation * Vector3.forward;
|
52 |
+
Vector3 lookPosition = focusPoint - lookDirection * distance;
|
53 |
+
|
54 |
+
if (Cast(focusPoint, lookRotation, -lookDirection, out var hitDistance, distance - _camera.nearClipPlane))
|
55 |
+
{
|
56 |
+
lookPosition = focusPoint - lookDirection * (hitDistance + _camera.nearClipPlane);
|
57 |
+
}
|
58 |
+
|
59 |
+
transform.SetPositionAndRotation(lookPosition, lookRotation);
|
60 |
+
}
|
61 |
+
|
62 |
+
private unsafe bool Cast(Vector3 origin, Quaternion rotation, Vector3 direction, out float hitDistance, float distance)
|
63 |
+
{
|
64 |
+
hitDistance = 0;
|
65 |
+
|
66 |
+
var frame = QuantumRunner.Default?.Game?.Frames.Verified;
|
67 |
+
if (frame != null)
|
68 |
+
{
|
69 |
+
var shape = Quantum.Shape3D.CreateBox(CameraPlaneExtends.ToFPVector3());
|
70 |
+
var options = Quantum.QueryOptions.ComputeDetailedInfo | Quantum.QueryOptions.HitAll;
|
71 |
+
var hit = frame.Physics3D.ShapeCast(origin.ToFPVector3(), rotation.ToFPQuaternion(), &shape, (direction * distance).ToFPVector3(), OcclusionQueryMask, options);
|
72 |
+
if (hit.HasValue)
|
73 |
+
{
|
74 |
+
hitDistance = (origin - hit.Value.Point.ToUnityVector3()).magnitude;
|
75 |
+
return true;
|
76 |
+
}
|
77 |
+
}
|
78 |
+
return false;
|
79 |
+
}
|
80 |
+
|
81 |
+
Vector3 CameraPlaneExtends
|
82 |
+
{
|
83 |
+
get
|
84 |
+
{
|
85 |
+
Vector3 halfExtends;
|
86 |
+
halfExtends.y =
|
87 |
+
_camera.nearClipPlane *
|
88 |
+
Mathf.Tan(0.5f * Mathf.Deg2Rad * _camera.fieldOfView) * 1.25f;
|
89 |
+
halfExtends.x = halfExtends.y * _camera.aspect;
|
90 |
+
halfExtends.z = 0.01f;
|
91 |
+
return halfExtends;
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
void UpdateDistance()
|
96 |
+
{
|
97 |
+
distance += Input.GetAxisRaw("Mouse ScrollWheel") * scrollSpeed;
|
98 |
+
distance = Mathf.Clamp(distance, 2, 15);
|
99 |
+
}
|
100 |
+
|
101 |
+
bool ManualRotation()
|
102 |
+
{
|
103 |
+
Vector2 input = new Vector2(
|
104 |
+
-Input.GetAxis("Mouse Y"),
|
105 |
+
Input.GetAxis("Mouse X")
|
106 |
+
);
|
107 |
+
const float e = 0.001f;
|
108 |
+
if (input.x < e || input.x > e || input.y < e || input.y > e)
|
109 |
+
{
|
110 |
+
orbitAngles += rotationSpeed * Time.unscaledDeltaTime * input;
|
111 |
+
return true;
|
112 |
+
}
|
113 |
+
return false;
|
114 |
+
}
|
115 |
+
|
116 |
+
void UpdateFocusPoint()
|
117 |
+
{
|
118 |
+
Vector3 targetPoint = Target.position;
|
119 |
+
if (focusRadius > 0f)
|
120 |
+
{
|
121 |
+
float distance = Vector3.Distance(targetPoint, focusPoint);
|
122 |
+
float t = 1f;
|
123 |
+
if (distance > 0.01f && focusCentering > 0f)
|
124 |
+
{
|
125 |
+
t = Mathf.Pow(1f - focusCentering, Time.unscaledDeltaTime);
|
126 |
+
}
|
127 |
+
if (distance > focusRadius)
|
128 |
+
{
|
129 |
+
t = Mathf.Min(t, focusRadius / distance);
|
130 |
+
}
|
131 |
+
focusPoint = Vector3.Lerp(targetPoint, focusPoint, t);
|
132 |
+
}
|
133 |
+
else
|
134 |
+
{
|
135 |
+
focusPoint = targetPoint;
|
136 |
+
}
|
137 |
+
}
|
138 |
+
|
139 |
+
void ConstrainAngles()
|
140 |
+
{
|
141 |
+
orbitAngles.x =
|
142 |
+
Mathf.Clamp(orbitAngles.x, minVerticalAngle, maxVerticalAngle);
|
143 |
+
|
144 |
+
if (orbitAngles.y < 0f)
|
145 |
+
{
|
146 |
+
orbitAngles.y += 360f;
|
147 |
+
}
|
148 |
+
else if (orbitAngles.y >= 360f)
|
149 |
+
{
|
150 |
+
orbitAngles.y -= 360f;
|
151 |
+
}
|
152 |
+
}
|
153 |
+
|
154 |
+
void OnValidate()
|
155 |
+
{
|
156 |
+
if (maxVerticalAngle < minVerticalAngle)
|
157 |
+
{
|
158 |
+
maxVerticalAngle = minVerticalAngle;
|
159 |
+
}
|
160 |
+
}
|
161 |
+
}
|
data/CardManager.cs
ADDED
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
using Photon.Deterministic;
|
4 |
+
|
5 |
+
unsafe partial struct CardManager
|
6 |
+
{
|
7 |
+
// CONSTANTS
|
8 |
+
|
9 |
+
public const byte AVAILABLE_CARDS_COUNT = 4;
|
10 |
+
|
11 |
+
// PUBLIC METHODS
|
12 |
+
|
13 |
+
public void Initialize(Frame frame, CardInfo[] cards, GameplaySettings settings)
|
14 |
+
{
|
15 |
+
var availableCards = frame.AllocateList<CardInfo>(AVAILABLE_CARDS_COUNT);
|
16 |
+
var cardQueue = frame.AllocateList<CardInfo>(cards.Length);
|
17 |
+
|
18 |
+
CardQueue = cardQueue;
|
19 |
+
AvailableCards = availableCards;
|
20 |
+
|
21 |
+
for (int idx = 0, count = cards.Length; idx < count; idx++)
|
22 |
+
{
|
23 |
+
cardQueue.Add(cards[idx]);
|
24 |
+
}
|
25 |
+
|
26 |
+
cardQueue.Shuffle(frame.RNG);
|
27 |
+
|
28 |
+
for (int idx = 0; idx < AVAILABLE_CARDS_COUNT; idx++)
|
29 |
+
{
|
30 |
+
availableCards.Add(cardQueue[idx]);
|
31 |
+
}
|
32 |
+
|
33 |
+
QueueHeadIndex = AVAILABLE_CARDS_COUNT;
|
34 |
+
|
35 |
+
CurrentEnergy = (int)settings.StartEnergy;
|
36 |
+
MaxEnergy = (int)settings.MaxEnergy;
|
37 |
+
}
|
38 |
+
|
39 |
+
public void SetFillRate(FP energyFillRate)
|
40 |
+
{
|
41 |
+
EnergyFillRate = energyFillRate;
|
42 |
+
}
|
43 |
+
|
44 |
+
public void Deinitialize(Frame frame)
|
45 |
+
{
|
46 |
+
frame.FreeList(AvailableCards);
|
47 |
+
frame.FreeList(CardQueue);
|
48 |
+
|
49 |
+
AvailableCards = default;
|
50 |
+
CardQueue = default;
|
51 |
+
}
|
52 |
+
|
53 |
+
public void Update(Frame frame, EntityRef entity)
|
54 |
+
{
|
55 |
+
if (CardQueue.Ptr.Offset == 0)
|
56 |
+
return;
|
57 |
+
|
58 |
+
CurrentEnergy = FPMath.Clamp(CurrentEnergy + frame.DeltaTime * EnergyFillRate, FP._0, MaxEnergy);
|
59 |
+
NextFillTime -= frame.DeltaTime;
|
60 |
+
|
61 |
+
if (EmptySlots > 0 && NextFillTime <= FP._0)
|
62 |
+
{
|
63 |
+
FillCardSlot(frame, entity);
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
+
public void UseCard(Frame frame, EntityRef entity, PlayerRef owner, byte cardIndex, FPVector2 position, FP rotation)
|
68 |
+
{
|
69 |
+
if (cardIndex < 0 || cardIndex >= AVAILABLE_CARDS_COUNT)
|
70 |
+
{
|
71 |
+
Log.Error($"Out of range card use request Index: {cardIndex}");
|
72 |
+
return;
|
73 |
+
}
|
74 |
+
|
75 |
+
var availableCards = frame.ResolveList(AvailableCards);
|
76 |
+
var card = availableCards[cardIndex];
|
77 |
+
|
78 |
+
if (card.CardSettings.Id.IsValid == false)
|
79 |
+
{
|
80 |
+
Log.Error($"Invalid card use request. Index: {cardIndex}");
|
81 |
+
return;
|
82 |
+
}
|
83 |
+
|
84 |
+
var settings = frame.FindAsset<CardSettings>(card.CardSettings.Id);
|
85 |
+
if (settings.EnergyCost > CurrentEnergy)
|
86 |
+
{
|
87 |
+
Log.Error($"Not enough energy card request. Index: {cardIndex} Cost: {settings.EnergyCost} Current: {CurrentEnergy}");
|
88 |
+
return;
|
89 |
+
}
|
90 |
+
|
91 |
+
if (settings is UnitSettings)
|
92 |
+
{
|
93 |
+
var gameplay = frame.Unsafe.GetPointerSingleton<Gameplay>();
|
94 |
+
if (gameplay->IsValidUnitPosition(frame, owner, position) == false)
|
95 |
+
{
|
96 |
+
Log.Error($"Invalid unit spawn position. Position: {position}");
|
97 |
+
return;
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
frame.SpawnCard(settings, owner, position, rotation, card.Level);
|
102 |
+
|
103 |
+
AddCardToQueue(frame, card);
|
104 |
+
|
105 |
+
CurrentEnergy -= settings.EnergyCost;
|
106 |
+
availableCards[cardIndex] = default;
|
107 |
+
EmptySlots += 1;
|
108 |
+
|
109 |
+
frame.Events.CardsChanged(entity);
|
110 |
+
}
|
111 |
+
|
112 |
+
// PRIVATE METHODS
|
113 |
+
|
114 |
+
private void FillCardSlot(Frame frame, EntityRef entity)
|
115 |
+
{
|
116 |
+
var availableCards = frame.ResolveList(AvailableCards);
|
117 |
+
|
118 |
+
for (int idx = 0; idx < AVAILABLE_CARDS_COUNT; idx++)
|
119 |
+
{
|
120 |
+
if (availableCards[idx].CardSettings.Id.IsValid == true)
|
121 |
+
continue;
|
122 |
+
|
123 |
+
var cardQueue = frame.ResolveList(CardQueue);
|
124 |
+
|
125 |
+
availableCards[idx] = cardQueue[QueueHeadIndex];
|
126 |
+
QueueHeadIndex = (byte)((QueueHeadIndex + 1) % cardQueue.Count);
|
127 |
+
EmptySlots -= 1;
|
128 |
+
NextFillTime = FP._2;
|
129 |
+
|
130 |
+
frame.Events.CardsChanged(entity);
|
131 |
+
break;
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
private void AddCardToQueue(Frame frame, CardInfo card)
|
136 |
+
{
|
137 |
+
var cardQueue = frame.ResolveList(CardQueue);
|
138 |
+
|
139 |
+
cardQueue[QueueTailIndex] = card;
|
140 |
+
QueueTailIndex = (byte)((QueueTailIndex + 1) % cardQueue.Count);
|
141 |
+
}
|
142 |
+
|
143 |
+
private FPVector2 TransformPosition(FPVector2 position, int unitCount, int unitIndex)
|
144 |
+
{
|
145 |
+
if (unitCount == 1)
|
146 |
+
return position;
|
147 |
+
|
148 |
+
if (unitCount <= 4)
|
149 |
+
{
|
150 |
+
var rotationOffset = FP.Rad_180 * FP._2 / unitCount * unitIndex;
|
151 |
+
position += FPVector2.Rotate(FPVector2.Right * FP._0_50, rotationOffset);
|
152 |
+
}
|
153 |
+
|
154 |
+
if (unitCount <= 12)
|
155 |
+
{
|
156 |
+
if (unitIndex < 4)
|
157 |
+
{
|
158 |
+
var rotationOffset = FP.Rad_180 * FP._2 / 4 * unitIndex;
|
159 |
+
position += FPVector2.Rotate(FPVector2.Right * FP._0_50, rotationOffset);
|
160 |
+
}
|
161 |
+
else
|
162 |
+
{
|
163 |
+
var rotationOffset = FP.Rad_180 * FP._2 / (unitCount - 4) * unitIndex;
|
164 |
+
position += FPVector2.Rotate(FPVector2.Right, rotationOffset);
|
165 |
+
}
|
166 |
+
}
|
167 |
+
|
168 |
+
return position;
|
169 |
+
}
|
170 |
+
}
|
171 |
+
|
172 |
+
[System.Serializable]
|
173 |
+
unsafe partial struct CardInfo
|
174 |
+
{
|
175 |
+
}
|
176 |
+
}
|
data/CardManager.qtn
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
asset CardSettings;
|
2 |
+
|
3 |
+
[ExcludeFromPrototype]
|
4 |
+
component CardManager
|
5 |
+
{
|
6 |
+
Byte EmptySlots;
|
7 |
+
Byte QueueHeadIndex;
|
8 |
+
Byte QueueTailIndex;
|
9 |
+
FP CurrentEnergy;
|
10 |
+
FP EnergyFillRate;
|
11 |
+
FP MaxEnergy;
|
12 |
+
FP NextFillTime;
|
13 |
+
list<CardInfo> CardQueue;
|
14 |
+
list<CardInfo> AvailableCards;
|
15 |
+
}
|
16 |
+
|
17 |
+
struct CardInfo
|
18 |
+
{
|
19 |
+
AssetRefCardSettings CardSettings;
|
20 |
+
Byte Level;
|
21 |
+
}
|
22 |
+
|
23 |
+
[PreserveInPrototype]
|
24 |
+
enum ERarity : byte
|
25 |
+
{
|
26 |
+
Common,
|
27 |
+
Uncommon,
|
28 |
+
Rare,
|
29 |
+
Epic,
|
30 |
+
Legendary,
|
31 |
+
}
|
32 |
+
|
33 |
+
synced event CardsChanged
|
34 |
+
{
|
35 |
+
EntityRef Entity;
|
36 |
+
}
|
data/CardManagerSystem.cs
ADDED
@@ -0,0 +1,38 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
using Photon.Deterministic;
|
4 |
+
|
5 |
+
unsafe class CardManagerSystem : SystemMainThread
|
6 |
+
{
|
7 |
+
public override void Update(Frame frame)
|
8 |
+
{
|
9 |
+
foreach (var pair in frame.Unsafe.GetComponentBlockIterator<CardManager>())
|
10 |
+
{
|
11 |
+
pair.Component->Update(frame, pair.Entity);
|
12 |
+
}
|
13 |
+
|
14 |
+
var gameplay = frame.Unsafe.GetPointerSingleton<Gameplay>();
|
15 |
+
if (gameplay->IsActive == false)
|
16 |
+
return;
|
17 |
+
|
18 |
+
foreach (var pair in frame.Unsafe.GetComponentBlockIterator<Player>())
|
19 |
+
{
|
20 |
+
var command = frame.GetPlayerCommand(pair.Component->PlayerRef);
|
21 |
+
switch (command)
|
22 |
+
{
|
23 |
+
case UseCardCommand useCard:
|
24 |
+
ProcessCommand(frame, pair.Entity, pair.Component->PlayerRef, useCard);
|
25 |
+
break;
|
26 |
+
}
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
+
// PRIVATE METHODS
|
31 |
+
|
32 |
+
private void ProcessCommand(Frame frame, EntityRef entity, PlayerRef playerRef, UseCardCommand useCard)
|
33 |
+
{
|
34 |
+
var cardManager = frame.Unsafe.GetPointer<CardManager>(entity);
|
35 |
+
cardManager->UseCard(frame, entity, playerRef, useCard.CardIndex, useCard.Position, playerRef * FP.Rad_180);
|
36 |
+
}
|
37 |
+
}
|
38 |
+
}
|
data/CardSettings.cs
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
using Photon.Deterministic;
|
4 |
+
using Quantum.Inspector;
|
5 |
+
|
6 |
+
public abstract partial class CardSettings
|
7 |
+
{
|
8 |
+
[Header("Card")]
|
9 |
+
public AssetRefEntityPrototype Prefab;
|
10 |
+
public ERarity Rarity;
|
11 |
+
public byte EnergyCost;
|
12 |
+
public FP ActivationDelay;
|
13 |
+
}
|
14 |
+
}
|
data/Chain.User.cs
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
using System.Collections.Generic;
|
3 |
+
using Photon.Deterministic;
|
4 |
+
|
5 |
+
namespace Quantum
|
6 |
+
{
|
7 |
+
unsafe partial struct Chain
|
8 |
+
{
|
9 |
+
public void Update(FrameThreadSafe frame, ref ChainSystem.Filter filter)
|
10 |
+
{
|
11 |
+
FPVector3 direction = filter.Transform->Position - LastPosition;
|
12 |
+
Alpha = direction.Magnitude / DistanceThreshold;
|
13 |
+
|
14 |
+
// cycle element
|
15 |
+
if (Alpha > FP._1)
|
16 |
+
{
|
17 |
+
Alpha = Alpha % FP._1;
|
18 |
+
AddBreadCrumb(direction);
|
19 |
+
}
|
20 |
+
|
21 |
+
filter.Body->Drag = MinDrag + Count * DragPerItem;
|
22 |
+
if (filter.Drivable->Grounded == false) filter.Body->GravityScale = FP._1;
|
23 |
+
filter.Drivable->Grounded = false;
|
24 |
+
#if DEBUG
|
25 |
+
for (int i = 0; i < Positions.Length; i++)
|
26 |
+
{
|
27 |
+
Draw.Sphere(Positions[i], FP._0_10, ColorRGBA.ColliderBlue);
|
28 |
+
}
|
29 |
+
#endif
|
30 |
+
}
|
31 |
+
|
32 |
+
public void AddBreadCrumb(FPVector3 direction)
|
33 |
+
{
|
34 |
+
FPVector3 newPosition = LastPosition + direction.Normalized * DistanceThreshold;
|
35 |
+
*Positions.GetPointer(Current) = newPosition;
|
36 |
+
Current = (Current + 1) % Positions.Length;
|
37 |
+
LastPosition = newPosition;
|
38 |
+
}
|
39 |
+
}
|
40 |
+
}
|
data/ChainItem.cs
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
using Photon.Deterministic;
|
3 |
+
|
4 |
+
namespace Quantum
|
5 |
+
{
|
6 |
+
unsafe partial struct ChainItem
|
7 |
+
{
|
8 |
+
public void Update(FrameThreadSafe frame, ref ChainItemSystem.Filter filter)
|
9 |
+
{
|
10 |
+
// READ-ONLY for this component, PLEASE
|
11 |
+
if (frame.TryGetPointer<Chain>(Chain, out var chain))
|
12 |
+
{
|
13 |
+
if (chain->Count <= Index)
|
14 |
+
{
|
15 |
+
Destroy = true;
|
16 |
+
return;
|
17 |
+
}
|
18 |
+
|
19 |
+
int indexFrom = (chain->Current - Index + chain->Positions.Length - 2) % chain->Positions.Length;
|
20 |
+
int indexTo = (indexFrom + 1) % chain->Positions.Length;
|
21 |
+
FPVector3 from = chain->Positions[indexFrom];
|
22 |
+
FPVector3 to = chain->Positions[indexTo];
|
23 |
+
FPVector3 position = FPVector3.Lerp(from, to, chain->Alpha);
|
24 |
+
filter.Transform->Position = position;
|
25 |
+
|
26 |
+
FPVector3 direction = (to - from).Normalized;
|
27 |
+
FPQuaternion desiredRotation = FPQuaternion.LookRotation(direction);
|
28 |
+
FP angle = FPQuaternion.Angle(desiredRotation, filter.Transform->Rotation);
|
29 |
+
if (angle < SnapAngle)
|
30 |
+
{
|
31 |
+
filter.Transform->Rotation = FPQuaternion.RotateTowards(filter.Transform->Rotation, desiredRotation, RotationSpeed * frame.DeltaTime);
|
32 |
+
}
|
33 |
+
else
|
34 |
+
{
|
35 |
+
filter.Transform->Rotation = desiredRotation;
|
36 |
+
}
|
37 |
+
|
38 |
+
}
|
39 |
+
}
|
40 |
+
}
|
41 |
+
}
|
data/ChainItemSystem.cs
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
using Photon.Deterministic;
|
3 |
+
using Quantum.Task;
|
4 |
+
|
5 |
+
namespace Quantum
|
6 |
+
{
|
7 |
+
public unsafe class ChainItemSystem : SystemThreadedFilter<ChainItemSystem.Filter>
|
8 |
+
{
|
9 |
+
public struct Filter
|
10 |
+
{
|
11 |
+
public EntityRef Entity;
|
12 |
+
public Transform3D* Transform;
|
13 |
+
public ChainItem* Item;
|
14 |
+
}
|
15 |
+
public override void Update(FrameThreadSafe frame, ref Filter filter)
|
16 |
+
{
|
17 |
+
filter.Item->Update(frame, ref filter);
|
18 |
+
}
|
19 |
+
}
|
20 |
+
}
|
data/ChainSystem.cs
ADDED
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
using Photon.Deterministic;
|
3 |
+
using Quantum.Task;
|
4 |
+
|
5 |
+
namespace Quantum
|
6 |
+
{
|
7 |
+
public unsafe class ChainSystem : SystemThreadedFilter<ChainSystem.Filter>, ISignalOnTrigger3D, ISignalOnCollision3D, ISignalOnComponentAdded<Chain>
|
8 |
+
{
|
9 |
+
public struct Filter
|
10 |
+
{
|
11 |
+
public EntityRef Entity;
|
12 |
+
public Transform3D* Transform;
|
13 |
+
public PhysicsBody3D* Body;
|
14 |
+
public Chain* Chain;
|
15 |
+
public Drivable* Drivable;
|
16 |
+
}
|
17 |
+
|
18 |
+
public void OnAdded(Frame frame, EntityRef entity, Chain* chain)
|
19 |
+
{
|
20 |
+
Transform3D transform = frame.Get<Transform3D>(entity);
|
21 |
+
chain->LastPosition = transform.Position;
|
22 |
+
for (int i = 0; i < 5; i++)
|
23 |
+
{
|
24 |
+
chain->AddBreadCrumb(transform.Back);
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
public void OnTrigger3D(Frame frame, TriggerInfo3D info)
|
29 |
+
{
|
30 |
+
if (frame.Unsafe.TryGetPointer<Pickup>(info.Other, out var pickup) && frame.Unsafe.TryGetPointer<Chain>(info.Entity, out var chain))
|
31 |
+
{
|
32 |
+
EntityRef entity = frame.Create(pickup->ItemPrototype);
|
33 |
+
if (frame.Unsafe.TryGetPointer<ChainItem>(entity, out var item))
|
34 |
+
{
|
35 |
+
int index = chain->Count++;
|
36 |
+
item->Chain = info.Entity;
|
37 |
+
item->Index = index;
|
38 |
+
}
|
39 |
+
if (frame.Unsafe.TryGetPointerSingleton<PickupSpawner>(out var spawner))
|
40 |
+
{
|
41 |
+
spawner->Count--;
|
42 |
+
}
|
43 |
+
frame.Destroy(info.Other);
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
public void OnCollision3D(Frame frame, CollisionInfo3D info)
|
48 |
+
{
|
49 |
+
if (frame.Unsafe.TryGetPointer<Drivable>(info.Entity, out var drivable) && frame.Unsafe.TryGetPointer<PhysicsBody3D>(info.Entity, out var body))
|
50 |
+
{
|
51 |
+
FP angle = FPVector3.Angle(info.ContactNormal, FPVector3.Up);
|
52 |
+
if (angle < 45)
|
53 |
+
{
|
54 |
+
drivable->Grounded = true;
|
55 |
+
drivable->SurfaceNormal = info.ContactNormal;
|
56 |
+
body->GravityScale = FP._0;
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
if (frame.Unsafe.TryGetPointer<ChainItem>(info.Other, out var item) && frame.Unsafe.TryGetPointer<Chain>(item->Chain, out var chain))
|
61 |
+
{
|
62 |
+
chain->Count = Math.Min(item->Index, chain->Count);
|
63 |
+
info.IgnoreCollision = true;
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
+
public override void Update(FrameThreadSafe frame, ref Filter filter)
|
68 |
+
{
|
69 |
+
filter.Chain->Update(frame, ref filter);
|
70 |
+
}
|
71 |
+
}
|
72 |
+
}
|
data/CheckIndicatorView.cs
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System.Collections;
|
2 |
+
using System.Collections.Generic;
|
3 |
+
using UnityEngine;
|
4 |
+
using Quantum;
|
5 |
+
|
6 |
+
public class CheckIndicatorView : QuantumCallbacks {
|
7 |
+
|
8 |
+
public GameObject Indicator;
|
9 |
+
public PieceView Piece;
|
10 |
+
|
11 |
+
void Start () {
|
12 |
+
Indicator.SetActive(false);
|
13 |
+
QuantumEvent.Subscribe<EventPlayerInCheck>(this, SetCheckIndicator);
|
14 |
+
QuantumEvent.Subscribe<EventTurnEnded>(this, ResetCheckIndicator);
|
15 |
+
}
|
16 |
+
|
17 |
+
private void SetCheckIndicator(EventPlayerInCheck e)
|
18 |
+
{
|
19 |
+
if (e.Color == Piece.Color)
|
20 |
+
{
|
21 |
+
Indicator.SetActive(true);
|
22 |
+
}
|
23 |
+
}
|
24 |
+
|
25 |
+
private void ResetCheckIndicator(EventTurnEnded e)
|
26 |
+
{
|
27 |
+
Indicator.SetActive(false);
|
28 |
+
}
|
29 |
+
|
30 |
+
protected override void OnDisable()
|
31 |
+
{
|
32 |
+
QuantumEvent.UnsubscribeListener(this);
|
33 |
+
}
|
34 |
+
}
|
data/ChecksumVerification.cs
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using Newtonsoft.Json;
|
2 |
+
using System;
|
3 |
+
using System.Collections.Generic;
|
4 |
+
using System.IO;
|
5 |
+
|
6 |
+
namespace Quantum {
|
7 |
+
public class ChecksumVerification : IDisposable {
|
8 |
+
private Dictionary<int, ChecksumFile.ChecksumEntry> _checksums;
|
9 |
+
private Quantum.CallbackDispatcher _gameCallbacks;
|
10 |
+
private bool _verbose;
|
11 |
+
|
12 |
+
public ChecksumVerification(string pathToChecksumFile, Quantum.CallbackDispatcher callbacks, bool verbose = false) {
|
13 |
+
_checksums = JsonConvert.DeserializeObject<ChecksumFile>(File.ReadAllText(pathToChecksumFile), ReplayJsonSerializerSettings.GetSettings()).ToDictionary();
|
14 |
+
_gameCallbacks = callbacks;
|
15 |
+
_gameCallbacks.Subscribe(this, (CallbackSimulateFinished callback) => OnSimulateFinished(callback.Game, callback.Frame));
|
16 |
+
_verbose = verbose;
|
17 |
+
}
|
18 |
+
|
19 |
+
private void OnSimulateFinished(QuantumGame game, Frame frame) {
|
20 |
+
if (frame != null) {
|
21 |
+
var f = frame.Number;
|
22 |
+
var cs = ChecksumFileHelper.UlongToLong(frame.CalculateChecksum());
|
23 |
+
|
24 |
+
if (_checksums != null) {
|
25 |
+
|
26 |
+
if (_checksums.ContainsKey(f)) {
|
27 |
+
Console.Write($"{f,6} {cs,25} ");
|
28 |
+
if (cs != _checksums[f].ChecksumAsLong) {
|
29 |
+
Console.ForegroundColor = ConsoleColor.Red;
|
30 |
+
Console.Write("(failed)");
|
31 |
+
} else {
|
32 |
+
Console.ForegroundColor = ConsoleColor.Green;
|
33 |
+
Console.Write("(verified)");
|
34 |
+
}
|
35 |
+
Console.Write("\n");
|
36 |
+
} else if (_verbose) {
|
37 |
+
Console.Write($"{f,6} {cs,25} ");
|
38 |
+
Console.Write("(skipped)");
|
39 |
+
}
|
40 |
+
Console.ForegroundColor = ConsoleColor.Gray;
|
41 |
+
}
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
public void Dispose() {
|
46 |
+
if (_gameCallbacks != null) {
|
47 |
+
_gameCallbacks.UnsubscribeListener(this);
|
48 |
+
_gameCallbacks = null;
|
49 |
+
}
|
50 |
+
}
|
51 |
+
}
|
52 |
+
}
|
data/ChessViewUpdater.cs
ADDED
@@ -0,0 +1,148 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System.Collections;
|
2 |
+
using System.Collections.Generic;
|
3 |
+
using UnityEngine;
|
4 |
+
using Quantum;
|
5 |
+
|
6 |
+
public unsafe class ChessViewUpdater : QuantumCallbacks
|
7 |
+
{
|
8 |
+
public static ChessViewUpdater Instance;
|
9 |
+
|
10 |
+
public PieceView[] Pieces = new PieceView[32];
|
11 |
+
|
12 |
+
public Vector3 PieceOffset = new Vector3(.5f, 0, .5f);
|
13 |
+
|
14 |
+
public GameObject LastMoveIdicatorInitial;
|
15 |
+
public GameObject LastMoveIdicatorTarget;
|
16 |
+
|
17 |
+
public Sprite WhiteQueenSprite;
|
18 |
+
public Sprite WhiteRookSprite;
|
19 |
+
public Sprite WhiteKnightSprite;
|
20 |
+
public Sprite WhiteBishopSprite;
|
21 |
+
//
|
22 |
+
public Sprite BlackQueenSprite;
|
23 |
+
public Sprite BlackRookSprite;
|
24 |
+
public Sprite BlackKnightSprite;
|
25 |
+
public Sprite BlackBishopSprite;
|
26 |
+
|
27 |
+
public DeadPiecesManager DeadPieces;
|
28 |
+
|
29 |
+
private bool _initialized = false;
|
30 |
+
|
31 |
+
|
32 |
+
public void Start()
|
33 |
+
{
|
34 |
+
if (Instance == null)
|
35 |
+
{
|
36 |
+
Instance = this;
|
37 |
+
}
|
38 |
+
|
39 |
+
QuantumEvent.Subscribe<EventChangePiecePosition>(this, UpdatePiece);
|
40 |
+
QuantumEvent.Subscribe<EventRemovePiece>(this, RemovePiece);
|
41 |
+
QuantumEvent.Subscribe<EventPiecePromotion>(this, PiecePromotion);
|
42 |
+
}
|
43 |
+
|
44 |
+
public override void OnUpdateView(QuantumGame game)
|
45 |
+
{
|
46 |
+
if (!_initialized)
|
47 |
+
{
|
48 |
+
_initialized = true;
|
49 |
+
var f = game.Frames.Verified;
|
50 |
+
for (int i = 0; i < f.Global->Board.Cells.Length; i++)
|
51 |
+
{
|
52 |
+
int index = GetPieceIndex(i);
|
53 |
+
if (index != -1)
|
54 |
+
{
|
55 |
+
var p = Pieces[index];
|
56 |
+
var position = BoardHelper.GetCordinatesByIndex(p.IndexOnBoard);
|
57 |
+
p.SetTargetPosition(new Vector3((float)position.X + PieceOffset.x, PieceOffset.x, (float)position.Y + PieceOffset.z));
|
58 |
+
}
|
59 |
+
}
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
public void PiecePromotion(EventPiecePromotion e)
|
64 |
+
{
|
65 |
+
var index = GetPieceIndex(e.Index);
|
66 |
+
Pieces[index].Type = e.NewType;
|
67 |
+
switch (e.NewType)
|
68 |
+
{
|
69 |
+
case PieceType.Bishop:
|
70 |
+
if (Pieces[index].Color == PieceColor.White)
|
71 |
+
Pieces[index].GetComponent<SpriteRenderer>().sprite = WhiteBishopSprite;
|
72 |
+
else
|
73 |
+
Pieces[index].GetComponent<SpriteRenderer>().sprite = BlackBishopSprite;
|
74 |
+
break;
|
75 |
+
case PieceType.Knight:
|
76 |
+
if (Pieces[index].Color == PieceColor.White)
|
77 |
+
Pieces[index].GetComponent<SpriteRenderer>().sprite = WhiteKnightSprite;
|
78 |
+
else
|
79 |
+
Pieces[index].GetComponent<SpriteRenderer>().sprite = BlackKnightSprite;
|
80 |
+
break;
|
81 |
+
case PieceType.Queen:
|
82 |
+
if (Pieces[index].Color == PieceColor.White)
|
83 |
+
Pieces[index].GetComponent<SpriteRenderer>().sprite = WhiteQueenSprite;
|
84 |
+
else
|
85 |
+
Pieces[index].GetComponent<SpriteRenderer>().sprite = BlackQueenSprite;
|
86 |
+
break;
|
87 |
+
case PieceType.Rook:
|
88 |
+
if (Pieces[index].Color == PieceColor.White)
|
89 |
+
Pieces[index].GetComponent<SpriteRenderer>().sprite = WhiteRookSprite;
|
90 |
+
else
|
91 |
+
Pieces[index].GetComponent<SpriteRenderer>().sprite = BlackRookSprite;
|
92 |
+
break;
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
public void UpdatePiece(EventChangePiecePosition e)
|
97 |
+
{
|
98 |
+
var origin = (int)e.Index.X;
|
99 |
+
var target = (int)e.Index.Y;
|
100 |
+
|
101 |
+
SetObjectByIndex(LastMoveIdicatorInitial, origin);
|
102 |
+
SetObjectByIndex(LastMoveIdicatorTarget, target);
|
103 |
+
|
104 |
+
int index = GetPieceIndex(origin);
|
105 |
+
if (index != -1)
|
106 |
+
{
|
107 |
+
var p = Pieces[index];
|
108 |
+
p.IndexOnBoard = target;
|
109 |
+
var position = BoardHelper.GetCordinatesByIndex(p.IndexOnBoard);
|
110 |
+
p.SetTargetPosition(new Vector3((float)position.X + PieceOffset.x, PieceOffset.x, (float)position.Y + PieceOffset.z));
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
public void SetObjectByIndex(GameObject go, int index)
|
115 |
+
{
|
116 |
+
var position = BoardHelper.GetCordinatesByIndex(index);
|
117 |
+
go.transform.position = new Vector3((float)position.X + PieceOffset.x, PieceOffset.y, (float)position.Y + PieceOffset.z);
|
118 |
+
go.SetActive(true);
|
119 |
+
}
|
120 |
+
|
121 |
+
public void RemovePiece(EventRemovePiece e)
|
122 |
+
{
|
123 |
+
var index = GetPieceIndex(e.Index);
|
124 |
+
DeadPieces.StoreDeadPiece(Pieces[index], e.Color);
|
125 |
+
Pieces[index].IndexOnBoard = -1;
|
126 |
+
}
|
127 |
+
|
128 |
+
public int GetPieceIndex(int index)
|
129 |
+
{
|
130 |
+
for (int i = 0; i < Pieces.Length; i++)
|
131 |
+
{
|
132 |
+
if (Pieces[i] == null)
|
133 |
+
{
|
134 |
+
continue;
|
135 |
+
}
|
136 |
+
if (Pieces[i].IndexOnBoard == index)
|
137 |
+
{
|
138 |
+
return i;
|
139 |
+
}
|
140 |
+
}
|
141 |
+
return -1;
|
142 |
+
}
|
143 |
+
|
144 |
+
public void OnDisable()
|
145 |
+
{
|
146 |
+
QuantumEvent.UnsubscribeListener(this);
|
147 |
+
}
|
148 |
+
}
|
data/CodeGen.cs
ADDED
@@ -0,0 +1,1995 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// <auto-generated>
|
2 |
+
// This code was auto-generated by a tool, every time
|
3 |
+
// the tool executes this code will be reset.
|
4 |
+
//
|
5 |
+
// If you need to extend the classes generated to add
|
6 |
+
// fields or methods to them, please create partial
|
7 |
+
// declarations in another file.
|
8 |
+
// </auto-generated>
|
9 |
+
#pragma warning disable 0649
|
10 |
+
#pragma warning disable 1522
|
11 |
+
#pragma warning disable 0414
|
12 |
+
#pragma warning disable 0219
|
13 |
+
#pragma warning disable 0109
|
14 |
+
|
15 |
+
namespace Quantum {
|
16 |
+
using System;
|
17 |
+
using System.Collections.Generic;
|
18 |
+
using System.Runtime.InteropServices;
|
19 |
+
using Photon.Deterministic;
|
20 |
+
using Quantum.Core;
|
21 |
+
using Quantum.Collections;
|
22 |
+
using Quantum.Inspector;
|
23 |
+
using Quantum.Physics2D;
|
24 |
+
using Quantum.Physics3D;
|
25 |
+
using Optional = Quantum.Inspector.OptionalAttribute;
|
26 |
+
using MethodImplAttribute = System.Runtime.CompilerServices.MethodImplAttribute;
|
27 |
+
using MethodImplOptions = System.Runtime.CompilerServices.MethodImplOptions;
|
28 |
+
|
29 |
+
public enum TurnEndReason : int {
|
30 |
+
Time,
|
31 |
+
Skip,
|
32 |
+
Play,
|
33 |
+
Resolved,
|
34 |
+
}
|
35 |
+
public enum TurnStatus : int {
|
36 |
+
Inactive,
|
37 |
+
Active,
|
38 |
+
Resolving,
|
39 |
+
}
|
40 |
+
public enum TurnType : int {
|
41 |
+
Play,
|
42 |
+
Countdown,
|
43 |
+
}
|
44 |
+
[System.FlagsAttribute()]
|
45 |
+
public enum InputButtons : int {
|
46 |
+
}
|
47 |
+
public static unsafe partial class InputButtons_ext {
|
48 |
+
public static Boolean IsFlagSet(this InputButtons self, InputButtons flag) {
|
49 |
+
return (self & flag) == flag;
|
50 |
+
}
|
51 |
+
public static InputButtons SetFlag(this InputButtons self, InputButtons flag) {
|
52 |
+
return self | flag;
|
53 |
+
}
|
54 |
+
public static InputButtons ClearFlag(this InputButtons self, InputButtons flag) {
|
55 |
+
return self & ~flag;
|
56 |
+
}
|
57 |
+
}
|
58 |
+
[StructLayout(LayoutKind.Explicit)]
|
59 |
+
public unsafe partial struct BitSet1024 {
|
60 |
+
public const Int32 SIZE = 128;
|
61 |
+
public const Int32 ALIGNMENT = 8;
|
62 |
+
[FieldOffset(0)]
|
63 |
+
private fixed UInt64 bits[16];
|
64 |
+
public const Int32 BitsSize = 1024;
|
65 |
+
public Int32 Length {
|
66 |
+
get {
|
67 |
+
return 1024;
|
68 |
+
}
|
69 |
+
}
|
70 |
+
public static void Print(void* ptr, FramePrinter printer) {
|
71 |
+
var p = (BitSet1024*)ptr;
|
72 |
+
printer.ScopeBegin();
|
73 |
+
UnmanagedUtils.PrintBytesBits((byte*)&p->bits, 1024, 64, printer);
|
74 |
+
printer.ScopeEnd();
|
75 |
+
}
|
76 |
+
[System.ObsoleteAttribute("Use instance Set method instead")]
|
77 |
+
public static void Set(BitSet1024* set, Int32 bit) {
|
78 |
+
set->bits[bit/64] |= (1UL<<(bit%64));
|
79 |
+
}
|
80 |
+
[System.ObsoleteAttribute("Use instance Clear method instead")]
|
81 |
+
public static void Clear(BitSet1024* set, Int32 bit) {
|
82 |
+
set->bits[bit/64] &= ~(1UL<<(bit%64));
|
83 |
+
}
|
84 |
+
[System.ObsoleteAttribute("Use instance ClearAll method instead")]
|
85 |
+
public static void ClearAll(BitSet1024* set) {
|
86 |
+
Native.Utils.Clear(&set->bits[0], 128);
|
87 |
+
}
|
88 |
+
[System.ObsoleteAttribute("Use instance IsSet method instead")]
|
89 |
+
public static Boolean IsSet(BitSet1024* set, Int32 bit) {
|
90 |
+
return (set->bits[bit/64]&(1UL<<(bit%64))) != 0UL;
|
91 |
+
}
|
92 |
+
public static BitSet1024 FromArray(UInt64[] values) {
|
93 |
+
Assert.Always(16 == values.Length);
|
94 |
+
BitSet1024 result = default;
|
95 |
+
for (int i = 0; i < 16; ++i) {
|
96 |
+
result.bits[i] = values[i];
|
97 |
+
}
|
98 |
+
return result;
|
99 |
+
}
|
100 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
101 |
+
public void Set(Int32 bit) {
|
102 |
+
Assert.Check(bit >= 0 && bit < 1024);
|
103 |
+
fixed (UInt64* p = bits) (p[bit/64]) |= (1UL<<(bit%64));
|
104 |
+
}
|
105 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
106 |
+
public void Clear(Int32 bit) {
|
107 |
+
Assert.Check(bit >= 0 && bit < 1024);
|
108 |
+
fixed (UInt64* p = bits) (p[bit/64]) &= ~(1UL<<(bit%64));
|
109 |
+
}
|
110 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
111 |
+
public void ClearAll() {
|
112 |
+
fixed (UInt64* p = bits) Native.Utils.Clear(p, 128);
|
113 |
+
}
|
114 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
115 |
+
public Boolean IsSet(Int32 bit) {
|
116 |
+
fixed (UInt64* p = bits) return ((p[bit/64])&(1UL<<(bit%64))) != 0UL;
|
117 |
+
}
|
118 |
+
public override Int32 GetHashCode() {
|
119 |
+
unchecked {
|
120 |
+
var hash = 37;
|
121 |
+
fixed (UInt64* p = bits) hash = hash * 31 + HashCodeUtils.GetArrayHashCode(p, 16);
|
122 |
+
return hash;
|
123 |
+
}
|
124 |
+
}
|
125 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
126 |
+
var p = (BitSet1024*)ptr;
|
127 |
+
serializer.Stream.SerializeBuffer(&p->bits[0], 16);
|
128 |
+
}
|
129 |
+
}
|
130 |
+
[StructLayout(LayoutKind.Explicit)]
|
131 |
+
public unsafe partial struct BitSet128 {
|
132 |
+
public const Int32 SIZE = 16;
|
133 |
+
public const Int32 ALIGNMENT = 8;
|
134 |
+
[FieldOffset(0)]
|
135 |
+
private fixed UInt64 bits[2];
|
136 |
+
public const Int32 BitsSize = 128;
|
137 |
+
public Int32 Length {
|
138 |
+
get {
|
139 |
+
return 128;
|
140 |
+
}
|
141 |
+
}
|
142 |
+
public static void Print(void* ptr, FramePrinter printer) {
|
143 |
+
var p = (BitSet128*)ptr;
|
144 |
+
printer.ScopeBegin();
|
145 |
+
UnmanagedUtils.PrintBytesBits((byte*)&p->bits, 128, 64, printer);
|
146 |
+
printer.ScopeEnd();
|
147 |
+
}
|
148 |
+
[System.ObsoleteAttribute("Use instance Set method instead")]
|
149 |
+
public static void Set(BitSet128* set, Int32 bit) {
|
150 |
+
set->bits[bit/64] |= (1UL<<(bit%64));
|
151 |
+
}
|
152 |
+
[System.ObsoleteAttribute("Use instance Clear method instead")]
|
153 |
+
public static void Clear(BitSet128* set, Int32 bit) {
|
154 |
+
set->bits[bit/64] &= ~(1UL<<(bit%64));
|
155 |
+
}
|
156 |
+
[System.ObsoleteAttribute("Use instance ClearAll method instead")]
|
157 |
+
public static void ClearAll(BitSet128* set) {
|
158 |
+
Native.Utils.Clear(&set->bits[0], 16);
|
159 |
+
}
|
160 |
+
[System.ObsoleteAttribute("Use instance IsSet method instead")]
|
161 |
+
public static Boolean IsSet(BitSet128* set, Int32 bit) {
|
162 |
+
return (set->bits[bit/64]&(1UL<<(bit%64))) != 0UL;
|
163 |
+
}
|
164 |
+
public static BitSet128 FromArray(UInt64[] values) {
|
165 |
+
Assert.Always(2 == values.Length);
|
166 |
+
BitSet128 result = default;
|
167 |
+
for (int i = 0; i < 2; ++i) {
|
168 |
+
result.bits[i] = values[i];
|
169 |
+
}
|
170 |
+
return result;
|
171 |
+
}
|
172 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
173 |
+
public void Set(Int32 bit) {
|
174 |
+
Assert.Check(bit >= 0 && bit < 128);
|
175 |
+
fixed (UInt64* p = bits) (p[bit/64]) |= (1UL<<(bit%64));
|
176 |
+
}
|
177 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
178 |
+
public void Clear(Int32 bit) {
|
179 |
+
Assert.Check(bit >= 0 && bit < 128);
|
180 |
+
fixed (UInt64* p = bits) (p[bit/64]) &= ~(1UL<<(bit%64));
|
181 |
+
}
|
182 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
183 |
+
public void ClearAll() {
|
184 |
+
fixed (UInt64* p = bits) Native.Utils.Clear(p, 16);
|
185 |
+
}
|
186 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
187 |
+
public Boolean IsSet(Int32 bit) {
|
188 |
+
fixed (UInt64* p = bits) return ((p[bit/64])&(1UL<<(bit%64))) != 0UL;
|
189 |
+
}
|
190 |
+
public override Int32 GetHashCode() {
|
191 |
+
unchecked {
|
192 |
+
var hash = 41;
|
193 |
+
fixed (UInt64* p = bits) hash = hash * 31 + HashCodeUtils.GetArrayHashCode(p, 2);
|
194 |
+
return hash;
|
195 |
+
}
|
196 |
+
}
|
197 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
198 |
+
var p = (BitSet128*)ptr;
|
199 |
+
serializer.Stream.SerializeBuffer(&p->bits[0], 2);
|
200 |
+
}
|
201 |
+
}
|
202 |
+
[StructLayout(LayoutKind.Explicit)]
|
203 |
+
public unsafe partial struct BitSet2 {
|
204 |
+
public const Int32 SIZE = 8;
|
205 |
+
public const Int32 ALIGNMENT = 8;
|
206 |
+
[FieldOffset(0)]
|
207 |
+
private fixed UInt64 bits[1];
|
208 |
+
public const Int32 BitsSize = 2;
|
209 |
+
public Int32 Length {
|
210 |
+
get {
|
211 |
+
return 2;
|
212 |
+
}
|
213 |
+
}
|
214 |
+
public static void Print(void* ptr, FramePrinter printer) {
|
215 |
+
var p = (BitSet2*)ptr;
|
216 |
+
printer.ScopeBegin();
|
217 |
+
UnmanagedUtils.PrintBytesBits((byte*)&p->bits, 2, 64, printer);
|
218 |
+
printer.ScopeEnd();
|
219 |
+
}
|
220 |
+
[System.ObsoleteAttribute("Use instance Set method instead")]
|
221 |
+
public static void Set(BitSet2* set, Int32 bit) {
|
222 |
+
set->bits[bit/64] |= (1UL<<(bit%64));
|
223 |
+
}
|
224 |
+
[System.ObsoleteAttribute("Use instance Clear method instead")]
|
225 |
+
public static void Clear(BitSet2* set, Int32 bit) {
|
226 |
+
set->bits[bit/64] &= ~(1UL<<(bit%64));
|
227 |
+
}
|
228 |
+
[System.ObsoleteAttribute("Use instance ClearAll method instead")]
|
229 |
+
public static void ClearAll(BitSet2* set) {
|
230 |
+
Native.Utils.Clear(&set->bits[0], 8);
|
231 |
+
}
|
232 |
+
[System.ObsoleteAttribute("Use instance IsSet method instead")]
|
233 |
+
public static Boolean IsSet(BitSet2* set, Int32 bit) {
|
234 |
+
return (set->bits[bit/64]&(1UL<<(bit%64))) != 0UL;
|
235 |
+
}
|
236 |
+
public static BitSet2 FromArray(UInt64[] values) {
|
237 |
+
Assert.Always(1 == values.Length);
|
238 |
+
BitSet2 result = default;
|
239 |
+
for (int i = 0; i < 1; ++i) {
|
240 |
+
result.bits[i] = values[i];
|
241 |
+
}
|
242 |
+
return result;
|
243 |
+
}
|
244 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
245 |
+
public void Set(Int32 bit) {
|
246 |
+
Assert.Check(bit >= 0 && bit < 2);
|
247 |
+
fixed (UInt64* p = bits) (p[bit/64]) |= (1UL<<(bit%64));
|
248 |
+
}
|
249 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
250 |
+
public void Clear(Int32 bit) {
|
251 |
+
Assert.Check(bit >= 0 && bit < 2);
|
252 |
+
fixed (UInt64* p = bits) (p[bit/64]) &= ~(1UL<<(bit%64));
|
253 |
+
}
|
254 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
255 |
+
public void ClearAll() {
|
256 |
+
fixed (UInt64* p = bits) Native.Utils.Clear(p, 8);
|
257 |
+
}
|
258 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
259 |
+
public Boolean IsSet(Int32 bit) {
|
260 |
+
fixed (UInt64* p = bits) return ((p[bit/64])&(1UL<<(bit%64))) != 0UL;
|
261 |
+
}
|
262 |
+
public override Int32 GetHashCode() {
|
263 |
+
unchecked {
|
264 |
+
var hash = 43;
|
265 |
+
fixed (UInt64* p = bits) hash = hash * 31 + HashCodeUtils.GetArrayHashCode(p, 1);
|
266 |
+
return hash;
|
267 |
+
}
|
268 |
+
}
|
269 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
270 |
+
var p = (BitSet2*)ptr;
|
271 |
+
serializer.Stream.SerializeBuffer(&p->bits[0], 1);
|
272 |
+
}
|
273 |
+
}
|
274 |
+
[StructLayout(LayoutKind.Explicit)]
|
275 |
+
public unsafe partial struct BitSet2048 {
|
276 |
+
public const Int32 SIZE = 256;
|
277 |
+
public const Int32 ALIGNMENT = 8;
|
278 |
+
[FieldOffset(0)]
|
279 |
+
private fixed UInt64 bits[32];
|
280 |
+
public const Int32 BitsSize = 2048;
|
281 |
+
public Int32 Length {
|
282 |
+
get {
|
283 |
+
return 2048;
|
284 |
+
}
|
285 |
+
}
|
286 |
+
public static void Print(void* ptr, FramePrinter printer) {
|
287 |
+
var p = (BitSet2048*)ptr;
|
288 |
+
printer.ScopeBegin();
|
289 |
+
UnmanagedUtils.PrintBytesBits((byte*)&p->bits, 2048, 64, printer);
|
290 |
+
printer.ScopeEnd();
|
291 |
+
}
|
292 |
+
[System.ObsoleteAttribute("Use instance Set method instead")]
|
293 |
+
public static void Set(BitSet2048* set, Int32 bit) {
|
294 |
+
set->bits[bit/64] |= (1UL<<(bit%64));
|
295 |
+
}
|
296 |
+
[System.ObsoleteAttribute("Use instance Clear method instead")]
|
297 |
+
public static void Clear(BitSet2048* set, Int32 bit) {
|
298 |
+
set->bits[bit/64] &= ~(1UL<<(bit%64));
|
299 |
+
}
|
300 |
+
[System.ObsoleteAttribute("Use instance ClearAll method instead")]
|
301 |
+
public static void ClearAll(BitSet2048* set) {
|
302 |
+
Native.Utils.Clear(&set->bits[0], 256);
|
303 |
+
}
|
304 |
+
[System.ObsoleteAttribute("Use instance IsSet method instead")]
|
305 |
+
public static Boolean IsSet(BitSet2048* set, Int32 bit) {
|
306 |
+
return (set->bits[bit/64]&(1UL<<(bit%64))) != 0UL;
|
307 |
+
}
|
308 |
+
public static BitSet2048 FromArray(UInt64[] values) {
|
309 |
+
Assert.Always(32 == values.Length);
|
310 |
+
BitSet2048 result = default;
|
311 |
+
for (int i = 0; i < 32; ++i) {
|
312 |
+
result.bits[i] = values[i];
|
313 |
+
}
|
314 |
+
return result;
|
315 |
+
}
|
316 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
317 |
+
public void Set(Int32 bit) {
|
318 |
+
Assert.Check(bit >= 0 && bit < 2048);
|
319 |
+
fixed (UInt64* p = bits) (p[bit/64]) |= (1UL<<(bit%64));
|
320 |
+
}
|
321 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
322 |
+
public void Clear(Int32 bit) {
|
323 |
+
Assert.Check(bit >= 0 && bit < 2048);
|
324 |
+
fixed (UInt64* p = bits) (p[bit/64]) &= ~(1UL<<(bit%64));
|
325 |
+
}
|
326 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
327 |
+
public void ClearAll() {
|
328 |
+
fixed (UInt64* p = bits) Native.Utils.Clear(p, 256);
|
329 |
+
}
|
330 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
331 |
+
public Boolean IsSet(Int32 bit) {
|
332 |
+
fixed (UInt64* p = bits) return ((p[bit/64])&(1UL<<(bit%64))) != 0UL;
|
333 |
+
}
|
334 |
+
public override Int32 GetHashCode() {
|
335 |
+
unchecked {
|
336 |
+
var hash = 47;
|
337 |
+
fixed (UInt64* p = bits) hash = hash * 31 + HashCodeUtils.GetArrayHashCode(p, 32);
|
338 |
+
return hash;
|
339 |
+
}
|
340 |
+
}
|
341 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
342 |
+
var p = (BitSet2048*)ptr;
|
343 |
+
serializer.Stream.SerializeBuffer(&p->bits[0], 32);
|
344 |
+
}
|
345 |
+
}
|
346 |
+
[StructLayout(LayoutKind.Explicit)]
|
347 |
+
public unsafe partial struct BitSet256 {
|
348 |
+
public const Int32 SIZE = 32;
|
349 |
+
public const Int32 ALIGNMENT = 8;
|
350 |
+
[FieldOffset(0)]
|
351 |
+
private fixed UInt64 bits[4];
|
352 |
+
public const Int32 BitsSize = 256;
|
353 |
+
public Int32 Length {
|
354 |
+
get {
|
355 |
+
return 256;
|
356 |
+
}
|
357 |
+
}
|
358 |
+
public static void Print(void* ptr, FramePrinter printer) {
|
359 |
+
var p = (BitSet256*)ptr;
|
360 |
+
printer.ScopeBegin();
|
361 |
+
UnmanagedUtils.PrintBytesBits((byte*)&p->bits, 256, 64, printer);
|
362 |
+
printer.ScopeEnd();
|
363 |
+
}
|
364 |
+
[System.ObsoleteAttribute("Use instance Set method instead")]
|
365 |
+
public static void Set(BitSet256* set, Int32 bit) {
|
366 |
+
set->bits[bit/64] |= (1UL<<(bit%64));
|
367 |
+
}
|
368 |
+
[System.ObsoleteAttribute("Use instance Clear method instead")]
|
369 |
+
public static void Clear(BitSet256* set, Int32 bit) {
|
370 |
+
set->bits[bit/64] &= ~(1UL<<(bit%64));
|
371 |
+
}
|
372 |
+
[System.ObsoleteAttribute("Use instance ClearAll method instead")]
|
373 |
+
public static void ClearAll(BitSet256* set) {
|
374 |
+
Native.Utils.Clear(&set->bits[0], 32);
|
375 |
+
}
|
376 |
+
[System.ObsoleteAttribute("Use instance IsSet method instead")]
|
377 |
+
public static Boolean IsSet(BitSet256* set, Int32 bit) {
|
378 |
+
return (set->bits[bit/64]&(1UL<<(bit%64))) != 0UL;
|
379 |
+
}
|
380 |
+
public static BitSet256 FromArray(UInt64[] values) {
|
381 |
+
Assert.Always(4 == values.Length);
|
382 |
+
BitSet256 result = default;
|
383 |
+
for (int i = 0; i < 4; ++i) {
|
384 |
+
result.bits[i] = values[i];
|
385 |
+
}
|
386 |
+
return result;
|
387 |
+
}
|
388 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
389 |
+
public void Set(Int32 bit) {
|
390 |
+
Assert.Check(bit >= 0 && bit < 256);
|
391 |
+
fixed (UInt64* p = bits) (p[bit/64]) |= (1UL<<(bit%64));
|
392 |
+
}
|
393 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
394 |
+
public void Clear(Int32 bit) {
|
395 |
+
Assert.Check(bit >= 0 && bit < 256);
|
396 |
+
fixed (UInt64* p = bits) (p[bit/64]) &= ~(1UL<<(bit%64));
|
397 |
+
}
|
398 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
399 |
+
public void ClearAll() {
|
400 |
+
fixed (UInt64* p = bits) Native.Utils.Clear(p, 32);
|
401 |
+
}
|
402 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
403 |
+
public Boolean IsSet(Int32 bit) {
|
404 |
+
fixed (UInt64* p = bits) return ((p[bit/64])&(1UL<<(bit%64))) != 0UL;
|
405 |
+
}
|
406 |
+
public override Int32 GetHashCode() {
|
407 |
+
unchecked {
|
408 |
+
var hash = 53;
|
409 |
+
fixed (UInt64* p = bits) hash = hash * 31 + HashCodeUtils.GetArrayHashCode(p, 4);
|
410 |
+
return hash;
|
411 |
+
}
|
412 |
+
}
|
413 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
414 |
+
var p = (BitSet256*)ptr;
|
415 |
+
serializer.Stream.SerializeBuffer(&p->bits[0], 4);
|
416 |
+
}
|
417 |
+
}
|
418 |
+
[StructLayout(LayoutKind.Explicit)]
|
419 |
+
public unsafe partial struct BitSet4096 {
|
420 |
+
public const Int32 SIZE = 512;
|
421 |
+
public const Int32 ALIGNMENT = 8;
|
422 |
+
[FieldOffset(0)]
|
423 |
+
private fixed UInt64 bits[64];
|
424 |
+
public const Int32 BitsSize = 4096;
|
425 |
+
public Int32 Length {
|
426 |
+
get {
|
427 |
+
return 4096;
|
428 |
+
}
|
429 |
+
}
|
430 |
+
public static void Print(void* ptr, FramePrinter printer) {
|
431 |
+
var p = (BitSet4096*)ptr;
|
432 |
+
printer.ScopeBegin();
|
433 |
+
UnmanagedUtils.PrintBytesBits((byte*)&p->bits, 4096, 64, printer);
|
434 |
+
printer.ScopeEnd();
|
435 |
+
}
|
436 |
+
[System.ObsoleteAttribute("Use instance Set method instead")]
|
437 |
+
public static void Set(BitSet4096* set, Int32 bit) {
|
438 |
+
set->bits[bit/64] |= (1UL<<(bit%64));
|
439 |
+
}
|
440 |
+
[System.ObsoleteAttribute("Use instance Clear method instead")]
|
441 |
+
public static void Clear(BitSet4096* set, Int32 bit) {
|
442 |
+
set->bits[bit/64] &= ~(1UL<<(bit%64));
|
443 |
+
}
|
444 |
+
[System.ObsoleteAttribute("Use instance ClearAll method instead")]
|
445 |
+
public static void ClearAll(BitSet4096* set) {
|
446 |
+
Native.Utils.Clear(&set->bits[0], 512);
|
447 |
+
}
|
448 |
+
[System.ObsoleteAttribute("Use instance IsSet method instead")]
|
449 |
+
public static Boolean IsSet(BitSet4096* set, Int32 bit) {
|
450 |
+
return (set->bits[bit/64]&(1UL<<(bit%64))) != 0UL;
|
451 |
+
}
|
452 |
+
public static BitSet4096 FromArray(UInt64[] values) {
|
453 |
+
Assert.Always(64 == values.Length);
|
454 |
+
BitSet4096 result = default;
|
455 |
+
for (int i = 0; i < 64; ++i) {
|
456 |
+
result.bits[i] = values[i];
|
457 |
+
}
|
458 |
+
return result;
|
459 |
+
}
|
460 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
461 |
+
public void Set(Int32 bit) {
|
462 |
+
Assert.Check(bit >= 0 && bit < 4096);
|
463 |
+
fixed (UInt64* p = bits) (p[bit/64]) |= (1UL<<(bit%64));
|
464 |
+
}
|
465 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
466 |
+
public void Clear(Int32 bit) {
|
467 |
+
Assert.Check(bit >= 0 && bit < 4096);
|
468 |
+
fixed (UInt64* p = bits) (p[bit/64]) &= ~(1UL<<(bit%64));
|
469 |
+
}
|
470 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
471 |
+
public void ClearAll() {
|
472 |
+
fixed (UInt64* p = bits) Native.Utils.Clear(p, 512);
|
473 |
+
}
|
474 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
475 |
+
public Boolean IsSet(Int32 bit) {
|
476 |
+
fixed (UInt64* p = bits) return ((p[bit/64])&(1UL<<(bit%64))) != 0UL;
|
477 |
+
}
|
478 |
+
public override Int32 GetHashCode() {
|
479 |
+
unchecked {
|
480 |
+
var hash = 59;
|
481 |
+
fixed (UInt64* p = bits) hash = hash * 31 + HashCodeUtils.GetArrayHashCode(p, 64);
|
482 |
+
return hash;
|
483 |
+
}
|
484 |
+
}
|
485 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
486 |
+
var p = (BitSet4096*)ptr;
|
487 |
+
serializer.Stream.SerializeBuffer(&p->bits[0], 64);
|
488 |
+
}
|
489 |
+
}
|
490 |
+
[StructLayout(LayoutKind.Explicit)]
|
491 |
+
public unsafe partial struct BitSet512 {
|
492 |
+
public const Int32 SIZE = 64;
|
493 |
+
public const Int32 ALIGNMENT = 8;
|
494 |
+
[FieldOffset(0)]
|
495 |
+
private fixed UInt64 bits[8];
|
496 |
+
public const Int32 BitsSize = 512;
|
497 |
+
public Int32 Length {
|
498 |
+
get {
|
499 |
+
return 512;
|
500 |
+
}
|
501 |
+
}
|
502 |
+
public static void Print(void* ptr, FramePrinter printer) {
|
503 |
+
var p = (BitSet512*)ptr;
|
504 |
+
printer.ScopeBegin();
|
505 |
+
UnmanagedUtils.PrintBytesBits((byte*)&p->bits, 512, 64, printer);
|
506 |
+
printer.ScopeEnd();
|
507 |
+
}
|
508 |
+
[System.ObsoleteAttribute("Use instance Set method instead")]
|
509 |
+
public static void Set(BitSet512* set, Int32 bit) {
|
510 |
+
set->bits[bit/64] |= (1UL<<(bit%64));
|
511 |
+
}
|
512 |
+
[System.ObsoleteAttribute("Use instance Clear method instead")]
|
513 |
+
public static void Clear(BitSet512* set, Int32 bit) {
|
514 |
+
set->bits[bit/64] &= ~(1UL<<(bit%64));
|
515 |
+
}
|
516 |
+
[System.ObsoleteAttribute("Use instance ClearAll method instead")]
|
517 |
+
public static void ClearAll(BitSet512* set) {
|
518 |
+
Native.Utils.Clear(&set->bits[0], 64);
|
519 |
+
}
|
520 |
+
[System.ObsoleteAttribute("Use instance IsSet method instead")]
|
521 |
+
public static Boolean IsSet(BitSet512* set, Int32 bit) {
|
522 |
+
return (set->bits[bit/64]&(1UL<<(bit%64))) != 0UL;
|
523 |
+
}
|
524 |
+
public static BitSet512 FromArray(UInt64[] values) {
|
525 |
+
Assert.Always(8 == values.Length);
|
526 |
+
BitSet512 result = default;
|
527 |
+
for (int i = 0; i < 8; ++i) {
|
528 |
+
result.bits[i] = values[i];
|
529 |
+
}
|
530 |
+
return result;
|
531 |
+
}
|
532 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
533 |
+
public void Set(Int32 bit) {
|
534 |
+
Assert.Check(bit >= 0 && bit < 512);
|
535 |
+
fixed (UInt64* p = bits) (p[bit/64]) |= (1UL<<(bit%64));
|
536 |
+
}
|
537 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
538 |
+
public void Clear(Int32 bit) {
|
539 |
+
Assert.Check(bit >= 0 && bit < 512);
|
540 |
+
fixed (UInt64* p = bits) (p[bit/64]) &= ~(1UL<<(bit%64));
|
541 |
+
}
|
542 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
543 |
+
public void ClearAll() {
|
544 |
+
fixed (UInt64* p = bits) Native.Utils.Clear(p, 64);
|
545 |
+
}
|
546 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
547 |
+
public Boolean IsSet(Int32 bit) {
|
548 |
+
fixed (UInt64* p = bits) return ((p[bit/64])&(1UL<<(bit%64))) != 0UL;
|
549 |
+
}
|
550 |
+
public override Int32 GetHashCode() {
|
551 |
+
unchecked {
|
552 |
+
var hash = 61;
|
553 |
+
fixed (UInt64* p = bits) hash = hash * 31 + HashCodeUtils.GetArrayHashCode(p, 8);
|
554 |
+
return hash;
|
555 |
+
}
|
556 |
+
}
|
557 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
558 |
+
var p = (BitSet512*)ptr;
|
559 |
+
serializer.Stream.SerializeBuffer(&p->bits[0], 8);
|
560 |
+
}
|
561 |
+
}
|
562 |
+
[StructLayout(LayoutKind.Explicit)]
|
563 |
+
[Quantum.AssetRefAttribute(typeof(BallPoolSpec))]
|
564 |
+
[System.SerializableAttribute()]
|
565 |
+
public unsafe partial struct AssetRefBallPoolSpec : IEquatable<AssetRefBallPoolSpec>, IAssetRef<BallPoolSpec> {
|
566 |
+
public const Int32 SIZE = 8;
|
567 |
+
public const Int32 ALIGNMENT = 8;
|
568 |
+
[FieldOffset(0)]
|
569 |
+
public AssetGuid Id;
|
570 |
+
public override String ToString() {
|
571 |
+
return AssetRef.ToString(Id);
|
572 |
+
}
|
573 |
+
public static implicit operator AssetRefBallPoolSpec(BallPoolSpec value) {
|
574 |
+
var r = default(AssetRefBallPoolSpec);
|
575 |
+
if (value != null) {
|
576 |
+
r.Id = value.Guid;
|
577 |
+
}
|
578 |
+
return r;
|
579 |
+
}
|
580 |
+
public override Boolean Equals(Object obj) {
|
581 |
+
return obj is AssetRefBallPoolSpec other && Equals(other);
|
582 |
+
}
|
583 |
+
public Boolean Equals(AssetRefBallPoolSpec other) {
|
584 |
+
return Id.Equals(other.Id);
|
585 |
+
}
|
586 |
+
public static Boolean operator ==(AssetRefBallPoolSpec a, AssetRefBallPoolSpec b) {
|
587 |
+
return a.Id == b.Id;
|
588 |
+
}
|
589 |
+
public static Boolean operator !=(AssetRefBallPoolSpec a, AssetRefBallPoolSpec b) {
|
590 |
+
return a.Id != b.Id;
|
591 |
+
}
|
592 |
+
public override Int32 GetHashCode() {
|
593 |
+
unchecked {
|
594 |
+
var hash = 67;
|
595 |
+
hash = hash * 31 + Id.GetHashCode();
|
596 |
+
return hash;
|
597 |
+
}
|
598 |
+
}
|
599 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
600 |
+
var p = (AssetRefBallPoolSpec*)ptr;
|
601 |
+
AssetGuid.Serialize(&p->Id, serializer);
|
602 |
+
}
|
603 |
+
}
|
604 |
+
[StructLayout(LayoutKind.Explicit)]
|
605 |
+
[Quantum.AssetRefAttribute(typeof(ConfigAssets))]
|
606 |
+
[System.SerializableAttribute()]
|
607 |
+
public unsafe partial struct AssetRefConfigAssets : IEquatable<AssetRefConfigAssets>, IAssetRef<ConfigAssets> {
|
608 |
+
public const Int32 SIZE = 8;
|
609 |
+
public const Int32 ALIGNMENT = 8;
|
610 |
+
[FieldOffset(0)]
|
611 |
+
public AssetGuid Id;
|
612 |
+
public override String ToString() {
|
613 |
+
return AssetRef.ToString(Id);
|
614 |
+
}
|
615 |
+
public static implicit operator AssetRefConfigAssets(ConfigAssets value) {
|
616 |
+
var r = default(AssetRefConfigAssets);
|
617 |
+
if (value != null) {
|
618 |
+
r.Id = value.Guid;
|
619 |
+
}
|
620 |
+
return r;
|
621 |
+
}
|
622 |
+
public override Boolean Equals(Object obj) {
|
623 |
+
return obj is AssetRefConfigAssets other && Equals(other);
|
624 |
+
}
|
625 |
+
public Boolean Equals(AssetRefConfigAssets other) {
|
626 |
+
return Id.Equals(other.Id);
|
627 |
+
}
|
628 |
+
public static Boolean operator ==(AssetRefConfigAssets a, AssetRefConfigAssets b) {
|
629 |
+
return a.Id == b.Id;
|
630 |
+
}
|
631 |
+
public static Boolean operator !=(AssetRefConfigAssets a, AssetRefConfigAssets b) {
|
632 |
+
return a.Id != b.Id;
|
633 |
+
}
|
634 |
+
public override Int32 GetHashCode() {
|
635 |
+
unchecked {
|
636 |
+
var hash = 71;
|
637 |
+
hash = hash * 31 + Id.GetHashCode();
|
638 |
+
return hash;
|
639 |
+
}
|
640 |
+
}
|
641 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
642 |
+
var p = (AssetRefConfigAssets*)ptr;
|
643 |
+
AssetGuid.Serialize(&p->Id, serializer);
|
644 |
+
}
|
645 |
+
}
|
646 |
+
[StructLayout(LayoutKind.Explicit)]
|
647 |
+
[Quantum.AssetRefAttribute(typeof(GameConfig))]
|
648 |
+
[System.SerializableAttribute()]
|
649 |
+
public unsafe partial struct AssetRefGameConfig : IEquatable<AssetRefGameConfig>, IAssetRef<GameConfig> {
|
650 |
+
public const Int32 SIZE = 8;
|
651 |
+
public const Int32 ALIGNMENT = 8;
|
652 |
+
[FieldOffset(0)]
|
653 |
+
public AssetGuid Id;
|
654 |
+
public override String ToString() {
|
655 |
+
return AssetRef.ToString(Id);
|
656 |
+
}
|
657 |
+
public static implicit operator AssetRefGameConfig(GameConfig value) {
|
658 |
+
var r = default(AssetRefGameConfig);
|
659 |
+
if (value != null) {
|
660 |
+
r.Id = value.Guid;
|
661 |
+
}
|
662 |
+
return r;
|
663 |
+
}
|
664 |
+
public override Boolean Equals(Object obj) {
|
665 |
+
return obj is AssetRefGameConfig other && Equals(other);
|
666 |
+
}
|
667 |
+
public Boolean Equals(AssetRefGameConfig other) {
|
668 |
+
return Id.Equals(other.Id);
|
669 |
+
}
|
670 |
+
public static Boolean operator ==(AssetRefGameConfig a, AssetRefGameConfig b) {
|
671 |
+
return a.Id == b.Id;
|
672 |
+
}
|
673 |
+
public static Boolean operator !=(AssetRefGameConfig a, AssetRefGameConfig b) {
|
674 |
+
return a.Id != b.Id;
|
675 |
+
}
|
676 |
+
public override Int32 GetHashCode() {
|
677 |
+
unchecked {
|
678 |
+
var hash = 73;
|
679 |
+
hash = hash * 31 + Id.GetHashCode();
|
680 |
+
return hash;
|
681 |
+
}
|
682 |
+
}
|
683 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
684 |
+
var p = (AssetRefGameConfig*)ptr;
|
685 |
+
AssetGuid.Serialize(&p->Id, serializer);
|
686 |
+
}
|
687 |
+
}
|
688 |
+
[StructLayout(LayoutKind.Explicit)]
|
689 |
+
[Quantum.AssetRefAttribute(typeof(TurnConfig))]
|
690 |
+
[System.SerializableAttribute()]
|
691 |
+
public unsafe partial struct AssetRefTurnConfig : IEquatable<AssetRefTurnConfig>, IAssetRef<TurnConfig> {
|
692 |
+
public const Int32 SIZE = 8;
|
693 |
+
public const Int32 ALIGNMENT = 8;
|
694 |
+
[FieldOffset(0)]
|
695 |
+
public AssetGuid Id;
|
696 |
+
public override String ToString() {
|
697 |
+
return AssetRef.ToString(Id);
|
698 |
+
}
|
699 |
+
public static implicit operator AssetRefTurnConfig(TurnConfig value) {
|
700 |
+
var r = default(AssetRefTurnConfig);
|
701 |
+
if (value != null) {
|
702 |
+
r.Id = value.Guid;
|
703 |
+
}
|
704 |
+
return r;
|
705 |
+
}
|
706 |
+
public override Boolean Equals(Object obj) {
|
707 |
+
return obj is AssetRefTurnConfig other && Equals(other);
|
708 |
+
}
|
709 |
+
public Boolean Equals(AssetRefTurnConfig other) {
|
710 |
+
return Id.Equals(other.Id);
|
711 |
+
}
|
712 |
+
public static Boolean operator ==(AssetRefTurnConfig a, AssetRefTurnConfig b) {
|
713 |
+
return a.Id == b.Id;
|
714 |
+
}
|
715 |
+
public static Boolean operator !=(AssetRefTurnConfig a, AssetRefTurnConfig b) {
|
716 |
+
return a.Id != b.Id;
|
717 |
+
}
|
718 |
+
public override Int32 GetHashCode() {
|
719 |
+
unchecked {
|
720 |
+
var hash = 79;
|
721 |
+
hash = hash * 31 + Id.GetHashCode();
|
722 |
+
return hash;
|
723 |
+
}
|
724 |
+
}
|
725 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
726 |
+
var p = (AssetRefTurnConfig*)ptr;
|
727 |
+
AssetGuid.Serialize(&p->Id, serializer);
|
728 |
+
}
|
729 |
+
}
|
730 |
+
[StructLayout(LayoutKind.Explicit)]
|
731 |
+
[Quantum.AssetRefAttribute(typeof(UserMap))]
|
732 |
+
[System.SerializableAttribute()]
|
733 |
+
public unsafe partial struct AssetRefUserMap : IEquatable<AssetRefUserMap>, IAssetRef<UserMap> {
|
734 |
+
public const Int32 SIZE = 8;
|
735 |
+
public const Int32 ALIGNMENT = 8;
|
736 |
+
[FieldOffset(0)]
|
737 |
+
public AssetGuid Id;
|
738 |
+
public override String ToString() {
|
739 |
+
return AssetRef.ToString(Id);
|
740 |
+
}
|
741 |
+
public static implicit operator AssetRefUserMap(UserMap value) {
|
742 |
+
var r = default(AssetRefUserMap);
|
743 |
+
if (value != null) {
|
744 |
+
r.Id = value.Guid;
|
745 |
+
}
|
746 |
+
return r;
|
747 |
+
}
|
748 |
+
public override Boolean Equals(Object obj) {
|
749 |
+
return obj is AssetRefUserMap other && Equals(other);
|
750 |
+
}
|
751 |
+
public Boolean Equals(AssetRefUserMap other) {
|
752 |
+
return Id.Equals(other.Id);
|
753 |
+
}
|
754 |
+
public static Boolean operator ==(AssetRefUserMap a, AssetRefUserMap b) {
|
755 |
+
return a.Id == b.Id;
|
756 |
+
}
|
757 |
+
public static Boolean operator !=(AssetRefUserMap a, AssetRefUserMap b) {
|
758 |
+
return a.Id != b.Id;
|
759 |
+
}
|
760 |
+
public override Int32 GetHashCode() {
|
761 |
+
unchecked {
|
762 |
+
var hash = 83;
|
763 |
+
hash = hash * 31 + Id.GetHashCode();
|
764 |
+
return hash;
|
765 |
+
}
|
766 |
+
}
|
767 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
768 |
+
var p = (AssetRefUserMap*)ptr;
|
769 |
+
AssetGuid.Serialize(&p->Id, serializer);
|
770 |
+
}
|
771 |
+
}
|
772 |
+
[StructLayout(LayoutKind.Explicit)]
|
773 |
+
public unsafe partial struct BallPoolPlayer {
|
774 |
+
public const Int32 SIZE = 48;
|
775 |
+
public const Int32 ALIGNMENT = 8;
|
776 |
+
[FieldOffset(0)]
|
777 |
+
public PlayerRef Ref;
|
778 |
+
[FieldOffset(4)]
|
779 |
+
public QBoolean StripedBalls;
|
780 |
+
[FieldOffset(8)]
|
781 |
+
public TurnData TurnStats;
|
782 |
+
public override Int32 GetHashCode() {
|
783 |
+
unchecked {
|
784 |
+
var hash = 89;
|
785 |
+
hash = hash * 31 + Ref.GetHashCode();
|
786 |
+
hash = hash * 31 + StripedBalls.GetHashCode();
|
787 |
+
hash = hash * 31 + TurnStats.GetHashCode();
|
788 |
+
return hash;
|
789 |
+
}
|
790 |
+
}
|
791 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
792 |
+
var p = (BallPoolPlayer*)ptr;
|
793 |
+
PlayerRef.Serialize(&p->Ref, serializer);
|
794 |
+
QBoolean.Serialize(&p->StripedBalls, serializer);
|
795 |
+
Quantum.TurnData.Serialize(&p->TurnStats, serializer);
|
796 |
+
}
|
797 |
+
}
|
798 |
+
[StructLayout(LayoutKind.Explicit)]
|
799 |
+
public unsafe partial struct Input {
|
800 |
+
public const Int32 SIZE = 48;
|
801 |
+
public const Int32 ALIGNMENT = 8;
|
802 |
+
[FieldOffset(8)]
|
803 |
+
public FPVector2 BallPosition;
|
804 |
+
[FieldOffset(24)]
|
805 |
+
public FPVector3 Direction;
|
806 |
+
[FieldOffset(0)]
|
807 |
+
public FP ForceBarMarkPos;
|
808 |
+
public const int MAX_COUNT = 2;
|
809 |
+
public override Int32 GetHashCode() {
|
810 |
+
unchecked {
|
811 |
+
var hash = 97;
|
812 |
+
hash = hash * 31 + BallPosition.GetHashCode();
|
813 |
+
hash = hash * 31 + Direction.GetHashCode();
|
814 |
+
hash = hash * 31 + ForceBarMarkPos.GetHashCode();
|
815 |
+
return hash;
|
816 |
+
}
|
817 |
+
}
|
818 |
+
public static Input Read(FrameSerializer serializer) {
|
819 |
+
Input i = new Input();
|
820 |
+
Serialize(&i, serializer);
|
821 |
+
return i;
|
822 |
+
}
|
823 |
+
public static void Write(FrameSerializer serializer, Input i) {
|
824 |
+
Serialize(&i, serializer);
|
825 |
+
}
|
826 |
+
public Boolean IsDown(InputButtons button) {
|
827 |
+
switch (button) {
|
828 |
+
}
|
829 |
+
return false;
|
830 |
+
}
|
831 |
+
public Boolean WasPressed(InputButtons button) {
|
832 |
+
switch (button) {
|
833 |
+
}
|
834 |
+
return false;
|
835 |
+
}
|
836 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
837 |
+
var p = (Input*)ptr;
|
838 |
+
FP.Serialize(&p->ForceBarMarkPos, serializer);
|
839 |
+
FPVector2.Serialize(&p->BallPosition, serializer);
|
840 |
+
FPVector3.Serialize(&p->Direction, serializer);
|
841 |
+
}
|
842 |
+
}
|
843 |
+
[StructLayout(LayoutKind.Explicit)]
|
844 |
+
public unsafe partial struct TurnData {
|
845 |
+
public const Int32 SIZE = 40;
|
846 |
+
public const Int32 ALIGNMENT = 8;
|
847 |
+
[FieldOffset(24)]
|
848 |
+
public AssetRefTurnConfig ConfigRef;
|
849 |
+
[FieldOffset(32)]
|
850 |
+
public EntityRef Entity;
|
851 |
+
[FieldOffset(0)]
|
852 |
+
public Int32 Number;
|
853 |
+
[FieldOffset(8)]
|
854 |
+
public PlayerRef Player;
|
855 |
+
[FieldOffset(12)]
|
856 |
+
public TurnStatus Status;
|
857 |
+
[FieldOffset(4)]
|
858 |
+
public Int32 Ticks;
|
859 |
+
[FieldOffset(16)]
|
860 |
+
public TurnType Type;
|
861 |
+
public override Int32 GetHashCode() {
|
862 |
+
unchecked {
|
863 |
+
var hash = 101;
|
864 |
+
hash = hash * 31 + ConfigRef.GetHashCode();
|
865 |
+
hash = hash * 31 + Entity.GetHashCode();
|
866 |
+
hash = hash * 31 + Number.GetHashCode();
|
867 |
+
hash = hash * 31 + Player.GetHashCode();
|
868 |
+
hash = hash * 31 + (Int32)Status;
|
869 |
+
hash = hash * 31 + Ticks.GetHashCode();
|
870 |
+
hash = hash * 31 + (Int32)Type;
|
871 |
+
return hash;
|
872 |
+
}
|
873 |
+
}
|
874 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
875 |
+
var p = (TurnData*)ptr;
|
876 |
+
serializer.Stream.Serialize(&p->Number);
|
877 |
+
serializer.Stream.Serialize(&p->Ticks);
|
878 |
+
PlayerRef.Serialize(&p->Player, serializer);
|
879 |
+
serializer.Stream.Serialize((Int32*)&p->Status);
|
880 |
+
serializer.Stream.Serialize((Int32*)&p->Type);
|
881 |
+
Quantum.AssetRefTurnConfig.Serialize(&p->ConfigRef, serializer);
|
882 |
+
EntityRef.Serialize(&p->Entity, serializer);
|
883 |
+
}
|
884 |
+
}
|
885 |
+
[StructLayout(LayoutKind.Explicit)]
|
886 |
+
public unsafe partial struct _globals_ {
|
887 |
+
public const Int32 SIZE = 776;
|
888 |
+
public const Int32 ALIGNMENT = 8;
|
889 |
+
[FieldOffset(4)]
|
890 |
+
public QBoolean CapturedEighthBall;
|
891 |
+
[FieldOffset(120)]
|
892 |
+
public TurnData CurrentTurn;
|
893 |
+
[FieldOffset(48)]
|
894 |
+
public FP DeltaTime;
|
895 |
+
[FieldOffset(80)]
|
896 |
+
public FrameMetaData FrameMetaData;
|
897 |
+
[FieldOffset(8)]
|
898 |
+
public QBoolean HasFirstCaptured;
|
899 |
+
[FieldOffset(12)]
|
900 |
+
public QBoolean IsFirstTurn;
|
901 |
+
[FieldOffset(32)]
|
902 |
+
public AssetRefMap Map;
|
903 |
+
[FieldOffset(56)]
|
904 |
+
public NavMeshRegionMask NavMeshRegions;
|
905 |
+
[FieldOffset(480)]
|
906 |
+
public PhysicsSceneSettings PhysicsSettings;
|
907 |
+
[FieldOffset(40)]
|
908 |
+
public BitSet2 PlayerLastConnectionState;
|
909 |
+
[FieldOffset(16)]
|
910 |
+
public QBoolean PlayerScoreThisTurn;
|
911 |
+
[FieldOffset(160)]
|
912 |
+
[FramePrinter.FixedArrayAttribute(typeof(BallPoolPlayer), 2)]
|
913 |
+
private fixed Byte _Players_[96];
|
914 |
+
[FieldOffset(20)]
|
915 |
+
public QBoolean ReplaceWhiteBall;
|
916 |
+
[FieldOffset(64)]
|
917 |
+
public RNGSession RngSession;
|
918 |
+
[FieldOffset(352)]
|
919 |
+
public BitSet1024 Systems;
|
920 |
+
[FieldOffset(0)]
|
921 |
+
public Int32 TicksResolving;
|
922 |
+
[FieldOffset(24)]
|
923 |
+
public QBoolean WhiteBallFirstContact;
|
924 |
+
[FieldOffset(256)]
|
925 |
+
[FramePrinter.FixedArrayAttribute(typeof(Input), 2)]
|
926 |
+
private fixed Byte _input_[96];
|
927 |
+
public FixedArray<BallPoolPlayer> Players {
|
928 |
+
get {
|
929 |
+
fixed (byte* p = _Players_) { return new FixedArray<BallPoolPlayer>(p, 48, 2); }
|
930 |
+
}
|
931 |
+
}
|
932 |
+
public FixedArray<Input> input {
|
933 |
+
get {
|
934 |
+
fixed (byte* p = _input_) { return new FixedArray<Input>(p, 48, 2); }
|
935 |
+
}
|
936 |
+
}
|
937 |
+
public override Int32 GetHashCode() {
|
938 |
+
unchecked {
|
939 |
+
var hash = 103;
|
940 |
+
hash = hash * 31 + CapturedEighthBall.GetHashCode();
|
941 |
+
hash = hash * 31 + CurrentTurn.GetHashCode();
|
942 |
+
hash = hash * 31 + DeltaTime.GetHashCode();
|
943 |
+
hash = hash * 31 + FrameMetaData.GetHashCode();
|
944 |
+
hash = hash * 31 + HasFirstCaptured.GetHashCode();
|
945 |
+
hash = hash * 31 + IsFirstTurn.GetHashCode();
|
946 |
+
hash = hash * 31 + Map.GetHashCode();
|
947 |
+
hash = hash * 31 + NavMeshRegions.GetHashCode();
|
948 |
+
hash = hash * 31 + PhysicsSettings.GetHashCode();
|
949 |
+
hash = hash * 31 + PlayerLastConnectionState.GetHashCode();
|
950 |
+
hash = hash * 31 + PlayerScoreThisTurn.GetHashCode();
|
951 |
+
hash = hash * 31 + HashCodeUtils.GetArrayHashCode(Players);
|
952 |
+
hash = hash * 31 + ReplaceWhiteBall.GetHashCode();
|
953 |
+
hash = hash * 31 + RngSession.GetHashCode();
|
954 |
+
hash = hash * 31 + Systems.GetHashCode();
|
955 |
+
hash = hash * 31 + TicksResolving.GetHashCode();
|
956 |
+
hash = hash * 31 + WhiteBallFirstContact.GetHashCode();
|
957 |
+
hash = hash * 31 + HashCodeUtils.GetArrayHashCode(input);
|
958 |
+
return hash;
|
959 |
+
}
|
960 |
+
}
|
961 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
962 |
+
var p = (_globals_*)ptr;
|
963 |
+
serializer.Stream.Serialize(&p->TicksResolving);
|
964 |
+
QBoolean.Serialize(&p->CapturedEighthBall, serializer);
|
965 |
+
QBoolean.Serialize(&p->HasFirstCaptured, serializer);
|
966 |
+
QBoolean.Serialize(&p->IsFirstTurn, serializer);
|
967 |
+
QBoolean.Serialize(&p->PlayerScoreThisTurn, serializer);
|
968 |
+
QBoolean.Serialize(&p->ReplaceWhiteBall, serializer);
|
969 |
+
QBoolean.Serialize(&p->WhiteBallFirstContact, serializer);
|
970 |
+
AssetRefMap.Serialize(&p->Map, serializer);
|
971 |
+
Quantum.BitSet2.Serialize(&p->PlayerLastConnectionState, serializer);
|
972 |
+
FP.Serialize(&p->DeltaTime, serializer);
|
973 |
+
NavMeshRegionMask.Serialize(&p->NavMeshRegions, serializer);
|
974 |
+
RNGSession.Serialize(&p->RngSession, serializer);
|
975 |
+
FrameMetaData.Serialize(&p->FrameMetaData, serializer);
|
976 |
+
Quantum.TurnData.Serialize(&p->CurrentTurn, serializer);
|
977 |
+
FixedArray.Serialize(p->Players, serializer, StaticDelegates.SerializeBallPoolPlayer);
|
978 |
+
FixedArray.Serialize(p->input, serializer, StaticDelegates.SerializeInput);
|
979 |
+
Quantum.BitSet1024.Serialize(&p->Systems, serializer);
|
980 |
+
PhysicsSceneSettings.Serialize(&p->PhysicsSettings, serializer);
|
981 |
+
}
|
982 |
+
}
|
983 |
+
[StructLayout(LayoutKind.Explicit)]
|
984 |
+
public unsafe partial struct BallFields : Quantum.IComponent {
|
985 |
+
public const Int32 SIZE = 40;
|
986 |
+
public const Int32 ALIGNMENT = 8;
|
987 |
+
[FieldOffset(4)]
|
988 |
+
public QBoolean InTable;
|
989 |
+
[FieldOffset(0)]
|
990 |
+
public Int32 Number;
|
991 |
+
[FieldOffset(16)]
|
992 |
+
public AssetRefBallPoolSpec Spec;
|
993 |
+
[FieldOffset(24)]
|
994 |
+
public FPVector2 Spin;
|
995 |
+
[FieldOffset(8)]
|
996 |
+
public QBoolean Striped;
|
997 |
+
public override Int32 GetHashCode() {
|
998 |
+
unchecked {
|
999 |
+
var hash = 107;
|
1000 |
+
hash = hash * 31 + InTable.GetHashCode();
|
1001 |
+
hash = hash * 31 + Number.GetHashCode();
|
1002 |
+
hash = hash * 31 + Spec.GetHashCode();
|
1003 |
+
hash = hash * 31 + Spin.GetHashCode();
|
1004 |
+
hash = hash * 31 + Striped.GetHashCode();
|
1005 |
+
return hash;
|
1006 |
+
}
|
1007 |
+
}
|
1008 |
+
public static void Serialize(void* ptr, FrameSerializer serializer) {
|
1009 |
+
var p = (BallFields*)ptr;
|
1010 |
+
serializer.Stream.Serialize(&p->Number);
|
1011 |
+
QBoolean.Serialize(&p->InTable, serializer);
|
1012 |
+
QBoolean.Serialize(&p->Striped, serializer);
|
1013 |
+
Quantum.AssetRefBallPoolSpec.Serialize(&p->Spec, serializer);
|
1014 |
+
FPVector2.Serialize(&p->Spin, serializer);
|
1015 |
+
}
|
1016 |
+
}
|
1017 |
+
public unsafe partial class Frame {
|
1018 |
+
private ISignalOnBallPoolShot[] _ISignalOnBallPoolShotSystems;
|
1019 |
+
private ISignalOnBallPoolHitHole[] _ISignalOnBallPoolHitHoleSystems;
|
1020 |
+
private ISignalOnTurnEnded[] _ISignalOnTurnEndedSystems;
|
1021 |
+
private ISignalOnPlayCommandReceived[] _ISignalOnPlayCommandReceivedSystems;
|
1022 |
+
private ISignalOnSkipCommandReceived[] _ISignalOnSkipCommandReceivedSystems;
|
1023 |
+
partial void AllocGen() {
|
1024 |
+
_globals = (_globals_*)Context.Allocator.AllocAndClear(sizeof(_globals_));
|
1025 |
+
}
|
1026 |
+
partial void FreeGen() {
|
1027 |
+
Context.Allocator.Free(_globals);
|
1028 |
+
}
|
1029 |
+
partial void CopyFromGen(Frame frame) {
|
1030 |
+
Native.Utils.Copy(_globals, frame._globals, sizeof(_globals_));
|
1031 |
+
}
|
1032 |
+
static partial void InitStaticGen() {
|
1033 |
+
ComponentTypeId.Setup(() => {
|
1034 |
+
ComponentTypeId.Add<Quantum.BallFields>(Quantum.BallFields.Serialize, null, null, ComponentFlags.None);
|
1035 |
+
});
|
1036 |
+
}
|
1037 |
+
partial void InitGen() {
|
1038 |
+
Initialize(this, this.SimulationConfig.Entities);
|
1039 |
+
_ISignalOnBallPoolShotSystems = BuildSignalsArray<ISignalOnBallPoolShot>();
|
1040 |
+
_ISignalOnBallPoolHitHoleSystems = BuildSignalsArray<ISignalOnBallPoolHitHole>();
|
1041 |
+
_ISignalOnTurnEndedSystems = BuildSignalsArray<ISignalOnTurnEnded>();
|
1042 |
+
_ISignalOnPlayCommandReceivedSystems = BuildSignalsArray<ISignalOnPlayCommandReceived>();
|
1043 |
+
_ISignalOnSkipCommandReceivedSystems = BuildSignalsArray<ISignalOnSkipCommandReceived>();
|
1044 |
+
_ComponentSignalsOnAdded = new ComponentReactiveCallbackInvoker[ComponentTypeId.Type.Length];
|
1045 |
+
_ComponentSignalsOnRemoved = new ComponentReactiveCallbackInvoker[ComponentTypeId.Type.Length];
|
1046 |
+
BuildSignalsArrayOnComponentAdded<Quantum.BallFields>();
|
1047 |
+
BuildSignalsArrayOnComponentRemoved<Quantum.BallFields>();
|
1048 |
+
BuildSignalsArrayOnComponentAdded<CharacterController2D>();
|
1049 |
+
BuildSignalsArrayOnComponentRemoved<CharacterController2D>();
|
1050 |
+
BuildSignalsArrayOnComponentAdded<CharacterController3D>();
|
1051 |
+
BuildSignalsArrayOnComponentRemoved<CharacterController3D>();
|
1052 |
+
BuildSignalsArrayOnComponentAdded<MapEntityLink>();
|
1053 |
+
BuildSignalsArrayOnComponentRemoved<MapEntityLink>();
|
1054 |
+
BuildSignalsArrayOnComponentAdded<NavMeshAvoidanceAgent>();
|
1055 |
+
BuildSignalsArrayOnComponentRemoved<NavMeshAvoidanceAgent>();
|
1056 |
+
BuildSignalsArrayOnComponentAdded<NavMeshAvoidanceObstacle>();
|
1057 |
+
BuildSignalsArrayOnComponentRemoved<NavMeshAvoidanceObstacle>();
|
1058 |
+
BuildSignalsArrayOnComponentAdded<NavMeshPathfinder>();
|
1059 |
+
BuildSignalsArrayOnComponentRemoved<NavMeshPathfinder>();
|
1060 |
+
BuildSignalsArrayOnComponentAdded<NavMeshSteeringAgent>();
|
1061 |
+
BuildSignalsArrayOnComponentRemoved<NavMeshSteeringAgent>();
|
1062 |
+
BuildSignalsArrayOnComponentAdded<PhysicsBody2D>();
|
1063 |
+
BuildSignalsArrayOnComponentRemoved<PhysicsBody2D>();
|
1064 |
+
BuildSignalsArrayOnComponentAdded<PhysicsBody3D>();
|
1065 |
+
BuildSignalsArrayOnComponentRemoved<PhysicsBody3D>();
|
1066 |
+
BuildSignalsArrayOnComponentAdded<PhysicsCollider2D>();
|
1067 |
+
BuildSignalsArrayOnComponentRemoved<PhysicsCollider2D>();
|
1068 |
+
BuildSignalsArrayOnComponentAdded<PhysicsCollider3D>();
|
1069 |
+
BuildSignalsArrayOnComponentRemoved<PhysicsCollider3D>();
|
1070 |
+
BuildSignalsArrayOnComponentAdded<Transform2D>();
|
1071 |
+
BuildSignalsArrayOnComponentRemoved<Transform2D>();
|
1072 |
+
BuildSignalsArrayOnComponentAdded<Transform2DVertical>();
|
1073 |
+
BuildSignalsArrayOnComponentRemoved<Transform2DVertical>();
|
1074 |
+
BuildSignalsArrayOnComponentAdded<Transform3D>();
|
1075 |
+
BuildSignalsArrayOnComponentRemoved<Transform3D>();
|
1076 |
+
BuildSignalsArrayOnComponentAdded<View>();
|
1077 |
+
BuildSignalsArrayOnComponentRemoved<View>();
|
1078 |
+
}
|
1079 |
+
public void SetPlayerInput(Int32 player, Input input) {
|
1080 |
+
if ((uint)player >= (uint)_globals->input.Length) { throw new System.ArgumentOutOfRangeException("player"); }
|
1081 |
+
var i = _globals->input.GetPointer(player);
|
1082 |
+
i->Direction = input.Direction;
|
1083 |
+
i->ForceBarMarkPos = input.ForceBarMarkPos;
|
1084 |
+
i->BallPosition = input.BallPosition;
|
1085 |
+
}
|
1086 |
+
public Input* GetPlayerInput(Int32 player) {
|
1087 |
+
if ((uint)player >= (uint)_globals->input.Length) { throw new System.ArgumentOutOfRangeException("player"); }
|
1088 |
+
return _globals->input.GetPointer(player);
|
1089 |
+
}
|
1090 |
+
public unsafe partial struct FrameSignals {
|
1091 |
+
public void OnBallPoolShot(PlayerRef player) {
|
1092 |
+
var array = _f._ISignalOnBallPoolShotSystems;
|
1093 |
+
for (Int32 i = 0; i < array.Length; ++i) {
|
1094 |
+
var s = array[i];
|
1095 |
+
if (_f.SystemIsEnabledInHierarchy((SystemBase)s)) {
|
1096 |
+
s.OnBallPoolShot(_f, player);
|
1097 |
+
}
|
1098 |
+
}
|
1099 |
+
}
|
1100 |
+
public void OnBallPoolHitHole(EntityRef ball) {
|
1101 |
+
var array = _f._ISignalOnBallPoolHitHoleSystems;
|
1102 |
+
for (Int32 i = 0; i < array.Length; ++i) {
|
1103 |
+
var s = array[i];
|
1104 |
+
if (_f.SystemIsEnabledInHierarchy((SystemBase)s)) {
|
1105 |
+
s.OnBallPoolHitHole(_f, ball);
|
1106 |
+
}
|
1107 |
+
}
|
1108 |
+
}
|
1109 |
+
public void OnTurnEnded(TurnData data, TurnEndReason reason) {
|
1110 |
+
var array = _f._ISignalOnTurnEndedSystems;
|
1111 |
+
for (Int32 i = 0; i < array.Length; ++i) {
|
1112 |
+
var s = array[i];
|
1113 |
+
if (_f.SystemIsEnabledInHierarchy((SystemBase)s)) {
|
1114 |
+
s.OnTurnEnded(_f, data, reason);
|
1115 |
+
}
|
1116 |
+
}
|
1117 |
+
}
|
1118 |
+
public void OnPlayCommandReceived(PlayerRef player, PlayCommandData data) {
|
1119 |
+
var array = _f._ISignalOnPlayCommandReceivedSystems;
|
1120 |
+
for (Int32 i = 0; i < array.Length; ++i) {
|
1121 |
+
var s = array[i];
|
1122 |
+
if (_f.SystemIsEnabledInHierarchy((SystemBase)s)) {
|
1123 |
+
s.OnPlayCommandReceived(_f, player, data);
|
1124 |
+
}
|
1125 |
+
}
|
1126 |
+
}
|
1127 |
+
public void OnSkipCommandReceived(PlayerRef player, SkipCommandData data) {
|
1128 |
+
var array = _f._ISignalOnSkipCommandReceivedSystems;
|
1129 |
+
for (Int32 i = 0; i < array.Length; ++i) {
|
1130 |
+
var s = array[i];
|
1131 |
+
if (_f.SystemIsEnabledInHierarchy((SystemBase)s)) {
|
1132 |
+
s.OnSkipCommandReceived(_f, player, data);
|
1133 |
+
}
|
1134 |
+
}
|
1135 |
+
}
|
1136 |
+
}
|
1137 |
+
public unsafe partial struct FrameEvents {
|
1138 |
+
public const Int32 EVENT_TYPE_COUNT = 18;
|
1139 |
+
public static Int32 GetParentEventID(Int32 eventID) {
|
1140 |
+
switch (eventID) {
|
1141 |
+
case EventTurnTypeChanged.ID: return EventTurnEvent.ID;
|
1142 |
+
case EventTurnStatusChanged.ID: return EventTurnEvent.ID;
|
1143 |
+
case EventTurnEnded.ID: return EventTurnEvent.ID;
|
1144 |
+
case EventTurnTimerReset.ID: return EventTurnEvent.ID;
|
1145 |
+
case EventTurnActivated.ID: return EventTurnEvent.ID;
|
1146 |
+
case EventPlayCommandReceived.ID: return EventCommandEvent.ID;
|
1147 |
+
case EventSkipCommandReceived.ID: return EventCommandEvent.ID;
|
1148 |
+
default: return -1;
|
1149 |
+
}
|
1150 |
+
}
|
1151 |
+
public static System.Type GetEventType(Int32 eventID) {
|
1152 |
+
switch (eventID) {
|
1153 |
+
case EventMessage.ID: return typeof(EventMessage);
|
1154 |
+
case EventRemoveBall.ID: return typeof(EventRemoveBall);
|
1155 |
+
case EventEndGame.ID: return typeof(EventEndGame);
|
1156 |
+
case EventReplaceBall.ID: return typeof(EventReplaceBall);
|
1157 |
+
case EventCueHitBall.ID: return typeof(EventCueHitBall);
|
1158 |
+
case EventBallsCollision.ID: return typeof(EventBallsCollision);
|
1159 |
+
case EventBallsHitWall.ID: return typeof(EventBallsHitWall);
|
1160 |
+
case EventBallsHitHole.ID: return typeof(EventBallsHitHole);
|
1161 |
+
case EventGameplayEnded.ID: return typeof(EventGameplayEnded);
|
1162 |
+
case EventTurnEvent.ID: return typeof(EventTurnEvent);
|
1163 |
+
case EventTurnTypeChanged.ID: return typeof(EventTurnTypeChanged);
|
1164 |
+
case EventTurnStatusChanged.ID: return typeof(EventTurnStatusChanged);
|
1165 |
+
case EventTurnEnded.ID: return typeof(EventTurnEnded);
|
1166 |
+
case EventTurnTimerReset.ID: return typeof(EventTurnTimerReset);
|
1167 |
+
case EventTurnActivated.ID: return typeof(EventTurnActivated);
|
1168 |
+
case EventCommandEvent.ID: return typeof(EventCommandEvent);
|
1169 |
+
case EventPlayCommandReceived.ID: return typeof(EventPlayCommandReceived);
|
1170 |
+
case EventSkipCommandReceived.ID: return typeof(EventSkipCommandReceived);
|
1171 |
+
default: throw new System.ArgumentOutOfRangeException("eventID");
|
1172 |
+
}
|
1173 |
+
}
|
1174 |
+
public EventMessage Message(String Header, String Text) {
|
1175 |
+
var ev = _f.Context.AcquireEvent<EventMessage>(EventMessage.ID);
|
1176 |
+
ev.Header = Header;
|
1177 |
+
ev.Text = Text;
|
1178 |
+
_f.AddEvent(ev);
|
1179 |
+
return ev;
|
1180 |
+
}
|
1181 |
+
public EventRemoveBall RemoveBall(Int32 Num) {
|
1182 |
+
var ev = _f.Context.AcquireEvent<EventRemoveBall>(EventRemoveBall.ID);
|
1183 |
+
ev.Num = Num;
|
1184 |
+
_f.AddEvent(ev);
|
1185 |
+
return ev;
|
1186 |
+
}
|
1187 |
+
public EventEndGame EndGame(PlayerRef Winner) {
|
1188 |
+
var ev = _f.Context.AcquireEvent<EventEndGame>(EventEndGame.ID);
|
1189 |
+
ev.Winner = Winner;
|
1190 |
+
_f.AddEvent(ev);
|
1191 |
+
return ev;
|
1192 |
+
}
|
1193 |
+
public EventReplaceBall ReplaceBall() {
|
1194 |
+
var ev = _f.Context.AcquireEvent<EventReplaceBall>(EventReplaceBall.ID);
|
1195 |
+
_f.AddEvent(ev);
|
1196 |
+
return ev;
|
1197 |
+
}
|
1198 |
+
public EventCueHitBall CueHitBall() {
|
1199 |
+
var ev = _f.Context.AcquireEvent<EventCueHitBall>(EventCueHitBall.ID);
|
1200 |
+
_f.AddEvent(ev);
|
1201 |
+
return ev;
|
1202 |
+
}
|
1203 |
+
public EventBallsCollision BallsCollision() {
|
1204 |
+
var ev = _f.Context.AcquireEvent<EventBallsCollision>(EventBallsCollision.ID);
|
1205 |
+
_f.AddEvent(ev);
|
1206 |
+
return ev;
|
1207 |
+
}
|
1208 |
+
public EventBallsHitWall BallsHitWall() {
|
1209 |
+
var ev = _f.Context.AcquireEvent<EventBallsHitWall>(EventBallsHitWall.ID);
|
1210 |
+
_f.AddEvent(ev);
|
1211 |
+
return ev;
|
1212 |
+
}
|
1213 |
+
public EventBallsHitHole BallsHitHole() {
|
1214 |
+
var ev = _f.Context.AcquireEvent<EventBallsHitHole>(EventBallsHitHole.ID);
|
1215 |
+
_f.AddEvent(ev);
|
1216 |
+
return ev;
|
1217 |
+
}
|
1218 |
+
public EventGameplayEnded GameplayEnded() {
|
1219 |
+
if (_f.IsPredicted) return null;
|
1220 |
+
var ev = _f.Context.AcquireEvent<EventGameplayEnded>(EventGameplayEnded.ID);
|
1221 |
+
_f.AddEvent(ev);
|
1222 |
+
return ev;
|
1223 |
+
}
|
1224 |
+
public EventTurnTypeChanged TurnTypeChanged(TurnData Turn, TurnType PreviousType) {
|
1225 |
+
if (_f.IsPredicted) return null;
|
1226 |
+
var ev = _f.Context.AcquireEvent<EventTurnTypeChanged>(EventTurnTypeChanged.ID);
|
1227 |
+
ev.Turn = Turn;
|
1228 |
+
ev.PreviousType = PreviousType;
|
1229 |
+
_f.AddEvent(ev);
|
1230 |
+
return ev;
|
1231 |
+
}
|
1232 |
+
public EventTurnStatusChanged TurnStatusChanged(TurnData Turn, TurnStatus PreviousStatus) {
|
1233 |
+
if (_f.IsPredicted) return null;
|
1234 |
+
var ev = _f.Context.AcquireEvent<EventTurnStatusChanged>(EventTurnStatusChanged.ID);
|
1235 |
+
ev.Turn = Turn;
|
1236 |
+
ev.PreviousStatus = PreviousStatus;
|
1237 |
+
_f.AddEvent(ev);
|
1238 |
+
return ev;
|
1239 |
+
}
|
1240 |
+
public EventTurnEnded TurnEnded(TurnData Turn, TurnEndReason Reason) {
|
1241 |
+
if (_f.IsPredicted) return null;
|
1242 |
+
var ev = _f.Context.AcquireEvent<EventTurnEnded>(EventTurnEnded.ID);
|
1243 |
+
ev.Turn = Turn;
|
1244 |
+
ev.Reason = Reason;
|
1245 |
+
_f.AddEvent(ev);
|
1246 |
+
return ev;
|
1247 |
+
}
|
1248 |
+
public EventTurnTimerReset TurnTimerReset(TurnData Turn) {
|
1249 |
+
if (_f.IsPredicted) return null;
|
1250 |
+
var ev = _f.Context.AcquireEvent<EventTurnTimerReset>(EventTurnTimerReset.ID);
|
1251 |
+
ev.Turn = Turn;
|
1252 |
+
_f.AddEvent(ev);
|
1253 |
+
return ev;
|
1254 |
+
}
|
1255 |
+
public EventTurnActivated TurnActivated(TurnData Turn) {
|
1256 |
+
if (_f.IsPredicted) return null;
|
1257 |
+
var ev = _f.Context.AcquireEvent<EventTurnActivated>(EventTurnActivated.ID);
|
1258 |
+
ev.Turn = Turn;
|
1259 |
+
_f.AddEvent(ev);
|
1260 |
+
return ev;
|
1261 |
+
}
|
1262 |
+
public EventPlayCommandReceived PlayCommandReceived(PlayerRef Player, PlayCommandData Data) {
|
1263 |
+
var ev = _f.Context.AcquireEvent<EventPlayCommandReceived>(EventPlayCommandReceived.ID);
|
1264 |
+
ev.Player = Player;
|
1265 |
+
ev.Data = Data;
|
1266 |
+
_f.AddEvent(ev);
|
1267 |
+
return ev;
|
1268 |
+
}
|
1269 |
+
public EventSkipCommandReceived SkipCommandReceived(PlayerRef Player, SkipCommandData Data) {
|
1270 |
+
var ev = _f.Context.AcquireEvent<EventSkipCommandReceived>(EventSkipCommandReceived.ID);
|
1271 |
+
ev.Player = Player;
|
1272 |
+
ev.Data = Data;
|
1273 |
+
_f.AddEvent(ev);
|
1274 |
+
return ev;
|
1275 |
+
}
|
1276 |
+
}
|
1277 |
+
public unsafe partial struct FrameAssets {
|
1278 |
+
public BallPoolSpec BallPoolSpec(AssetRefBallPoolSpec assetRef) {
|
1279 |
+
return _f.FindAsset<BallPoolSpec>(assetRef.Id);
|
1280 |
+
}
|
1281 |
+
public ConfigAssets ConfigAssets(AssetRefConfigAssets assetRef) {
|
1282 |
+
return _f.FindAsset<ConfigAssets>(assetRef.Id);
|
1283 |
+
}
|
1284 |
+
public GameConfig GameConfig(AssetRefGameConfig assetRef) {
|
1285 |
+
return _f.FindAsset<GameConfig>(assetRef.Id);
|
1286 |
+
}
|
1287 |
+
public UserMap UserMap(AssetRefUserMap assetRef) {
|
1288 |
+
return _f.FindAsset<UserMap>(assetRef.Id);
|
1289 |
+
}
|
1290 |
+
public TurnConfig TurnConfig(AssetRefTurnConfig assetRef) {
|
1291 |
+
return _f.FindAsset<TurnConfig>(assetRef.Id);
|
1292 |
+
}
|
1293 |
+
}
|
1294 |
+
}
|
1295 |
+
public unsafe interface ISignalOnBallPoolShot : ISignal {
|
1296 |
+
void OnBallPoolShot(Frame f, PlayerRef player);
|
1297 |
+
}
|
1298 |
+
public unsafe interface ISignalOnBallPoolHitHole : ISignal {
|
1299 |
+
void OnBallPoolHitHole(Frame f, EntityRef ball);
|
1300 |
+
}
|
1301 |
+
public unsafe interface ISignalOnTurnEnded : ISignal {
|
1302 |
+
void OnTurnEnded(Frame f, TurnData data, TurnEndReason reason);
|
1303 |
+
}
|
1304 |
+
public unsafe interface ISignalOnPlayCommandReceived : ISignal {
|
1305 |
+
void OnPlayCommandReceived(Frame f, PlayerRef player, PlayCommandData data);
|
1306 |
+
}
|
1307 |
+
public unsafe interface ISignalOnSkipCommandReceived : ISignal {
|
1308 |
+
void OnSkipCommandReceived(Frame f, PlayerRef player, SkipCommandData data);
|
1309 |
+
}
|
1310 |
+
public unsafe partial class EventMessage : EventBase {
|
1311 |
+
public new const Int32 ID = 0;
|
1312 |
+
public String Header;
|
1313 |
+
public String Text;
|
1314 |
+
protected EventMessage(Int32 id, EventFlags flags) :
|
1315 |
+
base(id, flags) {
|
1316 |
+
}
|
1317 |
+
public EventMessage() :
|
1318 |
+
base(0, EventFlags.Server|EventFlags.Client) {
|
1319 |
+
}
|
1320 |
+
public new QuantumGame Game {
|
1321 |
+
get {
|
1322 |
+
return (QuantumGame)base.Game;
|
1323 |
+
}
|
1324 |
+
set {
|
1325 |
+
base.Game = value;
|
1326 |
+
}
|
1327 |
+
}
|
1328 |
+
public override Int32 GetHashCode() {
|
1329 |
+
unchecked {
|
1330 |
+
var hash = 37;
|
1331 |
+
hash = hash * 31 + Header.GetHashCode();
|
1332 |
+
hash = hash * 31 + Text.GetHashCode();
|
1333 |
+
return hash;
|
1334 |
+
}
|
1335 |
+
}
|
1336 |
+
}
|
1337 |
+
public unsafe partial class EventRemoveBall : EventBase {
|
1338 |
+
public new const Int32 ID = 1;
|
1339 |
+
public Int32 Num;
|
1340 |
+
protected EventRemoveBall(Int32 id, EventFlags flags) :
|
1341 |
+
base(id, flags) {
|
1342 |
+
}
|
1343 |
+
public EventRemoveBall() :
|
1344 |
+
base(1, EventFlags.Server|EventFlags.Client) {
|
1345 |
+
}
|
1346 |
+
public new QuantumGame Game {
|
1347 |
+
get {
|
1348 |
+
return (QuantumGame)base.Game;
|
1349 |
+
}
|
1350 |
+
set {
|
1351 |
+
base.Game = value;
|
1352 |
+
}
|
1353 |
+
}
|
1354 |
+
public override Int32 GetHashCode() {
|
1355 |
+
unchecked {
|
1356 |
+
var hash = 41;
|
1357 |
+
hash = hash * 31 + Num.GetHashCode();
|
1358 |
+
return hash;
|
1359 |
+
}
|
1360 |
+
}
|
1361 |
+
}
|
1362 |
+
public unsafe partial class EventEndGame : EventBase {
|
1363 |
+
public new const Int32 ID = 2;
|
1364 |
+
public PlayerRef Winner;
|
1365 |
+
protected EventEndGame(Int32 id, EventFlags flags) :
|
1366 |
+
base(id, flags) {
|
1367 |
+
}
|
1368 |
+
public EventEndGame() :
|
1369 |
+
base(2, EventFlags.Server|EventFlags.Client) {
|
1370 |
+
}
|
1371 |
+
public new QuantumGame Game {
|
1372 |
+
get {
|
1373 |
+
return (QuantumGame)base.Game;
|
1374 |
+
}
|
1375 |
+
set {
|
1376 |
+
base.Game = value;
|
1377 |
+
}
|
1378 |
+
}
|
1379 |
+
public override Int32 GetHashCode() {
|
1380 |
+
unchecked {
|
1381 |
+
var hash = 43;
|
1382 |
+
hash = hash * 31 + Winner.GetHashCode();
|
1383 |
+
return hash;
|
1384 |
+
}
|
1385 |
+
}
|
1386 |
+
}
|
1387 |
+
public unsafe partial class EventReplaceBall : EventBase {
|
1388 |
+
public new const Int32 ID = 3;
|
1389 |
+
protected EventReplaceBall(Int32 id, EventFlags flags) :
|
1390 |
+
base(id, flags) {
|
1391 |
+
}
|
1392 |
+
public EventReplaceBall() :
|
1393 |
+
base(3, EventFlags.Server|EventFlags.Client) {
|
1394 |
+
}
|
1395 |
+
public new QuantumGame Game {
|
1396 |
+
get {
|
1397 |
+
return (QuantumGame)base.Game;
|
1398 |
+
}
|
1399 |
+
set {
|
1400 |
+
base.Game = value;
|
1401 |
+
}
|
1402 |
+
}
|
1403 |
+
public override Int32 GetHashCode() {
|
1404 |
+
unchecked {
|
1405 |
+
var hash = 47;
|
1406 |
+
return hash;
|
1407 |
+
}
|
1408 |
+
}
|
1409 |
+
}
|
1410 |
+
public unsafe partial class EventCueHitBall : EventBase {
|
1411 |
+
public new const Int32 ID = 4;
|
1412 |
+
protected EventCueHitBall(Int32 id, EventFlags flags) :
|
1413 |
+
base(id, flags) {
|
1414 |
+
}
|
1415 |
+
public EventCueHitBall() :
|
1416 |
+
base(4, EventFlags.Server|EventFlags.Client) {
|
1417 |
+
}
|
1418 |
+
public new QuantumGame Game {
|
1419 |
+
get {
|
1420 |
+
return (QuantumGame)base.Game;
|
1421 |
+
}
|
1422 |
+
set {
|
1423 |
+
base.Game = value;
|
1424 |
+
}
|
1425 |
+
}
|
1426 |
+
public override Int32 GetHashCode() {
|
1427 |
+
unchecked {
|
1428 |
+
var hash = 53;
|
1429 |
+
return hash;
|
1430 |
+
}
|
1431 |
+
}
|
1432 |
+
}
|
1433 |
+
public unsafe partial class EventBallsCollision : EventBase {
|
1434 |
+
public new const Int32 ID = 5;
|
1435 |
+
protected EventBallsCollision(Int32 id, EventFlags flags) :
|
1436 |
+
base(id, flags) {
|
1437 |
+
}
|
1438 |
+
public EventBallsCollision() :
|
1439 |
+
base(5, EventFlags.Server|EventFlags.Client) {
|
1440 |
+
}
|
1441 |
+
public new QuantumGame Game {
|
1442 |
+
get {
|
1443 |
+
return (QuantumGame)base.Game;
|
1444 |
+
}
|
1445 |
+
set {
|
1446 |
+
base.Game = value;
|
1447 |
+
}
|
1448 |
+
}
|
1449 |
+
public override Int32 GetHashCode() {
|
1450 |
+
unchecked {
|
1451 |
+
var hash = 59;
|
1452 |
+
return hash;
|
1453 |
+
}
|
1454 |
+
}
|
1455 |
+
}
|
1456 |
+
public unsafe partial class EventBallsHitWall : EventBase {
|
1457 |
+
public new const Int32 ID = 6;
|
1458 |
+
protected EventBallsHitWall(Int32 id, EventFlags flags) :
|
1459 |
+
base(id, flags) {
|
1460 |
+
}
|
1461 |
+
public EventBallsHitWall() :
|
1462 |
+
base(6, EventFlags.Server|EventFlags.Client) {
|
1463 |
+
}
|
1464 |
+
public new QuantumGame Game {
|
1465 |
+
get {
|
1466 |
+
return (QuantumGame)base.Game;
|
1467 |
+
}
|
1468 |
+
set {
|
1469 |
+
base.Game = value;
|
1470 |
+
}
|
1471 |
+
}
|
1472 |
+
public override Int32 GetHashCode() {
|
1473 |
+
unchecked {
|
1474 |
+
var hash = 61;
|
1475 |
+
return hash;
|
1476 |
+
}
|
1477 |
+
}
|
1478 |
+
}
|
1479 |
+
public unsafe partial class EventBallsHitHole : EventBase {
|
1480 |
+
public new const Int32 ID = 7;
|
1481 |
+
protected EventBallsHitHole(Int32 id, EventFlags flags) :
|
1482 |
+
base(id, flags) {
|
1483 |
+
}
|
1484 |
+
public EventBallsHitHole() :
|
1485 |
+
base(7, EventFlags.Server|EventFlags.Client) {
|
1486 |
+
}
|
1487 |
+
public new QuantumGame Game {
|
1488 |
+
get {
|
1489 |
+
return (QuantumGame)base.Game;
|
1490 |
+
}
|
1491 |
+
set {
|
1492 |
+
base.Game = value;
|
1493 |
+
}
|
1494 |
+
}
|
1495 |
+
public override Int32 GetHashCode() {
|
1496 |
+
unchecked {
|
1497 |
+
var hash = 67;
|
1498 |
+
return hash;
|
1499 |
+
}
|
1500 |
+
}
|
1501 |
+
}
|
1502 |
+
public unsafe partial class EventGameplayEnded : EventBase {
|
1503 |
+
public new const Int32 ID = 8;
|
1504 |
+
protected EventGameplayEnded(Int32 id, EventFlags flags) :
|
1505 |
+
base(id, flags) {
|
1506 |
+
}
|
1507 |
+
public EventGameplayEnded() :
|
1508 |
+
base(8, EventFlags.Server|EventFlags.Client|EventFlags.Synced) {
|
1509 |
+
}
|
1510 |
+
public new QuantumGame Game {
|
1511 |
+
get {
|
1512 |
+
return (QuantumGame)base.Game;
|
1513 |
+
}
|
1514 |
+
set {
|
1515 |
+
base.Game = value;
|
1516 |
+
}
|
1517 |
+
}
|
1518 |
+
public override Int32 GetHashCode() {
|
1519 |
+
unchecked {
|
1520 |
+
var hash = 71;
|
1521 |
+
return hash;
|
1522 |
+
}
|
1523 |
+
}
|
1524 |
+
}
|
1525 |
+
public abstract unsafe partial class EventTurnEvent : EventBase {
|
1526 |
+
public new const Int32 ID = 9;
|
1527 |
+
public TurnData Turn;
|
1528 |
+
protected EventTurnEvent(Int32 id, EventFlags flags) :
|
1529 |
+
base(id, flags) {
|
1530 |
+
}
|
1531 |
+
public new QuantumGame Game {
|
1532 |
+
get {
|
1533 |
+
return (QuantumGame)base.Game;
|
1534 |
+
}
|
1535 |
+
set {
|
1536 |
+
base.Game = value;
|
1537 |
+
}
|
1538 |
+
}
|
1539 |
+
public override Int32 GetHashCode() {
|
1540 |
+
unchecked {
|
1541 |
+
var hash = 73;
|
1542 |
+
hash = hash * 31 + Turn.GetHashCode();
|
1543 |
+
return hash;
|
1544 |
+
}
|
1545 |
+
}
|
1546 |
+
}
|
1547 |
+
public unsafe partial class EventTurnTypeChanged : EventTurnEvent {
|
1548 |
+
public new const Int32 ID = 10;
|
1549 |
+
public TurnType PreviousType;
|
1550 |
+
protected EventTurnTypeChanged(Int32 id, EventFlags flags) :
|
1551 |
+
base(id, flags) {
|
1552 |
+
}
|
1553 |
+
public EventTurnTypeChanged() :
|
1554 |
+
base(10, EventFlags.Server|EventFlags.Client|EventFlags.Synced) {
|
1555 |
+
}
|
1556 |
+
public override Int32 GetHashCode() {
|
1557 |
+
unchecked {
|
1558 |
+
var hash = 79;
|
1559 |
+
hash = hash * 31 + Turn.GetHashCode();
|
1560 |
+
hash = hash * 31 + PreviousType.GetHashCode();
|
1561 |
+
return hash;
|
1562 |
+
}
|
1563 |
+
}
|
1564 |
+
}
|
1565 |
+
public unsafe partial class EventTurnStatusChanged : EventTurnEvent {
|
1566 |
+
public new const Int32 ID = 11;
|
1567 |
+
public TurnStatus PreviousStatus;
|
1568 |
+
protected EventTurnStatusChanged(Int32 id, EventFlags flags) :
|
1569 |
+
base(id, flags) {
|
1570 |
+
}
|
1571 |
+
public EventTurnStatusChanged() :
|
1572 |
+
base(11, EventFlags.Server|EventFlags.Client|EventFlags.Synced) {
|
1573 |
+
}
|
1574 |
+
public override Int32 GetHashCode() {
|
1575 |
+
unchecked {
|
1576 |
+
var hash = 83;
|
1577 |
+
hash = hash * 31 + Turn.GetHashCode();
|
1578 |
+
hash = hash * 31 + PreviousStatus.GetHashCode();
|
1579 |
+
return hash;
|
1580 |
+
}
|
1581 |
+
}
|
1582 |
+
}
|
1583 |
+
public unsafe partial class EventTurnEnded : EventTurnEvent {
|
1584 |
+
public new const Int32 ID = 12;
|
1585 |
+
public TurnEndReason Reason;
|
1586 |
+
protected EventTurnEnded(Int32 id, EventFlags flags) :
|
1587 |
+
base(id, flags) {
|
1588 |
+
}
|
1589 |
+
public EventTurnEnded() :
|
1590 |
+
base(12, EventFlags.Server|EventFlags.Client|EventFlags.Synced) {
|
1591 |
+
}
|
1592 |
+
public override Int32 GetHashCode() {
|
1593 |
+
unchecked {
|
1594 |
+
var hash = 89;
|
1595 |
+
hash = hash * 31 + Turn.GetHashCode();
|
1596 |
+
hash = hash * 31 + Reason.GetHashCode();
|
1597 |
+
return hash;
|
1598 |
+
}
|
1599 |
+
}
|
1600 |
+
}
|
1601 |
+
public unsafe partial class EventTurnTimerReset : EventTurnEvent {
|
1602 |
+
public new const Int32 ID = 13;
|
1603 |
+
protected EventTurnTimerReset(Int32 id, EventFlags flags) :
|
1604 |
+
base(id, flags) {
|
1605 |
+
}
|
1606 |
+
public EventTurnTimerReset() :
|
1607 |
+
base(13, EventFlags.Server|EventFlags.Client|EventFlags.Synced) {
|
1608 |
+
}
|
1609 |
+
public override Int32 GetHashCode() {
|
1610 |
+
unchecked {
|
1611 |
+
var hash = 97;
|
1612 |
+
hash = hash * 31 + Turn.GetHashCode();
|
1613 |
+
return hash;
|
1614 |
+
}
|
1615 |
+
}
|
1616 |
+
}
|
1617 |
+
public unsafe partial class EventTurnActivated : EventTurnEvent {
|
1618 |
+
public new const Int32 ID = 14;
|
1619 |
+
protected EventTurnActivated(Int32 id, EventFlags flags) :
|
1620 |
+
base(id, flags) {
|
1621 |
+
}
|
1622 |
+
public EventTurnActivated() :
|
1623 |
+
base(14, EventFlags.Server|EventFlags.Client|EventFlags.Synced) {
|
1624 |
+
}
|
1625 |
+
public override Int32 GetHashCode() {
|
1626 |
+
unchecked {
|
1627 |
+
var hash = 101;
|
1628 |
+
hash = hash * 31 + Turn.GetHashCode();
|
1629 |
+
return hash;
|
1630 |
+
}
|
1631 |
+
}
|
1632 |
+
}
|
1633 |
+
public abstract unsafe partial class EventCommandEvent : EventBase {
|
1634 |
+
public new const Int32 ID = 15;
|
1635 |
+
public PlayerRef Player;
|
1636 |
+
protected EventCommandEvent(Int32 id, EventFlags flags) :
|
1637 |
+
base(id, flags) {
|
1638 |
+
}
|
1639 |
+
public new QuantumGame Game {
|
1640 |
+
get {
|
1641 |
+
return (QuantumGame)base.Game;
|
1642 |
+
}
|
1643 |
+
set {
|
1644 |
+
base.Game = value;
|
1645 |
+
}
|
1646 |
+
}
|
1647 |
+
public override Int32 GetHashCode() {
|
1648 |
+
unchecked {
|
1649 |
+
var hash = 103;
|
1650 |
+
hash = hash * 31 + Player.GetHashCode();
|
1651 |
+
return hash;
|
1652 |
+
}
|
1653 |
+
}
|
1654 |
+
}
|
1655 |
+
public unsafe partial class EventPlayCommandReceived : EventCommandEvent {
|
1656 |
+
public new const Int32 ID = 16;
|
1657 |
+
public PlayCommandData Data;
|
1658 |
+
protected EventPlayCommandReceived(Int32 id, EventFlags flags) :
|
1659 |
+
base(id, flags) {
|
1660 |
+
}
|
1661 |
+
public EventPlayCommandReceived() :
|
1662 |
+
base(16, EventFlags.Server|EventFlags.Client) {
|
1663 |
+
}
|
1664 |
+
public override Int32 GetHashCode() {
|
1665 |
+
unchecked {
|
1666 |
+
var hash = 107;
|
1667 |
+
hash = hash * 31 + Player.GetHashCode();
|
1668 |
+
hash = hash * 31 + Data.GetHashCode();
|
1669 |
+
return hash;
|
1670 |
+
}
|
1671 |
+
}
|
1672 |
+
}
|
1673 |
+
public unsafe partial class EventSkipCommandReceived : EventCommandEvent {
|
1674 |
+
public new const Int32 ID = 17;
|
1675 |
+
public SkipCommandData Data;
|
1676 |
+
protected EventSkipCommandReceived(Int32 id, EventFlags flags) :
|
1677 |
+
base(id, flags) {
|
1678 |
+
}
|
1679 |
+
public EventSkipCommandReceived() :
|
1680 |
+
base(17, EventFlags.Server|EventFlags.Client) {
|
1681 |
+
}
|
1682 |
+
public override Int32 GetHashCode() {
|
1683 |
+
unchecked {
|
1684 |
+
var hash = 109;
|
1685 |
+
hash = hash * 31 + Player.GetHashCode();
|
1686 |
+
hash = hash * 31 + Data.GetHashCode();
|
1687 |
+
return hash;
|
1688 |
+
}
|
1689 |
+
}
|
1690 |
+
}
|
1691 |
+
public static unsafe partial class BitStreamExtensions {
|
1692 |
+
public static void Serialize(this IBitStream stream, ref AssetRefBallPoolSpec value) {
|
1693 |
+
stream.Serialize(ref value.Id.Value);
|
1694 |
+
}
|
1695 |
+
public static void Serialize(this IBitStream stream, ref AssetRefConfigAssets value) {
|
1696 |
+
stream.Serialize(ref value.Id.Value);
|
1697 |
+
}
|
1698 |
+
public static void Serialize(this IBitStream stream, ref AssetRefGameConfig value) {
|
1699 |
+
stream.Serialize(ref value.Id.Value);
|
1700 |
+
}
|
1701 |
+
public static void Serialize(this IBitStream stream, ref AssetRefTurnConfig value) {
|
1702 |
+
stream.Serialize(ref value.Id.Value);
|
1703 |
+
}
|
1704 |
+
public static void Serialize(this IBitStream stream, ref AssetRefUserMap value) {
|
1705 |
+
stream.Serialize(ref value.Id.Value);
|
1706 |
+
}
|
1707 |
+
}
|
1708 |
+
[System.SerializableAttribute()]
|
1709 |
+
public unsafe partial class BallPoolSpec : AssetObject {
|
1710 |
+
}
|
1711 |
+
[System.SerializableAttribute()]
|
1712 |
+
public unsafe partial class ConfigAssets : AssetObject {
|
1713 |
+
}
|
1714 |
+
[System.SerializableAttribute()]
|
1715 |
+
public unsafe partial class GameConfig : AssetObject {
|
1716 |
+
}
|
1717 |
+
[System.SerializableAttribute()]
|
1718 |
+
public unsafe partial class UserMap : AssetObject {
|
1719 |
+
}
|
1720 |
+
[System.SerializableAttribute()]
|
1721 |
+
public unsafe partial class TurnConfig : AssetObject {
|
1722 |
+
}
|
1723 |
+
public unsafe partial class ComponentPrototypeVisitor : Prototypes.ComponentPrototypeVisitorBase {
|
1724 |
+
public virtual void Visit(Prototypes.BallFields_Prototype prototype) {
|
1725 |
+
VisitFallback(prototype);
|
1726 |
+
}
|
1727 |
+
}
|
1728 |
+
public static unsafe partial class Constants {
|
1729 |
+
public const Int32 MAX_PLAYERS = 2;
|
1730 |
+
}
|
1731 |
+
public static unsafe partial class StaticDelegates {
|
1732 |
+
public static FrameSerializer.Delegate SerializeBallPoolPlayer;
|
1733 |
+
public static FrameSerializer.Delegate SerializeInput;
|
1734 |
+
static partial void InitGen() {
|
1735 |
+
SerializeBallPoolPlayer = Quantum.BallPoolPlayer.Serialize;
|
1736 |
+
SerializeInput = Quantum.Input.Serialize;
|
1737 |
+
}
|
1738 |
+
}
|
1739 |
+
public unsafe partial class TypeRegistry {
|
1740 |
+
partial void AddGenerated() {
|
1741 |
+
Register(typeof(AssetGuid), AssetGuid.SIZE);
|
1742 |
+
Register(typeof(Quantum.AssetRefBallPoolSpec), Quantum.AssetRefBallPoolSpec.SIZE);
|
1743 |
+
Register(typeof(AssetRefCharacterController2DConfig), AssetRefCharacterController2DConfig.SIZE);
|
1744 |
+
Register(typeof(AssetRefCharacterController3DConfig), AssetRefCharacterController3DConfig.SIZE);
|
1745 |
+
Register(typeof(Quantum.AssetRefConfigAssets), Quantum.AssetRefConfigAssets.SIZE);
|
1746 |
+
Register(typeof(AssetRefEntityPrototype), AssetRefEntityPrototype.SIZE);
|
1747 |
+
Register(typeof(AssetRefEntityView), AssetRefEntityView.SIZE);
|
1748 |
+
Register(typeof(Quantum.AssetRefGameConfig), Quantum.AssetRefGameConfig.SIZE);
|
1749 |
+
Register(typeof(AssetRefMap), AssetRefMap.SIZE);
|
1750 |
+
Register(typeof(AssetRefNavMesh), AssetRefNavMesh.SIZE);
|
1751 |
+
Register(typeof(AssetRefNavMeshAgentConfig), AssetRefNavMeshAgentConfig.SIZE);
|
1752 |
+
Register(typeof(AssetRefPhysicsMaterial), AssetRefPhysicsMaterial.SIZE);
|
1753 |
+
Register(typeof(AssetRefPolygonCollider), AssetRefPolygonCollider.SIZE);
|
1754 |
+
Register(typeof(AssetRefTerrainCollider), AssetRefTerrainCollider.SIZE);
|
1755 |
+
Register(typeof(Quantum.AssetRefTurnConfig), Quantum.AssetRefTurnConfig.SIZE);
|
1756 |
+
Register(typeof(Quantum.AssetRefUserMap), Quantum.AssetRefUserMap.SIZE);
|
1757 |
+
Register(typeof(Quantum.BallFields), Quantum.BallFields.SIZE);
|
1758 |
+
Register(typeof(Quantum.BallPoolPlayer), Quantum.BallPoolPlayer.SIZE);
|
1759 |
+
Register(typeof(Quantum.BitSet1024), Quantum.BitSet1024.SIZE);
|
1760 |
+
Register(typeof(Quantum.BitSet128), Quantum.BitSet128.SIZE);
|
1761 |
+
Register(typeof(Quantum.BitSet2), Quantum.BitSet2.SIZE);
|
1762 |
+
Register(typeof(Quantum.BitSet2048), Quantum.BitSet2048.SIZE);
|
1763 |
+
Register(typeof(Quantum.BitSet256), Quantum.BitSet256.SIZE);
|
1764 |
+
Register(typeof(Quantum.BitSet4096), Quantum.BitSet4096.SIZE);
|
1765 |
+
Register(typeof(Quantum.BitSet512), Quantum.BitSet512.SIZE);
|
1766 |
+
Register(typeof(Button), Button.SIZE);
|
1767 |
+
Register(typeof(CharacterController2D), CharacterController2D.SIZE);
|
1768 |
+
Register(typeof(CharacterController3D), CharacterController3D.SIZE);
|
1769 |
+
Register(typeof(ColorRGBA), ColorRGBA.SIZE);
|
1770 |
+
Register(typeof(ComponentPrototypeRef), ComponentPrototypeRef.SIZE);
|
1771 |
+
Register(typeof(DistanceJoint), DistanceJoint.SIZE);
|
1772 |
+
Register(typeof(DistanceJoint3D), DistanceJoint3D.SIZE);
|
1773 |
+
Register(typeof(EntityPrototypeRef), EntityPrototypeRef.SIZE);
|
1774 |
+
Register(typeof(EntityRef), EntityRef.SIZE);
|
1775 |
+
Register(typeof(FP), FP.SIZE);
|
1776 |
+
Register(typeof(FPBounds2), FPBounds2.SIZE);
|
1777 |
+
Register(typeof(FPBounds3), FPBounds3.SIZE);
|
1778 |
+
Register(typeof(FPMatrix2x2), FPMatrix2x2.SIZE);
|
1779 |
+
Register(typeof(FPMatrix3x3), FPMatrix3x3.SIZE);
|
1780 |
+
Register(typeof(FPMatrix4x4), FPMatrix4x4.SIZE);
|
1781 |
+
Register(typeof(FPQuaternion), FPQuaternion.SIZE);
|
1782 |
+
Register(typeof(FPVector2), FPVector2.SIZE);
|
1783 |
+
Register(typeof(FPVector3), FPVector3.SIZE);
|
1784 |
+
Register(typeof(FrameMetaData), FrameMetaData.SIZE);
|
1785 |
+
Register(typeof(HingeJoint), HingeJoint.SIZE);
|
1786 |
+
Register(typeof(HingeJoint3D), HingeJoint3D.SIZE);
|
1787 |
+
Register(typeof(Hit), Hit.SIZE);
|
1788 |
+
Register(typeof(Hit3D), Hit3D.SIZE);
|
1789 |
+
Register(typeof(Quantum.Input), Quantum.Input.SIZE);
|
1790 |
+
Register(typeof(Quantum.InputButtons), 4);
|
1791 |
+
Register(typeof(Joint), Joint.SIZE);
|
1792 |
+
Register(typeof(Joint3D), Joint3D.SIZE);
|
1793 |
+
Register(typeof(LayerMask), LayerMask.SIZE);
|
1794 |
+
Register(typeof(MapEntityId), MapEntityId.SIZE);
|
1795 |
+
Register(typeof(MapEntityLink), MapEntityLink.SIZE);
|
1796 |
+
Register(typeof(NavMeshAvoidanceAgent), NavMeshAvoidanceAgent.SIZE);
|
1797 |
+
Register(typeof(NavMeshAvoidanceObstacle), NavMeshAvoidanceObstacle.SIZE);
|
1798 |
+
Register(typeof(NavMeshPathfinder), NavMeshPathfinder.SIZE);
|
1799 |
+
Register(typeof(NavMeshRegionMask), NavMeshRegionMask.SIZE);
|
1800 |
+
Register(typeof(NavMeshSteeringAgent), NavMeshSteeringAgent.SIZE);
|
1801 |
+
Register(typeof(NullableFP), NullableFP.SIZE);
|
1802 |
+
Register(typeof(NullableFPVector2), NullableFPVector2.SIZE);
|
1803 |
+
Register(typeof(NullableFPVector3), NullableFPVector3.SIZE);
|
1804 |
+
Register(typeof(NullableNonNegativeFP), NullableNonNegativeFP.SIZE);
|
1805 |
+
Register(typeof(PhysicsBody2D), PhysicsBody2D.SIZE);
|
1806 |
+
Register(typeof(PhysicsBody3D), PhysicsBody3D.SIZE);
|
1807 |
+
Register(typeof(PhysicsCollider2D), PhysicsCollider2D.SIZE);
|
1808 |
+
Register(typeof(PhysicsCollider3D), PhysicsCollider3D.SIZE);
|
1809 |
+
Register(typeof(PhysicsSceneSettings), PhysicsSceneSettings.SIZE);
|
1810 |
+
Register(typeof(PlayerRef), PlayerRef.SIZE);
|
1811 |
+
Register(typeof(Ptr), Ptr.SIZE);
|
1812 |
+
Register(typeof(QBoolean), QBoolean.SIZE);
|
1813 |
+
Register(typeof(Quantum.Ptr), Quantum.Ptr.SIZE);
|
1814 |
+
Register(typeof(RNGSession), RNGSession.SIZE);
|
1815 |
+
Register(typeof(Shape2D), Shape2D.SIZE);
|
1816 |
+
Register(typeof(Shape3D), Shape3D.SIZE);
|
1817 |
+
Register(typeof(SpringJoint), SpringJoint.SIZE);
|
1818 |
+
Register(typeof(SpringJoint3D), SpringJoint3D.SIZE);
|
1819 |
+
Register(typeof(Transform2D), Transform2D.SIZE);
|
1820 |
+
Register(typeof(Transform2DVertical), Transform2DVertical.SIZE);
|
1821 |
+
Register(typeof(Transform3D), Transform3D.SIZE);
|
1822 |
+
Register(typeof(Quantum.TurnData), Quantum.TurnData.SIZE);
|
1823 |
+
Register(typeof(Quantum.TurnEndReason), 4);
|
1824 |
+
Register(typeof(Quantum.TurnStatus), 4);
|
1825 |
+
Register(typeof(Quantum.TurnType), 4);
|
1826 |
+
Register(typeof(View), View.SIZE);
|
1827 |
+
Register(typeof(Quantum._globals_), Quantum._globals_.SIZE);
|
1828 |
+
}
|
1829 |
+
}
|
1830 |
+
public unsafe partial class FramePrinterGen {
|
1831 |
+
public static void EnsureNotStripped() {
|
1832 |
+
FramePrinter.EnsurePrimitiveNotStripped<Quantum.AssetRefBallPoolSpec>();
|
1833 |
+
FramePrinter.EnsurePrimitiveNotStripped<Quantum.AssetRefConfigAssets>();
|
1834 |
+
FramePrinter.EnsurePrimitiveNotStripped<Quantum.AssetRefGameConfig>();
|
1835 |
+
FramePrinter.EnsurePrimitiveNotStripped<Quantum.AssetRefTurnConfig>();
|
1836 |
+
FramePrinter.EnsurePrimitiveNotStripped<Quantum.AssetRefUserMap>();
|
1837 |
+
FramePrinter.EnsurePrimitiveNotStripped<Quantum.InputButtons>();
|
1838 |
+
FramePrinter.EnsurePrimitiveNotStripped<Quantum.TurnEndReason>();
|
1839 |
+
FramePrinter.EnsurePrimitiveNotStripped<Quantum.TurnStatus>();
|
1840 |
+
FramePrinter.EnsurePrimitiveNotStripped<Quantum.TurnType>();
|
1841 |
+
}
|
1842 |
+
}
|
1843 |
+
}
|
1844 |
+
namespace Quantum.Prototypes {
|
1845 |
+
using System;
|
1846 |
+
using System.Collections.Generic;
|
1847 |
+
using System.Runtime.InteropServices;
|
1848 |
+
using Photon.Deterministic;
|
1849 |
+
using Quantum.Core;
|
1850 |
+
using Quantum.Collections;
|
1851 |
+
using Quantum.Inspector;
|
1852 |
+
using Quantum.Physics2D;
|
1853 |
+
using Quantum.Physics3D;
|
1854 |
+
using Optional = Quantum.Inspector.OptionalAttribute;
|
1855 |
+
using MethodImplAttribute = System.Runtime.CompilerServices.MethodImplAttribute;
|
1856 |
+
using MethodImplOptions = System.Runtime.CompilerServices.MethodImplOptions;
|
1857 |
+
|
1858 |
+
[System.SerializableAttribute()]
|
1859 |
+
[Prototype(typeof(TurnEndReason))]
|
1860 |
+
public unsafe partial struct TurnEndReason_Prototype {
|
1861 |
+
public Int32 Value;
|
1862 |
+
public static implicit operator TurnEndReason(TurnEndReason_Prototype value) {
|
1863 |
+
return (TurnEndReason)value.Value;
|
1864 |
+
}
|
1865 |
+
public static implicit operator TurnEndReason_Prototype(TurnEndReason value) {
|
1866 |
+
return new TurnEndReason_Prototype() { Value = (Int32)value };
|
1867 |
+
}
|
1868 |
+
}
|
1869 |
+
[System.SerializableAttribute()]
|
1870 |
+
[Prototype(typeof(TurnStatus))]
|
1871 |
+
public unsafe partial struct TurnStatus_Prototype {
|
1872 |
+
public Int32 Value;
|
1873 |
+
public static implicit operator TurnStatus(TurnStatus_Prototype value) {
|
1874 |
+
return (TurnStatus)value.Value;
|
1875 |
+
}
|
1876 |
+
public static implicit operator TurnStatus_Prototype(TurnStatus value) {
|
1877 |
+
return new TurnStatus_Prototype() { Value = (Int32)value };
|
1878 |
+
}
|
1879 |
+
}
|
1880 |
+
[System.SerializableAttribute()]
|
1881 |
+
[Prototype(typeof(TurnType))]
|
1882 |
+
public unsafe partial struct TurnType_Prototype {
|
1883 |
+
public Int32 Value;
|
1884 |
+
public static implicit operator TurnType(TurnType_Prototype value) {
|
1885 |
+
return (TurnType)value.Value;
|
1886 |
+
}
|
1887 |
+
public static implicit operator TurnType_Prototype(TurnType value) {
|
1888 |
+
return new TurnType_Prototype() { Value = (Int32)value };
|
1889 |
+
}
|
1890 |
+
}
|
1891 |
+
[System.SerializableAttribute()]
|
1892 |
+
[Prototype(typeof(InputButtons))]
|
1893 |
+
public unsafe partial struct InputButtons_Prototype {
|
1894 |
+
public Int32 Value;
|
1895 |
+
public static implicit operator InputButtons(InputButtons_Prototype value) {
|
1896 |
+
return (InputButtons)value.Value;
|
1897 |
+
}
|
1898 |
+
public static implicit operator InputButtons_Prototype(InputButtons value) {
|
1899 |
+
return new InputButtons_Prototype() { Value = (Int32)value };
|
1900 |
+
}
|
1901 |
+
}
|
1902 |
+
[System.SerializableAttribute()]
|
1903 |
+
[Prototype(typeof(BallFields))]
|
1904 |
+
public sealed unsafe partial class BallFields_Prototype : ComponentPrototype<BallFields> {
|
1905 |
+
public FPVector2 Spin;
|
1906 |
+
public Int32 Number;
|
1907 |
+
public QBoolean Striped;
|
1908 |
+
public AssetRefBallPoolSpec Spec;
|
1909 |
+
public QBoolean InTable;
|
1910 |
+
partial void MaterializeUser(Frame frame, ref BallFields result, in PrototypeMaterializationContext context);
|
1911 |
+
public override Boolean AddToEntity(FrameBase f, EntityRef entity, in PrototypeMaterializationContext context) {
|
1912 |
+
BallFields component = default;
|
1913 |
+
Materialize((Frame)f, ref component, in context);
|
1914 |
+
return f.Set(entity, component) == SetResult.ComponentAdded;
|
1915 |
+
}
|
1916 |
+
public void Materialize(Frame frame, ref BallFields result, in PrototypeMaterializationContext context) {
|
1917 |
+
result.InTable = this.InTable;
|
1918 |
+
result.Number = this.Number;
|
1919 |
+
result.Spec = this.Spec;
|
1920 |
+
result.Spin = this.Spin;
|
1921 |
+
result.Striped = this.Striped;
|
1922 |
+
MaterializeUser(frame, ref result, in context);
|
1923 |
+
}
|
1924 |
+
public override void Dispatch(ComponentPrototypeVisitorBase visitor) {
|
1925 |
+
((ComponentPrototypeVisitor)visitor).Visit(this);
|
1926 |
+
}
|
1927 |
+
}
|
1928 |
+
[System.SerializableAttribute()]
|
1929 |
+
[Prototype(typeof(BallPoolPlayer))]
|
1930 |
+
public sealed unsafe partial class BallPoolPlayer_Prototype : StructPrototype {
|
1931 |
+
public PlayerRef Ref;
|
1932 |
+
public TurnData_Prototype TurnStats;
|
1933 |
+
public QBoolean StripedBalls;
|
1934 |
+
partial void MaterializeUser(Frame frame, ref BallPoolPlayer result, in PrototypeMaterializationContext context);
|
1935 |
+
public void Materialize(Frame frame, ref BallPoolPlayer result, in PrototypeMaterializationContext context) {
|
1936 |
+
result.Ref = this.Ref;
|
1937 |
+
result.StripedBalls = this.StripedBalls;
|
1938 |
+
this.TurnStats.Materialize(frame, ref result.TurnStats, in context);
|
1939 |
+
MaterializeUser(frame, ref result, in context);
|
1940 |
+
}
|
1941 |
+
}
|
1942 |
+
[System.SerializableAttribute()]
|
1943 |
+
[Prototype(typeof(Input))]
|
1944 |
+
public sealed unsafe partial class Input_Prototype : StructPrototype {
|
1945 |
+
public FPVector3 Direction;
|
1946 |
+
public FP ForceBarMarkPos;
|
1947 |
+
public FPVector2 BallPosition;
|
1948 |
+
partial void MaterializeUser(Frame frame, ref Input result, in PrototypeMaterializationContext context);
|
1949 |
+
public void Materialize(Frame frame, ref Input result, in PrototypeMaterializationContext context) {
|
1950 |
+
result.BallPosition = this.BallPosition;
|
1951 |
+
result.Direction = this.Direction;
|
1952 |
+
result.ForceBarMarkPos = this.ForceBarMarkPos;
|
1953 |
+
MaterializeUser(frame, ref result, in context);
|
1954 |
+
}
|
1955 |
+
}
|
1956 |
+
[System.SerializableAttribute()]
|
1957 |
+
[Prototype(typeof(TurnData))]
|
1958 |
+
public sealed unsafe partial class TurnData_Prototype : StructPrototype {
|
1959 |
+
public PlayerRef Player;
|
1960 |
+
public MapEntityId Entity;
|
1961 |
+
public AssetRefTurnConfig ConfigRef;
|
1962 |
+
public TurnType_Prototype Type;
|
1963 |
+
public TurnStatus_Prototype Status;
|
1964 |
+
public Int32 Number;
|
1965 |
+
public Int32 Ticks;
|
1966 |
+
partial void MaterializeUser(Frame frame, ref TurnData result, in PrototypeMaterializationContext context);
|
1967 |
+
public void Materialize(Frame frame, ref TurnData result, in PrototypeMaterializationContext context) {
|
1968 |
+
result.ConfigRef = this.ConfigRef;
|
1969 |
+
PrototypeValidator.FindMapEntity(this.Entity, in context, out result.Entity);
|
1970 |
+
result.Number = this.Number;
|
1971 |
+
result.Player = this.Player;
|
1972 |
+
result.Status = this.Status;
|
1973 |
+
result.Ticks = this.Ticks;
|
1974 |
+
result.Type = this.Type;
|
1975 |
+
MaterializeUser(frame, ref result, in context);
|
1976 |
+
}
|
1977 |
+
}
|
1978 |
+
public unsafe partial class FlatEntityPrototypeContainer {
|
1979 |
+
[ArrayLength(0, 1)]
|
1980 |
+
public List<Prototypes.BallFields_Prototype> BallFields;
|
1981 |
+
partial void CollectGen(List<ComponentPrototype> target) {
|
1982 |
+
Collect(BallFields, target);
|
1983 |
+
}
|
1984 |
+
public unsafe partial class StoreVisitor {
|
1985 |
+
public override void Visit(Prototypes.BallFields_Prototype prototype) {
|
1986 |
+
Storage.Store(prototype, ref Storage.BallFields);
|
1987 |
+
}
|
1988 |
+
}
|
1989 |
+
}
|
1990 |
+
}
|
1991 |
+
#pragma warning restore 0649
|
1992 |
+
#pragma warning restore 1522
|
1993 |
+
#pragma warning restore 0414
|
1994 |
+
#pragma warning restore 0219
|
1995 |
+
#pragma warning restore 0109
|
data/CommandSetup.Legacy.cs
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using Photon.Deterministic;
|
2 |
+
|
3 |
+
namespace Quantum
|
4 |
+
{
|
5 |
+
public static class CommandSetup
|
6 |
+
{
|
7 |
+
public static DeterministicCommand[] CreateCommands(RuntimeConfig gameConfig, SimulationConfig simulationConfig)
|
8 |
+
{
|
9 |
+
return null;
|
10 |
+
}
|
11 |
+
}
|
12 |
+
}
|
data/CommandSetup.User.cs
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
using System.Collections.Generic;
|
3 |
+
using Photon.Deterministic;
|
4 |
+
|
5 |
+
namespace Quantum
|
6 |
+
{
|
7 |
+
public static partial class DeterministicCommandSetup
|
8 |
+
{
|
9 |
+
static partial void AddCommandFactoriesUser(ICollection<IDeterministicCommandFactory> factories, RuntimeConfig gameConfig, SimulationConfig simulationConfig)
|
10 |
+
{
|
11 |
+
factories.Add(new GameMaster_SetCharacterPosition());
|
12 |
+
factories.Add(new GameMaster_SpawnPrototype());
|
13 |
+
}
|
14 |
+
}
|
15 |
+
}
|
data/CommandSetup.cs
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using Photon.Deterministic;
|
2 |
+
using System;
|
3 |
+
using System.Collections.Generic;
|
4 |
+
|
5 |
+
namespace Quantum
|
6 |
+
{
|
7 |
+
public static class CommandSetup
|
8 |
+
{
|
9 |
+
public static DeterministicCommand[] CreateCommands(RuntimeConfig gameConfig, SimulationConfig simulationConfig)
|
10 |
+
{
|
11 |
+
Type baseType = typeof(DeterministicCommand);
|
12 |
+
Type[] allTypes = typeof(CommandSetup).Assembly.GetTypes();
|
13 |
+
|
14 |
+
List<DeterministicCommand> commands = new List<DeterministicCommand>(16);
|
15 |
+
|
16 |
+
foreach (Type type in allTypes)
|
17 |
+
{
|
18 |
+
if (type.IsSubclassOf(baseType) == true && type.IsAbstract == false)
|
19 |
+
{
|
20 |
+
DeterministicCommand command = Activator.CreateInstance(type) as DeterministicCommand;
|
21 |
+
if (command != null)
|
22 |
+
{
|
23 |
+
commands.Add(command);
|
24 |
+
}
|
25 |
+
}
|
26 |
+
}
|
27 |
+
|
28 |
+
return commands.ToArray();
|
29 |
+
}
|
30 |
+
}
|
31 |
+
}
|
data/CommandSystem.cs
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
|
3 |
+
namespace Quantum
|
4 |
+
{
|
5 |
+
public unsafe class CommandSystem : SystemMainThread
|
6 |
+
{
|
7 |
+
public override void Update(Frame f)
|
8 |
+
{
|
9 |
+
var currentTurn = f.Global->CurrentTurn;
|
10 |
+
if (currentTurn.Status != TurnStatus.Active)
|
11 |
+
{
|
12 |
+
return;
|
13 |
+
}
|
14 |
+
|
15 |
+
|
16 |
+
var currentPlayer = f.Global->CurrentTurn.Player;
|
17 |
+
|
18 |
+
switch (f.GetPlayerCommand(currentPlayer))
|
19 |
+
{
|
20 |
+
case PlayCommand playCommand:
|
21 |
+
if (currentTurn.Type != TurnType.Play)
|
22 |
+
{
|
23 |
+
return;
|
24 |
+
}
|
25 |
+
f.Signals.OnPlayCommandReceived(currentPlayer, playCommand.Data);
|
26 |
+
f.Events.PlayCommandReceived(currentPlayer, playCommand.Data);
|
27 |
+
break;
|
28 |
+
|
29 |
+
case SkipCommand skipCommand:
|
30 |
+
var config = f.FindAsset<TurnConfig>(currentTurn.ConfigRef.Id);
|
31 |
+
if (!config.IsSkippable)
|
32 |
+
{
|
33 |
+
return;
|
34 |
+
}
|
35 |
+
f.Signals.OnSkipCommandReceived(currentPlayer, skipCommand.Data);
|
36 |
+
f.Events.SkipCommandReceived(currentPlayer, skipCommand.Data);
|
37 |
+
break;
|
38 |
+
}
|
39 |
+
}
|
40 |
+
}
|
41 |
+
}
|
data/ConfigAssets.cs
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum {
|
2 |
+
public partial class ConfigAssets {
|
3 |
+
public AssetRefGameConfig GameConfig;
|
4 |
+
public AssetRefTurnConfig StartCountdownConfig;
|
5 |
+
public AssetRefTurnConfig PlayTurnConfig;
|
6 |
+
public AssetRefTurnConfig CountdownTurnConfig;
|
7 |
+
}
|
8 |
+
}
|
data/ConfigAssetsHelper.cs
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
using System.Collections.Generic;
|
3 |
+
using System.Linq;
|
4 |
+
using System.Text;
|
5 |
+
using System.Threading.Tasks;
|
6 |
+
|
7 |
+
namespace Quantum
|
8 |
+
{
|
9 |
+
unsafe public class ConfigAssetsHelper
|
10 |
+
{
|
11 |
+
public static TurnConfig GetTurnConfig(Frame f, TurnType type)
|
12 |
+
{
|
13 |
+
var configAssets = f.FindAsset<ConfigAssets>(f.RuntimeConfig.ConfigAssets.Id);
|
14 |
+
TurnConfig config = null;
|
15 |
+
switch (type)
|
16 |
+
{
|
17 |
+
case TurnType.Countdown:
|
18 |
+
config = f.FindAsset<TurnConfig>(configAssets.CountdownTurnConfig.Id);
|
19 |
+
break;
|
20 |
+
case TurnType.Play:
|
21 |
+
config = f.FindAsset<TurnConfig>(configAssets.PlayTurnConfig.Id);
|
22 |
+
break;
|
23 |
+
default:
|
24 |
+
break;
|
25 |
+
}
|
26 |
+
return config;
|
27 |
+
}
|
28 |
+
|
29 |
+
public static GameConfig GetGameConfig(Frame f) {
|
30 |
+
var configAssets = f.FindAsset<ConfigAssets>(f.RuntimeConfig.ConfigAssets.Id);
|
31 |
+
return f.FindAsset<GameConfig>(configAssets.GameConfig.Id);
|
32 |
+
}
|
33 |
+
}
|
34 |
+
}
|
data/Configuration Files.txt
ADDED
@@ -0,0 +1,191 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Configuration Files
|
2 |
+
Introduction
|
3 |
+
Quantum Start Sequence
|
4 |
+
Config Files
|
5 |
+
PhotonServerSettings
|
6 |
+
DeterministicConfig
|
7 |
+
SimulationConfig
|
8 |
+
Delta Time Type
|
9 |
+
RuntimeConfig
|
10 |
+
RuntimePlayer
|
11 |
+
Using DSL Generated Code With RuntimePlayer And RuntimeConfig Serialization
|
12 |
+
|
13 |
+
Introduction
|
14 |
+
There are a few Quantum config files that have specific roles and purposes.
|
15 |
+
|
16 |
+
These config files are placed in different folders in the Unity project. Finding them quickly is made easy with the shortcuts (unity) editor window found in "Menu/Quantum/Show Shortcuts".
|
17 |
+
|
18 |
+
Most of default config instances reside as Scriptable Objects inside the "Resources" folder at the root level of the Unity project Assets, and will end up in your app build from there (see DeterministicSessionConfigAsset.Instance for example) while others (RuntimeConfig, RuntimePlayer) can be assembled during run-time.
|
19 |
+
|
20 |
+
Back To Top
|
21 |
+
|
22 |
+
|
23 |
+
Quantum Start Sequence
|
24 |
+
Which config is used by whom and send when is shown in the diagram below.
|
25 |
+
|
26 |
+
Config Sequence Diagram
|
27 |
+
Config Sequence Diagram
|
28 |
+
Back To Top
|
29 |
+
|
30 |
+
|
31 |
+
Config Files
|
32 |
+
|
33 |
+
PhotonServerSettings
|
34 |
+
Assets/Resources/PhotonServerSettings.asset
|
35 |
+
Quantum, from version 2.0, uses Photon Realtime to connect and communicate to the Photon Cloud. This config describes where the client connects to (cloud + region, local ip, ..).
|
36 |
+
|
37 |
+
photon realtime introduction
|
38 |
+
|
39 |
+
Also a valid AppId (referring to an active Quantum plugin) is set here.
|
40 |
+
|
41 |
+
Only one instance of this config file is allowed. The loading is tightly integrated into the PhotonNetwork class. See PhotonNetwork.PhotonServerSettings.
|
42 |
+
|
43 |
+
Photon Server Settings
|
44 |
+
Photon Server Settings
|
45 |
+
Back To Top
|
46 |
+
|
47 |
+
|
48 |
+
DeterministicConfig
|
49 |
+
Assets/Resouces/DeterministicConfig.asset
|
50 |
+
Via the DeterministicConfig developers can parametrize internals of the deterministic simulation and plugin (the Quantum server component). Toggle Show Help Info in the inspector of this config for details of each parameter.
|
51 |
+
|
52 |
+
The default way only allows one instance of this asset but as long as it is passed into QuantumRunner.StartParameters it does not matter how the file is retrieved.
|
53 |
+
|
54 |
+
This config file will be synchronized between all clients of one session. Although each player starts their own simulation locally with their own version of the DeterministicConfig, the server will distribute the config file instance of the first player who joined the plugin.
|
55 |
+
|
56 |
+
The data on this config is included in the checksum generation.
|
57 |
+
|
58 |
+
Deterministic Config
|
59 |
+
Deterministic Config
|
60 |
+
Back To Top
|
61 |
+
|
62 |
+
|
63 |
+
SimulationConfig
|
64 |
+
Assets/Resources/DB/Configs/SimulationConfig.asset
|
65 |
+
This config file holds parameters used in the ECS layer and inside core systems like physics and navigation. See the related system sections in the manual for more details of each value.
|
66 |
+
|
67 |
+
The SimulationConfig is part of the Quantum DB and multiple instances of this config are supported. Add the config asset GUID to the RuntimeConfig to select which SimualtionConfig should be used.
|
68 |
+
|
69 |
+
Developers can "extend" (create a partial class) the quantum_code/quantum.state/Core/SimulationConfig.cs class and add more data to it.
|
70 |
+
|
71 |
+
Simulation Config
|
72 |
+
Simulation Config
|
73 |
+
Back To Top
|
74 |
+
|
75 |
+
|
76 |
+
Delta Time Type
|
77 |
+
You can customize how the QuantumRunner will accumulate elapsed time to update the Quantum simulation (see the QuantumRunner.DeltaTime property).
|
78 |
+
|
79 |
+
The Default setting will use an internal stopwatch and is the recommended setting for production.
|
80 |
+
EngineDeltaTime will use, for example Unity.deltaTime, to track when to trigger simulation updates. This is very handy when debugging the project using break points, because upon resuming the simulation with not fast-forward but continue from the exact time the simulation was paused. Alas, this setting can cause issues with time synchronization when initializing online matches: the time tracking can be inaccurate under load (e.g. level loading) and result in a lot of large extra time syncs request and cancelled inputs for a client when starting an online game.
|
81 |
+
Back To Top
|
82 |
+
|
83 |
+
|
84 |
+
RuntimeConfig
|
85 |
+
In contrast to the SimulationConfig, which has only static configuration data, the RuntimeConfig holds information that can be different from game to game. By default is defines for example what map to load and the random start seed. It is assembled from scratch each time starting a game.
|
86 |
+
|
87 |
+
Developers can add custom data to quantum_code/quantum.state/RuntimeConfig.User.cs (don't forget to fill out the serialization methods).
|
88 |
+
|
89 |
+
Like the DeterministicConfig this "file" is distributed to every other client after the first player connected and joined the Quantum plugin.
|
90 |
+
|
91 |
+
A convenient way of using this config is by creating a MonoBehaviour that stores an instance of RuntimeConfig (and RuntimePlayer) with default values and asset links (GUIDs) for example pointing to other asset files containing specific balancing data. When the player is inside a game lobby parts of the Runtime configs can be overwritten with his custom load-out before connecting and starting the game. See QuantumRunnerLocalDebug.cs or the sample below:
|
92 |
+
|
93 |
+
Runtime Setup
|
94 |
+
Runtime Setup
|
95 |
+
using Quantum;
|
96 |
+
using UnityEngine;
|
97 |
+
|
98 |
+
public sealed class RuntimeSetup : MonoBehaviour
|
99 |
+
{
|
100 |
+
public static RuntimeSetup Instance { get; private set; }
|
101 |
+
|
102 |
+
public RuntimeConfig GameConfig { get { return _gameConfig; } }
|
103 |
+
public RuntimePlayer PlayerConfig { get { return _playerConfig; } }
|
104 |
+
|
105 |
+
[SerializeField] private RuntimeConfig _gameConfig;
|
106 |
+
[SerializeField] private RuntimePlayer _playerConfig;
|
107 |
+
|
108 |
+
private void Awake() {
|
109 |
+
Instance = this;
|
110 |
+
}
|
111 |
+
}
|
112 |
+
Back To Top
|
113 |
+
|
114 |
+
|
115 |
+
RuntimePlayer
|
116 |
+
Similar to the RuntimeConfig the RuntimePlayer describes dynamic properties for one player (quantum_code/quantum.state/RuntimePlayer.User.cs).
|
117 |
+
|
118 |
+
The data for a player behaves differently to the other configs, because it is send by each player individually after the actual game has been started. See the Player document in the manual for more information.
|
119 |
+
|
120 |
+
Back To Top
|
121 |
+
|
122 |
+
|
123 |
+
Using DSL Generated Code With RuntimePlayer And RuntimeConfig Serialization
|
124 |
+
RuntimeConfig and RuntimePlayer require to write manual serialization code. When using DSL generated structs of component prototypes the serialization code can be simplified.
|
125 |
+
|
126 |
+
Caveat: Never use objects that are actually pointers that require a frame to be resolved (e.g. Quantum collections).
|
127 |
+
|
128 |
+
The following struct Foo43 and components prototype Component43 will be used in the RuntimePlayer.
|
129 |
+
|
130 |
+
struct Foo43 {
|
131 |
+
int Integer;
|
132 |
+
array<Byte>[8] Bytes;
|
133 |
+
asset_ref<Map> MapAssetReference;
|
134 |
+
Bar43 Bar43;
|
135 |
+
}
|
136 |
+
|
137 |
+
struct Bar43 {
|
138 |
+
FPVector3 Vector3;
|
139 |
+
}
|
140 |
+
|
141 |
+
component Component43 {
|
142 |
+
int Integer;
|
143 |
+
OtherComponent43 OtherComponent;
|
144 |
+
}
|
145 |
+
|
146 |
+
component OtherComponent43 {
|
147 |
+
int Integer;
|
148 |
+
FP FP;
|
149 |
+
}
|
150 |
+
The partial RuntimePlayer.User implementation looks like this.
|
151 |
+
|
152 |
+
partial class RuntimePlayer {
|
153 |
+
// A) Use a DSL generated struct on RuntimePlayer
|
154 |
+
public Foo43 Foo;
|
155 |
+
|
156 |
+
// B) Piggyback on a component prototype to set data
|
157 |
+
public Component43_Prototype Component43 = new Component43_Prototype { OtherComponent = new OtherComponent43_Prototype() };
|
158 |
+
|
159 |
+
partial void SerializeUserData(BitStream stream) {
|
160 |
+
// A) Because the struct is memory alined we can pin the memory and serialize it as a byte array which will work platform indenpentently.
|
161 |
+
unsafe {
|
162 |
+
fixed (Foo43* p = &Foo) {
|
163 |
+
stream.SerializeBuffer((byte*)p, sizeof(Foo43));
|
164 |
+
}
|
165 |
+
}
|
166 |
+
|
167 |
+
// B) Initialized the references in the field declaration with new and serialize all fields here.
|
168 |
+
stream.Serialize(ref Component43.Integer);
|
169 |
+
stream.Serialize(ref Component43.OtherComponent.Integer);
|
170 |
+
stream.Serialize(ref Component43.OtherComponent.FP);
|
171 |
+
}
|
172 |
+
}
|
173 |
+
Send the RuntimePlayer from the client:
|
174 |
+
|
175 |
+
var runtimePlayer = new Quantum.RuntimePlayer {
|
176 |
+
Component43 = new Quantum.Prototypes.Component43_Prototype {
|
177 |
+
Integer = 1,
|
178 |
+
OtherComponent = new Quantum.Prototypes.OtherComponent43_Prototype { FP = 2, Integer = 3 } },
|
179 |
+
Foo = new Foo43 {
|
180 |
+
Bar43 = new Bar43 { Vector3 = FPVector3.One },
|
181 |
+
Integer = 4,
|
182 |
+
MapAssetReference = new AssetRefMap() { Id = 66 }
|
183 |
+
}
|
184 |
+
};
|
185 |
+
|
186 |
+
unsafe {
|
187 |
+
runtimePlayer.Foo.Bytes[0] = 7;
|
188 |
+
runtimePlayer.Foo.Bytes[1] = 6;
|
189 |
+
}
|
190 |
+
|
191 |
+
game.SendPlayerData(lp, runtimePlayer);
|
data/Consideration.cs
ADDED
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using Photon.Deterministic;
|
2 |
+
using System;
|
3 |
+
using Quantum.Prototypes;
|
4 |
+
|
5 |
+
namespace Quantum
|
6 |
+
{
|
7 |
+
[Serializable]
|
8 |
+
public struct ResponseCurvePack
|
9 |
+
{
|
10 |
+
public FP MultiplyFactor;
|
11 |
+
public AssetRefAIFunctionFP ResponseCurveRef;
|
12 |
+
[NonSerialized] public ResponseCurve ResponseCurve;
|
13 |
+
}
|
14 |
+
|
15 |
+
public unsafe partial class Consideration
|
16 |
+
{
|
17 |
+
public string Label;
|
18 |
+
|
19 |
+
public AssetRefAIFunctionInt RankRef;
|
20 |
+
public AssetRefAIFunctionBool CommitmentRef;
|
21 |
+
public AssetRefConsideration[] NextConsiderationsRefs;
|
22 |
+
public AssetRefAIAction[] OnEnterActionsRefs;
|
23 |
+
public AssetRefAIAction[] OnUpdateActionsRefs;
|
24 |
+
public AssetRefAIAction[] OnExitActionsRefs;
|
25 |
+
|
26 |
+
[NonSerialized] public AIFunctionInt Rank;
|
27 |
+
[NonSerialized] public AIFunctionBool Commitment;
|
28 |
+
[NonSerialized] public Consideration[] NextConsiderations;
|
29 |
+
[NonSerialized] public AIAction[] OnEnterActions;
|
30 |
+
[NonSerialized] public AIAction[] OnUpdateActions;
|
31 |
+
[NonSerialized] public AIAction[] OnExitActions;
|
32 |
+
|
33 |
+
public ResponseCurvePack[] ResponseCurvePacks;
|
34 |
+
|
35 |
+
public FP BaseScore;
|
36 |
+
|
37 |
+
public UTMomentumData MomentumData;
|
38 |
+
public FP Cooldown;
|
39 |
+
|
40 |
+
public byte Depth;
|
41 |
+
|
42 |
+
public int GetRank(Frame frame, EntityRef entity = default)
|
43 |
+
{
|
44 |
+
if (Rank == null)
|
45 |
+
return 0;
|
46 |
+
|
47 |
+
return Rank.Execute(frame, entity);
|
48 |
+
}
|
49 |
+
|
50 |
+
public FP Score(Frame frame, EntityRef entity = default)
|
51 |
+
{
|
52 |
+
if (ResponseCurvePacks.Length == 0)
|
53 |
+
return 0;
|
54 |
+
|
55 |
+
FP score = 1;
|
56 |
+
for (int i = 0; i < ResponseCurvePacks.Length; i++)
|
57 |
+
{
|
58 |
+
score *= ResponseCurvePacks[i].ResponseCurve.Execute(frame, entity) * ResponseCurvePacks[i].MultiplyFactor;
|
59 |
+
|
60 |
+
// If we find a negative veto, the final score would be zero anyways, so we stop here
|
61 |
+
if (score == 0)
|
62 |
+
{
|
63 |
+
break;
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
+
score += BaseScore;
|
68 |
+
|
69 |
+
FP modificationFactor = 1 - (1 / ResponseCurvePacks.Length);
|
70 |
+
FP makeUpValue = (1 - score) * modificationFactor;
|
71 |
+
FP finalScore = score + (makeUpValue * score);
|
72 |
+
|
73 |
+
return finalScore;
|
74 |
+
}
|
75 |
+
|
76 |
+
public void OnEnter(Frame frame, UtilityReasoner* reasoner, EntityRef entity = default)
|
77 |
+
{
|
78 |
+
for (int i = 0; i < OnEnterActions.Length; i++)
|
79 |
+
{
|
80 |
+
OnEnterActions[i].Update(frame, entity);
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
public void OnExit(Frame frame, UtilityReasoner* reasoner, EntityRef entity = default)
|
85 |
+
{
|
86 |
+
for (int i = 0; i < OnExitActions.Length; i++)
|
87 |
+
{
|
88 |
+
OnExitActions[i].Update(frame, entity);
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
public void OnUpdate(Frame frame, UtilityReasoner* reasoner, EntityRef entity = default)
|
93 |
+
{
|
94 |
+
for (int i = 0; i < OnUpdateActions.Length; i++)
|
95 |
+
{
|
96 |
+
OnUpdateActions[i].Update(frame, entity);
|
97 |
+
}
|
98 |
+
|
99 |
+
if (NextConsiderationsRefs != null && NextConsiderationsRefs.Length > 0)
|
100 |
+
{
|
101 |
+
Consideration chosenConsideration = reasoner->SelectBestConsideration(frame, NextConsiderations, (byte)(Depth + 1), reasoner, entity);
|
102 |
+
if (chosenConsideration != default)
|
103 |
+
{
|
104 |
+
chosenConsideration.OnUpdate(frame, reasoner, entity);
|
105 |
+
UTManager.ConsiderationChosen?.Invoke(entity, chosenConsideration.Identifier.Guid.Value);
|
106 |
+
}
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
public override void Loaded(IResourceManager resourceManager, Native.Allocator allocator)
|
111 |
+
{
|
112 |
+
base.Loaded(resourceManager, allocator);
|
113 |
+
|
114 |
+
Rank = (AIFunctionInt)resourceManager.GetAsset(RankRef.Id);
|
115 |
+
|
116 |
+
if (ResponseCurvePacks != null)
|
117 |
+
{
|
118 |
+
for (Int32 i = 0; i < ResponseCurvePacks.Length; i++)
|
119 |
+
{
|
120 |
+
ResponseCurvePacks[i].ResponseCurve = (ResponseCurve)resourceManager.GetAsset(ResponseCurvePacks[i].ResponseCurveRef.Id);
|
121 |
+
ResponseCurvePacks[i].MultiplyFactor = 1;
|
122 |
+
}
|
123 |
+
}
|
124 |
+
|
125 |
+
OnEnterActions = new AIAction[OnEnterActionsRefs == null ? 0 : OnEnterActionsRefs.Length];
|
126 |
+
if (OnEnterActionsRefs != null)
|
127 |
+
{
|
128 |
+
for (Int32 i = 0; i < OnEnterActionsRefs.Length; i++)
|
129 |
+
{
|
130 |
+
OnEnterActions[i] = (AIAction)resourceManager.GetAsset(OnEnterActionsRefs[i].Id);
|
131 |
+
}
|
132 |
+
}
|
133 |
+
|
134 |
+
OnUpdateActions = new AIAction[OnUpdateActionsRefs == null ? 0 : OnUpdateActionsRefs.Length];
|
135 |
+
if (OnEnterActionsRefs != null)
|
136 |
+
{
|
137 |
+
for (Int32 i = 0; i < OnUpdateActionsRefs.Length; i++)
|
138 |
+
{
|
139 |
+
OnUpdateActions[i] = (AIAction)resourceManager.GetAsset(OnUpdateActionsRefs[i].Id);
|
140 |
+
}
|
141 |
+
}
|
142 |
+
|
143 |
+
OnExitActions = new AIAction[OnExitActionsRefs == null ? 0 : OnExitActionsRefs.Length];
|
144 |
+
if (OnEnterActionsRefs != null)
|
145 |
+
{
|
146 |
+
for (Int32 i = 0; i < OnExitActionsRefs.Length; i++)
|
147 |
+
{
|
148 |
+
OnExitActions[i] = (AIAction)resourceManager.GetAsset(OnExitActionsRefs[i].Id);
|
149 |
+
}
|
150 |
+
}
|
151 |
+
|
152 |
+
Commitment = (AIFunctionBool)resourceManager.GetAsset(CommitmentRef.Id);
|
153 |
+
|
154 |
+
NextConsiderations = new Consideration[NextConsiderationsRefs == null ? 0 : NextConsiderationsRefs.Length];
|
155 |
+
if (NextConsiderationsRefs != null)
|
156 |
+
{
|
157 |
+
for (Int32 i = 0; i < NextConsiderationsRefs.Length; i++)
|
158 |
+
{
|
159 |
+
NextConsiderations[i] = (Consideration)resourceManager.GetAsset(NextConsiderationsRefs[i].Id);
|
160 |
+
}
|
161 |
+
}
|
162 |
+
}
|
163 |
+
}
|
164 |
+
}
|
data/Core.cs
ADDED
The diff for this file is too large to render.
See raw diff
|
|
data/DSL.txt
ADDED
@@ -0,0 +1,502 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Introduction
|
2 |
+
Quantum requires components and other runtime game state data types to be declared with its own DSL (domain-specific-language).
|
3 |
+
|
4 |
+
These definitions are written into text files with the .qtn extension. The Quantum compiler will parse them into an AST, and generate partial C# struct definitions for each type (definitions can be split across as many files if needed, the compiler will merge them accordingly).
|
5 |
+
|
6 |
+
The goal of the DSL is to abstract away from the developer the complex memory alignment requirements imposed by Quantum's ECS sparse set memory model, required to support the deterministic predict/rollback approach to simulation.
|
7 |
+
|
8 |
+
This code generation approach also eliminates the need to write "boiler-plate" code for type serialization (used for snapshots, game saves, killcam replays), checksumming and other functions, like printing/dumping frame data for debugging purposes.
|
9 |
+
|
10 |
+
The quantum dsl integration section shows how to add qtn files to the workflow.
|
11 |
+
|
12 |
+
Components
|
13 |
+
Components are special structs that can be attached to entities, and used for filtering them (iterating only a subset of the active entities based on its attached components). This is a basic example definition of a component:
|
14 |
+
|
15 |
+
component Action
|
16 |
+
{
|
17 |
+
FP Cooldown;
|
18 |
+
FP Power;
|
19 |
+
}
|
20 |
+
These will be turned into regular C# structs. Labelling them as components (like above) will generate the appropriate code structure (marker interface, id property, etc).
|
21 |
+
|
22 |
+
Aside from custom components, Quantum comes with several pre-built ones:
|
23 |
+
|
24 |
+
Transform2D/Transform3D: position and rotation using Fixed Point (FP) values;
|
25 |
+
PhysicsCollider, PhysicsBody, PhysicsCallbacks, PhysicsJoints (2D/3D): used by Quantum's stateless physics engines;
|
26 |
+
PathFinderAgent, SteeringAgent, AvoidanceAgent, AvoidanceObstacle: navmesh-based path finding and movement.
|
27 |
+
Back To Top
|
28 |
+
|
29 |
+
|
30 |
+
Structs
|
31 |
+
Structs can be defined in both the DSL and C#.
|
32 |
+
|
33 |
+
|
34 |
+
DSL Defined
|
35 |
+
The Quantum DSL also allows the definition of regular structs (just like components, memory alignment, and helper functions will be taken care of):
|
36 |
+
|
37 |
+
struct ResourceItem
|
38 |
+
{
|
39 |
+
FP Value;
|
40 |
+
FP MaxValue;
|
41 |
+
FP RegenRate;
|
42 |
+
}
|
43 |
+
The fields will be ordered in alphabetical order when the struct is generated. If you need / want to have them appear in a specific order, you will have to define the structs in C# (see section below).
|
44 |
+
|
45 |
+
This would let you use the "Resources" struct as a type in all other parts of the DSL, for example using it inside a component definition:
|
46 |
+
|
47 |
+
component Resources
|
48 |
+
{
|
49 |
+
ResourceItem Health;
|
50 |
+
ResourceItem Strength;
|
51 |
+
ResourceItem Mana;
|
52 |
+
}
|
53 |
+
The generated struct is partial and can be extended in C# if so desired.
|
54 |
+
|
55 |
+
Back To Top
|
56 |
+
|
57 |
+
|
58 |
+
CSharp Defined
|
59 |
+
You can define structs in C# as well; however, in this case you will have to manually define the memory aligned of the struct.
|
60 |
+
|
61 |
+
[StructLayout(LayoutKind.Explicit)]
|
62 |
+
public struct Foo {
|
63 |
+
public const int SIZE = 12; // the size in bytes of all members in bytes.
|
64 |
+
|
65 |
+
[FieldOffset(0)]
|
66 |
+
public int A;
|
67 |
+
|
68 |
+
[FieldOffset(4)]
|
69 |
+
public int B;
|
70 |
+
|
71 |
+
[FieldOffset(8)]
|
72 |
+
public int C;
|
73 |
+
}
|
74 |
+
When using C# defined structs in the DSL (e.g. inside components), you will have to manually import the struct definition.
|
75 |
+
|
76 |
+
import struct Foo(12);
|
77 |
+
N.B.: The import does not support constants in the size; you will have to specify the exact numerical value each time.
|
78 |
+
|
79 |
+
Back To Top
|
80 |
+
|
81 |
+
|
82 |
+
Components Vs. Structs
|
83 |
+
An important question is why and when should components be used instead of regular structs (components, in the end, are also structs).
|
84 |
+
|
85 |
+
Components contain generated meta-data that turns them into a special type with the following features:
|
86 |
+
|
87 |
+
Can be attached directly to entities;
|
88 |
+
Used to filter entities when traversing the game state (next chapter will dive into the filter API);
|
89 |
+
Components can accessed, used or passed as parameters as either pointers or as value types, just like any other struct.
|
90 |
+
|
91 |
+
Back To Top
|
92 |
+
|
93 |
+
|
94 |
+
Dynamic Collections
|
95 |
+
Quantum's custom allocator exposes blittable collections as part of the rollback-able game state. Collections only support support blittable types (i.e. primitive and DSL-defined types).
|
96 |
+
|
97 |
+
To manage collection, the Frame API offers 3 methods for each:
|
98 |
+
|
99 |
+
Frame.AllocateXXX: To allocate space for the collection on the heap.
|
100 |
+
Frame.FreeXXX: To free/deallocate the collection's memory.
|
101 |
+
Frame.ResolveXXX: To access the collection by resolving the pointer it.
|
102 |
+
Note: After freeing a collection, it HAS TO be nullified by setting it to default. This is required for serialization of the game state to work properly. Omitting the nullification will result in indeterministic behavior and desynchronisation. As alternative to freeing a collection and nullifying its Ptrs manually, it possible to use the FreeOnComponentRemoved attribute on the field in question.
|
103 |
+
|
104 |
+
Back To Top
|
105 |
+
|
106 |
+
|
107 |
+
Important Notes
|
108 |
+
Several components can reference the same collection instance.
|
109 |
+
Dynamic collections are stored as references inside components and structs. They therefore have to to be allocated when initializing them, and more importantly, freed when they are not needed any more. If the collection is part of a component, two options are available:
|
110 |
+
implement the reactive callbacks ISignalOnAdd<T> and ISignalOnRemove<T> and allocate/free the collections there. (For more information on these specific signals, see the Components page in the ECS section of the Manual); or,
|
111 |
+
use the [AllocateOnComponentAdded] and [FreeOnComponentRemoved] attributes to let Quantum handle the allocation and deallocation when the component is added and removed respectively.
|
112 |
+
Quantum do NOT pre-allocate collections from prototypes, unless there is at least value. If the collection is empty, the memory has to be manually allocated.
|
113 |
+
Attempting to free a collection more than once will throw an error and puts the heap in an invalid state internally.
|
114 |
+
Back To Top
|
115 |
+
|
116 |
+
|
117 |
+
Lists
|
118 |
+
Dynamic lists can be defined in the DSL using list<T> MyList.
|
119 |
+
|
120 |
+
component Targets {
|
121 |
+
list<EntityRef> Enemies;
|
122 |
+
}
|
123 |
+
The basic API methods for dealing with these Lists are:
|
124 |
+
|
125 |
+
Frame.AllocateList<T>()
|
126 |
+
Frame.FreeList(QListPtr<T> ptr)
|
127 |
+
Frame.ResolveList(QListPtr<T> ptr)
|
128 |
+
Once resolved, a list can be iterated over or manipulated with all the expected API methods of a list such as Add, Remove, Contains, IndexOf, RemoveAt, [], etc... .
|
129 |
+
|
130 |
+
To use the list in the component of type Targets defined in the code snippet above, you could create the following system:
|
131 |
+
|
132 |
+
namespace Quantum
|
133 |
+
{
|
134 |
+
public unsafe class HandleTargets : SystemMainThread, ISignalOnComponentAdded<Targets>, ISignalOnComponentRemoved<Targets>
|
135 |
+
{
|
136 |
+
public override void Update(Frame f)
|
137 |
+
{
|
138 |
+
var targets = f.GetComponentIterator<Targets>();
|
139 |
+
|
140 |
+
for (int i = 0; i < targets.Count; i++)
|
141 |
+
{
|
142 |
+
var target = targets[i];
|
143 |
+
|
144 |
+
// To use a list, you must first resolve its pointer via the frame
|
145 |
+
var list = frame.ResolveList(target.Enemies);
|
146 |
+
|
147 |
+
// Do stuff
|
148 |
+
}
|
149 |
+
}
|
150 |
+
|
151 |
+
public void OnAdded(Frame f, EntityRef entity, Targets* component)
|
152 |
+
{
|
153 |
+
// allocating a new List (returns the blittable reference type - QListPtr)
|
154 |
+
component->Enemies = f.AllocateList<EntityRef>();
|
155 |
+
}
|
156 |
+
|
157 |
+
public void OnRemoved(Frame f, EntityRef entity, Targets* component)
|
158 |
+
{
|
159 |
+
// A component HAS TO de-allocate all collection it owns from the frame data, otherwise it will lead to a memory leak.
|
160 |
+
// receives the list QListPtr reference.
|
161 |
+
f.FreeList(component->Enemies);
|
162 |
+
|
163 |
+
// All dynamic collections a component points to HAVE TO be nullified in a component's OnRemoved
|
164 |
+
// EVEN IF is only referencing an external one!
|
165 |
+
// This is to prevent serialization issues that otherwise lead to a desynchronisation.
|
166 |
+
component->Enemies = default;
|
167 |
+
}
|
168 |
+
}
|
169 |
+
}
|
170 |
+
Back To Top
|
171 |
+
|
172 |
+
|
173 |
+
Dictionaries
|
174 |
+
Dictionaries can be declared in the DSL like so dictionary<key, value> MyDictionary.
|
175 |
+
|
176 |
+
component Hazard{
|
177 |
+
dictionary<EntityRef, Int32> DamageDealt;
|
178 |
+
}
|
179 |
+
The basic API methods for dealing with these dictionaries are:
|
180 |
+
|
181 |
+
Frame.AllocateDictionary<K,V>()
|
182 |
+
Frame.FreeDictionary(QDictionaryPtr<K,V> ptr)
|
183 |
+
Frame.ResolveDictionary(QDictionaryPtr<K,V> ptr)
|
184 |
+
Just like with any other dynamic collection it is mandatory to allocate it before using it, as well as de-allocate it from the frame data and nullified it once the dictionary is no longer used. See the example provided in the section about lists here above.
|
185 |
+
|
186 |
+
Back To Top
|
187 |
+
|
188 |
+
|
189 |
+
HashSet
|
190 |
+
HashSets can be declared in the DSL like so hash_set<T> MyHashSet.
|
191 |
+
|
192 |
+
component Nodes{
|
193 |
+
hash_set<FP> ProcessedNodes;
|
194 |
+
}
|
195 |
+
The basic API methods for dealing with these dictionaries are:
|
196 |
+
|
197 |
+
Frame.AllocateHashSet(QHashSetPtr<T> ptr, int capacity = 8)
|
198 |
+
Frame.FreeHashSet(QHashSetPtr<T> ptr)
|
199 |
+
Frame.ResolveHashSet(QHashSetPtr<T> ptr)
|
200 |
+
Just like with any other dynamic collection it is mandatory to allocate it before using it, as well as de-allocate it from the frame data and nullified it once the hash set is no longer used. See the example provided in the section about lists here above.
|
201 |
+
|
202 |
+
Back To Top
|
203 |
+
|
204 |
+
|
205 |
+
Unions, Enums And Bitsets
|
206 |
+
C-like unions and enums can be generated as well. The example below demonstrates how to save data memory by overlapping some mutually exclusive data types/values into a union:
|
207 |
+
|
208 |
+
struct DataA
|
209 |
+
{
|
210 |
+
FPVector2 Something;
|
211 |
+
FP Anything;
|
212 |
+
}
|
213 |
+
|
214 |
+
struct DataB
|
215 |
+
{
|
216 |
+
FPVector3 SomethingElse;
|
217 |
+
Int32 AnythingElse;
|
218 |
+
}
|
219 |
+
|
220 |
+
union Data
|
221 |
+
{
|
222 |
+
DataA A;
|
223 |
+
DataB B;
|
224 |
+
}
|
225 |
+
The generated type Data will also include a differentiator property (to tell which union-type has been populated). "Touching" any of the union sub-types will set this property to the appropriate value.
|
226 |
+
|
227 |
+
Bitsets can be used to declared fixed-size memory blocks for any desired purpose (for example fog-of-war, grid-like structures for pixel perfect game mechanics, etc.):
|
228 |
+
|
229 |
+
struct FOWData
|
230 |
+
{
|
231 |
+
bitset[256] Map;
|
232 |
+
}
|
233 |
+
Back To Top
|
234 |
+
|
235 |
+
|
236 |
+
Input
|
237 |
+
In Quantum, the runtime input exchanged between clients is also declared in the DSL. This example defines a simple movement vector and a Fire button as input for a game:
|
238 |
+
|
239 |
+
input
|
240 |
+
{
|
241 |
+
FPVector2 Movement;
|
242 |
+
button Fire;
|
243 |
+
}
|
244 |
+
The input struct is polled every tick and sent to the server (when playing online).
|
245 |
+
|
246 |
+
For more information about input, such as best practices and recommended approaches to optimization, refer to this page: input
|
247 |
+
|
248 |
+
Back To Top
|
249 |
+
|
250 |
+
|
251 |
+
Signals
|
252 |
+
Signals are function signatures used as a decoupled inter-system communication API (a form of publisher/subscriber API). This would define a simple signal (notice the special type entity_ref - these will be listed at the end of this chapter):
|
253 |
+
|
254 |
+
signal OnDamage(FP damage, entity_ref entity);
|
255 |
+
This would generate the following interface (that can be implemented by any System):
|
256 |
+
|
257 |
+
public interface ISignalOnDamage
|
258 |
+
{
|
259 |
+
public void OnDamage(Frame f, FP damage, EntityRef entity);
|
260 |
+
}
|
261 |
+
Signals are the only concept which allows the direct declaration of a pointer in Quantum's DSL, so passing data by reference can be used to modify the original data directly in their concrete implementations:
|
262 |
+
|
263 |
+
signal OnBeforeDamage(FP damage, Resources* resources);
|
264 |
+
Notice this allows the passing of a component pointer (instead of the entity reference type).
|
265 |
+
|
266 |
+
Back To Top
|
267 |
+
|
268 |
+
|
269 |
+
Events
|
270 |
+
Events are a fine-grained solution to communicate what happens inside the simulation to the rendering engine / view (they should never be used to modify/update part of the game state). Use the "event" keyword to define its name and data:
|
271 |
+
|
272 |
+
Find detailed information about events in the game events manual.
|
273 |
+
|
274 |
+
Define an event using the Quantum DSL
|
275 |
+
|
276 |
+
event MyEvent{
|
277 |
+
int Foo;
|
278 |
+
}
|
279 |
+
Trigger the event from the simulation
|
280 |
+
|
281 |
+
f.Events.MyEvent(2022);
|
282 |
+
And subscribe and consume the event in Unity
|
283 |
+
|
284 |
+
QuantumEvent.Subscribe(listener: this, handler: (MyEvent e) => Debug.Log($"MyEvent {e.Foo}"));
|
285 |
+
Back To Top
|
286 |
+
|
287 |
+
|
288 |
+
Globals
|
289 |
+
It is possible to define globally accessible variables in the DSL. Globals can be declared in any .qtn file by using the global scope.
|
290 |
+
|
291 |
+
global {
|
292 |
+
// Any type that is valid in the DSL can also be used.
|
293 |
+
FP MyGlobalValue;
|
294 |
+
}
|
295 |
+
Like all things DSL-defined, global variables are part of the state and are fully compatible with the predict-rollback system.
|
296 |
+
|
297 |
+
Variables declared in the global scope are made available through the Frame API. They can be accessed (read/write) from any place that has access to the frame - see the Systems document in the ECS section.
|
298 |
+
|
299 |
+
N.B.: An alternative to global variables are the Singleton Components; for more information please refer to the Components page in the ECS section of the manual.
|
300 |
+
|
301 |
+
Back To Top
|
302 |
+
|
303 |
+
|
304 |
+
Special Types
|
305 |
+
Quantum has a few special types that are used to either abstract complex concepts (entity reference, player indexes, etc.), or to protect against common mistakes with unmanaged code, or both. The following special types are available to be used inside other data types (including in components, also in events, signals, etc.):
|
306 |
+
|
307 |
+
player_ref: represents a runtime player index (also cast to and from Int32). When defined in a component, can be used to store which player controls the associated entity (combined with Quantum's player-index-based input).
|
308 |
+
entity_ref: because each frame/tick data in quantum resides on a separate memory region/block (Quantum keeps a a few copies to support rollbacks), pointers cannot be cached in-between frames (nor in the game state neither in Unity scripts). An entity ref abstracts an entity's index and version properties (protecting the developer from accidentally accessing deprecated data over destroyed or reused entity slots with old refs).
|
309 |
+
asset_ref<AssetType>: rollback-able reference to a data asset instance from the Quantum asset database (please refer to the data assets chapter).
|
310 |
+
list<T>, dictionary<K,T>: dynamic collection references (stored in Quantum's frame heap). Only supports blittable types (primitives + DSL-defined types).
|
311 |
+
array<Type>[size]: fixed sized "arrays" to represent data collections. A normal C# array would be a heap-allocated object reference (it has properties, etc.), which violates Quantum's memory requirements, so the special array type generates a pointer based simple API to keep rollback-able data collections inside the game state;
|
312 |
+
Back To Top
|
313 |
+
|
314 |
+
|
315 |
+
A Note On Assets
|
316 |
+
Assets are a special feature of Quantum that let the developer define data-driven containers (normal classes, with inheritance, polymorphic methods, etc.) that end up as immutable instances inside an indexed database. The "asset" keyword is used to assign an (existing) class as a data asset that can have references assigned inside the game state (please refer to the Data Assets chapter to learn more about features and restrictions):
|
317 |
+
|
318 |
+
asset CharacterData; // the CharacterData class is partially defined in a normal C# file by the developer
|
319 |
+
The following struct show some valid examples of the types above (sometimes referencing previously defined types):
|
320 |
+
|
321 |
+
struct SpecialData
|
322 |
+
{
|
323 |
+
player_ref Player;
|
324 |
+
entity_ref Character;
|
325 |
+
entity_ref AnotherEntity;
|
326 |
+
asset_ref<CharacterData> CharacterData;
|
327 |
+
array<FP>[10] TenNumbers;
|
328 |
+
}
|
329 |
+
Back To Top
|
330 |
+
|
331 |
+
|
332 |
+
Available Types
|
333 |
+
When working in the DSL, you can use a variety of types. Some are pre-imported by the parsers, while others need to be manually imported.
|
334 |
+
|
335 |
+
|
336 |
+
By Default
|
337 |
+
Quantum's DSL parser has a list of pre-imported cross-platform deterministic types that can be used in the game state definition:
|
338 |
+
|
339 |
+
Boolean / bool - internally gets wrapped in QBoolean which works identically (get/set, compare, etc...)
|
340 |
+
Byte
|
341 |
+
SByte
|
342 |
+
UInt16 / Int16
|
343 |
+
UInt32 / Int32
|
344 |
+
UInt64 / Int64
|
345 |
+
FP
|
346 |
+
FPVector2
|
347 |
+
FPVector3
|
348 |
+
FPMatrix
|
349 |
+
FPQuaternion
|
350 |
+
PlayerRef / player_ref in the DSL
|
351 |
+
EntityRef / entity_ref in the DSL
|
352 |
+
LayerMask
|
353 |
+
NullableFP / FP? in the DSL
|
354 |
+
NullableFPVector2 / FPVector2? in the DSL
|
355 |
+
NullableFPVector3 / FPVector3? in the DSL
|
356 |
+
QString is for UTF-16 (aka Unicode in .NET)
|
357 |
+
QStringUtf8 is always UTF-8
|
358 |
+
Hit
|
359 |
+
Hit3D
|
360 |
+
Shape2D
|
361 |
+
Shape3D
|
362 |
+
Joint, DistanceJoint, SpringJoint and HingeJoint
|
363 |
+
Note on QStrings: N represents the total size of the string in bytes minus 2 bytes used for bookkeeping. In other words QString<64> will use 64 bytes for a string with a max byte length of 62 bytes, i.e. up to 31 UTF-16 characters.
|
364 |
+
|
365 |
+
Back To Top
|
366 |
+
|
367 |
+
|
368 |
+
Manual Import
|
369 |
+
If you need a type that is not listed in the previous section, you will have to import it manually when using it in QTN files.
|
370 |
+
|
371 |
+
|
372 |
+
Namespaces / Types Outside Of Quantum
|
373 |
+
To import types defined in other namespaces, you can use the following syntax:
|
374 |
+
|
375 |
+
import MyInterface;
|
376 |
+
or
|
377 |
+
import MyNameSpace.Utils;
|
378 |
+
For an enum the syntax is as follows:
|
379 |
+
|
380 |
+
import enum MyEnum(underlying_type);
|
381 |
+
|
382 |
+
// This syntax is identical for Quantum specific enums
|
383 |
+
import enum Shape3DType(byte);
|
384 |
+
Back To Top
|
385 |
+
|
386 |
+
|
387 |
+
Built-In Quantum Type And Custom Type
|
388 |
+
When importing a Quantum built-in type or a custom type, the struct size is predefined in their C# declaration. It is therefore important to add some safety measures.
|
389 |
+
|
390 |
+
namespace Quantum {
|
391 |
+
[StructLayout(LayoutKind.Explicit)]
|
392 |
+
public struct Foo {
|
393 |
+
public const int SIZE = sizeof(Int32) * 2;
|
394 |
+
[FieldOffset(0)]
|
395 |
+
public Int32 A;
|
396 |
+
[FieldOffset(sizeof(Int32))]
|
397 |
+
public Int32 B;
|
398 |
+
}
|
399 |
+
}
|
400 |
+
#define FOO_SIZE 8 // Define a constant value with the known size of the struct
|
401 |
+
import struct Foo(8);
|
402 |
+
To ensure the expected size of the struct is equal to the actual size, it is recommended to add an Assert as shown below in one of your systems.
|
403 |
+
|
404 |
+
public unsafe class MyStructSizeCheckingSystem : SystemMainThread{
|
405 |
+
public override void OnInit(Frame f)
|
406 |
+
{
|
407 |
+
Assert.Check(Constants.FOO_SIZE == Foo.SIZE);
|
408 |
+
}
|
409 |
+
}
|
410 |
+
If the size of the built-in struct changes during an upgrade, this Assert will throw and allow you to update the values in the DSL.
|
411 |
+
|
412 |
+
Back To Top
|
413 |
+
|
414 |
+
|
415 |
+
Attributes
|
416 |
+
Quantum supports several attributes to present parameters in the Inspector.
|
417 |
+
|
418 |
+
The attributes are contained within the Quantum.Inspector namespace.
|
419 |
+
|
420 |
+
Attribute Parameters Description
|
421 |
+
DrawIf string fieldName
|
422 |
+
long value
|
423 |
+
CompareOperator compare
|
424 |
+
HideType hide Displays the property only if the condition evaluates to true.
|
425 |
+
|
426 |
+
fieldName = the name of the property to evaluate.
|
427 |
+
value = the value used for comparison.
|
428 |
+
compare = the comparison operation to be performed Equal, NotEqual, Less, LessOrEqual, GreaterOrEqual or Greater.
|
429 |
+
hide = the field's behavior when the expression evaluates to False:Hide or ReadOnly.
|
430 |
+
|
431 |
+
For more information on compare and hide, see below.
|
432 |
+
Header string header Adds a header above the property.
|
433 |
+
|
434 |
+
header = the header text to display.
|
435 |
+
HideInInspector - Serializes the field and hides the following property in the Unity inspector.
|
436 |
+
Layer - Can only be applied to type int.
|
437 |
+
Will call EditorGUI.LayerField on the field.
|
438 |
+
Optional string enabledPropertyPath Allows to turn the display of a property on/off.
|
439 |
+
|
440 |
+
enabledPropertyPath = the path to the bool used to evaluate the toggle.
|
441 |
+
Space - Adds a space above the property
|
442 |
+
Tooltip string tooltip Displays a tool tip when hovering over the property.
|
443 |
+
|
444 |
+
tooltip = the tip to display.
|
445 |
+
ArrayLength (since 2.1)
|
446 |
+
FixedArray (in 2.0)
|
447 |
+
ONLY FOR CSharp int length
|
448 |
+
--------
|
449 |
+
int minLength
|
450 |
+
int maxLength Using length allows to define the size of a an array.
|
451 |
+
------
|
452 |
+
Using minLength and maxLength allows to define a range for the size in the Inspector.
|
453 |
+
The final size can then be set in the Inspector.
|
454 |
+
(minLength and maxLength are inclusive)
|
455 |
+
ExcludeFromPrototype - Can be applied to both a component and component fields.
|
456 |
+
------
|
457 |
+
- Field: Excludes field from a the prototype generated for the component.
|
458 |
+
- Component: No prototype will be generated for this component.
|
459 |
+
PreserveInPrototype - Added to a type marks it as usable in prototypes and prevents prototype class from being emit.
|
460 |
+
Added to a field only affects a specific field. Useful for simple [Serializable] structs as it avoids having to use _Prototype types on Unity side.
|
461 |
+
AllocateOnComponentAdded - Can be applied to dynamic collections.
|
462 |
+
This will allocate memory for the collection if it has not already been allocated when the component holding the collection is added to an entity.
|
463 |
+
FreeOnComponentRemoved - Can be applied to dynamic collections and Ptrs.
|
464 |
+
This will deallocate the associated memory and nullify the Ptr held in the field when the component is removed.
|
465 |
+
------
|
466 |
+
IMPORTANT: Do NOT use this attribute in combination with cross-referenced collections as it only nullifies the Ptr held in that particular field and the others will be pointing to invalid memory.
|
467 |
+
The *Attributes* can be used in both C# and qtn files unless otherwise specified; however, there are some syntactic differences.
|
468 |
+
Back To Top
|
469 |
+
|
470 |
+
|
471 |
+
Use In CSharp
|
472 |
+
In C# files, attributes can be used and concatenated like any other attribute.
|
473 |
+
|
474 |
+
// Multiple single attributes
|
475 |
+
[Header("Example Array")][Tooltip("min = 1\nmax = 20")] public FP[] TestArray = new FP[20];
|
476 |
+
|
477 |
+
// Multiple concatenated attributes
|
478 |
+
[Header("Example Array"), Tooltip("min = 1\nmax = 20")] public FP[] TestArray = new FP[20];
|
479 |
+
Back To Top
|
480 |
+
|
481 |
+
|
482 |
+
Use In Qtn
|
483 |
+
In qtn files, the usage of single attributes remains the same as in C#.
|
484 |
+
|
485 |
+
[Header("Example Array")] array<FP>[20] TestArray;
|
486 |
+
When combining multiple attributes, they have to be concatenated.
|
487 |
+
|
488 |
+
[Header("Example Array"), Tooltip("min = 1\nmax = 20")] array<FP>[20] TestArray;
|
489 |
+
Back To Top
|
490 |
+
|
491 |
+
|
492 |
+
Compiler Options
|
493 |
+
The following compiler options are currently available to be used inside Quantum's DSL files (more will be added in the future):
|
494 |
+
|
495 |
+
// pre defining max number of players (default is 6, absolute max is 64)
|
496 |
+
#pragma max_players 16
|
497 |
+
|
498 |
+
// numeric constants (useable inside the DSL by MY_NUMBER and useable in code by Constants.MY_NUMBER)
|
499 |
+
#define MY_NUMBER 10
|
500 |
+
|
501 |
+
// overriding the base class name for the generated constants (default is "Constants")
|
502 |
+
#pragma constants_class_name MyFancyConstants
|
data/DeadPieceSlot.cs
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System.Collections;
|
2 |
+
using System.Collections.Generic;
|
3 |
+
using UnityEngine;
|
4 |
+
|
5 |
+
public class DeadPieceSlot : MonoBehaviour {
|
6 |
+
|
7 |
+
public PieceView Piece;
|
8 |
+
}
|
data/DebugAction.cs
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
[System.Serializable]
|
4 |
+
public unsafe class DebugAction : AIAction
|
5 |
+
{
|
6 |
+
public string Message;
|
7 |
+
|
8 |
+
public override void Update(Frame frame, EntityRef entity)
|
9 |
+
{
|
10 |
+
Log.Info(Message);
|
11 |
+
}
|
12 |
+
}
|
13 |
+
}
|
data/DebugLeaf.cs
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
|
3 |
+
namespace Quantum
|
4 |
+
{
|
5 |
+
[Serializable]
|
6 |
+
public unsafe partial class DebugLeaf : BTLeaf
|
7 |
+
{
|
8 |
+
|
9 |
+
public string Message;
|
10 |
+
|
11 |
+
/// <summary>
|
12 |
+
/// When Update is called, we just write a message on the console.
|
13 |
+
/// This Leaf never fails, nor takes more than one frame to finish,
|
14 |
+
/// so we always return Success.
|
15 |
+
/// </summary>
|
16 |
+
protected override BTStatus OnUpdate(BTParams btParams)
|
17 |
+
{
|
18 |
+
Log.Info(Message + " | Frame: " + btParams.Frame.Number);
|
19 |
+
|
20 |
+
return BTStatus.Success;
|
21 |
+
}
|
22 |
+
}
|
23 |
+
}
|
data/DebugService.cs
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
|
3 |
+
namespace Quantum
|
4 |
+
{
|
5 |
+
[Serializable]
|
6 |
+
public unsafe partial class DebugService : BTService
|
7 |
+
{
|
8 |
+
public string Message;
|
9 |
+
protected unsafe override void OnUpdate(BTParams btParams)
|
10 |
+
{
|
11 |
+
Log.Info($"[BT SERVICE] { Message } | Frame: {btParams.Frame.Number}");
|
12 |
+
}
|
13 |
+
}
|
14 |
+
}
|
data/EffectArea.cs
ADDED
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
using Photon.Deterministic;
|
4 |
+
|
5 |
+
public unsafe partial struct EffectArea
|
6 |
+
{
|
7 |
+
public void Update(Frame frame, EntityRef entity)
|
8 |
+
{
|
9 |
+
StateTime -= frame.DeltaTime;
|
10 |
+
|
11 |
+
if (State == EEffectAreaState.Init)
|
12 |
+
{
|
13 |
+
if (StateTime <= FP._0)
|
14 |
+
{
|
15 |
+
State = EEffectAreaState.Active;
|
16 |
+
TickCount = System.Math.Max((byte)1, TickCount);
|
17 |
+
|
18 |
+
var behaviors = frame.ResolveList(Behaviors);
|
19 |
+
|
20 |
+
for (int idx = 0, count = behaviors.Count; idx < count; idx++)
|
21 |
+
{
|
22 |
+
behaviors.GetPointer(idx)->Initialize(Level);
|
23 |
+
}
|
24 |
+
}
|
25 |
+
}
|
26 |
+
|
27 |
+
if (State == EEffectAreaState.Active)
|
28 |
+
{
|
29 |
+
if (StateTime <= FP._0)
|
30 |
+
{
|
31 |
+
TickCount -= 1;
|
32 |
+
ProcessEffect(frame, entity);
|
33 |
+
|
34 |
+
StateTime = TickTime;
|
35 |
+
}
|
36 |
+
|
37 |
+
if (TickCount == 0)
|
38 |
+
{
|
39 |
+
State = EEffectAreaState.Finished;
|
40 |
+
StateTime = FP._0_50;
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
if (State == EEffectAreaState.Finished)
|
45 |
+
{
|
46 |
+
if (StateTime <= FP._0)
|
47 |
+
{
|
48 |
+
frame.Destroy(entity);
|
49 |
+
}
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
private void ProcessEffect(Frame frame, EntityRef entity)
|
54 |
+
{
|
55 |
+
var position = frame.Unsafe.GetPointer<Transform2D>(entity)->Position;
|
56 |
+
var behaviors = frame.ResolveList(Behaviors);
|
57 |
+
|
58 |
+
foreach (var targetPair in frame.Unsafe.GetComponentBlockIterator<Target>())
|
59 |
+
{
|
60 |
+
if (TargetType == EEffectAreaTarget.Enemy && targetPair.Component->OwnerPlayerRef == Owner)
|
61 |
+
continue;
|
62 |
+
if (TargetType == EEffectAreaTarget.Friendly && targetPair.Component->OwnerPlayerRef != Owner)
|
63 |
+
continue;
|
64 |
+
|
65 |
+
var targetPosition = frame.Unsafe.GetPointer<Transform2D>(targetPair.Entity)->Position;
|
66 |
+
var distance = (targetPosition - position).SqrMagnitude;
|
67 |
+
|
68 |
+
var radiusSqr = Radius + targetPair.Component->Size;
|
69 |
+
radiusSqr *= radiusSqr;
|
70 |
+
|
71 |
+
if (distance > radiusSqr)
|
72 |
+
continue;
|
73 |
+
|
74 |
+
for (int idx = 0, count = behaviors.Count; idx < count; idx++)
|
75 |
+
{
|
76 |
+
behaviors.GetPointer(idx)->ProcessEffect(frame, entity, targetPair.Entity, Level);
|
77 |
+
}
|
78 |
+
}
|
79 |
+
}
|
80 |
+
}
|
81 |
+
}
|
data/EffectArea.qtn
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
component EffectArea
|
2 |
+
{
|
3 |
+
[ExcludeFromPrototype] list<EffectAreaBehavior> Behaviors;
|
4 |
+
[ExcludeFromPrototype] PlayerRef Owner;
|
5 |
+
[ExcludeFromPrototype] FP Radius;
|
6 |
+
[ExcludeFromPrototype] FP StateTime;
|
7 |
+
[ExcludeFromPrototype] EEffectAreaState State;
|
8 |
+
[ExcludeFromPrototype] FP TickTime;
|
9 |
+
[ExcludeFromPrototype] byte TickCount;
|
10 |
+
[ExcludeFromPrototype] byte Level;
|
11 |
+
[ExcludeFromPrototype] EEffectAreaTarget TargetType;
|
12 |
+
}
|
13 |
+
|
14 |
+
enum EEffectAreaState : Byte
|
15 |
+
{
|
16 |
+
Init,
|
17 |
+
Active,
|
18 |
+
Finished,
|
19 |
+
}
|
20 |
+
|
21 |
+
enum EEffectAreaTarget : Byte
|
22 |
+
{
|
23 |
+
Enemy,
|
24 |
+
Friendly,
|
25 |
+
}
|
26 |
+
|
27 |
+
union EffectAreaBehavior
|
28 |
+
{
|
29 |
+
EffectAreaBehavior_Damage Damage;
|
30 |
+
EffectAreaBehavior_Buff Buff;
|
31 |
+
}
|
32 |
+
|
33 |
+
struct EffectAreaBehavior_Damage
|
34 |
+
{
|
35 |
+
FP Damage;
|
36 |
+
FP DamagePerLevelPercent;
|
37 |
+
}
|
38 |
+
|
39 |
+
struct EffectAreaBehavior_Buff
|
40 |
+
{
|
41 |
+
AssetRefEntityPrototype Buff;
|
42 |
+
}
|
data/EffectAreaBehavior.cs
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
public unsafe partial struct EffectAreaBehavior
|
4 |
+
{
|
5 |
+
public void Initialize(byte level)
|
6 |
+
{
|
7 |
+
switch (Field)
|
8 |
+
{
|
9 |
+
case DAMAGE: _Damage.Initialize(level); break;
|
10 |
+
|
11 |
+
case BUFF: break;
|
12 |
+
|
13 |
+
default:
|
14 |
+
throw new System.NotImplementedException();
|
15 |
+
}
|
16 |
+
}
|
17 |
+
|
18 |
+
public void ProcessEffect(Frame frame, EntityRef entity, EntityRef target, byte level)
|
19 |
+
{
|
20 |
+
switch (Field)
|
21 |
+
{
|
22 |
+
case DAMAGE: _Damage.ProcessEffect(frame, entity, target); break;
|
23 |
+
case BUFF: _Buff.ProcessEffect(frame, entity, target, level); break;
|
24 |
+
|
25 |
+
default:
|
26 |
+
throw new System.NotImplementedException();
|
27 |
+
}
|
28 |
+
}
|
29 |
+
}
|
30 |
+
}
|
data/EffectAreaBehavior_Buff.cs
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
public unsafe partial struct EffectAreaBehavior_Buff
|
4 |
+
{
|
5 |
+
// PUBLIC METHODS
|
6 |
+
|
7 |
+
public void ProcessEffect(Frame frame, EntityRef entity, EntityRef target, byte level)
|
8 |
+
{
|
9 |
+
if (frame.Unsafe.TryGetPointer<Buffs>(target, out var buffs) == false)
|
10 |
+
return;
|
11 |
+
|
12 |
+
|
13 |
+
buffs->AddBuff(frame, entity, target, Buff, level);
|
14 |
+
}
|
15 |
+
}
|
16 |
+
}
|
data/EffectAreaBehavior_Damage.cs
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
using Photon.Deterministic;
|
4 |
+
|
5 |
+
public unsafe partial struct EffectAreaBehavior_Damage
|
6 |
+
{
|
7 |
+
public void Initialize(byte level)
|
8 |
+
{
|
9 |
+
var perLevel = FP._1 + DamagePerLevelPercent * FP._0_01;
|
10 |
+
|
11 |
+
for (int idx = 1; idx < level; idx++)
|
12 |
+
{
|
13 |
+
Damage *= perLevel;
|
14 |
+
}
|
15 |
+
}
|
16 |
+
|
17 |
+
public void ProcessEffect(Frame frame, EntityRef entity, EntityRef target)
|
18 |
+
{
|
19 |
+
var position = frame.Unsafe.GetPointer<Transform2D>(entity)->Position;
|
20 |
+
var healthData = new HealthData()
|
21 |
+
{
|
22 |
+
Action = EHealthAction.Remove,
|
23 |
+
Value = Damage,
|
24 |
+
Target = target,
|
25 |
+
};
|
26 |
+
|
27 |
+
var targetHealth = frame.Unsafe.GetPointer<Health>(target);
|
28 |
+
targetHealth->ApplyHealthData(frame, healthData);
|
29 |
+
}
|
30 |
+
}
|
31 |
+
}
|
data/EffectAreaSettings.cs
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
using Quantum.Prototypes;
|
4 |
+
using Quantum.Inspector;
|
5 |
+
using Photon.Deterministic;
|
6 |
+
|
7 |
+
[System.Serializable]
|
8 |
+
public class EffectAreaSettings : CardSettings
|
9 |
+
{
|
10 |
+
[Header("Effect Area")]
|
11 |
+
public FP TickTime;
|
12 |
+
public byte TickCount;
|
13 |
+
public FP Radius;
|
14 |
+
public EEffectAreaTarget Target;
|
15 |
+
[Space]
|
16 |
+
public EffectAreaBehavior_Prototype[] Behaviors;
|
17 |
+
}
|
18 |
+
}
|
data/EffectAreaSystem.cs
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
unsafe class EffectAreaSystem : SystemMainThread
|
4 |
+
{
|
5 |
+
public override void Update(Frame frame)
|
6 |
+
{
|
7 |
+
foreach (var pair in frame.Unsafe.GetComponentBlockIterator<EffectArea>())
|
8 |
+
{
|
9 |
+
pair.Component->Update(frame, pair.Entity);
|
10 |
+
}
|
11 |
+
}
|
12 |
+
}
|
13 |
+
}
|
data/Fixed Point.txt
ADDED
@@ -0,0 +1,256 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Introduction
|
2 |
+
In Quantum the FP struct (Fixed Point) completely replaces all usages of floats and doubles to ensure cross-platform determinism. It offers versions of common math data structures like FPVector2, FPVector3, FPMatrix, FPQuaternion, RNGSession, FPBounds2, etc. All systems in Quantum, including physics and navigation, exclusively use FP values in their computations.
|
3 |
+
|
4 |
+
The fixed-point type implemented in Quantum is Q48.16. It has proved to a good balance between precision and performance with a bias towards the latter.
|
5 |
+
|
6 |
+
Internally FP uses one long to represent the combined fixed-point number (whole number + decimal part); the long value can be accessed and set via FP.RawValue.
|
7 |
+
|
8 |
+
Quantum's FP Math uses carefully tuned look up tables for fast trigonometric and square root functions (see QuantumSDK\quantum_unity\Assets\Photon\Quantum\Resources\LUT).
|
9 |
+
|
10 |
+
Back To Top
|
11 |
+
|
12 |
+
|
13 |
+
Parsing FPs
|
14 |
+
The representable FP fraction is limited and never as accurate as a double. Parsing is an approximation and will round to the nearest possible FP precision. This is reflected in:
|
15 |
+
|
16 |
+
parsing an FP as the float 1.1f and then converting back to float possibly resulting in 1.09999999f; and,
|
17 |
+
different parsing methods yielding different results on the same machine.
|
18 |
+
FP.FromFloat(1.1f).RawValue != FP.FromString("1.1").RawValue
|
19 |
+
Back To Top
|
20 |
+
|
21 |
+
|
22 |
+
TLDR
|
23 |
+
Use from float only during edit time, never inside the simulation or at runtime.
|
24 |
+
It is best to convert from raw whenever possible.
|
25 |
+
Back To Top
|
26 |
+
|
27 |
+
|
28 |
+
FP.FromFloat_UNSAFE()
|
29 |
+
Converting from float is not deterministic due to rounding errors and should never be done inside the simulation. Doing such a conversion in the simulation will cause desyncs 100% of the time.
|
30 |
+
|
31 |
+
However, it can be used during edit or build time, when the converted (FP) data is first created and then shared with everyone. IMPORTANT: Data generated this way on different machines may not be compatible.
|
32 |
+
|
33 |
+
var v = FP.FromFloat_UNSAFE(1.1f);
|
34 |
+
Back To Top
|
35 |
+
|
36 |
+
|
37 |
+
FP.FromString_UNSAFE()
|
38 |
+
This will internally parse the string as a float and then convert to FP. All caveats from FromFloat_UNSAFE() apply here as well.
|
39 |
+
|
40 |
+
var v = FP.FromFloat_UNSAFE("1.1");
|
41 |
+
Back To Top
|
42 |
+
|
43 |
+
|
44 |
+
FP.FromString()
|
45 |
+
This is deterministic and therefore safe to use anywhere but may not be the most performant option. A typical use case is balancing information (patch) that clients load from a server and then use to update data in Quantum assets.
|
46 |
+
|
47 |
+
Be aware of the string locale! It only parses English number formatting for decimals and requires a dot (e.g. 1000.01f).
|
48 |
+
|
49 |
+
var v = FP.FromFloat("1.1");
|
50 |
+
Back To Top
|
51 |
+
|
52 |
+
|
53 |
+
FP.FromRaw()
|
54 |
+
This is secure and fast as it mimics the internal representation.
|
55 |
+
|
56 |
+
var v = FP.FromRaw(72089);
|
57 |
+
This snippet can be used to create a FP converter window in Unity for convient conversion.
|
58 |
+
|
59 |
+
using System;
|
60 |
+
using UnityEditor;
|
61 |
+
using Photon.Deterministic;
|
62 |
+
|
63 |
+
public class FPConverter : EditorWindow {
|
64 |
+
private float _f;
|
65 |
+
private FP _fp;
|
66 |
+
|
67 |
+
[MenuItem("Quantum/FP Converter")]
|
68 |
+
public static void ShowWindow() {
|
69 |
+
GetWindow(typeof(FPConverter), false, "FP Converter");
|
70 |
+
}
|
71 |
+
|
72 |
+
public virtual void OnGUI() {
|
73 |
+
_f = EditorGUILayout.FloatField("Input", _f);
|
74 |
+
try {
|
75 |
+
_fp = FP.FromFloat_UNSAFE(_f);
|
76 |
+
var f = FPPropertyDrawer.GetRawAsFloat(_fp.RawValue);
|
77 |
+
var rect = EditorGUILayout.GetControlRect(true);
|
78 |
+
EditorGUI.FloatField(rect, "Output FP", f);
|
79 |
+
QuantumEditorGUI.Overlay(rect, "(FP)");
|
80 |
+
EditorGUILayout.LongField("Output Raw", _fp.RawValue);
|
81 |
+
}
|
82 |
+
catch (OverflowException e) {
|
83 |
+
EditorGUILayout.LabelField("Out of range");
|
84 |
+
}
|
85 |
+
}
|
86 |
+
}
|
87 |
+
Back To Top
|
88 |
+
|
89 |
+
|
90 |
+
Const Variables
|
91 |
+
The `FP._1_10` syntax can not be extended or generated.
|
92 |
+
FP is a struct and can therefore not be used as a constant. It is, however, possible to hard-code and use "FP" values in const variables:
|
93 |
+
|
94 |
+
Combine pre-defined FP._1 static getters or FP.Raw._1 const variables.
|
95 |
+
FP foo = FP._1 + FP._0_10;
|
96 |
+
// or
|
97 |
+
foo.RawValue = FP.Raw._1 + FP.Raw._0_10;
|
98 |
+
const long MagicNumber = FP.Raw._1 + FP.Raw._0_10;
|
99 |
+
|
100 |
+
FP foo = default;
|
101 |
+
foo.RawValue = MagicNumber;
|
102 |
+
// or
|
103 |
+
foo = FP.FromRaw(MagicNumber);
|
104 |
+
Convert the specific float once to FP and save the raw value as a constant
|
105 |
+
const long MagicNumber = 72089; // 1.1
|
106 |
+
|
107 |
+
var foo = FP.FromRaw(MagicNumber);
|
108 |
+
// or
|
109 |
+
foo.RawValue = MagicNumber;
|
110 |
+
Create the constant inside the Quantum DSL
|
111 |
+
#define FPConst 1.1
|
112 |
+
Then use like this:
|
113 |
+
|
114 |
+
var foo = default(FP);
|
115 |
+
foo += Constants.FPConst;
|
116 |
+
// or
|
117 |
+
foo.RawValue += Constants.Raw.FPConst;
|
118 |
+
It will generate code to represent the constant in the following way:
|
119 |
+
|
120 |
+
public static unsafe partial class Constants {
|
121 |
+
public const Int32 PLAYER_COUNT = 8;
|
122 |
+
/// <summary>1.100006</summary>
|
123 |
+
|
124 |
+
public static FP FPConst {
|
125 |
+
[MethodImpl(MethodImplOptions.AggressiveInlining)] get {
|
126 |
+
FP result;
|
127 |
+
result.RawValue = 72090;
|
128 |
+
return result;
|
129 |
+
}
|
130 |
+
}
|
131 |
+
public static unsafe partial class Raw {
|
132 |
+
/// <summary>1.100006</summary>
|
133 |
+
public const Int64 FPConst = 72090;
|
134 |
+
}
|
135 |
+
}
|
136 |
+
Define readonly static variables in the class.
|
137 |
+
private readonly static FP MagicNumber = FP._1 + FP._0_10;
|
138 |
+
There is a performance penalty compared to const variables and don't forget to mark readonly because randomly changing the value during runtime could lead to desyncs.
|
139 |
+
|
140 |
+
Back To Top
|
141 |
+
|
142 |
+
|
143 |
+
Casting
|
144 |
+
Implicit casting to FP from int, uint, short, ushort, byte, sbyte is allowed and safe.
|
145 |
+
|
146 |
+
FP v = (FP)1;
|
147 |
+
FP v = 1;
|
148 |
+
Explicit casting from FP to float or double is possible, but obviously should not be used inside the simulation.
|
149 |
+
|
150 |
+
var v = (double)FP._1;
|
151 |
+
var v = (float)FP._1;
|
152 |
+
Casting to integer and back is safe though.
|
153 |
+
|
154 |
+
FP v = (FP)(int)FP._1;
|
155 |
+
Unsafe casts are marked as [obsolete] and will cause a InvalidOperationException.
|
156 |
+
|
157 |
+
FP v = 1.1f; // ERROR
|
158 |
+
FP v = 1.1d; // ERROR
|
159 |
+
Back To Top
|
160 |
+
|
161 |
+
|
162 |
+
Inlining
|
163 |
+
All low-level Quantum systems use manual inlined FP arithmetic to extract every ounce of performance possible. Fixed point math uses integer division and multiplication. To achieve this, the result or dividend are bit-shifted by the FP-Precision (16) before or after the calculation.
|
164 |
+
|
165 |
+
var v = parameter * FP._0_01;
|
166 |
+
|
167 |
+
// inlined integer math
|
168 |
+
FP v = default;
|
169 |
+
v.RawValue = (parameter.RawValue * FP._0_01.RawValue) >> FPLut.PRECISION;
|
170 |
+
var v = parameter / FP._0_01;
|
171 |
+
|
172 |
+
// inlined integer math
|
173 |
+
FP v = default;
|
174 |
+
v.RawValue = (parameter.RawValue << FPLut.PRECISION) / FP._0_01.RawValue;
|
175 |
+
Back To Top
|
176 |
+
|
177 |
+
|
178 |
+
Overflow
|
179 |
+
FP.UseableMax represents the highest FP number that can be multiplied with itself and not cause an overflow (exceeding long range).
|
180 |
+
|
181 |
+
FP.UseableMax
|
182 |
+
Decimal: 32767.9999847412
|
183 |
+
Raw: 2147483647
|
184 |
+
Binary: 1111111111111111111111111111111 = 31 bit
|
185 |
+
FP.UseableMin
|
186 |
+
Decimal: -32768
|
187 |
+
Raw: -2147483648
|
188 |
+
Binary: 10000000000000000000000000000000 = 32 bit
|
189 |
+
Back To Top
|
190 |
+
|
191 |
+
|
192 |
+
Precision
|
193 |
+
The general FP precision is decent when the numbers are kept within a certain range (0.01..1000). FP-math related precision problems usually produce inaccurate results and tend to make systems (based on math) unstable. A very common case is to multiply very high or small numbers and than returning to the original range by division for example. The resulting numbers lose precision.
|
194 |
+
|
195 |
+
Another example is this method excerpt from ClosestDistanceToTriangle. Where t0 is calculated from multiplying two dot products with each other, where a dot-product is already also a result of multiplications. This is a problem when very accurate results are expected. A way to mitigate this issue is shifting the values artificially before the calculation then shift the result back. This will work when the ranges of the input are somewhat known.
|
196 |
+
|
197 |
+
var diff = p - v0;
|
198 |
+
var edge0 = v1 - v0;
|
199 |
+
var edge1 = v2 - v0;
|
200 |
+
var a00 = Dot(edge0, edge0);
|
201 |
+
var a01 = Dot(edge0, edge1);
|
202 |
+
var a11 = Dot(edge1, edge1);
|
203 |
+
var b0 = -Dot(diff, edge0);
|
204 |
+
var b1 = -Dot(diff, edge1);
|
205 |
+
var t0 = a01 * b1 - a11 * b0;
|
206 |
+
var t1 = a01 * b0 - a00 * b1;
|
207 |
+
// ...
|
208 |
+
closestPoint = v0 + t0 * edge0 + t1 * edge1;
|
209 |
+
Back To Top
|
210 |
+
|
211 |
+
|
212 |
+
FPAnimationCurves
|
213 |
+
Unity comes with a set of tools which are useful to express some values in the form of curves. It comes with a custom editor for such curves, which are then serialised and can be used in runtime in order to evaluate the value of the curve in some specific point.
|
214 |
+
|
215 |
+
There are many situations where curves can be used, such as expressing steering information when implementing vehicles, the utility value during the decision making for an AI agent (as done in Bot SDK's Utility Theory), getting the multiplier value for some attack's damage, and so on.
|
216 |
+
|
217 |
+
The Quantum SDK already comes with its own implementation of an animation curve, named FPAnimationCurve, evaluated as FPs. This custom type, when inspected directly on Data Assets and Components in Unity, are drawn with Unity's default Animation Curve editors, whose data are then internally baked into the deterministic type.
|
218 |
+
|
219 |
+
Back To Top
|
220 |
+
|
221 |
+
|
222 |
+
Polling Data From An FPAnimationCurve
|
223 |
+
The code needed to poll some data from a curve, with Quantum code, is very similar to the Unity's version:
|
224 |
+
|
225 |
+
// This returns the pre-baked value, interpolated accordingly to the curve's configuration such as it's key points, curve's resolution, tangets modes, etc
|
226 |
+
FP myValue = myCurve.Evaluate(FP._0_50);
|
227 |
+
Back To Top
|
228 |
+
|
229 |
+
|
230 |
+
Creating FPAnimationCurves Directly On The Simulation
|
231 |
+
Here are the snippets to create a deterministic animation curve from scratch, directly on the simulation:
|
232 |
+
|
233 |
+
// Creating a simple, linear curve with five key points
|
234 |
+
// Change the parameter as prefered
|
235 |
+
public static class FPAnimationCurveUtils
|
236 |
+
{
|
237 |
+
public static FPAnimationCurve CreateLinearCurve(FPAnimationCurve.WrapMode preWrapMode, FPAnimationCurve.WrapMode postWrapMode)
|
238 |
+
{
|
239 |
+
return new FPAnimationCurve
|
240 |
+
{
|
241 |
+
Samples = new FP[5] { FP._0, FP._0_25, FP._0_50, FP._0_75, FP._1 },
|
242 |
+
PostWrapMode = (int)postWrapMode,
|
243 |
+
PreWrapMode = (int)preWrapMode,
|
244 |
+
StartTime = 0,
|
245 |
+
EndTime = 1,
|
246 |
+
Resolution = 32
|
247 |
+
};
|
248 |
+
}
|
249 |
+
}
|
250 |
+
// Storing a curve into a local variable
|
251 |
+
var curve = FPAnimationCurveUtils.CreateLinearCurve(FPAnimationCurve.WrapMode.Clamp, FPAnimationCurve.WrapMode.Clamp);
|
252 |
+
|
253 |
+
// It can also be used directly to pre-initialise a curve in an asset
|
254 |
+
public unsafe partial class CollectibleData
|
255 |
+
{
|
256 |
+
public FPAnimationCurve myCurve = FPAnimationCurveUtils.CreateLinearCurv
|
data/Frame.User.cs
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
using System.Collections.Generic;
|
3 |
+
using System.Linq;
|
4 |
+
using System.Text;
|
5 |
+
|
6 |
+
namespace Quantum
|
7 |
+
{
|
8 |
+
unsafe partial class Frame
|
9 |
+
{
|
10 |
+
}
|
11 |
+
}
|
data/FrameContext.User.cs
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
public partial class FrameContextUser
|
4 |
+
{
|
5 |
+
|
6 |
+
}
|
7 |
+
}
|
data/GOAP.User.cs
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
public unsafe partial struct GOAPAgent
|
4 |
+
{
|
5 |
+
public AIConfig GetConfig(Frame frame)
|
6 |
+
{
|
7 |
+
return frame.FindAsset<AIConfig>(Config.Id);
|
8 |
+
}
|
9 |
+
}
|
10 |
+
}
|
data/GOAP.qtn
ADDED
@@ -0,0 +1,39 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#define MAX_PLAN_SIZE 6
|
2 |
+
|
3 |
+
asset GOAPRoot;
|
4 |
+
asset GOAPGoal;
|
5 |
+
asset GOAPAction;
|
6 |
+
asset GOAPBackValidation;
|
7 |
+
|
8 |
+
component GOAPAgent
|
9 |
+
{
|
10 |
+
asset_ref<GOAPRoot> Root;
|
11 |
+
AssetRefAIConfig Config;
|
12 |
+
|
13 |
+
[ExcludeFromPrototype]
|
14 |
+
GOAPState CurrentState;
|
15 |
+
|
16 |
+
[ExcludeFromPrototype]
|
17 |
+
asset_ref<GOAPGoal> CurrentGoal;
|
18 |
+
[ExcludeFromPrototype]
|
19 |
+
GOAPState GoalState;
|
20 |
+
|
21 |
+
[ExcludeFromPrototype]
|
22 |
+
sbyte CurrentActionIndex;
|
23 |
+
[ExcludeFromPrototype]
|
24 |
+
sbyte LastProcessedActionIndex;
|
25 |
+
[ExcludeFromPrototype]
|
26 |
+
byte CurrentPlanSize;
|
27 |
+
[ExcludeFromPrototype]
|
28 |
+
array<asset_ref<GOAPAction>>[MAX_PLAN_SIZE] Plan;
|
29 |
+
|
30 |
+
[ExcludeFromPrototype]
|
31 |
+
FP CurrentActionTime;
|
32 |
+
[ExcludeFromPrototype]
|
33 |
+
FP CurrentGoalTime;
|
34 |
+
[ExcludeFromPrototype]
|
35 |
+
FP InterruptionCheckCooldown;
|
36 |
+
|
37 |
+
[ExcludeFromPrototype]
|
38 |
+
list<FP> GoalDisableTimes;
|
39 |
+
}
|
data/GOAPAStar.cs
ADDED
@@ -0,0 +1,311 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
using System.Collections.Generic;
|
3 |
+
using Photon.Deterministic;
|
4 |
+
|
5 |
+
namespace Quantum
|
6 |
+
{
|
7 |
+
using System.Runtime.InteropServices;
|
8 |
+
|
9 |
+
[StructLayout(LayoutKind.Auto)]
|
10 |
+
public struct GOAPNode
|
11 |
+
{
|
12 |
+
public int Hash;
|
13 |
+
public byte Depth;
|
14 |
+
public int Parent;
|
15 |
+
public sbyte ActionIndex;
|
16 |
+
public GOAPState State;
|
17 |
+
public short F;
|
18 |
+
public short G;
|
19 |
+
|
20 |
+
public string ToString(GOAPAction[] actions)
|
21 |
+
{
|
22 |
+
string action = ActionIndex >= 0 && ActionIndex < actions.Length ? actions[ActionIndex].Path : "NoAction";
|
23 |
+
return $"{action}, real cost (G): {G / 100f}, total heuristic cost (F): {F / 100f}, hash: {Hash}, parent: {Parent}";
|
24 |
+
}
|
25 |
+
}
|
26 |
+
|
27 |
+
public struct StateBackValidation
|
28 |
+
{
|
29 |
+
public GOAPState ValidatedState;
|
30 |
+
public FP CostToNextState;
|
31 |
+
|
32 |
+
public StateBackValidation(GOAPState validatedState, FP costToNextState)
|
33 |
+
{
|
34 |
+
ValidatedState = validatedState;
|
35 |
+
CostToNextState = costToNextState;
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
public unsafe class GOAPAStar
|
40 |
+
{
|
41 |
+
public delegate int HeuristicCost(GOAPState fromState, GOAPState toState);
|
42 |
+
|
43 |
+
// PUBLIC MEMBERS
|
44 |
+
|
45 |
+
public StatisticsData Statistics;
|
46 |
+
|
47 |
+
// PRIVATE MEMBERS
|
48 |
+
|
49 |
+
private readonly Dictionary<int, GOAPNode> _active = new Dictionary<int, GOAPNode>();
|
50 |
+
private readonly Dictionary<int, GOAPNode> _closed = new Dictionary<int, GOAPNode>();
|
51 |
+
|
52 |
+
private readonly GOAPHeap _open = new GOAPHeap();
|
53 |
+
|
54 |
+
private ActionData[] _actionData;
|
55 |
+
private List<GOAPAction> _plan = new List<GOAPAction>(16);
|
56 |
+
|
57 |
+
private List<StateBackValidation> _planStateValidations = new List<StateBackValidation>(8);
|
58 |
+
|
59 |
+
// PUBLIC METHODS
|
60 |
+
|
61 |
+
public List<GOAPAction> Run(Frame frame, GOAPEntityContext context, GOAPState start, GOAPState end, GOAPGoal goal,
|
62 |
+
GOAPAction[] availableActions, HeuristicCost heuristic, int maxPlanSize)
|
63 |
+
{
|
64 |
+
Statistics = default;
|
65 |
+
|
66 |
+
int foundPathEndHash = BackwardAStar(frame, context, start, end, goal, availableActions, heuristic, maxPlanSize);
|
67 |
+
|
68 |
+
Statistics.Success = foundPathEndHash != 0;
|
69 |
+
Statistics.ClosedNodes = _closed.Count;
|
70 |
+
Statistics.OpenNodes = _open.Size;
|
71 |
+
Statistics.ActiveNodes = _active.Count;
|
72 |
+
|
73 |
+
if (foundPathEndHash == 0)
|
74 |
+
return null;
|
75 |
+
|
76 |
+
_plan.Clear();
|
77 |
+
|
78 |
+
int nodeHash = foundPathEndHash;
|
79 |
+
while (nodeHash != 0)
|
80 |
+
{
|
81 |
+
if (_closed.TryGetValue(nodeHash, out GOAPNode node))
|
82 |
+
{
|
83 |
+
if (node.ActionIndex >= 0)
|
84 |
+
{
|
85 |
+
_plan.Add(availableActions[node.ActionIndex]);
|
86 |
+
}
|
87 |
+
|
88 |
+
nodeHash = node.Parent;
|
89 |
+
}
|
90 |
+
}
|
91 |
+
|
92 |
+
return _plan;
|
93 |
+
}
|
94 |
+
|
95 |
+
// PRIVATE METHODS
|
96 |
+
|
97 |
+
private int BackwardAStar(Frame frame, GOAPEntityContext context, GOAPState start, GOAPState end, GOAPGoal goal,
|
98 |
+
GOAPAction[] availableActions, HeuristicCost heuristic, int maxPlanSize)
|
99 |
+
{
|
100 |
+
_open.Clear();
|
101 |
+
_closed.Clear();
|
102 |
+
_active.Clear();
|
103 |
+
|
104 |
+
PrepareActionData(ref _actionData, availableActions.Length);
|
105 |
+
|
106 |
+
GOAPNode startNode = new GOAPNode
|
107 |
+
{
|
108 |
+
Hash = end.GetHashCode(),
|
109 |
+
State = end,
|
110 |
+
F = 0,
|
111 |
+
G = 0,
|
112 |
+
Depth = 0,
|
113 |
+
ActionIndex = (sbyte)-1,
|
114 |
+
};
|
115 |
+
|
116 |
+
_open.Push(startNode);
|
117 |
+
_active.Add(startNode.Hash, startNode);
|
118 |
+
|
119 |
+
while (_open.Size > 0)
|
120 |
+
{
|
121 |
+
GOAPNode currentNode = _open.Pop();
|
122 |
+
_closed.Add(currentNode.Hash, currentNode);
|
123 |
+
|
124 |
+
//Log.Warn($"Closing node {currentNode.ToString()}");
|
125 |
+
|
126 |
+
if (start.Contains(currentNode.State) == true)
|
127 |
+
return currentNode.Hash;
|
128 |
+
|
129 |
+
if (currentNode.Depth >= maxPlanSize)
|
130 |
+
continue;
|
131 |
+
|
132 |
+
for (int i = availableActions.Length - 1; i >= 0; i--)
|
133 |
+
{
|
134 |
+
var action = availableActions[i];
|
135 |
+
var actionData = _actionData[i];
|
136 |
+
|
137 |
+
if (actionData.IsProcessed == true && actionData.IsValid == false)
|
138 |
+
continue;
|
139 |
+
|
140 |
+
// Check if action can satisfy state at least partially (backward search)
|
141 |
+
if (currentNode.State.ContainsAny(action.Effects) == false)
|
142 |
+
continue;
|
143 |
+
|
144 |
+
// Check if action will not incorrectly override current state (backward search)
|
145 |
+
// Note: Next few lines are a bit difficult to understand.
|
146 |
+
// Do not modify it unless you know what you are doing.
|
147 |
+
// Mistake here will lead in failed backward search in more complex situations.
|
148 |
+
// Help: Continued state says how state should look like after this action will be executed.
|
149 |
+
// With applied state we are checking whether the current state contains continued state,
|
150 |
+
// merge helps with checking only part of the current state that matters.
|
151 |
+
var continuedState = GOAPState.Merge(action.Conditions, action.Effects);
|
152 |
+
var appliedState = GOAPState.Merge(continuedState, currentNode.State);
|
153 |
+
|
154 |
+
if (appliedState.Contains(continuedState) == false)
|
155 |
+
continue;
|
156 |
+
|
157 |
+
// We are validating action after we decide it fits the plan to not do this
|
158 |
+
// potentially expensive call unnecessary
|
159 |
+
if (actionData.IsProcessed == false)
|
160 |
+
{
|
161 |
+
actionData.IsValid = action.ValidateAction(frame, context, start, out FP cost) && cost > 0;
|
162 |
+
actionData.Cost = cost;
|
163 |
+
actionData.IsProcessed = true;
|
164 |
+
|
165 |
+
Assert.Check(cost > 0, $"GOAP: Action cost has to be greater than zero. Action: {action.Path} Cost: {cost}");
|
166 |
+
|
167 |
+
if (actionData.IsValid == false)
|
168 |
+
{
|
169 |
+
Statistics.ValidationReturns++;
|
170 |
+
continue;
|
171 |
+
}
|
172 |
+
}
|
173 |
+
|
174 |
+
Statistics.ValidationCalls++;
|
175 |
+
|
176 |
+
// Remove effects, apply conditions to state (= backward apply action)
|
177 |
+
GOAPState newState = GOAPState.Remove(currentNode.State, action.Effects);
|
178 |
+
newState.Merge(action.Conditions);
|
179 |
+
|
180 |
+
if (action.UsePlanStateValidation == true)
|
181 |
+
{
|
182 |
+
_planStateValidations.Clear();
|
183 |
+
|
184 |
+
action.ValidatePlanState(frame, context, newState, currentNode.State, actionData.Cost, _planStateValidations);
|
185 |
+
|
186 |
+
Statistics.PlanStateValidationCalls++;
|
187 |
+
|
188 |
+
// With plan state validation the plan can branch
|
189 |
+
for (int j = 0; j < _planStateValidations.Count; j++)
|
190 |
+
{
|
191 |
+
var validation = _planStateValidations[j];
|
192 |
+
TryAddNode(currentNode, validation.ValidatedState, i, validation.CostToNextState, start, heuristic);
|
193 |
+
}
|
194 |
+
}
|
195 |
+
else
|
196 |
+
{
|
197 |
+
TryAddNode(currentNode, newState, i, actionData.Cost, start, heuristic);
|
198 |
+
}
|
199 |
+
}
|
200 |
+
}
|
201 |
+
|
202 |
+
return 0;
|
203 |
+
}
|
204 |
+
|
205 |
+
private void TryAddNode(GOAPNode currentNode, GOAPState newState, int actionIndex, FP actionCost, GOAPState start, HeuristicCost heuristic)
|
206 |
+
{
|
207 |
+
int newStateHash = newState.GetHashCode();
|
208 |
+
|
209 |
+
if (_closed.ContainsKey(newStateHash) == true)
|
210 |
+
{
|
211 |
+
Statistics.InClosedReturns++;
|
212 |
+
return;
|
213 |
+
}
|
214 |
+
|
215 |
+
short h = (short)(heuristic(start, newState) * 100);
|
216 |
+
short g = (short)(currentNode.G + actionCost * 100);
|
217 |
+
|
218 |
+
Statistics.ProcessedNodes++;
|
219 |
+
|
220 |
+
GOAPNode node = new GOAPNode
|
221 |
+
{
|
222 |
+
Hash = newStateHash,
|
223 |
+
State = newState,
|
224 |
+
ActionIndex = (sbyte)actionIndex,
|
225 |
+
G = g,
|
226 |
+
F = (short)(h + g),
|
227 |
+
Parent = currentNode.Hash,
|
228 |
+
Depth = (byte)(currentNode.Depth + 1),
|
229 |
+
};
|
230 |
+
|
231 |
+
if (_active.TryGetValue(node.Hash, out GOAPNode existing))
|
232 |
+
{
|
233 |
+
if (node.F >= existing.F)
|
234 |
+
return;
|
235 |
+
|
236 |
+
_open.Update(node);
|
237 |
+
_active[node.Hash] = node;
|
238 |
+
|
239 |
+
//Log.Warn($"Updating node {node.ToString()}");
|
240 |
+
}
|
241 |
+
else
|
242 |
+
{
|
243 |
+
_open.Push(node);
|
244 |
+
_active.Add(node.Hash, node);
|
245 |
+
|
246 |
+
//Log.Warn($"Adding node {node.ToString()}");
|
247 |
+
}
|
248 |
+
}
|
249 |
+
|
250 |
+
private static void PrepareActionData(ref ActionData[] actionData, int length)
|
251 |
+
{
|
252 |
+
int originalLength = actionData != null ? actionData.Length : 0;
|
253 |
+
|
254 |
+
if (originalLength < length)
|
255 |
+
{
|
256 |
+
Array.Resize(ref actionData, length);
|
257 |
+
}
|
258 |
+
|
259 |
+
for (int i = 0; i < length; i++)
|
260 |
+
{
|
261 |
+
if (i < originalLength)
|
262 |
+
{
|
263 |
+
actionData[i].IsProcessed = false;
|
264 |
+
}
|
265 |
+
else
|
266 |
+
{
|
267 |
+
actionData[i] = new ActionData();
|
268 |
+
}
|
269 |
+
}
|
270 |
+
}
|
271 |
+
|
272 |
+
private void PrintHeap(GOAPAction[] actions)
|
273 |
+
{
|
274 |
+
string heap = "HEAP: ";
|
275 |
+
int index = 0;
|
276 |
+
|
277 |
+
foreach (GOAPNode node in _open)
|
278 |
+
{
|
279 |
+
heap += $"{index}: COST: {node.F} {actions[node.ActionIndex].Path}\n";
|
280 |
+
index++;
|
281 |
+
}
|
282 |
+
|
283 |
+
Log.Info(heap);
|
284 |
+
}
|
285 |
+
|
286 |
+
private class ActionData
|
287 |
+
{
|
288 |
+
public bool IsProcessed;
|
289 |
+
public bool IsValid;
|
290 |
+
public FP Cost;
|
291 |
+
}
|
292 |
+
|
293 |
+
public struct StatisticsData
|
294 |
+
{
|
295 |
+
public bool Success;
|
296 |
+
public int ClosedNodes;
|
297 |
+
public int OpenNodes;
|
298 |
+
public int ActiveNodes;
|
299 |
+
public int ValidationCalls;
|
300 |
+
public int ValidationReturns;
|
301 |
+
public int PlanStateValidationCalls;
|
302 |
+
public int InClosedReturns;
|
303 |
+
public int ProcessedNodes;
|
304 |
+
|
305 |
+
public new string ToString()
|
306 |
+
{
|
307 |
+
return $"Success: {Success}, Closed: {ClosedNodes}, Open: {OpenNodes}, Active: {ActiveNodes}\nValidation calls: {ValidationCalls}\nValidation returns: {ValidationReturns}\nPlan State Validation calls: {PlanStateValidationCalls}\nIn Closed returns: {InClosedReturns}\n Processed nodes: {ProcessedNodes}";
|
308 |
+
}
|
309 |
+
}
|
310 |
+
}
|
311 |
+
}
|
data/GOAPAction.cs
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using Photon.Deterministic;
|
2 |
+
using System.Collections.Generic;
|
3 |
+
|
4 |
+
namespace Quantum
|
5 |
+
{
|
6 |
+
public abstract unsafe partial class GOAPAction
|
7 |
+
{
|
8 |
+
public enum EResult
|
9 |
+
{
|
10 |
+
Continue,
|
11 |
+
IsDone,
|
12 |
+
IsFailed,
|
13 |
+
}
|
14 |
+
|
15 |
+
// PUBLIC MEMBERS
|
16 |
+
|
17 |
+
public string Label;
|
18 |
+
|
19 |
+
[BotSDKHidden]
|
20 |
+
public GOAPState Conditions;
|
21 |
+
[BotSDKHidden]
|
22 |
+
public GOAPState Effects;
|
23 |
+
|
24 |
+
public bool Interruptible;
|
25 |
+
|
26 |
+
public abstract bool UsePlanStateValidation { get; }
|
27 |
+
|
28 |
+
// PUBLIC METHODS
|
29 |
+
|
30 |
+
public virtual bool ValidateAction(Frame frame, GOAPEntityContext context, GOAPState startState, out FP cost)
|
31 |
+
{
|
32 |
+
cost = 1;
|
33 |
+
return true;
|
34 |
+
}
|
35 |
+
|
36 |
+
public virtual void ValidatePlanState(Frame frame, GOAPEntityContext context, GOAPState stateToValidate, GOAPState nextState, FP costToNextState, List<StateBackValidation> validatedStates)
|
37 |
+
{
|
38 |
+
}
|
39 |
+
|
40 |
+
public virtual void Activate(Frame frame, GOAPEntityContext context)
|
41 |
+
{
|
42 |
+
}
|
43 |
+
|
44 |
+
public virtual EResult Update(Frame frame, GOAPEntityContext context)
|
45 |
+
{
|
46 |
+
return EResult.Continue;
|
47 |
+
}
|
48 |
+
|
49 |
+
public virtual void Deactivate(Frame frame, GOAPEntityContext context)
|
50 |
+
{
|
51 |
+
}
|
52 |
+
}
|
53 |
+
}
|
data/GOAPBackValidation.cs
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System.Collections.Generic;
|
2 |
+
using Photon.Deterministic;
|
3 |
+
|
4 |
+
|
5 |
+
namespace Quantum
|
6 |
+
{
|
7 |
+
public abstract partial class GOAPBackValidation
|
8 |
+
{
|
9 |
+
public abstract void ValidatePlanState(Frame frame, EntityRef entity, GOAPState stateToValidate, GOAPState nextState, FP costToNextState, List<StateBackValidation> validatedStates);
|
10 |
+
}
|
11 |
+
|
12 |
+
public abstract class GOAPSingleBackValidation : GOAPBackValidation
|
13 |
+
{
|
14 |
+
public override sealed void ValidatePlanState(Frame frame, EntityRef entity, GOAPState stateToValidate, GOAPState nextState, FP costToNextState,
|
15 |
+
List<StateBackValidation> validatedStates)
|
16 |
+
{
|
17 |
+
if (ValidatePlanState(frame, entity, ref stateToValidate, nextState, ref costToNextState) == true)
|
18 |
+
{
|
19 |
+
validatedStates.Add(new StateBackValidation(stateToValidate, costToNextState));
|
20 |
+
}
|
21 |
+
}
|
22 |
+
|
23 |
+
protected virtual bool ValidatePlanState(Frame frame, EntityRef entity, ref GOAPState stateToValidate, GOAPState nextState, ref FP costToNextState)
|
24 |
+
{
|
25 |
+
return false;
|
26 |
+
}
|
27 |
+
}
|
28 |
+
}
|
data/GOAPDefaultAction.cs
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using Photon.Deterministic;
|
2 |
+
using System.Collections.Generic;
|
3 |
+
using System;
|
4 |
+
|
5 |
+
namespace Quantum
|
6 |
+
{
|
7 |
+
[Serializable]
|
8 |
+
public unsafe partial class GOAPDefaultAction : GOAPAction
|
9 |
+
{
|
10 |
+
// PUBLIC MEMBERS
|
11 |
+
|
12 |
+
public AIParamBool Validation = true;
|
13 |
+
public AIParamFP Cost = FP._1;
|
14 |
+
public AssetRefGOAPBackValidation PlanStateValidationLink;
|
15 |
+
|
16 |
+
public AssetRefAIAction[] OnActivateLinks;
|
17 |
+
public AssetRefAIAction[] OnUpdateLinks;
|
18 |
+
public AssetRefAIAction[] OnDeactivateLinks;
|
19 |
+
|
20 |
+
public AIParamBool IsDone;
|
21 |
+
public AIParamBool IsFailed;
|
22 |
+
|
23 |
+
[NonSerialized]
|
24 |
+
public GOAPBackValidation PlanStateValidation;
|
25 |
+
|
26 |
+
[NonSerialized]
|
27 |
+
public AIAction[] OnActivate;
|
28 |
+
[NonSerialized]
|
29 |
+
public AIAction[] OnUpdate;
|
30 |
+
[NonSerialized]
|
31 |
+
public AIAction[] OnDeactivate;
|
32 |
+
|
33 |
+
public override bool UsePlanStateValidation => PlanStateValidation != null;
|
34 |
+
|
35 |
+
// PUBLIC METHODS
|
36 |
+
|
37 |
+
public override bool ValidateAction(Frame frame, GOAPEntityContext context, GOAPState startState, out FP cost)
|
38 |
+
{
|
39 |
+
cost = FP.MaxValue;
|
40 |
+
|
41 |
+
if (Validation.Resolve(frame, context.Entity, context.Blackboard, context.Config) == false)
|
42 |
+
return false;
|
43 |
+
|
44 |
+
cost = Cost.Resolve(frame, context.Entity, context.Blackboard, context.Config);
|
45 |
+
|
46 |
+
return cost < FP.MaxValue;
|
47 |
+
}
|
48 |
+
|
49 |
+
public override void ValidatePlanState(Frame frame, GOAPEntityContext context, GOAPState stateToValidate, GOAPState nextState, FP costToNextState, List<StateBackValidation> validatedStates)
|
50 |
+
{
|
51 |
+
PlanStateValidation.ValidatePlanState(frame, context.Entity, stateToValidate, nextState, costToNextState, validatedStates);
|
52 |
+
}
|
53 |
+
|
54 |
+
public override void Activate(Frame frame, GOAPEntityContext context)
|
55 |
+
{
|
56 |
+
ExecuteActions(frame, context.Entity, OnActivate);
|
57 |
+
}
|
58 |
+
|
59 |
+
public override EResult Update(Frame frame, GOAPEntityContext context)
|
60 |
+
{
|
61 |
+
if (IsDone.Resolve(frame, context.Entity, context.Blackboard, context.Config) == true)
|
62 |
+
return EResult.IsDone;
|
63 |
+
|
64 |
+
if (IsFailed.Resolve(frame, context.Entity, context.Blackboard, context.Config) == true)
|
65 |
+
return EResult.IsFailed;
|
66 |
+
|
67 |
+
ExecuteActions(frame, context.Entity, OnUpdate);
|
68 |
+
|
69 |
+
return EResult.Continue;
|
70 |
+
}
|
71 |
+
|
72 |
+
public override void Deactivate(Frame frame, GOAPEntityContext context)
|
73 |
+
{
|
74 |
+
ExecuteActions(frame, context.Entity, OnDeactivate);
|
75 |
+
}
|
76 |
+
|
77 |
+
// AssetObject INTERFACE
|
78 |
+
|
79 |
+
public override void Loaded(IResourceManager resourceManager, Native.Allocator allocator)
|
80 |
+
{
|
81 |
+
base.Loaded(resourceManager, allocator);
|
82 |
+
|
83 |
+
PlanStateValidation = (GOAPBackValidation)resourceManager.GetAsset(PlanStateValidationLink.Id);
|
84 |
+
|
85 |
+
OnActivate = new AIAction[OnActivateLinks == null ? 0 : OnActivateLinks.Length];
|
86 |
+
for (int i = 0; i < OnActivate.Length; i++)
|
87 |
+
{
|
88 |
+
OnActivate[i] = (AIAction)resourceManager.GetAsset(OnActivateLinks[i].Id);
|
89 |
+
}
|
90 |
+
|
91 |
+
OnUpdate = new AIAction[OnUpdateLinks == null ? 0 : OnUpdateLinks.Length];
|
92 |
+
for (int i = 0; i < OnUpdate.Length; i++)
|
93 |
+
{
|
94 |
+
OnUpdate[i] = (AIAction)resourceManager.GetAsset(OnUpdateLinks[i].Id);
|
95 |
+
}
|
96 |
+
|
97 |
+
OnDeactivate = new AIAction[OnDeactivateLinks == null ? 0 : OnDeactivateLinks.Length];
|
98 |
+
for (int i = 0; i < OnDeactivate.Length; i++)
|
99 |
+
{
|
100 |
+
OnDeactivate[i] = (AIAction)resourceManager.GetAsset(OnDeactivateLinks[i].Id);
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
// PRIVATE METHODS
|
105 |
+
|
106 |
+
private static void ExecuteActions(Frame frame, EntityRef entity, AIAction[] actions)
|
107 |
+
{
|
108 |
+
for (int i = 0; i < actions.Length; i++)
|
109 |
+
{
|
110 |
+
var action = actions[i];
|
111 |
+
|
112 |
+
action.Update(frame, entity);
|
113 |
+
|
114 |
+
int nextAction = action.NextAction(frame, entity);
|
115 |
+
if (nextAction > i)
|
116 |
+
{
|
117 |
+
i = nextAction;
|
118 |
+
}
|
119 |
+
}
|
120 |
+
}
|
121 |
+
}
|
122 |
+
}
|
data/GOAPDefaultGoal.cs
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
using Photon.Deterministic;
|
3 |
+
|
4 |
+
namespace Quantum
|
5 |
+
{
|
6 |
+
[Serializable]
|
7 |
+
public unsafe partial class GOAPDefaultGoal : GOAPGoal
|
8 |
+
{
|
9 |
+
// PUBLIC MEMBERS
|
10 |
+
|
11 |
+
public AIParamBool Validation = true;
|
12 |
+
public AIParamFP Relevancy = FP._1;
|
13 |
+
public AIParamFP DisableTime;
|
14 |
+
public AssetRefAIAction[] OnInitPlanningLinks;
|
15 |
+
public AssetRefAIAction[] OnActivateLinks;
|
16 |
+
public AssetRefAIAction[] OnDeactivateLinks;
|
17 |
+
public AIParamBool IsFinished;
|
18 |
+
|
19 |
+
[NonSerialized]
|
20 |
+
public AIAction[] OnInitPlanning;
|
21 |
+
[NonSerialized]
|
22 |
+
public AIAction[] OnActivate;
|
23 |
+
[NonSerialized]
|
24 |
+
public AIAction[] OnDeactivate;
|
25 |
+
|
26 |
+
// PUBLIC METHODS
|
27 |
+
|
28 |
+
public override FP GetRelevancy(Frame frame, GOAPEntityContext context)
|
29 |
+
{
|
30 |
+
if (Validation.Resolve(frame, context.Entity, context.Blackboard, context.Config) == false)
|
31 |
+
return 0;
|
32 |
+
|
33 |
+
return Relevancy.Resolve(frame, context.Entity, context.Blackboard, context.Config);
|
34 |
+
}
|
35 |
+
|
36 |
+
public override void InitPlanning(Frame frame, GOAPEntityContext context, ref GOAPState startState, ref GOAPState targetState)
|
37 |
+
{
|
38 |
+
base.InitPlanning(frame, context, ref startState, ref targetState);
|
39 |
+
|
40 |
+
ExecuteActions(frame, context.Entity, OnInitPlanning);
|
41 |
+
}
|
42 |
+
|
43 |
+
public override void Activate(Frame frame, GOAPEntityContext context)
|
44 |
+
{
|
45 |
+
base.Activate(frame, context);
|
46 |
+
|
47 |
+
ExecuteActions(frame, context.Entity, OnActivate);
|
48 |
+
}
|
49 |
+
|
50 |
+
public override void Deactivate(Frame frame, GOAPEntityContext context)
|
51 |
+
{
|
52 |
+
ExecuteActions(frame, context.Entity, OnDeactivate);
|
53 |
+
|
54 |
+
base.Deactivate(frame, context);
|
55 |
+
}
|
56 |
+
|
57 |
+
public override bool HasFinished(Frame frame, GOAPEntityContext context)
|
58 |
+
{
|
59 |
+
if (base.HasFinished(frame, context) == true)
|
60 |
+
return true;
|
61 |
+
|
62 |
+
return IsFinished.Resolve(frame, context.Entity, context.Blackboard, context.Config);
|
63 |
+
}
|
64 |
+
|
65 |
+
public override FP GetDisableTime(Frame frame, GOAPEntityContext context)
|
66 |
+
{
|
67 |
+
return DisableTime.Resolve(frame, context.Entity, context.Blackboard, context.Config);
|
68 |
+
}
|
69 |
+
|
70 |
+
// AssetObject INTERFACE
|
71 |
+
|
72 |
+
public override void Loaded(IResourceManager resourceManager, Native.Allocator allocator)
|
73 |
+
{
|
74 |
+
base.Loaded(resourceManager, allocator);
|
75 |
+
|
76 |
+
OnInitPlanning = new AIAction[OnInitPlanningLinks == null ? 0 : OnInitPlanningLinks.Length];
|
77 |
+
for (int i = 0; i < OnInitPlanning.Length; i++)
|
78 |
+
{
|
79 |
+
OnInitPlanning[i] = (AIAction)resourceManager.GetAsset(OnInitPlanningLinks[i].Id);
|
80 |
+
}
|
81 |
+
|
82 |
+
OnActivate = new AIAction[OnActivateLinks == null ? 0 : OnActivateLinks.Length];
|
83 |
+
for (int i = 0; i < OnActivate.Length; i++)
|
84 |
+
{
|
85 |
+
OnActivate[i] = (AIAction)resourceManager.GetAsset(OnActivateLinks[i].Id);
|
86 |
+
}
|
87 |
+
|
88 |
+
OnDeactivate = new AIAction[OnDeactivateLinks == null ? 0 : OnDeactivateLinks.Length];
|
89 |
+
for (int i = 0; i < OnDeactivate.Length; i++)
|
90 |
+
{
|
91 |
+
OnDeactivate[i] = (AIAction)resourceManager.GetAsset(OnDeactivateLinks[i].Id);
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
// PRIVATE METHODS
|
96 |
+
|
97 |
+
private static void ExecuteActions(Frame frame, EntityRef entity, AIAction[] actions)
|
98 |
+
{
|
99 |
+
for (int i = 0; i < actions.Length; i++)
|
100 |
+
{
|
101 |
+
var action = actions[i];
|
102 |
+
|
103 |
+
action.Update(frame, entity);
|
104 |
+
|
105 |
+
int nextAction = action.NextAction(frame, entity);
|
106 |
+
if (nextAction > i)
|
107 |
+
{
|
108 |
+
i = nextAction;
|
109 |
+
}
|
110 |
+
}
|
111 |
+
}
|
112 |
+
}
|
113 |
+
}
|
data/GOAPDefaultHeuristic.cs
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
public static class GOAPDefaultHeuristic
|
4 |
+
{
|
5 |
+
public static int BitmaskDifferenceUInt32(GOAPState start, GOAPState end)
|
6 |
+
{
|
7 |
+
EWorldState positiveAchieved = start.Positive & end.Positive;
|
8 |
+
EWorldState negativeAchieved = start.Negative & end.Negative;
|
9 |
+
|
10 |
+
EWorldState positiveMissing = end.Positive & ~positiveAchieved;
|
11 |
+
EWorldState negativeMissing = end.Negative & ~negativeAchieved;
|
12 |
+
|
13 |
+
return CountOnesUInt32((uint) positiveMissing) + CountOnesUInt32((uint) negativeMissing);
|
14 |
+
}
|
15 |
+
|
16 |
+
public static int BitmaskDifferenceUInt64(GOAPState start, GOAPState end)
|
17 |
+
{
|
18 |
+
EWorldState positiveAchieved = start.Positive & end.Positive;
|
19 |
+
EWorldState negativeAchieved = start.Negative & end.Negative;
|
20 |
+
|
21 |
+
EWorldState positiveMissing = end.Positive & ~positiveAchieved;
|
22 |
+
EWorldState negativeMissing = end.Negative & ~negativeAchieved;
|
23 |
+
|
24 |
+
return CountOnesUInt64((ulong) positiveMissing) + CountOnesUInt64((ulong) negativeMissing);
|
25 |
+
}
|
26 |
+
|
27 |
+
public static int CountOnesUInt32(uint x)
|
28 |
+
{
|
29 |
+
x = x - ((x >> 1) & 0x55555555u);
|
30 |
+
x = (x & 0x33333333u) + ((x >> 2) & 0x33333333u);
|
31 |
+
x = (x + (x >> 4)) & 0x0F0F0F0Fu;
|
32 |
+
|
33 |
+
return (int) ((x * 0x01010101u) >> 24);
|
34 |
+
}
|
35 |
+
|
36 |
+
public static int CountOnesUInt64(ulong x)
|
37 |
+
{
|
38 |
+
x = x - ((x >> 1) & 0x5555555555555555ul);
|
39 |
+
x = (x & 0x3333333333333333ul) + ((x >> 2) & 0x3333333333333333ul);
|
40 |
+
x = (x + (x >> 4)) & 0xF0F0F0F0F0F0F0Ful;
|
41 |
+
|
42 |
+
return (int) (x * 0x101010101010101ul >> 56);
|
43 |
+
}
|
44 |
+
}
|
45 |
+
}
|
data/GOAPGoal.cs
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using Photon.Deterministic;
|
2 |
+
|
3 |
+
namespace Quantum
|
4 |
+
{
|
5 |
+
public abstract unsafe partial class GOAPGoal
|
6 |
+
{
|
7 |
+
public enum EInterruptionBehavior
|
8 |
+
{
|
9 |
+
Never,
|
10 |
+
Always,
|
11 |
+
BasedOnActions,
|
12 |
+
}
|
13 |
+
|
14 |
+
// PUBLIC MEMBERS
|
15 |
+
|
16 |
+
public string Label;
|
17 |
+
|
18 |
+
[BotSDKHidden]
|
19 |
+
public GOAPState StartState;
|
20 |
+
[BotSDKHidden]
|
21 |
+
public GOAPState TargetState;
|
22 |
+
public EInterruptionBehavior InterruptionBehavior;
|
23 |
+
|
24 |
+
// PUBLIC INTERFACE
|
25 |
+
|
26 |
+
public virtual FP GetRelevancy(Frame frame, GOAPEntityContext context)
|
27 |
+
{
|
28 |
+
return 1;
|
29 |
+
}
|
30 |
+
|
31 |
+
public virtual void InitPlanning(Frame frame, GOAPEntityContext context, ref GOAPState startState, ref GOAPState targetState)
|
32 |
+
{
|
33 |
+
startState.Merge(StartState);
|
34 |
+
targetState.Merge(TargetState);
|
35 |
+
}
|
36 |
+
|
37 |
+
public virtual void Activate(Frame frame, GOAPEntityContext context)
|
38 |
+
{
|
39 |
+
}
|
40 |
+
|
41 |
+
public virtual void Deactivate(Frame frame, GOAPEntityContext context)
|
42 |
+
{
|
43 |
+
}
|
44 |
+
|
45 |
+
public virtual bool HasFinished(Frame frame, GOAPEntityContext context)
|
46 |
+
{
|
47 |
+
return context.Agent->CurrentState.Contains(context.Agent->GoalState);
|
48 |
+
}
|
49 |
+
|
50 |
+
public bool IsInterruptible(GOAPAction currentAction)
|
51 |
+
{
|
52 |
+
if (InterruptionBehavior == EInterruptionBehavior.Never)
|
53 |
+
return false;
|
54 |
+
|
55 |
+
if (InterruptionBehavior == EInterruptionBehavior.Always)
|
56 |
+
return true;
|
57 |
+
|
58 |
+
return currentAction != null && currentAction.Interruptible;
|
59 |
+
}
|
60 |
+
|
61 |
+
public virtual FP GetDisableTime(Frame frame, GOAPEntityContext context)
|
62 |
+
{
|
63 |
+
return 0;
|
64 |
+
}
|
65 |
+
}
|
66 |
+
}
|
data/GOAPHeap.cs
ADDED
@@ -0,0 +1,162 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
using System.Collections;
|
3 |
+
using System.Collections.Generic;
|
4 |
+
|
5 |
+
namespace Quantum
|
6 |
+
{
|
7 |
+
public class GOAPHeap : IEnumerable, IEnumerable<GOAPNode>
|
8 |
+
{
|
9 |
+
private GOAPNode[] _heap;
|
10 |
+
private int _size;
|
11 |
+
|
12 |
+
public GOAPHeap(int capacity)
|
13 |
+
{
|
14 |
+
_heap = new GOAPNode[capacity];
|
15 |
+
}
|
16 |
+
|
17 |
+
public GOAPHeap() : this(1024)
|
18 |
+
{
|
19 |
+
}
|
20 |
+
|
21 |
+
public int Size { get { return _size; } }
|
22 |
+
|
23 |
+
public void Clear()
|
24 |
+
{
|
25 |
+
_size = 0;
|
26 |
+
|
27 |
+
// remove all stuff from heap
|
28 |
+
Array.Clear(_heap, 0, _heap.Length);
|
29 |
+
}
|
30 |
+
|
31 |
+
public void Update(GOAPNode updateNode)
|
32 |
+
{
|
33 |
+
int bubbleIndex = -1;
|
34 |
+
for (int i = 0; i < _size; i++)
|
35 |
+
{
|
36 |
+
var node = _heap[i];
|
37 |
+
if (node.Hash == updateNode.Hash)
|
38 |
+
{
|
39 |
+
bubbleIndex = i;
|
40 |
+
break;
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
if (bubbleIndex < 0)
|
45 |
+
{
|
46 |
+
Log.Error($"Cannot update node: Node with hash {updateNode.Hash} is not present in the heap");
|
47 |
+
return;
|
48 |
+
}
|
49 |
+
|
50 |
+
_heap[bubbleIndex] = updateNode;
|
51 |
+
|
52 |
+
while (bubbleIndex != 0)
|
53 |
+
{
|
54 |
+
int parentIndex = (bubbleIndex - 1) / 2;
|
55 |
+
|
56 |
+
if (_heap[parentIndex].F <= updateNode.F)
|
57 |
+
break;
|
58 |
+
|
59 |
+
_heap[bubbleIndex] = _heap[parentIndex];
|
60 |
+
_heap[parentIndex] = updateNode;
|
61 |
+
|
62 |
+
bubbleIndex = parentIndex;
|
63 |
+
}
|
64 |
+
}
|
65 |
+
|
66 |
+
public void Push(GOAPNode node)
|
67 |
+
{
|
68 |
+
if (_size == _heap.Length)
|
69 |
+
{
|
70 |
+
ExpandHeap();
|
71 |
+
}
|
72 |
+
|
73 |
+
int bubbleIndex = _size;
|
74 |
+
_heap[bubbleIndex] = node;
|
75 |
+
|
76 |
+
_size++;
|
77 |
+
|
78 |
+
while (bubbleIndex != 0)
|
79 |
+
{
|
80 |
+
int parentIndex = (bubbleIndex - 1) / 2;
|
81 |
+
if (_heap[parentIndex].F <= node.F)
|
82 |
+
break;
|
83 |
+
|
84 |
+
_heap[bubbleIndex] = _heap[parentIndex];
|
85 |
+
_heap[parentIndex] = node;
|
86 |
+
|
87 |
+
bubbleIndex = parentIndex;
|
88 |
+
}
|
89 |
+
}
|
90 |
+
|
91 |
+
public GOAPNode Pop()
|
92 |
+
{
|
93 |
+
GOAPNode returnItem = _heap[0];
|
94 |
+
_heap[0] = _heap[_size - 1];
|
95 |
+
|
96 |
+
_size--;
|
97 |
+
|
98 |
+
int swapItem = 0;
|
99 |
+
int parent = 0;
|
100 |
+
|
101 |
+
do
|
102 |
+
{
|
103 |
+
parent = swapItem;
|
104 |
+
|
105 |
+
int leftChild = 2 * parent + 1;
|
106 |
+
int rightChild = 2 * parent + 2;
|
107 |
+
|
108 |
+
if (rightChild <= _size)
|
109 |
+
{
|
110 |
+
int smallerChild = _heap[leftChild].F < _heap[rightChild].F ? leftChild : rightChild;
|
111 |
+
|
112 |
+
if (_heap[parent].F >= _heap[smallerChild].F)
|
113 |
+
{
|
114 |
+
swapItem = smallerChild;
|
115 |
+
}
|
116 |
+
}
|
117 |
+
else if (leftChild <= _size)
|
118 |
+
{
|
119 |
+
// Only one child exists
|
120 |
+
if (_heap[parent].F >= _heap[leftChild].F)
|
121 |
+
{
|
122 |
+
swapItem = leftChild;
|
123 |
+
}
|
124 |
+
}
|
125 |
+
|
126 |
+
// One if the parent's children are smaller or equal, swap them
|
127 |
+
if (parent != swapItem)
|
128 |
+
{
|
129 |
+
GOAPNode tmpIndex = _heap[parent];
|
130 |
+
|
131 |
+
_heap[parent] = _heap[swapItem];
|
132 |
+
_heap[swapItem] = tmpIndex;
|
133 |
+
}
|
134 |
+
}
|
135 |
+
while (parent != swapItem);
|
136 |
+
|
137 |
+
return returnItem;
|
138 |
+
}
|
139 |
+
|
140 |
+
private void ExpandHeap()
|
141 |
+
{
|
142 |
+
// Double the size
|
143 |
+
GOAPNode[] newHeap = new GOAPNode[_heap.Length * 2];
|
144 |
+
|
145 |
+
Array.Copy(_heap, newHeap, _heap.Length);
|
146 |
+
_heap = newHeap;
|
147 |
+
}
|
148 |
+
|
149 |
+
IEnumerator<GOAPNode> IEnumerable<GOAPNode>.GetEnumerator()
|
150 |
+
{
|
151 |
+
for (int i = 0; i < _size; i++)
|
152 |
+
{
|
153 |
+
yield return _heap[i];
|
154 |
+
}
|
155 |
+
}
|
156 |
+
|
157 |
+
IEnumerator IEnumerable.GetEnumerator()
|
158 |
+
{
|
159 |
+
return (this as IEnumerable<GOAPNode>).GetEnumerator();
|
160 |
+
}
|
161 |
+
}
|
162 |
+
}
|
data/GOAPHeuristic.cs
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
namespace Quantum
|
2 |
+
{
|
3 |
+
public static class GOAPHeuristic
|
4 |
+
{
|
5 |
+
public static int BitmaskDifferenceUInt32(GOAPState start, GOAPState end)
|
6 |
+
{
|
7 |
+
EWorldState positiveAchieved = start.Positive & end.Positive;
|
8 |
+
EWorldState negativeAchieved = start.Negative & end.Negative;
|
9 |
+
|
10 |
+
EWorldState positiveMissing = end.Positive & ~positiveAchieved;
|
11 |
+
EWorldState negativeMissing = end.Negative & ~negativeAchieved;
|
12 |
+
|
13 |
+
return CountOnesUInt32((uint) positiveMissing) + CountOnesUInt32((uint) negativeMissing);
|
14 |
+
}
|
15 |
+
|
16 |
+
public static int BitmaskDifferenceUInt64(GOAPState start, GOAPState end)
|
17 |
+
{
|
18 |
+
EWorldState positiveAchieved = start.Positive & end.Positive;
|
19 |
+
EWorldState negativeAchieved = start.Negative & end.Negative;
|
20 |
+
|
21 |
+
EWorldState positiveMissing = end.Positive & ~positiveAchieved;
|
22 |
+
EWorldState negativeMissing = end.Negative & ~negativeAchieved;
|
23 |
+
|
24 |
+
return CountOnesUInt64((ulong) positiveMissing) + CountOnesUInt64((ulong) negativeMissing);
|
25 |
+
}
|
26 |
+
|
27 |
+
public static int CountOnesUInt32(uint x)
|
28 |
+
{
|
29 |
+
x = x - ((x >> 1) & 0x55555555u);
|
30 |
+
x = (x & 0x33333333u) + ((x >> 2) & 0x33333333u);
|
31 |
+
x = (x + (x >> 4)) & 0x0F0F0F0Fu;
|
32 |
+
|
33 |
+
return (int) ((x * 0x01010101u) >> 24);
|
34 |
+
}
|
35 |
+
|
36 |
+
public static int CountOnesUInt64(ulong x)
|
37 |
+
{
|
38 |
+
x = x - ((x >> 1) & 0x5555555555555555ul);
|
39 |
+
x = (x & 0x3333333333333333ul) + ((x >> 2) & 0x3333333333333333ul);
|
40 |
+
x = (x + (x >> 4)) & 0xF0F0F0F0F0F0F0Ful;
|
41 |
+
|
42 |
+
return (int) (x * 0x101010101010101ul >> 56);
|
43 |
+
}
|
44 |
+
}
|
45 |
+
}
|
data/GOAPManager.cs
ADDED
@@ -0,0 +1,450 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
using System;
|
2 |
+
using Photon.Deterministic;
|
3 |
+
using System.Collections.Generic;
|
4 |
+
|
5 |
+
namespace Quantum
|
6 |
+
{
|
7 |
+
public static unsafe class GOAPManager
|
8 |
+
{
|
9 |
+
// PUBLIC MEMBERS
|
10 |
+
|
11 |
+
public static EntityRef DebugEntity;
|
12 |
+
|
13 |
+
// PRIVATE MEMBERS
|
14 |
+
|
15 |
+
private static GOAPAStar.HeuristicCost _heuristicCost;
|
16 |
+
|
17 |
+
// PUBLIC METHODS
|
18 |
+
|
19 |
+
public static void Initialize(Frame frame, EntityRef entity, GOAPRoot root, GOAPAStar.HeuristicCost heuristicCost = null)
|
20 |
+
{
|
21 |
+
var agent = frame.Unsafe.GetPointer<GOAPAgent>(entity);
|
22 |
+
agent->Root = root;
|
23 |
+
|
24 |
+
var disableTimes = frame.AllocateList<FP>(root.Goals.Length);
|
25 |
+
for (int i = 0; i < root.GoalRefs.Length; i++)
|
26 |
+
{
|
27 |
+
disableTimes.Add(0);
|
28 |
+
}
|
29 |
+
|
30 |
+
agent->GoalDisableTimes = disableTimes;
|
31 |
+
|
32 |
+
if (heuristicCost != null)
|
33 |
+
{
|
34 |
+
_heuristicCost = heuristicCost;
|
35 |
+
}
|
36 |
+
else if (_heuristicCost == null)
|
37 |
+
{
|
38 |
+
switch (sizeof(EWorldState))
|
39 |
+
{
|
40 |
+
case 4:
|
41 |
+
_heuristicCost = GOAPHeuristic.BitmaskDifferenceUInt32;
|
42 |
+
break;
|
43 |
+
//case 8:
|
44 |
+
// _heuristicCost = GOAPHeuristic.BitmaskDifferenceUInt64;
|
45 |
+
// break;
|
46 |
+
default:
|
47 |
+
throw new NotImplementedException($"Heuristic for EWorldState size of {sizeof(EWorldState)} bytes is not implemented");
|
48 |
+
}
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
+
public static void Deinitialize(Frame frame, EntityRef entity)
|
53 |
+
{
|
54 |
+
var agent = frame.Unsafe.GetPointer<GOAPAgent>(entity);
|
55 |
+
|
56 |
+
agent->Root = default;
|
57 |
+
|
58 |
+
frame.FreeList(agent->GoalDisableTimes);
|
59 |
+
agent->GoalDisableTimes = default;
|
60 |
+
}
|
61 |
+
|
62 |
+
public static void Update(Frame frame, EntityRef entity, FP deltaTime)
|
63 |
+
{
|
64 |
+
var context = GetContext(frame, entity);
|
65 |
+
var agent = context.Agent;
|
66 |
+
|
67 |
+
bool debug = DebugEntity == entity;
|
68 |
+
|
69 |
+
// Update disable times
|
70 |
+
var goalDisableTimes = frame.ResolveList(agent->GoalDisableTimes);
|
71 |
+
for (int i = 0; i < goalDisableTimes.Count; i++)
|
72 |
+
{
|
73 |
+
goalDisableTimes[i] = FPMath.Max(FP._0, goalDisableTimes[i] - deltaTime);
|
74 |
+
}
|
75 |
+
|
76 |
+
var currentGoal = agent->CurrentGoal.Id.IsValid == true ? frame.FindAsset<GOAPGoal>(agent->CurrentGoal.Id) : null;
|
77 |
+
var currentAction = GetCurrentAction(frame, agent);
|
78 |
+
|
79 |
+
if (currentGoal != null)
|
80 |
+
{
|
81 |
+
// Decrease interruption timer
|
82 |
+
agent->InterruptionCheckCooldown = FPMath.Max(agent->InterruptionCheckCooldown - deltaTime, 0);
|
83 |
+
|
84 |
+
if (currentGoal.HasFinished(frame, context) == true)
|
85 |
+
{
|
86 |
+
StopCurrentGoal(frame, context, ref currentGoal, ref currentAction);
|
87 |
+
}
|
88 |
+
}
|
89 |
+
|
90 |
+
if (currentGoal == null || (agent->InterruptionCheckCooldown <= 0 && currentGoal.IsInterruptible(currentAction) == true))
|
91 |
+
{
|
92 |
+
FindNewGoal(frame, context, ref currentGoal, ref currentAction);
|
93 |
+
}
|
94 |
+
|
95 |
+
if (currentGoal != null)
|
96 |
+
{
|
97 |
+
UpdateCurrentGoal(frame, context, deltaTime, ref currentGoal, ref currentAction);
|
98 |
+
}
|
99 |
+
|
100 |
+
Pool.Return(context);
|
101 |
+
}
|
102 |
+
|
103 |
+
public static void StopCurrentGoal(Frame frame, EntityRef entity)
|
104 |
+
{
|
105 |
+
var context = GetContext(frame, entity);
|
106 |
+
|
107 |
+
var currentGoal = context.Agent->CurrentGoal.Id.IsValid == true ? frame.FindAsset<GOAPGoal>(context.Agent->CurrentGoal.Id) : null;
|
108 |
+
var currentAction = GetCurrentAction(frame, context.Agent);
|
109 |
+
|
110 |
+
StopCurrentGoal(frame, context, ref currentGoal, ref currentAction);
|
111 |
+
}
|
112 |
+
|
113 |
+
public static void SetGoalDisableTime(Frame frame, EntityRef entity, AssetRefGOAPGoal goal, FP disableTime)
|
114 |
+
{
|
115 |
+
if (goal.Id.IsValid == false)
|
116 |
+
return;
|
117 |
+
|
118 |
+
var agent = frame.Unsafe.GetPointer<GOAPAgent>(entity);
|
119 |
+
|
120 |
+
if (goal == agent->CurrentGoal)
|
121 |
+
{
|
122 |
+
StopCurrentGoal(frame, entity);
|
123 |
+
}
|
124 |
+
|
125 |
+
var root = frame.FindAsset<GOAPRoot>(agent->Root.Id);
|
126 |
+
int goalIndex = Array.IndexOf(root.GoalRefs, goal);
|
127 |
+
|
128 |
+
if (goalIndex >= 0)
|
129 |
+
{
|
130 |
+
var disableTimes = frame.ResolveList(agent->GoalDisableTimes);
|
131 |
+
disableTimes[goalIndex] = disableTime;
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
// PRIVATE METHODS
|
136 |
+
|
137 |
+
private static void UpdateCurrentGoal(Frame frame, GOAPEntityContext context, FP deltaTime, ref GOAPGoal currentGoal, ref GOAPAction currentAction)
|
138 |
+
{
|
139 |
+
var agent = context.Agent;
|
140 |
+
bool debug = DebugEntity == context.Entity;
|
141 |
+
|
142 |
+
if (currentAction != null && agent->CurrentState.Contains(currentAction.Effects) == true)
|
143 |
+
{
|
144 |
+
// This action is done, let's choose another one in next step
|
145 |
+
StopCurrentAction(frame, context, ref currentAction);
|
146 |
+
}
|
147 |
+
|
148 |
+
// Activate next action from the plan if needed
|
149 |
+
if (currentAction == null && agent->CurrentPlanSize > 0)
|
150 |
+
{
|
151 |
+
while (agent->CurrentActionIndex < agent->CurrentPlanSize - 1)
|
152 |
+
{
|
153 |
+
agent->LastProcessedActionIndex = agent->CurrentActionIndex;
|
154 |
+
agent->CurrentActionIndex++;
|
155 |
+
|
156 |
+
var nextAction = frame.FindAsset<GOAPAction>(agent->Plan[agent->CurrentActionIndex].Id);
|
157 |
+
|
158 |
+
if (agent->CurrentState.Contains(nextAction.Conditions) == false)
|
159 |
+
{
|
160 |
+
// Conditions are not met, terminate whole plan
|
161 |
+
StopCurrentGoal(frame, context, ref currentGoal, ref currentAction);
|
162 |
+
break;
|
163 |
+
}
|
164 |
+
|
165 |
+
if (agent->CurrentState.Contains(nextAction.Effects) == false)
|
166 |
+
{
|
167 |
+
// This action is valid, activate it
|
168 |
+
currentAction = nextAction;
|
169 |
+
currentAction.Activate(frame, context);
|
170 |
+
|
171 |
+
if (debug == true)
|
172 |
+
{
|
173 |
+
Log.Info($"GOAP: Action {currentAction.Path} activated");
|
174 |
+
}
|
175 |
+
|
176 |
+
agent->CurrentActionTime = 0;
|
177 |
+
break;
|
178 |
+
}
|
179 |
+
}
|
180 |
+
|
181 |
+
if (currentAction == null && currentGoal != null)
|
182 |
+
{
|
183 |
+
if (debug == true)
|
184 |
+
{
|
185 |
+
Log.Info($"GOAP: Plan execution failed: Probably last action is finished but goal is not satisfied (state might change during execution). Goal: {currentGoal.Path}");
|
186 |
+
}
|
187 |
+
|
188 |
+
StopCurrentGoal(frame, context, ref currentGoal, ref currentAction);
|
189 |
+
}
|
190 |
+
}
|
191 |
+
|
192 |
+
// Update action
|
193 |
+
if (currentAction != null)
|
194 |
+
{
|
195 |
+
var result = currentAction.Update(frame, context);
|
196 |
+
|
197 |
+
if (result == GOAPAction.EResult.IsFailed)
|
198 |
+
{
|
199 |
+
StopCurrentGoal(frame, context, ref currentGoal, ref currentAction);
|
200 |
+
}
|
201 |
+
else if (result == GOAPAction.EResult.IsDone)
|
202 |
+
{
|
203 |
+
// This action claims to be done, apply effects and next action will be chosen next Update
|
204 |
+
agent->CurrentState.Merge(currentAction.Effects);
|
205 |
+
agent->LastProcessedActionIndex = agent->CurrentActionIndex;
|
206 |
+
|
207 |
+
StopCurrentAction(frame, context, ref currentAction);
|
208 |
+
}
|
209 |
+
|
210 |
+
agent->CurrentActionTime += deltaTime;
|
211 |
+
}
|
212 |
+
|
213 |
+
if (currentGoal != null)
|
214 |
+
{
|
215 |
+
agent->CurrentGoalTime += deltaTime;
|
216 |
+
}
|
217 |
+
}
|
218 |
+
|
219 |
+
private static void StopCurrentAction(Frame frame, GOAPEntityContext context, ref GOAPAction currentAction)
|
220 |
+
{
|
221 |
+
if (currentAction == null)
|
222 |
+
return;
|
223 |
+
|
224 |
+
if (context.Agent->Plan[context.Agent->CurrentActionIndex] != currentAction)
|
225 |
+
{
|
226 |
+
Log.Error($"GOAP: Trying to stop action {currentAction.Path} that isn't currently active.");
|
227 |
+
return;
|
228 |
+
}
|
229 |
+
|
230 |
+
currentAction.Deactivate(frame, context);
|
231 |
+
context.Agent->LastProcessedActionIndex = context.Agent->CurrentActionIndex;
|
232 |
+
|
233 |
+
if (context.Entity == DebugEntity)
|
234 |
+
{
|
235 |
+
Log.Info($"GOAP: Action {currentAction.Path} deactivated");
|
236 |
+
}
|
237 |
+
|
238 |
+
currentAction = null;
|
239 |
+
}
|
240 |
+
|
241 |
+
private static void StopCurrentGoal(Frame frame, GOAPEntityContext context, ref GOAPGoal currentGoal, ref GOAPAction currentAction)
|
242 |
+
{
|
243 |
+
var agent = context.Agent;
|
244 |
+
|
245 |
+
StopCurrentAction(frame, context, ref currentAction);
|
246 |
+
|
247 |
+
if (currentGoal != null)
|
248 |
+
{
|
249 |
+
currentGoal.Deactivate(frame, context);
|
250 |
+
|
251 |
+
if (context.Entity == DebugEntity)
|
252 |
+
{
|
253 |
+
Log.Info($"GOAP: Goal {currentGoal.Path} deactivated");
|
254 |
+
}
|
255 |
+
|
256 |
+
FP disableTime = currentGoal.GetDisableTime(frame, context);
|
257 |
+
if (disableTime > 0)
|
258 |
+
{
|
259 |
+
var disableTimes = frame.ResolveList(agent->GoalDisableTimes);
|
260 |
+
|
261 |
+
int goalIndex = Array.IndexOf(context.Root.Goals, currentGoal);
|
262 |
+
if (goalIndex >= 0)
|
263 |
+
{
|
264 |
+
disableTimes[goalIndex] = disableTime;
|
265 |
+
}
|
266 |
+
}
|
267 |
+
}
|
268 |
+
|
269 |
+
agent->CurrentActionIndex = -1;
|
270 |
+
agent->LastProcessedActionIndex = -1;
|
271 |
+
agent->CurrentActionTime = 0;
|
272 |
+
|
273 |
+
agent->CurrentPlanSize = 0;
|
274 |
+
agent->CurrentGoal = default;
|
275 |
+
agent->CurrentGoalTime = 0;
|
276 |
+
|
277 |
+
currentGoal = null;
|
278 |
+
currentAction = null;
|
279 |
+
}
|
280 |
+
|
281 |
+
private static void FindNewGoal(Frame frame, GOAPEntityContext context, ref GOAPGoal currentGoal, ref GOAPAction currentAction)
|
282 |
+
{
|
283 |
+
var agent = context.Agent;
|
284 |
+
var goals = context.Root.Goals;
|
285 |
+
|
286 |
+
GOAPGoal bestGoal = null;
|
287 |
+
FP bestRelevancy = FP.MinValue;
|
288 |
+
|
289 |
+
var disableTimes = frame.ResolveList(agent->GoalDisableTimes);
|
290 |
+
for (int i = 0; i < goals.Length; i++)
|
291 |
+
{
|
292 |
+
if (disableTimes[i] > 0)
|
293 |
+
continue;
|
294 |
+
|
295 |
+
var goal = goals[i];
|
296 |
+
|
297 |
+
var startState = agent->CurrentState;
|
298 |
+
startState.Merge(goal.StartState);
|
299 |
+
|
300 |
+
if (startState.Contains(goal.TargetState) == true)
|
301 |
+
continue; // Goal is satisfied
|
302 |
+
|
303 |
+
FP relevancy = goal.GetRelevancy(frame, context);
|
304 |
+
|
305 |
+
if (relevancy <= 0)
|
306 |
+
continue;
|
307 |
+
|
308 |
+
if (relevancy > bestRelevancy)
|
309 |
+
{
|
310 |
+
bestRelevancy = relevancy;
|
311 |
+
bestGoal = goal;
|
312 |
+
}
|
313 |
+
}
|
314 |
+
|
315 |
+
// Reset interruption timer
|
316 |
+
agent->InterruptionCheckCooldown = context.Root.InterruptionCheckInterval;
|
317 |
+
|
318 |
+
if (bestGoal == null || bestGoal == currentGoal)
|
319 |
+
return;
|
320 |
+
|
321 |
+
bool debug = context.Entity == DebugEntity;
|
322 |
+
|
323 |
+
if (debug == true)
|
324 |
+
{
|
325 |
+
Log.Info($"GOAP: New best goal found: {bestGoal.Path}");
|
326 |
+
}
|
327 |
+
|
328 |
+
GOAPState currentState = agent->CurrentState;
|
329 |
+
GOAPState targetState = default;
|
330 |
+
|
331 |
+
bestGoal.InitPlanning(frame, context, ref currentState, ref targetState);
|
332 |
+
|
333 |
+
var aStar = Pool<GOAPAStar>.Get();
|
334 |
+
List<GOAPAction> plan = null;
|
335 |
+
|
336 |
+
if (debug == true)
|
337 |
+
{
|
338 |
+
using (new StopwatchBlock("GOAP: Backward A* search"))
|
339 |
+
{
|
340 |
+
plan = aStar.Run(frame, context, currentState, targetState, bestGoal, context.Root.Actions, _heuristicCost, Constants.MAX_PLAN_SIZE);
|
341 |
+
}
|
342 |
+
|
343 |
+
Log.Info($"GOAP: Search data - {aStar.Statistics.ToString()}");
|
344 |
+
}
|
345 |
+
else
|
346 |
+
{
|
347 |
+
plan = aStar.Run(frame, context, currentState, targetState, bestGoal, context.Root.Actions, _heuristicCost, Constants.MAX_PLAN_SIZE);
|
348 |
+
}
|
349 |
+
|
350 |
+
if (plan == null)
|
351 |
+
{
|
352 |
+
if (debug == true)
|
353 |
+
{
|
354 |
+
Log.Info($"GOAP: Failed to find plan for goal {bestGoal.Path}");
|
355 |
+
}
|
356 |
+
|
357 |
+
int goalIndex = Array.IndexOf(goals, bestGoal);
|
358 |
+
// Ensure there will be at least one planning without this failed goal
|
359 |
+
disableTimes[goalIndex] = FPMath.Max(FP._0_50, agent->InterruptionCheckCooldown + FP._0_10);
|
360 |
+
|
361 |
+
Pool<GOAPAStar>.Return(aStar);
|
362 |
+
|
363 |
+
return;
|
364 |
+
}
|
365 |
+
|
366 |
+
if (currentGoal != null)
|
367 |
+
{
|
368 |
+
StopCurrentGoal(frame, context, ref currentGoal, ref currentAction);
|
369 |
+
}
|
370 |
+
|
371 |
+
agent->CurrentGoal = bestGoal;
|
372 |
+
agent->CurrentGoalTime = 0;
|
373 |
+
agent->CurrentState = currentState;
|
374 |
+
agent->GoalState = targetState;
|
375 |
+
|
376 |
+
agent->CurrentActionIndex = -1;
|
377 |
+
agent->LastProcessedActionIndex = -1;
|
378 |
+
agent->CurrentActionTime = 0;
|
379 |
+
agent->CurrentPlanSize = 0;
|
380 |
+
|
381 |
+
currentGoal = bestGoal;
|
382 |
+
currentAction = null;
|
383 |
+
|
384 |
+
for (int i = 0; i < plan.Count; i++)
|
385 |
+
{
|
386 |
+
var action = plan[i];
|
387 |
+
if (action == null)
|
388 |
+
break;
|
389 |
+
|
390 |
+
*agent->Plan.GetPointer(i) = action;
|
391 |
+
agent->CurrentPlanSize++;
|
392 |
+
}
|
393 |
+
|
394 |
+
if (debug == true)
|
395 |
+
{
|
396 |
+
var planInfo = $"GOAP: Plan FOUND. Size: {agent->CurrentPlanSize} More...";
|
397 |
+
for (int i = 0; i < agent->CurrentPlanSize; i++)
|
398 |
+
{
|
399 |
+
planInfo += $"\nAction {i + 1}: {plan[i].Path}";
|
400 |
+
}
|
401 |
+
|
402 |
+
Log.Info(planInfo);
|
403 |
+
}
|
404 |
+
|
405 |
+
currentGoal.Activate(frame, context);
|
406 |
+
|
407 |
+
if (debug == true)
|
408 |
+
{
|
409 |
+
Log.Info($"GOAP: Goal {currentGoal.Path} activated");
|
410 |
+
}
|
411 |
+
|
412 |
+
// Plan object is part of pooled GOAPAStar object
|
413 |
+
// so GOAPAStar needs to be returned after plan is no longer needed
|
414 |
+
Pool<GOAPAStar>.Return(aStar);
|
415 |
+
}
|
416 |
+
|
417 |
+
private static GOAPAction GetCurrentAction(Frame frame, GOAPAgent* agent)
|
418 |
+
{
|
419 |
+
if (agent->CurrentActionIndex < 0)
|
420 |
+
return null;
|
421 |
+
|
422 |
+
if (agent->LastProcessedActionIndex >= agent->CurrentActionIndex)
|
423 |
+
return null;
|
424 |
+
|
425 |
+
return frame.FindAsset<GOAPAction>(agent->Plan[agent->CurrentActionIndex].Id);
|
426 |
+
}
|
427 |
+
|
428 |
+
private static GOAPEntityContext GetContext(Frame frame, EntityRef entity)
|
429 |
+
{
|
430 |
+
var context = Pool<GOAPEntityContext>.Get();
|
431 |
+
|
432 |
+
context.Entity = entity;
|
433 |
+
context.Agent = frame.Unsafe.GetPointer<GOAPAgent>(entity);
|
434 |
+
context.Blackboard = frame.Has<AIBlackboardComponent>(entity) ? frame.Unsafe.GetPointer<AIBlackboardComponent>(entity) : null;
|
435 |
+
context.Root = frame.FindAsset<GOAPRoot>(context.Agent->Root.Id);
|
436 |
+
context.Config = frame.FindAsset<AIConfig>(context.Agent->Config.Id);
|
437 |
+
|
438 |
+
return context;
|
439 |
+
}
|
440 |
+
}
|
441 |
+
|
442 |
+
public unsafe class GOAPEntityContext
|
443 |
+
{
|
444 |
+
public EntityRef Entity;
|
445 |
+
public GOAPAgent* Agent;
|
446 |
+
public GOAPRoot Root;
|
447 |
+
public AIConfig Config;
|
448 |
+
public AIBlackboardComponent* Blackboard;
|
449 |
+
}
|
450 |
+
}
|