Jump to content

[1.8][SOLVED] getGeneralQuads with ISmartItemModel causing massive lag


coolAlias

Recommended Posts

Some of you may have seen my previous post about getting shields to render correctly - that works perfectly now, but when I played my mod with actual Minecraft rather than via Eclipse, every time I held the shield, especially in first person, it would cause massive client-side lag. This lag does not happen in the development environment.

 

All I'm doing is adding one quad during getGeneralQuads():

 

public class ModelItemShield implements ISmartItemModel
{
private final IBakedModel shieldFront, shieldBack;
public ModelItemShield(IBakedModel shieldFront) {
	this.shieldFront = shieldFront;
	String resourceLocation = shieldFront.getTexture().getIconName().replaceAll("items/", "").replaceAll("#inventory", "").replaceAll("_using", "") + "_back";
	this.shieldBack = Minecraft.getMinecraft().getRenderItem().getItemModelMesher().getModelManager().getModel(new ModelResourceLocation(resourceLocation, "inventory"));
}

@Override
public IBakedModel handleItemState(ItemStack stack) {
	return this;
}

// all other methods just return shieldFront.whateverMethod()

@Override
public List<BakedQuad> getGeneralQuads() {
	List<BakedQuad> quads = shieldFront.getGeneralQuads();
	for (BakedQuad quad : (List<BakedQuad>) shieldBack.getGeneralQuads()) {
		if (quad.getFace() == EnumFacing.NORTH) {
			quads.add(quad);
		}
	}
	return quads;
}

 

 

Nothing out of the ordinary, right? Then in my Item class, I override getModel to return a different model location based on whether the player is using the item or not, but these locations are the same ones already registered:

 

@Override
@SideOnly(Side.CLIENT)
public ModelResourceLocation getModel(ItemStack stack, EntityPlayer player, int ticksRemaining) {
	return (player.isUsingItem() ? models.get(1) : models.get(0));
}

@Override
public String[] getVariants() {
	String name = getUnlocalizedName();
	name = ModInfo.ID + ":" + name.substring(name.lastIndexOf(".") + 1);
	return new String[]{name, name + "_using", name + "_back"};
}

@Override
@SideOnly(Side.CLIENT)
public void registerRenderers(ItemModelMesher mesher) {
	String[] resources = getVariants();
	models = new ArrayList<ModelResourceLocation>(resources.length);
	for (int i = 0; i < resources.length; ++i) { // adding all of the different model locations
		models.add(new ModelResourceLocation(resources[i], "inventory"));
	}
	// Register only the first model as the base resource because there are not actually any sub-items:
	mesher.register(this, 0, models.get(0));
}

 

I have other items that do somewhat similar things, or things I would imagine would be even more resource intensive, but those all work smoothly. Is there any reason that the above code would cause lag only when playing via the actual launcher?

Link to comment
Share on other sites

What is strange is the fact that it doesn't lag inside dev. It should after some time.

 

Btw. you sure getGeneralQuads() isn't mutable?

 

List<BakedQuad> quads = shieldFront.getGeneralQuads();
	for (BakedQuad quad : (List<BakedQuad>) shieldBack.getGeneralQuads()) {
		if (quad.getFace() == EnumFacing.NORTH) {
			quads.add(quad);
		}
	}

Rookies mistake. You are adding n/d number of quads to given model. That is like really bad.

 

Aside from that - I have no idea why it lags only in exported mod.

 

As to "ideas" - if you would do a LOT of changes in Quads in future (because right now you are not). You might wanna cache List of Quads for model.

private HashMap<String, List<BakedQuad>> cachedModels = new HashMap<String, List<BakedQuad>>();

@Override
public List getGeneralQuads()
{
String key = "";
for (String texture : this.textures) // this.textures are links from my ItemStack to models used by sword (sword is put together from few models)
{
	key += texture;
}
List<BakedQuad> combinedQuadsList = this.cachedModels.get(key);

if (combinedQuadsList != null) return combinedQuadsList;

combinedQuadsList = new ArrayList<BakedQuad>();

//Filling list with Quads from different models

this.cachedModels.put(key, combinedQuadsList);
return combinedQuadsList;
}

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

Caching the quads actually occurred to me just as I walked out the door for work after I posted this, and it works perfectly well so that's what I'm doing now. Haven't tested to see if it's any smoother in Minecraft vs. dev environment yet, though.

 

Can you clarify what you mean by n/d quads and 'rookie's mistake' ? I'm not sure what you mean, except perhaps that I forgot to break out of the loop as soon as I found the quad that I wanted.

 

Still, the mystery remains: why would my initial code be so much slower outside the dev environment?

Link to comment
Share on other sites

Cmon bruh :D Arrays are mutable. You are adding n/d (infinite) BakedQuads to array of quads of one model. That will cause MASSIVE lag as soon as your array reaches X size.

 

Do Syso(shieldFront.getGeneralQuads().size()) in your getGeneralQuads() - shit's gonna hit da fan! :D

List<BakedQuad> quads = new ArrayList<BakedQuad>();
quads.addAll(shieldFront.getGeneralQuads());   // Or you know - use copy ;p

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

I didn't realize that it was providing me with a mutable list, as in I expected shieldFront.getGeneralQuads() to always return the same list of quads. Now that you point it out, though, it is indeed obvious.

 

So yeah, you're right, rookie mistake. :P

 

Java and its kooky pass by reference/value stuff always trips me up too. The idea that you can modify the original parameter passed in is obviously powerful, but can actually be a pain when what you want is a copy to modify. I'm sure I've got several of these mistakes lurking in my code...

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

Link to comment
Share on other sites

It's not pass by reference / value that trips me up, I just totally forgot about it - in all my other code I use Lists.newArrayList(parentList), and I just kind of assumed that this was going on in the background somewhere... it didn't even cross my mind as I was looking at my code earlier that I was changing the parent list even though I know very well that's how it works. One of those facepalm moments for sure, and embarrassing to have posted about it :P

Link to comment
Share on other sites

It's not pass by reference / value that trips me up, I just totally forgot about it - in all my other code I use Lists.newArrayList(parentList)

 

Well, forgetting about it is what I mean by "tripping me up". Most old-school programming languages, like C, are true pass by value so you wouldn't have to make a copy since it would be made for you already.

 

Java's way of doing it is definitely powerful/convenient, but you have to do more to not forget about it as it can cause security/scope issues, memory leaks, etc. if not handled properly.

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

Link to comment
Share on other sites

Exactly, Java is always pass by value, though with non-primitive types it passes the value of the memory location rather than a copy of the entire object, thus acting like a C pointer passed by value, so you can always alter whatever is at that memory location, just not the initial reference to that memory location. As we all well know ;)

 

