Jump to content

Need packet to wait until runnable is executed before returning packet


Recommended Posts

Posted

Hey, so I was trying to send a packet to the server and get the output and that works the problem is that since I send an addScheduledTask the output from that comes later that the return statement. So basically I have to delay the return statement until my runnable executes on the main thread. Here is some of my code.

 

HandlerRunCommand.java

package com.radar.commandblockmod.packages;

import net.minecraft.client.Minecraft;
import net.minecraft.command.CommandResultStats.Type;
import net.minecraft.command.ICommandManager;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.Entity;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.IThreadListener;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;

public class HandlerRunCommand implements IMessageHandler <RunCommandMessage, IMessage>{

	private MessageContext ctx;

	private int out;
	@Override
	public IMessage onMessage(RunCommandMessage message, final MessageContext ctx) {
		final String command = message.getCommand();
		final int x = message.getxPos();
		final int y = message.getyPos();
		final int z = message.getzPos();
		final String name = message.getName();
		IThreadListener mainThread = (WorldServer) ctx.getServerHandler().playerEntity.worldObj;
		mainThread.addScheduledTask(new Runnable() {
			@Override
			public void run() {
				
				RunCommands onServer = new RunCommands(command,x,y,z,name);
				out = onServer.run();
				System.out.println("Sent "+out);
			}
			
			class RunCommands implements ICommandSender{
				
				public ICommandSender instance;
				private int x,y,z;
				private String nameBlock, command;
				public RunCommands(String command, int x, int y, int z, String name){
					this.x = x;
					this.y = y;
					this.z = z;
					this.command = command;
					this.nameBlock = name;
				}
				
				public int run (){
					ICommandManager icommandmanager = ctx.getServerHandler().playerEntity.worldObj.getMinecraftServer().commandManager;
			    	return icommandmanager.executeCommand(this, this.command);
					
				}
				
				
				@Override
				public String getName() {
					return ctx.getServerHandler().playerEntity.getName();
				}

				@Override
				public ITextComponent getDisplayName() {
					ITextComponent name = new TextComponentString(this.nameBlock);
					return name;
				}

				@Override
				public void addChatMessage(ITextComponent component) {
					
				}

				@Override
				public boolean canCommandSenderUseCommand(int permLevel, String commandName) {
					return true;
				}

				@Override
				public BlockPos getPosition() {
					return new BlockPos(x,y,z);
				}

				@Override
				public Vec3d getPositionVector() {
					return ctx.getServerHandler().playerEntity.getPositionVector();
				}

				@Override
				public World getEntityWorld() {
					return ctx.getServerHandler().playerEntity.worldObj;
				}

				@Override
				public Entity getCommandSenderEntity() {
					return ctx.getServerHandler().playerEntity;
				}

				@Override
				public boolean sendCommandFeedback() {
					return true;
				}

				@Override
				public void setCommandStat(Type type, int amount) {
					
				}

				@Override
				public MinecraftServer getServer() {
					return ctx.getServerHandler().playerEntity.worldObj.getMinecraftServer();
				}
				
			}
		});
		
		return new ReturnCommandOut(x,y,z,out);
	}

}

 

I hope this helps thanks!

Posted

You can't delay the return statement, but you can just send the response packet from the SimpleNetworkWrapper as you would a regular packet.

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 (edited)

 From what you said I should put it after all my other code in the run() class, correct? Where do I send the packet to because I need to specify a player on the client. Would Minecraft.getMinecraft.thePlayer work?

 

Figured it out had to use ctx.getServerHandler().playerEntity

Edited by Radar6255
Solved
Posted

Okay now for another problem that I was having related to this which is when I get the packet that I just received I need to wait until it is sent to my block before further action. Basically I have to wait until the packet has set the data then have my block use that data after it is done to set the comparator output. I need to wait for the packet in this code.

 

 

	@Override
	public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos p_189540_5_) {
		
		if (worldIn.isBlockPowered(pos) & previousState != worldIn.isBlockPowered(pos)){
			TileEntityDiamondCommand tile = (TileEntityDiamondCommand) Minecraft.getMinecraft().theWorld.getTileEntity(pos);
			commandblockmod.network.sendToServer(new RunCommandMessage(tile.getCommand(),pos.getX(),pos.getY(),pos.getZ(),"Diamond Command Block"));
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			out = tile.getOut();
			System.out.println("Update "+out);
			if (out > 0){
				out = 15;
			}else{
				out = 0;
			}
			worldIn.updateComparatorOutputLevel(pos, this);
		}
		previousState = worldIn.isBlockPowered(pos);
	}
	
	
	public boolean hasComparatorInputOverride(IBlockState state)
    {
        return true;
    }

    public int getComparatorInputOverride(IBlockState blockState, World worldIn, BlockPos pos)
    {
		return out;
    }

 

