Skip to content

Commit

Permalink
Switch train scanning logic
Browse files Browse the repository at this point in the history
  • Loading branch information
CSX8600 committed Apr 8, 2020
1 parent 5104e9c commit e91c440
Show file tree
Hide file tree
Showing 8 changed files with 428 additions and 184 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.clussmanproductions.railstuff.event;

import com.clussmanproductions.railstuff.ModRailStuff;
import com.clussmanproductions.railstuff.scanner.ScannerThread;

import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;

@EventBusSubscriber
public class WorldEventHandler {
@SubscribeEvent
public static void onLoad(WorldEvent.Load e)
{
if (e.getWorld().isRemote || !ModRailStuff.IR_INSTALLED)
{
return;
}

ScannerThread thread = new ScannerThread(e.getWorld());
ScannerThread.ThreadsByWorld.put(e.getWorld(), thread);
thread.start();
}

@SubscribeEvent
public static void onUnload(WorldEvent.Unload e)
{
if (e.getWorld().isRemote || !ModRailStuff.IR_INSTALLED)
{
return;
}

if (ScannerThread.ThreadsByWorld.containsKey(e.getWorld()))
{
ScannerThread thread = ScannerThread.ThreadsByWorld.get(e.getWorld());
thread.requestStop();

while(thread.isAlive()) {}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.clussmanproductions.railstuff.scanner;

import java.util.List;

public interface IScannerSubscriber {
List<ScanRequest> getScanRequests();
void onScanComplete(ScanCompleteData scanCompleteData);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.clussmanproductions.railstuff.scanner;

import net.minecraft.util.EnumFacing;

public class ScanCompleteData {
private ScanRequest scanRequest;
private boolean timedOut;
private boolean trainFound;
private boolean trainMovingTowardsDestination;

public ScanCompleteData(ScanRequest scanRequest, boolean timedOut, boolean trainFound, boolean trainMovingTowardsDestination)
{
this.scanRequest = scanRequest;
this.timedOut = timedOut;
this.trainFound = trainFound;
this.trainMovingTowardsDestination = trainMovingTowardsDestination;
}

public ScanRequest getScanRequest() { return scanRequest; }
public boolean getTimedOut() { return timedOut; }
public boolean getTrainFound() { return trainFound; }
public boolean getTrainMovingTowardsDestination() { return trainMovingTowardsDestination; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.clussmanproductions.railstuff.scanner;

import java.util.UUID;

import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;

public class ScanRequest {
private UUID requestID;
private BlockPos startingPos;
private BlockPos endingPos;
private EnumFacing startDirection;

public ScanRequest(UUID requestID, BlockPos startingPos, BlockPos endingPos, EnumFacing startDirection)
{
this.requestID = requestID;
this.startingPos = startingPos;
this.endingPos = endingPos;
this.startDirection = startDirection;
}

public UUID getRequestID() { return requestID; }
public BlockPos getStartingPos() { return startingPos; }
public BlockPos getEndingPos() { return endingPos; }
public EnumFacing getStartDirection() { return startDirection; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.clussmanproductions.railstuff.scanner;

import java.util.HashSet;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

import com.google.common.collect.ImmutableList;

import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.storage.WorldSavedData;

public class ScannerData extends WorldSavedData {

private HashSet<BlockPos> tileEntitySubscriptions = new HashSet<BlockPos>();
private ReentrantReadWriteLock tileEntitySubscriptionLock = new ReentrantReadWriteLock();

public ScannerData(String mapName)
{
super(mapName);
}

public ScannerData()
{
super("RS_scanner_data");
}

@Override
public void readFromNBT(NBTTagCompound nbt) {
int i = 0;
WriteLock lock = tileEntitySubscriptionLock.writeLock();
lock.lock();
while(nbt.hasKey("blockpos" + i))
{
long serializedBlockPos = nbt.getLong("blockpos" + i);
tileEntitySubscriptions.add(BlockPos.fromLong(serializedBlockPos));

i++;
}
lock.unlock();
}

@Override
public NBTTagCompound writeToNBT(NBTTagCompound compound) {
int i = 0;
ReadLock lock = tileEntitySubscriptionLock.readLock();
lock.lock();
for(BlockPos pos : tileEntitySubscriptions)
{
compound.setLong("blockpos" + i, pos.toLong());
}
lock.unlock();

return compound;
}

public ImmutableList<BlockPos> getSubscribers()
{
ReadLock lock = tileEntitySubscriptionLock.readLock();

lock.lock();
ImmutableList<BlockPos> list = ImmutableList.copyOf(tileEntitySubscriptions);
lock.unlock();

return list;
}

public void addSubscriber(BlockPos pos)
{
WriteLock lock = tileEntitySubscriptionLock.writeLock();

lock.lock();
if (tileEntitySubscriptions.add(pos))
{
markDirty();
}
lock.unlock();
}

public void removeSubscriber(BlockPos pos)
{
WriteLock lock = tileEntitySubscriptionLock.writeLock();

lock.lock();
if (tileEntitySubscriptions.remove(pos))
{
markDirty();
}
lock.unlock();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package com.clussmanproductions.railstuff.scanner;

import java.util.HashMap;
import java.util.List;

import com.clussmanproductions.railstuff.Config;
import com.clussmanproductions.railstuff.tile.SignalTileEntity.LastSwitchInfo;
import com.clussmanproductions.railstuff.util.ImmersiveRailroadingHelper;

import cam72cam.immersiverailroading.entity.EntityMoveableRollingStock;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;

public class ScannerThread extends Thread
{
public static HashMap<World, ScannerThread> ThreadsByWorld = new HashMap<World, ScannerThread>();

private World _world;
private boolean _stop = false;
private ScannerData _data;
public ScannerThread(World world)
{
super();
_world = world;
}

public void requestStop()
{
_stop = true;
}

public <T extends TileEntity & IScannerSubscriber> void subscribe(T subscriber)
{
_data.addSubscriber(subscriber.getPos());
}

@Override
public void run() {
_data = (ScannerData)_world.loadData(ScannerData.class, "RS_scanner_data");
if (_data == null)
{
_data = new ScannerData();
_world.setData(_data.mapName, _data);
}

while(true)
{
if (_stop)
{
return;
}

for(BlockPos pos : _data.getSubscribers())
{
if (!_world.isBlockLoaded(pos))
{
continue;
}

TileEntity tileEntity = _world.getTileEntity(pos);
if (!(tileEntity instanceof IScannerSubscriber))
{
_data.removeSubscriber(pos);
continue;
}

IScannerSubscriber subscriber = (IScannerSubscriber)tileEntity;
for(ScanRequest req : subscriber.getScanRequests())
{
if (_stop)
{
return;
}

ScanCompleteData data = performScan(req);

if (_stop)
{
return;
}

if (!_world.isBlockLoaded(pos))
{
break;
}

subscriber.onScanComplete(data);
}
}
}
}

private ScanCompleteData performScan(ScanRequest req)
{
boolean foundTrain;
boolean trainMovingTowardsDestination;

Vec3d currentPosition = new Vec3d(req.getStartingPos().getX(), req.getStartingPos().getY(), req.getStartingPos().getZ());
Vec3d motion = new Vec3d(req.getStartDirection().getDirectionVec());

ScanCompleteData earlyData = checkPosition(req, currentPosition, motion);
if (earlyData != null)
{
return earlyData;
}

LastSwitchInfo lastSwitchInfo = new LastSwitchInfo();
BlockPos endingPosition = req.getEndingPos();
Vec3d endingVec = new Vec3d(endingPosition.getX(), endingPosition.getY(), endingPosition.getZ());
for(int i = 0; i < Config.signalDistanceTimeout; i++)
{
Vec3d nextPosition = ImmersiveRailroadingHelper.getNextPosition(currentPosition, motion, _world, lastSwitchInfo);

if (nextPosition.equals(currentPosition) || endingPosition.equals(new BlockPos(nextPosition.x, nextPosition.y, nextPosition.z)))
{
return new ScanCompleteData(req, nextPosition.equals(currentPosition), false, false);
}

motion = new Vec3d(nextPosition.x - currentPosition.x,
nextPosition.y - currentPosition.y,
nextPosition.z - currentPosition.z);

currentPosition = nextPosition;
ScanCompleteData data = checkPosition(req, currentPosition, motion);
if (data != null)
{
return data;
}
}

return new ScanCompleteData(req, true, false, false);
}

private ScanCompleteData checkPosition(ScanRequest req, Vec3d position, Vec3d motion)
{
List<EntityMoveableRollingStock> moveableRollingStockNearby = ImmersiveRailroadingHelper.hasStockNearby(position, _world);
if (!moveableRollingStockNearby.isEmpty())
{
EntityMoveableRollingStock stock = moveableRollingStockNearby.get(0);
Vec3d stockVelocity = stock.getVelocity().internal;
EnumFacing stockMovementFacing = EnumFacing.getFacingFromVector((float)stockVelocity.x, (float)stockVelocity.y, (float)stockVelocity.z);
EnumFacing motionFacing = EnumFacing.getFacingFromVector((float)motion.x, (float)motion.y, (float)motion.z);

boolean trainMovingTowardsDestination = motionFacing.equals(stockMovementFacing);
return new ScanCompleteData(req, false, true, trainMovingTowardsDestination);
}

return null;
}
}
Loading

0 comments on commit e91c440

Please sign in to comment.