Jump to content

Recommended Posts

Posted

Hi!

I have been wanting to get into Minecraft modding, but it seems that I might have chosen a bad time to start. From what I can tell, [1.13] brought a lot of structural changes to Minecraft, and forge is doing the same to keep up. At first, I thought I should start with [1.12]. But I really do not want to, as I will be learning outdated workflow and structuring. So I decided to stick with [1.13]...

 

The official Forge documentation looked promising, but it seems to be outdated, which is understandable considering that [1.13] Forge is still in beta. I have tried to find good resources on how to learn [1.13] forge, besides this forum, I have had little success... The forum has at least saved me from using bad learning resources since there appear to be many pitfalls in Minecraft modding... Every time I find a learning resource, I always see the comments saying "this is bad practice", stuff like that. I have found some learning resources for people transitioning to [1.13]. But I have yet to find resources designed for new modders...

 

I think I have programming experience sufficient for getting into this. So in the end, my question is, does anyone have any pointers to some good resources or tips? All help is very much-appreciated! :)

Posted
7 hours ago, SizzleBae said:

Every time I find a learning resource, I always see the comments saying "this is bad practice", stuff like that. 

This is typical software engineering jargon for "I wouldn't do it that way." In this case, if the code works, it works. If you're going into professional programming, then maybe you should take the time to learn how to efficiently write code, but for someone who's learning how to mod Minecraft, it really doesn't matter. As time goes on, you'll eventually learn what practices to use over others.

 

The important thing is that most of this forum will not help you out well unless you come already with code. The people here, and in many other places, do not like to just "hand out code" and will be more likely to help. So start out by working with what you know. You're not expected to have perfect code when you first start.

 

And trust me, if you come here with one error, they're going to point out all of the other ones, too.

 

That's my advice. Chances are one of the "higher ups" here will trump me, because that's what they do. Welcome to Forge.

  • Like 2
  • Haha 2

Follow these rules when talking to me, and we'll get along fine.

1).I know Java fairly well. I don't know as much about modding. They are not the same, don't compare them.

2). I consider myself to always be learning. I make mistakes, you make mistakes. Who doesn't?

3). Insult me, and I will leave the thread. I have a real life, I don't have time to throw petty insults in a Minecraft Modding forum.

 

ModMCdl - Co-Founder and Director of Design for Artemis Game Studios

Posted
7 hours ago, SizzleBae said:

Every time I find a learning resource, I always see the comments saying "this is bad practice", stuff like that.

1. Do not watch tutorials on youtube, as most of them do have bad practices.

Most good tutorials are text-based, here is one for example: https://github.com/TheGreyGhost/MinecraftByExample/

 

2. Be prepared to make mistakes and get criticized. The best part (and perhaps the worst part) of the Forge Forum is that people are blunt in pointing out all the mistakes in your code. This is a great way to learn coding practices, as well as how to use the Forge API properly.

 

3. 1.13.2 is indeed quite new, and there are not enough tutorials out there. I would suggest you to search up 1.13.2 mods on GitHub and learn from their source code.

  • Like 1

Some tips:

Spoiler

Modder Support:

Spoiler

1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code.

2. Always post your code.

3. Never copy and paste code. You won't learn anything from doing that.

4. 

Quote

Programming via Eclipse's hotfixes will get you nowhere

5. Learn to use your IDE, especially the debugger.

6.

Quote

The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it.

Support & Bug Reports:

Spoiler

1. Read the EAQ before asking for help. Remember to provide the appropriate log(s).

2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.

 

 

Posted
4 minutes ago, DavidM said:

1. Do not watch tutorials on youtube, as most of them do have bad practices.

As Mod stated above, these "bad practices" don't matter too much for someone just starting out, as they'll learn how to improve it themselves as time goes on. Most of the text based tutorials rarely actually explain anything, or are outdated, or don't get into the complexities of some of the good YouTube tutorials, like those by McJty.

 

