Jump to content

Kalman98

Members
  • Posts

    6
  • Joined

  • Last visited

Converted

  • Gender
    Undisclosed
  • Personal Text
    I am new!

Kalman98's Achievements

Tree Puncher

Tree Puncher (2/8)

0

Reputation

  1. The code has now been ported to use ReflectionHelper. Thanks @Cardiboo! Here is the new solution (note that I wrote the code for 1.8.9, I believe it is the same or very similar on current versions): Field c01MessageField = ReflectionHelper.findField(C01PacketChatMessage.class, "message", "field_149440_a"); c01MessageField.setAccessible(true); C01PacketChatMessage packet = new C01PacketChatMessage(); try { c01MessageField.set(packet, msg); } catch (IllegalAccessException e) { MyModClass.logger.error("Error setting message length, sticking with 100.", e); packet = new C01PacketChatMessage(msg); } If more examples are needed for any future help-seekers, my full (1.8.9) source code is here: https://gitlab.com/Kalman98/256chat I am sorry to have devolved this thread back to 1.8. The code really is very close to the modern stuff, at least. ?
  2. Thank you very much! I am a bit busy at the moment, but I will look into the ReflectionHelper as soon as I am able to. Thank you again for pointing out the issue with the exceptions... I've never really heard of those particular exceptions before now and kind of glazed over them. I'll be sure to pay more attention to exception handling in the future. I'll post my updated solution code on this thread once it's finished. Thanks again, I appreciate the tips!
  3. I am marking this thread as solved. A friend of mine saw the thread and told me to use reflection. I have heard of this magical "reflection" in many places on the Internet, and I have always veered away from its mysterious workings. However, he gave me a sample of code, and it works perfectly! I am now researching how reflection works for the future. Thanks to anyone who took the time to read my silly, uneducated threads! ? Edit: Oh, fine, I can mention how it was fixed. The solution was to not use my custom packet class, and instead to use the original CPacketChatMessage class. Reflection allowed us to access the private String variable in the class, and from there we were able to set it to any length of String we wanted to! The following is code for the useless 1.12.2 version of the mod. I simply changed the class name to adapt this to 1.8. // code courtesy of @ParkerMc! Thanks a ton! try { // Needs to only be done once Field f = CPacketChatMessage.class.getDeclaredFields()[0]; // Get all the fields of the class including the private one(s). As it is the only field you need index 0 f.setAccessible(true); // Set the field to accessible so you can change it // Create the packet CPacketChatMessage packet = new CPacketChatMessage(); // Set it f.set(packet, "some text"); } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); }
  4. Hello again everyone. Thanks for stopping by! For reasons which I have explained over in this thread, I am creating a mod which extends the maximum amount of characters a player can type and send in chat for the client side only. That thread got closed for being about Forge for 1.8.9, so I have now ported my code to 1.12.2. Which means yes, this code is completely useless in 1.12, but hopefully the knowledge I gain from it will help me fix my 1.8.9 mod, as the code I am working with has not changed much between the versions. With that said, here's what I've done with Forge 1.12.2-14.23.5.2814: 1) Created a custom class, LongGuiChat, extending GuiChat, which is displayed to the player whenever I catch (and cancel) a GuiOpenEvent associated with a GuiChat. 2) Overridden LongGuiChat's sendChatMessage(String, boolean) method, as by default it converts the text to a CPacketChatMessage packet and then sends it off to be sent to the server. In CPacketChatMessage's constructor it truncates the String given to it down to 256 characters, and there is no public method to modify the String outside of this, so I had to override sendChatMessage to get around using that class. I would like to note that I could also subscribe to ClientChatEvent for the same effect here. 3) Created another custom class, LongCPacketChatMessage, which extends CPacketChatMessage and changes nothing. No, seriously, I didn't change anything, I just super call the constructor. In the final code this will have the maximum character limit raised, but that is not relevant right now. So what is the effect of this? Well, in singleplayer, the game works like normal. The game skips over the problematic code and there are no issues. When connected to a multiplayer server, however, things don't go so well. I can connect to a server, open chat, and type in it just fine. When I press Enter, though, I am kicked from the server, given this error message in-game: Internal Exception: io.netty.handler.codec.EncoderException: java.lang.RuntimeException: ConnectionProtocol unknown: net.kalman98.longerchat.LongCPacketChatMessage@3bd493fc ...and a stack trace in the logs. The trace leads to net.minecraft.network.NettyPacketEncoder.encode: protected void encode(ChannelHandlerContext p_encode_1_, Packet<?> p_encode_2_, ByteBuf p_encode_3_) throws IOException, Exception { EnumConnectionState enumconnectionstate = (EnumConnectionState)p_encode_1_.channel().attr(NetworkManager.PROTOCOL_ATTRIBUTE_KEY).get(); if (enumconnectionstate == null) { throw new RuntimeException("ConnectionProtocol unknown: " + p_encode_2_.toString()); } ...with that if statement resolving to true and the RuntimeException being thrown. The trace up to this point is just several classes passing the packet back and forth over and over again. For reference, the EncoderException is thrown in io.netty.handler.codec.MessageToByteEncoder.write(ChannelHandlerContext, Object, ChannelPromise), which is what calls the encode method shown above. I get these errors when I send my own LongCPacketChatMessage, which, as I said, extends CPacketChatMessage and has no code changes. The errors do not occur when I'm using my custom code but the original CPacketChatMessage instead of my LongCPacketChatMessage. I'm not sure how to write my own version of NettyPacketEncoder.encode to accomplish my purposes, and really, I don't think that would be a great idea. By the way, the ByteBuf argument comes from io.netty.handler.codec.MessageToByteEncoder.write(ChannelHandlerContext, Object, ChannelPromise), and the ChannelHandlerContext comes from io.netty.channel.DefaultChannelPipeline.writeAndflush(Object). Any insight, suggestions, opinions, and advice you can give would be appreciated. I'm not even sure what I'm trying to do is actually possible at this point. I make no claims to being incredibly knowledgeable about Java, and I'm sure I've made some mistakes in the process of creating this mod. I would be grateful if you could point out anything I've done incorrectly. And again, sorry about all the text. Thanks in advance for your time!
  5. Hello everyone, thanks for stopping by. I'm working on a mod for Forge 11.15.1.2318. I understand that's very outdated. My goal is to create a client-side-only mod that extends the maximum length you can type in the chat window from 100 characters to 256 characters, as was changed in the 1.11 update for Minecraft. The reasoning for this is that there are multiple Spigot servers which run 1.8.9 with plugins that allow newer versions to connect and, in turn, allow players to send longer messages... but the 1.8.9 client doesn't take advantage of the upgrade, obviously. (oh, and many people play 1.8 on these servers because the combat mechanics are much smoother than the approximations given to the newer clients, but that's a whole other conversation) So with that explanation out of the way, here's what I've done so far: 1) I'm intercepting and cancelling a GuiOpenEvent every time the player tries to open chat, and instead opening my own LongGuiChat, where the maximum character length has been raised to 256. 2) As ClientChatEvent doesn't exist in 1.8, I've instead resorted to modifying the sendChatMessage(String, boolean) method of my LongGuiChat class. This method executes when the player presses Enter in chat, and from there creates a new C01PacketChatMessage and adds it to the Player's send queue. 3) C01PacketChatMessages truncates the String passed to it down to 100 characters in the constructor. There is no publicly accessible method for modifying the String, which left me creating my own LongC01PacketChatMessage, which extends C01PacketChatMessage but has a constructor which truncates messages to 256 characters. At this point I was feeling pretty optimistic about the project so far. I do not claim to be great at Java by any means, so chances are I've already made several obvious mistakes by now... in which case please let me know, I'd love to learn how to improve. But anyway, I tested on a singleplayer world and to my surprise, it actually let me send 256 character messages which even show up in chat. Apparently the server side doesn't actually check the length of the chat packets. I realize now that was just the client adding the message to its own history, not sending it to the client-server. Then I tested on a Spigot server set up as mentioned at the top of this post. I could open chat and type 256 characters, of course, but the moment I hit send (regardless of if I had typed more than 100 characters), I got kicked from the server with an "Internal Exception: io.netty.handler.codec.EncoderException: java.lang.NullPointerException" in the game, and stack traces in the logs. They seem to all lead to the first line of net.minecraft.util.MessageSerializer.encode: protected void encode(ChannelHandlerContext p_encode_1_, Packet p_encode_2_, ByteBuf p_encode_3_) throws IOException, Exception { Integer integer = ((EnumConnectionState)p_encode_1_.channel().attr(NetworkManager.attrKeyConnectionState).get()).getPacketId(this.direction, p_encode_2_); At first I thought it was crashing at the getPacketId call, although the stack trace ends at the line I just posted, so I suppose it never actually made it that far. And I have no idea what would be throwing up a null pointer exception in the line I just posted. On the chance that I'm wrong, though, here's the getPacketId method: public Integer getPacketId(EnumPacketDirection direction, Packet packetIn) { return (Integer)((BiMap)this.directionMaps.get(direction)).inverse().get(packetIn.getClass()); } I assume that if the code does make it that far, it will fail anyway because of the "packetIn.getClass()" call being checked against the BiMap... I have a feeling my extension of C01PacketChatMessage will not be in that map, although I may just be misunderstanding how this works. I should probably also mention that my custom code works 100% perfectly if I just replace my LongC01PacketChatMessage with the original C01PacketChatMessage on the line where I add the message packet to the player's send queue. The issue is, apparently, with my custom packet class, even if I do not change a single thing and simply call super() in the constructor. That's where I'm at now. I'm used to being able to implement every feature I've ever wanted to in Forge, given enough time and research, but at this point I'm wondering if maybe I've chosen something that's beyond the realm of possibilities for once. Do any of you folks here have any suggestions, insights, or advice for this problem? I appreciate any time spent reading this thread, and apologize for the wall of text. Thanks in advance!
  6. Hello Minecraft Forge Forums people, thanks for checking my post. I don't ask for help online unless I absolutely can not figure something out, and right now I absolutely can not figure something out. So here's my problem: I'm modding in 1.8 and have created a block that can remove blocks from the world and same them in an ArrayList. I can also put the blocks back where they came from later. What I can't figure out is how to put tile entities back out again. I can copy the blockstates and tile entities into their own ArrayLists, but I can only place the blocks back out again. Here is some of my code: CustomTileEntity.class: CustomBlock.class: So from CustomTileEntity, this code here is where the problem seems to be: if (worldIn.getBlockState(new BlockPos(x, y, z)).getBlock() != CustomModBlockList.blockCustomBlock && this.blocks.get(index).getBlock() != Blocks.air) worldIn.setBlockState(new BlockPos(x, y, z), this.blocks.get(this.index)); if (worldIn.getBlockState(new BlockPos(x, y, z)).getBlock() != CustomModBlockList.blockCustomBlock && this.tileentities.get(index) != null) { NBTTagCompound nbttagcompound = new NBTTagCompound(); this.tileentities.get(index).writeToNBT(nbttagcompound); worldIn.getTileEntity(new BlockPos(x, y, z)).readFromNBT(nbttagcompound); //worldIn.setTileEntity(new BlockPos(x, y, z), this.tileentities.get(index)); System.out.println("Placing a tile entity at " + x + ", " + y + ", " + z + "! It's " + this.tileentities.get(index)); //System.out.println(this.tileentities.get(index).getTileData()); } What I originally tried here was this: if (worldIn.getBlockState(new BlockPos(x, y, z)).getBlock() != CustomModBlockList.blockCustomBlock && this.blocks.get(index).getBlock() != Blocks.air) worldIn.setBlockState(new BlockPos(x, y, z), this.blocks.get(this.index)); if (worldIn.getBlockState(new BlockPos(x, y, z)).getBlock() != CustomModBlockList.blockCustomBlock && this.tileentities.get(index) != null) worldIn.setTileEntity(new BlockPos(x, y, z), this.tileentities.get(index)); I tried using the code on a chest with items in it, and the chest copied just fine, but when it was placed out again it was empty. So I tried the code that you see in CustomTileEntity above just to see what would happen, and it worked... halfway. The chest full of items copied and placed back out right, and the items stayed in it. However, the items all had a count of 0. I tested it on a couple other tile entities, and it seemed to only copy half of the NBT information on them all. I've gone through all the Vanilla code I can think of that could help, and none of it has. So, do any of you know how I could do this? Also, while I'm here, I might as well mention one other problem I'm having with the same block/tile entity. In the code above, I have a writeToNBT() method and a readFromNBT() method, so when the block gets unloaded it can remember which blocks it picked up. writeToNBT() works fine, like this: @Override public void writeToNBT(NBTTagCompound parentNBTTagCompound) { super.writeToNBT(parentNBTTagCompound); parentNBTTagCompound.setBoolean("open", this.open); NBTTagList nbttaglist = new NBTTagList(); for (int i = 0; i < this.blocks.size(); i ++) { NBTTagCompound nbttagcompound = new NBTTagCompound(); NBTTagCompound nbttagcompound1 = new NBTTagCompound(); nbttagcompound.setInteger("Slot", i); nbttagcompound.setInteger("id", Block.getStateId(this.blocks.get(i))); try { this.tileentities.get(i).writeToNBT(nbttagcompound1); nbttagcompound.setTag("tag", nbttagcompound1); } catch (Exception ex) { } nbttaglist.appendTag(nbttagcompound); } parentNBTTagCompound.setTag("Blocks", nbttaglist); } And here's the readFromNBT() method: // This is where you load the data that you saved in writeToNBT @Override public void readFromNBT(NBTTagCompound parentNBTTagCompound) { super.readFromNBT(parentNBTTagCompound); this.open = parentNBTTagCompound.getBoolean("open"); NBTTagList nbttaglist = parentNBTTagCompound.getTagList("Blocks", 10); for (int i = 0; i < nbttaglist.tagCount(); i ++) { NBTTagCompound nbttagcompound = nbttaglist.getCompoundTagAt(i); this.blocks.add(Block.getStateById(nbttagcompound.getByte("id"))); NBTTagCompound nbttagcompound1 = (NBTTagCompound) nbttagcompound.getTag("tag"); if (nbttagcompound1 != null) { TileEntity tileentity = TileEntity.createAndLoadEntity(nbttagcompound1); this.tileentities.add(tileentity); System.out.println("The id of the loaded tile entity is " + tileentity); } } } I've checked with /blockdata and the boolean, blocks and tile entities save just fine. My problem here though is that the blocks lose their data values. So for instance, diorite loads back as plain stone, and colored wool is just white. I'm using the Block.getStateId() method, and then Block.getStateById() to load it back. Any ideas as to why it loses the data value, and how to fix it? Thanks in advance for your help. I hope I posted this all correctly, seeing as it's my first post on here. If you need more code or details just ask, and I'll give it to you.
×
×
  • Create New...

Important Information

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