Skip to content

Commit

Permalink
Clean up, doc comments
Browse files Browse the repository at this point in the history
  • Loading branch information
legobmw99 committed Jan 21, 2024
1 parent abc8b59 commit c8d1ee3
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.legobmw99.allomancy.modules.powers.PowerUtils;
import com.legobmw99.allomancy.modules.powers.PowersConfig;
import com.legobmw99.allomancy.modules.powers.data.AllomancerAttachment;
import com.legobmw99.allomancy.util.SyncList;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import net.minecraft.Util;
import net.minecraft.client.Minecraft;
Expand All @@ -17,16 +18,11 @@
import net.minecraft.world.phys.Vec3;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;

public class SensoryTracking {


private final List<Entity> metal_entities = new ArrayList<>();
private final SyncList<MetalBlockBlob> metal_blobs = new SyncList<>();
private final List<Player> nearby_allomancers = new ArrayList<>();
Expand Down Expand Up @@ -143,79 +139,13 @@ private boolean addSeeked(IAllomancerData data, Player otherPlayer) {
return true;
}


private static class SyncList<T> {
private final List<T> list_a = new ArrayList<>();
private final List<T> list_b = new ArrayList<>();

private final Lock swapLock = new ReentrantLock();

/**
* When this is even, we are reading A and writing B
*/
private final AtomicInteger AorB = new AtomicInteger(0);


/**
* Intended to be invoked from the main thread
*/
public void forEach(Consumer<T> f) {
this.swapLock.lock();
try {
if (this.AorB.get() % 2 == 0) {
this.list_a.forEach(f);
} else {
this.list_b.forEach(f);
}
} finally {
this.swapLock.unlock();
}
}

public void add(T t) {
if (this.AorB.get() % 2 == 1) {
this.list_a.add(t);
} else {
this.list_b.add(t);
}
}


/**
* Intended to be invoked from a thread other than main
*/
public void swapAndClearOld() {
this.swapLock.lock();
int newAB = this.AorB.incrementAndGet();
this.swapLock.unlock();
if (newAB % 2 == 1) {
this.list_a.clear();
} else {
this.list_b.clear();
}
}

public void clearBothAsync(ExecutorService ex) {
ex.submit(() -> {
this.swapLock.lock();
try {
this.list_a.clear();
this.list_b.clear();
} finally {
this.swapLock.unlock();
}
});
}
}


public static class MetalBlockBlob {

private static final Level level = Minecraft.getInstance().level;
private int blocks;
private Vec3 center;

public MetalBlockBlob(BlockPos initial, BlockState initialState) {
private MetalBlockBlob(BlockPos initial, BlockState initialState) {
this.blocks = 1;
this.center = getCenterOfBlock(initial, initialState);
}
Expand All @@ -232,7 +162,7 @@ public int size() {
return this.blocks;
}

public void add(BlockPos pos, BlockState state) {
private void add(BlockPos pos, BlockState state) {
this.blocks += 1;
this.center = this.center.scale(this.blocks - 1).add(getCenterOfBlock(pos, state)).scale(1.0D / this.blocks);
}
Expand Down
87 changes: 87 additions & 0 deletions src/main/java/com/legobmw99/allomancy/util/SyncList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package com.legobmw99.allomancy.util;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;

/**
* A wrapper around 2 array lists that allows "concurrent" modification
* while maintaining very fast reads at the cost of slower/buffered writes.
* Writes are issued to a list which is not currently a candidate for iteration,
* and on demand this list is swapped in. The lock required to swap is only held
* for the length of one atomic integer increment.
*/
public class SyncList<T> {
private final List<T> list_a = new ArrayList<>();
private final List<T> list_b = new ArrayList<>();

private final Lock swapLock = new ReentrantLock();

/**
* When this is even, we are reading A and writing B
*/
private final AtomicInteger AorB = new AtomicInteger(0);

/**
* Intended to be invoked from the main thread.
* Holds a lock to prevent swapping for entire iteration duration.
* Writes will still proceed to the unobserved list.
*/
public void forEach(Consumer<T> f) {
this.swapLock.lock();
try {
if (this.AorB.get() % 2 == 0) {
this.list_a.forEach(f);
} else {
this.list_b.forEach(f);
}
} finally {
this.swapLock.unlock();
}
}

/**
* Write to the unobserved list.
* Nothing added here wil be visible until
* a swapAndClearOld is completed.
*/
public void add(T t) {
if (this.AorB.get() % 2 == 1) {
this.list_a.add(t);
} else {
this.list_b.add(t);
}
}

/**
* Swap which list is observable as soon as the lock can be acquired,
* and clear the now-unobserved list.
* Intended to be invoked from a thread other than main
*/
public void swapAndClearOld() {
this.swapLock.lock();
int newAB = this.AorB.incrementAndGet();
this.swapLock.unlock();
if (newAB % 2 == 1) {
this.list_a.clear();
} else {
this.list_b.clear();
}
}

public void clearBothAsync(ExecutorService ex) {
ex.submit(() -> {
this.swapLock.lock();
try {
this.list_a.clear();
this.list_b.clear();
} finally {
this.swapLock.unlock();
}
});
}
}

0 comments on commit c8d1ee3

Please sign in to comment.