Skip to content

Commit 01282b6

Browse files
authored
Merge pull request #41 from cmwedin/Development-Branch
1.0.0 Release
2 parents 0b6a71c + d37dae8 commit 01282b6

File tree

15 files changed

+169
-105
lines changed

15 files changed

+169
-105
lines changed
15.6 KB
Binary file not shown.

README.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ This package contains a collection of classes and interfaces to allow for quick
33

44
## Installation
55
### Through GitHub (Recommended)
6+
#### Stable Installation
67
To install this package in your Unity project, select the "window/Package Manager" entry in the Unity Inspector toolbar. Then, select the "+" icon in the upper left corner of the opened window, and select "Add package from git url." Paste the following:
78

89
https://github.com/cmwedin/CommandPattern.git
@@ -11,22 +12,29 @@ Once you see this package show up in the Package Manager window, it has been suc
1112

1213
You can automatically update the package by clicking the "update," button in the bottom right corner of the package manager window. This will retrieve any changes on main branch on this repository since installation or your last update.
1314

14-
#### Advanced installation (Not Recommended)
15+
#### Bleeding-Edge Installation
1516
You can install the experimental version of this package instead by adding #Development-Branch to the end of the Github url above. This will make your installation use the most up to date version possible, even before changes are merged onto the main branch.
1617

1718
### Through Itch.io
18-
**This package will be available on Itch.io after 1.0.0 is released in the coming days, this section is currently a placeholder**
19+
When installing this package through Itch.io you will need to update the package manually. There are two methods to download the package through Itch, you can either install it with the rest of your packages, leaving your asset folder less cluttered, but preventing modifications to the packages files; or you can install it as an asset, placing all of the scripts within your asset folder and allowing you to modify them. Modifications to this packages scripts are recommended only for user very confident in what they are doing.
1920

20-
Download this package's archive from its Itch.io page [here](https://github.com/cmwedin/CommandPattern) **(link currently a placeholder)**. Once downloaded, extract the folder contained within to your desired installation location for the package. Note that deleting this folder will break your package installation, even after adding the package to a unity project.
21+
#### Installing as a Package
22+
Download this package's archive from its <a href="https://sadsapphic.itch.io/command-pattern" target="_blank">Itch.io page</a>. Once downloaded, extract the "CommandPattern" folder contained within to your desired installation location. Note that deleting this folder will break your package installation, even after adding the package to a Unity project.
2123

2224
After you have downloaded and unzipped the package, open the Unity project you wish to add this package too. Open the package manager window, and select the "+" icon in the upper left corner. Then, select the "Add package from disk" option. Navigate to your installation location and select the "package.json" file. Once you see this package show up in the Package Manager window, it has been successfully installed.
2325

24-
**Note that installing the package through this method will require you to update it manually**
26+
#### Installing as an Asset
27+
Download the .unitypackage file from this packages <a href="https://sadsapphic.itch.io/command-pattern" target="_blank">Itch.io page</a>. Once downloaded, open the Unity project you wish to add this package to. Select "Assets" from the Unity Editor's toolbar, an from the "Import Package" menu select "Custom Package". In the window that pops up navigate to the .unitypackage file you downloaded and select it. The package will be added to your assets folder in the "/Packages/CommandPattern/" directory.
2528

26-
**The above process is a placeholder and may be changed before the release of version 1.0.0 and upload to Itch.io**
29+
### Updating the Package
30+
If you installed the package through GitHub, you can automatically update it to its newest version by clicking the "update" button in the bottom right corner of its entry in the package manager window. If not, you will need to update it manually. In addition, there may be steps needed to migrate your code to the newer version of the package. If there are, these will be added to this section when the update has been released.
31+
#### Manual Updating as a package
32+
If you installed the package using the local package installation through the Unity package manager to update it you will need to download the archive for the updated version from the packages Itch.io page. Once you've done this, remove the old package in the package manager, delete the old installation and extract the inner folder from the new archive. If you plan to install the updated package with the same path, you may be able to skip removing the old package, but it is recommended you do so regardless. Once you have completed this, add the updated version of the package through the same installation progress you followed above.
33+
#### Manual Updating as an Asset
34+
If you installed the package as an asset using the .unitypackage file, simply download the updated .unitypackage file, delete you old installation in your assets folder, and follow the installation process above using the new .unitypackage file.
2735

