Improved transporter beacon usability

- add transporter room state to beacon
- resume transport when conflicting beacons are removed
- explicitly load chunks on beacon transport so players don't need their own
- support transport inside non-celestial object dimension (wip)
This commit is contained in:
Unknown 2019-04-27 00:03:20 +02:00 committed by unknown
parent a0b2c005d1
commit f04782dd72
4 changed files with 146 additions and 76 deletions

View file

@ -22,6 +22,7 @@ import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand; import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation; import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.IBlockAccess; import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -168,22 +169,27 @@ public class BlockTransporterBeacon extends BlockAbstractContainer {
} }
final TileEntityTransporterBeacon tileEntityTransporterBeacon = (TileEntityTransporterBeacon) tileEntity; final TileEntityTransporterBeacon tileEntityTransporterBeacon = (TileEntityTransporterBeacon) tileEntity;
// sneaking with an empty hand if (itemStackHeld.isEmpty()) {
if ( itemStackHeld.isEmpty() if (!entityPlayer.isSneaking()) {// non-sneaking with an empty hand
&& entityPlayer.isSneaking() ) { Commons.addChatMessage(entityPlayer, Commons.getChatPrefix(this)
final boolean isEnabledOld = tileEntityTransporterBeacon.getIsEnabled(); .appendSibling(new TextComponentString(tileEntityTransporterBeacon.stateTransporter)));
tileEntityTransporterBeacon.setIsEnabled(!isEnabledOld); return true;
final boolean isEnabledNew = tileEntityTransporterBeacon.getIsEnabled();
if (isEnabledOld != isEnabledNew) { } else {// sneaking with an empty hand
if (isEnabledNew) { final boolean isEnabledOld = tileEntityTransporterBeacon.getIsEnabled();
Commons.addChatMessage(entityPlayer, Commons.getChatPrefix(this) tileEntityTransporterBeacon.setIsEnabled(!isEnabledOld);
.appendSibling(new TextComponentTranslation("warpdrive.is_enabled.set.enabled"))); final boolean isEnabledNew = tileEntityTransporterBeacon.getIsEnabled();
} else { if (isEnabledOld != isEnabledNew) {
Commons.addChatMessage(entityPlayer, Commons.getChatPrefix(this) if (isEnabledNew) {
.appendSibling(new TextComponentTranslation("warpdrive.is_enabled.set.disabled"))); Commons.addChatMessage(entityPlayer, Commons.getChatPrefix(this)
.appendSibling(new TextComponentTranslation("warpdrive.is_enabled.set.enabled")));
} else {
Commons.addChatMessage(entityPlayer, Commons.getChatPrefix(this)
.appendSibling(new TextComponentTranslation("warpdrive.is_enabled.set.disabled")));
}
} }
return true;
} }
return true;
} }
return super.onBlockActivated(world, blockPos, blockState, entityPlayer, enumHand, enumFacing, hitX, hitY, hitZ); return super.onBlockActivated(world, blockPos, blockState, entityPlayer, enumHand, enumFacing, hitX, hitY, hitZ);

View file

