Jump to content

Recommended Posts

Posted

Got a quick question. I know using Thread.Sleep or anything as such causes minecraft to pause aswell as it is single threaded, which is obviously a nuisance...

Is there anyway to insert a delay between executing lines of code WITHOUT pausing minecraft?

 

For example:

 

KeyPresser.KeyPress(KeyEvent.VK_W);

//WAIT 1 SECOND WITHOUT PAUSING MINECRAFT

KeyPresser.KeyRelease(KeyEvent.VK_W);

 

 

I do have a tick handler class, but not really sure how this would help in this case...

Thanks in advance!

Posted

You could run the code in a separate thread and pause execution of that thread:

 

new Thread()
{
    @Override
    public void run()
    {
        //some code here.
        Thread.Sleep(1000);
        //more code here.
    }
}.start();

Posted

Yes, you can, but only if you understand multithreading well. For example you cannot interact with Minecraft at all from this separate thread, for the most part.

 

I did not know that. You can't, for example, interact with a TileEntity from a separate thread?

Posted

You have to exit out of the method, count ticks in a tick handler and then when you have counted the right amount of ticks (20 ticks = 1 second) you run the next part of the code.

 

Ok, how would I go about exiting the method and then returning at the same point?

I'm guessing i'd have to go into my TickHandlerClass and then run a command to exit the EventHandlerClass(where I'm using the Robot KeyPresser), and then run a command to re enter at the same point?

Posted

Yes, you can, but only if you understand multithreading well. For example you cannot interact with Minecraft at all from this separate thread, for the most part.

 

I did not know that. You can't, for example, interact with a TileEntity from a separate thread?

 

TileEntities exist in the world, so no.

 

Ok, how would I go about exiting the method and then returning at the same point?

 

It's called "two separate functions."

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

Does the game crash if you do that?

 

That entirely depends on a race condition and exactly what you're doing. But yes, it would, eventually. With a ConcurrentModificationException.

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

Yes, you can, but only if you understand multithreading well. For example you cannot interact with Minecraft at all from this separate thread, for the most part.

 

I did not know that. You can't, for example, interact with a TileEntity from a separate thread?

 

TileEntities exist in the world, so no.

 

Ok, how would I go about exiting the method and then returning at the same point?

 

It's called "two separate functions."

 

I'm pretty sure I have an idea of what I'm meant to do, just not how to do it...

 

In simple terms, in class 1 I would have:

 

KeyPresser.keyPress(KeyEvent.VK_W);

RUN METHOD IN CLASS 2

KeyPresser.keyRelease(KeyEvent.VK_W);

...

 

And the method in Class 2:

 

thread.sleep(20) (FOR ONE SECOND)

 

 

Is this how I would do it? and how would this look in code, I'm new to JAVA, appologies. If this is anything like Python, i'd make a function containing code and then call that function but its not as simple as that in java I'm gathering...

 

 

 

Posted

That's not at all how Thread.sleep works. Thread.sleep, as the name implies blocks the entire thread for the duration.

 

As diesieben07 said, you have to use a tick handler and count the number of ticks that have passed to determine the amount of time that has passed.

Don't make mods if you don't know Java.

Check out my website: http://shadowfacts.net

Developer of many mods

Posted

That's not at all how Thread.sleep works. Thread.sleep, as the name implies blocks the entire thread for the duration.

 

As diesieben07 said, you have to use a tick handler and count the number of ticks that have passed to determine the amount of time that has passed.

 

But I don't need to determine the amount of time that's passed? I just need to insert a delay between two commands running which doesn't pause the entire game, I don't really understand how a tick handler will help, don't really understand how ticks work, all I know is minecraft tick's 20 times per second, I'm guessing its obvious that i'm quite new but what you're saying makes little sense to me. How would i code a delay without pausing minecraft?

Posted

Intro:

Minecraft runs on 2 (+2 network) threads (http://mcforge.readthedocs.org/en/latest/concepts/sides/), you want to do stuff on client (bot?).

Each thread tick 20 times, 1tick = 50ms.

Aside from partialTicks (rendering only), this is "planck time" (smallest) in Minecraft world.

 

What to do?

Make scheduler.

1. @SubscribeEvent to ClientTickEvent.

- Check for event.phase (pick one).

2. Create static Queue or List or whatever (its important it's elements are ordered by inserting).

- You will be throwing "commands" to that list.

- Those "commands" will be calls to execute specific key.

3. Make ClientTickEvent execute one command at time from top of ordered list above every few ticks.

- 10 ticks = 0.5sec like you want.

- You want to do:

int ticks;
Queue commands;
ClientTickEvent
{
    if (ticks % 10 && !commands.isEmpty)
    {
       commands.getFromTop().call();
       commands.removeFromTop();
    }
    ++ticks;
}

4. Throw "commands" from wherever you want (client thread) into queue.

1.7.10 is no longer supported by forge, you are on your own.

Posted
But I don't need to determine the amount of time that's passed?

 

Surprise, that's what a tick handler is for.

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

That's not at all how Thread.sleep works... you have to use a tick handler...

 

I don't really understand how ticks work...

 

You said yourself that you want Minecraft to continue, so you must allow it to continue ticking. However, your thinking has been at the (virtual) machine stop level, which is the wrong level of thinking.

 

I'm reminded of how DOS programmers stumbled when they first encountered the Windoze "message loop". It took a while to wrap one's head around the idea that one's "program" was really just one subroutine among many being called repeatedly by the real master program. In that case it was the OS, but in this case, it's Minecraft.

 

Since your method may not hog the CPU all to itself for several seconds of GUI interaction, you must write code that can run in a series of blinks, somehow storing intermediate results for later resolution. In effect, Minecraft keeps ticking right along, but some sequence of your actions is spread out over time.

 

That's what tick handlers do. Your logic wakes up, looks at the world and its own preserved thoughts, increments tick counters, make decisions, take actions, stores (or wipes) data for next time, and then exits to allow the rest of the program to continue.

The debugger is a powerful and necessary tool in any IDE, so learn how to use it. You'll be able to tell us more and get better help here if you investigate your runtime problems in the debugger before posting.

Posted

Intro:

Minecraft runs on 2 (+2 network) threads (http://mcforge.readthedocs.org/en/latest/concepts/sides/), you want to do stuff on client (bot?).

Each thread tick 20 times, 1tick = 50ms.

Aside from partialTicks (rendering only), this is "planck time" (smallest) in Minecraft world.

 

What to do?

Make scheduler.

1. @SubscribeEvent to ClientTickEvent.

- Check for event.phase (pick one).

2. Create static Queue or List or whatever (its important it's elements are ordered by inserting).

- You will be throwing "commands" to that list.

- Those "commands" will be calls to execute specific key.

3. Make ClientTickEvent execute one command at time from top of ordered list above every few ticks.

- 10 ticks = 0.5sec like you want.

- You want to do:

int ticks;
Queue commands;
ClientTickEvent
{
    if (ticks % 10 && !commands.isEmpty)
    {
       commands.getFromTop().call();
       commands.removeFromTop();
    }
    ++ticks;
}

4. Throw "commands" from wherever you want (client thread) into queue.

Right, this is starting to make sense... I add commands to a queue which is handled by another class on each client tick, the commands i'd add in order would be like press key D, followed by release key D and one line would be executed for each client tick, right?

 

I added this code to a separate class but its coming up with errors, possibly due to a different version?

 

int ticks;

Queue commands;

 

@SubscribeEvent

public void onClientTick(TickEvent.ClientTickEvent event){

if(ticks % 10 && !commands.isEmpty()){  *Line doesn't work*

commands.getFromTop().call; *GET FROM and REMOVE FROM top not recognized*

commands.removeFromTop();

}

++ticks;

 

}

Posted

Right, this is starting to make sense... I add commands to a queue which is handled by another class on each client tick, the commands i'd add in order would be like press key D, followed by release key D and one line would be executed for each client tick, right?

 

I added this code to a separate class but its coming up with errors, possibly due to a different version?

 

int ticks;

Queue commands;

 

@SubscribeEvent

public void onClientTick(TickEvent.ClientTickEvent event){

if(ticks % 10 && !commands.isEmpty()){  *Line doesn't work*

commands.getFromTop().call; *GET FROM and REMOVE FROM top not recognized*

commands.removeFromTop();

}

++ticks;

 

}

 

What Ernio posted was pseudocode, you need to find the appropriate methods in the

Queue

interface yourself.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Posted

You can't use a

while

loop to check passage of time.  They explicitly do not exit (forcing thread halt) until their conditions are met, in this case, the release of the pressed key.

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 can't use a

while

loop to check passage of time.  They explicitly do not exit (forcing thread halt) until their conditions are met, in this case, the release of the pressed key.

That makes perfect sense, but that's the point in the break; command right? To exit the loop while the condition is still invalid?

Posted

Dude.

Seriously.

All of that code runs in a single tick.  It doesn't actually "wait" (even if real-time it takes it four seconds).

That's why the game appears to freeze.

 

In order for you to perform an operation over time you need to count ticks.

 

Open up TileEntityFurnace and look at the

burnTime

variable.  Look at what it does.

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

Dude.

Seriously.

All of that code runs in a single tick.  It doesn't actually "wait" (even if real-time it takes it four seconds).

That's why the game appears to freeze.

 

In order for you to perform an operation over time you need to count ticks.

 

Open up TileEntityFurnace and look at the

burnTime

variable.  Look at what it does.

 

burnTime is the amount of ticks it keeps the furnace burning for now it makes more sense, basically I need some sort of pressTime that does the same thing as burn time but for the key press.

 

Can you explain to me what 'counting ticks' actually means, how you do it, and how it will help me to perform the action over time?

 

I can sense I'm getting a little tedious, but I genuinely am grateful for the help just not really understanding how I can do this in my mod quite yet..

Posted

basically I need some sort of pressTime that does the same thing as burn time but for the key press.

 

Bingo.

 

Can you explain to me what 'counting ticks' actually means

 

@EventHandler
public void onTick(TickEvent event) {
    //a tick happened
    //increment counter
    pressTime++;
}

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

basically I need some sort of pressTime that does the same thing as burn time but for the key press.

 

Bingo.

 

Can you explain to me what 'counting ticks' actually means

 

@EventHandler
public void onTick(TickEvent event) {
    //a tick happened
    //increment counter
    pressTime++;
}

 

So maybe something like this could work?:

 

@EventHandler

public void onTick(TickEvent event) {

    //a tick happened

    //increment counter

    pressTime++;

}

 

 

(Psuedocode)

@SubscribeEvent

on key press

if key is harvest key

pressTime = 0

press key w

if pressTime = 10{

    release key w

    pressTime = 0

}

 

Having the above in a while loop*

Posted
Having the above in a while loop*

 

*Defeats the whole purpose.

 

DO NOT USE A LOOP ANYWHERE IN YOUR CODE.  The tick event handler IS the loop.

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.

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.