Jump to content

Recommended Posts

Posted

Hey guys. I've been rather idle lately. Busy porting stuff to 1.12 and finishing up college.

 

I'm trying to get a deeper understanding of capabilities and the ways they're called and gotten from the server/client. Possibly I should be doing research into how objects are stored/remembered in your java program as a whole. But I'm having very little luck with finding sources on that. 

 

So when I try to use a capability in a class I use a static method getHandler to get it.  I can't tell if the getcapability is static or not. Does it create a new object with the information of my capability in it and passes that to the class, or does it simply pass on a reference to the capability that's already in play?

 

For example. I'm making a GUI That will be able to change depending on a variable stored in the capabilities of the player.  

I have a handler and 'get' that by using 

 private final IStats handler = CustomStatsHandler.getHandler(Minecraft.getMinecraft().player);

 

then I get the value as such, nothing really too interesting: 

int i = handler.getInt();

for example.

 

If I change the value of handler.getInt() in another class yet NOT use my gethandler method again, would I get an updated int, or would I have to use my gethandler yet again to get an updated value?

 

I'm also trying to decide if it's more efficient to put all capability data I have in seperate capabilities by 'category' or if I should just put them all into a single one. I'm mostly worried about possible lag if clients need to try and load capability data every few seconds and the capability cointains 20 values. 

 

Sorry if my question is stupid. It's been a while since I worked on coding. Cheers in advance. 

Posted
41 minutes ago, oldcheese said:

I can't tell if the getcapability is static or not.

Its not. It would not make any sense for it to be.

  • Like 1

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
6 minutes ago, Draco18s said:

Its not. It would not make any sense for it to be.

 

So is what I'm passing on to my code a reference to where the capability is stored, or a copy of the capability itself? 

 

I'm calling the handler with a final method. So I'm guessing that I can change the state of the original object, but the values contained in 'handler' will always be the same untill I call it again?

Posted (edited)
35 minutes ago, oldcheese said:

 

So is what I'm passing on to my code a reference to where the capability is stored, or a copy of the capability itself?

Lets look at an example.

 

Here we have the getCapability method of a TileEntity (e.g. a chest):

https://github.com/Draco18s/ReasonableRealism/blob/1.12.1/src/main/java/com/draco18s/ores/entities/TileEntitySifter.java#L140-L158

It appear to be returning an object named inputSlot or outputSlotWrapper, sometimes together, sometimes not. We won't worry about the distinction for the moment.

Lets look at these two objects.

https://github.com/Draco18s/ReasonableRealism/blob/1.12.1/src/main/java/com/draco18s/ores/entities/TileEntitySifter.java#L41-L43

And by two, I mean three, as one is a wrapper around the third. In any case, they are ItemStackHandlers, which is a capability that is used to handle inventory: it holds (contains) ItemStacks.

https://github.com/Draco18s/ReasonableRealism/blob/1.12.1/src/main/java/com/draco18s/ores/entities/TileEntitySifter.java#L48-L50

The wrapper is done so that no items can be inserted into that inventory slot, but can be extracted. The original needs to allow insertion by the machine itself, but not exposed externally at any time for any reason.

 

Well, ok, but what is an ItemStackHandler? And how does it relate to this line?

https://github.com/Draco18s/ReasonableRealism/blob/1.12.1/src/main/java/com/draco18s/ores/entities/TileEntitySifter.java#L142

 

Well, ItemStackHandler is a class that implements IItemHandler and that line is a reference to the capability: Capability<IItemHandler> ITEM_HANDLER_CAPABILITY, supplied by Forge. Hey, look, both have something about the interface IItemHandler! So what is this thing?

 

IItemHandler is an interface that describes the functions of the capability, what methods it has, so that external code doesn't need to know what things like SiftableItemsHandler or OutputItemStackHandler are specifically. Both (eventually) inherit from IItemHandler and any code that gets passed these objects can still hold onto them and perform the necessary functions without crashing. The interface is a contract that the classes must adhere to.

Edited by Draco18s

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
56 minutes ago, loordgek said:

can you post your code on github so we can look at it

I'm looking to understand what happens when a capability is called. I don't have an actual problem.

 

