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.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
@ -168,22 +169,27 @@ public class BlockTransporterBeacon extends BlockAbstractContainer {
}
final TileEntityTransporterBeacon tileEntityTransporterBeacon = (TileEntityTransporterBeacon) tileEntity;
// sneaking with an empty hand
if ( itemStackHeld.isEmpty()
&& entityPlayer.isSneaking() ) {
final boolean isEnabledOld = tileEntityTransporterBeacon.getIsEnabled();
tileEntityTransporterBeacon.setIsEnabled(!isEnabledOld);
final boolean isEnabledNew = tileEntityTransporterBeacon.getIsEnabled();
if (isEnabledOld != isEnabledNew) {
if (isEnabledNew) {
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")));
if (itemStackHeld.isEmpty()) {
if (!entityPlayer.isSneaking()) {// non-sneaking with an empty hand
Commons.addChatMessage(entityPlayer, Commons.getChatPrefix(this)
.appendSibling(new TextComponentString(tileEntityTransporterBeacon.stateTransporter)));
return true;
} else {// sneaking with an empty hand
final boolean isEnabledOld = tileEntityTransporterBeacon.getIsEnabled();
tileEntityTransporterBeacon.setIsEnabled(!isEnabledOld);
final boolean isEnabledNew = tileEntityTransporterBeacon.getIsEnabled();
if (isEnabledOld != isEnabledNew) {
if (isEnabledNew) {
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);

View file

@ -206,37 +206,6 @@ public class ItemBlockTransporterBeacon extends ItemBlockAbstractBase implements
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
@Override
public EnumActionResult onItemUse(@Nonnull final EntityPlayer entityPlayer,

View file

@ -36,8 +36,9 @@ public class TileEntityTransporterBeacon extends TileEntityAbstractEnergyConsume
private UUID uuidTransporterCore;
private int tickDeploying = 0;
// computer properties
// computed properties
private boolean isActive = false;
protected String stateTransporter = "";
public TileEntityTransporterBeacon() {
super();
@ -128,7 +129,11 @@ public class TileEntityTransporterBeacon extends TileEntityAbstractEnergyConsume
}
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
@ -144,6 +149,8 @@ public class TileEntityTransporterBeacon extends TileEntityAbstractEnergyConsume
if (isEnabled) {
tickDeploying = 0;
}
// always clear status
stateTransporter = "";
}
@Override

View file

@ -49,7 +49,6 @@ import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
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.BlockPos;
import net.minecraft.util.math.BlockPos.MutableBlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
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.fml.common.Optional;
@ -98,6 +101,7 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
private int tickComputerPulse = 0;
private boolean isConnected = false;
private GlobalPosition globalPositionBeacon = null;
private Ticket ticketChunkloading;
private double energyCostForAcquiring = 0.0D;
private double energyCostForEnergizing = 0.0D;
private double lockStrengthOptimal = -1.0D;
@ -258,6 +262,7 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
// execute state transitions
switch (transporterState) {
case DISABLED:
releaseChunks();
isLockRequested = false;
isEnergizeRequested = false;
lockStrengthActual = 0.0D;
@ -272,6 +277,8 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
// force parameters validation for next tick
tickUpdateParameters = 0;
transporterState = EnumTransporterState.ACQUIRING;
} else {
releaseChunks();
}
break;
@ -321,6 +328,13 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
}
}
@Override
public void onChunkUnload() {
releaseChunks();
super.onChunkUnload();
}
@Override
public void invalidate() {
if (!world.isRemote) {
@ -340,6 +354,7 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
}
}
}
releaseChunks();
}
private void state_energizing() {
@ -667,6 +682,30 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
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() {
isJammed = false;
reasonJammed = "";
@ -688,23 +727,8 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
final CelestialObject celestialObjectLocal = CelestialObjectManager.get(world, pos.getX(), pos.getZ());
final Vector3 v3Local_universal = StarMapRegistry.getUniversalCoordinates(celestialObjectLocal, globalPositionLocal.x, globalPositionLocal.y, globalPositionLocal.z);
// check beacon obsolescence
if (globalPositionBeacon != null) {
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;
}
}
}
// validate context
checkBeaconObsolescence();
// compute remote global position
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);
}
} else if (vRequest.y > 256) {
vRequest.translateBack(celestialObjectLocal.getEntryOffset());
globalPositionRemoteNew = new GlobalPosition(celestialObjectLocal.parent.dimensionId, vRequest.x, vRequest.y % 256, vRequest.z);
if (celestialObjectLocal == null) {
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 {
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
if (celestialObjectLocal != celestialObjectRemote) {
if ( celestialObjectLocal.isHyperspace()
if ( ( celestialObjectLocal != null
&& celestialObjectLocal.isHyperspace() )
|| celestialObjectRemote.isHyperspace() ) {
isJammed = true;
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...
return true;
}
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));
// always validate context
checkBeaconObsolescence();
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
@ -938,6 +971,7 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
isJammed = true;
reasonJammed = "Beacon request received";
lockStrengthActual = 0.0D;
forceChunks();
if (transporterState == EnumTransporterState.ENERGIZING) {
transporterState = EnumTransporterState.ACQUIRING;
}
@ -947,6 +981,60 @@ public class TileEntityTransporterCore extends TileEntityAbstractEnergyConsumer
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) {
// return default values if world isn't loaded
if (world == null) {