5 minutes ago, DavidM said:

2. Be prepared to make mistakes and get criticized. The best part (and perhaps the worst part) of the Forge Forum is that people are blunt in pointing out all the mistakes in your code. This is a great way to learn coding practices, as well as how to use the Forge API properly.

Not for everyone. Some, like myself, learn better by example, and fixing one issue at a time, not having every single mistake pointed out all at once, in one massive dump. It's why I only use this forum as a last resort. Depending on OP's learning style, your advice could steer them away from making mods.

 

My suggestion, OP, is to look around in general, to figure out what method of learning helps you the most. I learn best from looking at YouTube tutorials by McJty, and looking through other mods' code, as well as Vanilla's. From there, I gather what I need to do to accomplish the task that I set out to do. You may learn in the way David supplied, or you may learn in a way unmentioned in this thread so far. But if you want my personal suggestion: don't mess with 1.13.2 yet. It's buggy, it's broken, and it's a pain to set up. If you want video tutorials, go to YouTube and search up "McJty modding tutorials". He's pretty good at what he does, and generally has good practices. Maybe not perfect, and maybe not universally considered as good, as it's a fairly subjective term, but at least in my experience, many people think his videos are good.

 

I also recommend looking at other mods, and how they do things. Just looking at 1.13.2 mods on GitHub won't give you everything, though, as you do have to do some things that weren't necessary in 1.12.2.

  • Like 1

Gne9eza.png

 

"Be patient with me, because I'm an absolute moron half the time."

Posted (edited)
18 minutes ago, Daring Do said:

these "bad practices" don't matter too much for someone just starting out

