cfbc6b4543
Fixes #1712
330 lines
9.5 KiB
Java
330 lines
9.5 KiB
Java
/*
|
|
* This file is part of Applied Energistics 2.
|
|
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
|
|
*
|
|
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
|
*/
|
|
|
|
package appeng.spatial;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import net.minecraft.block.Block;
|
|
import net.minecraft.block.state.IBlockState;
|
|
import net.minecraft.entity.Entity;
|
|
import net.minecraft.entity.player.EntityPlayerMP;
|
|
import net.minecraft.util.math.AxisAlignedBB;
|
|
import net.minecraft.util.math.BlockPos;
|
|
import net.minecraft.util.math.MathHelper;
|
|
import net.minecraft.world.Teleporter;
|
|
import net.minecraft.world.World;
|
|
import net.minecraft.world.WorldServer;
|
|
|
|
import appeng.api.AEApi;
|
|
import appeng.api.util.WorldCoord;
|
|
import appeng.core.stats.Achievements;
|
|
import appeng.util.Platform;
|
|
|
|
|
|
public class StorageHelper
|
|
{
|
|
|
|
private static StorageHelper instance;
|
|
|
|
public static StorageHelper getInstance()
|
|
{
|
|
if( instance == null )
|
|
{
|
|
instance = new StorageHelper();
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
/**
|
|
* Mostly from dimensional doors.. which mostly got it form X-Comp.
|
|
*
|
|
* @param entity to be teleported entity
|
|
* @param link destination
|
|
*
|
|
* @return teleported entity
|
|
*/
|
|
private Entity teleportEntity( Entity entity, final TelDestination link )
|
|
{
|
|
final WorldServer oldWorld;
|
|
final WorldServer newWorld;
|
|
final EntityPlayerMP player;
|
|
|
|
try
|
|
{
|
|
oldWorld = (WorldServer) entity.worldObj;
|
|
newWorld = (WorldServer) link.dim;
|
|
player = ( entity instanceof EntityPlayerMP ) ? (EntityPlayerMP) entity : null;
|
|
}
|
|
catch( final Throwable e )
|
|
{
|
|
return entity;
|
|
}
|
|
|
|
if( oldWorld == null )
|
|
{
|
|
return entity;
|
|
}
|
|
if( newWorld == null )
|
|
{
|
|
return entity;
|
|
}
|
|
|
|
// Are we riding something? Teleport it instead.
|
|
if( entity.isRiding() )
|
|
{
|
|
return this.teleportEntity( entity.getRidingEntity(), link );
|
|
}
|
|
|
|
// Is something riding us? Handle it first.
|
|
final List<Entity> passangers = entity.getPassengers();
|
|
final List<Entity> passangersOnOtherSide = new ArrayList<>();
|
|
if( !passangers.isEmpty() )
|
|
{
|
|
for( Entity passanger : passangers )
|
|
{
|
|
passanger.dismountRidingEntity();
|
|
passangersOnOtherSide.add( teleportEntity( passanger, link ) );
|
|
}
|
|
// We keep track of all so we can remount them on the other side.
|
|
}
|
|
|
|
// load the chunk!
|
|
newWorld.getChunkProvider().provideChunk( MathHelper.floor_double( link.x ) >> 4, MathHelper.floor_double( link.z ) >> 4 );
|
|
|
|
if( newWorld != oldWorld )
|
|
{
|
|
if( player != null )
|
|
{
|
|
if( link.dim.provider instanceof StorageWorldProvider )
|
|
{
|
|
Achievements.SpatialIOExplorer.addToPlayer( player );
|
|
}
|
|
|
|
player.mcServer.getPlayerList().transferPlayerToDimension( player, link.dim.provider.getDimension(), new METeleporter( newWorld, link ) );
|
|
}
|
|
else
|
|
{
|
|
entity.getServer().getPlayerList().transferEntityToWorld( entity, entity.dimension, entity.getServer().worldServerForDimension( entity.dimension ), (WorldServer) link.dim, new METeleporter( newWorld, link ) );
|
|
}
|
|
}
|
|
|
|
if( !passangersOnOtherSide.isEmpty() )
|
|
{
|
|
if( player != null )
|
|
{
|
|
entity.worldObj.updateEntityWithOptionalForce( entity, true );
|
|
}
|
|
|
|
for( Entity passanger : passangersOnOtherSide )
|
|
{
|
|
passanger.startRiding( entity, true );
|
|
}
|
|
}
|
|
|
|
return entity;
|
|
}
|
|
|
|
private void transverseEdges( final int minX, final int minY, final int minZ, final int maxX, final int maxY, final int maxZ, final ISpatialVisitor visitor )
|
|
{
|
|
for( int y = minY; y < maxY; y++ )
|
|
{
|
|
for( int z = minZ; z < maxZ; z++ )
|
|
{
|
|
visitor.visit( new BlockPos( minX, y, z ) );
|
|
visitor.visit( new BlockPos( maxX, y, z ) );
|
|
}
|
|
}
|
|
|
|
for( int x = minX; x < maxX; x++ )
|
|
{
|
|
for( int z = minZ; z < maxZ; z++ )
|
|
{
|
|
visitor.visit( new BlockPos( x, minY, z ) );
|
|
visitor.visit( new BlockPos( x, maxY, z ) );
|
|
}
|
|
}
|
|
|
|
for( int x = minX; x < maxX; x++ )
|
|
{
|
|
for( int y = minY; y < maxY; y++ )
|
|
{
|
|
visitor.visit( new BlockPos( x, y, minZ ) );
|
|
visitor.visit( new BlockPos( x, y, maxZ ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
public void swapRegions( final World srcWorld,
|
|
final int srcX, final int srcY, final int srcZ,
|
|
final World dstWorld,
|
|
final int dstX, final int dstY, final int dstZ,
|
|
final int scaleX, final int scaleY, final int scaleZ )
|
|
{
|
|
AEApi.instance().definitions().blocks().matrixFrame().maybeBlock().ifPresent( matrixFrameBlock ->
|
|
this.transverseEdges( dstX - 1, dstY - 1, dstZ - 1, dstX + scaleX + 1, dstY + scaleY + 1, dstZ + scaleZ + 1, new WrapInMatrixFrame( matrixFrameBlock.getDefaultState(), dstWorld ) )
|
|
);
|
|
|
|
final AxisAlignedBB srcBox = new AxisAlignedBB( srcX, srcY, srcZ, srcX + scaleX + 1, srcY + scaleY + 1, srcZ + scaleZ + 1 );
|
|
|
|
final AxisAlignedBB dstBox = new AxisAlignedBB( dstX, dstY, dstZ, dstX + scaleX + 1, dstY + scaleY + 1, dstZ + scaleZ + 1 );
|
|
|
|
final CachedPlane cDst = new CachedPlane( dstWorld, dstX, dstY, dstZ, dstX + scaleX, dstY + scaleY, dstZ + scaleZ );
|
|
final CachedPlane cSrc = new CachedPlane( srcWorld, srcX, srcY, srcZ, srcX + scaleX, srcY + scaleY, srcZ + scaleZ );
|
|
|
|
// do nearly all the work... swaps blocks, tiles, and block ticks
|
|
cSrc.swap( cDst );
|
|
|
|
final List<Entity> srcE = srcWorld.getEntitiesWithinAABB( Entity.class, srcBox );
|
|
final List<Entity> dstE = dstWorld.getEntitiesWithinAABB( Entity.class, dstBox );
|
|
|
|
for( final Entity e : dstE )
|
|
{
|
|
this.teleportEntity( e, new TelDestination( srcWorld, srcBox, e.posX, e.posY, e.posZ, -dstX + srcX, -dstY + srcY, -dstZ + srcZ ) );
|
|
}
|
|
|
|
for( final Entity e : srcE )
|
|
{
|
|
this.teleportEntity( e, new TelDestination( dstWorld, dstBox, e.posX, e.posY, e.posZ, -srcX + dstX, -srcY + dstY, -srcZ + dstZ ) );
|
|
}
|
|
|
|
for( final WorldCoord wc : cDst.getUpdates() )
|
|
{
|
|
cSrc.getWorld().notifyBlockOfStateChange( wc.getPos(), Platform.AIR_BLOCK );
|
|
}
|
|
|
|
for( final WorldCoord wc : cSrc.getUpdates() )
|
|
{
|
|
cSrc.getWorld().notifyBlockOfStateChange( wc.getPos(), Platform.AIR_BLOCK );
|
|
}
|
|
|
|
this.transverseEdges( srcX - 1, srcY - 1, srcZ - 1, srcX + scaleX + 1, srcY + scaleY + 1, srcZ + scaleZ + 1, new TriggerUpdates( srcWorld ) );
|
|
this.transverseEdges( dstX - 1, dstY - 1, dstZ - 1, dstX + scaleX + 1, dstY + scaleY + 1, dstZ + scaleZ + 1, new TriggerUpdates( dstWorld ) );
|
|
|
|
this.transverseEdges( srcX, srcY, srcZ, srcX + scaleX, srcY + scaleY, srcZ + scaleZ, new TriggerUpdates( srcWorld ) );
|
|
this.transverseEdges( dstX, dstY, dstZ, dstX + scaleX, dstY + scaleY, dstZ + scaleZ, new TriggerUpdates( dstWorld ) );
|
|
|
|
/*
|
|
* IChunkProvider cp = destination.getChunkProvider(); if ( cp instanceof ChunkProviderServer ) {
|
|
* ChunkProviderServer
|
|
* srv = (ChunkProviderServer) cp; srv.unloadAllChunks(); }
|
|
* cp.unloadQueuedChunks();
|
|
*/
|
|
|
|
}
|
|
|
|
private static class TriggerUpdates implements ISpatialVisitor
|
|
{
|
|
|
|
private final World dst;
|
|
|
|
public TriggerUpdates( final World dst2 )
|
|
{
|
|
this.dst = dst2;
|
|
}
|
|
|
|
@Override
|
|
public void visit( final BlockPos pos )
|
|
{
|
|
final Block blk = this.dst.getBlockState( pos ).getBlock();
|
|
blk.neighborChanged( Platform.AIR_BLOCK.getDefaultState(), this.dst, pos, Platform.AIR_BLOCK );
|
|
}
|
|
}
|
|
|
|
private static class WrapInMatrixFrame implements ISpatialVisitor
|
|
{
|
|
|
|
private final World dst;
|
|
private final IBlockState state;
|
|
|
|
public WrapInMatrixFrame( final IBlockState state, final World dst2 )
|
|
{
|
|
this.dst = dst2;
|
|
this.state = state;
|
|
}
|
|
|
|
@Override
|
|
public void visit( final BlockPos pos )
|
|
{
|
|
this.dst.setBlockState( pos, this.state );
|
|
}
|
|
}
|
|
|
|
private static class TelDestination
|
|
{
|
|
|
|
private final World dim;
|
|
private final double x;
|
|
private final double y;
|
|
private final double z;
|
|
private final int xOff;
|
|
private final int yOff;
|
|
private final int zOff;
|
|
|
|
TelDestination( final World dimension, final AxisAlignedBB srcBox, final double x, final double y, final double z, final int tileX, final int tileY, final int tileZ )
|
|
{
|
|
this.dim = dimension;
|
|
this.x = Math.min( srcBox.maxX - 0.5, Math.max( srcBox.minX + 0.5, x + tileX ) );
|
|
this.y = Math.min( srcBox.maxY - 0.5, Math.max( srcBox.minY + 0.5, y + tileY ) );
|
|
this.z = Math.min( srcBox.maxZ - 0.5, Math.max( srcBox.minZ + 0.5, z + tileZ ) );
|
|
this.xOff = tileX;
|
|
this.yOff = tileY;
|
|
this.zOff = tileZ;
|
|
}
|
|
}
|
|
|
|
private static class METeleporter extends Teleporter
|
|
{
|
|
|
|
private final TelDestination destination;
|
|
|
|
public METeleporter( final WorldServer par1WorldServer, final TelDestination d )
|
|
{
|
|
super( par1WorldServer );
|
|
this.destination = d;
|
|
}
|
|
|
|
@Override
|
|
public void placeInPortal( final Entity par1Entity, final float rotationYaw )
|
|
{
|
|
par1Entity.setLocationAndAngles( this.destination.x, this.destination.y, this.destination.z, par1Entity.rotationYaw, 0.0F );
|
|
par1Entity.motionX = par1Entity.motionY = par1Entity.motionZ = 0.0D;
|
|
}
|
|
|
|
@Override
|
|
public boolean placeInExistingPortal( final Entity entityIn, final float p_180620_2_ )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean makePortal( final Entity par1Entity )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void removeStalePortalLocations( final long par1 )
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|