Jump to content

[1.7.10] How Packet Handlers work?


yoshiquest

Recommended Posts

For the next step of my library, I need to be able to implement a Packet Handler. To make things simple, I'd like to simply make it send NBT data exclusively back and forth (I already have a converter for NBT data that makes it easier to deal with).

 

The main question is: What do I need to do to create a Packet Handler (classes involved, etc.)? Why are Packet Handlers used in the first place?

 

I know there's some tutorials out there, but the tutorial I usually use involved using another library to accomplish this (and a library using another library just gets annoying). And I've looked at some of the other ones, but they're kinda more general than I'd like, and also kinda gave me a headache. I just need an example of a simple Packet Handler that sends NBT data back and forth.

 

I have a feeling this is going to be my hardest challenge yet.

Currently working on a mod to provide support for the Clojure programming language in Minecraft, check it out here.

Link to comment
Share on other sites

The reason why you need packet handlers is because this is a networked game consisting of code running on a server and other code running on clients. Even when playing single player it uses networking to communicate between the code running for server and client.

 

You shouldn't need any packet libraries or anything. Forge already provides the simple network wrapper. I have a tutorial here (which also references other good tutorials): http://jabelarminecraft.blogspot.com/p/minecraft-forge.html.

 

 

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

Link to comment
Share on other sites

Ok, after a lot of reading I... think I get it now. Let me try to summarize how I think it works to see if I'm understanding this.

 

Packets themselves are basically wrappers that implement IMessage. They wrap around a message, providing a way to convert to and from bytes.

 

The Handler takes care of what happens when a message is received. I'm guessing an example would be detecting who received the message, then calling a function on them with the message as an argument.

 

For each mod, a new Channel needs to be created, which these packets are sent along, via the NetworkRegistry, and stored in a field of type SimpleNetworkWrapper.

 

For each type of message you make, the class needs to be registered via your network's registerMessage method. It takes the handler CLASS for it first, which is called upon receiving a message. Then it takes the message wrapper's CLASS (aka packet or implementation of IMessage). And after that it takes a unique ID and the side (client or server) that receives it.

 

These now-registered packets can then be sent by calling the network's .sendTo/.sentToServer/etc. method, with an INSTANCE of the message.

 

Ok, so in order to do what I wish to do, I have to create a new class for the wrapper (packet), of which in my case will only take the nbt data, and convert back and forth between that and bytes. I'd also have to create a new class for the handler in order to tell it what to do, which in my case will call a function of the user's choice. Finally I'd have to create a public static field to store the network itself in.

 

Did I get that right?

 

The reason I'm making this is because I'm creating an API to support another programming language (Clojure), and I needed to know how to do this in order to wrap around it in a Clojure-friendly way.

Currently working on a mod to provide support for the Clojure programming language in Minecraft, check it out here.

Link to comment
Share on other sites

Yep, that is all right.

 

Regarding the message payload:The bytes in the packet are in a ByteBuf which has methods for writing and reading various data types and there is a class called ByteBufUtils which allows you to write and read NBT and such. So you handler takes the ByteBuf and reads out the data types in the same order you wrote them in and stores them in custom fields that you can then work with.

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

Link to comment
Share on other sites

Is it alright to use one class as both the Packet and the Handler (aka have it implement both IMessage and IMessageHandler)? It might seem like bad practice in java, but I'm not using java, and just want to know if it's viable.

Currently working on a mod to provide support for the Clojure programming language in Minecraft, check it out here.

Link to comment
Share on other sites

It is theoretically possible, but it can lead to a lot of bugs, since all the fields that you have as payload in your message class will also be available in the message handler instance, but will always be meaningless there.

 

The forum is full of people having this exact issue, where they in implement

IMessage

and

IMessageHandler

on the same class and then accidentally use the

this

reference (the

IMessageHandler

) instead of

message

when accessing the message fields. And then they wonder why they are only getting

null

back.

 

Do the implemented methods from IMessageHandler need to be static? I saw in your example you used an internal static class, which is why I'm wonder if it needs to be static to work.

Currently working on a mod to provide support for the Clojure programming language in Minecraft, check it out here.

Link to comment
Share on other sites

If you implement the

IMessageHandler

as an inner class then yes, the class must be marked

static

. Otherwise instances of the message handler class will always have an instance of the message class attached (which is passed via a hidden constructor parameter). You (and FML!) cannot construct new instances of the message handler without a message argument if you do that, and that will break FML.

 

But if you're not using an inner class, but just implementing both interfaces (and being careful with the passed arguments), then it's fine, right?

 

If I can get this thing to work.... I might be able to make the simplest implementation of a network yet.

 

EDIT: I just realized some other problems with my setup, so nevermind. I'll just make a class for each using the darn messy gen-class instead. :P

Currently working on a mod to provide support for the Clojure programming language in Minecraft, check it out here.

Link to comment
Share on other sites

What weird language is that that you are using? :o

 

I'm using Clojure. If you wanna know how inter-op/clojure data in general works, just check out this road map (mainly used for inter-op exclusively).

 

Clojure is actually a beautiful language, it's just that things become a bit messy once you get into inter-op with java. Because Clojure is a functional programming language (focusing on function operations and immutability), and Java is an Object Oriented Language, inter-op becomes really difficult due to the differences in styles. Luckily, Clojure provides everything you need to make a library in this case (macros, aka clojure code that returns clojure code at compile time, letting you change the syntax, do things at compile time, etc).

 