2836
### Installing the Package Demo
29-
This package includes a demo showcasing how to use the command pattern along with many scripts you may find helpful to reference when implementing your own commands. Once the package is installed, this demo can easily be added by opening the "Samples" dropdown, and clicking the "import" button next to the "Simple Demo" entry. Once this demo has been imported, you can open it by navigating to the newly created "Samples/CommandPattern/[Current Version]/SimpleDemo" folder and opening the "SimpleDemo.Unity" scene. You may need to enter play-mode and resize your game window for the scene's ui elements to display properly.
37+
This package includes a demo showcasing how to use the command pattern along with many scripts you may find helpful to reference when implementing your own commands. If you installed the package as an asset the demo will be included by default within the "Demos/SimpleDemo" directory. Once the package is installed, this demo can easily be added by opening the "Samples" dropdown, and clicking the "import" button next to the "Simple Demo" entry. Once this demo has been imported, you can open it by navigating to the newly created "Samples/CommandPattern/[Current Version]/SimpleDemo" folder and opening the "SimpleDemo.Unity" scene. You may need to enter play-mode and resize your game window for the scene's ui elements to display properly.
3038

3139
## Using this package
3240
Full documentation of this package can be found [here](https://cmwedin.github.io/CommandPatternDocumentation/annotated.html)

Runtime/Commands/CommandStream.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ public CancellationTokenSource GetRunningTaskCTS(Task task) {
125125
return null;
126126
}
127127
}
128+
/// <summary>
129+
/// Gets the CancellationTokenSource of a running AsyncCommand's task
130+
/// </summary>
131+
/// <param name="task">The AsyncCommand to get the CTS of</param>
132+
/// <returns>The CTS of task if it is running, null if it is not</returns>
128133
public CancellationTokenSource GetRunningTaskCTS(IAsyncCommand asyncCommand) {
129134
return GetRunningTaskCTS(asyncCommand.CommandTask);
130135
}

Runtime/Monobehaviours/SingletonCommandManager.cs

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
using System;
12
using System.Collections;
23
using System.Collections.Generic;
34
using System.Collections.ObjectModel;
5+
using System.Threading;
46
using System.Threading.Tasks;
57
using UnityEngine;
68