Thanks for all the help and hope that you can help me figure this out also!

Posted

You cannot use Thread.sleep, that will pause the client or server thread completely and stop the game from running for the duration of the sleep. If you want to delay an action by a certain amount of time, you need to schedule a block update or count ticks in a ticking TileEntity or tick event handler.

 

Why is the client telling the server to run a command? The server should be in charge of the game state (e.g. running commands) and send any data necessary for display purposes to the appropriate clients.

 

The client doesn't need to know the comparator output level, it can simply return 0 while the server returns the actual value.

 

You can't store mutable data in fields of your Block class, it's a singleton shared between all occurrences of the block. Mutable data must be stored in the block state or TileEntity.

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

Okay I understand what you are saying, so set the comparator output on the server. How would I do this the closest method I can find to do this is 

ctx.getServerHandler().playerEntity.worldObj.updateComparatorOutputLevel(pos, blockIn);

Which doesn't set the comparator output it just calls the getComparatorInputOverride method in my block that I overrided. I hope this makes sense.

Posted

Override Block#getComparatorInputOverride to return the comparator output level stored in your TileEntity. When this level changes, call TileEntity#markDirty to notify Minecraft that the TileEntity's data has changed (so the chunk containing it won't be skipped when saving the world) and update the output level of adjacent comparators.

 

The client shouldn't be involved in this, it will simply return 0 (the default value of an int) from Block#getComparatorInputOverride if the TileEntity's output level isn't synced (which is fine, since the server's level will be the one used by the comparator).

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.

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

    • https://mclo.gs/46Xf7Sq thanks
    • That seems to have fixed it, thank you!
    • I am having some issues starting an RLCraft server on a minimal install of Debian 12. I have Java installed and I'm able to start the vanilla Minecraft server jar no problem and people can join and play without any issues, as soon as I try to create a new directory with the Forge jar the initial install with the INSTALLER jar works when I use the java command with the --installServer flag, but as soon as I try to start the server using the forge jar that is NOT labelled with installer I get the following error: A problem occurred running the Server launcher.java.lang.reflect.InvocationTargetException         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)         at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)         at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)         at java.base/java.lang.reflect.Method.invoke(Method.java:569)         at net.minecraftforge.fml.relauncher.ServerLaunchWrapper.run(ServerLaunchWrapper.java:70)         at net.minecraftforge.fml.relauncher.ServerLaunchWrapper.main(ServerLaunchWrapper.java:34) Caused by: java.lang.ClassCastException: class jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to class java.net.URLClassLoader (jdk.internal.loader.ClassLoaders$AppClassLoader and java.net.URLClassLoader are in module java.base of loader 'bootstrap')         at net.minecraft.launchwrapper.Launch.<init>(Launch.java:34)         at net.minecraft.launchwrapper.Launch.main(Launch.java:28)         ... 6 more   I have tried using newer versions of Java directly from Oracle as well. Has anybody been successful in starting and running a RLCraft server from the terminal on a Linux machine? I cannot figure out why it doesn't want to work but the vanilla jar works without issue. Thank you in advance!
    • This is my latest attempt :  public class ManaScreen extends Screen { Mana mana = new Mana(); boolean removeManaBar = false; ResourceLocation manaBar = ResourceLocation.fromNamespaceAndPath(RSGArmoury.MOD_ID, "/textures/block/spawnable_arena_wall.png"); public ManaScreen() { super(Component.literal("Mana")); } @Override protected void init() { super.init(); Minecraft.getInstance().setScreen(this); } @Override public boolean isPauseScreen() { return false; } @Override public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) { pGuiGraphics.blit(manaBar, 10, -10, 0, 0, mana.getMana(), 10, mana.getMana(), 10); if (removeManaBar) { this.onClose(); return; } super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick); } public void addManaBar() { removeManaBar = false; Minecraft.getInstance().setScreen(new ManaScreen()); } public boolean removeManaBar() { return removeManaBar = true; } }
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

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