@ -206,37 +206,6 @@ public class ItemBlockTransporterBeacon extends ItemBlockAbstractBase implements
super.onUpdate(itemStack, world, entity, indexSlot, isHeld); super.onUpdate(itemStack, world, entity, indexSlot, isHeld);
} }
/* @TODO 1.10 is the upstream 1.7.10 bug fixed?
@Override
public boolean onItemUseFirst(final ItemStack itemStack, final EntityPlayer entityPlayer,
final World world, final int x, final int y, final int z,
final int side, final float hitX, final float hitY, final float hitZ) {
// itemStack is constantly updated for energy updates
// in net.minecraft.network.NetHandlerPlayServer.processPlayerBlockPlacement(NetHandlerPlayServer.java:657), a NPE appears randomly due to bad multithreading in upstream
// consequently, we prevent to use the item on any tile entity other than a TransporterCore
// allows block placement while sneaking
if (entityPlayer.isSneaking()) {
return false;
}
// allows non-tile entities or transporter core
final TileEntity tileEntity = world.getTileEntity(x, y, z);
if ( tileEntity == null
|| tileEntity instanceof ITransporterCore ) {
return false;
}
// allow if beacon is disabled
if (!isActive(itemStack)) {
return false;
}
// forbid everything else
return true;
}
/**/
@Nonnull @Nonnull
@Override @Override
public EnumActionResult onItemUse(@Nonnull final EntityPlayer entityPlayer, public EnumActionResult onItemUse(@Nonnull final EntityPlayer entityPlayer,

View file

@ -36,8 +36,9 @@ public class TileEntityTransporterBeacon extends TileEntityAbstractEnergyConsume
private UUID uuidTransporterCore; private UUID uuidTransporterCore;
private int tickDeploying = 0; private int tickDeploying = 0;
// computer properties // computed properties
private boolean isActive = false; private boolean isActive = false;
protected String stateTransporter = "";
public TileEntityTransporterBeacon() { public TileEntityTransporterBeacon() {
super(); super();
@ -128,7 +129,11 @@ public class TileEntityTransporterBeacon extends TileEntityAbstractEnergyConsume
} }
final TileEntityTransporterCore tileEntityTransporterCore = (TileEntityTransporterCore) tileEntity; final TileEntityTransporterCore tileEntityTransporterCore = (TileEntityTransporterCore) tileEntity;
return tileEntityTransporterCore.updateBeacon(this, uuidTransporterCore); final boolean isActive = tileEntityTransporterCore.updateBeacon(this, uuidTransporterCore);
final Object[] state = tileEntityTransporterCore.state();
stateTransporter = (String) state[1];
return isActive;
} }
@Override @Override
@ -144,6 +149,8 @@ public class TileEntityTransporterBeacon extends TileEntityAbstractEnergyConsume
if (isEnabled) { if (isEnabled) {
tickDeploying = 0; tickDeploying = 0;
} }
// always clear status
stateTransporter = "";
} }
@Override @Override

View file

