Jump to content

[1.15.2] Teleport Player to Nearest "Safe" Spot


Recommended Posts

Posted

Hello. I wrote a custom teleporter (a basic implementation of ITeleporter) to bring the player in-between my custom dimension and others negating portal spawn. However, the generation in my dimension is made up of floating islands, similar to the End. Right now my custom teleporter brings players to the exact coordinates in each dimension, which results in them high up in the air, falling into the void, or spawning inside a block. What I would like to do is either of the following, for two separate instances:

 

a). Teleport the player to the nearest safe surface in each world. (Nearest island in my dimension, and up to the surface in the overworld).

b). Teleport the player to their own spawn point in the overworld, and the origin of my dimension.

 

I've poked around in the vanilla classes a bit, but can't seem to find any instances of this type of teleportation. Are there any examples of this that you can point me in the direction of and/or does anyone know how to achieve this?

 

Thanks.

Follow these rules when talking to me, and we'll get along fine.

1).I know Java fairly well. I don't know as much about modding. They are not the same, don't compare them.

2). I consider myself to always be learning. I make mistakes, you make mistakes. Who doesn't?

3). Insult me, and I will leave the thread. I have a real life, I don't have time to throw petty insults in a Minecraft Modding forum.

 

ModMCdl - Co-Founder and Director of Design for Artemis Game Studios

Posted

Well In the nether, if you spawn above lava, you spawn inside of a portal with 1 block out on both sides. You might want to use this solution. Or you could have it automatically place a block under the player when they spawn in

Posted
11 minutes ago, MrInfinity said:

Well In the nether, if you spawn above lava, you spawn inside of a portal with 1 block out on both sides. You might want to use this solution. Or you could have it automatically place a block under the player when they spawn in

But the portal still tries to locate the nearest solid ground to place a portal on, does it not? I tried reverse engineering that code but I was either looking at the wrong methods or just don't know how it's doing that.

 

And whilst I could just spawn a block under the player, that doesn't seem like a survival-friendly solution. 

Follow these rules when talking to me, and we'll get along fine.

1).I know Java fairly well. I don't know as much about modding. They are not the same, don't compare them.

2). I consider myself to always be learning. I make mistakes, you make mistakes. Who doesn't?

3). Insult me, and I will leave the thread. I have a real life, I don't have time to throw petty insults in a Minecraft Modding forum.

 

ModMCdl - Co-Founder and Director of Design for Artemis Game Studios

Posted (edited)

https://minecraft.gamepedia.com/Nether_portal#Portal_search - Under Portal Creation

 

Here it says that a nether portal first looks for any valid locations in a 4x4 chunk radius around the center of where it would spawn. If it finds none, then it will spawn somewhere between y 90 and 10 blocks below the world limit. So if you create a nether-portal like portal, it would follow those rules, meaning that if it spawned in empty space, the floating portal would be created

Edited by MrInfinity
Posted
Just now, MrInfinity said:

https://minecraft.gamepedia.com/Nether_portal#Portal_search - Under Portal Creation

 

Here it says that a nether portal first looks for any valid locations in a 4x4 chunk radius around the center of where it would spawn. If it finds none, then it will spawn somewhere between y 90 and 10 blocks below the world limit. So if you create a nether-portal like portal, it would follow those rules, meaning that if it spawned in empty space, the floating portal would be created

I don't create a portal though, as I specified in my OP. I use a special item to teleport players in between dimensions. 

Follow these rules when talking to me, and we'll get along fine.

1).I know Java fairly well. I don't know as much about modding. They are not the same, don't compare them.

2). I consider myself to always be learning. I make mistakes, you make mistakes. Who doesn't?

3). Insult me, and I will leave the thread. I have a real life, I don't have time to throw petty insults in a Minecraft Modding forum.

 

ModMCdl - Co-Founder and Director of Design for Artemis Game Studios

Posted
11 hours ago, ModMCdl said:

I've poked around in the vanilla classes a bit, but can't seem to find any instances of this type of teleportation. Are there any examples of this that you can point me in the direction of and/or does anyone know how to achieve this?

I think the method makePortal() in the Teleporter class is where vanilla tries to find a nearby valid position to create the portal in. However, it is kind of a large and unreadable method, so I don't know if it is realistic to try and replicate it.

 

Another possibility would be to do something similar to how the locate command works. I am not too familiar with world generation, but if your islands are generated similar to how vanilla structures are generated, then this could work.

