Jump to content

What would be the best way to handle long-distance TileEntity information...


Recommended Posts

Posted

Sorry for the confusing title, I wasn't exactly sure how to word it.

 

Basically, I want to make a TileEntity. Actually, it's two tileentities, effectively for "teleporation pads". So, all I need to do is for the sender pad to know where all the receiver pads in the world are located, then send the player there.

 

What I'm unsure about, is how can I make the receiver "tell" the sender where it's located, and when should I do that? I figured I could maybe save it's coordinates in a special NBT tag in the world, but when people use a lot of them that might get messy so what better ideas are there?

 

 

To be clear, there's no "channels" or anything. All senders should be able to send to any receiver, which will be selected in a GUI. The idea actually works a little differently but this is the easiest way to describe it :P

width=463 height=200

http://s13.postimg.org/z9mlly2av/siglogo.png[/img]

My mods (Links coming soon)

Cities | Roads | Remula | SilvaniaMod | MoreStats

Posted

Hi

 

I suspect this might be a bit harder than it seems at first, because TileEntities are loaded in and out of memory as the player moves around.  Luckily, I reckon it's probably unnecessary to store this information in the TileEntities.

 

I think your best bet is to write some code which searches all the chunks within a certain radius of the player for Teleportation TileEntitys.  You would call this code when the user opens the "receiver selection" GUI.

 

-TGG

 

Posted

This is why...I feel like it was IC2, but it might've been an addon, had a "teleporter remote control" item.  You'd right click on one teleporter, then go to the second teleporter and right click again.  Now the second one could send to the first one.

 

(The item carried NBT data tags holding the relevant data!)

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted

you could technicly store EVERY location of that block in another place then in the "world" and in the "chunks"

 

obviously if you scale this in a List it wont be scalable so youll have to make some kind of spatial partitionning to keep search time lows...

 

just throwing ideas

how to debug 101:http://www.minecraftforge.net/wiki/Debug_101

-hydroflame, author of the forge revolution-

Posted

If just getting a list of every loaded TileEntity in the world is enough for you, you can use the list in World:  world.loadedTileEntityList . And you could search for your own TileEntities in there.  However, teleportation often is about travelling far (and unloaded) distances so a loaded tile entity list probably doesn't suffice....

Author of PneumaticCraft, MineChess, Minesweeper Mod and Sokoban Mod. Visit www.minemaarten.com to take a look at them.

Posted

I've just thought; could I use something similar to how the enderchest works here?

 

I've not looked at the enderchest, but I could theoretically do a similar thing in the world NBT instead of the player one - with my "teleport locations" being the data stored instead of items, and the sender being the "physical chest" which can view those locations.

 

Am I on the right tracks with that? :P

width=463 height=200

http://s13.postimg.org/z9mlly2av/siglogo.png[/img]

My mods (Links coming soon)

Cities | Roads | Remula | SilvaniaMod | MoreStats

Posted

You could.  Yes.

Whether or not its a good idea is the question though.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted

Hi

 

I think the EnderChest stores its information in the player, which is probably not what you want.

 

Although I've never used it, WorldInfo appears to have space for "additional properties":

WorldInfo.setAdditionalProperties

WorldInfo.getAdditionalProperties

 

You could perhaps store a list of all receivers in this property and make sure you keep it updated when the receivers are created and destroyed.  I'd suggest introducing some sort of game mechanic to keep the number of receivers under control otherwise your GUI for receiver selection will become unmanageable.

 

Best way to find out is to try it I reckon :-)

 

-TGG

Posted

This really makes me think of IC2's way to manage the powernet. When you want to add an IC2 machine to the powernet, you'll have to post an event when you load the TileEntity and a different event when the TileEntity gets unloaded or removed. Although IC2 is closed source, you could learn from their API :).

 

A bit of info you could use in your implementation, from IC2 API's usage.txt:

You can detect the loading by either using the 1st iteration of updateEntity() or by waiting for