@ -49,7 +49,6 @@ import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid; import net.minecraft.block.BlockLiquid;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.player.EntityPlayerMP;
@ -68,10 +67,14 @@ import net.minecraft.util.EnumHand;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockPos.MutableBlockPos; import net.minecraft.util.math.BlockPos.MutableBlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.WorldServer; import net.minecraft.world.WorldServer;
import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.ForgeChunkManager;
import net.minecraftforge.common.ForgeChunkManager.Ticket;
import net.minecraftforge.common.ForgeChunkManager.Type;
import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fml.common.Optional; import net.minecraftforge.fml.common.Optional;
@ -98,6 +101,7 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
private int tickComputerPulse = 0; private int tickComputerPulse = 0;
private boolean isConnected = false; private boolean isConnected = false;
private GlobalPosition globalPositionBeacon = null; private GlobalPosition globalPositionBeacon = null;
private Ticket ticketChunkloading;
private double energyCostForAcquiring = 0.0D; private double energyCostForAcquiring = 0.0D;
private double energyCostForEnergizing = 0.0D; private double energyCostForEnergizing = 0.0D;
private double lockStrengthOptimal = -1.0D; private double lockStrengthOptimal = -1.0D;
@ -258,6 +262,7 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
// execute state transitions // execute state transitions
switch (transporterState) { switch (transporterState) {
case DISABLED: case DISABLED:
releaseChunks();
isLockRequested = false; isLockRequested = false;
isEnergizeRequested = false; isEnergizeRequested = false;
lockStrengthActual = 0.0D; lockStrengthActual = 0.0D;
@ -272,6 +277,8 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
// force parameters validation for next tick // force parameters validation for next tick
tickUpdateParameters = 0; tickUpdateParameters = 0;
transporterState = EnumTransporterState.ACQUIRING; transporterState = EnumTransporterState.ACQUIRING;
} else {
releaseChunks();
} }
break; break;
@ -321,6 +328,13 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
} }
} }
@Override
public void onChunkUnload() {
releaseChunks();
super.onChunkUnload();
}
@Override @Override
public void invalidate() { public void invalidate() {
if (!world.isRemote) { if (!world.isRemote) {
@ -340,6 +354,7 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
} }
} }
} }
releaseChunks();
} }
private void state_energizing() { private void state_energizing() {
@ -667,6 +682,30 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
long mass; long mass;
} }
private void checkBeaconObsolescence() {
if (globalPositionBeacon != null) {
final WorldServer worldBeacon = globalPositionBeacon.getWorldServerIfLoaded();
if (worldBeacon == null) {
globalPositionBeacon = null;
isLockRequested = false;
isEnergizeRequested = false;
isJammed = false;
reasonJammed = "";
} else {
final TileEntity tileEntity = worldBeacon.getTileEntity(new BlockPos(globalPositionBeacon.x, globalPositionBeacon.y, globalPositionBeacon.z));
if ( !(tileEntity instanceof ITransporterBeacon)
|| !((ITransporterBeacon) tileEntity).isActive() ) {
globalPositionBeacon = null;
isLockRequested = false;
isEnergizeRequested = false;
isJammed = false;
reasonJammed = "";
}
}
}
}
private void updateParameters() { private void updateParameters() {
isJammed = false; isJammed = false;
reasonJammed = ""; reasonJammed = "";
@ -688,23 +727,8 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
final CelestialObject celestialObjectLocal = CelestialObjectManager.get(world, pos.getX(), pos.getZ()); final CelestialObject celestialObjectLocal = CelestialObjectManager.get(world, pos.getX(), pos.getZ());
final Vector3 v3Local_universal = StarMapRegistry.getUniversalCoordinates(celestialObjectLocal, globalPositionLocal.x, globalPositionLocal.y, globalPositionLocal.z); final Vector3 v3Local_universal = StarMapRegistry.getUniversalCoordinates(celestialObjectLocal, globalPositionLocal.x, globalPositionLocal.y, globalPositionLocal.z);
// check beacon obsolescence // validate context
if (globalPositionBeacon != null) { checkBeaconObsolescence();
final WorldServer worldBeacon = globalPositionBeacon.getWorldServerIfLoaded();
if (worldBeacon == null) {
globalPositionBeacon = null;
isLockRequested = false;
isEnergizeRequested = false;
} else {
final TileEntity tileEntity = worldBeacon.getTileEntity(new BlockPos(globalPositionBeacon.x, globalPositionBeacon.y, globalPositionBeacon.z));
if ( !(tileEntity instanceof ITransporterBeacon)
|| !((ITransporterBeacon) tileEntity).isActive() ) {
globalPositionBeacon = null;
isLockRequested = false;
isEnergizeRequested = false;
}
}
}
// compute remote global position // compute remote global position
GlobalPosition globalPositionRemoteNew = null; GlobalPosition globalPositionRemoteNew = null;
@ -722,8 +746,12 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
globalPositionRemoteNew = new GlobalPosition(celestialObjectChild.dimensionId, vRequest.x, (vRequest.y + 1024) % 256, vRequest.z); globalPositionRemoteNew = new GlobalPosition(celestialObjectChild.dimensionId, vRequest.x, (vRequest.y + 1024) % 256, vRequest.z);
} }
} else if (vRequest.y > 256) { } else if (vRequest.y > 256) {
vRequest.translateBack(celestialObjectLocal.getEntryOffset()); if (celestialObjectLocal == null) {
globalPositionRemoteNew = new GlobalPosition(celestialObjectLocal.parent.dimensionId, vRequest.x, vRequest.y % 256, vRequest.z); reasonJammed = "Unknown dimension, no reachable orbit";
} else {
vRequest.translateBack(celestialObjectLocal.getEntryOffset());
globalPositionRemoteNew = new GlobalPosition(celestialObjectLocal.parent.dimensionId, vRequest.x, vRequest.y % 256, vRequest.z);
}
} else { } else {
globalPositionRemoteNew = new GlobalPosition(world.provider.getDimension(), vRequest.x, vRequest.y, vRequest.z); globalPositionRemoteNew = new GlobalPosition(world.provider.getDimension(), vRequest.x, vRequest.y, vRequest.z);
@ -783,7 +811,8 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
// validate cross dimension transport rules // validate cross dimension transport rules
if (celestialObjectLocal != celestialObjectRemote) { if (celestialObjectLocal != celestialObjectRemote) {
if ( celestialObjectLocal.isHyperspace() if ( ( celestialObjectLocal != null
&& celestialObjectLocal.isHyperspace() )
|| celestialObjectRemote.isHyperspace() ) { || celestialObjectRemote.isHyperspace() ) {
isJammed = true; isJammed = true;
reasonJammed = "Blocked by warp field barrier"; reasonJammed = "Blocked by warp field barrier";
@ -920,15 +949,19 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
if (globalPositionBeacon.distance2To(tileEntity) <= radius2) {// it's a beacon party! we're happy with it... if (globalPositionBeacon.distance2To(tileEntity) <= radius2) {// it's a beacon party! we're happy with it...
return true; return true;
} }
if (!isJammed && WarpDriveConfig.LOGGING_TRANSPORTER) {// only log first jamming occurrence // always validate context
WarpDrive.logger.info(String.format("%s Conflicting beacon requests received %s is not %s", checkBeaconObsolescence();
this, tileEntity, uuid)); if (globalPositionBeacon != null) {
if (!isJammed && WarpDriveConfig.LOGGING_TRANSPORTER) {// only log first jamming occurrence
WarpDrive.logger.info(String.format("%s Conflicting beacon requests received %s is not %s",
this, tileEntity, uuid));
}
isJammed = true;
reasonJammed = "Conflicting beacon requests received";
tickCooldown = Math.max(tickCooldown, WarpDriveConfig.TRANSPORTER_JAMMED_COOLDOWN_TICKS);
return false;
} }
isJammed = true;
reasonJammed = "Conflicting beacon requests received";
tickCooldown = Math.max(tickCooldown, WarpDriveConfig.TRANSPORTER_JAMMED_COOLDOWN_TICKS);
return false;
} }
// check for new beacon // check for new beacon
@ -938,6 +971,7 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
isJammed = true; isJammed = true;
reasonJammed = "Beacon request received"; reasonJammed = "Beacon request received";
lockStrengthActual = 0.0D; lockStrengthActual = 0.0D;
forceChunks();
if (transporterState == EnumTransporterState.ENERGIZING) { if (transporterState == EnumTransporterState.ENERGIZING) {
transporterState = EnumTransporterState.ACQUIRING; transporterState = EnumTransporterState.ACQUIRING;
} }
@ -947,6 +981,60 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
return true; return true;
} }
private void forceChunks() {
if (ticketChunkloading != null) {
WarpDrive.logger.warn(String.format("%s Already chunkloading...",
this));
return;
}
if (WarpDriveConfig.LOGGING_TRANSPORTER) {
WarpDrive.logger.info(String.format("%s Forcing chunks",
this));
}
ticketChunkloading = ForgeChunkManager.requestTicket(WarpDrive.instance, world, Type.NORMAL);
if (ticketChunkloading == null) {
WarpDrive.logger.error(String.format("%s Chunkloading rejected",
this));
return;
}
final AxisAlignedBB aabbArea = getStarMapArea();
final int minX = (int) aabbArea.minX >> 4;
final int maxX = (int) aabbArea.maxX >> 4;
final int minZ = (int) aabbArea.minZ >> 4;
final int maxZ = (int) aabbArea.maxZ >> 4;
int chunkCount = 0;
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
chunkCount++;
if (chunkCount > ticketChunkloading.getMaxChunkListDepth()) {
WarpDrive.logger.error(String.format("%s Too many chunks to load: %d > %d",
this,
(maxX - minX + 1) * (maxZ - minZ + 1),
ticketChunkloading.getMaxChunkListDepth() ));
return;
}
ForgeChunkManager.forceChunk(ticketChunkloading, new ChunkPos(x, z));
}
}
return;
}
private void releaseChunks() {
if (ticketChunkloading == null) {
return;
}
if (WarpDriveConfig.LOGGING_TRANSPORTER) {
WarpDrive.logger.info(this + " Releasing chunks");
}
if (ticketChunkloading != null) {
ForgeChunkManager.releaseTicket(ticketChunkloading);
ticketChunkloading = null;
}
}
private static FocusValues getFocusValueAtCoordinates(final World world, final VectorI vLocation, final int radius) { private static FocusValues getFocusValueAtCoordinates(final World world, final VectorI vLocation, final int radius) {
// return default values if world isn't loaded // return default values if world isn't loaded
if (world == null) { if (world == null) {