Posted
8 hours ago, diesieben07 said:

You can use World#getHeight to get the surface y position at a given x and z coordinate. You can then use that to place the player on the surface.

Thank you, I had tried doing that with the players spawnpoints, and World#getHeight is definitely a good thing to hear about. I also think I might have been phrasing my question wrong this entire time. I don't know how to implement additional, conditions shall we say, into the changeDimension method. Or even if I can. Do I need to write a custom teleport method to do this? Same thing with sending each player to the spawn point. (Sorry, I just really have no idea what I'm doing in this instance.)

Follow these rules when talking to me, and we'll get along fine.

1).I know Java fairly well. I don't know as much about modding. They are not the same, don't compare them.

2). I consider myself to always be learning. I make mistakes, you make mistakes. Who doesn't?

3). Insult me, and I will leave the thread. I have a real life, I don't have time to throw petty insults in a Minecraft Modding forum.

 

ModMCdl - Co-Founder and Director of Design for Artemis Game Studios

Posted
Just now, diesieben07 said:

That's exactly what a custom teleporter does, right? what do you mean by "conditions"?

I'm using changeDimension accepts a DimensionType and then ITeleporter, at least as far as I can tell, and so right now I'm using 

               player.changeDimension(world.dimension.getType() == DimensionType.byName(VoidaicDepths.VOID_DIM_TYPE) ? DimensionType.OVERWORLD : DimensionType.byName(VoidaicDepths.VOID_DIM_TYPE), new VoidTeleporter((ServerWorld) player.getEntityWorld()));

 

Passing in my custom dimension and then my custom teleporter.

 

My custom teleporter only overrides placeEntity from ITeleporter so that it does not place a portal. Forgive me, but I can't find how I would add additional methods to check, and as @vemerionhad mentioned, the place portal method that might be doing that is quite "unreadable," or at the very least hard to dissect.

 

Custom Teleporter: https://github.com/ModMCdl/Voidaic-Depths/blob/master/src/main/java/com/modmcdl/voidaicdepths/util/VoidTeleporter.java

Follow these rules when talking to me, and we'll get along fine.

1).I know Java fairly well. I don't know as much about modding. They are not the same, don't compare them.

2). I consider myself to always be learning. I make mistakes, you make mistakes. Who doesn't?

3). Insult me, and I will leave the thread. I have a real life, I don't have time to throw petty insults in a Minecraft Modding forum.

 

ModMCdl - Co-Founder and Director of Design for Artemis Game Studios

Posted
5 minutes ago, diesieben07 said:

Please describe what you want to achieve from a gameplay perspective, not how you have attempted to program it.

I have an item that on right click, teleports the player to another dimension. I do not want it to spawn a portal. I simply want to teleport the player to their relative coordinates in either dimension, but move them to the nearest "safe" surface. (In the overworld, this would be the surface, in my "void" dimension, this would be the nearest island). Originally, this seemed like the best option. However, after going through the code, I think a better alternative and easier solution would simply be to teleport to each world's spawnpoint. I've been told that each method follows the same idea of relocating the entity, but spawnpoints have an existing implementation, and I can kind of see how it's done with the if statement in player#changeDimension relating to the end.

 

My problem is while I have a general idea of how to do this, I do not know where to place this method so that it will successfully be called when the player teleports. I have considering putting it into my custom teleporter, but I'm not sure how to go about doing that without creating an entirely new changeDimension function. I'm lost in terms of I know the theory behind doing it, but have no idea how to actually implement it. Usually I can find an example in the vanilla code, (which is how I learn most of how I do modding, as seeing examples for me is the best sort of jumping-off point) but I can't seem to find a specific example that actually does what I want, and when I do, the specific use case does not allow me to implement it successfully.

Follow these rules when talking to me, and we'll get along fine.

1).I know Java fairly well. I don't know as much about modding. They are not the same, don't compare them.

2). I consider myself to always be learning. I make mistakes, you make mistakes. Who doesn't?

3). Insult me, and I will leave the thread. I have a real life, I don't have time to throw petty insults in a Minecraft Modding forum.

 

ModMCdl - Co-Founder and Director of Design for Artemis Game Studios

Posted (edited)
2 hours ago, diesieben07 said:

All you need to do is change the entity's position in placeEntity of your teleporter. That is literally the method is used for.

Been picking this problem apart for a few hours now.

 