@@ -32,6 +34,10 @@ public class SingletonCommandManager : MonoBehaviour
3234
/// </summary>
3335
private bool freezeCommandExecution = false;
3436
/// <summary>
37+
/// Invoked when the inner CommandStream invokes its OnTaskFaulted event
38+
/// </summary>
39+
public event Action<Exception> OnTaskFaulted;
40+
/// <summary>
3541
/// Turns command execution off if its on and on if its off
3642
/// </summary>
3743
public void ToggleCommandExecution()
@@ -61,6 +67,22 @@ public ReadOnlyCollection<Task> GetRunningCommandTasks() {
6167
return commandStream.GetRunningCommandTasks();
6268
}
6369
/// <summary>
70+
/// Gets the CancellationTokenSource of a running AsyncCommand's task
71+
/// </summary>
72+
/// <param name="task">The task to get the CTS of</param>
73+
/// <returns>The CTS of task if it is running, null if it is not</returns>
74+
public CancellationTokenSource GetRunningTaskCTS(Task task){
75+
return commandStream.GetRunningTaskCTS(task);
76+
}
77+
/// <summary>
78+
/// Gets the CancellationTokenSource of a running AsyncCommand's task
79+
/// </summary>
80+
/// <param name="task">The AsyncCommand to get the CTS of</param>
81+
/// <returns>The CTS of task if it is running, null if it is not</returns>
82+
public CancellationTokenSource GetRunningTaskCTS(IAsyncCommand asyncCommand){
83+
return commandStream.GetRunningTaskCTS(asyncCommand);
84+
}
85+
/// <summary>
6486
/// Cancels an AsyncCommand's running task through a reference to the task
6587
/// </summary>
6688
/// <param name="taskToCancel">the task of an AsyncCommand to cancel</param>
@@ -75,13 +97,27 @@ public void CancelRunningCommandTask(IAsyncCommand asyncCommand) {
7597
commandStream.CancelRunningCommandTask(asyncCommand);
7698
}
7799
/// <summary>
100+
/// Get a dictionary of any faulted tasks and the exceptions that they threw
101+
/// </summary>
102+
/// <returns> A read only copy of the dictionary of faulted tasks and their exceptions </returns>
103+
public ReadOnlyDictionary<Task, Exception> GetFaultedCommandTasks() {
104+
return commandStream.GetFaultedCommandTasks();
105+
}
106+
/// <summary>
78107
/// Empties the history of the internal CommandStream and replaces it with an empty one.
79108
/// </summary>
80109
/// <returns> The old history of the internal CommandStream </returns>
81-
public ReadOnlyCollection<ICommand> DropCommandHistory() {
110+
public ReadOnlyCollection<ICommand> DropHistory() {
82111
return commandStream.DropHistory();
83112
}
84-
113+
/// <summary>
114+
/// This will remove all commands from the CommandStream's queue and replace it with a new empty queue.
115+
/// </summary>
116+
/// <remark> This can be useful to rearrange the commands in a queue. Simple preform the needed changes on the returned list and re-queue it </remark>
117+
/// <returns> The commands in the previous queue, in case this information is needed.</returns>
118+
public List<ICommand> DropQueue() {
119+
return commandStream.DropQueue();
120+
}
85121
/// <summary>
86122
/// The number of Commands recorded by the CommandManager's CommandStream
87123
/// </summary>
@@ -137,6 +173,50 @@ public void ForceQueueUndoCommand(IUndoable commandToUndo) {
137173
commandStream.ForceQueueUndoCommand(commandToUndo);
138174
}
139175
/// <summary>
176+
/// Examine the next command in the CommandStream's commandQueue with out executing it
177+
/// </summary>
178+
/// <param name="nextCommand">The next command in the queue, null if empty</param>
179+
/// <returns>Wether there was a command in queue or not</returns>
180+
public bool TryPeekNext(out ICommand nextCommand) {
181+
return commandStream.TryPeekNext(out nextCommand);
182+
}
183+
/// <summary>
184+
/// Removes the next command in the CommandStream's queue, if it has one, and adds it back to the end of the queue.
185+
/// </summary>
186+
public void RequeueNextCommand() {
187+
commandStream.RequeueNextCommand();
188+
}
189+
/// <summary>
190+
/// Removes the next command from the CommandStream's queue without executing it
191+
/// </summary>
192+
public void SkipNextCommand(){
193+
commandStream.SkipNextCommand();
194+
}
195+
/// <summary>
196+
/// Bypass the CommandStream's queue and immediately attempt to execute a command
197+
/// </summary>
198+
/// <param name="command">The command to immediately be executed</param>
199+
/// <returns>The ExecuteCode for the attempt to execute the command</returns>
200+
public ExecuteCode TryExecuteImmediate(ICommand command) {
201+
return commandStream.TryExecuteImmediate(command);
202+
}
203+
/// <summary>
204+
/// Bypass the CommandStream's queue and immediately attempt to execute an IUndoable's undo command if the IUndoable is in the CommandStream's history
205+
/// </summary>
206+
/// <param name="undoable">the IUndoable to execute the undo command of</param>
207+
/// <returns>The ExecuteCode of the attempt to execute the undo command of the IUndoable, Execute.Failure if the IUndoable was not in the CommandStream's history </returns>
208+
public ExecuteCode TryUndoImmediate(IUndoable undoable) {
209+
return commandStream.TryUndoImmediate(undoable);
210+
}
211+
/// <summary>
212+
/// Bypass the command queue and immediately attempt to execute an IUndoable's undo command, regardless of wether the IUndoable is in the CommandStream's history
213+
/// </summary>
214+
/// <param name="undoable">the IUndoable to execute the undo command of</param>
215+
/// <returns>The ExecuteCode of the attempt to execute the undo command of the IUndoable</returns>
216+
public ExecuteCode ForceTryUndoImmediate(IUndoable undoable) {
217+
return commandStream.ForceTryUndoImmediate(undoable);
218+
}
219+
/// <summary>
140220
/// sets the singleton instance of this object
141221
/// </summary>
142222
private void Awake() {
@@ -155,8 +235,8 @@ void Start() {
155235
} else {
156236
commandStream = new CommandStream();
157237
}
238+
commandStream.OnTaskFaulted += (ex) => OnTaskFaulted.Invoke(ex);
158239
}
159-
160240
/// <summary>
161241
/// Executes the next command in queue if it isn't empty and command execution isn't frozen
162242
/// </summary>

Samples~/SimpleDemo/DemoScripts/InputPanel/LinearProj.cs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,27 +10,16 @@ namespace SadSapphicGames.CommandPattern.SimpleDemo
1010
public class LinearProj : ProjSO
1111
{
1212
/// <summary>
13-
/// the maximum y value the projectile can reach before being destroyed
14-
/// </summary>
15-
private float yMax;
16-
/// <summary>
17-
/// a property to set yMax based on the bounds of a RectTransform
18-
/// </summary>
19-
public override RectTransform BoundingBox { set {
20-
Vector3[] corners = new Vector3[4];
21-
value.GetWorldCorners(corners);
22-
yMax = corners[1].y;
23-
}}
24-
/// <summary>
2513
/// Updates the y value of the position to be a distance above the current position's y value based on this scriptable objects set speed
2614
/// </summary>
2715
/// <remark> unused parameters exclude </remark>
2816
/// <param name="currentPos">the current position of the projectile</param>
2917
/// <returns>The new position of the projectile</returns>
30-
public override Vector3 UpdatePosition(Vector3 currentPos, Vector3 origin, Vector3 prevDirection, out Vector3 nextDirection) {
18+
public override Vector3 UpdatePosition(Vector3 currentPos, Vector3 origin, RectTransform boundsRect, Vector3 prevDirection, out Vector3 nextDirection) {
19+
ProjBounds bounds = new ProjBounds(boundsRect);
3120
float targetY = currentPos.y + speed * Time.fixedDeltaTime;
3221
nextDirection = Vector3.up;
33-
if (targetY <= yMax) {
22+
if (targetY <= bounds.yMax) {
3423
return new Vector3(currentPos.x, targetY, currentPos.z);
3524
} else {
3625
return Vector3.zero;

Samples~/SimpleDemo/DemoScripts/InputPanel/Player.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,6 @@ void Update()
9191
) {
9292
inputCommandStream.QueueCommand(new SpawnProjectileCommand(this, altProjType,projMaxLifespan));
9393
}
94-
95-
if (Input.GetKey(inputCommandStream.InputKeybinds[InputType.Undo]))
96-
{
97-
inputCommandStream.Undo();
98-
}
9994
}
10095
}
10196
/// <summary>
@@ -111,6 +106,10 @@ private void FixedUpdate() {
111106
inputCommandStream.QueueCommand(new MovePlayerCommand(this, movementVector, baseSpeed));
112107
}
113108
}
109+
if (Input.GetKey(inputCommandStream.InputKeybinds[InputType.Undo]))
110+
{
111+
inputCommandStream.Undo();
112+
}
114113
}
115114

116115
}

