diff --git a/build.gradle b/build.gradle index 7b931f571..b893726b0 100644 --- a/build.gradle +++ b/build.gradle @@ -73,7 +73,6 @@ sourceSets { api main { java { - exclude 'appeng/worldgen/**' exclude 'appeng/spatial/StorageChunkProvider.java' exclude 'appeng/spatial/StorageHelper.java' exclude 'appeng/spatial/CachedPlane.java' diff --git a/src/api/java/appeng/api/features/IWorldGen.java b/src/api/java/appeng/api/features/IWorldGen.java index 154aa8a04..e9fa93136 100644 --- a/src/api/java/appeng/api/features/IWorldGen.java +++ b/src/api/java/appeng/api/features/IWorldGen.java @@ -24,6 +24,7 @@ package appeng.api.features; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraft.world.dimension.Dimension; @@ -33,9 +34,9 @@ public interface IWorldGen void disableWorldGenForProviderID( WorldGenType type, Class provider ); - void enableWorldGenForDimension( WorldGenType type, int dimID ); + void enableWorldGenForDimension( WorldGenType type, ResourceLocation dimID ); - void disableWorldGenForDimension( WorldGenType type, int dimID ); + void disableWorldGenForDimension( WorldGenType type, ResourceLocation dimID ); boolean isWorldGenEnabled( WorldGenType type, World w ); diff --git a/src/main/java/appeng/client/render/model/SkyCompassBakedModel.java b/src/main/java/appeng/client/render/model/SkyCompassBakedModel.java index e1c710f0c..c8f41afae 100644 --- a/src/main/java/appeng/client/render/model/SkyCompassBakedModel.java +++ b/src/main/java/appeng/client/render/model/SkyCompassBakedModel.java @@ -26,6 +26,8 @@ import java.util.Random; import javax.annotation.Nullable; +import appeng.hooks.CompassManager; +import appeng.hooks.CompassResult; import net.minecraft.block.BlockState; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.renderer.Matrix4f; @@ -188,38 +190,38 @@ public class SkyCompassBakedModel implements IDynamicBakedModel { // Only query for a meteor position if we know our own position -// FIXME if( pos != null ) -// FIXME { -// FIXME CompassResult cr = CompassManager.INSTANCE.getCompassDirection( 0, pos.getX(), pos.getY(), pos.getZ() ); -// FIXME -// FIXME // Prefetch meteor positions from the server for adjacent blocks so they are available more quickly when -// FIXME // we're moving -// FIXME if( prefetch ) -// FIXME { -// FIXME for( int i = 0; i < 3; i++ ) -// FIXME { -// FIXME for( int j = 0; j < 3; j++ ) -// FIXME { -// FIXME CompassManager.INSTANCE.getCompassDirection( 0, pos.getX() + i - 1, pos.getY(), pos.getZ() + j - 1 ); -// FIXME } -// FIXME } -// FIXME } -// FIXME -// FIXME if( cr.isValidResult() ) -// FIXME { -// FIXME if( cr.isSpin() ) -// FIXME { -// FIXME long timeMillis = System.currentTimeMillis(); -// FIXME // .5 seconds per full rotation -// FIXME timeMillis %= 500; -// FIXME return timeMillis / 500.f * (float) Math.PI * 2; -// FIXME } -// FIXME else -// FIXME { -// FIXME return (float) cr.getRad(); -// FIXME } -// FIXME } -// FIXME } + if( pos != null ) + { + CompassResult cr = CompassManager.INSTANCE.getCompassDirection( 0, pos.getX(), pos.getY(), pos.getZ() ); + + // Prefetch meteor positions from the server for adjacent blocks so they are available more quickly when + // we're moving + if( prefetch ) + { + for( int i = 0; i < 3; i++ ) + { + for( int j = 0; j < 3; j++ ) + { + CompassManager.INSTANCE.getCompassDirection( 0, pos.getX() + i - 1, pos.getY(), pos.getZ() + j - 1 ); + } + } + } + + if( cr.isValidResult() ) + { + if( cr.isSpin() ) + { + long timeMillis = System.currentTimeMillis(); + // .5 seconds per full rotation + timeMillis %= 500; + return timeMillis / 500.f * (float) Math.PI * 2; + } + else + { + return (float) cr.getRad(); + } + } + } long timeMillis = System.currentTimeMillis(); // 3 seconds per full rotation diff --git a/src/main/java/appeng/core/AppEng.java b/src/main/java/appeng/core/AppEng.java index 9f9c75a9b..813ddd38b 100644 --- a/src/main/java/appeng/core/AppEng.java +++ b/src/main/java/appeng/core/AppEng.java @@ -19,17 +19,14 @@ package appeng.core; -import java.io.File; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; -import appeng.api.AEApi; import appeng.block.paint.PaintSplotchesModel; import appeng.block.qnb.QnbFormedModel; import appeng.bootstrap.components.IClientSetupComponent; import appeng.bootstrap.components.IInitComponent; import appeng.bootstrap.components.IPostInitComponent; -import appeng.bootstrap.components.ItemColorComponent; import appeng.capabilities.Capabilities; import appeng.client.ClientHelper; import appeng.client.render.DummyFluidItemModel; @@ -45,9 +42,7 @@ import appeng.core.sync.network.NetworkHandler; import appeng.core.worlddata.WorldData; import appeng.hooks.TickHandler; import appeng.parts.PartPlacement; -import appeng.parts.automation.PlaneModel; import appeng.parts.automation.PlaneModelLoader; -import appeng.server.AECommand; import appeng.server.ServerHelper; import com.google.common.base.Stopwatch; import net.minecraft.block.Block; @@ -56,14 +51,18 @@ import net.minecraft.inventory.container.ContainerType; import net.minecraft.item.Item; import net.minecraft.item.crafting.IRecipeSerializer; import net.minecraft.particles.ParticleType; +import net.minecraft.server.MinecraftServer; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ResourceLocation; +import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.gen.feature.Feature; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.client.event.ColorHandlerEvent; import net.minecraftforge.client.model.ModelLoaderRegistry; import net.minecraftforge.client.model.geometry.IModelGeometry; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.fml.CrashReportExtender; import net.minecraftforge.fml.DistExecutor; @@ -75,12 +74,8 @@ import net.minecraftforge.fml.config.ModConfig; import appeng.core.crash.ModCrashEnhancement; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.event.server.FMLServerStartedEvent; -import net.minecraftforge.fml.event.server.FMLServerStartingEvent; -import net.minecraftforge.fml.event.server.FMLServerStoppedEvent; -import net.minecraftforge.fml.event.server.FMLServerStoppingEvent; +import net.minecraftforge.fml.event.server.*; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.fml.network.NetworkRegistry; import javax.annotation.Nonnull; @@ -136,6 +131,7 @@ public final class AppEng modEventBus.addGenericListener(TileEntityType.class, registration::registerTileEntities); modEventBus.addGenericListener(ContainerType.class, registration::registerContainerTypes); modEventBus.addGenericListener(IRecipeSerializer.class, registration::registerRecipeSerializers); + modEventBus.addGenericListener(Feature.class, registration::registerWorldGen); modEventBus.addListener(registration::registerParticleFactories); modEventBus.addListener(registration::registerTextures); modEventBus.addListener(registration::registerCommands); @@ -150,7 +146,7 @@ public final class AppEng MinecraftForge.EVENT_BUS.addListener( TickHandler.INSTANCE::unloadWorld ); MinecraftForge.EVENT_BUS.addListener( TickHandler.INSTANCE::onTick ); - MinecraftForge.EVENT_BUS.addListener( this::serverAboutToStart ); + MinecraftForge.EVENT_BUS.addListener( this::onServerAboutToStart ); MinecraftForge.EVENT_BUS.addListener( this::serverStopped ); MinecraftForge.EVENT_BUS.addListener( this::serverStopping ); @@ -305,9 +301,9 @@ public final class AppEng AELog.info( "Post Initialization ( ended after " + start.elapsed( TimeUnit.MILLISECONDS ) + "ms )" ); } - private void serverAboutToStart( final FMLServerStartedEvent evt ) + private void onServerAboutToStart(final FMLServerAboutToStartEvent evt) { - WorldData.onServerAboutToStart( evt.getServer() ); + WorldData.onServerStarting( evt.getServer() ); } private void serverStopping( final FMLServerStoppingEvent event ) diff --git a/src/main/java/appeng/core/Registration.java b/src/main/java/appeng/core/Registration.java index b296418bf..7d6f6b863 100644 --- a/src/main/java/appeng/core/Registration.java +++ b/src/main/java/appeng/core/Registration.java @@ -26,6 +26,7 @@ import appeng.api.definitions.IItems; import appeng.api.definitions.IParts; import appeng.api.features.IRegistryContainer; import appeng.api.features.IWirelessTermHandler; +import appeng.api.features.IWorldGen; import appeng.api.movable.IMovableRegistry; import appeng.api.networking.IGridCacheRegistry; import appeng.api.networking.crafting.ICraftingGrid; @@ -37,7 +38,6 @@ import appeng.api.networking.storage.IStorageGrid; import appeng.api.networking.ticking.ITickManager; import appeng.bootstrap.IModelRegistry; import appeng.bootstrap.components.*; -import appeng.capabilities.Capabilities; import appeng.client.gui.implementations.GuiCellWorkbench; import appeng.client.gui.implementations.GuiChest; import appeng.client.gui.implementations.GuiCondenser; @@ -101,6 +101,7 @@ import appeng.recipes.handlers.InscriberRecipeSerializer; import appeng.server.AECommand; import appeng.tile.AEBaseTile; import net.minecraft.advancements.CriteriaTriggers; +import appeng.worldgen.MeteoriteWorldGen; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.ScreenManager; @@ -112,6 +113,13 @@ import net.minecraft.item.crafting.IRecipeType; import net.minecraft.particles.ParticleType; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.ResourceLocation; +import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.gen.GenerationStage; +import net.minecraft.world.gen.feature.ConfiguredFeature; +import net.minecraft.world.gen.feature.Feature; +import net.minecraft.world.gen.feature.IFeatureConfig; +import net.minecraft.world.gen.feature.NoFeatureConfig; +import net.minecraft.world.gen.placement.Placement; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.event.*; @@ -127,6 +135,8 @@ import net.minecraftforge.fml.network.IContainerFactory; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.IForgeRegistry; +import java.util.Objects; + final class Registration { @@ -752,16 +762,6 @@ final class Registration // FIXME { // FIXME // TODO: VILLAGER TRADING // FIXME // VillagerRegistry.instance().getRegisteredVillagers().registerVillageTradeHandler( 3, new AETrading() ); -// FIXME } - -// FIXME if( AEConfig.instance().isFeatureEnabled( AEFeature.CERTUS_QUARTZ_WORLD_GEN ) ) -// FIXME { -// FIXME GameRegistry.registerWorldGenerator( new QuartzWorldGen(), 0 ); -// FIXME } -// FIXME -// FIXME if( AEConfig.instance().isFeatureEnabled( AEFeature.METEORITE_WORLD_GEN ) ) -// FIXME { -// FIXME GameRegistry.registerWorldGenerator( new MeteoriteWorldGen(), 0 ); // FIXME } final IMovableRegistry mr = registries.movable(); @@ -799,25 +799,42 @@ final class Registration */ mr.whiteListTileEntity( AEBaseTile.class ); -// FIXME /* -// FIXME * world gen -// FIXME */ -// FIXME for( final WorldGenType type : WorldGenType.values() ) -// FIXME { -// FIXME registries.worldgen().disableWorldGenForProviderID( type, StorageWorldProvider.class ); -// FIXME -// FIXME // nether -// FIXME registries.worldgen().disableWorldGenForDimension( type, -1 ); -// FIXME -// FIXME // end -// FIXME registries.worldgen().disableWorldGenForDimension( type, 1 ); -// FIXME } -// FIXME -// FIXME // whitelist from config -// FIXME for( final int dimension : AEConfig.instance().getMeteoriteDimensionWhitelist() ) -// FIXME { -// FIXME registries.worldgen().enableWorldGenForDimension( WorldGenType.METEORITES, dimension ); -// FIXME } + /* + * world gen + */ + for( final IWorldGen.WorldGenType type : IWorldGen.WorldGenType.values() ) + { + // FIXME: registries.worldgen().disableWorldGenForProviderID( type, StorageWorldProvider.class ); + + registries.worldgen().disableWorldGenForDimension( type, DimensionType.THE_NETHER.getRegistryName() ); + + registries.worldgen().disableWorldGenForDimension( type, DimensionType.THE_NETHER.getRegistryName() ); + } + + // whitelist from config + for( final String dimension : AEConfig.instance().getMeteoriteDimensionWhitelist() ) + { + registries.worldgen().enableWorldGenForDimension( IWorldGen.WorldGenType.METEORITES, new ResourceLocation( dimension ) ); + } + + ForgeRegistries.BIOMES.forEach( + b -> { + b.addFeature(GenerationStage.Decoration.TOP_LAYER_MODIFICATION, + new ConfiguredFeature>( + MeteoriteWorldGen.INSTANCE, + IFeatureConfig.NO_FEATURE_CONFIG + ) + ); + } + ); + + } + + public void registerWorldGen( RegistryEvent.Register> evt ) + { + IForgeRegistry> r = evt.getRegistry(); + + r.register( MeteoriteWorldGen.INSTANCE ); } // private static class ModelLoaderWrapper implements IModelRegistry diff --git a/src/main/java/appeng/core/features/registries/WorldGenRegistry.java b/src/main/java/appeng/core/features/registries/WorldGenRegistry.java index 2d9475a7b..3a1a24409 100644 --- a/src/main/java/appeng/core/features/registries/WorldGenRegistry.java +++ b/src/main/java/appeng/core/features/registries/WorldGenRegistry.java @@ -21,10 +21,13 @@ package appeng.core.features.registries; import java.util.HashSet; +import net.minecraft.util.ResourceLocation; import net.minecraft.world.World; import net.minecraft.world.dimension.Dimension; import appeng.api.features.IWorldGen; +import net.minecraft.world.dimension.DimensionType; +import net.minecraftforge.common.extensions.IForgeDimension; public final class WorldGenRegistry implements IWorldGen @@ -61,7 +64,7 @@ public final class WorldGenRegistry implements IWorldGen } @Override - public void enableWorldGenForDimension( final WorldGenType type, final int dimensionID ) + public void enableWorldGenForDimension( final WorldGenType type, final ResourceLocation dimensionID ) { if( type == null ) { @@ -72,7 +75,7 @@ public final class WorldGenRegistry implements IWorldGen } @Override - public void disableWorldGenForDimension( final WorldGenType type, final int dimensionID ) + public void disableWorldGenForDimension( final WorldGenType type, final ResourceLocation dimensionID ) { if( type == null ) { @@ -95,9 +98,10 @@ public final class WorldGenRegistry implements IWorldGen throw new IllegalArgumentException( "Bad Provider Passed" ); } + ResourceLocation id = w.dimension.getDimension().getType().getRegistryName(); final boolean isBadProvider = this.types[type.ordinal()].badProviders.contains( w.dimension.getClass() ); - final boolean isBadDimension = this.types[type.ordinal()].badDimensions.contains( w.dimension.getDimension() ); - final boolean isGoodDimension = this.types[type.ordinal()].enabledDimensions.contains( w.dimension.getDimension() ); + final boolean isBadDimension = this.types[type.ordinal()].badDimensions.contains( id ); + final boolean isGoodDimension = this.types[type.ordinal()].enabledDimensions.contains( id ); if( isBadProvider || isBadDimension ) { @@ -116,7 +120,7 @@ public final class WorldGenRegistry implements IWorldGen { final HashSet> badProviders = new HashSet<>(); - final HashSet badDimensions = new HashSet<>(); - final HashSet enabledDimensions = new HashSet<>(); + final HashSet badDimensions = new HashSet<>(); + final HashSet enabledDimensions = new HashSet<>(); } } diff --git a/src/main/java/appeng/core/sync/packets/PacketCompassRequest.java b/src/main/java/appeng/core/sync/packets/PacketCompassRequest.java index 365123aee..d4fc41d04 100644 --- a/src/main/java/appeng/core/sync/packets/PacketCompassRequest.java +++ b/src/main/java/appeng/core/sync/packets/PacketCompassRequest.java @@ -19,6 +19,7 @@ package appeng.core.sync.packets; +import appeng.core.worlddata.WorldData; import io.netty.buffer.Unpooled; import net.minecraft.entity.player.PlayerEntity; @@ -77,6 +78,6 @@ public class PacketCompassRequest extends AppEngPacket implements ICompassCallba this.talkBackTo = player; final DimensionalCoord loc = new DimensionalCoord( player.world, this.cx << 4, this.cdy << 5, this.cz << 4 ); - // FIXME WorldData.instance().compassData().service().getCompassDirection( loc, 174, this ); + WorldData.instance().compassData().service().getCompassDirection( loc, 174, this ); } } diff --git a/src/main/java/appeng/core/sync/packets/PacketCompassResponse.java b/src/main/java/appeng/core/sync/packets/PacketCompassResponse.java index 0d02473ee..1287ad0ae 100644 --- a/src/main/java/appeng/core/sync/packets/PacketCompassResponse.java +++ b/src/main/java/appeng/core/sync/packets/PacketCompassResponse.java @@ -19,6 +19,7 @@ package appeng.core.sync.packets; +import appeng.hooks.CompassManager; import appeng.hooks.CompassResult; import io.netty.buffer.Unpooled; @@ -71,6 +72,6 @@ public class PacketCompassResponse extends AppEngPacket @Override public void clientPacketData( final INetworkInfo network, final PlayerEntity player ) { -// TODO CompassManager.INSTANCE.postResult( this.attunement, this.cx << 4, this.cdy << 5, this.cz << 4, this.cr ); + CompassManager.INSTANCE.postResult( this.attunement, this.cx << 4, this.cdy << 5, this.cz << 4, this.cr ); } } diff --git a/src/main/java/appeng/core/worlddata/CompassData.java b/src/main/java/appeng/core/worlddata/CompassData.java index 22da52fba..b469d9d7e 100644 --- a/src/main/java/appeng/core/worlddata/CompassData.java +++ b/src/main/java/appeng/core/worlddata/CompassData.java @@ -38,9 +38,8 @@ final class CompassData implements IWorldCompassData @Nonnull private final CompassService service; - public CompassData( @Nonnull final File compassDirectory, @Nonnull final CompassService service ) + public CompassData( @Nonnull final CompassService service ) { - Preconditions.checkNotNull( compassDirectory ); Preconditions.checkNotNull( service ); this.service = service; diff --git a/src/main/java/appeng/core/worlddata/IWorldData.java b/src/main/java/appeng/core/worlddata/IWorldData.java index e9c453ef7..c46e4a572 100644 --- a/src/main/java/appeng/core/worlddata/IWorldData.java +++ b/src/main/java/appeng/core/worlddata/IWorldData.java @@ -41,7 +41,4 @@ public interface IWorldData @Nonnull IWorldCompassData compassData(); - - @Nonnull - IWorldSpawnData spawnData(); } diff --git a/src/main/java/appeng/core/worlddata/MeteorDataNameEncoder.java b/src/main/java/appeng/core/worlddata/MeteorDataNameEncoder.java index 0ba649dca..916467764 100644 --- a/src/main/java/appeng/core/worlddata/MeteorDataNameEncoder.java +++ b/src/main/java/appeng/core/worlddata/MeteorDataNameEncoder.java @@ -33,14 +33,6 @@ import com.google.common.base.Preconditions; */ public class MeteorDataNameEncoder { - private static final char DATA_SEPARATOR = '_'; - private static final char BASE_EXTENSION_SEPARATOR = '.'; - private static final String FILE_EXTENSION = "dat"; - - private final char dataSeparator; - @Nonnull - private final String fileExtension; - private final char baseExtSeparator; private final int bitScale; /** @@ -48,23 +40,11 @@ public class MeteorDataNameEncoder */ public MeteorDataNameEncoder( final int bitScale ) { - this( DATA_SEPARATOR, BASE_EXTENSION_SEPARATOR, FILE_EXTENSION, bitScale ); - } - - private MeteorDataNameEncoder( final char dataSeparator, final char baseExtSeparator, @Nonnull final String fileExtension, final int bitScale ) - { - Preconditions.checkNotNull( fileExtension ); - Preconditions.checkArgument( !fileExtension.isEmpty() ); Preconditions.checkArgument( bitScale >= 0 ); - - this.dataSeparator = dataSeparator; - this.baseExtSeparator = baseExtSeparator; - this.fileExtension = fileExtension; this.bitScale = bitScale; } /** - * @param dimension ID of the processed dimension. Can be any integer * @param chunkX X coordinate of the chunk. Can be any integer * @param chunkZ Z coordinate of the chunk. Can be any integer * @@ -73,12 +53,10 @@ public class MeteorDataNameEncoder * * @since rv3 05.06.2015 */ - public String encode( final int dimension, final int chunkX, final int chunkZ ) + public String encode( final int chunkX, final int chunkZ ) { final int shiftedX = chunkX >> this.bitScale; final int shiftedZ = chunkZ >> this.bitScale; - - return String.format( "%d%c%d%c%d%c%s", dimension, this.dataSeparator, shiftedX, this.dataSeparator, shiftedZ, this.baseExtSeparator, - this.fileExtension ); + return shiftedX + "_" + shiftedZ; } } diff --git a/src/main/java/appeng/core/worlddata/SpawnData.java b/src/main/java/appeng/core/worlddata/SpawnData.java deleted file mode 100644 index 0053d08c9..000000000 --- a/src/main/java/appeng/core/worlddata/SpawnData.java +++ /dev/null @@ -1,224 +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 . - */ - -package appeng.core.worlddata; - - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; - -import javax.annotation.Nonnull; - -import com.google.common.base.Preconditions; - -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.CompressedStreamTools; - -import appeng.core.AELog; -import net.minecraft.world.dimension.Dimension; - - -/** - * @author thatsIch - * @version rv3 - 30.05.2015 - * @since rv3 30.05.2015 - */ -final class SpawnData implements IWorldSpawnData -{ - @Nonnull - private final File spawnDirectory; - @Nonnull - private final MeteorDataNameEncoder encoder; - - public SpawnData( @Nonnull final File spawnDirectory ) - { - Preconditions.checkNotNull( spawnDirectory ); - - this.spawnDirectory = spawnDirectory; - this.encoder = new MeteorDataNameEncoder( 4 ); - } - - @Override - public void setGenerated(final Dimension dim, final int chunkX, final int chunkZ ) - { - int dimId = dim.getType().getId(); // FIXME This is most likely borked, see new string ids - - synchronized( SpawnData.class ) - { - final CompoundNBT data = this.loadSpawnData( dimId, chunkX, chunkZ ); - - // edit. - data.putBoolean(chunkX + "," + chunkZ, true); - - this.writeSpawnData( dimId, chunkX, chunkZ, data ); - } - } - - @Override - public boolean hasGenerated( final Dimension dim, final int chunkX, final int chunkZ ) - { - int dimId = dim.getType().getId(); // FIXME This is most likely borked, see new string ids - - synchronized( SpawnData.class ) - { - final CompoundNBT data = this.loadSpawnData( dimId, chunkX, chunkZ ); - return data.getBoolean( chunkX + "," + chunkZ ); - } - } - - @Override - public boolean addNearByMeteorites( final Dimension dim, final int chunkX, final int chunkZ, final CompoundNBT newData ) - { - int dimId = dim.getType().getId(); // FIXME This is most likely borked, see new string ids - - synchronized( SpawnData.class ) - { - final CompoundNBT data = this.loadSpawnData( dimId, chunkX, chunkZ ); - - // edit. - final int size = data.getInt( "num" ); - data.put( String.valueOf( size ), newData ); - data.putInt( "num", size + 1 ); - - this.writeSpawnData( dimId, chunkX, chunkZ, data ); - - return true; - } - } - - @Override - public Collection getNearByMeteorites( final Dimension dim, final int chunkX, final int chunkZ ) - { - final Collection ll = new ArrayList<>(); - - synchronized( SpawnData.class ) - { - for( int x = -1; x <= 1; x++ ) - { - for( int z = -1; z <= 1; z++ ) - { - final int cx = x + ( chunkX >> 4 ); - final int cz = z + ( chunkZ >> 4 ); - - // FIXME Using the numerical dimension id here is fishy - final CompoundNBT data = this.loadSpawnData( dim.getType().getId(), cx << 4, cz << 4 ); - - if( data != null ) - { - // edit. - final int size = data.getInt( "num" ); - for( int s = 0; s < size; s++ ) - { - ll.add( data.getCompound( String.valueOf( s ) ) ); - } - } - } - } - } - - return ll; - } - - private CompoundNBT loadSpawnData( final int dim, final int chunkX, final int chunkZ ) - { - if( !Thread.holdsLock( SpawnData.class ) ) - { - throw new IllegalStateException( "Invalid Request" ); - } - - CompoundNBT data = null; - final String fileName = this.encoder.encode( dim, chunkX, chunkZ ); - final File file = new File( this.spawnDirectory, fileName ); - - if( file.isFile() ) - { - FileInputStream fileInputStream = null; - - try - { - fileInputStream = new FileInputStream( file ); - data = CompressedStreamTools.readCompressed( fileInputStream ); - } - catch( final Throwable e ) - { - data = new CompoundNBT(); - AELog.debug( e ); - } - finally - { - if( fileInputStream != null ) - { - try - { - fileInputStream.close(); - } - catch( final IOException e ) - { - AELog.debug( e ); - } - } - } - } - else - { - data = new CompoundNBT(); - } - - return data; - } - - private void writeSpawnData( final int dim, final int chunkX, final int chunkZ, final CompoundNBT data ) - { - if( !Thread.holdsLock( SpawnData.class ) ) - { - throw new IllegalStateException( "Invalid Request" ); - } - - final String fileName = this.encoder.encode( dim, chunkX, chunkZ ); - final File file = new File( this.spawnDirectory, fileName ); - FileOutputStream fileOutputStream = null; - - try - { - fileOutputStream = new FileOutputStream( file ); - CompressedStreamTools.writeCompressed( data, fileOutputStream ); - } - catch( final Throwable e ) - { - AELog.debug( e ); - } - finally - { - if( fileOutputStream != null ) - { - try - { - fileOutputStream.close(); - } - catch( final IOException e ) - { - AELog.debug( e ); - } - } - } - } -} diff --git a/src/main/java/appeng/core/worlddata/WorldData.java b/src/main/java/appeng/core/worlddata/WorldData.java index 63dc5c515..ea1da46c4 100644 --- a/src/main/java/appeng/core/worlddata/WorldData.java +++ b/src/main/java/appeng/core/worlddata/WorldData.java @@ -19,6 +19,8 @@ package appeng.core.worlddata; +import appeng.services.CompassService; +import appeng.services.compass.CompassThreadFactory; import com.google.common.base.Preconditions; import net.minecraft.server.MinecraftServer; import net.minecraft.world.dimension.DimensionType; @@ -26,6 +28,7 @@ import net.minecraft.world.server.ServerWorld; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import java.util.concurrent.ThreadFactory; /** @@ -48,34 +51,33 @@ public final class WorldData implements IWorldData @Nullable private static IWorldData instance; + @Nullable + private static MinecraftServer server; + private final IWorldPlayerData playerData; private final IWorldGridStorageData storageData; private final IWorldCompassData compassData; - private final IWorldSpawnData spawnData; - private WorldData( @Nonnull final MinecraftServer server ) + private WorldData( @Nonnull final ServerWorld overworld ) { - Preconditions.checkNotNull( server ); + Preconditions.checkNotNull( overworld ); // Attach shared data to the server's overworld dimension - ServerWorld overworld = server.getWorld(DimensionType.OVERWORLD); - if (overworld == null) { + if (overworld.getDimension().getType() != DimensionType.OVERWORLD) { throw new IllegalStateException("The server doesn't have an Overworld dimension we could store our data on!"); } final PlayerData playerData = overworld.getSavedData().getOrCreate(PlayerData::new, PlayerData.NAME); final StorageData storageData = overworld.getSavedData().getOrCreate(StorageData::new, StorageData.NAME); -// final ThreadFactory compassThreadFactory = new CompassThreadFactory(); -// final CompassService compassService = new CompassService( this.compassDirectory, compassThreadFactory ); -// final CompassData compassData = new CompassData( this.compassDirectory, compassService ); -// -// final IWorldSpawnData spawnData = new SpawnData( this.spawnDirectory ); + final ThreadFactory compassThreadFactory = new CompassThreadFactory(); + final CompassService compassService = new CompassService(server, compassThreadFactory ); + final CompassData compassData = new CompassData( compassService ); this.playerData = playerData; this.storageData = storageData; - this.compassData = null; // compassData; - this.spawnData = null; // spawnData; + this.compassData = compassData; + } /** @@ -85,8 +87,19 @@ public final class WorldData implements IWorldData */ @Deprecated @Nonnull - public static IWorldData instance() + public synchronized static IWorldData instance() { + // The overworld is lazily loaded, meaning we cannot access it right away + // when the server is starting, but the first time the instance is accessed, + // we create the actual world data + if (instance == null) { + if (server == null) { + throw new IllegalStateException("No server set."); + } + + ServerWorld overworld = server.getWorld(DimensionType.OVERWORLD); + instance = new WorldData(overworld); + } return instance; } @@ -94,12 +107,10 @@ public final class WorldData implements IWorldData * Requires to start up from external from here * * drawback of the singleton build style - * - * @param server */ - public static void onServerAboutToStart( MinecraftServer server ) + public static void onServerStarting(MinecraftServer server) { - instance = new WorldData(server); + WorldData.server = server; } @Override @@ -111,8 +122,9 @@ public final class WorldData implements IWorldData @Override public void onServerStoppped() { - Preconditions.checkNotNull( instance ); + Preconditions.checkNotNull( server ); instance = null; + WorldData.server = null; } @Nonnull @@ -135,11 +147,4 @@ public final class WorldData implements IWorldData { return this.compassData; } - - @Nonnull - @Override - public IWorldSpawnData spawnData() - { - return this.spawnData; - } } diff --git a/src/main/java/appeng/debug/ToolMeteoritePlacer.java b/src/main/java/appeng/debug/ToolMeteoritePlacer.java index 8179034f3..0c7d7aacf 100644 --- a/src/main/java/appeng/debug/ToolMeteoritePlacer.java +++ b/src/main/java/appeng/debug/ToolMeteoritePlacer.java @@ -19,6 +19,10 @@ package appeng.debug; +import appeng.worldgen.MeteoritePlacer; +import appeng.worldgen.MeteoriteSpawner; +import appeng.worldgen.PlacedMeteoriteSettings; +import appeng.worldgen.meteorite.StandardWorld; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.item.ItemUseContext; @@ -28,7 +32,6 @@ import net.minecraft.util.text.StringTextComponent; import net.minecraft.world.World; import appeng.items.AEBaseItem; -import appeng.util.Platform; public class ToolMeteoritePlacer extends AEBaseItem @@ -53,13 +56,17 @@ public class ToolMeteoritePlacer extends AEBaseItem return ActionResultType.PASS; } -//FIXME final MeteoritePlacer mp = new MeteoritePlacer(); -//FIXME final boolean worked = mp.spawnMeteorite( new StandardWorld( world ), pos.getX(), pos.getY(), pos.getZ() ); -//FIXME -//FIXME if( !worked ) -//FIXME { -//FIXME player.sendMessage( new StringTextComponent( "Un-suitable Location." ) ); -//FIXME } + final MeteoriteSpawner ms = new MeteoriteSpawner(); + PlacedMeteoriteSettings spawned = ms.trySpawnMeteorite(world, pos); + + if( spawned == null ) + { + player.sendMessage( new StringTextComponent( "Un-suitable Location." ) ); + return ActionResultType.FAIL; + } + + final MeteoritePlacer placer = new MeteoritePlacer(world, spawned); + placer.place(); return ActionResultType.SUCCESS; } diff --git a/src/main/java/appeng/decorative/solid/BlockSkyStone.java b/src/main/java/appeng/decorative/solid/BlockSkyStone.java index b988f9517..8598e80b2 100644 --- a/src/main/java/appeng/decorative/solid/BlockSkyStone.java +++ b/src/main/java/appeng/decorative/solid/BlockSkyStone.java @@ -19,6 +19,7 @@ package appeng.decorative.solid; +import appeng.core.worlddata.WorldData; import net.minecraft.block.BlockState; import net.minecraft.inventory.EquipmentSlotType; import net.minecraft.item.ItemStack; @@ -26,6 +27,7 @@ import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.world.IWorld; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.ToolType; import net.minecraftforge.event.entity.player.PlayerEvent; @@ -70,9 +72,9 @@ public class BlockSkyStone extends AEBaseBlock @Override public BlockState updatePostPlacement(BlockState stateIn, Direction facing, BlockState facingState, IWorld worldIn, BlockPos currentPos, BlockPos facingPos) { - if( Platform.isServer() ) + if( worldIn instanceof ServerWorld) { - // FIXME WorldData.instance().compassData().service().updateArea( worldIn, currentPos.getX(), currentPos.getY(), currentPos.getZ() ); + WorldData.instance().compassData().service().updateArea((ServerWorld) worldIn, currentPos.getX(), currentPos.getY(), currentPos.getZ() ); } return super.updatePostPlacement(stateIn, facing, facingState, worldIn, currentPos, facingPos); @@ -86,9 +88,9 @@ public class BlockSkyStone extends AEBaseBlock super.onReplaced(state, w, pos, newState, isMoving); - if( Platform.isServer() ) + if( w instanceof ServerWorld ) { - // FIXME WorldData.instance().compassData().service().updateArea( w, pos.getX(), pos.getY(), pos.getZ() ); + WorldData.instance().compassData().service().updateArea((ServerWorld) w, pos.getX(), pos.getY(), pos.getZ() ); } } diff --git a/src/main/java/appeng/services/CompassService.java b/src/main/java/appeng/services/CompassService.java index 9886a391e..e8df2c70f 100644 --- a/src/main/java/appeng/services/CompassService.java +++ b/src/main/java/appeng/services/CompassService.java @@ -19,55 +19,40 @@ package appeng.services; -import java.io.File; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; - -import javax.annotation.Nonnull; - -import com.google.common.base.Preconditions; - -import net.minecraft.block.Block; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IWorld; -import net.minecraft.world.World; -import net.minecraft.world.chunk.IChunk; -import net.minecraft.world.server.ServerWorld; -import net.minecraftforge.event.world.WorldEvent; - import appeng.api.AEApi; import appeng.api.util.DimensionalCoord; import appeng.services.compass.CompassReader; import appeng.services.compass.ICompassCallback; import appeng.util.Platform; +import net.minecraft.block.Block; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; +import net.minecraft.world.chunk.IChunk; +import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; +import javax.annotation.Nonnull; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.*; + public final class CompassService { private static final int CHUNK_SIZE = 16; - private final Map worldSet = new HashMap<>( 10 ); + private final MinecraftServer server; + private final Map worldSet = new HashMap<>( 10 ); private final ExecutorService executor; - /** - * AE2 Folder for each world - */ - private final File worldCompassFolder; - private int jobSize; - public CompassService( @Nonnull final File worldCompassFolder, @Nonnull final ThreadFactory factory ) + public CompassService(MinecraftServer server, @Nonnull final ThreadFactory factory) { - Preconditions.checkNotNull( worldCompassFolder ); - - this.worldCompassFolder = worldCompassFolder; + this.server = server; this.executor = Executors.newSingleThreadExecutor( factory ); this.jobSize = 0; } @@ -83,13 +68,15 @@ public final class CompassService * * @param event the event containing the unloaded world. */ + // FIXME this is never registered @SubscribeEvent public void unloadWorld( final WorldEvent.Unload event ) { - if( Platform.isServer() && this.worldSet.containsKey( event.getWorld() ) ) - { - final CompassReader compassReader = this.worldSet.remove( event.getWorld() ); + DimensionType dim = event.getWorld().getDimension().getType(); + if( Platform.isServer() && this.worldSet.containsKey( dim ) ) + { + final CompassReader compassReader = this.worldSet.remove( dim ); compassReader.close(); } } @@ -107,7 +94,7 @@ public final class CompassService } } - public void updateArea( final World w, final int chunkX, final int chunkZ ) + public void updateArea( final IWorld w, final int chunkX, final int chunkZ ) { final int x = chunkX << 4; final int z = chunkZ << 4; @@ -137,27 +124,29 @@ public final class CompassService // lower level... final IChunk c = w.getChunk( cx, cz ); - Optional maybeBlock = AEApi.instance().definitions().blocks().skyStoneBlock().maybeBlock(); - if( maybeBlock.isPresent() ) + DimensionType dim = w.getDimension().getType(); + + Block skyStoneBlock = AEApi.instance().definitions().blocks().skyStoneBlock().block(); + BlockPos.Mutable pos = new BlockPos.Mutable(); + for( int i = 0; i < CHUNK_SIZE; i++ ) { - Block skyStoneBlock = maybeBlock.get(); - for( int i = 0; i < CHUNK_SIZE; i++ ) + pos.setX(i); + for( int j = 0; j < CHUNK_SIZE; j++ ) { - for( int j = 0; j < CHUNK_SIZE; j++ ) + pos.setZ(j); + for( int k = low_y; k < hi_y; k++ ) { - for( int k = low_y; k < hi_y; k++ ) + pos.setY(k); + final Block blk = c.getBlockState( pos ).getBlock(); + if( blk == skyStoneBlock ) { - final Block blk = c.getBlockState( new BlockPos(i, k, j) ).getBlock(); - if( blk == skyStoneBlock ) - { - return this.executor.submit( new CMUpdatePost( w, cx, cz, cdy, true ) ); - } + return this.executor.submit( new CMUpdatePost( dim, cx, cz, cdy, true ) ); } } } } - return this.executor.submit( new CMUpdatePost( w, cx, cz, cdy, false ) ); + return this.executor.submit( new CMUpdatePost( dim, cx, cz, cdy, false ) ); } public void kill() @@ -182,16 +171,15 @@ public final class CompassService } } - private CompassReader getReader( final IWorld w ) + private CompassReader getReader( final DimensionType dim ) { - CompassReader cr = this.worldSet.get( w ); + CompassReader cr = this.worldSet.get( dim ); if( cr == null ) { - ServerWorld sw = (ServerWorld) w; - // FIXME: using the numeric dimension ID here seems to be a bad idea! - cr = new CompassReader( sw.dimension.getType().getId(), this.worldCompassFolder ); - this.worldSet.put( w, cr ); + ServerWorld sw = server.getWorld(dim); + cr = new CompassReader(sw); + this.worldSet.put( dim, cr ); } return cr; @@ -216,16 +204,16 @@ public final class CompassService private class CMUpdatePost implements Runnable { - public final IWorld world; + public final DimensionType dim; public final int chunkX; public final int chunkZ; public final int doubleChunkY; // 32 blocks instead of 16. public final boolean value; - public CMUpdatePost( final IWorld w, final int cx, final int cz, final int dcy, final boolean val ) + public CMUpdatePost(final DimensionType dim, final int cx, final int cz, final int dcy, final boolean val ) { - this.world = w; + this.dim = dim; this.chunkX = cx; this.doubleChunkY = dcy; this.chunkZ = cz; @@ -237,7 +225,7 @@ public final class CompassService { CompassService.this.jobSize--; - final CompassReader cr = CompassService.this.getReader( this.world ); + final CompassReader cr = CompassService.this.getReader( this.dim ); cr.setHasBeacon( this.chunkX, this.chunkZ, this.doubleChunkY, this.value ); if( CompassService.this.jobSize() < 2 ) @@ -269,7 +257,7 @@ public final class CompassService final int cx = this.coord.x >> 4; final int cz = this.coord.z >> 4; - final CompassReader cr = CompassService.this.getReader( this.coord.getWorld() ); + final CompassReader cr = CompassService.this.getReader( this.coord.getWorld().getDimension().getType() ); // Am I standing on it? if( cr.hasBeacon( cx, cz ) ) diff --git a/src/main/java/appeng/services/compass/CompassReader.java b/src/main/java/appeng/services/compass/CompassReader.java index f0d34c786..2b63465cc 100644 --- a/src/main/java/appeng/services/compass/CompassReader.java +++ b/src/main/java/appeng/services/compass/CompassReader.java @@ -19,28 +19,21 @@ package appeng.services.compass; -import java.io.File; +import com.google.common.base.Preconditions; +import net.minecraft.world.server.ServerWorld; + import java.util.HashMap; import java.util.Map; -import javax.annotation.Nonnull; - -import com.google.common.base.Preconditions; - public final class CompassReader { private final Map regions = new HashMap<>( 100 ); - private final int dimensionId; - private final File worldCompassFolder; + private final ServerWorld world; - public CompassReader( final int dimensionId, @Nonnull final File worldCompassFolder ) + public CompassReader( ServerWorld world ) { - Preconditions.checkNotNull( worldCompassFolder ); - Preconditions.checkArgument( worldCompassFolder.isDirectory() ); - - this.dimensionId = dimensionId; - this.worldCompassFolder = worldCompassFolder; + this.world = Preconditions.checkNotNull( world ); } public void close() @@ -77,7 +70,7 @@ public final class CompassReader if( cr == null ) { - cr = new CompassRegion( cx, cz, this.dimensionId, this.worldCompassFolder ); + cr = new CompassRegion( world, cx, cz ); this.regions.put( pos, cr ); } diff --git a/src/main/java/appeng/services/compass/CompassRegion.java b/src/main/java/appeng/services/compass/CompassRegion.java index c22780655..32bdb6891 100644 --- a/src/main/java/appeng/services/compass/CompassRegion.java +++ b/src/main/java/appeng/services/compass/CompassRegion.java @@ -19,38 +19,23 @@ package appeng.services.compass; -import java.io.File; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; - -import javax.annotation.Nonnull; - import com.google.common.base.Preconditions; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.world.server.ServerWorld; +import net.minecraft.world.storage.WorldSavedData; -import appeng.core.worlddata.MeteorDataNameEncoder; - - -public final class CompassRegion +final class CompassRegion { private final int lowX; private final int lowZ; - private final int world; - private final File worldCompassFolder; - private final MeteorDataNameEncoder encoder; + private final ServerWorld world; + private SaveData data; - private boolean hasFile = false; - private RandomAccessFile raf = null; - private ByteBuffer buffer; - - public CompassRegion( final int cx, final int cz, final int worldID, @Nonnull final File worldCompassFolder ) + public CompassRegion(ServerWorld world, final int cx, final int cz ) { - Preconditions.checkNotNull( worldCompassFolder ); - Preconditions.checkArgument( worldCompassFolder.isDirectory() ); + Preconditions.checkNotNull( world ); - this.world = worldID; - this.worldCompassFolder = worldCompassFolder; - this.encoder = new MeteorDataNameEncoder( 0 ); + this.world = world; final int region_x = cx >> 10; final int region_z = cz >> 10; @@ -58,39 +43,26 @@ public final class CompassRegion this.lowX = region_x << 10; this.lowZ = region_z << 10; - this.openFile( false ); + this.openData(false); } void close() { - try + if( this.data != null ) { - if( this.hasFile ) - { - this.buffer = null; - this.raf.close(); - this.raf = null; - this.hasFile = false; - } - } - catch( final Throwable t ) - { - throw new CompassException( t ); + this.data = null; } } boolean hasBeacon( int cx, int cz ) { - if( this.hasFile ) + if( this.data != null ) { cx &= 0x3FF; cz &= 0x3FF; final int val = this.read( cx, cz ); - if( val != 0 ) - { - return true; - } + return val != 0; } return false; @@ -101,9 +73,9 @@ public final class CompassRegion cx &= 0x3FF; cz &= 0x3FF; - this.openFile( hasBeacon ); + this.openData( hasBeacon ); - if( this.hasFile ) + if( this.data != null ) { int val = this.read( cx, cz ); final int originalVal = val; @@ -124,88 +96,67 @@ public final class CompassRegion } } - @Override - protected void finalize() throws Throwable + private void openData(final boolean create ) { - try - { - if( this.raf != null ) - { - this.raf.close(); - } - } - finally - { - super.finalize(); - } - - } - - private void openFile( final boolean create ) - { - if( this.hasFile ) + if( this.data != null ) { return; } - final File file = this.getFile(); - if( create || this.isFileExistent( file ) ) - { - try - { - this.raf = new RandomAccessFile( file, "rw" ); - final FileChannel fc = this.raf.getChannel(); - this.buffer = fc.map( FileChannel.MapMode.READ_WRITE, 0, 0x400 * 0x400 );// fc.size() ); - this.hasFile = true; - } - catch( final Throwable t ) - { - throw new CompassException( t ); + String name = this.lowX + "_" + this.lowZ; + + if (create) { + this.data = world.getSavedData().getOrCreate(() -> new SaveData(name), name); + if (this.data.bitmap == null) { + this.data.bitmap = new byte[SaveData.BITMAP_LENGTH]; } + } else { + this.data = world.getSavedData().get(() -> new SaveData(name), name); } } - private File getFile() - { - final String fileName = this.encoder.encode( this.world, this.lowX, this.lowZ ); - - return new File( this.worldCompassFolder, fileName ); - } - - private boolean isFileExistent( final File file ) - { - return file.exists() && file.isFile(); - } - private int read( final int cx, final int cz ) { try { - return this.buffer.get( cx + cz * 0x400 ); - // raf.seek( cx + cz * 0x400 ); - // return raf.readByte(); + return this.data.bitmap[cx + cz * 0x400]; } catch( final IndexOutOfBoundsException outOfBounds ) { return 0; } - catch( final Throwable t ) - { - throw new CompassException( t ); - } } private void write( final int cx, final int cz, final int val ) { - try - { - this.buffer.put( cx + cz * 0x400, (byte) val ); - // raf.seek( cx + cz * 0x400 ); - // raf.writeByte( val ); - } - catch( final Throwable t ) - { - throw new CompassException( t ); - } + this.data.bitmap[cx + cz * 0x400] = (byte) val; + this.data.markDirty(); } + + private static class SaveData extends WorldSavedData { + + private static final int BITMAP_LENGTH = 0x400 * 0x400; + + private byte[] bitmap; + + public SaveData(String name) { + super(name); + } + + @Override + public void read(CompoundNBT nbt) { + this.bitmap = nbt.getByteArray("b"); + if (this.bitmap.length != BITMAP_LENGTH) { + throw new IllegalStateException("Invalid bitmap length: " + bitmap.length); + } + } + + @Override + public CompoundNBT write(CompoundNBT compound) { + compound.putByteArray("b", bitmap); + return compound; + } + + } + } diff --git a/src/main/java/appeng/worldgen/MeteoritePiece.java b/src/main/java/appeng/worldgen/MeteoritePiece.java new file mode 100644 index 000000000..4b18ed8c2 --- /dev/null +++ b/src/main/java/appeng/worldgen/MeteoritePiece.java @@ -0,0 +1,32 @@ +package appeng.worldgen; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.MutableBoundingBox; +import net.minecraft.world.IWorld; +import net.minecraft.world.gen.ChunkGenerator; +import net.minecraft.world.gen.feature.structure.IStructurePieceType; +import net.minecraft.world.gen.feature.structure.ScatteredStructurePiece; +import net.minecraft.world.gen.feature.structure.StructurePiece; +import net.minecraft.world.gen.feature.template.TemplateManager; + +import java.util.Random; + +public class MeteoritePiece extends ScatteredStructurePiece { + + public static IStructurePieceType TYPE = IStructurePieceType.register(MeteoritePiece::new, "AE2M"); + + public MeteoritePiece(Random random, int x, int z) { + super(TYPE, random, x, 64, z, 7, 7, 9); + } + + public MeteoritePiece(TemplateManager p_i51340_1_, CompoundNBT p_i51340_2_) { + super(TYPE, p_i51340_2_); + } + + @Override + public boolean create(IWorld worldIn, ChunkGenerator chunkGeneratorIn, Random randomIn, MutableBoundingBox mutableBoundingBoxIn, ChunkPos chunkPosIn) { + return false; + } + +} diff --git a/src/main/java/appeng/worldgen/MeteoritePlacer.java b/src/main/java/appeng/worldgen/MeteoritePlacer.java index 40e6ac655..b0d1633a8 100644 --- a/src/main/java/appeng/worldgen/MeteoritePlacer.java +++ b/src/main/java/appeng/worldgen/MeteoritePlacer.java @@ -19,20 +19,18 @@ package appeng.worldgen; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; +import java.util.*; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.entity.Entity; import net.minecraft.entity.item.ItemEntity; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; -import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; +import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; @@ -51,128 +49,102 @@ import appeng.worldgen.meteorite.FalloutSand; import appeng.worldgen.meteorite.FalloutSnow; import appeng.worldgen.meteorite.IMeteoriteWorld; import appeng.worldgen.meteorite.MeteoriteBlockPutter; +import net.minecraft.world.IWorld; public final class MeteoritePlacer { private static final double PRESSES_SPAWN_CHANCE = 0.7; private static final int SKYSTONE_SPAWN_LIMIT = 12; - private final Collection validSpawn = new HashSet<>(); - private final Collection invalidSpawn = new HashSet<>(); private final IBlockDefinition skyChestDefinition; - private final IBlockDefinition skyStoneDefinition; + private final BlockState skyStone; + private final Item skyStoneItem; private final MeteoriteBlockPutter putter = new MeteoriteBlockPutter(); - private double meteoriteSize = ( Math.random() * 6.0 ) + 2; - private double realCrater = this.meteoriteSize * 2 + 5; - private double squaredMeteoriteSize = this.meteoriteSize * this.meteoriteSize; - private double crater = this.realCrater * this.realCrater; - private CompoundNBT settings; - private Fallout type; + private final IWorld world; + private final Fallout type; + private final BlockPos pos; + private final int x; + private final int y; + private final int z; + private final double meteoriteSize; + private final double realCrater; + private final double squaredMeteoriteSize; + private final double crater; + private final int skyMode; + private final boolean lava; - public MeteoritePlacer() + public MeteoritePlacer(IWorld world, PlacedMeteoriteSettings settings) { + this.world = world; + this.pos = settings.getPos(); + this.x = settings.getPos().getX(); + this.y = settings.getPos().getY(); + this.z = settings.getPos().getZ(); + this.meteoriteSize = settings.getMeteoriteRadius(); + this.realCrater = settings.getCraterRadius(); + this.skyMode = settings.getSkyMode(); + this.lava = settings.isLava(); + this.squaredMeteoriteSize = this.meteoriteSize * this.meteoriteSize; + this.crater = this.realCrater * this.realCrater; + final IBlocks blocks = AEApi.instance().definitions().blocks(); this.skyChestDefinition = blocks.skyStoneChest(); - this.skyStoneDefinition = blocks.skyStoneBlock(); + this.skyStone = blocks.skyStoneBlock().block().getDefaultState(); + this.skyStoneItem = blocks.skyStoneBlock().item(); - this.validSpawn.add( Blocks.STONE ); - this.validSpawn.add( Blocks.COBBLESTONE ); - this.validSpawn.add( Blocks.GRASS ); - this.validSpawn.add( Blocks.SAND ); - this.validSpawn.add( Blocks.DIRT ); - this.validSpawn.add( Blocks.GRAVEL ); - this.validSpawn.add( Blocks.NETHERRACK ); - this.validSpawn.add( Blocks.IRON_ORE ); - this.validSpawn.add( Blocks.GOLD_ORE ); - this.validSpawn.add( Blocks.DIAMOND_ORE ); - this.validSpawn.add( Blocks.REDSTONE_ORE ); - this.validSpawn.add( Blocks.ICE ); - this.validSpawn.add( Blocks.SNOW ); - - this.skyStoneDefinition.maybeBlock().ifPresent( this.invalidSpawn::add ); - this.invalidSpawn.add( Blocks.IRON_DOOR ); - this.invalidSpawn.add( Blocks.IRON_BARS ); - this.invalidSpawn.add( Blocks.OAK_DOOR ); - this.invalidSpawn.add( Blocks.ACACIA_DOOR ); - this.invalidSpawn.add( Blocks.BIRCH_DOOR ); - this.invalidSpawn.add( Blocks.DARK_OAK_DOOR ); - this.invalidSpawn.add( Blocks.IRON_DOOR ); - this.invalidSpawn.add( Blocks.JUNGLE_DOOR ); - this.invalidSpawn.add( Blocks.SPRUCE_DOOR ); - this.invalidSpawn.add( Blocks.BRICKS ); - this.invalidSpawn.add( Blocks.CLAY ); - this.invalidSpawn.add( Blocks.WATER ); - - this.type = new Fallout( this.putter, this.skyStoneDefinition ); + this.type = getFalloutFromBaseBlock(world, settings.getPos(), settings.getBlk()); } - boolean spawnMeteorite( final IMeteoriteWorld w, final CompoundNBT meteoriteBlob ) - { - this.settings = meteoriteBlob; - - final int x = this.settings.getInt( "x" ); - final int y = this.settings.getInt( "y" ); - final int z = this.settings.getInt( "z" ); - - this.meteoriteSize = this.settings.getDouble( "real_sizeOfMeteorite" ); - this.realCrater = this.settings.getDouble( "realCrater" ); - this.squaredMeteoriteSize = this.settings.getDouble( "sizeOfMeteorite" ); - this.crater = this.settings.getDouble( "crater" ); - - final Block blk = Block.getBlockById( this.settings.getInt( "blk" ) ); - - if( blk == Blocks.SAND ) - { - this.type = new FalloutSand( w, x, y, z, this.putter, this.skyStoneDefinition ); - } - else if( blk == Blocks.HARDENED_CLAY ) - { - this.type = new FalloutCopy( w, x, y, z, this.putter, this.skyStoneDefinition ); - } - else if( blk == Blocks.ICE || blk == Blocks.SNOW ) - { - this.type = new FalloutSnow( w, x, y, z, this.putter, this.skyStoneDefinition ); - } - - final int skyMode = this.settings.getInt( "skyMode" ); - + public void place() { // creator if( skyMode > 10 ) { - this.placeCrater( w, x, y, z ); + this.placeCrater(); } - this.placeMeteorite( w, x, y, z ); + this.placeMeteorite(); // collapse blocks... if( skyMode > 3 ) { - this.decay( w, x, y, z ); + this.decay(); } - - w.done(); - return true; } - private void placeCrater( final IMeteoriteWorld w, final int x, final int y, final int z ) + private int minX(int x) { + return x; + } + private int minZ(int x) { + return x; + } + private int maxX(int x) { + return x; + } + private int maxZ(int x) { + return x; + } + + private void placeCrater() { - final boolean lava = this.settings.getBoolean( "lava" ); - final int maxY = 255; - final int minX = w.minX( x - 200 ); - final int maxX = w.maxX( x + 200 ); - final int minZ = w.minZ( z - 200 ); - final int maxZ = w.maxZ( z + 200 ); + final int minX = minX( x - 200 ); + final int maxX = maxX( x + 200 ); + final int minZ = minZ( z - 200 ); + final int maxZ = maxZ( z + 200 ); + BlockPos.Mutable blockPos = new BlockPos.Mutable(); for( int j = y - 5; j < maxY; j++ ) { + blockPos.setY(j); boolean changed = false; for( int i = minX; i < maxX; i++ ) { + blockPos.setX(i); for( int k = minZ; k < maxZ; k++ ) { + blockPos.setZ(k); final double dx = i - x; final double dz = k - z; final double h = y - this.meteoriteSize + 1 + this.type.adjustCrater(); @@ -181,45 +153,48 @@ public final class MeteoritePlacer if( j > h + distanceFrom * 0.02 ) { - if( lava && j < y && w.getBlockState( i, j, k ).getMaterial().isSolid() ) + if( lava && j < y && world.getBlockState( blockPos ).getMaterial().isSolid() ) { if( j > h + distanceFrom * 0.02 ) { - this.putter.put( w, i, j, k, Blocks.LAVA ); + this.putter.put(world, blockPos, Blocks.LAVA.getDefaultState() ); } } else { - changed = this.putter.put( w, i, j, k, Platform.AIR_BLOCK ) || changed; + changed = this.putter.put(world, blockPos, Platform.AIR_BLOCK.getDefaultState() ) || changed; } } } } } - for( final Object o : w.getWorld() - .getEntitiesWithinAABB( ItemEntity.class, - new AxisAlignedBB( w.minX( x - 30 ), y - 5, w.minZ( z - 30 ), w.maxX( x + 30 ), y + 30, w.maxZ( z + 30 ) ) ) ) + for( final Object o : world.getEntitiesWithinAABB( ItemEntity.class, + new AxisAlignedBB( minX( x - 30 ), y - 5, minZ( z - 30 ), maxX( x + 30 ), y + 30, maxZ( z + 30 ) ) ) ) { final Entity e = (Entity) o; e.remove(); } } - private void placeMeteorite( final IMeteoriteWorld w, final int x, final int y, final int z ) + private void placeMeteorite() { - // spawn meteor - this.skyStoneDefinition.maybeBlock().ifPresent( block -> this.placeMeteoriteSkyStone( w, x, y, z, block ) ); + this.placeMeteoriteSkyStone(); + placeChest(); + } + + private void placeChest() { if( AEConfig.instance().isFeatureEnabled( AEFeature.SPAWN_PRESSES_IN_METEORITES ) ) { - this.skyChestDefinition.maybeBlock().ifPresent( block -> this.putter.put( w, x, y, z, block ) ); + this.putter.put(world, pos, this.skyChestDefinition.block().getDefaultState()); - final TileEntity te = w.getTileEntity( x, y, z ); + final TileEntity te = world.getTileEntity(pos); // FIXME: this is also probably a band-aid for another issue final InventoryAdaptor ap = InventoryAdaptor.getAdaptor( te, Direction.UP ); - if( ap != null ) + if( ap != null && !ap.containsItems() ) // FIXME: band-aid for meteorites being generated multiple times { + // TODO: loot tables would be better int primary = Math.max( 1, (int) ( Math.random() * 4 ) ); if( primary > 3 ) // in case math breaks... @@ -287,14 +262,14 @@ public final class MeteoritePlacer { case 0: final int amount = (int) ( ( Math.random() * SKYSTONE_SPAWN_LIMIT ) + 1 ); - this.skyStoneDefinition.maybeStack( amount ).ifPresent( ap::addItems ); + ap.addItems(new ItemStack(skyStoneItem, amount)); break; case 1: final List possibles = new ArrayList<>(); possibles.add( new ItemStack( net.minecraft.item.Items.GOLD_NUGGET ) ); ItemStack nugget = Platform.pickRandom( possibles ); - if( !nugget.isEmpty() ) + if( nugget != null && !nugget.isEmpty() ) { nugget = nugget.copy(); nugget.setCount( (int) ( Math.random() * 12 ) + 1 ); @@ -307,63 +282,80 @@ public final class MeteoritePlacer } } - private void placeMeteoriteSkyStone( IMeteoriteWorld w, int x, int y, int z, Block block ) + private void placeMeteoriteSkyStone() { - final int meteorXLength = w.minX( x - 8 ); - final int meteorXHeight = w.maxX( x + 8 ); - final int meteorZLength = w.minZ( z - 8 ); - final int meteorZHeight = w.maxZ( z + 8 ); + final int meteorXLength = minX( x - 8 ); + final int meteorXHeight = maxX( x + 8 ); + final int meteorZLength = minZ( z - 8 ); + final int meteorZHeight = maxZ( z + 8 ); + BlockPos.Mutable pos = new BlockPos.Mutable(); for( int i = meteorXLength; i < meteorXHeight; i++ ) { + pos.setX(i); for( int j = y - 8; j < y + 8; j++ ) { + pos.setY(j); for( int k = meteorZLength; k < meteorZHeight; k++ ) { + pos.setZ(k); final double dx = i - x; final double dy = j - y; final double dz = k - z; if( dx * dx * 0.7 + dy * dy * ( j > y ? 1.4 : 0.8 ) + dz * dz * 0.7 < this.squaredMeteoriteSize ) { - this.putter.put( w, i, j, k, block ); + this.putter.put(world, pos, skyStone ); } } } } } - private void decay( final IMeteoriteWorld w, final int x, final int y, final int z ) + private void decay() { double randomShit = 0; - final int meteorXLength = w.minX( x - 30 ); - final int meteorXHeight = w.maxX( x + 30 ); - final int meteorZLength = w.minZ( z - 30 ); - final int meteorZHeight = w.maxZ( z + 30 ); + final int meteorXLength = minX( x - 30 ); + final int meteorXHeight = maxX( x + 30 ); + final int meteorZLength = minZ( z - 30 ); + final int meteorZHeight = maxZ( z + 30 ); + BlockPos.Mutable blockPos = new BlockPos.Mutable(); + BlockPos.Mutable blockPosUp = new BlockPos.Mutable(); + BlockPos.Mutable blockPosDown = new BlockPos.Mutable(); for( int i = meteorXLength; i < meteorXHeight; i++ ) { + blockPos.setX(i); + blockPosUp.setX(i); + blockPosDown.setX(i); for( int k = meteorZLength; k < meteorZHeight; k++ ) { + blockPos.setZ(k); + blockPosUp.setZ(k); + blockPosDown.setZ(k); for( int j = y - 9; j < y + 30; j++ ) { - Block blk = w.getBlock( i, j, k ); + blockPos.setY(j); + blockPosUp.setY(j + 1); + blockPosDown.setY(j - 1); + BlockState state = world.getBlockState( blockPos ); + Block blk = world.getBlockState( blockPos ).getBlock(); if( blk == Blocks.LAVA ) { continue; } - if( blk.isReplaceable( w.getWorld(), new BlockPos( i, j, k ) ) ) + // TODO reconsider + if( state.canBeReplacedByLogs( world, new BlockPos( blockPos ) ) ) { blk = Platform.AIR_BLOCK; - final Block blk_b = w.getBlock( i, j + 1, k ); + final Block blk_b = world.getBlockState( blockPosUp ).getBlock(); if( blk_b != blk ) { - final BlockState meta_b = w.getBlockState( i, j + 1, k ); - - w.setBlock( i, j, k, meta_b, 3 ); + final BlockState stateUp = world.getBlockState( blockPosUp ); + world.setBlockState( blockPos, stateUp, 3 ); } else if( randomShit < 100 * this.crater ) { @@ -372,16 +364,16 @@ public final class MeteoritePlacer final double dz = k - z; final double dist = dx * dx + dy * dy + dz * dz; - final Block xf = w.getBlock( i, j - 1, k ); - if( !xf.isReplaceable( w.getWorld(), new BlockPos( i, j - 1, k ) ) ) + final BlockState xf = world.getBlockState( blockPosDown ); + if( !xf.canBeReplacedByLogs( world, blockPosDown ) ) { final double extraRange = Math.random() * 0.6; final double height = this.crater * ( extraRange + 0.2 ) - Math.abs( dist - this.crater * 1.7 ); - if( xf != blk && height > 0 && Math.random() > 0.6 ) + if( xf.getBlock() != blk && height > 0 && Math.random() > 0.6 ) { randomShit++; - this.type.getRandomFall( w, i, j, k ); + this.type.getRandomFall(world, blockPos); } } } @@ -389,8 +381,7 @@ public final class MeteoritePlacer else { // decay. - final Block blk_b = w.getBlock( i, j + 1, k ); - if( blk_b == Platform.AIR_BLOCK ) + if( world.isAirBlock(blockPosUp) ) { if( Math.random() > 0.4 ) { @@ -400,7 +391,7 @@ public final class MeteoritePlacer if( dx * dx + dy * dy + dz * dz < this.crater * 1.6 ) { - this.type.getRandomInset( w, i, j, k ); + this.type.getRandomInset(world, blockPos); } } } @@ -410,151 +401,23 @@ public final class MeteoritePlacer } } - double getSqDistance( final int x, final int z ) - { - final int chunkX = this.settings.getInt( "x" ) - x; - final int chunkZ = this.settings.getInt( "z" ) - z; - - return chunkX * chunkX + chunkZ * chunkZ; + private Fallout getFalloutFromBaseBlock(IWorld w, BlockPos pos, ResourceLocation blk) { + if( blk.equals(Blocks.SAND.getRegistryName()) ) + { + return new FalloutSand( w, pos, this.putter, this.skyStone ); + } + else if( blk.equals(Blocks.TERRACOTTA.getRegistryName()) ) + { + return new FalloutCopy( w, pos, this.putter, this.skyStone ); + } + else if( blk.equals(Blocks.ICE.getRegistryName()) || blk.equals(Blocks.SNOW.getRegistryName()) ) + { + return new FalloutSnow( w, pos, this.putter, this.skyStone ); + } + else + { + return new Fallout( this.putter, this.skyStone ); + } } - public boolean spawnMeteorite( final IMeteoriteWorld w, final int x, final int y, final int z ) - { - - if( !w.isNether() ) - { - return false; - } - - Block blk = w.getBlock( x, y, z ); - if( !this.validSpawn.contains( blk ) ) - { - return false; // must spawn on a valid block.. - } - - this.settings = new CompoundNBT(); - this.settings.putInt( "x", x ); - this.settings.putInt( "y", y ); - this.settings.putInt( "z", z ); - this.settings.putString( "blk", blk.getRegistryName().toString() ); - - this.settings.putDouble( "real_sizeOfMeteorite", this.meteoriteSize ); - this.settings.putDouble( "realCrater", this.realCrater ); - this.settings.putDouble( "sizeOfMeteorite", this.squaredMeteoriteSize ); - this.settings.putDouble( "crater", this.crater ); - - this.settings.putBoolean( "lava", Math.random() > 0.9 ); - - if( blk == Blocks.SAND ) - { - this.type = new FalloutSand( w, x, y, z, this.putter, this.skyStoneDefinition ); - } - else if( blk == Blocks.TERRACOTTA ) - { - this.type = new FalloutCopy( w, x, y, z, this.putter, this.skyStoneDefinition ); - } - else if( blk == Blocks.ICE || blk == Blocks.SNOW ) - { - this.type = new FalloutSnow( w, x, y, z, this.putter, this.skyStoneDefinition ); - } - - int realValidBlocks = 0; - - for( int i = x - 6; i < x + 6; i++ ) - { - for( int j = y - 6; j < y + 6; j++ ) - { - for( int k = z - 6; k < z + 6; k++ ) - { - blk = w.getBlock( i, j, k ); - if( this.validSpawn.contains( blk ) ) - { - realValidBlocks++; - } - } - } - } - - int validBlocks = 0; - for( int i = x - 15; i < x + 15; i++ ) - { - for( int j = y - 15; j < y + 15; j++ ) - { - for( int k = z - 15; k < z + 15; k++ ) - { - blk = w.getBlock( i, j, k ); - if( this.invalidSpawn.contains( blk ) ) - { - return false; - } - if( this.validSpawn.contains( blk ) ) - { - validBlocks++; - } - } - } - } - - final int minBlocks = 200; - if( validBlocks > minBlocks && realValidBlocks > 80 ) - { - // we can spawn here! - - int skyMode = 0; - - for( int i = x - 15; i < x + 15; i++ ) - { - for( int j = y - 15; j < y + 11; j++ ) - { - for( int k = z - 15; k < z + 15; k++ ) - { - if( w.canBlockSeeTheSky( i, j, k ) ) - { - skyMode++; - } - } - } - } - - boolean solid = true; - for( int j = y - 15; j < y - 1; j++ ) - { - if( w.getBlock( x, j, z ) == Platform.AIR_BLOCK ) - { - solid = false; - } - } - - if( !solid ) - { - skyMode = 0; - } - - // creator - if( skyMode > 10 ) - { - this.placeCrater( w, x, y, z ); - } - - this.placeMeteorite( w, x, y, z ); - - // collapse blocks... - if( skyMode > 3 ) - { - this.decay( w, x, y, z ); - } - - this.settings.putInt( "skyMode", skyMode ); - w.done(); - - WorldData.instance().spawnData().addNearByMeteorites( w.getWorld().getDimension(), x >> 4, z >> 4, this.settings ); - return true; - } - return false; - } - - CompoundNBT getSettings() - { - return this.settings; - } } diff --git a/src/main/java/appeng/worldgen/MeteoriteSpawnData.java b/src/main/java/appeng/worldgen/MeteoriteSpawnData.java new file mode 100644 index 000000000..15c82cce2 --- /dev/null +++ b/src/main/java/appeng/worldgen/MeteoriteSpawnData.java @@ -0,0 +1,181 @@ +package appeng.worldgen; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.IWorld; +import net.minecraft.world.server.ServerWorld; +import net.minecraft.world.storage.WorldSavedData; +import net.minecraftforge.fml.server.ServerLifecycleHooks; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Collection; + +/** + * This is per-world data to track where Meteorites have been spawned. + */ +public final class MeteoriteSpawnData { + + private static final String NAME = "ae2_meteorite_spawns"; + + private final SavedData data; + + private MeteoriteSpawnData(SavedData data) { + this.data = data; + } + + public void setGenerated( int chunkX, int chunkZ ) { + synchronized (data) { + // edit. + data.generated.putBoolean(chunkX + "," + chunkZ, true); + data.markDirty(); + } + } + + public boolean hasGenerated( int chunkX, int chunkZ ) { + synchronized( data ) + { + return data.generated.getBoolean( chunkX + "," + chunkZ ); + } + } + + @Nullable + private CompoundNBT getSpawnData(int chunkX, int chunkZ, boolean create) { + chunkX /= 16; + chunkZ /= 16; + String key = chunkX + "," + chunkZ; + INBT inbt = data.spawns.get(key); + if (!(inbt instanceof CompoundNBT)) { + if (create) { + inbt = new CompoundNBT(); + data.spawns.put(key, inbt); + data.markDirty(); + } else { + return null; + } + } + return (CompoundNBT) inbt; + } + + /** + * Checks whether another meteorite has spawned within the given block range of the given position. + */ + public boolean isMeteoriteSpawnInRange(BlockPos pos, int rangeSquared) { + synchronized( data ) + { + ChunkPos chunkPos = new ChunkPos(pos); + CompoundNBT spawnData = getSpawnData(chunkPos.x, chunkPos.z, false); + if (spawnData == null) { + return false; + } + final int size = spawnData.getInt( "num" ); + for (int i = 0; i < size; i++) { + CompoundNBT existingSettingsNbt = spawnData.getCompound(String.valueOf(i)); + BlockPos existingPos = PlacedMeteoriteSettings.read(existingSettingsNbt).getPos(); + int deltaX = (existingPos.getX() - pos.getX()); + int deltaZ = (existingPos.getZ() - pos.getZ()); + if (deltaX * deltaX + deltaZ * deltaZ <= rangeSquared) { + return true; + } + } + } + return false; + } + + public boolean tryAddSpawnedMeteorite(PlacedMeteoriteSettings settings, int minDistanceSquared) { + synchronized( data ) + { + if (isMeteoriteSpawnInRange(settings.getPos(), minDistanceSquared)) { + return false; + } + + addSpawnedMeteorite(settings); + } + return true; + } + + public void addSpawnedMeteorite(PlacedMeteoriteSettings settings) { + synchronized( data ) + { + ChunkPos chunkPos = new ChunkPos(settings.getPos()); + CompoundNBT spawnData = getSpawnData(chunkPos.x, chunkPos.z, true); + final int size = spawnData.getInt( "num" ); + spawnData.put( String.valueOf( size ), settings.write(new CompoundNBT()) ); + spawnData.putInt( "num", size + 1 ); + data.markDirty(); + } + } + + public Collection getNearByMeteorites(int chunkX, int chunkZ) { + final Collection ll = new ArrayList<>(); + + synchronized( data ) + { + for( int x = -1; x <= 1; x++ ) + { + for( int z = -1; z <= 1; z++ ) + { + final int cx = x + ( chunkX >> 4 ); + final int cz = z + ( chunkZ >> 4 ); + + final CompoundNBT data = getSpawnData( cx << 4, cz << 4, false ); + + if( data != null ) + { + // edit. + final int size = data.getInt( "num" ); + for( int s = 0; s < size; s++ ) + { + CompoundNBT settingsNbt = data.getCompound(String.valueOf(s)); + ll.add(PlacedMeteoriteSettings.read(settingsNbt)); + } + } + } + } + } + + return ll; + } + + public synchronized static MeteoriteSpawnData get(IWorld world) { + ServerWorld serverWorld; + if (world instanceof ServerWorld) { + serverWorld = (ServerWorld) world; + } else { + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + serverWorld = server.getWorld(world.getDimension().getType()); + } + + SavedData savedData = serverWorld.getSavedData().getOrCreate(SavedData::new, NAME); + return new MeteoriteSpawnData(savedData); + } + + private static class SavedData extends WorldSavedData { + + private CompoundNBT generated; + private CompoundNBT spawns; + + public SavedData() { + super(NAME); + this.generated = new CompoundNBT(); + this.spawns = new CompoundNBT(); + } + + @Override + public synchronized void read(CompoundNBT nbt) { + this.generated = nbt.getCompound("generated"); + this.spawns = nbt.getCompound("spawns"); + } + + @Override + public synchronized CompoundNBT write(CompoundNBT compound) { + compound.put("generated", generated); + compound.put("spawns", spawns); + return compound; + } + } + +} diff --git a/src/main/java/appeng/worldgen/MeteoriteSpawner.java b/src/main/java/appeng/worldgen/MeteoriteSpawner.java new file mode 100644 index 000000000..6bc6063cd --- /dev/null +++ b/src/main/java/appeng/worldgen/MeteoriteSpawner.java @@ -0,0 +1,191 @@ +package appeng.worldgen; + +import appeng.api.AEApi; +import appeng.api.definitions.IBlocks; +import appeng.core.AEConfig; +import appeng.worldgen.meteorite.IMeteoriteWorld; +import appeng.worldgen.meteorite.StandardWorld; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorldReader; + +import javax.annotation.Nullable; +import java.util.HashSet; +import java.util.Set; + +/** + * Makes decisions about spawning meteorites in the world. + */ +public class MeteoriteSpawner { + + private final Set validSpawn = new HashSet<>(); + private final Set invalidSpawn = new HashSet<>(); + + public MeteoriteSpawner() + { + final IBlocks blocks = AEApi.instance().definitions().blocks(); + + this.validSpawn.add( Blocks.STONE ); + this.validSpawn.add( Blocks.COBBLESTONE ); + this.validSpawn.add( Blocks.GRASS ); + this.validSpawn.add( Blocks.SAND ); + this.validSpawn.add( Blocks.DIRT ); + this.validSpawn.add( Blocks.GRAVEL ); + this.validSpawn.add( Blocks.NETHERRACK ); + this.validSpawn.add( Blocks.IRON_ORE ); + this.validSpawn.add( Blocks.GOLD_ORE ); + this.validSpawn.add( Blocks.DIAMOND_ORE ); + this.validSpawn.add( Blocks.REDSTONE_ORE ); + this.validSpawn.add( Blocks.ICE ); + this.validSpawn.add( Blocks.SNOW ); + + this.invalidSpawn.add( blocks.skyStoneBlock().block() ); + this.invalidSpawn.add( Blocks.IRON_DOOR ); + this.invalidSpawn.add( Blocks.IRON_BARS ); + this.invalidSpawn.add( Blocks.OAK_DOOR ); + this.invalidSpawn.add( Blocks.ACACIA_DOOR ); + this.invalidSpawn.add( Blocks.BIRCH_DOOR ); + this.invalidSpawn.add( Blocks.DARK_OAK_DOOR ); + this.invalidSpawn.add( Blocks.JUNGLE_DOOR ); + this.invalidSpawn.add( Blocks.SPRUCE_DOOR ); + this.invalidSpawn.add( Blocks.BRICKS ); + this.invalidSpawn.add( Blocks.CLAY ); + this.invalidSpawn.add( Blocks.WATER ); + } + + public PlacedMeteoriteSettings trySpawnMeteoriteAtSuitableHeight(IWorldReader world, int x, int y, int z) { + + for( int tries = 0; tries < 20; tries++ ) + { + PlacedMeteoriteSettings spawned = trySpawnMeteorite(world, new BlockPos(x, y, z)); + if (spawned != null) { + return spawned; + } + + y -= 15; + if( y < 40 ) + { + return null; + } + } + + return null; + } + + @Nullable + public PlacedMeteoriteSettings trySpawnMeteorite(IWorldReader world, BlockPos pos ) + { + Block blk = world.getBlockState(pos).getBlock(); + if( !this.validSpawn.contains( blk ) ) + { + return null; // must spawn on a valid block.. + } + + double meteoriteSize = ( Math.random() * 6.0 ) + 2; + double realCrater = meteoriteSize * 2 + 5; + boolean lava = Math.random() > 0.9; + + if (!areSurroundingsSuitable(world, pos)) { + return null; + } + + // we can spawn here! + int skyMode = countBlockWithSkyLight(world, pos); + + boolean solid = !isAirBelowSpawnPoint(world, pos); + + if( !solid ) + { + skyMode = 0; + } + + return new PlacedMeteoriteSettings(pos, blk.getRegistryName(), lava, skyMode, meteoriteSize, realCrater); + } + + private static boolean isAirBelowSpawnPoint(IWorldReader w, BlockPos pos) { + BlockPos.Mutable testPos = new BlockPos.Mutable(pos); + for( int j = pos.getY() - 15; j < pos.getY() - 1; j++ ) + { + testPos.setY(j); + if( w.isAirBlock(testPos) ) + { + return true; + } + } + return false; + } + + private int countBlockWithSkyLight(IWorldReader w, BlockPos pos) { + int skyMode = 0; + + BlockPos.Mutable testPos = new BlockPos.Mutable(); + for( int i = pos.getX() - 15; i < pos.getX() + 15; i++ ) + { + testPos.setX(i); + for( int j = pos.getY() - 15; j < pos.getY() + 11; j++ ) + { + testPos.setY(j); + for( int k = pos.getZ() - 15; k < pos.getZ() + 15; k++ ) + { + testPos.setZ(k); + if( w.canBlockSeeSky( testPos ) ) + { + skyMode++; + } + } + } + } + return skyMode; + } + + private boolean areSurroundingsSuitable(IWorldReader w, BlockPos pos) { + int realValidBlocks = 0; + + BlockPos.Mutable testPos = new BlockPos.Mutable(); + for( int i = pos.getX() - 6; i < pos.getX() + 6; i++ ) + { + testPos.setX(i); + for( int j = pos.getY() - 6; j < pos.getY() + 6; j++ ) + { + testPos.setY(j); + for( int k = pos.getZ() - 6; k < pos.getZ() + 6; k++ ) + { + testPos.setZ(k); + Block testBlk = w.getBlockState(testPos).getBlock(); + if( this.validSpawn.contains( testBlk ) ) + { + realValidBlocks++; + } + } + } + } + + int validBlocks = 0; + for( int i = pos.getX() - 15; i < pos.getX() + 15; i++ ) + { + testPos.setX(i); + for( int j = pos.getY() - 15; j < pos.getY() + 15; j++ ) + { + testPos.setY(j); + for( int k = pos.getZ() - 15; k < pos.getZ() + 15; k++ ) + { + testPos.setZ(k); + Block testBlk = w.getBlockState( testPos ).getBlock(); + if( this.invalidSpawn.contains( testBlk ) ) + { + return false; + } + if( this.validSpawn.contains( testBlk ) ) + { + validBlocks++; + } + } + } + } + + final int minBlocks = 200; + return validBlocks > minBlocks && realValidBlocks > 80; + } + +} diff --git a/src/main/java/appeng/worldgen/MeteoriteWorldGen.java b/src/main/java/appeng/worldgen/MeteoriteWorldGen.java index 7ceddeaf9..e678ba781 100644 --- a/src/main/java/appeng/worldgen/MeteoriteWorldGen.java +++ b/src/main/java/appeng/worldgen/MeteoriteWorldGen.java @@ -19,134 +19,91 @@ package appeng.worldgen; -import java.util.Random; - -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.world.World; -import net.minecraft.world.chunk.IChunkProvider; -import net.minecraft.world.gen.IChunkGenerator; -import net.minecraftforge.fml.common.IWorldGenerator; - +import appeng.api.features.AEFeature; import appeng.api.features.IWorldGen.WorldGenType; import appeng.core.AEConfig; +import appeng.core.AppEng; import appeng.core.features.registries.WorldGenRegistry; import appeng.core.worlddata.WorldData; -import appeng.hooks.TickHandler; -import appeng.util.IWorldCallable; import appeng.util.Platform; -import appeng.worldgen.meteorite.ChunkOnly; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.IWorld; +import net.minecraft.world.gen.ChunkGenerator; +import net.minecraft.world.gen.GenerationSettings; +import net.minecraft.world.gen.feature.Feature; +import net.minecraft.world.gen.feature.NoFeatureConfig; +import net.minecraft.world.server.ServerWorld; + +import javax.annotation.ParametersAreNonnullByDefault; +import java.util.Random; -public final class MeteoriteWorldGen implements IWorldGenerator +public final class MeteoriteWorldGen extends Feature { + + public static final MeteoriteWorldGen INSTANCE = new MeteoriteWorldGen(); + + private MeteoriteWorldGen( ) + { + super( NoFeatureConfig::deserialize ); + setRegistryName( AppEng.MOD_ID, "meteorite" ); + } + + private final MeteoriteSpawner spawner = new MeteoriteSpawner(); + + @ParametersAreNonnullByDefault @Override - public void generate( final Random r, final int chunkX, final int chunkZ, final World w, final IChunkGenerator chunkGenerator, final IChunkProvider chunkProvider ) + public boolean place( IWorld w, ChunkGenerator generator, Random r, BlockPos pos, NoFeatureConfig config ) { - if( WorldGenRegistry.INSTANCE.isWorldGenEnabled( WorldGenType.METEORITES, w ) ) - { - final int x = r.nextInt( 16 ) + ( chunkX << 4 ); - final int z = r.nextInt( 16 ) + ( chunkZ << 4 ); - final int depth = AEConfig.instance().getMeteoriteMaximumSpawnHeight() + r.nextInt( 20 ); - - TickHandler.INSTANCE.addCallable( w, new MeteoriteSpawn( x, depth, z ) ); + if(!AEConfig.instance().isFeatureEnabled( AEFeature.METEORITE_WORLD_GEN )) { + return false; } - else - { - WorldData.instance().compassData().service().updateArea( w, chunkX, chunkZ ); + + ChunkPos chunkPos = new ChunkPos( pos ); + if (!WorldGenRegistry.INSTANCE.isWorldGenEnabled(WorldGenType.METEORITES, w.getWorld())) { + return false; } - } - private boolean tryMeteorite( final World w, int depth, final int x, final int z ) - { - for( int tries = 0; tries < 20; tries++ ) + double minSqDist = Double.MAX_VALUE; + + MeteoriteSpawnData spawnData = MeteoriteSpawnData.get(w); + + // near by meteorites! + for( final PlacedMeteoriteSettings data : spawnData.getNearByMeteorites(chunkPos.x, chunkPos.z) ) { - final MeteoritePlacer mp = new MeteoritePlacer(); + minSqDist = Math.min( minSqDist, getSqDistance( data, pos ) ); + } - if( mp.spawnMeteorite( new ChunkOnly( w, x >> 4, z >> 4 ), x, depth, z ) ) - { - final int px = x >> 4; - final int pz = z >> 4; + final boolean isCluster = ( minSqDist < 30 * 30 ) && Platform.getRandomFloat() < AEConfig.instance().getMeteoriteClusterChance(); - for( int cx = px - 6; cx < px + 6; cx++ ) - { - for( int cz = pz - 6; cz < pz + 6; cz++ ) - { - if( w.getChunkProvider().getLoadedChunk( cx, cz ) != null ) - { - if( px == cx && pz == cz ) - { - continue; - } + if( minSqDist > AEConfig.instance().getMinMeteoriteDistanceSq() || isCluster ) + { + final int x = r.nextInt( 16 ) + ( chunkPos.x << 4 ); + final int y = AEConfig.instance().getMeteoriteMaximumSpawnHeight() + r.nextInt( 20 ); + final int z = r.nextInt( 16 ) + ( chunkPos.z << 4 ); - if( WorldData.instance().spawnData().hasGenerated( w.provider.getDimension(), cx, cz ) ) - { - final MeteoritePlacer mp2 = new MeteoritePlacer(); - mp2.spawnMeteorite( new ChunkOnly( w, cx, cz ), mp.getSettings() ); - } - } - } + PlacedMeteoriteSettings settings = spawner.trySpawnMeteoriteAtSuitableHeight(w, x, y, z); + if (settings != null) { + // Double check that no other chunk generated a meteorite within range while we were working + int checkRange = isCluster ? (30*30) : AEConfig.instance().getMinMeteoriteDistanceSq(); + if (spawnData.tryAddSpawnedMeteorite(settings, checkRange)) { + MeteoritePlacer placer = new MeteoritePlacer(w, settings); + placer.place(); + WorldData.instance().compassData().service().updateArea( w, chunkPos.x, chunkPos.z ); } - - return true; - } - - depth -= 15; - if( depth < 40 ) - { - return false; } } - return false; + spawnData.setGenerated( chunkPos.x, chunkPos.z ); + return true; } - private Iterable getNearByMeteorites( final World w, final int chunkX, final int chunkZ ) + private static double getSqDistance( PlacedMeteoriteSettings placed, BlockPos pos ) { - return WorldData.instance().spawnData().getNearByMeteorites( w.provider.getDimension(), chunkX, chunkZ ); + final int chunkX = placed.getPos().getX() - pos.getX(); + final int chunkZ = placed.getPos().getZ() - pos.getZ(); + return chunkX * chunkX + chunkZ * chunkZ; } - private class MeteoriteSpawn implements IWorldCallable - { - - private final int x; - private final int z; - private final int depth; - - public MeteoriteSpawn( final int x, final int depth, final int z ) - { - this.x = x; - this.z = z; - this.depth = depth; - } - - @Override - public Object call( final World world ) throws Exception - { - final int chunkX = this.x >> 4; - final int chunkZ = this.z >> 4; - - double minSqDist = Double.MAX_VALUE; - - // near by meteorites! - for( final CompoundNBT data : MeteoriteWorldGen.this.getNearByMeteorites( world, chunkX, chunkZ ) ) - { - final MeteoritePlacer mp = new MeteoritePlacer(); - mp.spawnMeteorite( new ChunkOnly( world, chunkX, chunkZ ), data ); - - minSqDist = Math.min( minSqDist, mp.getSqDistance( this.x, this.z ) ); - } - - final boolean isCluster = ( minSqDist < 30 * 30 ) && Platform.getRandomFloat() < AEConfig.instance().getMeteoriteClusterChance(); - - if( minSqDist > AEConfig.instance().getMinMeteoriteDistanceSq() || isCluster ) - { - MeteoriteWorldGen.this.tryMeteorite( world, this.depth, this.x, this.z ); - } - - WorldData.instance().spawnData().setGenerated( world.provider.getDimension(), chunkX, chunkZ ); - WorldData.instance().compassData().service().updateArea( world, chunkX, chunkZ ); - - return null; - } - } } diff --git a/src/main/java/appeng/worldgen/PlacedMeteoriteSettings.java b/src/main/java/appeng/worldgen/PlacedMeteoriteSettings.java new file mode 100644 index 000000000..50b6be51a --- /dev/null +++ b/src/main/java/appeng/worldgen/PlacedMeteoriteSettings.java @@ -0,0 +1,78 @@ +package appeng.worldgen; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.common.util.INBTSerializable; + +import java.util.Objects; + +public final class PlacedMeteoriteSettings { + + private final BlockPos pos; + private final ResourceLocation blk; + private final boolean lava; + private final int skyMode; + private final double meteoriteRadius; + private final double craterRadius; + + public PlacedMeteoriteSettings(BlockPos pos, ResourceLocation blk, boolean lava, int skyMode, double meteoriteRadius, double craterRadius) { + this.pos = pos; + this.blk = blk; + this.lava = lava; + this.skyMode = skyMode; + this.meteoriteRadius = meteoriteRadius; + this.craterRadius = craterRadius; + } + + public BlockPos getPos() { + return pos; + } + + public ResourceLocation getBlk() { + return blk; + } + + public boolean isLava() { + return lava; + } + + public int getSkyMode() { + return skyMode; + } + + public double getMeteoriteRadius() { + return meteoriteRadius; + } + + public double getCraterRadius() { + return craterRadius; + } + + public CompoundNBT write(CompoundNBT tag) { + tag.putInt("x", pos.getX()); + tag.putInt("y", pos.getY()); + tag.putInt("z", pos.getZ()); + tag.putString( "blk", blk.toString() ); + + tag.putDouble( "meteoriteRadius", meteoriteRadius ); + tag.putDouble( "craterRadius", craterRadius ); + + tag.putBoolean( "lava", lava ); + tag.putInt( "skyMode", skyMode ); + return tag; + } + + public static PlacedMeteoriteSettings read(CompoundNBT tag) { + BlockPos pos = new BlockPos(tag.getInt("x"), tag.getInt("y"), tag.getInt("z")); + ResourceLocation blk = new ResourceLocation(tag.getString("blk")); + double meteoriteRadius = tag.getDouble("meteoriteRadius"); + double craterRadius = tag.getDouble("craterRadius"); + boolean lava = tag.getBoolean("lava"); + int skyMode = tag.getInt("skyMode"); + + return new PlacedMeteoriteSettings(pos, blk, lava, skyMode, meteoriteRadius, craterRadius); + } + +} diff --git a/src/main/java/appeng/worldgen/QuartzWorldGen.java b/src/main/java/appeng/worldgen/QuartzWorldGen.java index 87ce83e4e..f553ffe12 100644 --- a/src/main/java/appeng/worldgen/QuartzWorldGen.java +++ b/src/main/java/appeng/worldgen/QuartzWorldGen.java @@ -19,60 +19,75 @@ package appeng.worldgen; -import java.util.Random; - -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import net.minecraft.world.chunk.AbstractChunkProvider; -import net.minecraft.world.gen.ChunkGenerator; -import net.minecraft.world.gen.feature.WorldGenMinable; -import net.minecraftforge.fml.common.IWorldGenerator; - import appeng.api.AEApi; import appeng.api.definitions.IBlockDefinition; import appeng.api.definitions.IBlocks; import appeng.api.features.IWorldGen.WorldGenType; -import appeng.core.AEConfig; import appeng.core.features.registries.WorldGenRegistry; +import com.mojang.datafixers.Dynamic; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; +import net.minecraft.world.World; +import net.minecraft.world.gen.ChunkGenerator; +import net.minecraft.world.gen.GenerationSettings; +import net.minecraft.world.gen.feature.ReplaceBlockConfig; +import net.minecraft.world.gen.feature.ReplaceBlockFeature; + +import java.util.Random; +import java.util.function.Function; -public final class QuartzWorldGen implements IWorldGenerator +public final class QuartzWorldGen extends ReplaceBlockFeature { + /* private final WorldGenMinable oreNormal; private final WorldGenMinable oreCharged; + */ - public QuartzWorldGen() + public QuartzWorldGen( Function, ? extends ReplaceBlockConfig> serializer ) { + super(serializer); final IBlocks blocks = AEApi.instance().definitions().blocks(); final IBlockDefinition oreDefinition = blocks.quartzOre(); final IBlockDefinition chargedDefinition = blocks.quartzOreCharged(); + /* this.oreNormal = oreDefinition.maybeBlock() .map( b -> new WorldGenMinable( b.getDefaultState(), AEConfig.instance().getQuartzOresPerCluster() ) ) .orElse( null ); this.oreCharged = chargedDefinition.maybeBlock() .map( b -> new WorldGenMinable( b.getDefaultState(), AEConfig.instance().getQuartzOresPerCluster() ) ) .orElse( null ); + */ } - @Override - public void generate(final Random r, final int chunkX, final int chunkZ, final World w, final ChunkGenerator chunkGenerator, final AbstractChunkProvider chunkProvider ) + private static boolean shouldGenerate( final boolean isCharged, final World w ) { + return WorldGenRegistry.INSTANCE.isWorldGenEnabled( isCharged ? WorldGenType.CHARGED_CERTUS_QUARTZ : WorldGenType.CERTUS_QUARTZ, w ); + } + + @Override public boolean place( IWorld worldIn, ChunkGenerator generator, Random r, BlockPos pos, ReplaceBlockConfig config ) + { + /* if( this.oreNormal == null && this.oreCharged == null ) { - return; + return false; } - int seaLevel = w.provider.getAverageGroundLevel() + 1; + World w = worldIn.getWorld(); + + int seaLevel = w.getSeaLevel(); + + ChunkPos chunkPos = new ChunkPos( pos ); if( seaLevel < 20 ) { - final int x = ( chunkX << 4 ) + 8; - final int z = ( chunkZ << 4 ) + 8; - seaLevel = w.getHeight( x, z ); + final int x = ( chunkPos.x << 4 ) + 8; + final int z = ( chunkPos.z << 4 ) + 8; + seaLevel = w.getHeight( Heightmap.Type.WORLD_SURFACE, x, z ); } - final double oreDepthMultiplier = AEConfig.instance().getQuartzOresClusterAmount() * seaLevel / 64; + final int oreDepthMultiplier = AEConfig.instance().getQuartzOresClusterAmount() * seaLevel / 64; final int scale = (int) Math.round( r.nextGaussian() * Math.sqrt( oreDepthMultiplier ) + oreDepthMultiplier ); for( int cnt = 0; cnt < ( r.nextBoolean() ? scale * 2 : scale ) / 2; ++cnt ) @@ -87,16 +102,14 @@ public final class QuartzWorldGen implements IWorldGenerator final WorldGenMinable whichOre = isCharged ? this.oreCharged : this.oreNormal; if( whichOre != null && shouldGenerate( isCharged, w ) ) { - final int cx = chunkX * 16 + r.nextInt( 16 ); + final int cx = chunkPos.x * 16 + r.nextInt( 16 ); final int cy = r.nextInt( 40 * seaLevel / 64 ) + r.nextInt( 22 * seaLevel / 64 ) + 12 * seaLevel / 64; - final int cz = chunkZ * 16 + r.nextInt( 16 ); + final int cz = chunkPos.z * 16 + r.nextInt( 16 ); whichOre.generate( w, r, new BlockPos( cx, cy, cz ) ); } } + */ + return true; } - private static boolean shouldGenerate( final boolean isCharged, final World w ) - { - return WorldGenRegistry.INSTANCE.isWorldGenEnabled( isCharged ? WorldGenType.CHARGED_CERTUS_QUARTZ : WorldGenType.CERTUS_QUARTZ, w ); - } } diff --git a/src/main/java/appeng/worldgen/meteorite/ChunkOnly.java b/src/main/java/appeng/worldgen/meteorite/ChunkOnly.java index 7dbb28a09..6fce554a3 100644 --- a/src/main/java/appeng/worldgen/meteorite/ChunkOnly.java +++ b/src/main/java/appeng/worldgen/meteorite/ChunkOnly.java @@ -22,21 +22,22 @@ package appeng.worldgen.meteorite; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; import net.minecraft.world.World; import net.minecraft.world.chunk.Chunk; import appeng.util.Platform; +import net.minecraft.world.chunk.IChunk; public class ChunkOnly extends StandardWorld { - private final Chunk target; + private final IChunk target; private final int cx; private final int cz; - private int verticalBits = 0; - public ChunkOnly( final World w, final int cx, final int cz ) + public ChunkOnly(final IWorld w, final int cx, final int cz ) { super( w ); this.target = w.getChunk( cx, cz ); @@ -68,48 +69,42 @@ public class ChunkOnly extends StandardWorld return Math.min( in, ( this.cz + 1 ) << 4 ); } - @Override - public Block getBlock( final int x, final int y, final int z ) + @Override + public boolean contains(BlockPos pos) { + return this.range(pos); + } + + @Override + public Block getBlock( BlockPos pos ) { - if( this.range( x, y, z ) ) + if( this.range( pos ) ) { - return this.target.getBlockState( new BlockPos(x, y, z) ).getBlock(); + return this.target.getBlockState( new BlockPos(pos) ).getBlock(); } return Platform.AIR_BLOCK; } @Override - public void setBlock( final int x, final int y, final int z, final Block blk ) + public void setBlock( BlockPos pos, final BlockState blk ) { - if( this.range( x, y, z ) ) + if( this.range( pos ) ) { - this.verticalBits |= 1 << ( y >> 4 ); - this.getWorld().setBlockState( new BlockPos( x, y, z ), blk.getDefaultState() ); + target.setBlockState(new BlockPos( pos ), blk, false); } } @Override - public void setBlock( final int x, final int y, final int z, final BlockState state, final int flags ) + public void setBlock( BlockPos pos, final BlockState state, final int flags ) { - if( this.range( x, y, z ) ) + if( this.range( pos ) ) { - this.verticalBits |= 1 << ( y >> 4 ); - this.getWorld().setBlockState( new BlockPos( x, y, z ), state, flags & ( ~2 ) ); + this.getWorld().setBlockState( new BlockPos( pos ), state, flags & ( ~2 ) ); } } @Override - public void done() + public boolean range( BlockPos pos ) { - if( this.verticalBits != 0 ) - { - Platform.sendChunk( this.target, this.verticalBits ); - } - } - - @Override - public boolean range( final int x, final int y, final int z ) - { - return this.cx == ( x >> 4 ) && this.cz == ( z >> 4 ); + return this.cx == ( pos.getX() >> 4 ) && this.cz == ( pos.getZ() >> 4 ); } } diff --git a/src/main/java/appeng/worldgen/meteorite/Fallout.java b/src/main/java/appeng/worldgen/meteorite/Fallout.java index 9b2d64464..aa1062a88 100644 --- a/src/main/java/appeng/worldgen/meteorite/Fallout.java +++ b/src/main/java/appeng/worldgen/meteorite/Fallout.java @@ -19,21 +19,23 @@ package appeng.worldgen.meteorite; +import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; -import appeng.api.definitions.IBlockDefinition; import appeng.util.Platform; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; public class Fallout { private final MeteoriteBlockPutter putter; - private final IBlockDefinition skyStoneDefinition; + private final BlockState skyStone; - public Fallout( final MeteoriteBlockPutter putter, final IBlockDefinition skyStoneDefinition ) + public Fallout( final MeteoriteBlockPutter putter, final BlockState skyStone ) { this.putter = putter; - this.skyStoneDefinition = skyStoneDefinition; + this.skyStone = skyStone; } public int adjustCrater() @@ -41,53 +43,53 @@ public class Fallout return 0; } - public void getRandomFall( final IMeteoriteWorld w, final int x, final int y, final int z ) + public void getRandomFall(final IWorld w, BlockPos pos ) { final double a = Math.random(); if( a > 0.9 ) { - this.putter.put( w, x, y, z, Blocks.STONE ); + this.putter.put( w, pos, Blocks.STONE.getDefaultState() ); } else if( a > 0.8 ) { - this.putter.put( w, x, y, z, Blocks.COBBLESTONE ); + this.putter.put( w, pos, Blocks.COBBLESTONE.getDefaultState() ); } else if( a > 0.7 ) { - this.putter.put( w, x, y, z, Blocks.DIRT ); + this.putter.put( w, pos, Blocks.DIRT.getDefaultState() ); } else { - this.putter.put( w, x, y, z, Blocks.GRAVEL ); + this.putter.put( w, pos, Blocks.GRAVEL.getDefaultState() ); } } - public void getRandomInset( final IMeteoriteWorld w, final int x, final int y, final int z ) + public void getRandomInset( final IWorld w, BlockPos pos ) { final double a = Math.random(); if( a > 0.9 ) { - this.putter.put( w, x, y, z, Blocks.COBBLESTONE ); + this.putter.put( w, pos, Blocks.COBBLESTONE.getDefaultState() ); } else if( a > 0.8 ) { - this.putter.put( w, x, y, z, Blocks.STONE ); + this.putter.put( w, pos, Blocks.STONE.getDefaultState() ); } else if( a > 0.7 ) { - this.putter.put( w, x, y, z, Blocks.GRASS_BLOCK ); + this.putter.put( w, pos, Blocks.GRASS_BLOCK.getDefaultState() ); } else if( a > 0.6 ) { - this.skyStoneDefinition.maybeBlock().ifPresent( block -> this.putter.put( w, x, y, z, block ) ); + this.putter.put( w, pos, this.skyStone ); } else if( a > 0.5 ) { - this.putter.put( w, x, y, z, Blocks.GRAVEL ); + this.putter.put( w, pos, Blocks.GRAVEL.getDefaultState() ); } else { - this.putter.put( w, x, y, z, Platform.AIR_BLOCK ); + this.putter.put( w, pos, Platform.AIR_BLOCK.getDefaultState() ); } } } diff --git a/src/main/java/appeng/worldgen/meteorite/FalloutCopy.java b/src/main/java/appeng/worldgen/meteorite/FalloutCopy.java index 69dfa4076..4528896ee 100644 --- a/src/main/java/appeng/worldgen/meteorite/FalloutCopy.java +++ b/src/main/java/appeng/worldgen/meteorite/FalloutCopy.java @@ -19,10 +19,14 @@ package appeng.worldgen.meteorite; +import net.minecraft.block.Block; import net.minecraft.block.BlockState; import appeng.api.definitions.IBlockDefinition; import appeng.util.Platform; +import net.minecraft.block.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; public class FalloutCopy extends Fallout @@ -34,47 +38,47 @@ public class FalloutCopy extends Fallout private final BlockState block; private final MeteoriteBlockPutter putter; - public FalloutCopy( final IMeteoriteWorld w, final int x, final int y, final int z, final MeteoriteBlockPutter putter, final IBlockDefinition skyStoneDefinition ) + public FalloutCopy(final IWorld w, BlockPos pos, final MeteoriteBlockPutter putter, final BlockState skyStone ) { - super( putter, skyStoneDefinition ); + super( putter, skyStone ); this.putter = putter; - this.block = w.getBlockState( x, y, z ); + this.block = w.getBlockState( pos ); } @Override - public void getRandomFall( final IMeteoriteWorld w, final int x, final int y, final int z ) + public void getRandomFall( final IWorld w, BlockPos pos ) { final double a = Math.random(); if( a > SPECIFIED_BLOCK_THRESHOLD ) { - this.putter.put( w, x, y, z, this.block, 3 ); + this.putter.put( w, pos, this.block ); } else { - this.getOther( w, x, y, z, a ); + this.getOther( w, pos, a ); } } - public void getOther( final IMeteoriteWorld w, final int x, final int y, final int z, final double a ) + public void getOther( final IWorld w, BlockPos pos, final double a ) { } @Override - public void getRandomInset( final IMeteoriteWorld w, final int x, final int y, final int z ) + public void getRandomInset( final IWorld w, BlockPos pos ) { final double a = Math.random(); if( a > SPECIFIED_BLOCK_THRESHOLD ) { - this.putter.put( w, x, y, z, this.block, 3 ); + this.putter.put( w, pos, this.block ); } else if( a > AIR_BLOCK_THRESHOLD ) { - this.putter.put( w, x, y, z, Platform.AIR_BLOCK ); + this.putter.put( w, pos, Blocks.AIR.getDefaultState() ); } else { - this.getOther( w, x, y, z, a - BLOCK_THRESHOLD_STEP ); + this.getOther( w, pos, a - BLOCK_THRESHOLD_STEP ); } } } \ No newline at end of file diff --git a/src/main/java/appeng/worldgen/meteorite/FalloutSand.java b/src/main/java/appeng/worldgen/meteorite/FalloutSand.java index 179c3c52b..36b62c95a 100644 --- a/src/main/java/appeng/worldgen/meteorite/FalloutSand.java +++ b/src/main/java/appeng/worldgen/meteorite/FalloutSand.java @@ -19,9 +19,12 @@ package appeng.worldgen.meteorite; +import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import appeng.api.definitions.IBlockDefinition; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; public class FalloutSand extends FalloutCopy @@ -29,9 +32,9 @@ public class FalloutSand extends FalloutCopy private static final double GLASS_THRESHOLD = 0.66; private final MeteoriteBlockPutter putter; - public FalloutSand( final IMeteoriteWorld w, final int x, final int y, final int z, final MeteoriteBlockPutter putter, final IBlockDefinition skyStoneDefinition ) + public FalloutSand(final IWorld w, BlockPos pos, final MeteoriteBlockPutter putter, final BlockState skyStone ) { - super( w, x, y, z, putter, skyStoneDefinition ); + super( w, pos, putter, skyStone ); this.putter = putter; } @@ -42,11 +45,11 @@ public class FalloutSand extends FalloutCopy } @Override - public void getOther( final IMeteoriteWorld w, final int x, final int y, final int z, final double a ) + public void getOther( final IWorld w, BlockPos pos, final double a ) { if( a > GLASS_THRESHOLD ) { - this.putter.put( w, x, y, z, Blocks.GLASS ); + this.putter.put( w, pos, Blocks.GLASS.getDefaultState() ); } } } \ No newline at end of file diff --git a/src/main/java/appeng/worldgen/meteorite/FalloutSnow.java b/src/main/java/appeng/worldgen/meteorite/FalloutSnow.java index 305120a08..7a1b9fda4 100644 --- a/src/main/java/appeng/worldgen/meteorite/FalloutSnow.java +++ b/src/main/java/appeng/worldgen/meteorite/FalloutSnow.java @@ -19,9 +19,12 @@ package appeng.worldgen.meteorite; +import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import appeng.api.definitions.IBlockDefinition; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; public class FalloutSnow extends FalloutCopy @@ -30,9 +33,9 @@ public class FalloutSnow extends FalloutCopy private static final double ICE_THRESHOLD = 0.5; private final MeteoriteBlockPutter putter; - public FalloutSnow( final IMeteoriteWorld w, final int x, final int y, final int z, final MeteoriteBlockPutter putter, final IBlockDefinition skyStoneDefinition ) + public FalloutSnow(final IWorld w, BlockPos pos, final MeteoriteBlockPutter putter, final BlockState skyStone) { - super( w, x, y, z, putter, skyStoneDefinition ); + super( w, pos, putter, skyStone ); this.putter = putter; } @@ -43,15 +46,15 @@ public class FalloutSnow extends FalloutCopy } @Override - public void getOther( final IMeteoriteWorld w, final int x, final int y, final int z, final double a ) + public void getOther( final IWorld w, BlockPos pos, final double a ) { if( a > SNOW_THRESHOLD ) { - this.putter.put( w, x, y, z, Blocks.SNOW ); + this.putter.put( w, pos, Blocks.SNOW.getDefaultState() ); } else if( a > ICE_THRESHOLD ) { - this.putter.put( w, x, y, z, Blocks.ICE ); + this.putter.put( w, pos, Blocks.ICE.getDefaultState() ); } } } \ No newline at end of file diff --git a/src/main/java/appeng/worldgen/meteorite/IMeteoriteWorld.java b/src/main/java/appeng/worldgen/meteorite/IMeteoriteWorld.java index e8d3e1626..29aeaf040 100644 --- a/src/main/java/appeng/worldgen/meteorite/IMeteoriteWorld.java +++ b/src/main/java/appeng/worldgen/meteorite/IMeteoriteWorld.java @@ -22,6 +22,8 @@ package appeng.worldgen.meteorite; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; import net.minecraft.world.World; @@ -35,21 +37,19 @@ public interface IMeteoriteWorld int maxZ( int in ); - boolean isNether(); + boolean contains( BlockPos pos ); - Block getBlock( int x, int y, int z ); + Block getBlock( BlockPos pos ); - boolean canBlockSeeTheSky( int i, int j, int k ); + boolean canBlockSeeTheSky( BlockPos pos ); - TileEntity getTileEntity( int x, int y, int z ); + TileEntity getTileEntity( BlockPos pos ); - World getWorld(); + IWorld getWorld(); - void setBlock( int i, int j, int k, Block blk ); + void setBlock( BlockPos pos, final BlockState state, final int flags ); - void setBlock( int i, int j, int k, BlockState state, int l ); + void setBlock( BlockPos pos, BlockState blk ); - void done(); - - BlockState getBlockState( int x, int y, int z ); + BlockState getBlockState( BlockPos pos ); } \ No newline at end of file diff --git a/src/main/java/appeng/worldgen/meteorite/MeteoriteBlockPutter.java b/src/main/java/appeng/worldgen/meteorite/MeteoriteBlockPutter.java index f8052fa6e..eb35882a4 100644 --- a/src/main/java/appeng/worldgen/meteorite/MeteoriteBlockPutter.java +++ b/src/main/java/appeng/worldgen/meteorite/MeteoriteBlockPutter.java @@ -22,30 +22,23 @@ package appeng.worldgen.meteorite; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; public class MeteoriteBlockPutter { - public boolean put( final IMeteoriteWorld w, final int i, final int j, final int k, final Block blk ) + public boolean put(final IWorld w, BlockPos pos, final BlockState blk ) { - final Block original = w.getBlock( i, j, k ); + final BlockState original = w.getBlockState( pos ); - if( original == Blocks.BEDROCK || original == blk ) + if( original.getBlock() == Blocks.BEDROCK || original == blk ) { return false; } - w.setBlock( i, j, k, blk ); + w.setBlockState(pos, blk, 0); return true; } - void put( final IMeteoriteWorld w, final int i, final int j, final int k, final BlockState state, final int meta ) - { - if( w.getBlock( i, j, k ) == Blocks.BEDROCK ) - { - return; - } - - w.setBlock( i, j, k, state, 3 ); - } } diff --git a/src/main/java/appeng/worldgen/meteorite/StandardWorld.java b/src/main/java/appeng/worldgen/meteorite/StandardWorld.java index 69b731990..f8d49e8ae 100644 --- a/src/main/java/appeng/worldgen/meteorite/StandardWorld.java +++ b/src/main/java/appeng/worldgen/meteorite/StandardWorld.java @@ -24,6 +24,7 @@ import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; import net.minecraft.world.World; import appeng.util.Platform; @@ -32,9 +33,9 @@ import appeng.util.Platform; public class StandardWorld implements IMeteoriteWorld { - private final World w; + private final IWorld w; - public StandardWorld( final World w ) + public StandardWorld( final IWorld w ) { this.w = w; } @@ -64,82 +65,76 @@ public class StandardWorld implements IMeteoriteWorld } @Override - public boolean isNether() - { - return !this.getWorld().provider.isNether(); + public boolean contains(BlockPos pos) { + return true; } @Override - public Block getBlock( final int x, final int y, final int z ) + public Block getBlock( BlockPos pos ) { - if( this.range( x, y, z ) ) + if( this.range( pos ) ) { - return this.getWorld().getBlockState( new BlockPos( x, y, z ) ).getBlock(); + return this.getWorld().getBlockState( new BlockPos( pos ) ).getBlock(); } return Platform.AIR_BLOCK; } @Override - public boolean canBlockSeeTheSky( final int x, final int y, final int z ) + public boolean canBlockSeeTheSky( BlockPos pos ) { - if( this.range( x, y, z ) ) + if( this.range( pos ) ) { - return this.getWorld().canBlockSeeSky( new BlockPos( x, y, z ) ); + return this.getWorld().canBlockSeeSky( new BlockPos( pos ) ); } return false; } @Override - public TileEntity getTileEntity( final int x, final int y, final int z ) + public TileEntity getTileEntity( BlockPos pos ) { - if( this.range( x, y, z ) ) + if( this.range( pos ) ) { - return this.getWorld().getTileEntity( new BlockPos( x, y, z ) ); + return this.getWorld().getTileEntity( new BlockPos( pos ) ); } return null; } @Override - public World getWorld() + public IWorld getWorld() { return this.w; } @Override - public void setBlock( final int x, final int y, final int z, final Block blk ) + public void setBlock( BlockPos pos, final BlockState blk ) { - if( this.range( x, y, z ) ) + if( this.range( pos ) ) { - this.getWorld().setBlockState( new BlockPos( x, y, z ), blk.getDefaultState() ); + // FIXME: Attempt at reducing impact of placing meteors by passing 16|32 here + this.getWorld().setBlockState( new BlockPos( pos ), blk, 16|32 ); } } - @Override - public void done() - { - - } - - public boolean range( final int x, final int y, final int z ) + public boolean range( BlockPos pos ) { return true; } @Override - public void setBlock( final int x, final int y, final int z, final BlockState state, final int l ) + public void setBlock( BlockPos pos, final BlockState state, final int l ) { - if( this.range( x, y, z ) ) + if( this.range( pos ) ) { - this.w.setBlockState( new BlockPos( x, y, z ), state, l ); + this.w.setBlockState( new BlockPos( pos ), state, l ); } } @Override - public BlockState getBlockState( final int x, final int y, final int z ) + public BlockState getBlockState( BlockPos pos ) { - if( this.range( x, y, z ) ) + if( this.range( pos ) ) { - return this.w.getBlockState( new BlockPos( x, y, z ) ); + return this.w.getBlockState( new BlockPos( pos ) ); } return Blocks.AIR.getDefaultState(); }