1010import org .jspecify .annotations .Nullable ;
1111
1212import java .util .List ;
13+ import java .util .Objects ;
1314import java .util .Set ;
1415import java .util .concurrent .ConcurrentLinkedQueue ;
1516import java .util .function .Supplier ;
1617
1718/**
1819 * I'll be using this to represent a path that not be processed yet!
1920 */
20- public class AsyncPath extends Path {
21+ public final class AsyncPath extends Path implements Runnable {
2122
22- /**
23- * Instead of three states, only one is actually required
24- * This will update when any thread is done with the path
25- */
26- private volatile boolean ready = false ;
23+ private boolean ready = false ;
2724
2825 /**
2926 * Runnable waiting for this to be processed
@@ -36,19 +33,9 @@ public class AsyncPath extends Path {
3633 */
3734 private final Set <BlockPos > positions ;
3835
39- /**
40- * The supplier of the real processed path
41- */
42- private final Supplier <Path > pathSupplier ;
43-
44- /*
45- * Processed values
46- */
36+ private @ Nullable Supplier <Path > task ;
37+ private volatile @ Nullable Path ret ;
4738
48- /**
49- * This is a reference to the nodes list in the parent `Path` object
50- */
51- private final List <Node > nodes ;
5239 /**
5340 * The block we're trying to path to
5441 * <p>
@@ -72,13 +59,20 @@ public class AsyncPath extends Path {
7259 public AsyncPath (List <Node > emptyNodeList , Set <BlockPos > positions , Supplier <Path > pathSupplier ) {
7360 super (emptyNodeList , null , false );
7461
75- this .nodes = emptyNodeList ;
7662 this .positions = positions ;
77- this .pathSupplier = pathSupplier ;
63+ this .task = pathSupplier ;
7864
7965 AsyncPathProcessor .queue (this );
8066 }
8167
68+ @ Override
69+ public void run () {
70+ Supplier <Path > task = this .task ;
71+ if (task != null ) {
72+ this .ret = task .get ();
73+ }
74+ }
75+
8276 @ Override
8377 public boolean isProcessed () {
8478 return this .ready ;
@@ -92,9 +86,6 @@ public final void schedulePostProcessing(Runnable runnable) {
9286 runnable .run ();
9387 } else {
9488 this .postProcessing .offer (runnable );
95- if (this .ready ) {
96- this .runAllPostProcessing (true );
97- }
9889 }
9990 }
10091
@@ -105,34 +96,31 @@ public final void schedulePostProcessing(Runnable runnable) {
10596 * @return true if we are processing the same positions
10697 */
10798 public final boolean hasSameProcessingPositions (final Set <BlockPos > positions ) {
108- if (this .positions .size () != positions .size ()) {
109- return false ;
110- }
111-
112- // For single position (common case), do direct comparison
113- if (positions .size () == 1 ) { // Both have the same size at this point
114- return this .positions .iterator ().next ().equals (positions .iterator ().next ());
115- }
116-
117- return this .positions .containsAll (positions );
99+ return this .positions .equals (positions );
118100 }
119101
120102 /**
121103 * Starts processing this path
122104 * Since this is no longer a synchronized function, checkProcessed is no longer required
123105 */
124- public final void process () {
125- if (this .ready ) return ;
126-
127- synchronized (this ) {
128- if (this .ready ) return ; // In the worst case, the main thread only waits until any async thread is done and returns immediately
129- final Path bestPath = this .pathSupplier .get ();
130- this .nodes .addAll (bestPath .nodes ); // We mutate this list to reuse the logic in Path
131- this .target = bestPath .getTarget ();
132- this .distToTarget = bestPath .getDistToTarget ();
133- this .canReach = bestPath .canReach ();
134- this .ready = true ;
106+ private final void process () {
107+ if (this .ready ) {
108+ return ;
135109 }
110+ final Path ret = this .ret ;
111+ final Supplier <Path > task = this .task ;
112+ final Path bestPath = ret != null ? ret : Objects .requireNonNull (task ).get ();
113+ complete (bestPath );
114+ }
115+
116+ // not this.ready
117+ private final void complete (Path bestPath ) {
118+ this .nodes = bestPath .nodes ;
119+ this .target = bestPath .getTarget ();
120+ this .distToTarget = bestPath .getDistToTarget ();
121+ this .canReach = bestPath .canReach ();
122+ this .task = null ;
123+ this .ready = true ;
136124
137125 this .runAllPostProcessing (TickThread .isTickThread ());
138126 }
@@ -176,7 +164,14 @@ public boolean canReach() {
176164
177165 @ Override
178166 public boolean isDone () {
179- return this .ready && super .isDone ();
167+ boolean ready = this .ready ;
168+ if (!ready ) {
169+ Path ret = this .ret ;
170+ if (ret != null ) {
171+ complete (ret );
172+ }
173+ }
174+ return ready && super .isDone ();
180175 }
181176
182177 @ Override
0 commit comments