mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-11-12 03:13:00 +00:00
Merge branch 'mc-1.20.x' into mc-1.20.y
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
package dan200.computercraft.client.sound;
|
||||
|
||||
import dan200.computercraft.shared.peripheral.speaker.EncodedAudio;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -16,7 +17,7 @@ public class DfpwmStreamTest {
|
||||
var stream = new DfpwmStream();
|
||||
|
||||
var input = ByteBuffer.wrap(new byte[]{ 43, -31, 33, 44, 30, -16, -85, 23, -3, -55, 46, -70, 68, -67, 74, -96, -68, 16, 94, -87, -5, 87, 11, -16, 19, 92, 85, -71, 126, 5, -84, 64, 17, -6, 85, -11, -1, -87, -12, 1, 85, -56, 33, -80, 82, 104, -93, 17, 126, 23, 91, -30, 37, -32, 117, -72, -58, 11, -76, 19, -108, 86, -65, -10, -1, -68, -25, 10, -46, 85, 124, -54, 15, -24, 43, -94, 117, 63, -36, 15, -6, 88, 87, -26, -83, 106, 41, 13, -28, -113, -10, -66, 119, -87, -113, 68, -55, 40, -107, 62, 20, 72, 3, -96, 114, -87, -2, 39, -104, 30, 20, 42, 84, 24, 47, 64, 43, 61, -35, 95, -65, 42, 61, 42, -50, 4, -9, 81 });
|
||||
stream.push(input);
|
||||
stream.push(new EncodedAudio(0, 0, false, input));
|
||||
|
||||
var buffer = stream.read(1024 + 1);
|
||||
assertEquals(1024, buffer.remaining(), "Must have read 1024 bytes");
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.impl.network.wired;
|
||||
|
||||
import dan200.computercraft.api.network.wired.WiredNetwork;
|
||||
import dan200.computercraft.impl.network.wired.NetworkTest.NetworkElement;
|
||||
import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import org.openjdk.jmh.annotations.*;
|
||||
import org.openjdk.jmh.runner.Runner;
|
||||
import org.openjdk.jmh.runner.RunnerException;
|
||||
import org.openjdk.jmh.runner.options.OptionsBuilder;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
public class NetworkBenchmark {
|
||||
private static final int BRUTE_SIZE = 16;
|
||||
|
||||
public static void main(String[] args) throws RunnerException {
|
||||
var opts = new OptionsBuilder()
|
||||
.include(NetworkBenchmark.class.getName() + "\\..*")
|
||||
.warmupIterations(2)
|
||||
.measurementIterations(5)
|
||||
.forks(1)
|
||||
.build();
|
||||
new Runner(opts).run();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@Warmup(time = 1, timeUnit = TimeUnit.SECONDS)
|
||||
@Measurement(time = 2, timeUnit = TimeUnit.SECONDS)
|
||||
public void removeEveryNode(ConnectedGrid grid) {
|
||||
grid.grid.forEach((node, pos) -> node.remove());
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@Warmup(time = 1, timeUnit = TimeUnit.SECONDS)
|
||||
@Measurement(time = 2, timeUnit = TimeUnit.SECONDS)
|
||||
public void connectAndDisconnect(SplitGrid connectedGrid) {
|
||||
WiredNodeImpl left = connectedGrid.left, right = connectedGrid.right;
|
||||
|
||||
assertNotEquals(left.getNetwork(), right.getNetwork());
|
||||
left.connectTo(right);
|
||||
assertEquals(left.getNetwork(), right.getNetwork());
|
||||
left.disconnectFrom(right);
|
||||
assertNotEquals(left.getNetwork(), right.getNetwork());
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
@Warmup(time = 1, timeUnit = TimeUnit.SECONDS)
|
||||
@Measurement(time = 2, timeUnit = TimeUnit.SECONDS)
|
||||
public void connectAndRemove(SplitGrid connectedGrid) {
|
||||
WiredNodeImpl left = connectedGrid.left, right = connectedGrid.right, centre = connectedGrid.centre;
|
||||
|
||||
assertNotEquals(left.getNetwork(), right.getNetwork());
|
||||
centre.connectTo(left);
|
||||
centre.connectTo(right);
|
||||
assertEquals(left.getNetwork(), right.getNetwork());
|
||||
centre.remove();
|
||||
assertNotEquals(left.getNetwork(), right.getNetwork());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a grid where all nodes are connected to their neighbours.
|
||||
*/
|
||||
@State(Scope.Thread)
|
||||
public static class ConnectedGrid {
|
||||
Grid<WiredNodeImpl> grid;
|
||||
|
||||
@Setup(Level.Invocation)
|
||||
public void setup() {
|
||||
var grid = this.grid = new Grid<>(BRUTE_SIZE);
|
||||
grid.map((existing, pos) -> new NetworkElement("n_" + pos, pos.getX() == pos.getY() && pos.getY() == pos.getZ()).getNode());
|
||||
|
||||
// Connect every node
|
||||
grid.forEach((node, pos) -> {
|
||||
for (var facing : DirectionUtil.FACINGS) {
|
||||
var other = grid.get(pos.relative(facing));
|
||||
if (other != null) node.connectTo(other);
|
||||
}
|
||||
});
|
||||
|
||||
var networks = countNetworks(grid);
|
||||
if (networks.size() != 1) throw new AssertionError("Expected exactly one network.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a grid where the nodes at {@code x < BRUTE_SIZE/2} and {@code x >= BRUTE_SIZE/2} are in separate networks,
|
||||
* but otherwise connected to their neighbours.
|
||||
*/
|
||||
@State(Scope.Thread)
|
||||
public static class SplitGrid {
|
||||
Grid<WiredNodeImpl> grid;
|
||||
WiredNodeImpl left, right, centre;
|
||||
|
||||
@Setup
|
||||
public void setup() {
|
||||
var grid = this.grid = new Grid<>(BRUTE_SIZE);
|
||||
grid.map((existing, pos) -> new NetworkElement("n_" + pos, pos.getX() == pos.getY() && pos.getY() == pos.getZ()).getNode());
|
||||
|
||||
// Connect every node
|
||||
grid.forEach((node, pos) -> {
|
||||
for (var facing : DirectionUtil.FACINGS) {
|
||||
var offset = pos.relative(facing);
|
||||
if (offset.getX() >= BRUTE_SIZE / 2 == pos.getX() >= BRUTE_SIZE / 2) {
|
||||
var other = grid.get(offset);
|
||||
if (other != null) node.connectTo(other);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var networks = countNetworks(grid);
|
||||
if (networks.size() != 2) throw new AssertionError("Expected exactly two networks.");
|
||||
for (var network : networks.object2IntEntrySet()) {
|
||||
if (network.getIntValue() != BRUTE_SIZE * BRUTE_SIZE * (BRUTE_SIZE / 2)) {
|
||||
throw new AssertionError("Network is the wrong size");
|
||||
}
|
||||
}
|
||||
|
||||
left = Objects.requireNonNull(grid.get(new BlockPos(BRUTE_SIZE / 2 - 1, 0, 0)));
|
||||
right = Objects.requireNonNull(grid.get(new BlockPos(BRUTE_SIZE / 2, 0, 0)));
|
||||
centre = new NetworkElement("c", false).getNode();
|
||||
}
|
||||
}
|
||||
|
||||
private static Object2IntMap<WiredNetwork> countNetworks(Grid<WiredNodeImpl> grid) {
|
||||
Object2IntMap<WiredNetwork> networks = new Object2IntOpenHashMap<>();
|
||||
grid.forEach((node, pos) -> networks.put(node.network, networks.getOrDefault(node.network, 0) + 1));
|
||||
return networks;
|
||||
}
|
||||
|
||||
private static class Grid<T> {
|
||||
private final int size;
|
||||
private final T[] box;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Grid(int size) {
|
||||
this.size = size;
|
||||
this.box = (T[]) new Object[size * size * size];
|
||||
}
|
||||
|
||||
public T get(BlockPos pos) {
|
||||
int x = pos.getX(), y = pos.getY(), z = pos.getZ();
|
||||
|
||||
return x >= 0 && x < size && y >= 0 && y < size && z >= 0 && z < size
|
||||
? box[x * size * size + y * size + z]
|
||||
: null;
|
||||
}
|
||||
|
||||
public void forEach(BiConsumer<T, BlockPos> transform) {
|
||||
for (var x = 0; x < size; x++) {
|
||||
for (var y = 0; y < size; y++) {
|
||||
for (var z = 0; z < size; z++) {
|
||||
transform.accept(box[x * size * size + y * size + z], new BlockPos(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void map(BiFunction<T, BlockPos, T> transform) {
|
||||
for (var x = 0; x < size; x++) {
|
||||
for (var y = 0; y < size; y++) {
|
||||
for (var z = 0; z < size; z++) {
|
||||
box[x * size * size + y * size + z] = transform.apply(box[x * size * size + y * size + z], new BlockPos(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,19 +9,14 @@ import dan200.computercraft.api.network.wired.WiredNetwork;
|
||||
import dan200.computercraft.api.network.wired.WiredNetworkChange;
|
||||
import dan200.computercraft.api.network.wired.WiredNode;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.util.DirectionUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@@ -29,11 +24,11 @@ public class NetworkTest {
|
||||
@Test
|
||||
public void testConnect() {
|
||||
NetworkElement
|
||||
aE = new NetworkElement(null, null, "a"),
|
||||
bE = new NetworkElement(null, null, "b"),
|
||||
cE = new NetworkElement(null, null, "c");
|
||||
aE = new NetworkElement("a"),
|
||||
bE = new NetworkElement("b"),
|
||||
cE = new NetworkElement("c");
|
||||
|
||||
WiredNode
|
||||
WiredNodeImpl
|
||||
aN = aE.getNode(),
|
||||
bN = bE.getNode(),
|
||||
cN = cE.getNode();
|
||||
@@ -42,8 +37,8 @@ public class NetworkTest {
|
||||
assertNotEquals(aN.getNetwork(), cN.getNetwork(), "A's and C's network must be different");
|
||||
assertNotEquals(bN.getNetwork(), cN.getNetwork(), "B's and C's network must be different");
|
||||
|
||||
assertTrue(aN.getNetwork().connect(aN, bN), "Must be able to add connection");
|
||||
assertFalse(aN.getNetwork().connect(aN, bN), "Cannot add connection twice");
|
||||
assertTrue(aN.connectTo(bN), "Must be able to add connection");
|
||||
assertFalse(aN.connectTo(bN), "Cannot add connection twice");
|
||||
|
||||
assertEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must be equal");
|
||||
assertEquals(Set.of(aN, bN), nodes(aN.getNetwork()), "A's network should be A and B");
|
||||
@@ -51,7 +46,7 @@ public class NetworkTest {
|
||||
assertEquals(Set.of("a", "b"), aE.allPeripherals().keySet(), "A's peripheral set should be A, B");
|
||||
assertEquals(Set.of("a", "b"), bE.allPeripherals().keySet(), "B's peripheral set should be A, B");
|
||||
|
||||
aN.getNetwork().connect(aN, cN);
|
||||
aN.connectTo(cN);
|
||||
|
||||
assertEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must be equal");
|
||||
assertEquals(aN.getNetwork(), cN.getNetwork(), "A's and C's network must be equal");
|
||||
@@ -69,20 +64,20 @@ public class NetworkTest {
|
||||
@Test
|
||||
public void testDisconnectNoChange() {
|
||||
NetworkElement
|
||||
aE = new NetworkElement(null, null, "a"),
|
||||
bE = new NetworkElement(null, null, "b"),
|
||||
cE = new NetworkElement(null, null, "c");
|
||||
aE = new NetworkElement("a"),
|
||||
bE = new NetworkElement("b"),
|
||||
cE = new NetworkElement("c");
|
||||
|
||||
WiredNode
|
||||
WiredNodeImpl
|
||||
aN = aE.getNode(),
|
||||
bN = bE.getNode(),
|
||||
cN = cE.getNode();
|
||||
|
||||
aN.getNetwork().connect(aN, bN);
|
||||
aN.getNetwork().connect(aN, cN);
|
||||
aN.getNetwork().connect(bN, cN);
|
||||
aN.connectTo(bN);
|
||||
aN.connectTo(cN);
|
||||
bN.connectTo(cN);
|
||||
|
||||
aN.getNetwork().disconnect(aN, bN);
|
||||
aN.disconnectFrom(bN);
|
||||
|
||||
assertEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must be equal");
|
||||
assertEquals(aN.getNetwork(), cN.getNetwork(), "A's and C's network must be equal");
|
||||
@@ -96,19 +91,19 @@ public class NetworkTest {
|
||||
@Test
|
||||
public void testDisconnectLeaf() {
|
||||
NetworkElement
|
||||
aE = new NetworkElement(null, null, "a"),
|
||||
bE = new NetworkElement(null, null, "b"),
|
||||
cE = new NetworkElement(null, null, "c");
|
||||
aE = new NetworkElement("a"),
|
||||
bE = new NetworkElement("b"),
|
||||
cE = new NetworkElement("c");
|
||||
|
||||
WiredNode
|
||||
WiredNodeImpl
|
||||
aN = aE.getNode(),
|
||||
bN = bE.getNode(),
|
||||
cN = cE.getNode();
|
||||
|
||||
aN.getNetwork().connect(aN, bN);
|
||||
aN.getNetwork().connect(aN, cN);
|
||||
aN.connectTo(bN);
|
||||
aN.connectTo(cN);
|
||||
|
||||
aN.getNetwork().disconnect(aN, bN);
|
||||
aN.disconnectFrom(bN);
|
||||
|
||||
assertNotEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must not be equal");
|
||||
assertEquals(aN.getNetwork(), cN.getNetwork(), "A's and C's network must be equal");
|
||||
@@ -123,23 +118,23 @@ public class NetworkTest {
|
||||
@Test
|
||||
public void testDisconnectSplit() {
|
||||
NetworkElement
|
||||
aE = new NetworkElement(null, null, "a"),
|
||||
aaE = new NetworkElement(null, null, "a_"),
|
||||
bE = new NetworkElement(null, null, "b"),
|
||||
bbE = new NetworkElement(null, null, "b_");
|
||||
aE = new NetworkElement("a"),
|
||||
aaE = new NetworkElement("a_"),
|
||||
bE = new NetworkElement("b"),
|
||||
bbE = new NetworkElement("b_");
|
||||
|
||||
WiredNode
|
||||
WiredNodeImpl
|
||||
aN = aE.getNode(),
|
||||
aaN = aaE.getNode(),
|
||||
bN = bE.getNode(),
|
||||
bbN = bbE.getNode();
|
||||
|
||||
aN.getNetwork().connect(aN, aaN);
|
||||
bN.getNetwork().connect(bN, bbN);
|
||||
aN.connectTo(aaN);
|
||||
bN.connectTo(bbN);
|
||||
|
||||
aN.getNetwork().connect(aN, bN);
|
||||
aN.connectTo(bN);
|
||||
|
||||
aN.getNetwork().disconnect(aN, bN);
|
||||
aN.disconnectFrom(bN);
|
||||
|
||||
assertNotEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must not be equal");
|
||||
assertEquals(aN.getNetwork(), aaN.getNetwork(), "A's and A_'s network must be equal");
|
||||
@@ -154,7 +149,7 @@ public class NetworkTest {
|
||||
|
||||
@Test
|
||||
public void testRemoveSingle() {
|
||||
var aE = new NetworkElement(null, null, "a");
|
||||
var aE = new NetworkElement("a");
|
||||
var aN = aE.getNode();
|
||||
|
||||
var network = aN.getNetwork();
|
||||
@@ -165,20 +160,20 @@ public class NetworkTest {
|
||||
@Test
|
||||
public void testRemoveLeaf() {
|
||||
NetworkElement
|
||||
aE = new NetworkElement(null, null, "a"),
|
||||
bE = new NetworkElement(null, null, "b"),
|
||||
cE = new NetworkElement(null, null, "c");
|
||||
aE = new NetworkElement("a"),
|
||||
bE = new NetworkElement("b"),
|
||||
cE = new NetworkElement("c");
|
||||
|
||||
WiredNode
|
||||
WiredNodeImpl
|
||||
aN = aE.getNode(),
|
||||
bN = bE.getNode(),
|
||||
cN = cE.getNode();
|
||||
|
||||
aN.getNetwork().connect(aN, bN);
|
||||
aN.getNetwork().connect(aN, cN);
|
||||
aN.connectTo(bN);
|
||||
aN.connectTo(cN);
|
||||
|
||||
assertTrue(aN.getNetwork().remove(bN), "Must be able to remove node");
|
||||
assertFalse(aN.getNetwork().remove(bN), "Cannot remove a second time");
|
||||
assertTrue(bN.remove(), "Must be able to remove node");
|
||||
assertFalse(bN.remove(), "Cannot remove a second time");
|
||||
|
||||
assertNotEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must not be equal");
|
||||
assertEquals(aN.getNetwork(), cN.getNetwork(), "A's and C's network must be equal");
|
||||
@@ -194,26 +189,26 @@ public class NetworkTest {
|
||||
@Test
|
||||
public void testRemoveSplit() {
|
||||
NetworkElement
|
||||
aE = new NetworkElement(null, null, "a"),
|
||||
aaE = new NetworkElement(null, null, "a_"),
|
||||
bE = new NetworkElement(null, null, "b"),
|
||||
bbE = new NetworkElement(null, null, "b_"),
|
||||
cE = new NetworkElement(null, null, "c");
|
||||
aE = new NetworkElement("a"),
|
||||
aaE = new NetworkElement("a_"),
|
||||
bE = new NetworkElement("b"),
|
||||
bbE = new NetworkElement("b_"),
|
||||
cE = new NetworkElement("c");
|
||||
|
||||
WiredNode
|
||||
WiredNodeImpl
|
||||
aN = aE.getNode(),
|
||||
aaN = aaE.getNode(),
|
||||
bN = bE.getNode(),
|
||||
bbN = bbE.getNode(),
|
||||
cN = cE.getNode();
|
||||
|
||||
aN.getNetwork().connect(aN, aaN);
|
||||
bN.getNetwork().connect(bN, bbN);
|
||||
aN.connectTo(aaN);
|
||||
bN.connectTo(bbN);
|
||||
|
||||
cN.getNetwork().connect(aN, cN);
|
||||
cN.getNetwork().connect(bN, cN);
|
||||
cN.connectTo(aN);
|
||||
cN.connectTo(bN);
|
||||
|
||||
cN.getNetwork().remove(cN);
|
||||
cN.remove();
|
||||
|
||||
assertNotEquals(aN.getNetwork(), bN.getNetwork(), "A's and B's network must not be equal");
|
||||
assertEquals(aN.getNetwork(), aaN.getNetwork(), "A's and A_'s network must be equal");
|
||||
@@ -228,96 +223,30 @@ public class NetworkTest {
|
||||
assertEquals(Set.of(), cE.allPeripherals().keySet(), "C's peripheral set should be empty");
|
||||
}
|
||||
|
||||
private static final int BRUTE_SIZE = 16;
|
||||
private static final int TOGGLE_CONNECTION_TIMES = 5;
|
||||
private static final int TOGGLE_NODE_TIMES = 5;
|
||||
|
||||
@Test
|
||||
@Disabled("Takes a long time to run, mostly for stress testing")
|
||||
public void testLarge() {
|
||||
var grid = new Grid<WiredNode>(BRUTE_SIZE);
|
||||
grid.map((existing, pos) -> new NetworkElement(null, null, "n_" + pos).getNode());
|
||||
|
||||
// Test connecting
|
||||
{
|
||||
var start = System.nanoTime();
|
||||
|
||||
grid.forEach((existing, pos) -> {
|
||||
for (var facing : DirectionUtil.FACINGS) {
|
||||
var offset = pos.relative(facing);
|
||||
if (offset.getX() > BRUTE_SIZE / 2 == pos.getX() > BRUTE_SIZE / 2) {
|
||||
var other = grid.get(offset);
|
||||
if (other != null) existing.getNetwork().connect(existing, other);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var end = System.nanoTime();
|
||||
|
||||
System.out.printf("Connecting %s³ nodes took %s seconds\n", BRUTE_SIZE, (end - start) * 1e-9);
|
||||
}
|
||||
|
||||
// Test toggling
|
||||
{
|
||||
var left = grid.get(new BlockPos(BRUTE_SIZE / 2, 0, 0));
|
||||
var right = grid.get(new BlockPos(BRUTE_SIZE / 2 + 1, 0, 0));
|
||||
assertNotEquals(left.getNetwork(), right.getNetwork());
|
||||
|
||||
var start = System.nanoTime();
|
||||
for (var i = 0; i < TOGGLE_CONNECTION_TIMES; i++) {
|
||||
left.getNetwork().connect(left, right);
|
||||
left.getNetwork().disconnect(left, right);
|
||||
}
|
||||
|
||||
var end = System.nanoTime();
|
||||
|
||||
System.out.printf("Toggling connection %s times took %s seconds\n", TOGGLE_CONNECTION_TIMES, (end - start) * 1e-9);
|
||||
}
|
||||
|
||||
{
|
||||
var left = grid.get(new BlockPos(BRUTE_SIZE / 2, 0, 0));
|
||||
var right = grid.get(new BlockPos(BRUTE_SIZE / 2 + 1, 0, 0));
|
||||
var centre = new NetworkElement(null, null, "c").getNode();
|
||||
assertNotEquals(left.getNetwork(), right.getNetwork());
|
||||
|
||||
var start = System.nanoTime();
|
||||
for (var i = 0; i < TOGGLE_NODE_TIMES; i++) {
|
||||
left.getNetwork().connect(left, centre);
|
||||
right.getNetwork().connect(right, centre);
|
||||
|
||||
left.getNetwork().remove(centre);
|
||||
}
|
||||
|
||||
var end = System.nanoTime();
|
||||
|
||||
System.out.printf("Toggling node %s times took %s seconds\n", TOGGLE_NODE_TIMES, (end - start) * 1e-9);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class NetworkElement implements WiredElement {
|
||||
private final Level world;
|
||||
private final Vec3 position;
|
||||
static final class NetworkElement implements WiredElement {
|
||||
private final String id;
|
||||
private final WiredNode node;
|
||||
private final WiredNodeImpl node;
|
||||
private final Map<String, IPeripheral> localPeripherals = new HashMap<>();
|
||||
private final Map<String, IPeripheral> remotePeripherals = new HashMap<>();
|
||||
|
||||
private NetworkElement(Level world, Vec3 position, String id) {
|
||||
this.world = world;
|
||||
this.position = position;
|
||||
NetworkElement(String id) {
|
||||
this(id, true);
|
||||
}
|
||||
|
||||
NetworkElement(String id, boolean peripheral) {
|
||||
this.id = id;
|
||||
this.node = new WiredNodeImpl(this);
|
||||
this.addPeripheral(id);
|
||||
if (peripheral) addPeripheral(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Level getLevel() {
|
||||
return world;
|
||||
throw new IllegalStateException("Unexpected call to getLevel()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 getPosition() {
|
||||
return position;
|
||||
throw new IllegalStateException("Unexpected call to getPosition()");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -331,7 +260,7 @@ public class NetworkTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredNode getNode() {
|
||||
public WiredNodeImpl getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -364,45 +293,6 @@ public class NetworkTest {
|
||||
}
|
||||
}
|
||||
|
||||
private static class Grid<T> {
|
||||
private final int size;
|
||||
private final T[] box;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Grid(int size) {
|
||||
this.size = size;
|
||||
this.box = (T[]) new Object[size * size * size];
|
||||
}
|
||||
|
||||
public T get(BlockPos pos) {
|
||||
int x = pos.getX(), y = pos.getY(), z = pos.getZ();
|
||||
|
||||
return x >= 0 && x < size && y >= 0 && y < size && z >= 0 && z < size
|
||||
? box[x * size * size + y * size + z]
|
||||
: null;
|
||||
}
|
||||
|
||||
public void forEach(BiConsumer<T, BlockPos> transform) {
|
||||
for (var x = 0; x < size; x++) {
|
||||
for (var y = 0; y < size; y++) {
|
||||
for (var z = 0; z < size; z++) {
|
||||
transform.accept(box[x * size * size + y * size + z], new BlockPos(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void map(BiFunction<T, BlockPos, T> transform) {
|
||||
for (var x = 0; x < size; x++) {
|
||||
for (var y = 0; y < size; y++) {
|
||||
for (var z = 0; z < size; z++) {
|
||||
box[x * size * size + y * size + z] = transform.apply(box[x * size * size + y * size + z], new BlockPos(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Set<WiredNodeImpl> nodes(WiredNetwork network) {
|
||||
return ((WiredNetworkImpl) network).nodes;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.command.arguments;
|
||||
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.context.StringRange;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.suggestion.Suggestion;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import dan200.computercraft.shared.command.Exceptions;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.test.core.ReplaceUnderscoresDisplayNameGenerator;
|
||||
import org.junit.jupiter.api.DisplayNameGeneration;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
@DisplayNameGeneration(ReplaceUnderscoresDisplayNameGenerator.class)
|
||||
class ComputerSelectorTest {
|
||||
@ParameterizedTest(name = "{0}")
|
||||
@MethodSource("getArgumentTestCases")
|
||||
public void Parse_basic_inputs(String input, ComputerSelector expected) throws CommandSyntaxException {
|
||||
assertEquals(expected, ComputerSelector.parse(new StringReader(input)));
|
||||
}
|
||||
|
||||
public static Arguments[] getArgumentTestCases() {
|
||||
return new Arguments[]{
|
||||
// Legacy selectors
|
||||
Arguments.of("@some_label", new ComputerSelector("@some_label", OptionalInt.empty(), null, OptionalInt.empty(), "some_label", null, null, null)),
|
||||
Arguments.of("~normal", new ComputerSelector("~normal", OptionalInt.empty(), null, OptionalInt.empty(), null, ComputerFamily.NORMAL, null, null)),
|
||||
Arguments.of("#123", new ComputerSelector("#123", OptionalInt.empty(), null, OptionalInt.of(123), null, null, null, null)),
|
||||
Arguments.of("123", new ComputerSelector("123", OptionalInt.of(123), null, OptionalInt.empty(), null, null, null, null)),
|
||||
// New selectors
|
||||
Arguments.of("@c[]", new ComputerSelector("@c[]", OptionalInt.empty(), null, OptionalInt.empty(), null, null, null, null)),
|
||||
Arguments.of("@c[instance=5e18f505-62f7-46f8-83f3-792f03224724]", new ComputerSelector("@c[instance=5e18f505-62f7-46f8-83f3-792f03224724]", OptionalInt.empty(), UUID.fromString("5e18f505-62f7-46f8-83f3-792f03224724"), OptionalInt.empty(), null, null, null, null)),
|
||||
Arguments.of("@c[id=123]", new ComputerSelector("@c[id=123]", OptionalInt.empty(), null, OptionalInt.of(123), null, null, null, null)),
|
||||
Arguments.of("@c[label=\"foo\"]", new ComputerSelector("@c[label=\"foo\"]", OptionalInt.empty(), null, OptionalInt.empty(), "foo", null, null, null)),
|
||||
Arguments.of("@c[family=normal]", new ComputerSelector("@c[family=normal]", OptionalInt.empty(), null, OptionalInt.empty(), null, ComputerFamily.NORMAL, null, null)),
|
||||
// Complex selectors
|
||||
Arguments.of("@c[ id = 123 , ]", new ComputerSelector("@c[ id = 123 , ]", OptionalInt.empty(), null, OptionalInt.of(123), null, null, null, null)),
|
||||
Arguments.of("@c[id=123,family=normal]", new ComputerSelector("@c[id=123,family=normal]", OptionalInt.empty(), null, OptionalInt.of(123), null, ComputerFamily.NORMAL, null, null)),
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void Fails_on_repeated_options() {
|
||||
var error = assertThrows(CommandSyntaxException.class, () -> ComputerSelector.parse(new StringReader("@c[id=1, id=2]")));
|
||||
assertEquals(Exceptions.ERROR_INAPPLICABLE_OPTION, error.getType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void Complete_selector_components() {
|
||||
assertEquals(List.of(new Suggestion(StringRange.between(0, 1), "@c[")), suggest("@"));
|
||||
assertThat(suggest("@c["), hasItem(
|
||||
new Suggestion(StringRange.at(3), "family", ComputerSelector.options().get("family").tooltip())
|
||||
));
|
||||
assertEquals(List.of(new Suggestion(StringRange.at(9), "=")), suggest("@c[family"));
|
||||
assertEquals(List.of(new Suggestion(StringRange.at(16), ",")), suggest("@c[family=normal"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void Complete_selector_family() {
|
||||
assertThat(suggest("@c[family="), containsInAnyOrder(
|
||||
new Suggestion(StringRange.at(10), "normal"),
|
||||
new Suggestion(StringRange.at(10), "advanced"),
|
||||
new Suggestion(StringRange.at(10), "command")
|
||||
));
|
||||
assertThat(suggest("@c[family=n"), contains(
|
||||
new Suggestion(StringRange.between(10, 11), "normal")
|
||||
));
|
||||
}
|
||||
|
||||
private List<Suggestion> suggest(String input) {
|
||||
var context = new CommandContext<>(new Object(), "", Map.of(), null, null, List.of(), StringRange.at(0), null, null, false);
|
||||
return ComputerSelector.suggest(context, new SuggestionsBuilder(input, 0)).getNow(null).getList();
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ class DfpwmStateTest {
|
||||
|
||||
var state = new DfpwmState();
|
||||
state.pushBuffer(new ObjectLuaTable(inputTbl), input.length, Optional.empty());
|
||||
var result = state.pullPending(0);
|
||||
var result = state.pullPending(0).audio();
|
||||
var contents = new byte[result.remaining()];
|
||||
result.get(contents);
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// SPDX-FileCopyrightText: 2023 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.peripheral.speaker;
|
||||
|
||||
import dan200.computercraft.test.core.ArbitraryByteBuffer;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.jqwik.api.*;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
class EncodedAudioTest {
|
||||
/**
|
||||
* Sends the audio on a roundtrip, ensuring that its contents are reassembled on the other end.
|
||||
*
|
||||
* @param audio The message to send.
|
||||
*/
|
||||
@Property
|
||||
public void testRoundTrip(@ForAll("audio") EncodedAudio audio) {
|
||||
var buffer = new FriendlyByteBuf(Unpooled.directBuffer());
|
||||
audio.write(buffer);
|
||||
|
||||
var converted = EncodedAudio.read(buffer);
|
||||
assertEquals(buffer.readableBytes(), 0, "Whole packet was read");
|
||||
|
||||
assertThat("Messages are equal", converted, equalTo(converted));
|
||||
}
|
||||
|
||||
@Provide
|
||||
Arbitrary<EncodedAudio> audio() {
|
||||
return Combinators.combine(
|
||||
Arbitraries.integers(),
|
||||
Arbitraries.integers(),
|
||||
Arbitraries.of(true, false),
|
||||
ArbitraryByteBuffer.bytes().ofMaxSize(1000)
|
||||
).as(EncodedAudio::new);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user