Samples~/SimpleDemo/DemoScripts/InputPanel/ProjSO.cs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,40 @@ namespace SadSapphicGames.CommandPattern.SimpleDemo
88
/// The base scriptable object for the data of projectile behavior
99
/// </summary>
1010
public abstract class ProjSO : ScriptableObject {
11+
/// <summary>
12+
/// The bounds of a projectile
13+
/// </summary>
14+
protected struct ProjBounds {
15+
/// <summary>
16+
/// The max x position
17+
/// </summary>
18+
public float xMax;
19+
/// <summary>
20+
/// The max y position
21+
/// </summary>
22+
public float yMax;
23+
/// <summary>
24+
/// The min x position
25+
/// </summary>
26+
public float xMin;
27+
/// <summary>
28+
/// The min y position
29+
/// </summary>
30+
public float yMin;
31+
32+
/// <summary>
33+
/// Constructs a ProjBounds struct from a rect transform
34+
/// </summary>
35+
/// <param name="rectTransform"></param>
36+
public ProjBounds(RectTransform rectTransform)
37+
{
38+
var corners = rectTransform.GetWorldCorners();
39+
xMax = corners[2].x;
40+
yMax = corners[2].y;
41+
xMin = corners[0].x;
42+
yMin = corners[0].y;
43+
}
44+
}
1145
/// <summary>
1246
/// The prefab object to instantiate as the visual base for the projectile
1347
/// </summary>
@@ -18,11 +52,6 @@ public abstract class ProjSO : ScriptableObject {
1852
/// </summary>
1953
[SerializeField] protected float speed;
2054

21-
/// <summary>
22-
/// The box that should bound the projectiles movement
23-
/// </summary>
24-
public abstract RectTransform BoundingBox { set; }
25-
2655
/// <summary>
2756
/// Invoked in the projectile FixedUpdate method to determine where it should move to next based on where it currently is, where it started, and what direction it was last moving in
2857
/// Some projectile types may not use all of this information
@@ -32,7 +61,7 @@ public abstract class ProjSO : ScriptableObject {
3261
/// <param name="prevDirection">the previous direction the projectile moved in</param>
3362
/// <param name="newDirection">the direction the projectile is moving in now</param>
3463
/// <returns> The new position of the projectile </returns>
35-
public abstract Vector3 UpdatePosition(Vector3 currentPos, Vector3 origin, Vector3 prevDirection, out Vector3 newDirection);
64+
public abstract Vector3 UpdatePosition(Vector3 currentPos, Vector3 origin, RectTransform rectBounds, Vector3 prevDirection, out Vector3 newDirection);
3665

3766
}
3867
}

Samples~/SimpleDemo/DemoScripts/InputPanel/Projectile.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ public class Projectile : MonoBehaviour
1818
/// </summary>
1919
private ProjSO data;
2020
/// <summary>
21+
/// The RectTransform the projectile can move within
22+
/// </summary>
23+
public RectTransform rectBounds { get; set; }
24+
/// <summary>
2125
/// The starting position of the projectile, relevant for some projectile types
2226
/// </summary>
2327
public Vector3 Origin { get; set; }
@@ -55,7 +59,7 @@ void FixedUpdate()
5559
{
5660
if (data == null) { Destroy(gameObject); }
5761
Destroy(gameObject, Lifespan);
58-
Vector3 target = data.UpdatePosition(transform.position, Origin, prevDirection, out prevDirection);
62+
Vector3 target = data.UpdatePosition(transform.position, Origin, rectBounds,prevDirection, out prevDirection);
5963
if (target == Vector3.zero)
6064
{
6165
Destroy(gameObject);

0 commit comments

Comments
 (0)