This is what I'm working on, which from what I've gathered should get the spawn points for each world and place them in a BlockPos, but I'm not sure what I should be doing afterwards to return the new position to the Player. Looking through the javadocs, it appears that repositionEntity is reserved for portal placement specifically, so I don't think I want to return that as true. Right now my script does nothing, as I don't call these new dimensions anywhere.

    @Override
    public Entity placeEntity(Entity entity, ServerWorld currentWorld, ServerWorld destWorld, float yaw, Function<Boolean, Entity> repositionEntity)
    {
        BlockPos pos;

        if(destWorld.dimension.getType() == DimensionType.byName(VoidaicDepths.VOID_DIM_TYPE))
        {
            pos = destWorld.getSpawnCoordinate();
        }
        else if(destWorld.dimension.getType() == DimensionType.OVERWORLD)
        {
            pos = destWorld.getHeight(Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, destWorld.getSpawnPoint());
        }
        return repositionEntity.apply(false);
    }

 

I don't really know what ask here without sounding stupid, and I know everyone hates it when people ask stupid questions here. You've given me a lot of good information on how to go about doing this, but do you have an example to point me to or an implementation? As I said before, I don't understand how it is working in the vanilla Teleporter class. I tried updating my forge mappings to try and clear up the methods in the Teleporter class, but that didn't seem to change much.

Edited by ModMCdl

Follow these rules when talking to me, and we'll get along fine.

1).I know Java fairly well. I don't know as much about modding. They are not the same, don't compare them.

2). I consider myself to always be learning. I make mistakes, you make mistakes. Who doesn't?

3). Insult me, and I will leave the thread. I have a real life, I don't have time to throw petty insults in a Minecraft Modding forum.

 

ModMCdl - Co-Founder and Director of Design for Artemis Game Studios

Posted
10 hours ago, ModMCdl said:

This is what I'm working on, which from what I've gathered should get the spawn points for each world and place them in a BlockPos, but I'm not sure what I should be doing afterwards to return the new position to the Player

