Working on Spatial Stuff.

This commit is contained in:
Sebastian Hartte
2020-07-17 22:38:27 +02:00
parent 0c5c23e9ff
commit 15d4583c56
35 changed files with 860 additions and 693 deletions
@@ -10,6 +10,7 @@ import appeng.client.render.SimpleModelLoader;
import appeng.client.render.cablebus.CableBusModelLoader;
import appeng.client.render.effects.*;
import appeng.client.render.model.SkyCompassModel;
import appeng.client.render.spatial.SpatialPylonModel;
import appeng.client.render.tesr.InscriberTESR;
import appeng.client.render.tesr.SkyChestTESR;
import appeng.container.implementations.*;
@@ -245,7 +246,7 @@ public final class AppEngClient extends AppEngBase {
// FIXME FABRIC addBuiltInModel("biometric_card", BiometricCardModel::new);
// FIXME FABRIC addBuiltInModel("drive", DriveModel::new);
// FIXME FABRIC addBuiltInModel("color_applicator", ColorApplicatorModel::new);
// FIXME FABRIC addBuiltInModel("spatial_pylon", SpatialPylonModel::new);
addBuiltInModel("block/spatial_pylon", SpatialPylonModel::new);
// FIXME FABRIC addBuiltInModel("paint_splotches", PaintSplotchesModel::new);
// FIXME FABRIC addBuiltInModel("quantum_bridge_formed", QnbFormedModel::new);
// FIXME FABRIC addBuiltInModel("p2p_tunnel_frequency", P2PTunnelFrequencyModel::new);
@@ -45,26 +45,26 @@ public class SpatialIOPortScreen extends AEBaseScreen<SpatialIOPortContainer> {
@Override
public void drawFG(MatrixStack matrices, final int offsetX, final int offsetY, final int mouseX, final int mouseY) {
this.textRenderer.draw(matrices, GuiText.StoredPower.text() + ": "
+ Platform.formatPowerLong(this.handler.getCurrentPower(), false), 13, 21, 4210752);
this.textRenderer.draw(matrices, GuiText.StoredPower.withSuffix(": "
+ Platform.formatPowerLong(this.handler.getCurrentPower(), false)), 13, 21, 4210752);
this.textRenderer.draw(matrices,
GuiText.MaxPower.text() + ": " + Platform.formatPowerLong(this.handler.getMaxPower(), false), 13,
GuiText.MaxPower.withSuffix(": " + Platform.formatPowerLong(this.handler.getMaxPower(), false)), 13,
31, 4210752);
this.textRenderer.draw(matrices, GuiText.RequiredPower.text() + ": "
+ Platform.formatPowerLong(this.handler.getRequiredPower(), false), 13, 73, 4210752);
this.textRenderer.draw(matrices, GuiText.RequiredPower.withSuffix(": "
+ Platform.formatPowerLong(this.handler.getRequiredPower(), false)), 13, 73, 4210752);
this.textRenderer.draw(matrices,
GuiText.Efficiency.text() + ": " + (((float) this.handler.getEfficency()) / 100) + '%', 13, 83,
GuiText.Efficiency.withSuffix(": " + (((float) this.handler.getEfficency()) / 100) + '%'), 13, 83,
4210752);
this.textRenderer.draw(matrices, this.getGuiDisplayName(GuiText.SpatialIOPort.text()), 8, 6, 4210752);
this.textRenderer.draw(matrices, GuiText.inventory.text(), 8, this.backgroundHeight - 96, 4210752);
if (this.handler.xSize != 0 && this.handler.ySize != 0 && this.handler.zSize != 0) {
final String text = GuiText.SCSSize.text() + ": " + this.handler.xSize + "x" + this.handler.ySize
+ "x" + this.handler.zSize;
final Text text = GuiText.SCSSize.withSuffix(": " + this.handler.xSize + "x" + this.handler.ySize
+ "x" + this.handler.zSize);
this.textRenderer.draw(matrices, text, 13, 93, 4210752);
} else {
this.textRenderer.draw(matrices, GuiText.SCSSize.text() + ": " + GuiText.SCSInvalid.text(), 13, 93, 4210752);
this.textRenderer.draw(matrices, GuiText.SCSSize.withSuffix(": ").append(GuiText.SCSInvalid.text()), 13, 93, 4210752);
}
}
@@ -6,6 +6,7 @@ import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -17,6 +18,11 @@ import java.util.stream.Stream;
*/
public interface BasicUnbakedModel extends UnbakedModel {
@Override
default Collection<Identifier> getModelDependencies() {
return Collections.emptyList();
}
default Stream<SpriteIdentifier> getAdditionalTextures() {
return Stream.empty();
}
@@ -0,0 +1,244 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.client.render.spatial;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel;
import net.fabricmc.fabric.api.renderer.v1.render.RenderContext;
import net.fabricmc.fabric.api.rendering.data.v1.RenderAttachedBlockView;
import net.minecraft.block.BlockState;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.BakedQuad;
import net.minecraft.client.render.model.json.ModelOverrideList;
import net.minecraft.client.render.model.json.ModelTransformation;
import net.minecraft.client.texture.Sprite;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.BlockRenderView;
import appeng.client.render.cablebus.CubeBuilder;
import appeng.tile.spatial.SpatialPylonBlockEntity;
/**
* The baked model that will be used for rendering the spatial pylon.
*/
class SpatialPylonBakedModel implements BakedModel, FabricBakedModel {
private final Map<SpatialPylonTextureType, Sprite> textures;
SpatialPylonBakedModel(Map<SpatialPylonTextureType, Sprite> textures) {
this.textures = ImmutableMap.copyOf(textures);
}
@Override
public boolean isVanillaAdapter() {
return false;
}
@Override
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
int flags = getFlags(blockView, pos);
CubeBuilder builder = new CubeBuilder(context.getEmitter());
if (flags != 0) {
Direction ori = null;
int displayAxis = flags & SpatialPylonBlockEntity.DISPLAY_Z;
if (displayAxis == SpatialPylonBlockEntity.DISPLAY_X) {
ori = Direction.EAST;
if ((flags & SpatialPylonBlockEntity.DISPLAY_MIDDLE) == SpatialPylonBlockEntity.DISPLAY_END_MAX) {
builder.setUvRotation(Direction.SOUTH, 1);
builder.setUvRotation(Direction.NORTH, 1);
builder.setUvRotation(Direction.UP, 2);
builder.setUvRotation(Direction.DOWN, 2);
} else if ((flags & SpatialPylonBlockEntity.DISPLAY_MIDDLE) == SpatialPylonBlockEntity.DISPLAY_END_MIN) {
builder.setUvRotation(Direction.SOUTH, 2);
builder.setUvRotation(Direction.NORTH, 2);
builder.setUvRotation(Direction.UP, 1);
builder.setUvRotation(Direction.DOWN, 1);
} else {
builder.setUvRotation(Direction.SOUTH, 1);
builder.setUvRotation(Direction.NORTH, 1);
builder.setUvRotation(Direction.UP, 1);
builder.setUvRotation(Direction.DOWN, 1);
}
}
else if (displayAxis == SpatialPylonBlockEntity.DISPLAY_Y) {
ori = Direction.UP;
if ((flags & SpatialPylonBlockEntity.DISPLAY_MIDDLE) == SpatialPylonBlockEntity.DISPLAY_END_MAX) {
builder.setUvRotation(Direction.NORTH, 3);
builder.setUvRotation(Direction.SOUTH, 3);
builder.setUvRotation(Direction.EAST, 3);
builder.setUvRotation(Direction.WEST, 3);
}
}
else if (displayAxis == SpatialPylonBlockEntity.DISPLAY_Z) {
ori = Direction.NORTH;
if ((flags & SpatialPylonBlockEntity.DISPLAY_MIDDLE) == SpatialPylonBlockEntity.DISPLAY_END_MAX) {
builder.setUvRotation(Direction.EAST, 2);
builder.setUvRotation(Direction.WEST, 1);
} else if ((flags & SpatialPylonBlockEntity.DISPLAY_MIDDLE) == SpatialPylonBlockEntity.DISPLAY_END_MIN) {
builder.setUvRotation(Direction.EAST, 1);
builder.setUvRotation(Direction.WEST, 2);
builder.setUvRotation(Direction.UP, 3);
builder.setUvRotation(Direction.DOWN, 3);
} else {
builder.setUvRotation(Direction.EAST, 1);
builder.setUvRotation(Direction.WEST, 2);
}
}
builder.setTextures(this.textures.get(getTextureTypeFromSideOutside(flags, ori, Direction.UP)),
this.textures.get(getTextureTypeFromSideOutside(flags, ori, Direction.DOWN)),
this.textures.get(getTextureTypeFromSideOutside(flags, ori, Direction.NORTH)),
this.textures.get(getTextureTypeFromSideOutside(flags, ori, Direction.SOUTH)),
this.textures.get(getTextureTypeFromSideOutside(flags, ori, Direction.EAST)),
this.textures.get(getTextureTypeFromSideOutside(flags, ori, Direction.WEST)));
builder.addCube(0, 0, 0, 16, 16, 16);
if ((flags
& SpatialPylonBlockEntity.DISPLAY_POWERED_ENABLED) == SpatialPylonBlockEntity.DISPLAY_POWERED_ENABLED) {
builder.setRenderFullBright(true);
}
builder.setTextures(this.textures.get(getTextureTypeFromSideInside(flags, ori, Direction.UP)),
this.textures.get(getTextureTypeFromSideInside(flags, ori, Direction.DOWN)),
this.textures.get(getTextureTypeFromSideInside(flags, ori, Direction.NORTH)),
this.textures.get(getTextureTypeFromSideInside(flags, ori, Direction.SOUTH)),
this.textures.get(getTextureTypeFromSideInside(flags, ori, Direction.EAST)),
this.textures.get(getTextureTypeFromSideInside(flags, ori, Direction.WEST)));
builder.addCube(0, 0, 0, 16, 16, 16);
} else {
builder.setTexture(this.textures.get(SpatialPylonTextureType.BASE));
builder.addCube(0, 0, 0, 16, 16, 16);
builder.setTexture(this.textures.get(SpatialPylonTextureType.DIM));
builder.addCube(0, 0, 0, 16, 16, 16);
}
}
@Override
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
// Not intended to be used as an item model.
}
@Nonnull
@Override
public List<BakedQuad> getQuads(@Nullable BlockState state, @Nullable Direction side, @Nonnull Random rand) {
// Can only sensibly render using the new API
return Collections.emptyList();
}
private int getFlags(BlockRenderView blockRenderView, BlockPos pos) {
if (!(blockRenderView instanceof RenderAttachedBlockView)) {
return 0;
}
Object attachment = ((RenderAttachedBlockView) blockRenderView).getBlockEntityRenderAttachment(pos);
if (!(attachment instanceof Integer)) {
return 0;
}
return (Integer) attachment;
}
private static SpatialPylonTextureType getTextureTypeFromSideOutside(int flags, Direction ori, Direction dir) {
if (ori == dir || ori.getOpposite() == dir) {
return SpatialPylonTextureType.BASE;
}
if ((flags & SpatialPylonBlockEntity.DISPLAY_MIDDLE) == SpatialPylonBlockEntity.DISPLAY_MIDDLE) {
return SpatialPylonTextureType.BASE_SPANNED;
} else if ((flags & SpatialPylonBlockEntity.DISPLAY_MIDDLE) == SpatialPylonBlockEntity.DISPLAY_END_MIN) {
return SpatialPylonTextureType.BASE_END;
} else if ((flags & SpatialPylonBlockEntity.DISPLAY_MIDDLE) == SpatialPylonBlockEntity.DISPLAY_END_MAX) {
return SpatialPylonTextureType.BASE_END;
}
return SpatialPylonTextureType.BASE;
}
private static SpatialPylonTextureType getTextureTypeFromSideInside(int flags, Direction ori, Direction dir) {
final boolean good = (flags & SpatialPylonBlockEntity.DISPLAY_ENABLED) == SpatialPylonBlockEntity.DISPLAY_ENABLED;
if (ori == dir || ori.getOpposite() == dir) {
return good ? SpatialPylonTextureType.DIM : SpatialPylonTextureType.RED;
}
if ((flags & SpatialPylonBlockEntity.DISPLAY_MIDDLE) == SpatialPylonBlockEntity.DISPLAY_MIDDLE) {
return good ? SpatialPylonTextureType.DIM_SPANNED : SpatialPylonTextureType.RED_SPANNED;
} else if ((flags & SpatialPylonBlockEntity.DISPLAY_MIDDLE) == SpatialPylonBlockEntity.DISPLAY_END_MIN) {
return good ? SpatialPylonTextureType.DIM_END : SpatialPylonTextureType.RED_END;
} else if ((flags & SpatialPylonBlockEntity.DISPLAY_MIDDLE) == SpatialPylonBlockEntity.DISPLAY_END_MAX) {
return good ? SpatialPylonTextureType.DIM_END : SpatialPylonTextureType.RED_END;
}
return SpatialPylonTextureType.BASE;
}
@Override
public boolean isSideLit() {
return false;
}
@Override
public boolean useAmbientOcclusion() {
return true;
}
@Override
public boolean hasDepth() {
return false;
}
@Override
public boolean isBuiltin() {
return false;
}
@Override
public Sprite getSprite() {
return this.textures.get(SpatialPylonTextureType.DIM);
}
@Override
public ModelTransformation getTransformation() {
return ModelTransformation.NONE;
}
@Override
public ModelOverrideList getOverrides() {
return ModelOverrideList.EMPTY;
}
}
@@ -0,0 +1,62 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.client.render.spatial;
import appeng.client.render.BasicUnbakedModel;
import appeng.core.AppEng;
import net.minecraft.client.render.model.BakedModel;
import net.minecraft.client.render.model.ModelBakeSettings;
import net.minecraft.client.render.model.ModelLoader;
import net.minecraft.client.texture.Sprite;
import net.minecraft.client.texture.SpriteAtlasTexture;
import net.minecraft.client.util.SpriteIdentifier;
import net.minecraft.util.Identifier;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
public class SpatialPylonModel implements BasicUnbakedModel {
@Nullable
@Override
public BakedModel bake(ModelLoader loader, Function<SpriteIdentifier, Sprite> textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) {
Map<SpatialPylonTextureType, Sprite> textures = new EnumMap<>(SpatialPylonTextureType.class);
for (SpatialPylonTextureType type : SpatialPylonTextureType.values()) {
textures.put(type, textureGetter.apply(getTexturePath(type)));
}
return new SpatialPylonBakedModel(textures);
}
@Override
public Stream<SpriteIdentifier> getAdditionalTextures() {
return Arrays.stream(SpatialPylonTextureType.values()).map(SpatialPylonModel::getTexturePath);
}
private static SpriteIdentifier getTexturePath(SpatialPylonTextureType type) {
return new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEX,
new Identifier(AppEng.MOD_ID, "block/spatial_pylon/" + type.name().toLowerCase()));
}
}
@@ -0,0 +1,23 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.client.render.spatial;
enum SpatialPylonTextureType {
BASE, BASE_END, BASE_SPANNED, DIM, DIM_END, DIM_SPANNED, RED, RED_END, RED_SPANNED
}
+35
View File
@@ -33,8 +33,12 @@ import appeng.hooks.ToolItemHook;
import appeng.items.tools.NetworkToolItem;
import appeng.me.cache.*;
import appeng.mixins.CriteriaRegisterMixin;
import appeng.hooks.RegisterDimensionTypeCallback;
import appeng.recipes.handlers.*;
import appeng.server.AECommand;
import appeng.spatial.SpatialDimensionManager;
import appeng.spatial.StorageCellBiome;
import appeng.spatial.StorageChunkGenerator;
import appeng.worldgen.ChargedQuartzOreConfig;
import appeng.worldgen.ChargedQuartzOreFeature;
import appeng.worldgen.meteorite.MeteoriteStructure;
@@ -50,10 +54,12 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.recipe.Recipe;
import net.minecraft.recipe.RecipeType;
import net.minecraft.screen.ScreenHandlerType;
import net.minecraft.tag.BlockTags;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.World;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.chunk.StructureConfig;
import net.minecraft.world.gen.decorator.Decorator;
@@ -64,6 +70,7 @@ import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.FeatureConfig;
import net.minecraft.world.gen.feature.OreFeatureConfig;
import java.util.OptionalLong;
import java.util.function.Consumer;
public abstract class AppEngBase implements AppEng {
@@ -97,6 +104,7 @@ public abstract class AppEngBase implements AppEng {
registerRecipeSerializers();
registerWorldGen();
registerServerCommands();
registerDimension();
setupInternalRegistries();
@@ -368,4 +376,31 @@ public abstract class AppEngBase implements AppEng {
});
}
private void registerDimension() {
Registry.register(Registry.BIOME, AppEng.makeId("storage"), StorageCellBiome.INSTANCE);
Registry.register(Registry.CHUNK_GENERATOR, AppEng.makeId("storage"), StorageChunkGenerator.CODEC);
RegisterDimensionTypeCallback.EVENT.register(registryTracker -> {
registryTracker.addDimensionType(
SpatialDimensionManager.STORAGE_DIMENSION_TYPE,
new DimensionType(
OptionalLong.of(12000),
false,
false,
false,
false,
false,
false,
true,
true,
false,
256,
BlockTags.INFINIBURN_OVERWORLD.getId(),
0.5f
)
);
});
}
}
@@ -83,76 +83,76 @@ import static appeng.block.AEBaseBlock.defaultProps;
* Internal implementation for the API blocks
*/
public final class ApiBlocks implements IBlocks {
private IBlockDefinition quartzOre;
private IBlockDefinition quartzOreCharged;
private IBlockDefinition matrixFrame;
private IBlockDefinition quartzBlock;
private IBlockDefinition quartzPillar;
private IBlockDefinition chiseledQuartzBlock;
private IBlockDefinition quartzGlass;
private IBlockDefinition quartzVibrantGlass;
private IBlockDefinition quartzFixture;
private IBlockDefinition fluixBlock;
private IBlockDefinition skyStoneBlock;
private IBlockDefinition smoothSkyStoneBlock;
private IBlockDefinition skyStoneBrick;
private IBlockDefinition skyStoneSmallBrick;
private IBlockDefinition skyStoneChest;
private IBlockDefinition smoothSkyStoneChest;
private IBlockDefinition skyCompass;
private ITileDefinition grindstone;
private ITileDefinition crank;
private ITileDefinition inscriber;
private ITileDefinition wirelessAccessPoint;
private ITileDefinition charger;
private IBlockDefinition tinyTNT;
private ITileDefinition securityStation;
private ITileDefinition quantumRing;
private ITileDefinition quantumLink;
private ITileDefinition spatialPylon;
private ITileDefinition spatialIOPort;
private ITileDefinition multiPart;
private ITileDefinition controller;
private ITileDefinition drive;
private ITileDefinition chest;
private ITileDefinition iface;
private ITileDefinition fluidIface;
private ITileDefinition cellWorkbench;
private ITileDefinition iOPort;
private ITileDefinition condenser;
private ITileDefinition energyAcceptor;
private ITileDefinition vibrationChamber;
private ITileDefinition quartzGrowthAccelerator;
private ITileDefinition energyCell;
private ITileDefinition energyCellDense;
private ITileDefinition energyCellCreative;
private ITileDefinition craftingUnit;
private ITileDefinition craftingAccelerator;
private ITileDefinition craftingStorage1k;
private ITileDefinition craftingStorage4k;
private ITileDefinition craftingStorage16k;
private ITileDefinition craftingStorage64k;
private ITileDefinition craftingMonitor;
private ITileDefinition molecularAssembler;
private ITileDefinition lightDetector;
private ITileDefinition paint;
private IBlockDefinition skyStoneStairs;
private IBlockDefinition smoothSkyStoneStairs;
private IBlockDefinition skyStoneBrickStairs;
private IBlockDefinition skyStoneSmallBrickStairs;
private IBlockDefinition fluixStairs;
private IBlockDefinition quartzStairs;
private IBlockDefinition chiseledQuartzStairs;
private IBlockDefinition quartzPillarStairs;
private final IBlockDefinition quartzOre;
private final IBlockDefinition quartzOreCharged;
private final IBlockDefinition matrixFrame;
private final IBlockDefinition quartzBlock;
private final IBlockDefinition quartzPillar;
private final IBlockDefinition chiseledQuartzBlock;
private final IBlockDefinition quartzGlass;
private final IBlockDefinition quartzVibrantGlass;
private final IBlockDefinition quartzFixture;
private final IBlockDefinition fluixBlock;
private final IBlockDefinition skyStoneBlock;
private final IBlockDefinition smoothSkyStoneBlock;
private final IBlockDefinition skyStoneBrick;
private final IBlockDefinition skyStoneSmallBrick;
private final IBlockDefinition skyStoneChest;
private final IBlockDefinition smoothSkyStoneChest;
private final IBlockDefinition skyCompass;
private final ITileDefinition grindstone;
private final ITileDefinition crank;
private final ITileDefinition inscriber;
private final ITileDefinition wirelessAccessPoint;
private final ITileDefinition charger;
private final IBlockDefinition tinyTNT;
private final ITileDefinition securityStation;
private final ITileDefinition quantumRing;
private final ITileDefinition quantumLink;
private final ITileDefinition spatialPylon;
private final ITileDefinition spatialIOPort;
private final ITileDefinition multiPart;
private final ITileDefinition controller;
private final ITileDefinition drive;
private final ITileDefinition chest;
private final ITileDefinition iface;
private final ITileDefinition fluidIface;
private final ITileDefinition cellWorkbench;
private final ITileDefinition iOPort;
private final ITileDefinition condenser;
private final ITileDefinition energyAcceptor;
private final ITileDefinition vibrationChamber;
private final ITileDefinition quartzGrowthAccelerator;
private final ITileDefinition energyCell;
private final ITileDefinition energyCellDense;
private final ITileDefinition energyCellCreative;
private final ITileDefinition craftingUnit;
private final ITileDefinition craftingAccelerator;
private final ITileDefinition craftingStorage1k;
private final ITileDefinition craftingStorage4k;
private final ITileDefinition craftingStorage16k;
private final ITileDefinition craftingStorage64k;
private final ITileDefinition craftingMonitor;
private final ITileDefinition molecularAssembler;
private final ITileDefinition lightDetector;
private final ITileDefinition paint;
private final IBlockDefinition skyStoneStairs;
private final IBlockDefinition smoothSkyStoneStairs;
private final IBlockDefinition skyStoneBrickStairs;
private final IBlockDefinition skyStoneSmallBrickStairs;
private final IBlockDefinition fluixStairs;
private final IBlockDefinition quartzStairs;
private final IBlockDefinition chiseledQuartzStairs;
private final IBlockDefinition quartzPillarStairs;
private IBlockDefinition skyStoneSlab;
private IBlockDefinition smoothSkyStoneSlab;
private IBlockDefinition skyStoneBrickSlab;
private IBlockDefinition skyStoneSmallBrickSlab;
private IBlockDefinition fluixSlab;
private IBlockDefinition quartzSlab;
private IBlockDefinition chiseledQuartzSlab;
private IBlockDefinition quartzPillarSlab;
private final IBlockDefinition skyStoneSlab;
private final IBlockDefinition smoothSkyStoneSlab;
private final IBlockDefinition skyStoneBrickSlab;
private final IBlockDefinition skyStoneSmallBrickSlab;
private final IBlockDefinition fluixSlab;
private final IBlockDefinition quartzSlab;
private final IBlockDefinition chiseledQuartzSlab;
private final IBlockDefinition quartzPillarSlab;
private IBlockDefinition itemGen;
private IBlockDefinition chunkLoader;
@@ -47,6 +47,7 @@ import appeng.items.misc.PaintBallItemRendering;
import appeng.items.parts.FacadeItem;
import appeng.items.storage.BasicStorageCellItem;
import appeng.items.storage.CreativeStorageCellItem;
import appeng.items.storage.SpatialStorageCellItem;
import appeng.items.storage.ViewCellItem;
import appeng.items.tools.BiometricCardItem;
import appeng.items.tools.MemoryCardItem;
@@ -55,7 +56,6 @@ import appeng.items.tools.powered.*;
import appeng.items.tools.quartz.*;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.tool.attribute.v1.FabricToolTags;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.item.Item;
@@ -67,59 +67,59 @@ import java.util.function.Consumer;
* Internal implementation for the API items
*/
public final class ApiItems implements IItems {
private IItemDefinition certusQuartzAxe;
private IItemDefinition certusQuartzHoe;
private IItemDefinition certusQuartzShovel;
private IItemDefinition certusQuartzPick;
private IItemDefinition certusQuartzSword;
private IItemDefinition certusQuartzWrench;
private IItemDefinition certusQuartzKnife;
private final IItemDefinition certusQuartzAxe;
private final IItemDefinition certusQuartzHoe;
private final IItemDefinition certusQuartzShovel;
private final IItemDefinition certusQuartzPick;
private final IItemDefinition certusQuartzSword;
private final IItemDefinition certusQuartzWrench;
private final IItemDefinition certusQuartzKnife;
private IItemDefinition netherQuartzAxe;
private IItemDefinition netherQuartzHoe;
private IItemDefinition netherQuartzShovel;
private IItemDefinition netherQuartzPick;
private IItemDefinition netherQuartzSword;
private IItemDefinition netherQuartzWrench;
private IItemDefinition netherQuartzKnife;
private final IItemDefinition netherQuartzAxe;
private final IItemDefinition netherQuartzHoe;
private final IItemDefinition netherQuartzShovel;
private final IItemDefinition netherQuartzPick;
private final IItemDefinition netherQuartzSword;
private final IItemDefinition netherQuartzWrench;
private final IItemDefinition netherQuartzKnife;
private IItemDefinition entropyManipulator;
private IItemDefinition wirelessTerminal;
private IItemDefinition biometricCard;
private IItemDefinition chargedStaff;
private IItemDefinition massCannon;
private IItemDefinition memoryCard;
private IItemDefinition networkTool;
private IItemDefinition portableCell;
private final IItemDefinition entropyManipulator;
private final IItemDefinition wirelessTerminal;
private final IItemDefinition biometricCard;
private final IItemDefinition chargedStaff;
private final IItemDefinition massCannon;
private final IItemDefinition memoryCard;
private final IItemDefinition networkTool;
private final IItemDefinition portableCell;
private IItemDefinition cellCreative;
private IItemDefinition viewCell;
private final IItemDefinition cellCreative;
private final IItemDefinition viewCell;
private IItemDefinition cell1k;
private IItemDefinition cell4k;
private IItemDefinition cell16k;
private IItemDefinition cell64k;
private final IItemDefinition cell1k;
private final IItemDefinition cell4k;
private final IItemDefinition cell16k;
private final IItemDefinition cell64k;
private IItemDefinition fluidCell1k;
private IItemDefinition fluidCell4k;
private IItemDefinition fluidCell16k;
private IItemDefinition fluidCell64k;
private final IItemDefinition fluidCell1k;
private final IItemDefinition fluidCell4k;
private final IItemDefinition fluidCell16k;
private final IItemDefinition fluidCell64k;
private IItemDefinition spatialCell2;
private IItemDefinition spatialCell16;
private IItemDefinition spatialCell128;
private final IItemDefinition spatialCell2;
private final IItemDefinition spatialCell16;
private final IItemDefinition spatialCell128;
private IItemDefinition facade;
private IItemDefinition certusCrystalSeed;
private IItemDefinition fluixCrystalSeed;
private IItemDefinition netherQuartzSeed;
private final IItemDefinition facade;
private final IItemDefinition certusCrystalSeed;
private final IItemDefinition fluixCrystalSeed;
private final IItemDefinition netherQuartzSeed;
// rv1
private IItemDefinition encodedPattern;
private IItemDefinition colorApplicator;
private final IItemDefinition encodedPattern;
private final IItemDefinition colorApplicator;
private AEColoredItemDefinition coloredPaintBall;
private AEColoredItemDefinition coloredLumenPaintBall;
private final AEColoredItemDefinition coloredPaintBall;
private final AEColoredItemDefinition coloredLumenPaintBall;
// unsupported dev tools
private IItemDefinition toolEraser;
@@ -249,15 +249,15 @@ public final class ApiItems implements IItems {
.props(storageCellProps).build();
FeatureFactory spatialCells = registry.features(AEFeature.SPATIAL_IO);
// FIXME FABRIC this.spatialCell2 = spatialCells
// FIXME FABRIC .item("2_cubed_spatial_storage_cell", props -> new SpatialStorageCellItem(props, 2))
// FIXME FABRIC .props(storageCellProps).build();
// FIXME FABRIC this.spatialCell16 = spatialCells
// FIXME FABRIC .item("16_cubed_spatial_storage_cell", props -> new SpatialStorageCellItem(props, 16))
// FIXME FABRIC .props(storageCellProps).build();
// FIXME FABRIC this.spatialCell128 = spatialCells
// FIXME FABRIC .item("128_cubed_spatial_storage_cell", props -> new SpatialStorageCellItem(props, 128))
// FIXME FABRIC .props(storageCellProps).build();
this.spatialCell2 = spatialCells
.item("2_cubed_spatial_storage_cell", props -> new SpatialStorageCellItem(props, 2))
.props(storageCellProps).build();
this.spatialCell16 = spatialCells
.item("16_cubed_spatial_storage_cell", props -> new SpatialStorageCellItem(props, 16))
.props(storageCellProps).build();
this.spatialCell128 = spatialCells
.item("128_cubed_spatial_storage_cell", props -> new SpatialStorageCellItem(props, 128))
.props(storageCellProps).build();
this.facade = registry.item("facade", FacadeItem::new).features(AEFeature.FACADES).build();
@@ -0,0 +1,13 @@
package appeng.hooks;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.World;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.chunk.ChunkGenerator;
public interface DynamicDimensions {
ServerWorld addWorld(RegistryKey<World> worldId, RegistryKey<DimensionType> dimensionTypeId, ChunkGenerator chunkGenerator);
}
@@ -0,0 +1,17 @@
package appeng.hooks;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.util.registry.RegistryTracker;
public interface RegisterDimensionTypeCallback {
Event<RegisterDimensionTypeCallback> EVENT = EventFactory.createArrayBacked(RegisterDimensionTypeCallback.class, (listeners) -> (registryTracker) -> {
for (RegisterDimensionTypeCallback listener : listeners) {
listener.addDimensionTypes(registryTracker);
}
});
void addDimensionTypes(RegistryTracker.Modifiable registryTracker);
}
@@ -0,0 +1,154 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.items.storage;
import java.util.List;
import net.fabricmc.api.EnvType;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.LiteralText;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.text.Text;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.World;
import net.fabricmc.api.Environment;
import appeng.api.implementations.TransitionResult;
import appeng.api.implementations.items.ISpatialStorageCell;
import appeng.api.storage.ISpatialDimension;
import appeng.api.util.WorldCoord;
import appeng.core.AELog;
import appeng.core.localization.GuiText;
import appeng.items.AEBaseItem;
import appeng.spatial.SpatialDimensionManager;
import appeng.spatial.StorageHelper;
public class SpatialStorageCellItem extends AEBaseItem implements ISpatialStorageCell {
private static final String TAG_DIMENSION_ID = "dimension_id";
private final int maxRegion;
public SpatialStorageCellItem(Settings props, final int spatialScale) {
super(props);
this.maxRegion = spatialScale;
}
@Environment(EnvType.CLIENT)
@Override
public void appendTooltip(final ItemStack stack, final World world, final List<Text> lines,
final TooltipContext advancedTooltips) {
final RegistryKey<World> worldId = this.getStoredDimension(stack);
if (worldId == null) {
lines.add(GuiText.Unformatted.text().copy().formatted(Formatting.ITALIC));
lines.add(GuiText.SpatialCapacity.text(maxRegion, maxRegion, maxRegion));
} else {
SpatialDimensionManager.INSTANCE.addCellDimensionTooltip(worldId, lines);
}
if (advancedTooltips.isAdvanced()) {
if (worldId != null && worldId.getValue() != null) {
lines.add(new LiteralText("Dimension: " + worldId.getValue()));
}
}
}
@Override
public boolean isSpatialStorage(final ItemStack is) {
return true;
}
@Override
public int getMaxStoredDim(final ItemStack is) {
return this.maxRegion;
}
@Override
public RegistryKey<World> getStoredDimension(final ItemStack is) {
final CompoundTag c = is.getTag();
if (c != null && c.contains(TAG_DIMENSION_ID)) {
try {
Identifier worldId = new Identifier(c.getString(TAG_DIMENSION_ID));
return RegistryKey.of(Registry.DIMENSION, worldId);
} catch (Exception e) {
AELog.warn("Failed to retrieve storage cell dimension.", e);
}
}
return null;
}
@Override
public TransitionResult doSpatialTransition(final ItemStack is, final ServerWorld w, final WorldCoord min,
final WorldCoord max, int playerId) {
final int targetX = max.x - min.x - 1;
final int targetY = max.y - min.y - 1;
final int targetZ = max.z - min.z - 1;
final int maxSize = this.getMaxStoredDim(is);
final BlockPos targetSize = new BlockPos(targetX, targetY, targetZ);
ISpatialDimension manager = SpatialDimensionManager.INSTANCE;
RegistryKey<World> worldId = this.getStoredDimension(is);
if (worldId == null || manager.getWorld(worldId) == null) {
worldId = manager.createNewCellDimension(targetSize);
}
if (worldId == null) {
// Failed to create the dimension
return new TransitionResult(false, 0);
}
try {
if (manager.isCellDimension(worldId)) {
ServerWorld cellWorld = manager.getWorld(worldId);
BlockPos scale = manager.getCellDimensionSize(worldId);
if (scale.equals(targetSize)) {
if (targetX <= maxSize && targetY <= maxSize && targetZ <= maxSize) {
BlockPos offset = manager.getCellDimensionOrigin(worldId);
this.setStoredDimension(is, worldId);
StorageHelper.getInstance().swapRegions(w, min.x + 1, min.y + 1, min.z + 1, cellWorld,
offset.getX(), offset.getY(), offset.getZ(), targetX - 1, targetY - 1, targetZ - 1);
return new TransitionResult(true, 0);
}
}
}
return new TransitionResult(false, 0);
} finally {
// clean up newly created dimensions that failed transfer
if (manager.isCellDimension(worldId) && this.getStoredDimension(is) == null) {
manager.deleteCellDimension(worldId);
}
}
}
private void setStoredDimension(final ItemStack is, RegistryKey<World> worldId) {
final CompoundTag c = is.getOrCreateTag();
c.putString(TAG_DIMENSION_ID, worldId.getValue().toString());
}
}
@@ -0,0 +1,19 @@
package appeng.mixins;
import appeng.hooks.RegisterDimensionTypeCallback;
import net.minecraft.util.registry.RegistryTracker;
import net.minecraft.world.dimension.DimensionType;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(DimensionType.class)
public class DimensionTypeMixin {
@Inject(method="addRegistryDefaults", at=@At("TAIL"))
private static void addRegistryDefaults(RegistryTracker.Modifiable registryTracker, CallbackInfoReturnable<?> cir) {
RegisterDimensionTypeCallback.EVENT.invoker().addDimensionTypes(registryTracker);
}
}
@@ -0,0 +1,95 @@
package appeng.mixins;
import appeng.hooks.DynamicDimensions;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.WorldGenerationProgressListener;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.util.registry.RegistryTracker;
import net.minecraft.world.SaveProperties;
import net.minecraft.world.World;
import net.minecraft.world.border.WorldBorder;
import net.minecraft.world.border.WorldBorderListener;
import net.minecraft.world.dimension.DimensionOptions;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.gen.GeneratorOptions;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.level.ServerWorldProperties;
import net.minecraft.world.level.UnmodifiableLevelProperties;
import net.minecraft.world.level.storage.LevelStorage;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import java.util.Map;
import java.util.concurrent.Executor;
@Mixin(MinecraftServer.class)
public class MinecraftServerMixin implements DynamicDimensions {
@Shadow
private RegistryTracker.Modifiable dimensionTracker;
@Shadow
private Map<RegistryKey<World>, ServerWorld> worlds;
@Shadow
private SaveProperties saveProperties;
@Shadow
private Executor workerExecutor;
@Shadow
private LevelStorage.Session session;
public ServerWorld addWorld(RegistryKey<World> worldId, RegistryKey<DimensionType> dimensionTypeId, ChunkGenerator chunkGenerator) {
Preconditions.checkArgument(!worlds.containsKey(worldId), "World with id %s already exists.", worldId.getValue());
// Each worlds must have a corresponding dimension options, otherwise they will not be re-created on load
GeneratorOptions generatorOptions = this.saveProperties.getGeneratorOptions();
Preconditions.checkArgument(!generatorOptions.getDimensionMap().containsId(worldId.getValue()),
"Dimension config with id %s already exists.", worldId.getValue());
DimensionType dimensionType = dimensionTracker.getDimensionTypeRegistry().get(dimensionTypeId);
Preconditions.checkArgument(dimensionType != null, "dimensionTypeId %s is not registered", dimensionTypeId);
// Create dimension options with the given world-id and chunk generator
DimensionOptions dimensionOptions = new DimensionOptions(
() -> dimensionTracker.getDimensionTypeRegistry().get(dimensionTypeId),
chunkGenerator
);
ServerWorldProperties serverWorldProperties = this.saveProperties.getMainWorldProperties();
// This sucks a little, but during startup, the server will use the same listener for every world,
// but it is ultimately only stored in the chunk storage. So we retrieve it from the overworld to
// mirror the original code as much as possible
ServerWorld overworld = worlds.get(ServerWorld.OVERWORLD);
Preconditions.checkState(overworld != null, "Overworld does not exist!");
WorldGenerationProgressListener worldGenerationProgressListener = ((ThreadedAnvilChunkStorageAccessor) overworld.getChunkManager().threadedAnvilChunkStorage).getWorldGenerationProgressListener();
// Inherit seed + WorldBorder from overworld
long seed = overworld.getSeed();
WorldBorder worldBorder = overworld.getWorldBorder();
MinecraftServer self = (MinecraftServer) (Object) this;
UnmodifiableLevelProperties unmodifiableLevelProperties = new UnmodifiableLevelProperties(this.saveProperties, serverWorldProperties);
ServerWorld world = new ServerWorld(
self, this.workerExecutor, this.session, unmodifiableLevelProperties, worldId, dimensionTypeId, dimensionType, worldGenerationProgressListener, chunkGenerator, false, seed, ImmutableList.of(), false
);
worldBorder.addListener(new WorldBorderListener.WorldBorderSyncer(world.getWorldBorder()));
this.worlds.put(worldId, world);
// Adding it here will cause the world to be re-created on server restart
RegistryKey<DimensionOptions> dimOptKey = RegistryKey.of(Registry.DIMENSION_OPTIONS, worldId.getValue());
generatorOptions.getDimensionMap().add(dimOptKey, dimensionOptions);
generatorOptions.getDimensionMap().markLoaded(dimOptKey); // Otherwise it wont be saved
// Ensure the save properties are saved, or the world will potentially be lost on restart
this.session.method_27426(this.dimensionTracker, this.saveProperties, self.getPlayerManager().getUserData());
return world;
}
}
@@ -0,0 +1,14 @@
package appeng.mixins;
import net.minecraft.server.WorldGenerationProgressListener;
import net.minecraft.server.world.ThreadedAnvilChunkStorage;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ThreadedAnvilChunkStorage.class)
public interface ThreadedAnvilChunkStorageAccessor {
@Accessor
WorldGenerationProgressListener getWorldGenerationProgressListener();
}
@@ -0,0 +1,408 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.spatial;
import appeng.api.AEApi;
import appeng.api.movable.IMovableHandler;
import appeng.api.movable.IMovableRegistry;
import appeng.api.util.AEPartLocation;
import appeng.api.util.WorldCoord;
import appeng.core.AELog;
import appeng.core.worlddata.WorldData;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.network.packet.s2c.play.ChunkDataS2CPacket;
import net.minecraft.server.world.ServerChunkManager;
import net.minecraft.server.world.ServerTickScheduler;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Tickable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ScheduledTick;
import net.minecraft.world.TickScheduler;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkSection;
import net.minecraft.world.chunk.WorldChunk;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public class CachedPlane {
private final int x_size;
private final int z_size;
private final int cx_size;
private final int cz_size;
private final int x_offset;
private final int y_offset;
private final int z_offset;
private final int y_size;
private final WorldChunk[][] myChunks;
private final Column[][] myColumns;
private final List<BlockEntity> tiles = new ArrayList<>();
private final List<ScheduledTick<Block>> ticks = new ArrayList<>();
private final World world;
private final IMovableRegistry reg = AEApi.instance().registries().movable();
private final List<WorldCoord> updates = new ArrayList<>();
private int verticalBits;
private final BlockState matrixBlockState;
public CachedPlane(final World w, final int minX, final int minY, final int minZ, final int maxX, final int maxY,
final int maxZ) {
Block matrixFrameBlock = AEApi.instance().definitions().blocks().matrixFrame().maybeBlock().orElse(null);
if (matrixFrameBlock != null) {
this.matrixBlockState = matrixFrameBlock.getDefaultState();
} else {
this.matrixBlockState = null;
}
this.world = w;
this.x_size = maxX - minX + 1;
this.y_size = maxY - minY + 1;
this.z_size = maxZ - minZ + 1;
this.x_offset = minX;
this.y_offset = minY;
this.z_offset = minZ;
final int minCX = minX >> 4;
final int minCY = minY >> 4;
final int minCZ = minZ >> 4;
final int maxCX = maxX >> 4;
final int maxCY = maxY >> 4;
final int maxCZ = maxZ >> 4;
this.cx_size = maxCX - minCX + 1;
final int cy_size = maxCY - minCY + 1;
this.cz_size = maxCZ - minCZ + 1;
this.myChunks = new WorldChunk[this.cx_size][this.cz_size];
this.myColumns = new Column[this.x_size][this.z_size];
this.verticalBits = 0;
for (int cy = 0; cy < cy_size; cy++) {
this.verticalBits |= 1 << (minCY + cy);
}
for (int x = 0; x < this.x_size; x++) {
for (int z = 0; z < this.z_size; z++) {
this.myColumns[x][z] = new Column(w.getChunk((minX + x) >> 4, (minZ + z) >> 4), (minX + x) & 0xF,
(minZ + z) & 0xF, minCY, cy_size);
}
}
final IMovableRegistry mr = AEApi.instance().registries().movable();
for (int cx = 0; cx < this.cx_size; cx++) {
for (int cz = 0; cz < this.cz_size; cz++) {
final List<BlockPos> deadTiles = new ArrayList<>();
final WorldChunk c = w.getChunk(minCX + cx, minCZ + cz);
this.myChunks[cx][cz] = c;
Set<BlockPos> blockEntityPositions = c.getBlockEntityPositions();
for (BlockPos tePOS : blockEntityPositions) {
final BlockEntity te = c.getBlockEntity(tePOS);
if (te == null) {
continue;
}
if (tePOS.getX() >= minX && tePOS.getX() <= maxX && tePOS.getY() >= minY && tePOS.getY() <= maxY
&& tePOS.getZ() >= minZ && tePOS.getZ() <= maxZ) {
if (mr.askToMove(te)) {
this.tiles.add(te);
deadTiles.add(tePOS);
} else {
final BlockStorageData details = new BlockStorageData();
this.myColumns[tePOS.getX() - minX][tePOS.getZ() - minZ].fillData(tePOS.getY(), details);
// don't skip air, just let the code replace it...
if (details.state.isAir()) {
w.removeBlock(tePOS, false);
} else {
this.myColumns[tePOS.getX() - minX][tePOS.getZ() - minZ].setSkip(tePOS.getY());
}
}
}
}
for (final BlockPos cp : deadTiles) {
c.removeBlockEntity(cp);
}
final long gameTime = this.getWorld().getTime();
final TickScheduler<Block> pendingBlockTicks = this.getWorld().getBlockTickScheduler();
if (pendingBlockTicks instanceof ServerTickScheduler) {
List<ScheduledTick<Block>> pending = ((ServerTickScheduler<Block>) pendingBlockTicks)
.getScheduledTicksInChunk(c.getPos(), false, true);
for (final ScheduledTick<Block> entry : pending) {
final BlockPos tePOS = entry.pos;
if (tePOS.getX() >= minX && tePOS.getX() <= maxX && tePOS.getY() >= minY && tePOS.getY() <= maxY
&& tePOS.getZ() >= minZ && tePOS.getZ() <= maxZ) {
this.ticks.add(new ScheduledTick<>(tePOS, entry.getObject(),
entry.time - gameTime, entry.priority));
}
}
}
}
}
for (final BlockEntity te : this.tiles) {
try {
this.getWorld().blockEntities.remove(te);
if (te instanceof Tickable) {
this.getWorld().tickingBlockEntities.remove(te);
}
} catch (final Exception e) {
AELog.debug(e);
}
}
}
private IMovableHandler getHandler(final BlockEntity te) {
final IMovableRegistry mr = AEApi.instance().registries().movable();
return mr.getHandler(te);
}
void swap(final CachedPlane dst) {
final IMovableRegistry mr = AEApi.instance().registries().movable();
if (dst.x_size == this.x_size && dst.y_size == this.y_size && dst.z_size == this.z_size) {
AELog.info("Block Copy Scale: " + this.x_size + ", " + this.y_size + ", " + this.z_size);
long startTime = System.nanoTime();
final BlockStorageData aD = new BlockStorageData();
final BlockStorageData bD = new BlockStorageData();
for (int x = 0; x < this.x_size; x++) {
for (int z = 0; z < this.z_size; z++) {
final Column a = this.myColumns[x][z];
final Column b = dst.myColumns[x][z];
for (int y = 0; y < this.y_size; y++) {
final int src_y = y + this.y_offset;
final int dst_y = y + dst.y_offset;
if (a.doNotSkip(src_y) && b.doNotSkip(dst_y)) {
a.fillData(src_y, aD);
b.fillData(dst_y, bD);
a.setBlockState(src_y, bD);
b.setBlockState(dst_y, aD);
} else {
this.markForUpdate(x + this.x_offset, src_y, z + this.z_offset);
dst.markForUpdate(x + dst.x_offset, dst_y, z + dst.z_offset);
}
}
}
}
long endTime = System.nanoTime();
long duration = endTime - startTime;
AELog.info("Block Copy Time: " + duration);
for (final BlockEntity te : this.tiles) {
final BlockPos tePOS = te.getPos();
dst.addTile(tePOS.getX() - this.x_offset, tePOS.getY() - this.y_offset, tePOS.getZ() - this.z_offset,
te, this, mr);
}
for (final BlockEntity te : dst.tiles) {
final BlockPos tePOS = te.getPos();
this.addTile(tePOS.getX() - dst.x_offset, tePOS.getY() - dst.y_offset, tePOS.getZ() - dst.z_offset, te,
dst, mr);
}
for (final ScheduledTick<Block> entry : this.ticks) {
final BlockPos tePOS = entry.pos;
dst.addTick(tePOS.getX() - this.x_offset, tePOS.getY() - this.y_offset, tePOS.getZ() - this.z_offset,
entry);
}
for (final ScheduledTick<Block> entry : dst.ticks) {
final BlockPos tePOS = entry.pos;
this.addTick(tePOS.getX() - dst.x_offset, tePOS.getY() - dst.y_offset, tePOS.getZ() - dst.z_offset,
entry);
}
startTime = System.nanoTime();
this.updateChunks();
dst.updateChunks();
endTime = System.nanoTime();
duration = endTime - startTime;
AELog.info("Update Time: " + duration);
}
}
private void markForUpdate(final int x, final int y, final int z) {
this.updates.add(new WorldCoord(x, y, z));
for (final AEPartLocation d : AEPartLocation.SIDE_LOCATIONS) {
this.updates.add(new WorldCoord(x + d.xOffset, y + d.yOffset, z + d.zOffset));
}
}
private void addTick(final int x, final int y, final int z, final ScheduledTick<Block> entry) {
BlockPos where = new BlockPos(x + this.x_offset, y + this.y_offset, z + this.z_offset);
this.world.getBlockTickScheduler().schedule(where, entry.getObject(), (int) entry.time,
entry.priority);
}
private void addTile(final int x, final int y, final int z, final BlockEntity te,
final CachedPlane alternateDestination, final IMovableRegistry mr) {
try {
final Column c = this.myColumns[x][z];
if (c.doNotSkip(y + this.y_offset) || alternateDestination == null) {
final IMovableHandler handler = this.getHandler(te);
try {
handler.moveTile(te, this.world,
new BlockPos(x + this.x_offset, y + this.y_offset, z + this.z_offset));
} catch (final Throwable e) {
AELog.debug(e);
final BlockPos pos = new BlockPos(x, y, z);
// attempt recovery...
c.c.setBlockEntity(pos, te);
this.world.updateListeners(pos, this.world.getBlockState(pos), this.world.getBlockState(pos), z);
}
mr.doneMoving(te);
} else {
alternateDestination.addTile(x, y, z, te, null, mr);
}
} catch (final Throwable e) {
AELog.debug(e);
}
}
private void updateChunks() {
// update shit..
for (int x = 0; x < this.cx_size; x++) {
for (int z = 0; z < this.cz_size; z++) {
final WorldChunk c = this.myChunks[x][z];
// FIXME: Light shit
c.markDirty();
}
}
// send shit...
for (int x = 0; x < this.cx_size; x++) {
for (int z = 0; z < this.cz_size; z++) {
final WorldChunk c = this.myChunks[x][z];
WorldData.instance().compassData().service().updateArea((ServerWorld) this.getWorld(), c);
// FIXME this was sending chunks to players...
ChunkDataS2CPacket cdp = new ChunkDataS2CPacket(c, verticalBits, false);
((ServerChunkManager) world.getChunkManager()).threadedAnvilChunkStorage.getPlayersWatchingChunk(c.getPos(), false)
.forEach(spe -> spe.networkHandler.sendPacket(cdp));
}
}
// FIXME check if this makes any sense at all to send changes to players asap
ServerChunkManager serverChunkProvider = (ServerChunkManager) world.getChunkManager();
serverChunkProvider.tick(() -> false);
}
List<WorldCoord> getUpdates() {
return this.updates;
}
World getWorld() {
return this.world;
}
private static class BlockStorageData {
public BlockState state;
public int light;
}
private class Column {
private final int x;
private final int z;
private final Chunk c;
private List<Integer> skipThese = null;
public Column(final Chunk chunk, final int x, final int z, final int chunkY, final int chunkHeight) {
this.x = x;
this.z = z;
this.c = chunk;
final ChunkSection[] storage = this.c.getSectionArray();
// make sure storage exists before hand...
for (int ay = 0; ay < chunkHeight; ay++) {
final int by = (ay + chunkY);
ChunkSection extendedblockstorage = storage[by];
if (extendedblockstorage == null) {
extendedblockstorage = storage[by] = new ChunkSection(by << 4);
}
}
}
private void setBlockState(final int y, BlockStorageData data) {
if (data.state == CachedPlane.this.matrixBlockState) {
data.state = Blocks.AIR.getDefaultState();
}
final ChunkSection[] storage = this.c.getSectionArray();
final ChunkSection extendedBlockStorage = storage[y >> 4];
extendedBlockStorage.setBlockState(this.x, y & 15, this.z, data.state);
// FIXME extendedBlockStorage.setBlockLight( this.x, y & 15, this.z, data.light
// );
}
private void fillData(final int y, BlockStorageData data) {
final ChunkSection[] storage = this.c.getSectionArray();
final ChunkSection extendedblockstorage = storage[y >> 4];
data.state = extendedblockstorage.getBlockState(this.x, y & 15, this.z);
// FIXME data.light = extendedblockstorage.getBlockLight( this.x, y & 15, this.z
// );
}
private boolean doNotSkip(final int y) {
final ChunkSection[] storage = this.c.getSectionArray();
final ChunkSection extendedblockstorage = storage[y >> 4];
if (CachedPlane.this.reg
.isBlacklisted(extendedblockstorage.getBlockState(this.x, y & 15, this.z).getBlock())) {
return false;
}
return this.skipThese == null || !this.skipThese.contains(y);
}
private void setSkip(final int yCoord) {
if (this.skipThese == null) {
this.skipThese = new ArrayList<>();
}
this.skipThese.add(yCoord);
}
}
}
@@ -0,0 +1,26 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.spatial;
import net.minecraft.util.math.BlockPos;
public interface ISpatialVisitor {
void visit(BlockPos pos);
}
@@ -0,0 +1,70 @@
package appeng.spatial;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtHelper;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.PersistentState;
/**
* Helps with encoding and decoding the extra data we attach to each created
* storage dimension world as persistent state.
*/
public final class SpatialDimensionExtraData extends PersistentState {
/**
* ID of this data when it is attached to a world.
*/
public static final String ID = "ae2_spatial_info";
// Used to allow forward compatibility
private static final int CURRENT_FORMAT = 1;
private static final String TAG_FORMAT = "format";
private static final String TAG_SIZE = "size";
/**
* The storage size of this dimension. This is dicateted by the pylon structure
* size used to perform the first transfer into this dimension. Once it's set,
* it cannot be changed anymore.
*/
private BlockPos size = BlockPos.ORIGIN;
public SpatialDimensionExtraData() {
super(ID);
}
public SpatialDimensionExtraData(BlockPos size) {
super(ID);
this.size = size;
}
public BlockPos getSize() {
return size;
}
public void setSize(BlockPos size) {
this.size = size;
setDirty(true);
}
@Override
public void fromTag(CompoundTag tag) {
int version = tag.getInt(TAG_FORMAT);
if (version != CURRENT_FORMAT) {
// Currently no new format has been defined, as such anything but the current
// version is invalid
throw new IllegalStateException("Invalid AE2 spatial info version: " + version);
}
size = NbtHelper.toBlockPos(tag.getCompound(TAG_SIZE));
}
@Override
public CompoundTag toTag(CompoundTag tag) {
tag.putInt(TAG_FORMAT, CURRENT_FORMAT);
tag.put(TAG_SIZE, NbtHelper.fromBlockPos(size));
return tag;
}
}
@@ -0,0 +1,196 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2017, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.spatial;
import appeng.api.storage.ISpatialDimension;
import appeng.core.AELog;
import appeng.core.AppEng;
import appeng.core.localization.GuiText;
import appeng.hooks.DynamicDimensions;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.World;
import net.minecraft.world.dimension.DimensionType;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Locale;
public final class SpatialDimensionManager implements ISpatialDimension {
// A region file is 512x512 blocks (32x32 chunks),
// to avoid creating the 4 regions around 0,0,0,
// we move the origin to the middle of region 0,0
public static final BlockPos REGION_CENTER = new BlockPos(512 / 2, 64, 512 / 2);
public static final RegistryKey<DimensionType> STORAGE_DIMENSION_TYPE = RegistryKey.of(Registry.DIMENSION_TYPE_KEY, AppEng.makeId("storage_cell"));
public static final ISpatialDimension INSTANCE = new SpatialDimensionManager();
private static final String DIM_ID_PREFIX = "spatial_";
private SpatialDimensionManager() {
}
@Override
public ServerWorld getWorld(RegistryKey<World> cellDim) {
MinecraftServer server = getServer();
return server.getWorld(cellDim);
}
@Override
public RegistryKey<World> createNewCellDimension(BlockPos size) {
Identifier dimKey = findFreeDimensionId();
AELog.info("Allocating storage cell dimension '%s'", dimKey);
DynamicDimensions dynamicDimensions = (DynamicDimensions) getServer();
RegistryKey<World> worldId = RegistryKey.of(Registry.DIMENSION, dimKey);
ServerWorld world = dynamicDimensions.addWorld(worldId, STORAGE_DIMENSION_TYPE, StorageChunkGenerator.INSTANCE);
SpatialDimensionExtraData spatialExtraData = world.getPersistentStateManager().getOrCreate(SpatialDimensionExtraData::new, SpatialDimensionExtraData.ID);
spatialExtraData.setSize(size);
return worldId;
}
/**
* Tries finding the next free storage cell dimension ID based on the currently
* registered storage cell dimensions.
*/
private Identifier findFreeDimensionId() {
int maxId = 0;
for (RegistryKey<World> worldId : getServer().getWorldRegistryKeys()) {
Identifier regName = worldId.getValue();
if (regName == null || !AppEng.MOD_ID.equals(regName.getNamespace())) {
continue;
}
String path = regName.getPath();
if (!path.startsWith(DIM_ID_PREFIX)) {
continue;
}
try {
String numericIdPart = path.substring(DIM_ID_PREFIX.length());
maxId = Math.max(Integer.parseUnsignedInt(numericIdPart), maxId);
} catch (NumberFormatException e) {
AELog.warn("Unparsable storage cell dimension id '%s'", path, e);
}
}
++maxId;
return new Identifier(AppEng.MOD_ID, DIM_ID_PREFIX + maxId);
}
@Override
public void deleteCellDimension(RegistryKey<World> worldId) {
AELog.info("Unregistering storage cell dimension %s", worldId.getValue());
MinecraftServer server = getServer();
// FIXME FABRIC ServerWorld world = DimensionManager.getWorld(server, worldId, false, false);
// FIXME FABRIC if (world != null) {
// FIXME FABRIC DimensionManager.unloadWorld(world);
// FIXME FABRIC }
// FIXME FABRIC DimensionManager.unloadWorlds(server, true);
// FIXME FABRIC DimensionManager.unregisterDimension(worldId.getId());
throw new IllegalStateException();
}
@Override
public boolean isCellDimension(RegistryKey<World> worldId) {
Identifier id = worldId.getValue();
if (!id.getNamespace().equals(AppEng.MOD_ID)) {
return false; // World belongs to a different mod
}
if (!id.getPath().startsWith(DIM_ID_PREFIX)) {
return false;
}
// Check that the world has the right dimension type
ServerWorld world = getServer().getWorld(worldId);
if (world == null) {
return false; // Non-existent world
}
return world.getDimensionRegistryKey().equals(STORAGE_DIMENSION_TYPE);
}
@Override
public BlockPos getCellDimensionOrigin(RegistryKey<World> worldId) {
return REGION_CENTER;
}
@Override
public BlockPos getCellDimensionSize(RegistryKey<World> worldId) {
SpatialDimensionExtraData extraData = getExtraData(worldId);
return extraData != null ? extraData.getSize() : BlockPos.ORIGIN;
}
@Override
public void addCellDimensionTooltip(RegistryKey<World> worldId, List<Text> lines) {
// Check if the cell dimension type is even registered
Identifier registryName = worldId.getValue();
if (registryName == null || !AppEng.MOD_ID.equals(registryName.getNamespace())) {
return;
}
if (!registryName.getPath().startsWith(DIM_ID_PREFIX)) {
return;
}
// Add the actual stored size
BlockPos size = SpatialDimensionManager.INSTANCE.getCellDimensionSize(worldId);
lines.add(GuiText.StoredSize.text(size.getX(), size.getY(), size.getZ()));
// Add a serial number to allows players to keep different cells apart
int dimId;
try {
String numericIdPart = registryName.getPath().substring(DIM_ID_PREFIX.length());
dimId = Integer.parseUnsignedInt(numericIdPart);
} catch (NumberFormatException ignored) {
return;
}
// Try to make this a little more flavorful.
String serialNumber = String.format(Locale.ROOT, "SP-%04d", dimId);
lines.add(GuiText.SerialNumber.text(serialNumber));
}
@Nullable
private SpatialDimensionExtraData getExtraData(RegistryKey<World> worldId) {
ServerWorld world = getWorld(worldId);
if (world == null) {
return null;
}
return world.getPersistentStateManager().get(SpatialDimensionExtraData::new, SpatialDimensionExtraData.ID);
}
private static MinecraftServer getServer() {
return AppEng.instance().getServer();
}
}
@@ -0,0 +1,51 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.spatial;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeEffects;
import net.minecraft.world.gen.surfacebuilder.ConfiguredSurfaceBuilder;
import net.minecraft.world.gen.surfacebuilder.SurfaceBuilder;
public class StorageCellBiome extends Biome {
public static final StorageCellBiome INSTANCE = new StorageCellBiome();
public StorageCellBiome() {
super(new Biome.Settings().surfaceBuilder(new ConfiguredSurfaceBuilder<>(SurfaceBuilder.NOPE, SurfaceBuilder.STONE_CONFIG))
.precipitation(Precipitation.NONE).category(Category.NONE).depth(0).scale(1)
// Copied from the vanilla void biome
.temperature(0.5F).downfall(0.5F)
.effects(new BiomeEffects.Builder()
.waterColor(4159204)
.waterFogColor(329011)
.fogColor(0)
.build())
.parent(null));
}
@Override
@Environment(EnvType.CLIENT)
public int getSkyColor() {
return 0x111111;
}
}
@@ -0,0 +1,132 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.spatial;
import appeng.api.AEApi;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.BlockView;
import net.minecraft.world.ChunkRegion;
import net.minecraft.world.Heightmap;
import net.minecraft.world.WorldAccess;
import net.minecraft.world.biome.source.BiomeAccess;
import net.minecraft.world.biome.source.BiomeSource;
import net.minecraft.world.biome.source.FixedBiomeSource;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.StructureAccessor;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import net.minecraft.world.gen.chunk.StructuresConfig;
import net.minecraft.world.gen.chunk.VerticalBlockSample;
import java.util.Arrays;
import java.util.Collections;
import java.util.Optional;
public class StorageChunkGenerator extends ChunkGenerator {
private final VerticalBlockSample columnSample;
public static final StorageChunkGenerator INSTANCE = new StorageChunkGenerator();
public static final Codec<StorageChunkGenerator> CODEC = RecordCodecBuilder.create((instance) ->
instance.stable(INSTANCE));
private final BlockState defaultBlockState;
private StorageChunkGenerator() {
super(createBiomeProvider(), createSettings());
this.defaultBlockState = AEApi.instance().definitions().blocks().matrixFrame().block().getDefaultState();
// Vertical sample is mostly used for Feature generation, for those purposes we're all filled with matrix blocks
BlockState[] columnSample = new BlockState[256];
Arrays.fill(columnSample, this.defaultBlockState);
this.columnSample = new VerticalBlockSample(columnSample);
}
@Override
protected Codec<? extends ChunkGenerator> method_28506() {
return CODEC;
}
private static BiomeSource createBiomeProvider() {
return new FixedBiomeSource(StorageCellBiome.INSTANCE);
}
private static StructuresConfig createSettings() {
return new StructuresConfig(Optional.empty(), Collections.emptyMap());
}
@Override
public void buildSurface(ChunkRegion region, Chunk chunk) {
this.fillChunk(chunk);
chunk.setShouldSave(false);
}
private void fillChunk(Chunk chunk) {
BlockPos.Mutable mutPos = new BlockPos.Mutable();
for (int cx = 0; cx < 16; cx++) {
mutPos.setX(cx);
for (int cz = 0; cz < 16; cz++) {
// FIXME: It's likely a bad idea to fill Y in the inner-loop given the storage
// layout of chunks
mutPos.setZ(cz);
for (int cy = 0; cy < 256; cy++) {
mutPos.setY(cy);
chunk.setBlockState(mutPos, defaultBlockState, false);
}
}
}
}
@Override
public int getSeaLevel() {
return 0;
}
@Override
public ChunkGenerator withSeed(long seed) {
return this;
}
@Override
public void populateNoise(WorldAccess world, StructureAccessor accessor, Chunk chunk) {
}
@Override
public BlockView getColumnSample(int x, int z) {
return columnSample;
}
@Override
public int getHeight(int p_222529_1_, int p_222529_2_, Heightmap.Type heightmapType) {
return 0;
}
@Override
public void generateFeatures(ChunkRegion region, StructureAccessor accessor) {
}
@Override
public void carve(long seed, BiomeAccess access, Chunk chunk, GenerationStep.Carver carver) {
}
}
@@ -0,0 +1,244 @@
/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.spatial;
import appeng.api.AEApi;
import appeng.api.util.WorldCoord;
import appeng.core.AppEng;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.Entity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.RegistryKey;
import net.minecraft.world.World;
import net.minecraft.world.chunk.ChunkStatus;
import net.minecraft.world.dimension.DimensionType;
import java.util.ArrayList;
import java.util.List;
public class StorageHelper {
private static StorageHelper instance;
public static StorageHelper getInstance() {
if (instance == null) {
instance = new StorageHelper();
}
return instance;
}
/**
* Mostly from dimensional doors.. which mostly got it form X-Comp.
*
* @param entity to be teleported entity
* @param link destination
*
* @return teleported entity
*/
private Entity teleportEntity(Entity entity, final TelDestination link) {
final ServerWorld oldWorld;
final ServerWorld newWorld;
try {
oldWorld = (ServerWorld) entity.world;
newWorld = link.dim;
} catch (final Throwable e) {
return entity;
}
if (oldWorld == null) {
return entity;
}
if (newWorld == null) {
return entity;
}
if (newWorld == oldWorld) {
return entity;
}
// Are we riding something? Teleport it instead.
if (entity.hasVehicle()) {
return this.teleportEntity(entity.getVehicle(), link);
}
// Is something riding us? Handle it first.
final List<Entity> passengers = entity.getPassengerList();
final List<Entity> passengersOnOtherSide = new ArrayList<>(passengers.size());
for (Entity passenger : passengers) {
passenger.stopRiding();
passengersOnOtherSide.add(this.teleportEntity(passenger, link));
}
// We keep track of all so we can remount them on the other side.
// load the chunk!
newWorld.getChunkManager().getChunk(MathHelper.floor(link.x) >> 4, MathHelper.floor(link.z) >> 4,
ChunkStatus.FULL, true);
if (entity instanceof ServerPlayerEntity && link.dim.getDimensionRegistryKey().equals(SpatialDimensionManager.STORAGE_DIMENSION_TYPE)) {
AppEng.instance().getAdvancementTriggers().getSpatialExplorer().trigger((ServerPlayerEntity) entity);
}
// FIXME FABRIC new METeleporter(link)
float yaw = entity.yaw;
entity = entity.changeDimension(link.dim);
entity.yaw = yaw;
entity.refreshPositionAfterTeleport(link.x, link.y, link.z);
entity.setVelocity(0, 0, 0);
if (!passengersOnOtherSide.isEmpty()) {
for (Entity passanger : passengersOnOtherSide) {
passanger.startRiding(entity, true);
}
}
return entity;
}
private void transverseEdges(final int minX, final int minY, final int minZ, final int maxX, final int maxY,
final int maxZ, final ISpatialVisitor visitor) {
for (int y = minY; y < maxY; y++) {
for (int z = minZ; z < maxZ; z++) {
visitor.visit(new BlockPos(minX, y, z));
visitor.visit(new BlockPos(maxX, y, z));
}
}
for (int x = minX; x < maxX; x++) {
for (int z = minZ; z < maxZ; z++) {
visitor.visit(new BlockPos(x, minY, z));
visitor.visit(new BlockPos(x, maxY, z));
}
}
for (int x = minX; x < maxX; x++) {
for (int y = minY; y < maxY; y++) {
visitor.visit(new BlockPos(x, y, minZ));
visitor.visit(new BlockPos(x, y, maxZ));
}
}
}
public void swapRegions(final ServerWorld srcWorld, final int srcX, final int srcY, final int srcZ, final ServerWorld dstWorld,
final int dstX, final int dstY, final int dstZ, final int scaleX, final int scaleY, final int scaleZ) {
AEApi.instance().definitions().blocks().matrixFrame().maybeBlock()
.ifPresent(matrixFrameBlock -> this.transverseEdges(dstX - 1, dstY - 1, dstZ - 1, dstX + scaleX + 1,
dstY + scaleY + 1, dstZ + scaleZ + 1,
new WrapInMatrixFrame(matrixFrameBlock.getDefaultState(), dstWorld)));
final Box srcBox = new Box(srcX, srcY, srcZ, srcX + scaleX + 1, srcY + scaleY + 1,
srcZ + scaleZ + 1);
final Box dstBox = new Box(dstX, dstY, dstZ, dstX + scaleX + 1, dstY + scaleY + 1,
dstZ + scaleZ + 1);
final CachedPlane cDst = new CachedPlane(dstWorld, dstX, dstY, dstZ, dstX + scaleX, dstY + scaleY,
dstZ + scaleZ);
final CachedPlane cSrc = new CachedPlane(srcWorld, srcX, srcY, srcZ, srcX + scaleX, srcY + scaleY,
srcZ + scaleZ);
// do nearly all the work... swaps blocks, tiles, and block ticks
cSrc.swap(cDst);
final List<Entity> srcE = srcWorld.getEntitiesIncludingUngeneratedChunks(Entity.class, srcBox);
final List<Entity> dstE = dstWorld.getEntitiesIncludingUngeneratedChunks(Entity.class, dstBox);
for (final Entity e : dstE) {
this.teleportEntity(e, new TelDestination(srcWorld, srcBox, e.getX(), e.getY(), e.getZ(),
-dstX + srcX, -dstY + srcY, -dstZ + srcZ));
}
for (final Entity e : srcE) {
this.teleportEntity(e, new TelDestination(dstWorld, dstBox, e.getX(), e.getY(), e.getZ(),
-srcX + dstX, -srcY + dstY, -srcZ + dstZ));
}
for (final WorldCoord wc : cDst.getUpdates()) {
cSrc.getWorld().updateNeighborsAlways(wc.getPos(), Blocks.AIR);
}
for (final WorldCoord wc : cSrc.getUpdates()) {
cSrc.getWorld().updateNeighborsAlways(wc.getPos(), Blocks.AIR);
}
this.transverseEdges(srcX - 1, srcY - 1, srcZ - 1, srcX + scaleX + 1, srcY + scaleY + 1, srcZ + scaleZ + 1,
new TriggerUpdates(srcWorld));
this.transverseEdges(dstX - 1, dstY - 1, dstZ - 1, dstX + scaleX + 1, dstY + scaleY + 1, dstZ + scaleZ + 1,
new TriggerUpdates(dstWorld));
this.transverseEdges(srcX, srcY, srcZ, srcX + scaleX, srcY + scaleY, srcZ + scaleZ,
new TriggerUpdates(srcWorld));
this.transverseEdges(dstX, dstY, dstZ, dstX + scaleX, dstY + scaleY, dstZ + scaleZ,
new TriggerUpdates(dstWorld));
}
private static class TriggerUpdates implements ISpatialVisitor {
private final World dst;
public TriggerUpdates(final World dst2) {
this.dst = dst2;
}
@Override
public void visit(final BlockPos pos) {
final BlockState state = this.dst.getBlockState(pos);
final Block blk = state.getBlock();
blk.neighborUpdate(state, this.dst, pos, blk, pos, false);
}
}
private static class WrapInMatrixFrame implements ISpatialVisitor {
private final World dst;
private final BlockState state;
public WrapInMatrixFrame(final BlockState state, final World dst2) {
this.dst = dst2;
this.state = state;
}
@Override
public void visit(final BlockPos pos) {
this.dst.setBlockState(pos, this.state);
}
}
private static class TelDestination {
private final ServerWorld dim;
private final double x;
private final double y;
private final double z;
TelDestination(final ServerWorld dimension, final Box srcBox, final double x, final double y,
final double z, final int tileX, final int tileY, final int tileZ) {
this.dim = dimension;
this.x = Math.min(srcBox.maxX - 0.5, Math.max(srcBox.minX + 0.5, x + tileX));
this.y = Math.min(srcBox.maxY - 0.5, Math.max(srcBox.minY + 0.5, y + tileY));
this.z = Math.min(srcBox.maxZ - 0.5, Math.max(srcBox.minZ + 0.5, z + tileZ));
}
}
}
@@ -117,10 +117,10 @@ public class SpatialIOPortBlockEntity extends AENetworkInvBlockEntity implements
@Override
public Void call(final World world) throws Exception {
if (!(world instanceof ServerWorld)) {
if (!(this.world instanceof ServerWorld)) {
return null;
}
ServerWorld serverWorld = (ServerWorld) world;
ServerWorld serverWorld = (ServerWorld) this.world;
final ItemStack cell = this.inv.getInvStack(0);
if (this.isSpatialCell(cell) && this.inv.getInvStack(1).isEmpty()) {