Topic category: User side tutorials
Player Animator is a mod that allows your player to do pre-made animations and primarily shows them on client-side ONLY meaning that other players on a server cannot see them. While there are some animations that will play server-side (when entity swings main hand / takes damage) animations that trigger through any other method (when a player uses a keybind / potion effects triggers) will only be played on the player client that triggers the animation.
There is a way to get around this if you knew how to code in java, basically you have to allow the information that the client uses to play an animation to be send as a packet to a server which is then distributed across all clients, but I don't know how to code in java and the documentation makes my head spin. So, this guide takes that same principle but emulates it with mcreator generated code.
PLEASE READ THE WHOLE GUIDE. I TRIED TO MAKE IT AS ORGANIZED AS POSSIBLE BUT THERE MAY BE SOME IMPORTANT INFORMATION THAT IS SOMEWHAT HIDDEN IN AN EXPLANATION.
LOOK (WITH YOUR EYES) AT THIS REALLY BIG TEXT. IF YOU LEAVE A REPLY ASKING WHERE THE PICTURES ARE I AM NOT RESPONDING.
THE PICTURES ARE BROKEN, PLEASE REFER TO THIS GOOGLE DOC AND THE FIGURE NAMES FOR THE PICTURES: https://docs.google.com/document/d/1Zcca8-h6GRd7q0-0gLXcrlG_kktkFsJw_2Qp1SO58XU/edit?usp=sharing
THE BASIC PLAN
(ignore the text at the bottom, it was a side note that I guess I forgot to finish typing and just ended the sentence?)
Figure 1.1
Basically we are mimicking server-side animations by just giving the observing player information about what animation is being played and then having their client play that animation on their screen.
EXECUTION
(the part you probably care about)
SENDING THE "PACKET":
FROM NOW ON when you want a player to trigger an animation it should look like this. ("Ignore active animations" can be whatever you want, but I recommend false because setting it to true can cause some desync between what is being played and what people see)
Figure 1.2
This is important because its what sends the information to players that are observing you do the animation. The variables "animStorage" and "animPlayer" contain both the name of the animation that needs to be sent and the name of the player doing the animation respectively. The variable names themself are arbitrary, but for all purposes in this guide, these two variables will makeup our "packet" that we send to the other observing players. And also, the size of the square cube is arbitrary, its essentially just the render distance that the packet is sent, larger size mean more people will see it. For testing purposes I set it to 21 because it was a number I pulled out of thin air, but in the mod that I'm doing this for I was going to make it an option for players to make it larger or smaller (also with some basic trig you can make this range a circle instead of a cube). The word "blank" will appear pretty often and that's just because that's what i initialized the default state of the variable as. I recommend something that could not be a player name, but "blank" is just the first thing I thought of when I needed to represent that the stored information was blank.
PROCESSING THE "PACKET":
Figure 2.1
These are the procedures needed for rendering side of this idea (the parts necessary to process the data sent out from triggering an animation). The two that I have crossed out were for debugging purposes and are NOT necessary. Of course, the procedure names are arbitrary, but (and this should go without saying) all the animation names that are included should pertain to YOUR animation names in YOUR animation files.
The core of this processing is done by the "RenderRange" procedure:
Figure 2.2
This block of code will essentially scan around the observing player for players within their rendering radius (size of the square cube) and apply the packet, given by a player who triggers an animation, to that same player just on the client of the observing player. Basically, if player A does an animation, player B will not actually be able to see it. But, because of the "packet" that we send, when player A triggers an animation, player B gets the information of who is doing the animation and what animation is being played. Using this information from the "packet", player B's client can then, through this block of code, scan for any players that match the name of "player A" and then play the corresponding animation onto them from the perspective of player B. This is why I call it "pseudo server-side" communication.
The "ignore active animation" unfortunately needs to be false in this scenario. I have thought up a way to allow for both true and false animations to be played so that certain ones can cancel active animations, but I have not created a concrete method yet.
The "AnimReset" potion effect serves to reset the memory of the observing player once the animation has been played on their end. This is necessary because if the data was not cleared, it would keep looping the animation on the player that send the packet despite them not actually triggering anymore animations or "packet" sends on their end.
Figures 2.3 & 2.4
Again, "blank" is just an arbitrary string I came up with to represent the memory as empty. It can be anything u want it to be. Just make sure that if you replace it, you replace every instance of the word "blank" within the other necessary procedures as well as the initialization string of the variables "animStorage" and "animPlayer". Honestly, it shouldn't even be much of a problem unless you are the person who's minecraft username is actually just "blank".
Now, of course, having this block of code that will render the sent "packet" will do nothing if there is no trigger for it which is where the AnimRender potion effect comes in.
Figure 2.5
This potion effect is actually important because using a looping tick event like "on player tick update" will actually send some real packets to the server/client that mess with the effectiveness of this whole plan. A potion effect will process the procedures nested within it in a different way that acts much nicer for the purposes of this plan. (At least, that's what I think is happening, what you really need to know is that the potion effect is a lot less finnicky than the on player tick update trigger)
And finally, to apply this potion effect to the player so that they can render incoming "packets" containing the animations
Figure 2.6
OK SO LETS RECAP.
- Whenever a player triggers an animation, they will send a "packet" out to all observing players within a certain range that contains their name and the animation they're playing
- When an observing player receives this information, it is processed through a block of code that tells the observing player's client to play the necessary animation onto the player that triggered the information then clears its memory
- The block of code that processes the "packet" sent by the player needs to be run every tick to mitigate any desync between both the triggering players client and the observing players client. To do this, the block of code can't just be ran on every player tick update for some reason because it messes things up and causes a slew of problems. So, to get around that, the block of code is nested within a potion effect that will run it every tick. That same potion effect is then applied to all players every tick.
VIDEO: https://youtu.be/MmOBPTfksqQ?si=gNj_xmVVkWsK5wlP
The main monitor is the primary account, the triggering player, and the laptop is signed into an alt account (in spectator mode) observing my player do the animation
That's it, that's the whole guide. There is a reply below this one (by me) that shows how to make the server-side animation cancelable. The google doc also includes those pictures.
UPDATE:
I figured out how to make animations cancelable
Added a new variable to the packet that tells the observer whether or not it can cancel the animation
Updated the packet that the triggering player sends to observers
Updated the renderer to process the new packet information of canceling or not canceling animations
Some heroes use capes. Mine does a tutorial for server side trigger animations for player animation plugin.
hi, I think I did exactly everything as you said and still it doesn't work can i have your discord id
youcreate, (i cant reply in a forum) please create a reply with all the procedures you used and the details of how it isn't working (crashes or just non-functional). Make sure to title what each one is supposed to do and make it clear which procedure is which.
https://drive.google.com/drive/folders/1jBqTZ8s8530ba4gxnqr_f7Yvh-2AnmJa?usp=drive_link
These are screenshots of the blocks in Mcreator the other player doesn't see animation.
Hey Marshmilo thanks for the tutorial. I was wondering, you mentioned that animations will trigger server side if the entity swings main hand, what if every animation I needed to be triggered I used the swing hand block too? Would work?
Nerddogueto, yes, but in the case of my mod, I needed animations for ability casts and other, similar, purposes (hence the tutorial). If you just need to have a weapon with a custom animation then it should be fine to just put the animation procedure within the block.
youcreate, in your RenderRange procedure the "Get (display) name of [Event/target entity]" should be "Get (display) name of [Entity iterator]"
ok, thanks so much
ternal Exception: java.lang.NullPointerException: Cannot invoke
"net.minecraft.nbt.CompoundTag.m_128461_(String)" because "nbt" is null
when i try to join the server it says this do you know why
youcreate, look at your renderrange procedure again, "if event/target entity is a player, play animation..." should be "if entity iterator is a player, play animation..."
Other than that, then I don't know
Neat, that will be useful for many! :)
Thanks Klemen!
So in that case, I could simply put before every animation trigger block a swing main hand block and it should play in server too?