24 minutes ago, Draco18s said:

IItemHandler is an interface that describes the functions of the capability, what methods it has, so that external code doesn't need to know what things like SiftableItemsHandler or OutputItemStackHandler are specifically. Both (eventually) inherit from IItemHandler and any code that gets passed these objects can still hold onto them and perform the necessary functions without crashing. The interface is a contract that the classes must adhere to.

So I'm not loading the entire capability information object whenever I use the getCapability code?  I'm just getting an interface so I can interact with a part of the object without crashing?

And when I use the ItemStackHandler for example, I'm not getting literal info. I'm just 'loading' the interface so to speak, so I can then interact with the object that exists somewhere on my machine?

 

So that would mean that having a single capability that contains many  values would be as fast to load as having three/four capabilities with the values split among them? 

 

I feel like I might not have adequately clarified my question. I think you answered my first question about how capabilities are called if the above is true and I'm understanding it right. 

 

so imagine the following: 

 

Imagine if I had a capability that stored a single Integer.

 

on tick 1, code X would load and initiate a 'getCapability' line to get the interface/capability and interact with it.

 

on tick 2, a different class of my code would change the integer of my capability from 2 to 5.

 

on tick 3, I would call the getInteger method from code X without using 'getCapability' again. 

 

Would I get 2 or 5?

 

 

From what I understand from your comment I should get 5. But I could really try this myself once I get back home. I'd rather know if the above assumption is correct in that getting a value from a small capability is the same as getting one from a big capability.

 

English is not my main language, so I might be constructing my questions a bit weird. I'm sorry if it's annoying.

Posted
1 hour ago, oldcheese said:

I'm just getting an interface

No, you're getting an object that is an instance of a class that implements an interface.

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're getting mixed up on some Java concepts. Here's some clarification (hopefully).

 

In Java, when you pass a object instance as a parameter it is accessible by the method. It is not a copy. This differs from some other programming languages.

 

Also, when you use the assignment (=) it does not make a copy. So if you say Object A = B and then change something in A it will also change in B. 

 

To make a copy in Java, you have to go to explicit work to make the copy. It is good programming practice with your custom classes to create a proper copy() method. To make a copy the basic idea (there are other "levels" of copying) create a new instance and go through an find all the primitive fields and copy their values over.

 

Generally, you'll only get a copy if a new instance is created. Otherwise it is passed on through. Passing through is how method "chaining" works (allowing you to take the returned value and apply additional methods). For example, if you have a method that takes in an ItemStack and then returns it, it is the same instance. But if the method takes in the ItemStack, creates a new ItemStack and returns that then it would be a copy. 

 

Now the other Java concept you need to understand better is interfaces. You also said:

4 hours ago, oldcheese said:

So I'm not loading the entire capability information object whenever I use the getCapability code?  I'm just getting an interface so I can interact with a part of the object without crashing?

That is only partially right. You get the whole instance but are only guaranteed that it supports the interface. However, if you have confidence that it is actually a certain class type you can access its methods too. To check if something is actually a certain class you can use the instanceof operator and then cast. Like there are many methods in modding that have a EntityLiving passed in, but you can check if it is actually instanceof EntityPlayer and if it is then cast it to EntityPlayer and then you're allowed to access the rest of the EntityPlayer methods.

  • Like 1

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted
47 minutes ago, jabelar said:

You're getting mixed up on some Java concepts. Here's some clarification (hopefully).

 

In Java, when you pass a object instance as a parameter it is accessible by the method. It is not a copy. This differs from some other programming languages.

 

Also, when you use the assignment (=) it does not make a copy. So if you say Object A = B and then change something in A it will also change in B. 

 

To make a copy in Java, you have to go to explicit work to make the copy. It is good programming practice with your custom classes to create a proper copy() method. To make a copy the basic idea (there are other "levels" of copying) create a new instance and go through an find all the primitive fields and copy their values over.

 

 

I was getting that mixed up! That's exactly what I needed for an answer. Thanks.

 

I was somehow under the impression that there were differences. 

 

This is solved.

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

  • Who's Online (See full list)

    • There are no registered users currently online
×
×
  • Create New...

Important Information

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