From 58c42f04bfa7bcf3bc77b017befaa765de87fc8d Mon Sep 17 00:00:00 2001 From: Runemoro Date: Sat, 7 Dec 2019 23:48:16 -0500 Subject: [PATCH] Add missing files --- .../dimdoors/commands/CommandSaveSchem.java | 49 ++++ .../dimdoors/item/RiftSignatureItem.java | 129 ++++++++++ .../dimdoors/item/WorldThreadArmorItem.java | 27 +++ .../rift/registry/RiftPlaceholder.java | 42 ++++ .../dimdoors/rift/targets/DefaultTargets.java | 19 ++ .../dimdoors/rift/targets/FluidTarget.java | 10 + .../dimdoors/rift/targets/LocalReference.java | 34 +++ .../dimdoors/rift/targets/MessageTarget.java | 34 +++ .../rift/targets/PocketExitMarker.java | 26 ++ .../rift/targets/PrivatePocketTarget.java | 94 ++++++++ .../rift/targets/RelativeReference.java | 39 +++ .../dimdev/dimdoors/rift/targets/Targets.java | 45 ++++ .../dimdoors/rift/targets/VirtualTarget.java | 64 +++++ .../dimdoors/tools/SchematicGenerator.java | 224 ++++++++++++++++++ .../org/dimdev/dimdoors/world/ModBiomes.java | 34 +++ .../world/gateways/BaseSchematicGateway.java | 72 ++++++ .../world/gateways/GatewayTwoPillars.java | 37 +++ .../dimdoors/world/gateways/LimboGateway.java | 33 +++ .../dimdoors/world/limbo/LimboDecay.java | 128 ++++++++++ .../world/limbo/LimboSkyProvider.java | 22 ++ .../world/pocketdimension/BlankBiome.java | 71 ++++++ 21 files changed, 1233 insertions(+) create mode 100644 src/main/java/org/dimdev/dimdoors/commands/CommandSaveSchem.java create mode 100644 src/main/java/org/dimdev/dimdoors/item/RiftSignatureItem.java create mode 100644 src/main/java/org/dimdev/dimdoors/item/WorldThreadArmorItem.java create mode 100644 src/main/java/org/dimdev/dimdoors/rift/registry/RiftPlaceholder.java create mode 100644 src/main/java/org/dimdev/dimdoors/rift/targets/DefaultTargets.java create mode 100644 src/main/java/org/dimdev/dimdoors/rift/targets/FluidTarget.java create mode 100644 src/main/java/org/dimdev/dimdoors/rift/targets/LocalReference.java create mode 100644 src/main/java/org/dimdev/dimdoors/rift/targets/MessageTarget.java create mode 100644 src/main/java/org/dimdev/dimdoors/rift/targets/PocketExitMarker.java create mode 100644 src/main/java/org/dimdev/dimdoors/rift/targets/PrivatePocketTarget.java create mode 100644 src/main/java/org/dimdev/dimdoors/rift/targets/RelativeReference.java create mode 100644 src/main/java/org/dimdev/dimdoors/rift/targets/Targets.java create mode 100644 src/main/java/org/dimdev/dimdoors/rift/targets/VirtualTarget.java create mode 100644 src/main/java/org/dimdev/dimdoors/tools/SchematicGenerator.java create mode 100644 src/main/java/org/dimdev/dimdoors/world/ModBiomes.java create mode 100644 src/main/java/org/dimdev/dimdoors/world/gateways/BaseSchematicGateway.java create mode 100644 src/main/java/org/dimdev/dimdoors/world/gateways/GatewayTwoPillars.java create mode 100644 src/main/java/org/dimdev/dimdoors/world/gateways/LimboGateway.java create mode 100644 src/main/java/org/dimdev/dimdoors/world/limbo/LimboDecay.java create mode 100644 src/main/java/org/dimdev/dimdoors/world/limbo/LimboSkyProvider.java create mode 100644 src/main/java/org/dimdev/dimdoors/world/pocketdimension/BlankBiome.java diff --git a/src/main/java/org/dimdev/dimdoors/commands/CommandSaveSchem.java b/src/main/java/org/dimdev/dimdoors/commands/CommandSaveSchem.java new file mode 100644 index 00000000..527896d9 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/commands/CommandSaveSchem.java @@ -0,0 +1,49 @@ +//package org.dimdev.dimdoors.commands; +// +//import net.minecraft.command.CommandBase; +//import net.minecraft.command.CommandException; +//import net.minecraft.command.ICommandSender; +//import net.minecraft.command.WrongUsageException; +//import net.minecraft.entity.player.EntityPlayerMP; +//import net.minecraft.server.MinecraftServer; +//import net.minecraft.util.math.Vec3i; +//import org.dimdev.util.schem.Schematic; +//import org.dimdev.dimdoors.pockets.SchematicHandler; +//import org.dimdev.pocketlib.Pocket; +//import org.dimdev.pocketlib.PocketRegistry; +//import org.dimdev.pocketlib.PocketWorldDimension; +// +//public class CommandSaveSchem extends CommandBase { +// +// @Override +// public String getName() { +// return "saveschem"; +// } +// +// @Override +// public String getUsage(ICommandSender sender) { +// return "commands.saveschem.usage"; +// } +// +// @Override +// public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException { +// EntityPlayerMP player = getCommandSenderAsPlayer(sender); +// +// if (args.length != 1) { +// throw new WrongUsageException("commands.saveschem.usage"); +// } +// +// if (!(player.world.dimension instanceof PocketWorldDimension)) +// throw new CommandException("commands.generic.dimdoors.not_in_pocket"); +// Pocket pocket = PocketRegistry.instance(player.dimension).getPocketAt(player.getPosition()); +// if (pocket == null) throw new CommandException("commands.generic.dimdoors.not_in_pocket"); +// +// int size = (pocket.getSize() + 1) * 16 - 1; +// Schematic schematic = Schematic.createFromWorld(player.world, pocket.getOrigin(), pocket.getOrigin().add(new Vec3i(size, size, size))); +// schematic.name = args[0]; +// schematic.author = player.getName(); +// +// SchematicHandler.INSTANCE.saveSchematicForEditing(schematic, args[0]); +// notifyCommandListener(sender, this, "commands.saveschem.success", args[0]); +// } +//} diff --git a/src/main/java/org/dimdev/dimdoors/item/RiftSignatureItem.java b/src/main/java/org/dimdev/dimdoors/item/RiftSignatureItem.java new file mode 100644 index 00000000..90f514bc --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/item/RiftSignatureItem.java @@ -0,0 +1,129 @@ +package org.dimdev.dimdoors.item; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.resources.I18n; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.sound.SoundCategory; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TextComponentTranslation; +import net.minecraft.world.World; +import org.dimdev.dimdoors.DimDoors; +import org.dimdev.dimdoors.block.ModBlocks; +import org.dimdev.dimdoors.rift.targets.RiftReference; +import org.dimdev.dimdoors.sound.ModSoundEvents; +import org.dimdev.dimdoors.tileentities.DetachedRiftBlockEntity; +import org.dimdev.util.Location; +import org.dimdev.util.RotatedLocation; + +import java.util.List; + +public class RiftSignatureItem extends Item { + public static final String ID = "rift_signature"; + + public RiftSignatureItem(Settings settings) { + setMaxStackSize(1); + setMaxDamage(1); + setCreativeTab(ModItemGroups.DIMENSIONAL_DOORS); + setTranslationKey(ID); + setRegistryName(new Identifier("dimdoors", ID)); + } + + @Environment(EnvType.CLIENT) + @Override + public boolean hasEffect(ItemStack stack) { + return stack.getTagCompound() != null && stack.getTagCompound().hasKey("destination"); + } + + @Override + public ActionResult onItemUse(PlayerEntity player, World world, BlockPos pos, Hand hand, Direction side, float hitX, float hitY, float hitZ) { + ItemStack stack = player.getHeldItem(hand); + pos = world.getBlockState(pos).getBlock().isReplaceable(world, pos) ? pos : pos.offset(side); + + // Fail if the player can't place a block there + if (!player.canPlayerEdit(pos, side.getOpposite(), stack)) { + return ActionResult.FAIL; + } + + if (world.isClient) { + return ActionResult.SUCCESS; + } + + RotatedLocation target = getSource(stack); + + if (target == null) { + // The link signature has not been used. Store its current target as the first location. + setSource(stack, new RotatedLocation(world, pos, player.rotationYaw, 0)); + player.sendStatusMessage(new TextComponentTranslation(getRegistryName() + ".stored"), true); + world.playSound(null, player.getPosition(), ModSoundEvents.RIFT_START, SoundCategory.BLOCKS, 0.6f, 1); + } else { + // Place a rift at the saved point + if (target.getBlockState().getBlock() != ModBlocks.DETACHED_RIFT) { + if (!target.getBlockState().getBlock().isReplaceable(world, ((Location) target).getPos())) { + DimDoors.sendTranslatedMessage(player, "tools.target_became_block"); + clearSource(stack); // TODO: But is this fair? It's a rather hidden way of unbinding your signature! + return ActionResult.FAIL; + } + World sourceWorld = ((Location) target).getWorld(); + sourceWorld.setBlockState(((Location) target).getPos(), ModBlocks.DETACHED_RIFT.getDefaultState()); + DetachedRiftBlockEntity rift1 = (DetachedRiftBlockEntity) target.getBlockEntity(); + rift1.setDestination(RiftReference.tryMakeRelative(target, new Location(world, pos))); + rift1.setTeleportTargetRotation(target.yaw, 0); // setting pitch to 0 because player is always facing down to place rift + rift1.register(); + } + + // Place a rift at the target point + world.setBlockState(pos, ModBlocks.DETACHED_RIFT.getDefaultState()); + DetachedRiftBlockEntity rift2 = (DetachedRiftBlockEntity) world.getBlockEntity(pos); + rift2.setDestination(RiftReference.tryMakeRelative(new Location(world, pos), target)); + rift2.setTeleportTargetRotation(player.rotationYaw, 0); + rift2.register(); + + stack.damageItem(1, player); // TODO: calculate damage based on position? + + clearSource(stack); + player.sendStatusMessage(new TextComponentTranslation(getRegistryName() + ".created"), true); + // null = send sound to the player too, we have to do this because this code is not run client-side + world.playSound(null, player.getPosition(), ModSoundEvents.RIFT_END, SoundCategory.BLOCKS, 0.6f, 1); + } + + return ActionResult.SUCCESS; + } + + public static void setSource(ItemStack itemStack, RotatedLocation destination) { + if (!itemStack.hasTagCompound()) itemStack.setTagCompound(new CompoundTag()); + itemStack.getTagCompound().put("destination", destination.serialize()); + } + + public static void clearSource(ItemStack itemStack) { + if (itemStack.hasTagCompound()) { + itemStack.getTagCompound().removeTag("destination"); + } + } + + public static RotatedLocation getSource(ItemStack itemStack) { + if (itemStack.hasTagCompound() && itemStack.getTagCompound().hasKey("destination")) { + RotatedLocation transform = RotatedLocation.deserialize(itemStack.getTagCompound().getCompoundTag("destination")); + return transform; + } else { + return null; + } + } + + @Override + @Environment(EnvType.CLIENT) + public void addInformation(ItemStack stack, World world, List tooltip, ITooltipFlag flag) { + RotatedLocation transform = getSource(stack); + if (transform != null) { + tooltip.add(I18n.format(I18n.format(getRegistryName() + ".bound.info", transform.getX(), transform.getY(), transform.getZ(), ((Location) transform).dim))); + } else { + tooltip.add(I18n.format(getRegistryName() + ".unbound.info")); + } + } +} diff --git a/src/main/java/org/dimdev/dimdoors/item/WorldThreadArmorItem.java b/src/main/java/org/dimdev/dimdoors/item/WorldThreadArmorItem.java new file mode 100644 index 00000000..8152bd22 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/item/WorldThreadArmorItem.java @@ -0,0 +1,27 @@ +package org.dimdev.dimdoors.item; + +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.init.SoundEvents; +import net.minecraft.item.ArmorItem; +import net.minecraft.item.ArmorMaterial; +import net.minecraft.item.ItemStack; +import net.minecraft.sound.SoundEvents; + +public class WorldThreadArmorItem extends ArmorItem { + public static final ArmorMaterial WOVEN_WORLD_THREAD = EnumHelper.addArmorMaterial( + "woven_world_thread", + "dimdoors:woven_world_thread", + 20, + new int[]{2, 3, 4, 5}, + 20, + SoundEvents.ITEM_ARMOR_EQUIP_GENERIC, + 1.0f) + .setRepairItem(new ItemStack(ModItems.WORLD_THREAD)); + + public WorldThreadArmorItem(String name, int renderIndex, EquipmentSlot equipmentSlot) { + super(WOVEN_WORLD_THREAD, renderIndex, equipmentSlot); + setRegistryName("dimdoors", name); + setTranslationKey(name); + setCreativeTab(ModItemGroups.DIMENSIONAL_DOORS); + } +} diff --git a/src/main/java/org/dimdev/dimdoors/rift/registry/RiftPlaceholder.java b/src/main/java/org/dimdev/dimdoors/rift/registry/RiftPlaceholder.java new file mode 100644 index 00000000..eb3cbb25 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/rift/registry/RiftPlaceholder.java @@ -0,0 +1,42 @@ +package org.dimdev.dimdoors.rift.registry; + +import net.minecraft.nbt.CompoundTag; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.dimdev.dimdoors.DimDoors; + +public class RiftPlaceholder extends Rift { // TODO: don't extend rift + private static final Logger LOGGER = LogManager.getLogger(); + + @Override + public void sourceGone(RegistryVertex source) {} + + @Override + public void targetGone(RegistryVertex target) {} + + @Override + public void sourceAdded(RegistryVertex source) {} + + @Override + public void targetAdded(RegistryVertex target) {} + + @Override + public void targetChanged(RegistryVertex target) {} + + @Override + public void markDirty() { + RiftRegistry.instance().markSubregistryDirty(dim); + } + + @Override + public void fromTag(CompoundTag nbt) { + LOGGER.error("Reading a rift placeholder from NBT!"); + super.fromTag(nbt); + } + + @Override + public CompoundTag toTag(CompoundTag nbt) { + LOGGER.error("Writing a rift placeholder from NBT!"); + return super.toTag(nbt); + } +} diff --git a/src/main/java/org/dimdev/dimdoors/rift/targets/DefaultTargets.java b/src/main/java/org/dimdev/dimdoors/rift/targets/DefaultTargets.java new file mode 100644 index 00000000..43373a96 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/rift/targets/DefaultTargets.java @@ -0,0 +1,19 @@ +package org.dimdev.dimdoors.rift.targets; + +import org.dimdev.util.InstanceMap; + +public final class DefaultTargets { + private static final InstanceMap DEFAULT_TARGETS = new InstanceMap(); + + public static T getDefaultTarget(Class type) { + if (DEFAULT_TARGETS.containsKey(type)) { + return DEFAULT_TARGETS.get(type); + } else { + throw new RuntimeException("No default target for " + type.getName() + " registered"); + } + } + + public static void registerDefaultTarget(Class type, U impl) { + DEFAULT_TARGETS.put(type, impl); + } +} diff --git a/src/main/java/org/dimdev/dimdoors/rift/targets/FluidTarget.java b/src/main/java/org/dimdev/dimdoors/rift/targets/FluidTarget.java new file mode 100644 index 00000000..063a6a2b --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/rift/targets/FluidTarget.java @@ -0,0 +1,10 @@ +package org.dimdev.dimdoors.rift.targets; + +import net.minecraft.fluid.Fluid; +import net.minecraft.util.math.Direction; + +public interface FluidTarget extends Target { + boolean addFluidFlow(Direction relativeFacing, Fluid fluid, int level); + + void subtractFluidFlow(Direction relativeFacing, Fluid fluid, int level); +} diff --git a/src/main/java/org/dimdev/dimdoors/rift/targets/LocalReference.java b/src/main/java/org/dimdev/dimdoors/rift/targets/LocalReference.java new file mode 100644 index 00000000..05075013 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/rift/targets/LocalReference.java @@ -0,0 +1,34 @@ +package org.dimdev.dimdoors.rift.targets; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.math.BlockPos; +import org.dimdev.annotatednbt.Saved; +import org.dimdev.util.Location; +import org.dimdev.annotatednbt.AnnotatedNbt; + +public class LocalReference extends RiftReference { + @Saved protected BlockPos target; + + public LocalReference(BlockPos target) { + this.target = target; + } + + @Override + public void fromTag(CompoundTag nbt) { + super.fromTag(nbt); + AnnotatedNbt.load(this, nbt); + } + + @Override + public CompoundTag toTag(CompoundTag nbt) { + nbt = super.toTag(nbt); + return AnnotatedNbt.serialize(this); + } + + @Override + public Location getReferencedLocation() { + return new Location(location.world, target); + } + + public BlockPos getTarget() {return target;} +} diff --git a/src/main/java/org/dimdev/dimdoors/rift/targets/MessageTarget.java b/src/main/java/org/dimdev/dimdoors/rift/targets/MessageTarget.java new file mode 100644 index 00000000..ad21d527 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/rift/targets/MessageTarget.java @@ -0,0 +1,34 @@ +package org.dimdev.dimdoors.rift.targets; + +import net.minecraft.entity.Entity; +import net.minecraft.text.TranslatableText; + +@SuppressWarnings("OverloadedVarargsMethod") +public class MessageTarget implements EntityTarget { + private Target forwardTo; + private String message; + private Object[] messageParams; + + public MessageTarget(Target forwardTo, String message, Object... messageParams) { + this.forwardTo = forwardTo; + this.message = message; + this.messageParams = messageParams; + } + + public MessageTarget(String message, Object... messageParams) { + this.message = message; + this.messageParams = messageParams; + } + + @Override + public boolean receiveEntity(Entity entity, float relativeYaw, float relativePitch) { + entity.sendMessage(new TranslatableText(message, messageParams)); + + if (forwardTo != null) { + forwardTo.as(Targets.ENTITY).receiveEntity(entity, relativeYaw, relativePitch); + return true; + } else { + return false; + } + } +} diff --git a/src/main/java/org/dimdev/dimdoors/rift/targets/PocketExitMarker.java b/src/main/java/org/dimdev/dimdoors/rift/targets/PocketExitMarker.java new file mode 100644 index 00000000..93faf1ea --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/rift/targets/PocketExitMarker.java @@ -0,0 +1,26 @@ +package org.dimdev.dimdoors.rift.targets; + +import net.minecraft.entity.Entity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.text.TranslatableText; + +public class PocketExitMarker extends VirtualTarget implements EntityTarget { + public PocketExitMarker() {} + + @Override + public void fromTag(CompoundTag nbt) { + super.fromTag(nbt); + } + + @Override + public CompoundTag toTag(CompoundTag nbt) { + nbt = super.toTag(nbt); + return nbt; + } + + @Override + public boolean receiveEntity(Entity entity, float relativeYaw, float relativePitch) { + entity.sendMessage(new TranslatableText("The exit of this dungeon has not been linked. If this is a normally generated pocket, please report this bug.")); + return false; + } +} diff --git a/src/main/java/org/dimdev/dimdoors/rift/targets/PrivatePocketTarget.java b/src/main/java/org/dimdev/dimdoors/rift/targets/PrivatePocketTarget.java new file mode 100644 index 00000000..1310af97 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/rift/targets/PrivatePocketTarget.java @@ -0,0 +1,94 @@ +package org.dimdev.dimdoors.rift.targets; + +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.Entity; +import net.minecraft.entity.ItemEntity; +import net.minecraft.item.DyeItem; +import net.minecraft.item.Item; +import net.minecraft.nbt.CompoundTag; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.dimdev.dimdoors.pockets.PocketGenerator; +import org.dimdev.dimdoors.rift.registry.RiftRegistry; +import org.dimdev.pocketlib.Pocket; +import org.dimdev.pocketlib.PrivatePocketData; +import org.dimdev.pocketlib.VirtualLocation; +import org.dimdev.util.EntityUtils; +import org.dimdev.util.Location; + +import java.util.UUID; + +public class PrivatePocketTarget extends VirtualTarget implements EntityTarget { + private static final Logger LOGGER = LogManager.getLogger(); + + public PrivatePocketTarget() {} + + @Override + public void fromTag(CompoundTag nbt) { super.fromTag(nbt); } + + @Override + public CompoundTag toTag(CompoundTag nbt) { + nbt = super.toTag(nbt); + return nbt; + } + + @Override + public boolean receiveEntity(Entity entity, float relativeYaw, float relativePitch) { + // TODO: make this recursive + UUID uuid = EntityUtils.getOwner(entity).getUuid(); + VirtualLocation virtualLocation = VirtualLocation.fromLocation(location); + if (uuid != null) { + Pocket pocket = PrivatePocketData.instance().getPrivatePocket(uuid); + if (pocket == null) { // generate the private pocket and get its entrances + // set to where the pocket was first created + pocket = PocketGenerator.generatePrivatePocket(virtualLocation != null ? + new VirtualLocation(virtualLocation.world, virtualLocation.x, virtualLocation.z, -1) : + null + ); + + PrivatePocketData.instance().setPrivatePocketID(uuid, pocket); + processEntity(pocket, RiftRegistry.instance().getPocketEntrance(pocket).getBlockEntity(), entity, uuid, relativeYaw, relativePitch); + return true; + } else { + Location destLoc = RiftRegistry.instance().getPrivatePocketEntrance(uuid); // get the last used entrances + if (destLoc == null) destLoc = RiftRegistry.instance().getPocketEntrance(pocket); // if there's none, then set the target to the main entrances + if (destLoc == null) { // if the pocket entrances is gone, then create a new private pocket + LOGGER.info("All entrances are gone, creating a new private pocket!"); + pocket = PocketGenerator.generatePrivatePocket(virtualLocation != null ? + new VirtualLocation(virtualLocation.world, virtualLocation.x, virtualLocation.z, -1) : + null + ); + + PrivatePocketData.instance().setPrivatePocketID(uuid, pocket); + destLoc = RiftRegistry.instance().getPocketEntrance(pocket); + } + + processEntity(pocket, destLoc.getBlockEntity(), entity, uuid, relativePitch, relativePitch); + return true; + } + } else { + return false; + } + } + + private void processEntity(Pocket pocket, BlockEntity BlockEntity, Entity entity, UUID uuid, float relativeYaw, float relativePitch) { + if (entity instanceof ItemEntity) { + Item item = ((ItemEntity) entity).getStack().getItem(); + + if (item instanceof DyeItem) { + pocket.addDye(EntityUtils.getOwner(entity), ((DyeItem) item).getColor()); + entity.remove(); + } else { + ((EntityTarget) BlockEntity).receiveEntity(entity, relativeYaw, relativePitch); + } + } else { + ((EntityTarget) BlockEntity).receiveEntity(entity, relativeYaw, relativePitch); + RiftRegistry.instance().setLastPrivatePocketExit(uuid, location); + } + } + + @Override + public float[] getColor() { + return new float[]{0, 1, 0, 1}; + } +} diff --git a/src/main/java/org/dimdev/dimdoors/rift/targets/RelativeReference.java b/src/main/java/org/dimdev/dimdoors/rift/targets/RelativeReference.java new file mode 100644 index 00000000..043f5e53 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/rift/targets/RelativeReference.java @@ -0,0 +1,39 @@ +package org.dimdev.dimdoors.rift.targets; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.math.Vec3i; +import org.dimdev.annotatednbt.AnnotatedNbt; +import org.dimdev.annotatednbt.Saved; +import org.dimdev.util.Location; + +public class RelativeReference extends RiftReference { + @Saved protected Vec3i offset; + + public RelativeReference() {} + + public RelativeReference(Vec3i offset) { + this.offset = offset; + } + + @Override + public void fromTag(CompoundTag nbt) { + super.fromTag(nbt); + AnnotatedNbt.load(this, nbt); + } + + @Override + public CompoundTag toTag(CompoundTag tag) { + tag = super.toTag(tag); + AnnotatedNbt.save(this, tag); + return tag; + } + + @Override + public Location getReferencedLocation() { + return new Location(location.world, location.pos.add(offset)); + } + + public Vec3i getOffset() { + return offset; + } +} diff --git a/src/main/java/org/dimdev/dimdoors/rift/targets/Targets.java b/src/main/java/org/dimdev/dimdoors/rift/targets/Targets.java new file mode 100644 index 00000000..0bb38c72 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/rift/targets/Targets.java @@ -0,0 +1,45 @@ +package org.dimdev.dimdoors.rift.targets; + +import net.minecraft.fluid.Fluid; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.math.Direction; + +// A list of the default targets provided by dimcore. Add your own in ModTargets +public final class Targets { + public static final Class ENTITY = EntityTarget.class; + public static final Class ITEM = ItemTarget.class; + public static final Class FLUID = FluidTarget.class; + public static final Class REDSTONE = RedstoneTarget.class; + + public static void registerDefaultTargets() { + DefaultTargets.registerDefaultTarget(ENTITY, (entity, relativeYaw, relativePitch) -> { + entity.sendMessage(new TranslatableText("rifts.unlinked")); + return false; + }); + DefaultTargets.registerDefaultTarget(ITEM, stack -> false); + + DefaultTargets.registerDefaultTarget(FLUID, new FluidTarget() { + @Override + public boolean addFluidFlow(Direction relativeFacing, Fluid fluid, int level) { + return false; + } + + @Override + public void subtractFluidFlow(Direction relativeFacing, Fluid fluid, int level) { + throw new RuntimeException("Subtracted fluid flow that was never accepted"); + } + }); + + DefaultTargets.registerDefaultTarget(REDSTONE, new RedstoneTarget() { + @Override + public boolean addRedstonePower(Direction relativeFacing, int strength) { + return false; + } + + @Override + public void subtractRedstonePower(Direction relativeFacing, int strength) { + throw new RuntimeException("Subtracted redstone that was never accepted"); + } + }); + } +} diff --git a/src/main/java/org/dimdev/dimdoors/rift/targets/VirtualTarget.java b/src/main/java/org/dimdev/dimdoors/rift/targets/VirtualTarget.java new file mode 100644 index 00000000..d3e79260 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/rift/targets/VirtualTarget.java @@ -0,0 +1,64 @@ +package org.dimdev.dimdoors.rift.targets; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import net.minecraft.nbt.CompoundTag; +import org.dimdev.util.Location; + +/** + * A target that is not an actual object in the game such as a block or a tile + * entity. Only virtual targets can be saved to NBT. + */ +public abstract class VirtualTarget implements Target { + + public static final BiMap> registry = HashBiMap.create(); + protected Location location; + + public static VirtualTarget readVirtualTargetNBT(CompoundTag nbt) { + String type = nbt.getString("type"); + Class destinationClass = registry.get(type); + if (destinationClass == null) throw new RuntimeException("Unknown type '" + type + "'."); + try { + VirtualTarget destination = destinationClass.newInstance(); + destination.fromTag(nbt); + return destination; + } catch (IllegalAccessException | InstantiationException e) { + throw new RuntimeException("The class registered for virtual target " + type + " must have a public no-args constructor and must not be abstract", e); + } + } + + public void fromTag(CompoundTag nbt) {} + + public CompoundTag toTag(CompoundTag nbt) { + String type = registry.inverse().get(getClass()); + if (type == null) throw new RuntimeException("No type has been registered for class" + getClass().getName()); + nbt.putString("type", type); + return nbt; + } + + public void register() {} + + public void unregister() {} + + public boolean shouldInvalidate(Location riftDeleted) { + return false; + } + + public float[] getColor() { + return new float[]{1, 0, 0, 1}; + } + + public boolean equals(Object o) { + return o instanceof VirtualTarget && + ((VirtualTarget) o).canEqual(this) && + (location == null ? ((VirtualTarget) o).location == null : ((Object) location).equals(((VirtualTarget) o).location)); + } + + protected boolean canEqual(Object other) {return other instanceof VirtualTarget;} + + public int hashCode() { + return 59 + (location == null ? 43 : location.hashCode()); + } + + public void setLocation(Location location) {this.location = location; } +} diff --git a/src/main/java/org/dimdev/dimdoors/tools/SchematicGenerator.java b/src/main/java/org/dimdev/dimdoors/tools/SchematicGenerator.java new file mode 100644 index 00000000..d4959c9e --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/tools/SchematicGenerator.java @@ -0,0 +1,224 @@ +//package org.dimdev.dimdoors.tools; +// +//import net.minecraft.block.DoorBlock; +//import net.minecraft.block.state.BlockState; +//import net.minecraft.item.DyeColor; +//import net.minecraft.nbt.CompressedStreamTools; +//import net.minecraft.nbt.CompoundTag; +//import org.dimdev.util.schem.Schematic; +//import org.dimdev.dimdoors.block.DimensionalDoorBlock; +//import org.dimdev.dimdoors.block.FabricBlock; +//import org.dimdev.dimdoors.block.AncientFabricBlock; +//import org.dimdev.dimdoors.block.ModBlocks; +//import org.dimdev.dimdoors.rift.targets.VirtualTarget; +//import org.dimdev.dimdoors.rift.targets.PocketEntranceMarker; +//import org.dimdev.dimdoors.rift.targets.PocketExitMarker; +//import org.dimdev.dimdoors.rift.targets.PrivatePocketExitTarget; +//import org.dimdev.dimdoors.rift.registry.LinkProperties; +//import org.dimdev.dimdoors.block.entity.EntranceRiftBlockEntity; +// +//import java.io.DataOutputStream; +//import java.io.File; +//import java.io.FileOutputStream; +//import java.io.IOException; +//import java.util.ArrayList; +//import java.util.Arrays; +//import java.util.Collections; +//import java.util.List; +// +//public final class SchematicGenerator { +// +// // Run "gradlew generatePocketSchematics" to generate the pocket schematics +// @SuppressWarnings("UseOfSystemOutOrSystemErr") +// public static void main(String... args) throws IOException { +// +// // Parse arguments +// File schematicDir; +// if (args.length > 1) { +// System.err.println("Too many arguments!"); +// return; +// } else if (args.length == 1) { +// schematicDir = new File(args[0]); +// if (!schematicDir.isDirectory()) { +// System.err.print("The directory " + args[0] + " couldn't be found!"); +// return; +// } +// } else { +// schematicDir = new File("schematics/"); +// } +// +// // Register blocks and tile entities to be able to run this without starting Minecraft +// Initializer.initialize(); +// +// // Generate the schematics +// List schematics = generatePocketSchematics(); +// +// // Save the schematics +// String[] saveFolders = {"public/", "private/", "blank/", "blank/", "blank/"}; +// int i = 0; +// for (Schematic schematic : schematics) { +// CompoundTag schematicNBT = schematic.saveToNBT(); +// File saveFile = new File(schematicDir, saveFolders[i++ % saveFolders.length] + schematic.name + ".schem"); +// saveFile.getParentFile().mkdirs(); +// DataOutputStream schematicDataStream = new DataOutputStream(new FileOutputStream(saveFile)); +// CompressedStreamTools.writeCompressed(schematicNBT, schematicDataStream); +// schematicDataStream.flush(); +// schematicDataStream.close(); +// } +// // TODO: also generate JSON files +// } +// +// public static List generatePocketSchematics() { +// List schematics = new ArrayList<>(); +// for (int pocketSize = 0; pocketSize < 8; pocketSize++) { // Changing to 8 to 16 would cause out of memory (256^3*4 bytes = 64MB/schematic) +// schematics.add(generateBlankWithDoor( +// "public_pocket", // base name +// pocketSize, // size +// ModBlocks.ANCIENT_FABRIC.getDefaultState(), // outer wall +// ModBlocks.BLACK_FABRIC.getDefaultState(), // inner wall +// ModBlocks.IRON_DIMENSIONAL_DOOR, // door +// PocketExitMarker.builder().build(),// exit rift destination +// LinkProperties.builder() +// .groups(Collections.singleton(1)) +// .linksRemaining(1) +// .entranceWeight(1) +// .floatingWeight(1) +// .build())); +// +// schematics.add(generateBlankWithDoor( +// "private_pocket", // base name +// pocketSize, // size +// ModBlocks.ANCIENT_FABRIC.getDefaultState().withProperty(AncientFabricBlock.COLOR, DyeColor.WHITE), // outer wall +// ModBlocks.BLACK_FABRIC.getDefaultState().withProperty(AncientFabricBlock.COLOR, DyeColor.WHITE), // inner wall +// ModBlocks.QUARTZ_DIMENSIONAL_DOOR, // door +// PrivatePocketExitTarget.builder().build(),// exit rift destination +// null)); +// +// schematics.add(generateBlank( +// "blank_pocket", +// pocketSize, +// ModBlocks.ANCIENT_FABRIC.getDefaultState(), +// ModBlocks.BLACK_FABRIC.getDefaultState())); +// +// schematics.add(generateFrame( +// "void_pocket", +// pocketSize, +// ModBlocks.BLACK_FABRIC.getDefaultState().withProperty(FabricBlock.COLOR, DyeColor.LIGHT_BLUE))); +// +// schematics.add(generateResizableFrame( +// "resizable_pocket", +// pocketSize, +// ModBlocks.BLACK_FABRIC.getDefaultState().withProperty(FabricBlock.COLOR, DyeColor.ORANGE))); +// } +// return schematics; +// } +// +// private static Schematic generateBlank(String baseName, int pocketSize, BlockState outerWall, BlockState innerWall) { +// short size = (short) ((pocketSize + 1) * 16 - 1); // -1 so that the door can be centered +// +// // Set schematic info +// Schematic schematic = new Schematic(baseName + "_" + pocketSize, "DimDoors", size, size, size); +// schematic.requiredMods = new String[]{"dimdoors"}; +// +// // Set block data +// for (int x = 0; x < size; x++) { +// for (int y = 0; y < size; y++) { +// for (int z = 0; z < size; z++) { +// int layer = Collections.min(Arrays.asList(x, y, z, size - 1 - x, size - 1 - y, size - 1 - z)); +// if (layer == 0) { +// schematic.setBlockState(x, y, z, outerWall); +// } else if (layer < 5) { +// schematic.setBlockState(x, y, z, innerWall); +// } +// } +// } +// } +// +// return schematic; +// } +// +// private static Schematic generateBlankWithDoor(String baseName, int pocketSize, BlockState outerWall, BlockState innerWall, DimensionalDoorBlock doorBlock, VirtualTarget exitDest, LinkProperties link) { +// short size = (short) ((pocketSize + 1) * 16 - 1); // -1 so that the door can be centered +// +// // Make the schematic +// Schematic schematic = generateBlank(baseName, pocketSize, outerWall, innerWall); +// +// // Add the door +// schematic.setBlockState((size - 1) / 2, 5, 4, doorBlock.getDefaultState().withProperty(DoorBlock.HALF, DoorBlock.EnumDoorHalf.LOWER)); +// schematic.setBlockState((size - 1) / 2, 6, 4, doorBlock.getDefaultState().withProperty(DoorBlock.HALF, DoorBlock.EnumDoorHalf.UPPER)); +// +// // Set the rift entities +// schematic.tileEntities = new ArrayList<>(); +// EntranceRiftBlockEntity rift = (EntranceRiftBlockEntity) doorBlock.createTileEntity(null, doorBlock.getDefaultState()); +// rift.setDestination(PocketEntranceMarker.builder() +// .ifDestination(exitDest) +// .build()); +// rift.setProperties(link); +// +// rift.setLeaveRiftOnBreak(true); +// CompoundTag tileNBT = rift.serializeNBT(); +// tileNBT.setInteger("x", (size - 1) / 2); +// tileNBT.setInteger("y", 5); +// tileNBT.setInteger("z", 4); +// schematic.tileEntities.add(tileNBT); +// +// return schematic; +// } +// +// private static Schematic generateFrame(String baseName, int chunkSize, BlockState frame) { +// short size = (short) ((chunkSize + 1) * 16 - 1); // -1 so that the door can be centered +// +// // Set schematic info +// Schematic schematic = new Schematic(baseName + "_" + chunkSize, "DimDoors", size, size, size); +// schematic.requiredMods = new String[]{"dimdoors"}; +// +// // Set block data +// for (int x = 0; x < size; x++) { +// for (int y = 0; y < size; y++) { +// for (int z = 0; z < size; z++) { +// int sides = 0; +// if (x == 0 || x == size - 1) sides++; +// if (y == 0 || y == size - 1) sides++; +// if (z == 0 || z == size - 1) sides++; +// +// if (sides >= 2) { +// schematic.setBlockState(x, y, z, frame); +// } +// } +// } +// } +// +// return schematic; +// } +// +// private static Schematic generateResizableFrame(String baseName, int chunkSize, BlockState frame) { +// short size = (short) ((chunkSize + 1) * 16); +// +// // Set schematic info +// Schematic schematic = new Schematic(baseName + "_" + chunkSize, "DimDoors", size, size, size); +// schematic.requiredMods = new String[]{"dimdoors"}; +// +// // Set block data +// for (int x = 0; x < size; x++) { +// for (int y = 0; y < size; y++) { +// for (int z = 0; z < size; z++) { +// int sides = 0; +// if (x % 16 == 0) sides++; +// if (y % 16 == 0) sides++; +// if (z % 16 == 0) sides++; +// int cubeSides = 3; +// int cubeSize = Math.max(x, Math.max(y, z)); +// if (cubeSize - x != 0) cubeSides--; +// if (cubeSize - y != 0) cubeSides--; +// if (cubeSize - z != 0) cubeSides--; +// +// if (sides >= 2 && cubeSides >= 2) { +// schematic.setBlockState(x, y, z, frame); +// } +// } +// } +// } +// +// return schematic; +// } +//} diff --git a/src/main/java/org/dimdev/dimdoors/world/ModBiomes.java b/src/main/java/org/dimdev/dimdoors/world/ModBiomes.java new file mode 100644 index 00000000..3d49f2fb --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/world/ModBiomes.java @@ -0,0 +1,34 @@ +package org.dimdev.dimdoors.world; + +import org.dimdev.dimdoors.world.limbo.BiomeLimbo; +import org.dimdev.dimdoors.world.pocketdimension.BlankBiome; +import net.minecraft.util.Identifier; +import net.minecraft.world.biome.Biome; +import net.minecraftforge.common.BiomeDictionary; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +public final class ModBiomes { + + public static final BiomeLimbo LIMBO = new BiomeLimbo(); + public static final BlankBiome WHITE_VOID = new BlankBiome(true, false); + public static final BlankBiome BLACK_VOID = new BlankBiome(false, false); + public static final BlankBiome DANGEROUS_BLACK_VOID = new BlankBiome(false, true); + + @SubscribeEvent + public static void registerBiomes(RegistryEvent.Register event) { + LIMBO.setRegistryName(new Identifier("dimdoors", "limbo")); + WHITE_VOID.setRegistryName(new Identifier("dimdoors", "white_void")); + BLACK_VOID.setRegistryName(new Identifier("dimdoors", "black_void")); + DANGEROUS_BLACK_VOID.setRegistryName(new Identifier("dimdoors", "dangerous_black_void")); + event.getRegistry().registerAll( + LIMBO, + WHITE_VOID, + BLACK_VOID, + DANGEROUS_BLACK_VOID); + BiomeDictionary.addTypes(LIMBO, BiomeDictionary.Type.VOID); + BiomeDictionary.addTypes(WHITE_VOID, BiomeDictionary.Type.VOID); + BiomeDictionary.addTypes(BLACK_VOID, BiomeDictionary.Type.VOID); + BiomeDictionary.addTypes(DANGEROUS_BLACK_VOID, BiomeDictionary.Type.VOID); + } +} diff --git a/src/main/java/org/dimdev/dimdoors/world/gateways/BaseSchematicGateway.java b/src/main/java/org/dimdev/dimdoors/world/gateways/BaseSchematicGateway.java new file mode 100644 index 00000000..977ebc35 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/world/gateways/BaseSchematicGateway.java @@ -0,0 +1,72 @@ +package org.dimdev.dimdoors.world.gateways; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.world.World; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.dimdev.dimdoors.DimDoors; +import org.dimdev.dimdoors.pockets.PocketTemplate; +import org.dimdev.util.schem.Schematic; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; + +public abstract class BaseSchematicGateway extends BaseGateway { + private static final Logger LOGGER = LogManager.getLogger(); + private Schematic schematic; + + public BaseSchematicGateway(String id) { + String schematicJarDirectory = "/assets/dimdoors/gateways/"; + + //Initialising the possible locations/formats for the schematic file + InputStream schematicStream = DimDoors.class.getResourceAsStream(schematicJarDirectory + id + ".schem"); + + //determine which location to load the schematic file from (and what format) + DataInputStream schematicDataStream = null; + boolean streamOpened = false; + if (schematicStream != null) { + schematicDataStream = new DataInputStream(schematicStream); + streamOpened = true; + } else { + LOGGER.warn("Schematic '" + id + "' was not found in the jar or config directory, neither with the .schem extension, nor with the .schematic extension."); + } + + CompoundTag schematicNBT; + schematic = null; + if (streamOpened) { + try { + schematicNBT = NbtIo.readCompressed(schematicDataStream); + schematic = Schematic.loadFromNBT(schematicNBT); + PocketTemplate.replacePlaceholders(schematic); + schematicDataStream.close(); + } catch (IOException ex) { + LOGGER.error("Schematic file for " + id + " could not be read as a valid schematic NBT file.", ex); + } finally { + try { + schematicDataStream.close(); + } catch (IOException ex) { + LOGGER.error("Error occured while closing schematicDataStream", ex); + } + } + } + } + + @Override + public void generate(World world, int x, int y, int z) { + schematic.place(world, x, y, z); + generateRandomBits(world, x, y, z); + } + + /** + * Generates randomized portions of the gateway structure (e.g. rubble, foliage) + * + * @param world - the world in which to generate the gateway + * @param x - the x-coordinate at which to center the gateway; usually where the door is placed + * @param y - the y-coordinate of the block on which the gateway may be built + * @param z - the z-coordinate at which to center the gateway; usually where the door is placed + */ + protected void generateRandomBits(World world, int x, int y, int z) { + } +} \ No newline at end of file diff --git a/src/main/java/org/dimdev/dimdoors/world/gateways/GatewayTwoPillars.java b/src/main/java/org/dimdev/dimdoors/world/gateways/GatewayTwoPillars.java new file mode 100644 index 00000000..83eb66c9 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/world/gateways/GatewayTwoPillars.java @@ -0,0 +1,37 @@ +package org.dimdev.dimdoors.world.gateways; + +import net.minecraft.block.BlockStoneBrick; +import net.minecraft.init.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class GatewayTwoPillars extends BaseSchematicGateway { + private static final int GATEWAY_RADIUS = 4; + + public GatewayTwoPillars() { + super("two_pillars"); + } + + @Override + protected void generateRandomBits(World world, int x, int y, int z) { + //Replace some of the ground around the gateway with bricks + for (int xc = -GATEWAY_RADIUS; xc <= GATEWAY_RADIUS; xc++) { + for (int zc = -GATEWAY_RADIUS; zc <= GATEWAY_RADIUS; zc++) { + //Check that the block is supported by an opaque block. + //This prevents us from building over a cliff, on the peak of a mountain, + //or the surface of the ocean or a frozen lake. + if (world.getBlockState(new BlockPos(x + xc, y - 1, z + zc)).getMaterial().isSolid()) { + //Randomly choose whether to place bricks or not. The math is designed so that the + //chances of placing a block decrease as we get farther from the gateway's center. + if (Math.abs(xc) + Math.abs(zc) < world.rand.nextInt(2) + 3) { + //Place Stone Bricks + world.setBlockState(new BlockPos(x + xc, y, z + zc), Blocks.STONEBRICK.getDefaultState()); + } else if (Math.abs(xc) + Math.abs(zc) < world.rand.nextInt(3) + 3) { + //Place Cracked Stone Bricks + world.setBlockState(new BlockPos(x + xc, y, z + zc), Blocks.STONEBRICK.getDefaultState().withProperty(BlockStoneBrick.VARIANT, BlockStoneBrick.EnumType.CRACKED)); + } + } + } + } + } +} diff --git a/src/main/java/org/dimdev/dimdoors/world/gateways/LimboGateway.java b/src/main/java/org/dimdev/dimdoors/world/gateways/LimboGateway.java new file mode 100644 index 00000000..5158cc6d --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/world/gateways/LimboGateway.java @@ -0,0 +1,33 @@ +package org.dimdev.dimdoors.world.gateways; + +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import org.dimdev.dimdoors.block.ModBlocks; +import org.dimdev.dimdoors.item.DimensionalDoorItem; +import org.dimdev.dimdoors.world.limbo.LimboDimension; + +public class LimboGateway extends BaseGateway { + @Override + public void generate(World world, int x, int y, int z) { + BlockState unravelledFabric = ModBlocks.UNRAVELLED_FABRIC.getDefaultState(); + // Build the gateway out of Unraveled Fabric. Since nearly all the blocks in Limbo are of + // that type, there is no point replacing the ground. + world.setBlockState(new BlockPos(x, y + 3, z + 1), unravelledFabric); + world.setBlockState(new BlockPos(x, y + 3, z - 1), unravelledFabric); + + // Build the columns around the door + world.setBlockState(new BlockPos(x, y + 2, z - 1), unravelledFabric); + world.setBlockState(new BlockPos(x, y + 2, z + 1), unravelledFabric); + world.setBlockState(new BlockPos(x, y + 1, z - 1), unravelledFabric); + world.setBlockState(new BlockPos(x, y + 1, z + 1), unravelledFabric); + + DimensionalDoorItem.placeDoor(world, new BlockPos(x, y + 1, z), Direction.NORTH, ModBlocks.DIMENSIONAL_PORTAL, false); + } + + @Override + public boolean isLocationValid(World world, int x, int y, int z) { + return world.dimension instanceof LimboDimension; + } +} diff --git a/src/main/java/org/dimdev/dimdoors/world/limbo/LimboDecay.java b/src/main/java/org/dimdev/dimdoors/world/limbo/LimboDecay.java new file mode 100644 index 00000000..29e55ea8 --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/world/limbo/LimboDecay.java @@ -0,0 +1,128 @@ +package org.dimdev.dimdoors.world.limbo; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.BlockWithEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.resource.Resource; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.World; +import org.dimdev.dimdoors.ModConfig; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +import static net.minecraft.block.Blocks.*; +import static org.dimdev.dimdoors.block.ModBlocks.*; + +/** + * Provides methods for applying Limbo decay. Limbo decay refers to the effect that most blocks placed in Limbo + * naturally change into stone, then cobble, then gravel, and finally Unraveled Fabric as time passes. + */ +public final class LimboDecay { + private static final Map DECAY_SEQUENCE = new HashMap<>(); + + static { // TODO: make this work on the server + try { + for (Resource resource : MinecraftClient.getInstance().getResourceManager().getAllResources(new Identifier("dimdoors:limbo_decay"))) { + Map decays = new Gson().fromJson(new InputStreamReader(resource.getInputStream()), new TypeToken>() {}.getType()); + + for (Map.Entry decay : decays.entrySet()) { + DECAY_SEQUENCE.put(Registry.BLOCK.get(new Identifier(decay.getKey())), Registry.BLOCK.get(new Identifier(decay.getValue()))); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static final Random random = new Random(); + private static Block[] blocksImmuneToDecay = null; + + public static Map getDecaySequence() { + return DECAY_SEQUENCE; + } + + public static Block[] getBlocksImmuneToDecay() { + if (blocksImmuneToDecay == null) { + blocksImmuneToDecay = new Block[]{ + UNRAVELLED_FABRIC, + ETERNAL_FABRIC, + DIMENSIONAL_PORTAL, + IRON_DIMENSIONAL_DOOR, + WOOD_DIMENSIONAL_DOOR, + DETACHED_RIFT, + GOLD_DOOR, + QUARTZ_DOOR, + GOLD_DIMENSIONAL_DOOR + }; + } + + return blocksImmuneToDecay; + } + + /** + * Checks the blocks orthogonally around a given location (presumably the location of an Unraveled Fabric block) + * and applies Limbo decay to them. This gives the impression that decay spreads outward from Unraveled Fabric. + */ + public static void applySpreadDecay(World world, BlockPos pos) { + //Check if we randomly apply decay spread or not. This can be used to moderate the frequency of + //full spread decay checks, which can also shift its performance impact on the game. + if (random.nextDouble() < ModConfig.LIMBO.decaySpreadChance) { + //Apply decay to the blocks above, below, and on all four sides. + //World.getBlockId() implements bounds checking, so we don't have to worry about reaching out of the world + decayBlock(world, pos.up()); + decayBlock(world, pos.down()); + decayBlock(world, pos.north()); + decayBlock(world, pos.south()); + decayBlock(world, pos.west()); + decayBlock(world, pos.east()); + } + } + + /** + * Checks if a block can be decayed and, if so, changes it to the next block ID along the decay sequence. + */ + private static boolean decayBlock(World world, BlockPos pos) { + BlockState state = world.getBlockState(pos); + + if (canDecayBlock(state, world, pos)) { + //Loop over the block IDs that decay can go through. + //Find an index matching the current blockID, if any. + + if (getDecaySequence().containsKey(state.getBlock())) { + Block decay = getDecaySequence().get(state.getBlock()); + world.setBlockState(pos, decay.getDefaultState()); + } else if (!state.isFullCube(world, pos)) { + world.setBlockState(pos, AIR.getDefaultState()); + } + return true; + } + + return false; + } + + /** + * Checks if a block can decay. We will not decay air, certain DD blocks, or containers. + */ + private static boolean canDecayBlock(BlockState state, World world, BlockPos pos) { + if (world.isAir(pos)) { + return false; + } + + for (int k = 0; k < getBlocksImmuneToDecay().length; k++) { + if (state.getBlock().equals(getBlocksImmuneToDecay()[k])) { + return false; + } + } + + return !(state.getBlock() instanceof BlockWithEntity); + } +} diff --git a/src/main/java/org/dimdev/dimdoors/world/limbo/LimboSkyProvider.java b/src/main/java/org/dimdev/dimdoors/world/limbo/LimboSkyProvider.java new file mode 100644 index 00000000..f8a2e3fe --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/world/limbo/LimboSkyProvider.java @@ -0,0 +1,22 @@ +package org.dimdev.dimdoors.world.limbo; + +import org.dimdev.dimdoors.world.CustomSkyProvider; +import net.minecraft.util.Identifier; + +/** + * Created by Jared Johnson on 1/24/2017. + */ +public class LimboSkyProvider extends CustomSkyProvider { + private static final Identifier moonRenderPath = new Identifier("dimdoors:textures/other/limbo_moon.png"); + private static final Identifier sunRenderPath = new Identifier("dimdoors:textures/other/limbo_sun.png"); + + @Override + public Identifier getMoonRenderPath() { + return moonRenderPath; + } + + @Override + public Identifier getSunRenderPath() { + return sunRenderPath; + } +} diff --git a/src/main/java/org/dimdev/dimdoors/world/pocketdimension/BlankBiome.java b/src/main/java/org/dimdev/dimdoors/world/pocketdimension/BlankBiome.java new file mode 100644 index 00000000..17eb057d --- /dev/null +++ b/src/main/java/org/dimdev/dimdoors/world/pocketdimension/BlankBiome.java @@ -0,0 +1,71 @@ +package org.dimdev.dimdoors.world.pocketdimension; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.init.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.chunk.ChunkPrimer; + +import java.util.Random; + +public class BlankBiome extends Biome { + + private final boolean white; + + public BlankBiome(boolean white, boolean monoliths) { + super(new BiomeProperties((monoliths ? "Dangerous " : "") + (white ? "White" : "Black") + " Void") + .setBaseHeight(0F) + .setHeightVariation(0F) + .setRainDisabled() + .setRainfall(0) + .setWaterColor(white ? 0xFFFFFF : 0x000055)); + this.white = white; + + topBlock = Blocks.AIR.getDefaultState(); + fillerBlock = Blocks.AIR.getDefaultState(); + + spawnableMonsterList.clear(); + spawnableCreatureList.clear(); + spawnableWaterCreatureList.clear(); + spawnableCaveCreatureList.clear(); + + flowers.clear(); + + decorator.extraTreeChance = 0; + decorator.flowersPerChunk = 0; + decorator.grassPerChunk = 0; + decorator.gravelPatchesPerChunk = 0; + decorator.sandPatchesPerChunk = 0; + decorator.clayPerChunk = 0; + decorator.generateFalls = false; + } + + // Some mods like RFTools rely on the decorator being present, so we need to create one even if we don't use it. + //@Override public BiomeDecorator createBiomeDecorator() { return null; } + + @Override + public void decorate(World world, Random rand, BlockPos pos) {} + + @Override + public void genTerrainBlocks(World world, Random rand, ChunkPrimer chunkPrimer, int x, int z, double noiseVal) {} + + @Override + @Environment(EnvType.CLIENT) + public int getSkyColorByTemp(float currentTemperature) { + return white ? 0xFCFCFC : 0x000000; // https://bugs.mojang.com/projects/MC/issues/MC-123703 + } + + @Override + @Environment(EnvType.CLIENT) + public int getGrassColorAtPos(BlockPos pos) { + return getModdedBiomeGrassColor(white ? 0xFFFFFF : 0x003300); + } + + @Override + @Environment(EnvType.CLIENT) + public int getFoliageColorAtPos(BlockPos pos) { + return getModdedBiomeFoliageColor(white ? 0xFFFFFF : 0x003300); + } +}