Depends. Starting with bad practices might cause people going back and rewriting everything (which normally isn't the desired case). I personally had the painful experience of going "wtf why" as videos promote (terrible) practices like CommonProxy and IHasModel when I first learned to make mods.

 

18 minutes ago, Daring Do said:

Most of the text based tutorials rarely actually explain anything, or are outdated, or don't get into the complexities of some of the good YouTube tutorials, like those by McJty.

AFAIK it is the other way around. McJty's tutorials are indeed good, but the rest of the tutorials on youtube only covers the basics, as well as suggesting "just copy the code and paste them in your code because it worked for me" (i.e. loremaster and harrytalks). Text-based tutorials often go in more depth about concepts like packets, complex item/block behaviors, rendering, and networking.

 

To sum it up, I would recommend to start with video tutorials like McJty's, and move on to text-based ones. It is easy to get lost if you start with text-based ones at first, so you might want to get the feel of modding by watching videos first. It's up to you, really.

Edited by DavidM
  • Like 1

Some tips:

Spoiler

Modder Support:

Spoiler

1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code.

2. Always post your code.

3. Never copy and paste code. You won't learn anything from doing that.

4. 

Quote

Programming via Eclipse's hotfixes will get you nowhere

5. Learn to use your IDE, especially the debugger.

6.

Quote

The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it.

Support & Bug Reports:

Spoiler

1. Read the EAQ before asking for help. Remember to provide the appropriate log(s).

2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.

 

 

Posted
3 minutes ago, DavidM said:

Depends. Starting with bad practices might cause people going back and rewriting everything (which normally isn't the desired case). I personally had the painful experience of going "wtf why" as videos promote (terrible) practices like CommonProxy and IHasModel when I first learned to make mods.

I've literally never heard a reason to not uses IHasModel beyond "it's a terrible idea, use this far more complicated method instead". As for common proxy, I don't think any of the 3 "big" modding tutorial channels even use it for registry. I literally only use it for networking, and have never had a problem with it.

  • Like 2

Gne9eza.png

 

"Be patient with me, because I'm an absolute moron half the time."

Posted
13 minutes ago, Daring Do said:

As Mod stated above, these "bad practices" don't matter too much for someone just starting out, as they'll learn how to improve it themselves as time goes on. Most of the text based tutorials rarely actually explain anything, or are outdated, or don't get into the complexities of some of the good YouTube tutorials, like those by McJty.

Yes they do matter. They break your own mod and other peoples mods. Usually text based tutorials have something at the beginning saying “learn java”. This is important. Most video tutorials say “I’m just starting, this is what worked for me. Do this, this, this and this. Why? Because.”

  • Like 2

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted
Just now, Cadiboo said:

Yes they do matter. They break your own mod and other peoples mods. Usually text based tutorials have something at the beginning saying “learn java”. This is important. Most video tutorials say “I’m just starting, this is what worked for me. Do this, this, this and this. Why? Because.”

I mean, I respect you, Cadiboo, but I've not had a situation where it was the things I've used that many would've considered bad practice breaking other mods, or my own. The most incompatible mod I've made would be Resizing Potion/ArtemisLib, and its issues are with mods that mess with hitboxes or eye height, just like those do. That's less bad practices, and more lack of easy compatibility (which is the whole reason ArtemisLib was made in the first place).

 

As I stated, I've yet to be given an actual reason to not use IHasModel when registering item renders, despite how many people have said they don't recommend using it to others. There's blind acceptance on all sides.

  • Like 1

Gne9eza.png

 

"Be patient with me, because I'm an absolute moron half the time."

Posted (edited)
1 hour ago, Daring Do said:

As I stated, I've yet to be given an actual reason to not use IHasModel when registering item renders, despite how many people have said they don't recommend using it to others. There's blind acceptance on all sides.

https://gist.github.com/Cadiboo/fbea89dc95ebbdc58d118f5350b7ba93

 

Short version: "Every item/block has a model, therefore every single item/block should implements IHasModel".

Well, in that case, since every item/block has a model, then why bother to create another interface for it? Why not just register every item/block's model?

 

Theoretically, IHasModel would not break anything. However, the concept itself is totally pointless, and causes people to write extra useless code. The point of IHasModel is to distinguish those with a model from those without a model; however, everything has a mode.

 

1 hour ago, Daring Do said:

As for common proxy, I don't think any of the 3 "big" modding tutorial channels even use it for registry. I literally only use it for networking, and have never had a problem with it.

The whole point of having proxies is that they run code based on the sides, which is the exact opposite of what a CommonProxy does. Proxies should not have common code. All common code goes in the main mod file.

Edited by DavidM
  • Like 1

Some tips:

Spoiler

Modder Support:

Spoiler

1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code.

2. Always post your code.

3. Never copy and paste code. You won't learn anything from doing that.

4. 

Quote

Programming via Eclipse's hotfixes will get you nowhere

5. Learn to use your IDE, especially the debugger.

6.

Quote

The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it.

Support & Bug Reports:

Spoiler

1. Read the EAQ before asking for help. Remember to provide the appropriate log(s).

2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.

 

 

Posted
1 minute ago, DavidM said:

Short version: "Every item/block has a model, therefore every single item/block should implements IHasModel".

Well, in that case, since every item/block has a model, then why bother to create another interface for it? Why not just register every item/block's model?

SpecialTileEntityRenders.

 

1 minute ago, DavidM said:

The whole point of having proxies is that they run code based on the sides, which is the exact opposite of what a CommonProxy does. Proxies should not have common code. All common code goes in the main mood file.

Clutters the main file. Some people like to keep their nice and neat main file clear of clutter, like myself. While I don't use my proxies for that (though I should definitely use my client proxy for client-side stuff), it has the same effect. It's not really as bad as you want to think it is, since most of the time, mods don't register stuff solely on the server-side. A common proxy setup really just saves space in your main file, for most people. And by the time an aspiring mod dev is making server only mods, they probably have a good idea of how to register it so it's not needed on the client.

  • Like 1

Gne9eza.png

 

"Be patient with me, because I'm an absolute moron half the time."

Posted (edited)
3 minutes ago, Daring Do said:

SpecialTileEntityRenders

I suppose you meant TileEntitySpecialRenderer. How is that related to IHasModel?

 

3 minutes ago, Daring Do said:

Clutters the main file. Some people like to keep their nice and neat main file clear of clutter

Do not abuse inheritance to "just keep my code cleaner". Composition over inheritance.

Edited by DavidM

Some tips:

Spoiler

Modder Support:

Spoiler

1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code.

2. Always post your code.

3. Never copy and paste code. You won't learn anything from doing that.

4. 

Quote

Programming via Eclipse's hotfixes will get you nowhere

5. Learn to use your IDE, especially the debugger.

6.

Quote

The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it.

Support & Bug Reports:

Spoiler

1. Read the EAQ before asking for help. Remember to provide the appropriate log(s).

2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.

 

 

Posted
1 minute ago, DavidM said:

I suppose you meant TileEntitySpecialRenderer. How is that related to IHasModel?

You don't need IHasModel for it. Registering a model for it would just take up time, and is completely unnecessary.

 

2 minutes ago, DavidM said:

Do not abuse inheritance to "just keep my code cleaner". Composition over inheritance.

I'm not. I just like to keep my code clean. Messy code is hard for me to read, and it takes me longer to find an issue in it that code I've kept nice and tidy. It's not just for cleanliness's sake, it's for identifying potential problems easier.

Gne9eza.png

 

"Be patient with me, because I'm an absolute moron half the time."

Posted (edited)
53 minutes ago, DavidM said:

I personally had the painful experience of going "wtf why" as videos promote (terrible) practices like CommonProxy and IHasModel when I first learned to make mods.

 

AFAIK it is the other way around. McJty's tutorials are indeed good, but the rest of the tutorials on youtube only covers the basics (i.e. loremaster and harrytalks)

Ok great so literally the two guys I started watching are the wrong ones. of course. Also, very curious why CommonProxy and IHasModel are bad practice (other than the Hungarian notation there). That is straight from loremaster, and wondering why this is bad practice.  Nevermind, I kept reading. Although from a design patterns perspective I very much agree with a HasModel Interface. And very much disagree with using a CommonProxy lol. You can separate and declutter your main file in much better ways that breaking the purpose of a structure.

 

I am new to mc modding as well. (as of today) I am a professional developer, and want to get my younger brother into coding as well, and I thought a good way to do that would be to teach him how to write his own mc mods. So I need to learn this quickly. I am only focussing on 1.12, not 1.13. Any good text tutorials would be great, as well as any 1.12 mods (github links) with good practices so I can review them. 

Edited by devguydan
I kept reading and found the answer to stuff:)

I hate signatures, they're too distracting

Posted
2 minutes ago, devguydan said:

why CommonProxy and IHasModel are bad practice

Coding style, 1 and 3.

  • Like 2

Some tips:

Spoiler

Modder Support:

Spoiler

1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code.

2. Always post your code.

3. Never copy and paste code. You won't learn anything from doing that.

4. 

Quote

Programming via Eclipse's hotfixes will get you nowhere

5. Learn to use your IDE, especially the debugger.

6.

Quote

The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it.

Support & Bug Reports:

Spoiler

1. Read the EAQ before asking for help. Remember to provide the appropriate log(s).

2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.

 

 

Posted

Thank you so much for your tips, everyone! I am happy to see such an active forum :) I will take you up on the tips concerning looking at other [1.13.2] mod sources and vanilla source. Also, McJty's wiki and youtube tutorial look promising. I will try some different learning methods, and if I absolutely have to, I'll post threads concerning specific problems in the future! Again, thanks a lot for your responses! :)