If you look at the call hierarchy of the placeEntity() method, you can see that the entity it returns is in fact the entity that is teleported. Therefore, to change the position of the entity you would only need to change the position of the entity you return before returning it.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Version 1.19 - Forge 41.0.63 I want to create a wolf entity that I can ride, so far it seems to be working, but the problem is that when I get on the wolf, I can’t control it. I then discovered that the issue is that the server doesn’t detect that I’m riding the wolf, so I’m struggling with synchronization. However, it seems to not be working properly. As I understand it, the server receives the packet but doesn’t register it correctly. I’m a bit new to Java, and I’ll try to provide all the relevant code and prints *The comments and prints are translated by chatgpt since they were originally in Spanish* Thank you very much in advance No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. MountableWolfEntity package com.vals.valscraft.entity; import com.vals.valscraft.network.MountSyncPacket; import com.vals.valscraft.network.NetworkHandler; import net.minecraft.client.Minecraft; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.animal.Wolf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.Entity; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.network.PacketDistributor; public class MountableWolfEntity extends Wolf { private boolean hasSaddle; private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(MountableWolfEntity.class, EntityDataSerializers.BYTE); public MountableWolfEntity(EntityType<? extends Wolf> type, Level level) { super(type, level); this.hasSaddle = false; } @Override protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(DATA_ID_FLAGS, (byte)0); } public static AttributeSupplier.Builder createAttributes() { return Wolf.createAttributes() .add(Attributes.MAX_HEALTH, 20.0) .add(Attributes.MOVEMENT_SPEED, 0.3); } @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); if (itemstack.getItem() == Items.SADDLE && !this.hasSaddle()) { if (!player.isCreative()) { itemstack.shrink(1); } this.setSaddle(true); return InteractionResult.SUCCESS; } else if (!level.isClientSide && this.hasSaddle()) { player.startRiding(this); MountSyncPacket packet = new MountSyncPacket(true); // 'true' means the player is mounted NetworkHandler.CHANNEL.sendToServer(packet); // Ensure the server handles the packet return InteractionResult.SUCCESS; } return InteractionResult.PASS; } @Override public void travel(Vec3 travelVector) { if (this.isVehicle() && this.getControllingPassenger() instanceof Player) { System.out.println("The wolf has a passenger."); System.out.println("The passenger is a player."); Player player = (Player) this.getControllingPassenger(); // Ensure the player is the controller this.setYRot(player.getYRot()); this.yRotO = this.getYRot(); this.setXRot(player.getXRot() * 0.5F); this.setRot(this.getYRot(), this.getXRot()); this.yBodyRot = this.getYRot(); this.yHeadRot = this.yBodyRot; float forward = player.zza; float strafe = player.xxa; if (forward <= 0.0F) { forward *= 0.25F; } this.flyingSpeed = this.getSpeed() * 0.1F; this.setSpeed((float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 1.5F); this.setDeltaMovement(new Vec3(strafe, travelVector.y, forward).scale(this.getSpeed())); this.calculateEntityAnimation(this, false); } else { // The wolf does not have a passenger or the passenger is not a player System.out.println("No player is mounted, or the passenger is not a player."); super.travel(travelVector); } } public boolean hasSaddle() { return this.hasSaddle; } public void setSaddle(boolean hasSaddle) { this.hasSaddle = hasSaddle; } @Override protected void dropEquipment() { super.dropEquipment(); if (this.hasSaddle()) { this.spawnAtLocation(Items.SADDLE); this.setSaddle(false); } } @SubscribeEvent public static void onServerTick(TickEvent.ServerTickEvent event) { if (event.phase == TickEvent.Phase.START) { MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer(); if (server != null) { for (ServerPlayer player : server.getPlayerList().getPlayers()) { if (player.isPassenger() && player.getVehicle() instanceof MountableWolfEntity) { MountableWolfEntity wolf = (MountableWolfEntity) player.getVehicle(); System.out.println("Tick: " + player.getName().getString() + " is correctly mounted on " + wolf); } } } } } private boolean lastMountedState = false; @Override public void tick() { super.tick(); if (!this.level.isClientSide) { // Only on the server boolean isMounted = this.isVehicle() && this.getControllingPassenger() instanceof Player; // Only print if the state changed if (isMounted != lastMountedState) { if (isMounted) { Player player = (Player) this.getControllingPassenger(); // Verify the passenger is a player System.out.println("Server: Player " + player.getName().getString() + " is now mounted."); } else { System.out.println("Server: The wolf no longer has a passenger."); } lastMountedState = isMounted; } } } @Override public void addPassenger(Entity passenger) { super.addPassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(true)); } } } @Override public void removePassenger(Entity passenger) { super.removePassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is no longer mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(false)); } } } @Override public boolean isControlledByLocalInstance() { Entity entity = this.getControllingPassenger(); return entity instanceof Player; } @Override public void positionRider(Entity passenger) { if (this.hasPassenger(passenger)) { double xOffset = Math.cos(Math.toRadians(this.getYRot() + 90)) * 0.4; double zOffset = Math.sin(Math.toRadians(this.getYRot() + 90)) * 0.4; passenger.setPos(this.getX() + xOffset, this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset(), this.getZ() + zOffset); } } } MountSyncPacket package com.vals.valscraft.network; import com.vals.valscraft.entity.MountableWolfEntity; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class MountSyncPacket { private final boolean isMounted; public MountSyncPacket(boolean isMounted) { this.isMounted = isMounted; } public void encode(FriendlyByteBuf buffer) { buffer.writeBoolean(isMounted); } public static MountSyncPacket decode(FriendlyByteBuf buffer) { return new MountSyncPacket(buffer.readBoolean()); } public void handle(NetworkEvent.Context context) { context.enqueueWork(() -> { ServerPlayer player = context.getSender(); // Get the player from the context if (player != null) { // Verifies if the player has dismounted if (!isMounted) { Entity vehicle = player.getVehicle(); if (vehicle instanceof MountableWolfEntity wolf) { // Logic to remove the player as a passenger wolf.removePassenger(player); System.out.println("Server: Player " + player.getName().getString() + " is no longer mounted."); } } } }); context.setPacketHandled(true); // Marks the packet as handled } } networkHandler package com.vals.valscraft.network; import com.vals.valscraft.valscraft; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class NetworkHandler { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel( new ResourceLocation(valscraft.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); public static void init() { int packetId = 0; // Register the mount synchronization packet CHANNEL.registerMessage( packetId++, MountSyncPacket.class, MountSyncPacket::encode, MountSyncPacket::decode, (msg, context) -> msg.handle(context.get()) // Get the context with context.get() ); } }  
    • Do you use features of inventory profiles next (ipnext) or is there a change without it?
    • Remove rubidium - you are already using embeddium, which is a fork of rubidium
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.