Jump to content

Recommended Posts

Posted

(I apologize for all the questions this week... I'm sure things will "click" for me soon, and later when I know what I'm doing, I promise to repay my karma by helping newbies whenever I can!)

 

I have a ClientChatEvent handler from which I wish to change the world — for starters, just clear a block to air.  I have no trouble telling what block the user is looking at, and I can call world.setBlockToAir and it clears the block locally... but it fails to do an update (so water doesn't flow into the new hole, for example), and of course this is a blatant siding violation.

 

 

But though I think I understand the concept of sides — and the rule that any world changes need to happen on the logical server — I'm still clueless as to how to actually do that.  One post I found here recommended wrapping any state changes in if (!world.isRemote), but when I do that, then world.setBlockToAir simply doesn't get called at all.   Current, non-working code looks like this:

 	@SubscribeEvent
 	public static void onChat(ClientChatEvent event) {
 		String msg = event.getMessage();
 		if (msg.equals("/evanesco")) {
 			// Vanish whatever we're pointed at
 			RayTraceResult trace = PointingAt();   // (helper method, don't worry about it)
 			if (trace == null || trace.typeOfHit == RayTraceResult.Type.MISS) {
 	 			SendStatus("§6Whiff!§r");	 				
 			} else {
 				BlockPos pos = trace.getBlockPos();
                // sort-of works, but is a siding violation, and doesn't update water etc:
				//Minecraft.getMinecraft().world.setBlockToAir(pos);
                // attempt to do it more properly:
 				WorldClient world = Minecraft.getMinecraft().world; 
                if (!world.isRemote) {
                		world.setBlockToAir(pos);
                		System.out.println("Set block to air on the server");
                } else {
                		// (this is what actually happens in my tests)
                		System.out.println("Not on the server, so doing nothing");
                }
                world.playSound(Minecraft.getMinecraft().player, pos, SoundEvents.ENTITY_ENDERMEN_TELEPORT, SoundCategory.PLAYERS, 1.0F, 1.0F);
 				SendStatus("§5Shoop!§r");
 			}
 			event.setCanceled(true);
 		}
 	}

 

Can anyone point me in the right direction for going from my client-side event detection, to changing block states on the server?

Posted
39 minutes ago, diesieben07 said:

But since you just obtained the client world one line earlier

The key bit there being WorldClient world

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 all makes great sense.  And it's good to know about registering commands — while I'm currently just doing quick hacks to explore various bits of the API, I may as well do them properly!

 

Posted (edited)
13 hours ago, JoeStrout said:

(I apologize for all the questions this week... I'm sure things will "click" for me soon, and later when I know what I'm doing, I promise to repay my karma by helping newbies whenever I can!)

 

I have a ClientChatEvent handler from which I wish to change the world — for starters, just clear a block to air.  I have no trouble telling what block the user is looking at, and I can call world.setBlockToAir and it clears the block locally... but it fails to do an update (so water doesn't flow into the new hole, for example), and of course this is a blatant siding violation.

 

 

But though I think I understand the concept of sides — and the rule that any world changes need to happen on the logical server — I'm still clueless as to how to actually do that.  One post I found here recommended wrapping any state changes in if (!world.isRemote), but when I do that, then world.setBlockToAir simply doesn't get called at all.   Current, non-working code looks like this:


 	@SubscribeEvent
 	public static void onChat(ClientChatEvent event) {
 		String msg = event.getMessage();
 		if (msg.equals("/evanesco")) {
 			// Vanish whatever we're pointed at
 			RayTraceResult trace = PointingAt();   // (helper method, don't worry about it)
 			if (trace == null || trace.typeOfHit == RayTraceResult.Type.MISS) {
 	 			SendStatus("§6Whiff!§r");	 				
 			} else {
 				BlockPos pos = trace.getBlockPos();
                // sort-of works, but is a siding violation, and doesn't update water etc:
				//Minecraft.getMinecraft().world.setBlockToAir(pos);
                // attempt to do it more properly:
 				WorldClient world = Minecraft.getMinecraft().world; 
                if (!world.isRemote) {
                		world.setBlockToAir(pos);
                		System.out.println("Set block to air on the server");
                } else {
                		// (this is what actually happens in my tests)
                		System.out.println("Not on the server, so doing nothing");
                }
                world.playSound(Minecraft.getMinecraft().player, pos, SoundEvents.ENTITY_ENDERMEN_TELEPORT, SoundCategory.PLAYERS, 1.0F, 1.0F);
 				SendStatus("§5Shoop!§r");
 			}
 			event.setCanceled(true);
 		}
 	}

 

Can anyone point me in the right direction for going from my client-side event detection, to changing block states on the server?

Comments for feedback:

1. Since you are handling block replacements, you need to use ServerChatEvent instead of ClientChatEvent.

2. You can just make a new command and register it. execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException method is executed in server-side.

3. Don't use Minecraft.getMinecraft() in server-side once you get the server to run the code, this might crash you or cause errors if on a server.

4. Don't use WorldClient, simply use playerIn.world once you have EntityPlayerMP through CommandBase in execute(...) method.

 

Follow these tips and you'll be set!

...
        @Override
        public String getCommandName()
        {
            return "evanesco";
        }

	@Override
 	public void execute(MinecraftServer serverIn, ICommandSender senderIn, String[] args) throws CommandException
    	{
      	    EntityPlayer playerIn = CommandBase.getCommandSenderAsPlayer(senderIn);
 	    RayTraceResult trace = PointingAt();
 			
 	    if (trace == null || trace.typeOfHit == RayTraceResult.Type.MISS) 
 	    {
 	 	SendStatus("§6Whiff!§r");	 				
 	    } 
 	    else 
 	    {
 		BlockPos pos = trace.getBlockPos();
 			
 		World worldIn = playerIn.world;
            	worldIn.setBlockToAir(pos);
            	worldIn.playSound(/* if you want sound to play for all players */ null /* else if only for this player, playerIn */, pos, SoundEvents.ENTITY_ENDERMEN_TELEPORT, SoundCategory.PLAYERS, 1.0F, 1.0F);
 			
 		SendStatus("§5Shoop!§r");
		CommandBase.notifyCommandListener("commands.evanesco.success", new Object[0]);
            }
    	}
...

I stripped the code for you, if you wish to use it, you may.

 

I hope I helped. Happy modding!

Edited by Differentiation
  • Like 1
Posted
9 hours ago, Differentiation said:

What is in this method? Please show the contents.

Thanks!

Sure, I'd be delighted to actually be on the helpful end around here for a change.  :)

	// Get a RayTraceResult describing whatever the player's looking at (within 32 blocks).
	private static RayTraceResult PointingAt(boolean stopOnLiquid) {
		WorldClient world = Minecraft.getMinecraft().world;
		EntityPlayerSP player = Minecraft.getMinecraft().player;
		Vec3d posVec = new Vec3d(player.posX, player.posY + player.getEyeHeight(), player.posZ);
		Vec3d lookVec = player.getLookVec();
		return world.rayTraceBlocks(posVec, posVec.add(lookVec.scale(32)), stopOnLiquid);
	}

 

  • Like 1

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



×
×
  • Create New...

Important Information

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