Posted
5 hours ago, Daring Do said:

SpecialTileEntityRenders.

  1. I'm going to assume you're referring to TileEntityItemStackRenderer, since TileEntitySpecialRenderer has nothing to do with items (it's purely for tile entities).
  2. Assuming you're using a TileEntityItemStackRenderer, it's because your item has some special animation requirements, and you're not using the Forge animation system. Even in that case, your item will need a static model for rendering in a GUI, on the ground, in an item frame, etc.

So no - there is no case for IHasModel, under any circumstances. It does not make your code simpler, it just adds unnecessary cruft. Please don't use it, and please, please, don't suggest that its use is in any way OK.

 

As for your assertion that using a "CommonProxy" avoids cluttering the main file - seriously?  If you're that concerned about clutter, put those "common" methods in their own class.  But not in a proxy class whose sole point is to separate the implementation of client-only and server-only code.

Posted

To add my 2 cents on the issue:

 

IHasModel makes you write redundant code. It's not bad in a sense that it will break compatibility or something, it's bad because you literally write way too much code. For an interface that's suposed to simplify the code it's doing the exact opposite. Consider the following:

A typical IHasModel usage:

class ItemX extends Item implements IHasModel
{
...

	@Override
	void registerModels()
	{
		Mod.proxy.registerModel(this, 0, "inventory");
	}
}

class ClientProxy implements IProxy
{
	...
	
	@Override
	void registerModel(Item i, int meta, string variant)
	{
		ModelLoader.setCustomModelResourceLocation(i, new ModelResourceLocation(i.getRegistryName(), variant));
	}

	@Override
	void registerModel(Block b, int meta, string variant)
	{
		ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(b), new ModelResourceLocation(b.getRegistryName(), variant));
	}
}