the next world tick after TileEntity.validate(). The 2nd approach is obviously more sophisticated

and requires to use some tick queuing mechanism.

 

And about the unloading:

The event has to be posted as soon as the implementing tile entity is being unloaded, either by

unloading the containing chunk or by destroying the block containing it.

 

It's possible to detect the unloading by triggering on both the beginning of

TileEntity.invalidate() and the beginning of TileEntity.onChunkUnload().

The difference is they stop using the TileEntity when it's unloaded.

 

So they are using events, but that's with an API in mind, you could just add to a list and store it in WorldInfo like TheGreyGhost mentioned (I also never have used this).

 

Good luck!

Author of PneumaticCraft, MineChess, Minesweeper Mod and Sokoban Mod. Visit www.minemaarten.com to take a look at them.

Posted

IC2 may be open source, but its not stopping me.

Get bearded octo nemesis and jdgui.

1st. Run bearded octo nemesis on ic2 (or any other mod)

2nd. Open your new file with jdgui

3rd. Click file-save all sources

4th. You now have a deobsfucated decompiled minecraft mod!

Have fun sirs!

"you seem to be THE best modder I've seen imo."

~spynathan

 

ლ(́◉◞౪◟◉‵ლ

Posted

Hi

 

I think the EnderChest stores its information in the player, which is probably not what you want.

 

Although I've never used it, WorldInfo appears to have space for "additional properties":

WorldInfo.setAdditionalProperties

WorldInfo.getAdditionalProperties

 

You could perhaps store a list of all receivers in this property and make sure you keep it updated when the receivers are created and destroyed.  I'd suggest introducing some sort of game mechanic to keep the number of receivers under control otherwise your GUI for receiver selection will become unmanageable.

 

Best way to find out is to try it I reckon :-)

 

-TGG

 

I'll look into that :) This is more of an admin thing anyway for setting up on a server/map. It's only going to be available in creative mode by default - I'll have a crafting recipe which can be enabled but it'll be endgame expensive even then.

 

It's for part of the mechanics of my Cities mod. What is actually happening is the receiver is the only "block" part of it, and will actually be hidden. The sender is really a mob, whom will teleport you to it after selecting your location and paying a fee with the built-in economy, as part of an airline fast-travel system I'm adding to the mod.

width=463 height=200

http://s13.postimg.org/z9mlly2av/siglogo.png[/img]

My mods (Links coming soon)

Cities | Roads | Remula | SilvaniaMod | MoreStats

Posted

IC2 may be open source, but its not stopping me.

Get bearded octo nemesis and jdgui.

1st. Run bearded octo nemesis on ic2 (or any other mod)

2nd. Open your new file with jdgui

3rd. Click file-save all sources

4th. You now have a deobsfucated decompiled minecraft mod!

Have fun sirs!

 

JDGUI by itself is usually sufficient.  Most mods don't obfuscate themselves, so you're left with only the Minecraft obfuscated parameters, but most you can figure out just by the context, the rest you can lookup using MCP :)

 

I actually peeked inside Twilight Forest at the Anti-Builder to see if it had done anything special/clever to minimize get, save, check, and reset blocks (as I needed similar functionality).  It was just a standard 3 dimensional for loop.  I've also poked my nose into Mystcraft on occasion (notably when trying to figure out how to use XCompWiz's API, I'll get confused over the usage of one parameter, so I pull up base and take a look at how he was using it).

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted

I'm gonna make a really stupid comment here. I don't fully yet understand how it works but wouldn't it be possible to make a static list and whenever a tileEntity is created it adds to the list and whenever it's gets destroyed it removes itself?

Posted

Hi

 

That idea would work, with the restriction that the information would be lost when you shut the server down.

Hence the suggestions for saving it somewhere permanent, like  WorldInfo.setAdditionalProperties or in a player's item.

There are other ways of course, for example saving/loading to your own configuration file somewhere.  Or you could search the entire world at startup to regenerate your static list.

 

-TGG

 

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.