Spatial rework (#3048)

* Moved all spatial cells into a single dimension instead of one dimension per cell

Each cell will now be backed by a single region file each. So  backups and restores can still be done on a per cell level.

Old cells will not be migrated.

* Moved custom cell tracking to a capability based one on the world

The size and owner of a cell is now stored inside the capabilities of the world/dimension not a custom system and we can rely on forge handling the persistence of it.

* Added the cell id to the actual item tooltip, as this is now a real identifier and not an arbitrary dimension id.

* Added vanilla banners to the whitelist

* Added unittests to the dimension manager to ensure the algorithm mapping to the correct region file

* Updated the API to conform with the new dimenion/types/biomes registration and mappings

* Fixed a couple of bugs related to world/dimension/biome registration 

* Fixed a bug when transfering certain blocks due to passing missing/incorrect blockstate
This commit is contained in:
fscan
2017-08-24 11:24:33 +02:00
committed by yueh
parent 1513ba3f6a
commit bbf4d4a9ce
21 changed files with 615 additions and 427 deletions
@@ -28,6 +28,7 @@ import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.energy.IEnergyStorage;
import appeng.api.storage.ISpatialDimension;
import appeng.api.storage.IStorageMonitorableAccessor;
import appeng.integration.IntegrationRegistry;
import appeng.integration.IntegrationType;
@@ -45,6 +46,8 @@ public final class Capabilities
public static Capability<IStorageMonitorableAccessor> STORAGE_MONITORABLE_ACCESSOR;
public static Capability<ISpatialDimension> SPATIAL_DIMENSION;
public static Capability<ITeslaConsumer> TESLA_CONSUMER;
public static Capability<ITeslaHolder> TESLA_HOLDER;
@@ -57,6 +60,7 @@ public final class Capabilities
public static void register()
{
CapabilityManager.INSTANCE.register( IStorageMonitorableAccessor.class, createNullStorage(), NullMENetworkAccessor::new );
CapabilityManager.INSTANCE.register( ISpatialDimension.class, createNullStorage(), NullSpatialDimension::new );
}
@CapabilityInject( IStorageMonitorableAccessor.class )
@@ -65,6 +69,12 @@ public final class Capabilities
STORAGE_MONITORABLE_ACCESSOR = cap;
}
@CapabilityInject( ISpatialDimension.class )
private static void capISpatialDimensionRegistered( Capability<ISpatialDimension> cap )
{
SPATIAL_DIMENSION = cap;
}
@CapabilityInject( ITeslaConsumer.class )
private static void capITeslaConsumerRegistered( Capability<ITeslaConsumer> cap )
{
@@ -0,0 +1,70 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2017, 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.capabilities;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import appeng.api.storage.ISpatialDimension;
class NullSpatialDimension implements ISpatialDimension
{
@Override
public int createNewCellDimension( BlockPos size, int owner )
{
return -1;
}
@Override
public void deleteCellDimension( int cellStorageId )
{
}
@Override
public int getCellDimensionOwner( int cellStorageId )
{
return -1;
}
@Override
public BlockPos getCellDimensionOrigin( int cellStorageId )
{
return null;
}
@Override
public World getWorld()
{
return null;
}
@Override
public boolean isCellDimension( int cellDimID )
{
return false;
}
@Override
public BlockPos getCellContentSize( int cellDimId )
{
return null;
}
}
+13 -13
View File
@@ -95,8 +95,8 @@ public final class AEConfig extends Configuration implements IConfigurableObject
private final int[] levelByStacks = { 1, 10, 100, 1000 };
// Spatial IO/Dimension
private int storageBiomeID = -1;
private int storageProviderID = -1;
private int storageDimensionID = -1;
private double spatialPowerExponent = 1.35;
private double spatialPowerMultiplier = 1250.0;
@@ -251,8 +251,8 @@ public final class AEConfig extends Configuration implements IConfigurableObject
if( this.isFeatureEnabled( AEFeature.SPATIAL_IO ) )
{
this.storageBiomeID = this.get( "spatialio", "storageBiomeID", this.storageBiomeID ).getInt( this.storageBiomeID );
this.storageProviderID = this.get( "spatialio", "storageProviderID", this.storageProviderID ).getInt( this.storageProviderID );
this.storageDimensionID = this.get( "spatialio", "storageDimensionID", this.storageDimensionID ).getInt( this.storageDimensionID );
this.spatialPowerMultiplier = this.get( "spatialio", "spatialPowerMultiplier", this.spatialPowerMultiplier ).getDouble(
this.spatialPowerMultiplier );
this.spatialPowerExponent = this.get( "spatialio", "spatialPowerExponent", this.spatialPowerExponent ).getDouble( this.spatialPowerExponent );
@@ -397,8 +397,8 @@ public final class AEConfig extends Configuration implements IConfigurableObject
{
if( this.isFeatureEnabled( AEFeature.SPATIAL_IO ) )
{
this.get( "spatialio", "storageBiomeID", this.storageBiomeID ).set( this.storageBiomeID );
this.get( "spatialio", "storageProviderID", this.storageProviderID ).set( this.storageProviderID );
this.get( "spatialio", "storageDimensionID", this.storageDimensionID ).set( this.storageDimensionID );
}
this.get( "Client", "PowerUnit", this.selectedPowerUnit.name(), this.getListComment( this.selectedPowerUnit ) ).set( this.selectedPowerUnit.name() );
@@ -619,16 +619,16 @@ public final class AEConfig extends Configuration implements IConfigurableObject
return this.levelByStacks;
}
public int getStorageBiomeID()
{
return this.storageBiomeID;
}
public int getStorageProviderID()
{
return this.storageProviderID;
}
public int getStorageDimensionID()
{
return this.storageDimensionID;
}
public double getSpatialPowerExponent()
{
return this.spatialPowerExponent;
@@ -766,13 +766,13 @@ public final class AEConfig extends Configuration implements IConfigurableObject
// Setters keep visibility as low as possible.
void setStorageBiomeID( int id )
{
this.storageBiomeID = id;
}
void setStorageProviderID( int id )
{
this.storageProviderID = id;
}
void setStorageDimensionID( int id )
{
this.storageDimensionID = id;
}
}
+6 -1
View File
@@ -136,6 +136,11 @@ public final class AppEng
return this.registration.storageDimensionType;
}
public int getStorageDimensionID()
{
return this.registration.storageDimensionID;
}
@EventHandler
private void preInit( final FMLPreInitializationEvent event )
{
@@ -170,7 +175,7 @@ public final class AppEng
{
IntegrationRegistry.INSTANCE.add( type );
}
this.registration.preInitialize( event );
if( Platform.isClient() )
+48 -24
View File
@@ -35,10 +35,13 @@ import net.minecraft.item.Item;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.DimensionType;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
@@ -86,10 +89,8 @@ import appeng.core.features.registries.cell.CreativeCellHandler;
import appeng.core.localization.GuiText;
import appeng.core.localization.PlayerMessages;
import appeng.core.stats.PlayerStatsRegistration;
import appeng.core.worlddata.SpatialDimensionManager;
import appeng.hooks.TickHandler;
import appeng.integration.IntegrationRegistry;
import appeng.integration.IntegrationType;
import appeng.integration.Integrations;
import appeng.items.materials.ItemMaterial;
import appeng.items.parts.ItemFacade;
import appeng.loot.ChestLoot;
@@ -128,6 +129,7 @@ import appeng.worldgen.QuartzWorldGen;
final class Registration
{
DimensionType storageDimensionType;
int storageDimensionID;
Biome storageBiome;
private File recipeDirectory;
@@ -159,28 +161,29 @@ final class Registration
definitions.getRegistry().getBootstrapComponents( IPreInitComponent.class ).forEachRemaining( b -> b.preInitialize( event.getSide() ) );
}
private void registerSpatial( final boolean force, IForgeRegistry<Biome> registry )
private void registerSpatialBiome( IForgeRegistry<Biome> registry )
{
if( !AEConfig.instance().isFeatureEnabled( AEFeature.SPATIAL_IO ) )
{
return;
}
final AEConfig config = AEConfig.instance();
if( this.storageBiome == null )
{
this.storageBiome = new BiomeGenStorage();
}
registry.register( this.storageBiome.setRegistryName( "appliedenergistics2:storage_biome" ) );
}
if( config.getStorageProviderID() != -1 )
private void registerSpatialDimension()
{
final AEConfig config = AEConfig.instance();
if( !config.isFeatureEnabled( AEFeature.SPATIAL_IO ) )
{
this.storageDimensionType = DimensionType.register( "Storage Cell", "_cell", config.getStorageProviderID(), StorageWorldProvider.class, false );
return;
}
if( config.getStorageProviderID() == -1 && force )
if( config.getStorageProviderID() == -1 )
{
final Set<Integer> ids = new HashSet<>();
for( DimensionType type : DimensionType.values() )
@@ -188,17 +191,25 @@ final class Registration
ids.add( type.getId() );
}
config.setStorageProviderID( -11 );
while( ids.contains( config.getStorageProviderID() ) )
int newId = -11;
while( ids.contains( newId ) )
{
config.setStorageProviderID( config.getStorageProviderID() - 1 );
--newId;
}
this.storageDimensionType = DimensionType.register( "Storage Cell", "_cell", config.getStorageProviderID(), StorageWorldProvider.class, false );
config.setStorageProviderID( newId );
config.save();
}
this.storageDimensionType = DimensionType.register( "Storage Cell", "_cell", config.getStorageProviderID(), StorageWorldProvider.class, true );
if( config.getStorageDimensionID() == -1 )
{
config.setStorageDimensionID( DimensionManager.getNextFreeDimId() );
config.save();
}
this.storageDimensionID = config.getStorageDimensionID();
DimensionManager.registerDimension( this.storageDimensionID, this.storageDimensionType );
}
private void registerCraftHandlers( final IRecipeHandlerRegistry registry )
@@ -284,7 +295,7 @@ final class Registration
public void registerBiomes( RegistryEvent.Register<Biome> event )
{
final IForgeRegistry<Biome> registry = event.getRegistry();
this.registerSpatial( false, registry );
this.registerSpatialBiome( registry );
}
@SubscribeEvent
@@ -355,6 +366,16 @@ final class Registration
recipeHandler.injectRecipes();
}
@SubscribeEvent
public void attachSpatialDimensionManager( AttachCapabilitiesEvent<World> event )
{
if( AEConfig.instance()
.isFeatureEnabled( AEFeature.SPATIAL_IO ) && event.getObject() == DimensionManager.getWorld( AEConfig.instance().getStorageDimensionID() ) )
{
event.addCapability( new ResourceLocation( "appliedenergistics2:spatial_dimension_manager" ), new SpatialDimensionManager( event.getObject() ) );
}
}
void postInit( final FMLPostInitializationEvent event )
{
final IRegistryContainer registries = Api.INSTANCE.registries();
@@ -363,6 +384,8 @@ final class Registration
final IBlocks blocks = definitions.blocks();
final IItems items = definitions.items();
registerSpatialDimension();
// default settings..
( (P2PTunnelRegistry) registries.p2pTunnel() ).configure();
@@ -469,6 +492,7 @@ final class Registration
/*
* White List Vanilla...
*/
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityBanner.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityBeacon.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityBrewingStand.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityChest.class );
@@ -480,15 +504,15 @@ final class Registration
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityEnchantmentTable.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityEnderChest.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityEndPortal.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntitySkull.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityFurnace.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityMobSpawner.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntitySign.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityPiston.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityFlowerPot.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityNote.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityFurnace.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityHopper.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityMobSpawner.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityNote.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityPiston.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntityShulkerBox.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntitySign.class );
mr.whiteListTileEntity( net.minecraft.tileentity.TileEntitySkull.class );
/*
* Whitelist AE2
@@ -92,7 +92,10 @@ public enum GuiText
FETunnel,
PressureTunnel,
// spatial
StoredSize,
CellId,
CopyMode,
CopyModeDesc,
PatternTerminal,
@@ -39,7 +39,6 @@ import appeng.core.sync.packets.PacketLightning;
import appeng.core.sync.packets.PacketMEInventoryUpdate;
import appeng.core.sync.packets.PacketMatterCannon;
import appeng.core.sync.packets.PacketMockExplosion;
import appeng.core.sync.packets.PacketNewStorageDimension;
import appeng.core.sync.packets.PacketPaintedEntity;
import appeng.core.sync.packets.PacketPartPlacement;
import appeng.core.sync.packets.PacketPartialItem;
@@ -83,8 +82,6 @@ public class AppEngPacketHandlerBase
PACKET_CLICK( PacketClick.class ),
PACKET_NEW_STORAGE_DIMENSION( PacketNewStorageDimension.class ),
PACKET_SWITCH_GUIS( PacketSwitchGuis.class ),
PACKET_SWAP_SLOTS( PacketSwapSlots.class ),
@@ -24,15 +24,12 @@ import net.minecraft.network.NetHandlerPlayServer;
import net.minecraft.network.ThreadQuickExitException;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
import net.minecraftforge.fml.common.network.FMLEventChannel;
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ClientCustomPacketEvent;
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ServerConnectionFromClientEvent;
import net.minecraftforge.fml.common.network.FMLNetworkEvent.ServerCustomPacketEvent;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import appeng.core.sync.AppEngPacket;
import appeng.core.worlddata.WorldData;
public class NetworkHandler
@@ -89,21 +86,6 @@ public class NetworkHandler
}
}
@SubscribeEvent
public void newConnection( final ServerConnectionFromClientEvent ev )
{
WorldData.instance().dimensionData().sendToPlayer( ev.getManager() );
}
@SubscribeEvent
public void newConnection( final PlayerLoggedInEvent loginEvent )
{
if( loginEvent.player instanceof EntityPlayerMP )
{
WorldData.instance().dimensionData().sendToPlayer( null );
}
}
@SubscribeEvent
public void serverPacket( final ServerCustomPacketEvent ev )
{
@@ -1,72 +0,0 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, 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.core.sync.packets;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import appeng.core.AppEng;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
public class PacketNewStorageDimension extends AppEngPacket
{
private final int newDim;
// automatic.
public PacketNewStorageDimension( final ByteBuf stream )
{
this.newDim = stream.readInt();
}
// api
public PacketNewStorageDimension( final int newDim )
{
this.newDim = newDim;
final ByteBuf data = Unpooled.buffer();
data.writeInt( this.getPacketID() );
data.writeInt( newDim );
this.configureWrite( data );
}
@Override
@SideOnly( Side.CLIENT )
public void clientPacketData( final INetworkInfo network, final AppEngPacket packet, final EntityPlayer player )
{
try
{
DimensionManager.registerDimension( this.newDim, AppEng.instance().getStorageDimensionType() );
}
catch( final IllegalArgumentException iae )
{
// ok!
}
}
}
@@ -1,171 +0,0 @@
/*
* 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.core.worlddata;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import net.minecraft.network.NetworkManager;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.config.Configuration;
import net.minecraftforge.common.config.Property;
import appeng.api.util.WorldCoord;
import appeng.core.AppEng;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketNewStorageDimension;
import appeng.hooks.TickHandler;
/**
* @author thatsIch
* @version rv3 - 30.05.2015
* @since rv3 30.05.2015
*/
final class DimensionData implements IWorldDimensionData, IOnWorldStartable, IOnWorldStoppable
{
private static final String CONFIG_CATEGORY = "DimensionManager";
private static final String CONFIG_KEY = "StorageCells";
private static final int[] STORAGE_CELLS_DEFAULT = new int[0];
private static final String STORAGE_CELL_CATEGORY = "StorageCell";
private static final String STORAGE_CELL_SCALE_X_KEY = "scaleX";
private static final String STORAGE_CELL_SCALE_Y_KEY = "scaleY";
private static final String STORAGE_CELL_SCALE_Z_KEY = "scaleZ";
private static final String PACKAGE_DEST_CATEGORY = "DimensionManager";
private static final String PACKAGE_KEY_CATEGORY = "StorageCells";
private static final int[] PACKAGE_DEF_CATEGORY = new int[0];
private final Configuration config;
private final List<Integer> storageCellDimensionIDs;
DimensionData( @Nonnull final Configuration parentFile )
{
Preconditions.checkNotNull( parentFile );
this.config = parentFile;
final int[] storageCellIDs = this.storageCellIDsProperty().getIntList();
this.storageCellDimensionIDs = Lists.newArrayList();
for( final int storageCellID : storageCellIDs )
{
this.storageCellDimensionIDs.add( storageCellID );
}
}
private Property storageCellIDsProperty()
{
return this.config.get( CONFIG_CATEGORY, CONFIG_KEY, STORAGE_CELLS_DEFAULT );
}
@Override
public void onWorldStart()
{
for( final Integer storageCellDimID : this.storageCellDimensionIDs )
{
DimensionManager.registerDimension( storageCellDimID, AppEng.instance().getStorageDimensionType() );
}
this.config.save();
}
@Override
public void onWorldStop()
{
this.config.save();
for( final Integer storageCellDimID : this.storageCellDimensionIDs )
{
DimensionManager.unregisterDimension( storageCellDimID );
}
this.storageCellDimensionIDs.clear();
}
@Override
public void addStorageCell( final int newStorageCellID )
{
this.storageCellDimensionIDs.add( newStorageCellID );
DimensionManager.registerDimension( newStorageCellID, AppEng.instance().getStorageDimensionType() );
NetworkHandler.instance().sendToAll( new PacketNewStorageDimension( newStorageCellID ) );
final String[] values = new String[this.storageCellDimensionIDs.size()];
for( int x = 0; x < values.length; x++ )
{
values[x] = String.valueOf( this.storageCellDimensionIDs.get( x ) );
}
this.storageCellIDsProperty().set( values );
this.config.save();
}
@Override
public WorldCoord getStoredSize( final int dim )
{
final String category = STORAGE_CELL_CATEGORY + dim;
final int x = this.config.get( category, STORAGE_CELL_SCALE_X_KEY, 0 ).getInt();
final int y = this.config.get( category, STORAGE_CELL_SCALE_Y_KEY, 0 ).getInt();
final int z = this.config.get( category, STORAGE_CELL_SCALE_Z_KEY, 0 ).getInt();
return new WorldCoord( x, y, z );
}
@Override
public void setStoredSize( final int dim, final int targetX, final int targetY, final int targetZ )
{
final String category = STORAGE_CELL_CATEGORY + dim;
this.config.get( category, STORAGE_CELL_SCALE_X_KEY, 0 ).set( targetX );
this.config.get( category, STORAGE_CELL_SCALE_Y_KEY, 0 ).set( targetY );
this.config.get( category, STORAGE_CELL_SCALE_Z_KEY, 0 ).set( targetZ );
this.config.save();
}
@Override
public void sendToPlayer( @Nullable final NetworkManager manager )
{
if( manager != null )
{
for( final int newDim : this.config.get( PACKAGE_DEST_CATEGORY, PACKAGE_KEY_CATEGORY, PACKAGE_DEF_CATEGORY ).getIntList() )
{
manager.sendPacket( ( new PacketNewStorageDimension( newDim ) ).getProxy() );
}
}
else
{
for( final TickHandler.PlayerColor pc : TickHandler.INSTANCE.getPlayerColors().values() )
{
NetworkHandler.instance().sendToAll( pc.getPacket() );
}
}
}
}
@@ -39,9 +39,6 @@ public interface IWorldData
@Nonnull
IWorldPlayerData playerData();
@Nonnull
IWorldDimensionData dimensionData();
@Nonnull
IWorldCompassData compassData();
@@ -0,0 +1,245 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2017, 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.core.worlddata;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
import net.minecraftforge.common.util.INBTSerializable;
import appeng.api.storage.ISpatialDimension;
import appeng.capabilities.Capabilities;
public class SpatialDimensionManager implements ISpatialDimension, ICapabilitySerializable<NBTTagCompound>
{
private static final String NBT_SPATIAL_DATA_KEY = "spatial_data";
private static final String NBT_SPATIAL_ID_KEY = "id";
private World world;
private Map<Integer, StorageCellData> spatialData = new HashMap<>();
private static final int MAX_CELL_DIMENSION = 512;
public SpatialDimensionManager( World world )
{
this.world = world;
}
@Override
public World getWorld()
{
return this.world;
}
@Override
public int createNewCellDimension( BlockPos contentSize, int owner )
{
int newId = this.getNextId();
StorageCellData data = new StorageCellData();
data.contentDimension = contentSize;
data.owner = owner;
this.spatialData.put( newId, data );
return newId;
}
@Override
public void deleteCellDimension( int cellStorageId )
{
StorageCellData removed = spatialData.remove( cellStorageId );
if( removed != null )
{
this.clearCellArea( cellStorageId, removed );
}
}
@Override
public boolean isCellDimension( int cellStorageId )
{
return this.spatialData.containsKey( cellStorageId );
}
@Override
public int getCellDimensionOwner( int cellStorageId )
{
StorageCellData cell = this.spatialData.get( cellStorageId );
if( cell != null )
{
return cell.owner;
}
return -1;
}
@Override
public BlockPos getCellDimensionOrigin( int cellStorageId )
{
if( this.isCellDimension( cellStorageId ) )
{
return getBlockPosFromId( cellStorageId );
}
return null;
}
@Override
public BlockPos getCellContentSize( int cellStorageId )
{
StorageCellData cell = this.spatialData.get( cellStorageId );
if( cell != null )
{
return cell.contentDimension;
}
return null;
}
@Override
public boolean hasCapability( Capability<?> capability, EnumFacing facing )
{
return capability == Capabilities.SPATIAL_DIMENSION;
}
@Override
public <T> T getCapability( Capability<T> capability, EnumFacing facing )
{
if( capability == Capabilities.SPATIAL_DIMENSION )
{
return (T) this;
}
return null;
}
@Override
public NBTTagCompound serializeNBT()
{
final NBTTagCompound ret = new NBTTagCompound();
final NBTTagList list = new NBTTagList();
for( Map.Entry<Integer, StorageCellData> entry : this.spatialData.entrySet() )
{
final NBTTagCompound nbt = entry.getValue().serializeNBT();
nbt.setInteger( NBT_SPATIAL_ID_KEY, entry.getKey() );
list.appendTag( nbt );
}
ret.setTag( NBT_SPATIAL_DATA_KEY, list );
return ret;
}
@Override
public void deserializeNBT( NBTTagCompound nbt )
{
if( nbt.hasKey( NBT_SPATIAL_DATA_KEY ) )
{
final NBTTagList list = (NBTTagList) nbt.getTag( NBT_SPATIAL_DATA_KEY );
this.spatialData.clear();
for( int i = 0; i < list.tagCount(); ++i )
{
final NBTTagCompound entry = list.getCompoundTagAt( i );
final StorageCellData data = new StorageCellData();
final int id = entry.getInteger( NBT_SPATIAL_ID_KEY );
data.deserializeNBT( entry );
this.spatialData.put( id, data );
}
}
}
private int getNextId()
{
return this.spatialData.keySet().stream().max( Integer::compare ).orElse( -1 ) + 1;
}
private BlockPos getBlockPosFromId( int id )
{
int signBits = id & 0b11;
int offsetBits = id >> 2;
int offsetScale = 1;
int posx = MAX_CELL_DIMENSION / 2;
int posz = MAX_CELL_DIMENSION / 2;
// find quadrant
while( offsetBits != 0 )
{
posx += MAX_CELL_DIMENSION * offsetScale * ( offsetBits & 0b01 );
posz += MAX_CELL_DIMENSION * offsetScale * ( offsetBits >> 1 & 0b01 );
offsetBits >>= 2;
offsetScale <<= 1;
}
// mirror in one of 4 directions
if( ( signBits & 0b01 ) == 0 )
{
posx *= -1;
}
if( ( signBits & 0b10 ) == 0 )
{
posz *= -1;
}
// offset from cell center
posx -= 64;
posz -= 64;
return new BlockPos( posx, 64, posz );
}
private void clearCellArea( int cellId, StorageCellData cell )
{
// TODO reset chunks?
}
private static class StorageCellData implements INBTSerializable<NBTTagCompound>
{
private static final String NBT_OWNER_KEY = "owner";
private static final String NBT_DIM_X_KEY = "dim_x";
private static final String NBT_DIM_Y_KEY = "dim_y";
private static final String NBT_DIM_Z_KEY = "dim_z";
public BlockPos contentDimension;
public int owner;
@Override
public NBTTagCompound serializeNBT()
{
NBTTagCompound nbt = new NBTTagCompound();
nbt.setInteger( NBT_DIM_X_KEY, contentDimension.getX() );
nbt.setInteger( NBT_DIM_Y_KEY, contentDimension.getY() );
nbt.setInteger( NBT_DIM_Z_KEY, contentDimension.getZ() );
nbt.setInteger( NBT_OWNER_KEY, owner );
return nbt;
}
@Override
public void deserializeNBT( NBTTagCompound nbt )
{
contentDimension = new BlockPos( nbt.getInteger( NBT_DIM_X_KEY ), nbt.getInteger( NBT_DIM_Y_KEY ), nbt.getInteger( NBT_DIM_Z_KEY ) );
owner = nbt.getInteger( NBT_OWNER_KEY );
}
}
}
@@ -60,7 +60,6 @@ public final class WorldData implements IWorldData
private static IWorldData instance;
private final IWorldPlayerData playerData;
private final IWorldDimensionData dimensionData;
private final IWorldGridStorageData storageData;
private final IWorldCompassData compassData;
private final IWorldSpawnData spawnData;
@@ -87,7 +86,6 @@ public final class WorldData implements IWorldData
this.sharedConfig = new Configuration( settingsFile, AEConfig.VERSION );
final PlayerData playerData = new PlayerData( this.sharedConfig );
final DimensionData dimensionData = new DimensionData( this.sharedConfig );
final StorageData storageData = new StorageData( this.sharedConfig );
final ThreadFactory compassThreadFactory = new CompassThreadFactory();
@@ -97,13 +95,12 @@ public final class WorldData implements IWorldData
final IWorldSpawnData spawnData = new SpawnData( this.spawnDirectory );
this.playerData = playerData;
this.dimensionData = dimensionData;
this.storageData = storageData;
this.compassData = compassData;
this.spawnData = spawnData;
this.startables = Lists.<IOnWorldStartable>newArrayList( playerData, dimensionData, storageData );
this.stoppables = Lists.<IOnWorldStoppable>newArrayList( playerData, dimensionData, storageData, compassData );
this.startables = Lists.<IOnWorldStartable>newArrayList( playerData, storageData );
this.stoppables = Lists.<IOnWorldStoppable>newArrayList( playerData, storageData, compassData );
}
/**
@@ -198,13 +195,6 @@ public final class WorldData implements IWorldData
return this.playerData;
}
@Nonnull
@Override
public IWorldDimensionData dimensionData()
{
return this.dimensionData;
}
@Nonnull
@Override
public IWorldCompassData compassData()
@@ -24,6 +24,7 @@ import java.util.List;
import net.minecraft.client.util.ITooltipFlag;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.fml.relauncher.Side;
@@ -31,17 +32,23 @@ import net.minecraftforge.fml.relauncher.SideOnly;
import appeng.api.implementations.TransitionResult;
import appeng.api.implementations.items.ISpatialStorageCell;
import appeng.api.storage.ISpatialDimension;
import appeng.api.util.WorldCoord;
import appeng.capabilities.Capabilities;
import appeng.core.AppEng;
import appeng.core.localization.GuiText;
import appeng.core.worlddata.WorldData;
import appeng.items.AEBaseItem;
import appeng.spatial.StorageHelper;
import appeng.spatial.StorageWorldProvider;
import appeng.util.Platform;
public class ItemSpatialStorageCell extends AEBaseItem implements ISpatialStorageCell
{
private static final String NBT_CELL_ID_KEY = "StorageCellID";
private static final String NBT_SIZE_X_KEY = "sizeX";
private static final String NBT_SIZE_Y_KEY = "sizeY";
private static final String NBT_SIZE_Z_KEY = "sizeZ";
private final int maxRegion;
public ItemSpatialStorageCell( final int spatialScale )
@@ -54,6 +61,12 @@ public class ItemSpatialStorageCell extends AEBaseItem implements ISpatialStorag
@Override
public void addCheckedInformation( final ItemStack stack, final World world, final List<String> lines, final ITooltipFlag advancedTooltips )
{
final int id = this.getStoredDimensionID( stack );
if( id >= 0 )
{
lines.add( GuiText.CellId.getLocal() + ": " + id );
}
final WorldCoord wc = this.getStoredSize( stack );
if( wc.x > 0 )
{
@@ -74,26 +87,19 @@ public class ItemSpatialStorageCell extends AEBaseItem implements ISpatialStorag
}
@Override
public World getWorld( final ItemStack is )
public ISpatialDimension getSpatialDimension()
{
if( is.hasTagCompound() )
final int id = AppEng.instance().getStorageDimensionID();
World w = DimensionManager.getWorld( id );
if( w == null )
{
final NBTTagCompound c = is.getTagCompound();
final int dim = c.getInteger( "StorageDim" );
World w = DimensionManager.getWorld( dim );
if( w == null )
{
DimensionManager.initDimension( dim );
w = DimensionManager.getWorld( dim );
}
DimensionManager.initDimension( id );
w = DimensionManager.getWorld( id );
}
if( w != null )
{
if( w.provider instanceof StorageWorldProvider )
{
return w;
}
}
if( w != null && w.hasCapability( Capabilities.SPATIAL_DIMENSION, null ) )
{
return w.getCapability( Capabilities.SPATIAL_DIMENSION, null );
}
return null;
}
@@ -104,102 +110,80 @@ public class ItemSpatialStorageCell extends AEBaseItem implements ISpatialStorag
if( is.hasTagCompound() )
{
final NBTTagCompound c = is.getTagCompound();
if( Platform.isServer() )
{
final int dim = c.getInteger( "StorageDim" );
return WorldData.instance().dimensionData().getStoredSize( dim );
}
else
{
return new WorldCoord( c.getInteger( "sizeX" ), c.getInteger( "sizeY" ), c.getInteger( "sizeZ" ) );
}
return new WorldCoord( c.getInteger( NBT_SIZE_X_KEY ), c.getInteger( NBT_SIZE_Y_KEY ), c.getInteger( NBT_SIZE_Z_KEY ) );
}
return new WorldCoord( 0, 0, 0 );
}
@Override
public WorldCoord getMin( final ItemStack is )
public int getStoredDimensionID( final ItemStack is )
{
final World w = this.getWorld( is );
if( w != null )
if( is.hasTagCompound() )
{
final NBTTagCompound info = (NBTTagCompound) w.getWorldInfo().getAdditionalProperty( "storageCell" );
if( info != null )
{
return new WorldCoord( info.getInteger( "minX" ), info.getInteger( "minY" ), info.getInteger( "minZ" ) );
}
final NBTTagCompound c = is.getTagCompound();
return c.getInteger( NBT_CELL_ID_KEY );
}
return new WorldCoord( 0, 0, 0 );
return -1;
}
@Override
public WorldCoord getMax( final ItemStack is )
public TransitionResult doSpatialTransition( final ItemStack is, final World w, final WorldCoord min, final WorldCoord max, int playerId )
{
final World w = this.getWorld( is );
if( w != null )
{
final NBTTagCompound info = (NBTTagCompound) w.getWorldInfo().getAdditionalProperty( "storageCell" );
if( info != null )
{
return new WorldCoord( info.getInteger( "maxX" ), info.getInteger( "maxY" ), info.getInteger( "maxZ" ) );
}
}
return new WorldCoord( 0, 0, 0 );
}
@Override
public TransitionResult doSpatialTransition( final ItemStack is, final World w, final WorldCoord min, final WorldCoord max, final boolean doTransition )
{
final WorldCoord scale = this.getStoredSize( is );
final int targetX = max.x - min.x - 1;
final int targetY = max.y - min.y - 1;
final int targetZ = max.z - min.z - 1;
final int maxSize = this.getMaxStoredDim( is );
World destination = this.getWorld( is );
final BlockPos targetSize = new BlockPos( targetX, targetY, targetZ );
if( ( scale.x == 0 && scale.y == 0 && scale.z == 0 ) || ( scale.x == targetX && scale.y == targetY && scale.z == targetZ ) )
ISpatialDimension manager = this.getSpatialDimension();
int cellid = this.getStoredDimensionID( is );
if( cellid < 0 )
{
if( targetX <= maxSize && targetY <= maxSize && targetZ <= maxSize )
cellid = manager.createNewCellDimension( targetSize, playerId );
}
try
{
if( manager.isCellDimension( cellid ) )
{
if( destination == null )
BlockPos scale = manager.getCellContentSize( cellid );
if( scale.equals( targetSize ) )
{
destination = this.createNewWorld( is );
if( targetX <= maxSize && targetY <= maxSize && targetZ <= maxSize )
{
BlockPos offset = manager.getCellDimensionOrigin( cellid );
this.setStorageCell( is, cellid, targetSize );
StorageHelper.getInstance().swapRegions( w, min.x + 1, min.y + 1, min.z + 1, manager.getWorld(), offset.getX(), offset.getY(),
offset.getZ(), targetX - 1, targetY - 1,
targetZ - 1 );
return new TransitionResult( true, 0 );
}
}
final int floorBuffer = 64;
StorageHelper.getInstance().swapRegions( w, min.x + 1, min.y + 1, min.z + 1, destination, 0, floorBuffer, 0, targetX - 1, targetY - 1,
targetZ - 1 );
this.setStoredSize( is, targetX, targetY, targetZ );
return new TransitionResult( true, 0 );
}
return new TransitionResult( false, 0 );
}
finally
{
// clean up newly created dimensions that failed transfer
if( manager.isCellDimension( cellid ) && this.getStoredDimensionID( is ) < 0 )
{
manager.deleteCellDimension( cellid );
}
}
return new TransitionResult( false, 0 );
}
private World createNewWorld( final ItemStack is )
private void setStorageCell( final ItemStack is, int id, BlockPos size )
{
final NBTTagCompound c = Platform.openNbtData( is );
final int newDim = DimensionManager.getNextFreeDimId();
c.setInteger( "StorageDim", newDim );
WorldData.instance().dimensionData().addStorageCell( newDim );
DimensionManager.initDimension( newDim );
return DimensionManager.getWorld( newDim );
}
private void setStoredSize( final ItemStack is, final int targetX, final int targetY, final int targetZ )
{
if( is.hasTagCompound() )
{
final NBTTagCompound c = is.getTagCompound();
final int dim = c.getInteger( "StorageDim" );
c.setInteger( "sizeX", targetX );
c.setInteger( "sizeY", targetY );
c.setInteger( "sizeZ", targetZ );
WorldData.instance().dimensionData().setStoredSize( dim, targetX, targetY, targetZ );
}
c.setInteger( NBT_CELL_ID_KEY, id );
c.setInteger( NBT_SIZE_X_KEY, size.getX() );
c.setInteger( NBT_SIZE_Y_KEY, size.getY() );
c.setInteger( NBT_SIZE_Z_KEY, size.getZ() );
}
}
@@ -147,13 +147,12 @@ public class CachedPlane
else
{
final Object[] details = this.myColumns[tePOS.getX() - minX][tePOS.getZ() - minZ].getDetails( tePOS.getY() );
final Block blk = (Block) details[0];
final IBlockState blkState = (IBlockState) details[0];
// don't skip air, just let the code replace it...
if( blk != null && blk.isAir( c.getWorld().getBlockState( tePOS ), c.getWorld(), tePOS ) && blk.isReplaceable( c.getWorld(),
tePOS ) )
if( blkState != null && blkState.getBlock() == Platform.AIR_BLOCK && blkState.getMaterial().isReplaceable() )
{
c.getWorld().setBlockToAir( tePOS );
w.setBlockToAir( tePOS );
}
else
{
@@ -241,8 +241,9 @@ public class StorageHelper
@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, pos );
final IBlockState state = this.dst.getBlockState( pos );
final Block blk = state.getBlock();
blk.neighborChanged( state, this.dst, pos, blk, pos );
}
}
@@ -19,8 +19,11 @@
package appeng.tile.spatial;
import javax.annotation.Nonnull;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.World;
import net.minecraftforge.items.IItemHandler;
@@ -47,6 +50,7 @@ import appeng.tile.inventory.AppEngInternalInventory;
import appeng.util.IWorldCallable;
import appeng.util.Platform;
import appeng.util.inv.InvOperation;
import appeng.util.inv.WrapperFilteredItemHandler;
import appeng.util.inv.filter.IAEItemFilter;
@@ -54,12 +58,12 @@ public class TileSpatialIOPort extends AENetworkInvTile implements IWorldCallabl
{
private final AppEngInternalInventory inv = new AppEngInternalInventory( this, 2 );
private final IItemHandler invExt = new WrapperFilteredItemHandler( inv, new SpatialIOFilter() );
private YesNo lastRedstoneState = YesNo.UNDECIDED;
public TileSpatialIOPort()
{
this.getProxy().setFlags( GridFlags.REQUIRE_CHANNEL );
this.inv.setFilter( new SpatialIOFilter() );
}
@TileEvent( TileEventType.WORLD_NBT_WRITE )
@@ -143,7 +147,13 @@ public class TileSpatialIOPort extends AENetworkInvTile implements IWorldCallabl
final MENetworkEvent res = gi.postEvent( new MENetworkSpatialEvent( this, req ) );
if( !res.isCanceled() )
{
final TransitionResult tr = sc.doSpatialTransition( cell, this.world, spc.getMin(), spc.getMax(), true );
int playerId = -1;
if( getProxy().getSecurity().isAvailable() )
{
playerId = getProxy().getSecurity().getOwner();
}
final TransitionResult tr = sc.doSpatialTransition( cell, this.world, spc.getMin(), spc.getMax(), playerId );
if( tr.success )
{
energy.extractAEPower( req, Actionable.MODULATE, PowerMultiplier.CONFIG );
@@ -170,6 +180,12 @@ public class TileSpatialIOPort extends AENetworkInvTile implements IWorldCallabl
return new DimensionalCoord( this );
}
@Override
protected @Nonnull IItemHandler getItemHandlerForSide( @Nonnull EnumFacing side )
{
return this.invExt;
}
@Override
public IItemHandler getInternalInventory()
{