Skip to content

Commit

Permalink
internal: port Transmission to Java
Browse files Browse the repository at this point in the history
  • Loading branch information
MrTJP committed Apr 30, 2023
1 parent 0d3053f commit 340d9fc
Show file tree
Hide file tree
Showing 132 changed files with 6,617 additions and 3,601 deletions.
69 changes: 69 additions & 0 deletions src/core/scala/mrtjp/projectred/core/CenterLookup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package mrtjp.projectred.core;

import codechicken.multipart.api.part.TMultiPart;
import codechicken.multipart.block.TileMultiPart;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

public class CenterLookup {

//Starting conditions
public final World world;
public final BlockPos pos;
public final int direction;

// Located objects
public final BlockState state;
public final Block block;
public final TileEntity tile;
public final TMultiPart part;

// Conditions for reverse lookup
public final BlockPos otherPos;
public final int otherDirection;

public CenterLookup(World world, BlockPos pos, int direction, BlockState state, TileEntity tile, TMultiPart part, BlockPos otherPos, int otherDirection) {
this.world = world;
this.pos = pos;
this.direction = direction;
this.state = state;
this.block = state.getBlock();
this.tile = tile;
this.part = part;
this.otherPos = otherPos;
this.otherDirection = otherDirection;
}

public static CenterLookup lookupInsideFace(World world, BlockPos pos, int direction) {

int otherDir = direction ^ 1;

BlockState state = world.getBlockState(pos);
TileEntity tile = world.getBlockEntity(pos);
TMultiPart part = null;
if (tile instanceof TileMultiPart) {
part = ((TileMultiPart) tile).getSlottedPart(direction);
}

return new CenterLookup(world, pos, direction, state, tile, part, pos, otherDir);
}

public static CenterLookup lookupStraightCenter(World world, BlockPos pos, int direction) {

BlockPos otherPos = pos.relative(Direction.values()[direction]);
int otherDir = direction ^ 1;

BlockState state = world.getBlockState(otherPos);
TileEntity tile = world.getBlockEntity(otherPos);
TMultiPart part = null;
if (tile instanceof TileMultiPart) {
part = ((TileMultiPart) tile).getSlottedPart(6);
}

return new CenterLookup(world, pos, direction, state, tile, part, otherPos, otherDir);
}
}
110 changes: 110 additions & 0 deletions src/core/scala/mrtjp/projectred/core/FaceLookup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package mrtjp.projectred.core;

import codechicken.lib.vec.Rotation;
import codechicken.multipart.api.part.TMultiPart;
import codechicken.multipart.block.TileMultiPart;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