@EventBusSubscriber
class ModelHandler
{
	@SubscribeEvent
    public static void onModelRegistry(ModelRegistryEvent event)
    {
    	for (Item i : ModItems.ITEMS)
        {
        	if (i instanceof IHasModel)
            {
            	((IHasModel)i).registerModel();
            }
        }
      
      for (Block i : ModBlocks.BLOCKS)
        {
        	if (i instanceof IHasModel)
            {
            	((IHasModel)i).registerModel();
            }
        }
    }
}

And then you have to duplicate the code in ItemX for every item class you have. While you can have something like ItemBase do that for you you will STILL have to replicate this code for every item that doesn't extend ItemBase, like custom tools or armor or god knows what.

Now compare this to the "correct" approach to the situation:

@EventBusSubscriber
class ModelHandler
{
	@SubscribeEvent
    public static void onModelRegistry(ModelRegistryEvent event)
    {
      	StreamSupport.stream(Item.REGISTRY.spliterator(), false).filter(i -> i.getRegistryName().getResourceDomain().equalsIgnoreCase("modid")).forEach(i -> ModelLoader.setCustomModelResourceLocation(i, 0, new ModelResourceLocation(i.getRegistryName(), "inventory")));
    }
}

..and you are done. No, really, that's it. 

How about items that have damage?

@EventBusSubscriber
    class ModelHandler
    {
        @SubscribeEvent
        public static void onModelRegistry(ModelRegistryEvent event)
        {
            StreamSupport.stream(Item.REGISTRY.spliterator(), false).filter(i -> i.getRegistryName().getResourceDomain().equalsIgnoreCase("modid")).forEach(i -> 
            {
                ModelResourceLocation staticLocation = new ModelResourceLocation(i.getRegistryName(), "inventory");
                if (i.getMaxDamage() == 0)
                {
                    ModelLoader.setCustomModelResourceLocation(i, 0, staticLocation);
                }
                else
                {
                    ModelLoader.setCustomMeshDefinition(i, it -> staticLocation);
                    ModelBakery.registerItemVariants(i, staticLocation);
                }
            });
        }
    }

What about special cases? This is where an interface is acceptable. There, that's all the code you need and even this can be simplified further using streams better than I did. No need to repeat your code for each new item.

 

CommonProxy:

Of course a common proxy isn't going to cause incompatibilities. There are 2 issues with this concept - the first one is the name, the second one - the whole concept. The tutorials on the internet don't explain you what a proxy is or why it is needed, they just blindly tell you - create these classes, do that and this and it will work. The thing is though - a common proxy makes no sense at all if you think about it. Proxies existed to separate sided only code. If your code is common it goes anywhere else but the proxy. Think about it. A network handler wouldn't have a "Common" side - it has a client and a server. Why would a proxy have it?

As for the "clutter" argument - please provide me an example of things you put in your common proxy that would otherwise clutter your mod class. What code do you even have there? 95% of all things were done with event handlers anyway, you rarely needed to do something in your FML lifecycle events.

Additionally I just want to point out that I indeed had helped people on this very forum that had an issue with their code where the whole case of the issue was indeed the CommonProxy. So it's not even harmless.

Also we are talking about 1.13.2. Proxies are gone anyway.

 

As for the whole "it's fine for a beginner, they will learn to do stuff properly later" argument - no, they won't. Look at the most popular mods out there. They still use IHasModel and CommonProxy. And many other things. Clearly those people haven't learned.

  • Like 1
Posted

1. The IHasModel interface can actually be harmful in that it confuses beginners how the model registry actually works.

Examples of which being:

http://www.minecraftforge.net/forum/topic/69344-solved-1122-block-item-texture-missing/

http://www.minecraftforge.net/forum/topic/69142-texture-not-showing/

Both Modder are confused on how the model registry works, and led to double registering/didn't register some model due to the inconsistence usage of IHasModel.

 

2.

9 hours ago, Daring Do said:

I'm not. I just like to keep my code clean.

 

9 hours ago, DavidM said:

Do not abuse inheritance to "just keep my code cleaner".

Again, the point of OOP is not "make my code look nice".

 

3. Never judge a code in the sense "it works so it is fine". Optimizations, readability and conventions matters.

Some tips:

Spoiler

Modder Support:

Spoiler

1. Do not follow tutorials on YouTube, especially TechnoVision (previously called Loremaster) and HarryTalks, due to their promotion of bad practice and usage of outdated code.

2. Always post your code.

3. Never copy and paste code. You won't learn anything from doing that.

4. 

Quote

Programming via Eclipse's hotfixes will get you nowhere

5. Learn to use your IDE, especially the debugger.

6.

Quote

The "picture that's worth 1000 words" only works if there's an obvious problem or a freehand red circle around it.

Support & Bug Reports:

Spoiler

1. Read the EAQ before asking for help. Remember to provide the appropriate log(s).

2. Versions below 1.11 are no longer supported due to their age. Update to a modern version of Minecraft to receive support.

 

 

Posted

IHasModel is fine if it’s used for what it’s meant for, a high level of control over individual item models. For example if your mod has lots of items with many variants and complicated models. It is not fine for beginners as it complicates their code, they don’t need it and they probably don’t understand how it works,  why it’s used or what it does. Therefore it shouldn’t be in tutorials.

@devguydan Some good tutorials include MinecraftByExample, ShadowFacts tutorials, Jabelar’s tutorials and Cubicoder’s tutorials. I’ve also heard that McJty’s tutorials are good, but IIRC they use IHasModel and CommonProxy. I’ve got a list of tutorials and resources at https://github.com/Cadiboo/Example-Mod and I’m also doing my own 1.13.2 tutorials. 

  • Like 1

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted
1 hour ago, Cadiboo said:

IHasModel is fine if it’s used for what it’s meant for, a high level of control over individual item models.

In which case, it should be something like IComplicatedModel or something.

 

Like this:

https://github.com/Draco18s/ReasonableRealism/blob/1.12.1/src/main/java/com/draco18s/hardlib/api/interfaces/IItemWithMeshDefinition.java

 

That lets me go "oh, this is special and needs special treatment" and register its model appropriately.

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.