I just completely spaced out about the list and started focusing on other things as the possible cause, exacerbated by the fact that I was working on it in short amounts of time between waking up and going to work. So yeah, I got tripped up lol :P

Link to comment
Share on other sites

In fact, Java is pass by value, if you think about it. There is no "pass by reference". Pass by reference just means you pass the value, but the value is not the object, it's the reference (=pointer) to the object.

 

Yeah, I know the semantic argument ("it's by value but it is the value of the reference"), but for practical purposes Java is passing the pointer which is not expected if you come from another programming language where you need to explicitly indicate when the parameter is a pointer. And further Java's inconsistency with primitive types not passing that way adds further confusion when starting with Java.

 

In addition to this thread, there was another also created today with same problem -- someone not realizing they were modifying the list parameter passed into their method. And CoolAlias (and I know I do) forget about it sometimes. So it is definitely a pain point that you have to learn a few times the hard way.

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

Link to comment
Share on other sites

Did you just actually read it?

Yes, of course.

 

I'm gonna be blatant here and say that an object oriented language is impossible without pass-by-reference and anything else would be completely counter-intuitive.

 

Sure, but old-school languages have an explicit indication for it. C++ has the &, and C (I know it isn't an OO language) can simulate pass by reference (sure it is really passing a pointer by value) with *, and C# has the ref indicator. Java is a surprise for people like me coming from those languages.

 

Anyway, the proper terminology is an almost endless debate so we don't need to repeat that here. I'm just saying I see a lot of people, including me, mistakenly modifying a referenced object passed in and I think Java is more prone to that than other OO languages due to lack of explicitness.

 

I like Java, but it has some built in "laziness" compared to stricter languages.

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

Link to comment
Share on other sites

I never worked with C++. But are you telling me that if I just call a method in C++ all the parameters are cloned by default? :o

Yep.

 

void myfunction(string astring) passes a copy of the string

void myfunction(string &astring) passes a reference to the string, so if you modify astring within myfunction, the caller's string parameter gets modified

 

void myfunction(const string &astring) passes a reference to the string and doesn't let myfunction modify the caller's string parameter.

 

It makes good sense once you get used to it.  Const is very helpful to stop these "oops I modified the object by mistake" errors.

 

Going to Java from C++ is a bit confusing because the behaviour is different for primitives

void myfunction(int a)  // can't modify caller's parameter

vs

void myfunction(MyClass myClass) // can modify caller's parameter

 

I rather miss C++'s good control of lifetime especially constructors and destructors for releasing resources.  But I sure don't miss having to worry about memory allocation all the time.

 

-TGG

 

Link to comment
Share on other sites

But... how is "copy" of an object defined? Is it a deep copy? Whatever, this is getting very off topic. I'm glad that I am not using C++ then. :D

A copy is defined however you decide to implement it for your object, just like 'equals' is defined however you implement it in Java. This is part of what makes C++ so powerful, though I don't miss memory management in the least - automatic memory management, e.g. via JVM, makes life 100x simpler.

 

While Java does have clone() and you can implement a copy() constructor, it isn't quite the same in that you'd have to call the copy constructor yourself, whereas in C++ the copy constructor is called automatically whenever creating a copy of an object.

 

However, as you say, this is going into much more detail than is required for the (solved!) issue. The one time in over a year that it slips by me and we get a whole freaking discussion thread about Java vs. C++ :D

 

EDIT: Here is a good writeup about Java / C++ with respect to this issue.

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.



×
×
  • Create New...

Important Information

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