I have a custom mob named Trog that has custom animations. I'm trying to activate those animations from custom AI classes, but it's not working.
Here's the catch - if I activate the animations from update() in EntityTrog, everything works fine. It's only when I try to activate the animations from elsewhere that I have issues.
I suspect I'm running into a pass-by-value issue, where the entity whose animations I'm trying to activate is actually a copy of the real entity. Except then nothing makes sense in any of the vanilla AI classes, because they do the same thing.
Here's my code. I could use some help troubleshooting this.
I'm not familiar with MCAnimator, does the animation handler automatically sync the animation state to all clients watching the entity? You may need to manually trigger the syncing or sync it yourself.
Entity#update is called from both the logical client (whose copy of the entity is rendered) and server, but AI tasks are only run on the logical server.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
I was able to create a stop-gap solution by changing the type of "entity" from IMCAnimatedEntity to EntityTrog. Information about EntityTrog's animationHandler seems to have been getting lost when it was cast to the parent type. (EntityTrog extends IMCAnimatedEntity)
However, I want to be able to use this AI class for more than just EntityTrog. GetAnimationHandler() exists in IMCAnimatedEntity, and is overridden in EntityTrog, but it seems like casting EntityTrog to IMCAnimatedEntity is preventing it from working.
I tried moving the initialization of animationHandler to IMCAnimatedEntity (and then calling this.animationHandler=new AnimationHandlerTrog() in EntityTrog), but that didn't work either.
I was able to create a stop-gap solution by changing the type of "entity" from IMCAnimatedEntity to EntityTrog. Information about EntityTrog's animationHandler seems to have been getting lost when it was cast to the parent type. (EntityTrog extends IMCAnimatedEntity)
However, I want to be able to use this AI class for more than just EntityTrog. GetAnimationHandler() exists in IMCAnimatedEntity, and is overridden in EntityTrog, but it seems like casting EntityTrog to IMCAnimatedEntity is preventing it from working.
I don't see how that's possible if you're passing the same value and calling the same method. When you call a method, Java uses the implementation from the value's actual class, regardless of the variable's type.
Can you think of a way around this?
The AI task should work for any class that extends EntityLiving (required by the super class) and implements IMCAnimatedEntity (required by your class), so create a generic type argument for the class with these bounds and use it as the type of the field and the constructor parameter. Remove the IMCAnimatedEntity/EntityTrog parameter from the constructor.
I'm not sure if this will fix your issue (I don't know what's causing it), but it ensures that both your class and the super class are acting on the same entity.
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Okay, so I decided to move the actual calls to animationHandler into the entity class itself, because the names of the animations will likely be different for each entity. But now I'm encountering an even more baffling issue.
I've created a super simple new AI class called EntityAIPlayRandomIdle. Basically, it does a random number roll to see if the entity should play an idle animation, then sets the boolean flag playAnim_idle to True. (The reason I'm using an AI class is so the masking done by the mutex bits will keep idle animations from playing when the entity is suppose to be fleeing, or doing something else more important).
Then, in the onUpdate() method inside EntityTrog, I check to see if playAnim_idle is True. If it is True, and a cooldown has expired, the idle animation should play. I put in a console print line to display text on the console when both these conditions have been met and the animation is activated.
Here's where things get weird: Everything works fine UNTIL I add the condition that checks playAnim_idle == True. The console still prints out the line saying that the animation has been activated, meaning that the conditions have been passed, but the animation doesn't actually play.
There is no reason for this to be the case. None. Whether your If statement is "If (a==true)" or "If (a==true and b==true)", if the condition(s) have been met, the code inside the If statement should execute the same way it always does.
Here is the relevant code. I am literally pulling my hair out about this. It makes no logical sense. There is no reason why an AI class should interfere with the animation actually playing once ActivateAnimation() has been called.
I suspect you may be running into the issue of logical sides again. Both sides have their own copy of the entity, each with its own playAnim_idle field. The AI task that sets it to true only runs on the logical server, so only the logical server's copy of the entity plays the animation. This field is never synced to the logical client, so it never plays the animation.
Looking at MCAnimator's documentation, it appears you need to activate the animation on both logical sides. The best way to sync the playAnim_idle flag is probably using the entity's EntityDataManager.
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
I suspect you may be running into the issue of logical sides again. Both sides have their own copy of the entity, each with its own playAnim_idle field. The AI task that sets it to true only runs on the logical server, so only the logical server's copy of the entity plays the animation. This field is never synced to the logical client, so it never plays the animation.
Looking at MCAnimator's documentation, it appears you need to activate the animation on both logical sides. The best way to sync the playAnim_idle flag is probably using the entity's EntityDataManager.
I suspect you may be right. I'm not very experienced with how to handle different sides, though, aside from the basic proxy setup shown in every tutorial.
Do you know of any examples that could show me to to sync playAnim_idle on both client and server?
I suspect you may be right. I'm not very experienced with how to handle different sides, though, aside from the basic proxy setup shown in every tutorial.
Proxies are for physical sides, you're dealing with logical sides here.
Do you know of any examples that could show me to to sync playAnim_idle on both client and server?
Look at the EntityEnderman#SCREAMING field and the uses of it to see how EntityEnderman syncs the screaming state.
Rollback Post to RevisionRollBack
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
I have a custom mob named Trog that has custom animations. I'm trying to activate those animations from custom AI classes, but it's not working.
Here's the catch - if I activate the animations from update() in EntityTrog, everything works fine. It's only when I try to activate the animations from elsewhere that I have issues.
I suspect I'm running into a pass-by-value issue, where the entity whose animations I'm trying to activate is actually a copy of the real entity. Except then nothing makes sense in any of the vanilla AI classes, because they do the same thing.
Here's my code. I could use some help troubleshooting this.
https://pastebin.com/48DMuwwv
EDIT: The console print line IS appearing, so it's not a problem with the AI task itself.
I'm not familiar with MCAnimator, does the animation handler automatically sync the animation state to all clients watching the entity? You may need to manually trigger the syncing or sync it yourself.
Entity#update is called from both the logical client (whose copy of the entity is rendered) and server, but AI tasks are only run on the logical server.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
I was able to create a stop-gap solution by changing the type of "entity" from IMCAnimatedEntity to EntityTrog. Information about EntityTrog's animationHandler seems to have been getting lost when it was cast to the parent type. (EntityTrog extends IMCAnimatedEntity)
However, I want to be able to use this AI class for more than just EntityTrog. GetAnimationHandler() exists in IMCAnimatedEntity, and is overridden in EntityTrog, but it seems like casting EntityTrog to IMCAnimatedEntity is preventing it from working.
I tried moving the initialization of animationHandler to IMCAnimatedEntity (and then calling this.animationHandler=new AnimationHandlerTrog() in EntityTrog), but that didn't work either.
Can you think of a way around this?
I don't see how that's possible if you're passing the same value and calling the same method. When you call a method, Java uses the implementation from the value's actual class, regardless of the variable's type.
The AI task should work for any class that extends EntityLiving (required by the super class) and implements IMCAnimatedEntity (required by your class), so create a generic type argument for the class with these bounds and use it as the type of the field and the constructor parameter. Remove the IMCAnimatedEntity/EntityTrog parameter from the constructor.
I'm not sure if this will fix your issue (I don't know what's causing it), but it ensures that both your class and the super class are acting on the same entity.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
Oh boy. This is even MORE fun.
Okay, so I decided to move the actual calls to animationHandler into the entity class itself, because the names of the animations will likely be different for each entity. But now I'm encountering an even more baffling issue.
I've created a super simple new AI class called EntityAIPlayRandomIdle. Basically, it does a random number roll to see if the entity should play an idle animation, then sets the boolean flag playAnim_idle to True. (The reason I'm using an AI class is so the masking done by the mutex bits will keep idle animations from playing when the entity is suppose to be fleeing, or doing something else more important).
Then, in the onUpdate() method inside EntityTrog, I check to see if playAnim_idle is True. If it is True, and a cooldown has expired, the idle animation should play. I put in a console print line to display text on the console when both these conditions have been met and the animation is activated.
Here's where things get weird: Everything works fine UNTIL I add the condition that checks playAnim_idle == True. The console still prints out the line saying that the animation has been activated, meaning that the conditions have been passed, but the animation doesn't actually play.
There is no reason for this to be the case. None. Whether your If statement is "If (a==true)" or "If (a==true and b==true)", if the condition(s) have been met, the code inside the If statement should execute the same way it always does.
Here is the relevant code. I am literally pulling my hair out about this. It makes no logical sense. There is no reason why an AI class should interfere with the animation actually playing once ActivateAnimation() has been called.
https://pastebin.com/52RQLsWX
I suspect you may be running into the issue of logical sides again. Both sides have their own copy of the entity, each with its own playAnim_idle field. The AI task that sets it to true only runs on the logical server, so only the logical server's copy of the entity plays the animation. This field is never synced to the logical client, so it never plays the animation.
Looking at MCAnimator's documentation, it appears you need to activate the animation on both logical sides. The best way to sync the playAnim_idle flag is probably using the entity's EntityDataManager.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.
I suspect you may be right. I'm not very experienced with how to handle different sides, though, aside from the basic proxy setup shown in every tutorial.
Do you know of any examples that could show me to to sync playAnim_idle on both client and server?
Proxies are for physical sides, you're dealing with logical sides here.
Look at the EntityEnderman#SCREAMING field and the uses of it to see how EntityEnderman syncs the screaming state.
Chisel Facades: For all your decorative pipe-hiding needs.
Please don't PM me to ask for help or to join your mod development team. Asking your question in a public thread preserves it for people who are having the same problem in the future. I'm not interested in developing mods with people.