public class FaceLookup {

//Starting conditions
public final World world;
public final BlockPos pos;
public final int side;
public final int r;

//Located objects
public final BlockState state;
public final Block block;
public final TileEntity tile;
public final TMultiPart part;

//Conditions for reverse lookup
public final BlockPos otherPos;
public final int otherSide;
public final int otherRotation;

public FaceLookup(World world, BlockPos pos, int side, int r, BlockState state, TileEntity tile, TMultiPart part, BlockPos otherPos, int otherSide, int otherRotation) {
this.world = world;
this.pos = pos;
this.side = side;
this.r = r;
this.state = state;
this.block = state.getBlock();
this.tile = tile;
this.part = part;
this.otherPos = otherPos;
this.otherSide = otherSide;
this.otherRotation = otherRotation;
}

public static FaceLookup lookupCorner(World world, BlockPos pos, int side, int r) {
int absDir = Rotation.rotateSide(side, r);
int otherSide = absDir ^ 1;
int otherRotation = Rotation.rotationTo(absDir ^ 1, side ^ 1);

BlockPos pos2 = pos
.relative(Direction.values()[absDir])
.relative(Direction.values()[side]);

BlockState state = world.getBlockState(pos2);
TileEntity tile = world.getBlockEntity(pos2);
TMultiPart part = null;
if (tile instanceof TileMultiPart) {
part = ((TileMultiPart) tile).getSlottedPart(otherSide);
}

return new FaceLookup(world, pos, side, r, state, tile, part, pos2, otherSide, otherRotation);
}

public static FaceLookup lookupStraight(World world, BlockPos pos, int side, int r) {
int otherSide = side;
int otherRotation = (r + 2) % 4;

BlockPos pos2 = pos.relative(Direction.values()[Rotation.rotateSide(side, r)]);

BlockState state = world.getBlockState(pos2);
TileEntity tile = world.getBlockEntity(pos2);
TMultiPart part = null;
if (tile instanceof TileMultiPart) {
part = ((TileMultiPart) tile).getSlottedPart(otherSide);
}

return new FaceLookup(world, pos, side, r, state, tile, part, pos2, otherSide, otherRotation);
}

public static FaceLookup lookupInsideFace(World world, BlockPos pos, int side, int r) {
int absDir = Rotation.rotateSide(side, r);
int otherSide = absDir;
int otherRotation = Rotation.rotationTo(absDir, side);

BlockState state = world.getBlockState(pos);
TileEntity tile = world.getBlockEntity(pos);
TMultiPart part = null;
if (tile instanceof TileMultiPart) {
part = ((TileMultiPart) tile).getSlottedPart(otherSide);
}

return new FaceLookup(world, pos, side, r, state, tile, part, pos, otherSide, otherRotation);
}

public static FaceLookup lookupInsideCenter(World world, BlockPos pos, int side) {

int otherSide = side;
int otherRotation = -1; // Part is not on face

BlockState state = world.getBlockState(pos);
TileEntity tile = world.getBlockEntity(pos);
TMultiPart part = null;
if (tile instanceof TileMultiPart) {
part = ((TileMultiPart) tile).getSlottedPart(6);
}

return new FaceLookup(world, pos, side, -1, state, tile, part, pos, otherRotation, otherSide);
}
}
191 changes: 191 additions & 0 deletions src/core/scala/mrtjp/projectred/core/RedstonePropagator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package mrtjp.projectred.core;

import codechicken.multipart.api.part.TMultiPart;
import codechicken.multipart.block.TileMultiPart;
import codechicken.multipart.init.CBMultipartModContent;
import com.google.common.collect.HashMultimap;
import mrtjp.projectred.core.part.IPropagationPart;
import net.minecraft.block.Blocks;
import net.minecraft.block.RedstoneWireBlock;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

