diff --git a/src/main/java/de/ellpeck/naturesaura/api/misc/IWorldData.java b/src/main/java/de/ellpeck/naturesaura/api/misc/IWorldData.java index 09da5c2c..7317c89e 100644 --- a/src/main/java/de/ellpeck/naturesaura/api/misc/IWorldData.java +++ b/src/main/java/de/ellpeck/naturesaura/api/misc/IWorldData.java @@ -2,11 +2,12 @@ package de.ellpeck.naturesaura.api.misc; import de.ellpeck.naturesaura.api.NaturesAuraAPI; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.server.MinecraftServer; import net.minecraft.world.DimensionType; import net.minecraft.world.World; -import net.minecraftforge.common.DimensionManager; import net.minecraftforge.common.capabilities.ICapabilityProvider; import net.minecraftforge.common.util.INBTSerializable; +import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.items.IItemHandlerModifiable; public interface IWorldData extends ICapabilityProvider, INBTSerializable { @@ -18,8 +19,9 @@ public interface IWorldData extends ICapabilityProvider, INBTSerializable TYPE = PropertyEnum.create("type", Type.class); + public static final PropertyEnum SHAPE = PropertyEnum.create("shape", EnumRailDirection.class, EnumRailDirection.NORTH_SOUTH, EnumRailDirection.EAST_WEST); + + public BlockDimensionRail() { + super(false); + ModRegistry.add(this); + } + + @Override + public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ) { + ItemStack stack = playerIn.getHeldItem(hand); + if (stack.getItem() == ModItems.RANGE_VISUALIZER) { + if (!worldIn.isRemote) { + Type type = state.getValue(TYPE); + BlockPos goalPos = this.getGoalCoords(worldIn, pos, type); + PacketHandler.sendTo(playerIn, + new PacketClient(0, type.goalDim, goalPos.getX(), goalPos.getY(), goalPos.getZ())); + } + return true; + } + return false; + } + + @Override + public void onMinecartPass(World world, EntityMinecart cart, BlockPos pos) { + if (world.isRemote) + return; + if (cart.isBeingRidden()) + return; + IBlockState state = world.getBlockState(pos); + Type type = state.getValue(TYPE); + if (!type.canUseHere(world.provider.getDimensionType())) + return; + BlockPos goalCoords = this.getGoalCoords(world, pos, type); + cart.changeDimension(type.goalDim, (newWorld, entity, yaw) -> + entity.moveToBlockPosAndAngles(goalCoords, yaw, entity.rotationPitch)); + } + + private BlockPos getGoalCoords(World world, BlockPos pos, Type type) { + MinecraftServer server = world.getMinecraftServer(); + if (type == Type.NETHER) { + // travel to the nether from the overworld + return new BlockPos(pos.getX() / 8, pos.getY() / 2, pos.getZ() / 8); + } else if (type == Type.END) { + // travel to the end from the overworld + WorldServer end = server.getWorld(type.goalDim); + return end.getSpawnCoordinate().up(8); + } else { + if (world.provider.getDimensionType() == DimensionType.NETHER) { + // travel to the overworld from the nether + return new BlockPos(pos.getX() * 8, pos.getY() * 2, pos.getZ() * 8); + } else { + // travel to the overworld from the end + World overworld = server.getWorld(type.goalDim); + return overworld.getTopSolidOrLiquidBlock(overworld.getSpawnPoint()); + } + } + } + + @Override + public IProperty getShapeProperty() { + return SHAPE; + } + + @Override + public boolean isFlexibleRail(IBlockAccess world, BlockPos pos) { + return false; + } + + @Override + public boolean canMakeSlopes(IBlockAccess world, BlockPos pos) { + return false; + } + + @Override + protected BlockStateContainer createBlockState() { + return new BlockStateContainer(this, TYPE, SHAPE); + } + + @Override + public int getMetaFromState(IBlockState state) { + int meta = 0; + meta |= state.getValue(SHAPE).getMetadata(); + meta |= state.getValue(TYPE).ordinal() << 1; + return meta; + } + + @Override + public IBlockState getStateFromMeta(int meta) { + return this.getDefaultState() + .withProperty(SHAPE, EnumRailDirection.byMetadata(meta & 1)) + .withProperty(TYPE, Type.values()[meta >> 1]); + } + + @Override + public String getBaseName() { + return "dimension_rail"; + } + + @Override + public void onPreInit(FMLPreInitializationEvent event) { + + } + + @Override + public void onInit(FMLInitializationEvent event) { + + } + + @Override + public void onPostInit(FMLPostInitializationEvent event) { + + } + + public enum Type implements IStringSerializable { + OVERWORLD("overworld", DimensionType.OVERWORLD, DimensionType.NETHER, DimensionType.THE_END), + NETHER("nether", DimensionType.NETHER, DimensionType.OVERWORLD), + END("end", DimensionType.THE_END, DimensionType.OVERWORLD); + + private final String name; + private final int goalDim; + private final DimensionType[] canUseDims; + + Type(String name, DimensionType goalDim, DimensionType... canUseDims) { + this.name = name; + this.goalDim = goalDim.getId(); + this.canUseDims = canUseDims; + } + + public boolean canUseHere(DimensionType dimension) { + for (DimensionType dim : this.canUseDims) + if (dim == dimension) + return true; + return false; + } + + @Override + public String getName() { + return this.name; + } + } +} diff --git a/src/main/java/de/ellpeck/naturesaura/blocks/ModBlocks.java b/src/main/java/de/ellpeck/naturesaura/blocks/ModBlocks.java index fe47f74b..f5283fd6 100644 --- a/src/main/java/de/ellpeck/naturesaura/blocks/ModBlocks.java +++ b/src/main/java/de/ellpeck/naturesaura/blocks/ModBlocks.java @@ -54,4 +54,5 @@ public final class ModBlocks { public static final Block FIREWORK_GENERATOR = new BlockFireworkGenerator(); public static final Block PROJECTILE_GENERATOR = new BlockProjectileGenerator(); public static final Block CHUNK_LOADER = ModConfig.enabledFeatures.chunkLoader ? new BlockChunkLoader() : null; + public static final Block DIMENSION_RAIL = new BlockDimensionRail(); } diff --git a/src/main/java/de/ellpeck/naturesaura/events/ClientEvents.java b/src/main/java/de/ellpeck/naturesaura/events/ClientEvents.java index 11fcbf35..8d054563 100644 --- a/src/main/java/de/ellpeck/naturesaura/events/ClientEvents.java +++ b/src/main/java/de/ellpeck/naturesaura/events/ClientEvents.java @@ -9,6 +9,7 @@ import de.ellpeck.naturesaura.api.aura.chunk.IAuraChunk; import de.ellpeck.naturesaura.api.aura.container.IAuraContainer; import de.ellpeck.naturesaura.api.aura.type.IAuraType; import de.ellpeck.naturesaura.api.render.IVisualizable; +import de.ellpeck.naturesaura.blocks.BlockDimensionRail; import de.ellpeck.naturesaura.blocks.tiles.TileEntityGratedChute; import de.ellpeck.naturesaura.blocks.tiles.TileEntityNatureAltar; import de.ellpeck.naturesaura.blocks.tiles.TileEntityRFConverter; @@ -120,10 +121,7 @@ public class ClientEvents { Minecraft mc = Minecraft.getMinecraft(); if (mc.world == null) { ParticleHandler.clearParticles(); - if (!ItemRangeVisualizer.VISUALIZED_BLOCKS.isEmpty()) - ItemRangeVisualizer.VISUALIZED_BLOCKS.clear(); - if (!ItemRangeVisualizer.VISUALIZED_ENTITIES.isEmpty()) - ItemRangeVisualizer.VISUALIZED_ENTITIES.clear(); + ItemRangeVisualizer.clear(); } else if (!mc.isGamePaused()) { if (mc.world.getTotalWorldTime() % 20 == 0) { mc.profiler.func_194340_a(() -> NaturesAura.MOD_ID + ":spawnExcessParticles"); @@ -156,44 +154,57 @@ public class ClientEvents { mc.profiler.endSection(); } + if (Helper.isHoldingItem(mc.player, ModItems.RANGE_VISUALIZER) && mc.world.getTotalWorldTime() % 5 == 0) { + NaturesAuraAPI.IInternalHooks inst = NaturesAuraAPI.instance(); + inst.setParticleSpawnRange(512); + inst.setParticleDepth(false); + for (BlockPos pos : ItemRangeVisualizer.VISUALIZED_RAILS.get(mc.world.provider.getDimension())) { + NaturesAuraAPI.instance().spawnMagicParticle( + pos.getX() + mc.world.rand.nextFloat(), + pos.getY() + mc.world.rand.nextFloat(), + pos.getZ() + mc.world.rand.nextFloat(), + 0F, 0F, 0F, 0xe0faff, mc.world.rand.nextFloat() * 5 + 1, 100, 0F, false, true); + } + inst.setParticleDepth(true); + inst.setParticleSpawnRange(32); + } + mc.profiler.func_194340_a(() -> NaturesAura.MOD_ID + ":updateParticles"); ParticleHandler.updateParticles(); mc.profiler.endSection(); - if (mc.player != null) { - if (Compat.baubles) { - IItemHandler baubles = BaublesApi.getBaublesHandler(mc.player); - for (int i = 0; i < baubles.getSlots(); i++) { - ItemStack slot = baubles.getStackInSlot(i); - if (!slot.isEmpty()) { - if (slot.getItem() instanceof ItemAuraCache) - heldCache = slot; - else if (slot.getItem() == ModItems.EYE) - heldEye = slot; - else if (slot.getItem() == ModItems.EYE_IMPROVED) - heldOcular = slot; - } - } - } - - for (int i = 0; i < mc.player.inventory.getSizeInventory(); i++) { - ItemStack slot = mc.player.inventory.getStackInSlot(i); + if (Compat.baubles) { + IItemHandler baubles = BaublesApi.getBaublesHandler(mc.player); + for (int i = 0; i < baubles.getSlots(); i++) { + ItemStack slot = baubles.getStackInSlot(i); if (!slot.isEmpty()) { if (slot.getItem() instanceof ItemAuraCache) heldCache = slot; - else if (slot.getItem() == ModItems.EYE && i <= 8) + else if (slot.getItem() == ModItems.EYE) heldEye = slot; else if (slot.getItem() == ModItems.EYE_IMPROVED) heldOcular = slot; } } + } - if (!heldOcular.isEmpty() && mc.world.getTotalWorldTime() % 20 == 0) { - SHOWING_EFFECTS.clear(); - Helper.getAuraChunksInArea(mc.world, mc.player.getPosition(), 100, - chunk -> chunk.getActiveEffectIcons(mc.player, SHOWING_EFFECTS)); + for (int i = 0; i < mc.player.inventory.getSizeInventory(); i++) { + ItemStack slot = mc.player.inventory.getStackInSlot(i); + if (!slot.isEmpty()) { + if (slot.getItem() instanceof ItemAuraCache) + heldCache = slot; + else if (slot.getItem() == ModItems.EYE && i <= 8) + heldEye = slot; + else if (slot.getItem() == ModItems.EYE_IMPROVED) + heldOcular = slot; } } + + if (!heldOcular.isEmpty() && mc.world.getTotalWorldTime() % 20 == 0) { + SHOWING_EFFECTS.clear(); + Helper.getAuraChunksInArea(mc.world, mc.player.getPosition(), 100, + chunk -> chunk.getActiveEffectIcons(mc.player, SHOWING_EFFECTS)); + } } } } @@ -243,33 +254,32 @@ public class ClientEvents { GL11.glPopMatrix(); } - if (mc.objectMouseOver != null) { - if (Helper.isHoldingItem(mc.player, ModItems.RANGE_VISUALIZER)) { - GL11.glPushMatrix(); - GL11.glDisable(GL11.GL_CULL_FACE); - GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); - GL11.glDisable(GL11.GL_TEXTURE_2D); - GL11.glEnable(GL11.GL_BLEND); - GL11.glBegin(GL11.GL_QUADS); - for (BlockPos pos : ItemRangeVisualizer.VISUALIZED_BLOCKS) { - if (!mc.world.isBlockLoaded(pos)) - continue; - IBlockState state = mc.world.getBlockState(pos); - Block block = state.getBlock(); - if (!(block instanceof IVisualizable)) - continue; - this.renderVisualize((IVisualizable) block, mc.world, pos); - } - for (Entity entity : ItemRangeVisualizer.VISUALIZED_ENTITIES) { - if (entity.isDead || !(entity instanceof IVisualizable)) - continue; - this.renderVisualize((IVisualizable) entity, mc.world, entity.getPosition()); - } - GL11.glEnd(); - GL11.glPopAttrib(); - GL11.glEnable(GL11.GL_CULL_FACE); - GL11.glPopMatrix(); + if (Helper.isHoldingItem(mc.player, ModItems.RANGE_VISUALIZER)) { + int dim = mc.world.provider.getDimension(); + GL11.glPushMatrix(); + GL11.glDisable(GL11.GL_CULL_FACE); + GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glEnable(GL11.GL_BLEND); + GL11.glBegin(GL11.GL_QUADS); + for (BlockPos pos : ItemRangeVisualizer.VISUALIZED_BLOCKS.get(dim)) { + if (!mc.world.isBlockLoaded(pos)) + continue; + IBlockState state = mc.world.getBlockState(pos); + Block block = state.getBlock(); + if (!(block instanceof IVisualizable)) + continue; + this.renderVisualize((IVisualizable) block, mc.world, pos); } + for (Entity entity : ItemRangeVisualizer.VISUALIZED_ENTITIES.get(dim)) { + if (entity.isDead || !(entity instanceof IVisualizable)) + continue; + this.renderVisualize((IVisualizable) entity, mc.world, entity.getPosition()); + } + GL11.glEnd(); + GL11.glPopAttrib(); + GL11.glEnable(GL11.GL_CULL_FACE); + GL11.glPopMatrix(); } GL11.glPopMatrix(); diff --git a/src/main/java/de/ellpeck/naturesaura/items/ItemRangeVisualizer.java b/src/main/java/de/ellpeck/naturesaura/items/ItemRangeVisualizer.java index e60b2a22..fa1bdcc6 100644 --- a/src/main/java/de/ellpeck/naturesaura/items/ItemRangeVisualizer.java +++ b/src/main/java/de/ellpeck/naturesaura/items/ItemRangeVisualizer.java @@ -1,6 +1,9 @@ package de.ellpeck.naturesaura.items; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ListMultimap; import de.ellpeck.naturesaura.api.render.IVisualizable; +import de.ellpeck.naturesaura.blocks.BlockDimensionRail; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.entity.Entity; @@ -20,8 +23,9 @@ import java.util.Set; public class ItemRangeVisualizer extends ItemImpl { - public static final Set VISUALIZED_BLOCKS = new HashSet<>(); - public static final Set VISUALIZED_ENTITIES = new HashSet<>(); + public static final ListMultimap VISUALIZED_BLOCKS = ArrayListMultimap.create(); + public static final ListMultimap VISUALIZED_ENTITIES = ArrayListMultimap.create(); + public static final ListMultimap VISUALIZED_RAILS = ArrayListMultimap.create(); public ItemRangeVisualizer() { super("range_visualizer"); @@ -33,16 +37,26 @@ public class ItemRangeVisualizer extends ItemImpl { IBlockState state = worldIn.getBlockState(pos); Block block = state.getBlock(); if (block instanceof IVisualizable) { + int dim = worldIn.provider.getDimension(); if (worldIn.isRemote) - if (VISUALIZED_BLOCKS.contains(pos)) - VISUALIZED_BLOCKS.remove(pos); + if (VISUALIZED_BLOCKS.containsEntry(dim, pos)) + VISUALIZED_BLOCKS.remove(dim, pos); else - VISUALIZED_BLOCKS.add(pos); + VISUALIZED_BLOCKS.put(dim, pos); return EnumActionResult.SUCCESS; } return EnumActionResult.PASS; } + public static void clear() { + if (!VISUALIZED_BLOCKS.isEmpty()) + VISUALIZED_BLOCKS.clear(); + if (!VISUALIZED_ENTITIES.isEmpty()) + VISUALIZED_ENTITIES.clear(); + if (!VISUALIZED_RAILS.isEmpty()) + VISUALIZED_RAILS.clear(); + } + @SubscribeEvent public void onInteract(PlayerInteractEvent.EntityInteractSpecific event) { ItemStack stack = event.getItemStack(); @@ -51,10 +65,11 @@ public class ItemRangeVisualizer extends ItemImpl { Entity entity = event.getTarget(); if (entity instanceof IVisualizable) { if (entity.world.isRemote) { - if (VISUALIZED_ENTITIES.contains(entity)) - VISUALIZED_ENTITIES.remove(entity); + int dim = entity.world.provider.getDimension(); + if (VISUALIZED_ENTITIES.containsEntry(dim, entity)) + VISUALIZED_ENTITIES.remove(dim, entity); else - VISUALIZED_ENTITIES.add(entity); + VISUALIZED_ENTITIES.put(dim, entity); } event.getEntityPlayer().swingArm(event.getHand()); event.setCancellationResult(EnumActionResult.SUCCESS); diff --git a/src/main/java/de/ellpeck/naturesaura/packet/PacketClient.java b/src/main/java/de/ellpeck/naturesaura/packet/PacketClient.java new file mode 100644 index 00000000..a1fe482d --- /dev/null +++ b/src/main/java/de/ellpeck/naturesaura/packet/PacketClient.java @@ -0,0 +1,69 @@ +package de.ellpeck.naturesaura.packet; + +import de.ellpeck.naturesaura.NaturesAura; +import de.ellpeck.naturesaura.items.ItemRangeVisualizer; +import io.netty.buffer.ByteBuf; +import net.minecraft.client.Minecraft; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.fml.common.network.simpleimpl.IMessage; +import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; +import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +public class PacketClient implements IMessage { + + private int type; + private int[] data; + + public PacketClient(int type, int... data) { + this.type = type; + this.data = data; + } + + public PacketClient() { + + } + + @Override + public void fromBytes(ByteBuf buf) { + this.type = buf.readByte(); + this.data = new int[buf.readByte()]; + for (int i = 0; i < this.data.length; i++) + this.data[i] = buf.readInt(); + } + + @Override + public void toBytes(ByteBuf buf) { + buf.writeByte(this.type); + buf.writeByte(this.data.length); + for (int i : this.data) + buf.writeInt(i); + } + + public static class Handler implements IMessageHandler { + + @Override + @SideOnly(Side.CLIENT) + public IMessage onMessage(PacketClient message, MessageContext ctx) { + NaturesAura.proxy.scheduleTask(() -> { + World world = Minecraft.getMinecraft().world; + if (world != null) { + switch (message.type) { + case 0: // dimension rail visualization + int goalDim = message.data[0]; + BlockPos goalPos = new BlockPos(message.data[1], message.data[2], message.data[3]); + if (ItemRangeVisualizer.VISUALIZED_RAILS.containsEntry(goalDim, goalPos)) + ItemRangeVisualizer.VISUALIZED_RAILS.remove(goalDim, goalPos); + else + ItemRangeVisualizer.VISUALIZED_RAILS.put(goalDim, goalPos); + break; + } + } + }); + + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/de/ellpeck/naturesaura/packet/PacketHandler.java b/src/main/java/de/ellpeck/naturesaura/packet/PacketHandler.java index b645da4f..753e22e1 100644 --- a/src/main/java/de/ellpeck/naturesaura/packet/PacketHandler.java +++ b/src/main/java/de/ellpeck/naturesaura/packet/PacketHandler.java @@ -19,6 +19,7 @@ public final class PacketHandler { network.registerMessage(PacketParticleStream.Handler.class, PacketParticleStream.class, 0, Side.CLIENT); network.registerMessage(PacketParticles.Handler.class, PacketParticles.class, 1, Side.CLIENT); network.registerMessage(PacketAuraChunk.Handler.class, PacketAuraChunk.class, 2, Side.CLIENT); + network.registerMessage(PacketClient.Handler.class, PacketClient.class, 3, Side.CLIENT); } public static void sendToAllLoaded(World world, BlockPos pos, IMessage message) { diff --git a/src/main/resources/assets/naturesaura/blockstates/dimension_rail.json b/src/main/resources/assets/naturesaura/blockstates/dimension_rail.json new file mode 100644 index 00000000..6db889a7 --- /dev/null +++ b/src/main/resources/assets/naturesaura/blockstates/dimension_rail.json @@ -0,0 +1,42 @@ +{ + "forge_marker": 1, + "defaults": { + "model": "minecraft:rail_flat", + "transform": "forge:default-block" + }, + "variants": { + "normal": [{}], + "inventory": [ + { + "model": "builtin/generated", + "textures": { + "layer0": "naturesaura:blocks/dimension_rail_overworld" + }, + "transform": "forge:default-item" + } + ], + "shape": { + "north_south": {}, + "east_west": { + "y": 90 + } + }, + "type": { + "overworld": { + "textures": { + "rail": "naturesaura:blocks/dimension_rail_overworld" + } + }, + "nether": { + "textures": { + "rail": "naturesaura:blocks/dimension_rail_nether" + } + }, + "end": { + "textures": { + "rail": "naturesaura:blocks/dimension_rail_end" + } + } + } + } +} \ No newline at end of file