forge-clj is actually coming along pretty well though! You can view the project in the Mods section here, or just go straight to the github via the link in my signiture. I've managed to compress many complicated processes into simple and clean clojure code so far, so it's nice.

Currently working on a mod to provide support for the Clojure programming language in Minecraft, check it out here.

Link to comment
Share on other sites

Scala tries to be the end-all-be-all solution, which presents a lot of problems, especially since functional programming is more or less tacked on at the end.

 

Honestly? The weirdness is worth it. It's an EXTREMELY powerful language when you get used to it. If you want an example of how powerful it can be if used properly, just look at Walmart's implementation of Clojure for their website, database, etc. And see it get through without a scratch.

 

If you (or anyone else reading this) decides to try learning Clojure, my main piece of advice is to FORGET Java. It uses a completely different (and in my opinion, superior) mindset. As such, forget about Objects, Interfaces, and Methods while reading about Clojure (at least until you need to do inter-op). And I'd also recommend Clojure for the Brave and True, it has a nice sense of humor and yet also explains things quite well (and you can ignore the section on Emacs, there's a lot of options for coding environments).

 

Anyways, on the topic at hand, I think I've just implemented the network system, I just need to test it now. Thanks for the help.

 

EDIT: Just thought I'd say that I did it. You can now create a simple network and such, with only about 5 lines of code.

Currently working on a mod to provide support for the Clojure programming language in Minecraft, check it out here.

Link to comment
Share on other sites

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

    • Hi, I want to make a client-only mod, everything is ok, but when I use shaders, none of the textures rendered in RenderLevelStageEvent nor the crow entity model are rendered, I want them to be visible, because it's a horror themed mod Here is how i render the crow model in the CrowEntityRenderer<CrowEntity>, by the time i use this method, i know is not the right method but i don't think this is the cause of the problem, the renderType i'm using is entityCutout @Override public void render(CrowEntity p_entity, float entityYaw, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight) { super.render(p_entity, entityYaw, partialTick, poseStack, bufferSource, packedLight); ClientEventHandler.getClient().crow.renderToBuffer(poseStack, bufferSource.getBuffer(ClientEventHandler.getClient().crow .renderType(TEXTURE)), packedLight, OverlayTexture.NO_OVERLAY, Utils.rgb(255, 255, 255)); } Here renderLevelStage @Override public void renderWorld(RenderLevelStageEvent e) { horrorEvents.draw(e); } Here is how i render every event public void draw(RenderLevelStageEvent e) { for (HorrorEvent event : currentHorrorEvents) { event.tick(e.getPartialTick()); event.draw(e); } } Here is how i render the crow model on the event @Override public void draw(RenderLevelStageEvent e) { if(e.getStage() == RenderLevelStageEvent.Stage.AFTER_ENTITIES) { float arcProgress = getArcProgress(0.25f); int alpha = (int) Mth.lerp(arcProgress, 0, 255); int packedLight = LevelRenderer.getLightColor(Minecraft.getInstance().level, blockPos); VertexConsumer builder = ClientEventHandler.bufferSource.getBuffer(crow); Crow<CreepyBirdHorrorEvent> model = ClientEventHandler .getClient().crow; model.setupAnim(this); RenderHelper.renderModelInWorld(model, position, offset, e.getCamera(), e.getPoseStack(), builder, packedLight, OverlayTexture.NO_OVERLAY, alpha); builder = ClientEventHandler.bufferSource.getBuffer(eyes); RenderHelper.renderModelInWorld(model, position, offset, e.getCamera(), e.getPoseStack(), builder, 15728880, OverlayTexture.NO_OVERLAY, alpha); } } How i render the model public static void renderModelInWorld(Model model, Vector3f pos, Vector3f offset, Camera camera, PoseStack matrix, VertexConsumer builder, int light, int overlay, int alpha) { matrix.pushPose(); Vec3 cameraPos = camera.getPosition(); double finalX = pos.x - cameraPos.x + offset.x; double finalY = pos.y - cameraPos.y + offset.y; double finalZ = pos.z - cameraPos.z + offset.z; matrix.pushPose(); matrix.translate(finalX, finalY, finalZ); matrix.mulPose(Axis.XP.rotationDegrees(180f)); model.renderToBuffer(matrix, builder, light, overlay, Utils .rgba(255, 255, 255, alpha)); matrix.popPose(); matrix.popPose(); } Thanks in advance
    • Here's the link: https://mclo.gs/7L5FibL Here's the link: https://mclo.gs/7L5FibL
    • Also the mod "Connector Extras" modifies Reach-entity-attributes and can cause fatal errors when combined with ValkrienSkies mod. Disable this mod and continue to use Syntra without it.
    • Hi everyone. I was trying modify the vanilla loot of the "short_grass" block, I would like it drops seeds and vegetal fiber (new item of my mod), but I don't found any guide or tutorial on internet. Somebody can help me?
    • On 1.20.1 use ValkrienSkies mod version 2.3.0 Beta 1. I had the same issues as you and it turns out the newer beta versions have tons of unresolved incompatibilities. If you change the version you will not be required to change the versions of eureka or any other additions unless prompted at startup. This will resolve Reach-entity-attributes error sound related error and cowardly errors.
  • Topics

×
×
  • Create New...

Important Information

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