public class RedstonePropagator {
/**
* Standard operation procedure, no special propagation rules. The
* propagator signal may not have increased.
*/
public static final int RISING = 0;
/**
* Used when the propagator signal dropped (to 0). Propagation should
* continue until a rising or constant change is encountered at which point
* a RISING should be propagated back to this wire.
*/
public static final int DROPPING = 1;
/**
* Used when a wire's connection state has changed. Even if the signal
* remains the same, new connections still need to be recalculated
*/
public static final int FORCE = 2;
/**
* Used when the propagator did not change signal, but a new connection may
* have been established and signal needs recalculating
*/
public static final int FORCED = 3;

private static final LinkedList<PropagationRun> reusableRuns = new LinkedList<>();
private static PropagationRun currentRun = null;
private static PropagationRun finishingRun = null;

private static boolean canRedwiresProvidePower = true;
private static boolean canConnectRedwires = true;

public static boolean canConnectRedwires() {
return canConnectRedwires;
}
public static void setCanConnectRedwires(boolean canConnectRedwires) {
RedstonePropagator.canConnectRedwires = canConnectRedwires;
}

public static boolean canRedwiresProvidePower() {
return canRedwiresProvidePower;
}
public static void setDustProvidesPower(boolean dustProvidesPower) {
((RedstoneWireBlock)Blocks.REDSTONE_WIRE).shouldSignal = dustProvidesPower;
}
public static void setRedwiresProvidePower(boolean canRedwiresProvidePower) {
RedstonePropagator.canRedwiresProvidePower = canRedwiresProvidePower;
}

public static void resetPowerFlags() {
setDustProvidesPower(true);
setRedwiresProvidePower(true);
setCanConnectRedwires(true);
}

public static void addNeighborChange(World world, BlockPos pos) {
currentRun.neighborChanges.put(world, pos);
}

public static void addPartChange(TMultiPart part) {
currentRun.partChanges.put(part.tile(), part);
}

public static void logCalculation() {
if (finishingRun != null) {
finishingRun.recalcs++;
}
}

public static void propagateTo(IPropagationPart part, IPropagationPart from, int mode) {
if (currentRun != null) {
currentRun.add(part, from, mode);
return;
}
currentRun = reusableRuns.isEmpty() ? new PropagationRun() : reusableRuns.removeFirst();
currentRun.add(part, from, mode);
currentRun.executeRun(finishingRun);
}

public static void propagateTo(IPropagationPart part, int mode) {
propagateTo(part, null, mode);
}

public static void propagateAnalogDrop(IPropagationPart part) {
currentRun.addAnalogDrop(part);
}

private static class PropagationRun {

private PropagationRun parent;
private IPropagationPart lastCaller;
private int count = 0;
private int recalcs = 0;

HashMultimap<TileMultiPart, TMultiPart> partChanges = HashMultimap.create();
HashMultimap<World, BlockPos> neighborChanges = HashMultimap.create();
List<Runnable> propagationTasks = new LinkedList<>();
List<Runnable> analogDropPropagationTasks = new LinkedList<>();

void clear() {
partChanges.clear();
neighborChanges.clear();
count = 0;
recalcs = 0;
lastCaller = null;
reusableRuns.add(this);
}

void executeRun(PropagationRun parent) {
this.parent = parent;
RedstonePropagator.currentRun = this;
runLoop();
finishRun();
}

void runLoop() {
do {
List<Runnable> pTasks = propagationTasks;
propagationTasks = new LinkedList<>();

pTasks.forEach(Runnable::run);

if (propagationTasks.isEmpty() && !analogDropPropagationTasks.isEmpty()) {
propagationTasks = analogDropPropagationTasks;
analogDropPropagationTasks = new LinkedList<>();
}
} while (!propagationTasks.isEmpty());
}

void finishRun() {
RedstonePropagator.currentRun = null;

if (partChanges.isEmpty() && neighborChanges.isEmpty()) {
RedstonePropagator.finishingRun = parent;
clear();
return;
}

RedstonePropagator.finishingRun = this;

// Notify part changes in bulk
for (Map.Entry<TileMultiPart, Collection<TMultiPart>> entry : partChanges.asMap().entrySet()) {
Collection<TMultiPart> parts = entry.getValue();
for (TMultiPart part : parts) {
((IPropagationPart) part).onSignalUpdate();
}
entry.getKey().multiPartChange(parts);
}

// Notify normal neighbor changes in bulk
for (Map.Entry<World, Collection<BlockPos>> entry : neighborChanges.asMap().entrySet()) {
World world = entry.getKey();
Collection<BlockPos> positions = entry.getValue();
for (BlockPos pos : positions) {
world.neighborChanged(pos, CBMultipartModContent.blockMultipart, pos);
}
}

RedstonePropagator.finishingRun = parent;
clear();
}

void add(IPropagationPart part, IPropagationPart from, int mode) {
if (from != lastCaller) {
lastCaller = from;
count++;
}
propagationTasks.add(() -> part.updateAndPropagate(from, mode));
}

void addAnalogDrop(IPropagationPart part) {
analogDropPropagationTasks.add(() -> part.updateAndPropagate(null, RISING));
}
}

}
Loading

0 comments on commit 340d9fc

Please sign in to comment.