From 1f9a053f685144e931a59ce619acaebf5e25a85f Mon Sep 17 00:00:00 2001 From: Nekojimi Date: Mon, 17 Oct 2022 01:11:57 +0100 Subject: [PATCH] WIP: prototype item teleportation to random dimensions, with safe landing. --- .../dimensionwalker/DimensionwalkerItem.java | 64 ++++++++++ .../dimensionwalker/DimensionwalkerMod.java | 69 +++++++++++ .../DimensionwalkerTeleporter.java | 115 ++++++++++++++++++ .../moe/nekojimi/dimensionwalker/Peachy.java | 9 ++ 4 files changed, 257 insertions(+) create mode 100644 src/main/java/moe/nekojimi/dimensionwalker/DimensionwalkerItem.java create mode 100644 src/main/java/moe/nekojimi/dimensionwalker/DimensionwalkerMod.java create mode 100644 src/main/java/moe/nekojimi/dimensionwalker/DimensionwalkerTeleporter.java create mode 100644 src/main/java/moe/nekojimi/dimensionwalker/Peachy.java diff --git a/src/main/java/moe/nekojimi/dimensionwalker/DimensionwalkerItem.java b/src/main/java/moe/nekojimi/dimensionwalker/DimensionwalkerItem.java new file mode 100644 index 0000000..1ff777d --- /dev/null +++ b/src/main/java/moe/nekojimi/dimensionwalker/DimensionwalkerItem.java @@ -0,0 +1,64 @@ +package moe.nekojimi.dimensionwalker; + +import com.mojang.logging.LogUtils; +import net.minecraft.client.renderer.item.ItemProperties; +import net.minecraft.core.Registry; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.commands.TeleportCommand; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.NetherPortalBlock; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.List; +import java.util.Collections; +import java.util.Random; +import java.util.logging.Logger; +import java.util.stream.StreamSupport; + +public class DimensionwalkerItem extends Item +{ + private static DeferredRegister DIMENSION_REGISTER = DeferredRegister.create(Registry.DIMENSION_REGISTRY, DimensionwalkerMod.MODID); + + private static final org.slf4j.Logger LOGGER = LogUtils.getLogger(); + + public DimensionwalkerItem() { + super(new Item.Properties().tab(CreativeModeTab.TAB_TOOLS)); + } + + @Override + public @NotNull InteractionResultHolder use(Level level, @NotNull Player player, @NotNull InteractionHand hand) + { + if (!level.isClientSide()) + { + MinecraftServer server = level.getServer(); + if (server != null) + { + Iterable allLevels = server.getAllLevels(); + List levels = new java.util.ArrayList<>(StreamSupport.stream(allLevels.spliterator(), false).toList()); + levels.remove((ServerLevel) level); + ServerLevel destination = levels.get(new Random().nextInt(levels.size())); +// server.getPlayerList().getPlayer(player.getUUID()).teleportTo(destination, player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot()); + ServerPlayer serverPlayer = server.getPlayerList().getPlayer(player.getUUID()); + if (serverPlayer != null) + serverPlayer.changeDimension(destination, DimensionwalkerTeleporter.instance()); + else + LOGGER.warn("Can't teleport, serverPlayer == null"); + } + else + LOGGER.warn("Can't teleport, server == null"); + } + return super.use(level, player, hand); + } +} diff --git a/src/main/java/moe/nekojimi/dimensionwalker/DimensionwalkerMod.java b/src/main/java/moe/nekojimi/dimensionwalker/DimensionwalkerMod.java new file mode 100644 index 0000000..1a20623 --- /dev/null +++ b/src/main/java/moe/nekojimi/dimensionwalker/DimensionwalkerMod.java @@ -0,0 +1,69 @@ +package moe.nekojimi.dimensionwalker; + +import com.mojang.logging.LogUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Blocks; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.event.server.ServerStartingEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; +import org.slf4j.Logger; + +// The value here should match an entry in the META-INF/mods.toml file +@Mod(DimensionwalkerMod.MODID) +public class DimensionwalkerMod +{ + // Define mod id in a common place for everything to reference + public static final String MODID = "examplemod"; + // Directly reference a slf4j logger + private static final Logger LOGGER = LogUtils.getLogger(); + + public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, MODID); + + public static final RegistryObject DIMENSIONWALKER_GLOVE_ITEM = ITEMS.register("dimensionwalker_glove", ()->new DimensionwalkerItem() ); + + public DimensionwalkerMod() + { + IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + + // Register the commonSetup method for modloading + modEventBus.addListener(this::commonSetup); + + // Register the Deferred Register to the mod event bus so items get registered + ITEMS.register(modEventBus); + + // Register ourselves for server and other game events we are interested in + MinecraftForge.EVENT_BUS.register(this); + } + + private void commonSetup(final FMLCommonSetupEvent event) + { + // Some common setup code + LOGGER.info("HELLO FROM COMMON SETUP"); + LOGGER.info("DIRT BLOCK >> {}", ForgeRegistries.BLOCKS.getKey(Blocks.DIRT)); + } + + // You can use SubscribeEvent and let the Event Bus discover methods to call + @SubscribeEvent + public void onServerStarting(ServerStartingEvent event) + { + // Do something when the server starts + LOGGER.info("HELLO from server starting"); + + Iterable levels = event.getServer().getAllLevels(); + levels.forEach(serverLevel -> + { + LOGGER.info(serverLevel.dimension().toString() + " scale: " + serverLevel.dimensionType().coordinateScale()); + }); + } + +} diff --git a/src/main/java/moe/nekojimi/dimensionwalker/DimensionwalkerTeleporter.java b/src/main/java/moe/nekojimi/dimensionwalker/DimensionwalkerTeleporter.java new file mode 100644 index 0000000..d3a7a00 --- /dev/null +++ b/src/main/java/moe/nekojimi/dimensionwalker/DimensionwalkerTeleporter.java @@ -0,0 +1,115 @@ +package moe.nekojimi.dimensionwalker; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.portal.PortalInfo; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.common.util.ITeleporter; +import org.apache.http.io.SessionOutputBuffer; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.function.Function; + +public class DimensionwalkerTeleporter implements ITeleporter +{ + private static DimensionwalkerTeleporter INSTANCE = null; + + @Override + public Entity placeEntity(Entity entity, ServerLevel currentWorld, ServerLevel destWorld, float yaw, Function repositionEntity) + { + return repositionEntity.apply(true); + } + + @Override + public @Nullable PortalInfo getPortalInfo(Entity entity, ServerLevel destWorld, Function defaultPortalInfo) + { +// return ITeleporter.super.getPortalInfo(entity, destWorld, defaultPortalInfo); + + BlockPos startPos = new BlockPos(entity.getBlockX(), entity.getBlockY(), entity.getBlockZ()); + System.out.println("Current player position: " + startPos); +// ChunkAccess chunk = destWorld.getChunk(startPos); +// int maxHeight = startPos.getY(); +// destWorld.get +// for (Heightmap.Types type : Heightmap.Types.values()) +// { +// int height = chunk.getHeight(type,startPos.getX(),startPos.getZ()); +// System.out.println("Heightmap type: " + type.name() + ", height: " + height); +// if (height > maxHeight) +// maxHeight = height; +// } + BlockPos blockPos = findSafePosition(destWorld,startPos); + if (blockPos == null) + blockPos = startPos; + return new PortalInfo(new Vec3((double)blockPos.getX() + 0.5D, (double)blockPos.getY()+1.0D, (double)blockPos.getZ() + 0.5D), entity.getDeltaMovement(), entity.getYRot(), entity.getXRot()); + } + + public @Nullable BlockPos findSafePosition(ServerLevel destWorld, BlockPos startPos) + { +// List candidates = new ArrayList<>(); + + WorldBorder worldborder = destWorld.getWorldBorder(); + int worldHeight = Math.min(destWorld.getMaxBuildHeight(), destWorld.getMinBuildHeight() + destWorld.getLogicalHeight()) - 1; + + outer: + for (BlockPos.MutableBlockPos pos : BlockPos.spiralAround(startPos, 16, Direction.EAST, Direction.SOUTH)) + { + if (pos == null) + return null; + ChunkAccess chunk = destWorld.getChunk(pos); + int terrainHeight = chunk.getHeight(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,pos.getX(),pos.getZ()); + int freeBlocksAbove = 999; + int startY = Math.min(worldHeight, terrainHeight); + System.out.println("Starting search for safe destination at Y=" + startY); + for (int y = startY; y >= destWorld.getMinBuildHeight(); y--) + { + pos.setY(y); + + // check that y is solid + BlockState blockState = chunk.getBlockState(pos); + if (blockState.getMaterial().isSolid()) + { + if (worldborder.isWithinBounds(pos) && y < worldHeight-3 && freeBlocksAbove >= 2) + { + System.out.println("Found safe destination! pos: " + pos + " material: " + blockState.getMaterial() + " state: " + blockState); + return pos; +// candidates.add(pos); +// if (candidates.size() >= 16) +// break outer; + } + freeBlocksAbove = 0; + } + else if (blockState.getMaterial().isLiquid() || !blockState.isAir()) + { + freeBlocksAbove = 0; // liquid blocks aren't free + } + else + { + freeBlocksAbove++; + } + } + } +// if (candidates.size() > 0) +// { +// candidates.sort(Comparator.comparingDouble(a -> a.distSqr(startPos))); +// return candidates.get(0); +// } + + return null; + } + + public static ITeleporter instance() + { + if (INSTANCE == null) + INSTANCE = new DimensionwalkerTeleporter(); + return INSTANCE; + } +} diff --git a/src/main/java/moe/nekojimi/dimensionwalker/Peachy.java b/src/main/java/moe/nekojimi/dimensionwalker/Peachy.java new file mode 100644 index 0000000..64a17fb --- /dev/null +++ b/src/main/java/moe/nekojimi/dimensionwalker/Peachy.java @@ -0,0 +1,9 @@ +package moe.nekojimi.dimensionwalker; + +public class Peachy +{ + Peachy() + { + System.out.println("I'm Peachy!"); + } +}