ZigTheHedge Posted November 9, 2020 Report Share Posted November 9, 2020 (edited) Hey, guys! I decided to prettify my mods by adding animation to blocks. Making animation itself in VS Model Creator was easy, but the code part not so. Here's what I've done: 1. Added Animatable entityBehavior 2. Initialized animUtil 3. Start animating on GUI open 4. Stop animating on GUI closed Everything works, but animation doesn't play itself backwards on GUI closing despite of "Rewind" action onActivityStopped. Am I missing something important? shape.json: Spoiler "animations": [ { "name": "open", "code": "open", "quantityframes": 30, "onActivityStopped": "Rewind", "onAnimationEnd": "Hold", "keyframes": [ { "frame": 0, "elements": { "doorleft": { "rotationX": 0.0, "rotationY": 0.0, "rotationZ": 0.0 }, "doorright": { "rotationX": 0.0, "rotationY": 0.0, "rotationZ": 0.0 } } }, { "frame": 29, "elements": { "doorleft": { "rotationX": 0.0, "rotationY": 135.0, "rotationZ": 0.0 }, "doorright": { "rotationX": 0.0, "rotationY": -135.0, "rotationZ": 0.0 } } } ] } ] BE: Spoiler private BlockEntityAnimationUtil animUtil => ((BEBehaviorAnimatable)GetBehavior<BEBehaviorAnimatable>())?.animUtil; public override void Initialize(ICoreAPI api) { base.Initialize(api); if (api.World.Side == EnumAppSide.Client) { animUtil.InitializeAnimator("zeekea:tall_locker", new Vec3f(0, Block.Shape.rotateY, 0)); } } public override void OnReceivedServerPacket(int packetid, byte[] data) { base.OnReceivedServerPacket(packetid, data); if (packetid == (int)EnumBlockStovePacket.OpenGUI) { ... if (nightstandDialog == null) { Api.World.PlaySoundAt(new AssetLocation("zeekea:sounds/locker_open.ogg"), Pos.X, Pos.Y, Pos.Z); nightstandDialog = new GuiTwentyFourSlots(Lang.Get("zeekea:tall_locker-title"), Inventory, Pos, Api as ICoreClientAPI); nightstandDialog.OnClosed += () => { nightstandDialog = null; Api.World.PlaySoundAt(new AssetLocation("zeekea:sounds/locker_close.ogg"), Pos.X, Pos.Y, Pos.Z); animUtil.StopAnimation("open"); }; } nightstandDialog.TryOpen(); animUtil.StartAnimation(new AnimationMetaData() { Animation = "open", Code = "open", AnimationSpeed = 0.2F}); } } ... } Edited November 9, 2020 by ZigTheHedge Link to comment Share on other sites More sharing options...
Rhonen Posted November 9, 2020 Report Share Posted November 9, 2020 Took some minutes for inspect your idea. Code using seems okay, but i have no experience by using "Rewind" in the Shape-json. Did you test with a breakpoint? is the animUtil object available on the Client-Side? Is OnClosed handled by client? Link to comment Share on other sites More sharing options...
ZigTheHedge Posted November 9, 2020 Author Report Share Posted November 9, 2020 1 hour ago, Rhonen said: but i have no experience by using "Rewind" in the Shape-json. That's the main problem. Everything works beside it. 1 hour ago, Rhonen said: Did you test with a breakpoint? is the animUtil object available on the Client-Side? Is OnClosed handled by client? Yes to all questions. Shape state resets to initial upon call of animUtil.StopAnimation. I think, I misunderstand the whole Animation behavior, should it really perform backwards animation upon call of StopAnimation, or it should actually stop (and rewind to beginning off camera)? Link to comment Share on other sites More sharing options...
Rhonen Posted November 9, 2020 Report Share Posted November 9, 2020 (edited) may be create a second animation which is the Rewind. "animations": [ { "name": "close", "code": "close", "quantityframes": 30, "onActivityStopped": "Stop", "onAnimationEnd": "Hold", Edited November 9, 2020 by Rhonen Link to comment Share on other sites More sharing options...
ZigTheHedge Posted November 9, 2020 Author Report Share Posted November 9, 2020 Well... I've managed to get it to work the way I want, but I don't think that's how it supposed to be. Spoiler "animations": [ { "name": "open", "code": "open", "quantityframes": 30, "onActivityStopped": "Rewind", "onAnimationEnd": "Hold", "keyframes": [ { "frame": 0, "elements": { "doorleft": { "rotationX": 0.0, "rotationY": 135.0, "rotationZ": 0.0 }, "doorright": { "rotationX": 0.0, "rotationY": -135.0, "rotationZ": 0.0 } } } ] }, { "name": "close", "code": "close", "quantityframes": 30, "onActivityStopped": "PlayTillEnd", "onAnimationEnd": "Stop", "keyframes": [ { "frame": 0, "elements": { "doorright": { "rotationX": 0.0, "rotationY": 0, "rotationZ": 0.0 }, "doorleft": { "rotationX": 0.0, "rotationY": 0, "rotationZ": 0.0 } } } ] } ] Spoiler Close: animUtil.StartAnimation(new AnimationMetaData() { Animation = "close", Code = "close", AnimationSpeed = 0.2F }); animUtil.StopAnimation("open"); Open: animUtil.StartAnimation(new AnimationMetaData() { Animation = "open", Code = "open", AnimationSpeed = 0.2F}); I removed last keyframes, and set all necessary coordinates in first ones. Now for some reason it works... I don't get it and I don't like it Link to comment Share on other sites More sharing options...
ZigTheHedge Posted November 10, 2020 Author Report Share Posted November 10, 2020 And another issue. Models get doubled after animation. It seems, animation doesn't "stop" itself properly on "Stop" action. Here's the scenario (tested with static model hidden via "return true" from OnTesselation): Model hidden by OnTesselation. - StartAnimation("open"); // onAnimationEnd = "Hold"; Model visible. Animation on Hold. - StopAnimation("open"); Model disappears. Animation stopped. - StartAnimation("close"); // onAnimationEnd = "Stop"; Model visible despite of "Stop" action. animUtil.activeAnimationsByAnimCode.Count == 0. It seems, I must explicitly call StopAnimation to stop the animated model from rendering, but how to know that moment? Link to comment Share on other sites More sharing options...
Rhonen Posted November 10, 2020 Report Share Posted November 10, 2020 i only have used stop animation to stop them realy. so animation itself "name": "switch", "code": "switch", "quantityframes": 160, "onActivityStopped": "Stop", "onAnimationEnd": "Hold", no idea why rewind does not work Link to comment Share on other sites More sharing options...
Rhonen Posted November 10, 2020 Report Share Posted November 10, 2020 (edited) one more point: - StopAnimation("open"); also stop rendering the animated model, so your OnTessaltion must deliver false then to render default shape. may be rewind does not work correctly i would prefer following animations: closeIdle (like it had been placed) => this animation will be started when block placed openAnim (OnAnimationEnd = hold) closeAnim (OnAnimationEnd = hold) --------------- switch animations -------- onOpenGui => stop closeIdle / closeAnim, start openAnim onCloseGui => stop openAnim , start closeAnim --------------------- may be this way can help when rewind not realy works Edited November 10, 2020 by Rhonen 1 Link to comment Share on other sites More sharing options...
ZigTheHedge Posted November 10, 2020 Author Report Share Posted November 10, 2020 16 minutes ago, Rhonen said: one more point: - StopAnimation("open"); also stop rendering the animated model, so your OnTessaltion must deliver false then to render default shape. may be rewind does not work correctly Yeah, I know. The thing is OnAnimationEnd: "Stop" doesn't stop rendering the model. That's the problem. Only BlockEntityAnimationUtil::StopAnimation() does. 32 minutes ago, Rhonen said: closeIdle (like it had been placed) => this animation will be started when block placed That's the way I were thinking of, but trying to avoid, because I think rendering the animated model is much more expensive resource-wise than static cached version. I think, I'll leave my shapes not animated until 1.14. It seems, Animation API has changed there. Thanks for trying to help Link to comment Share on other sites More sharing options...
Rhonen Posted November 10, 2020 Report Share Posted November 10, 2020 (edited) then this way could be possible when placed => OnTesselation returns false --------------- switch animations -------- onOpenGui => OnTessaltion returns true start openAnim now the complex part onCloseGui calculate an estimated duration for your animation-duration stop openAnim start closeAnim when animation-duration is elapsed stop closeAnim, animation settings: "onActivityStopped": "Stop", "onAnimationEnd": "Hold", OnTessaltion returns false re-initialize the AnimUtil This is the way i use to get the animated drawbridges / portcullis / gates. Place it, OnInteraction start animation and tessaltion = true Calculate an estimated duration by the known frames when duration is elapsed, stop animation, re-initialize the animUtil and let tessaltion return false Edited November 10, 2020 by Rhonen Link to comment Share on other sites More sharing options...
ZigTheHedge Posted November 10, 2020 Author Report Share Posted November 10, 2020 Well. I've tried 1.14-pre4 aaaand... It works as intended! With just one animation with Hold/Rewind So, I'll leave it as it is for 1.13. That's really isn't that necessary. Link to comment Share on other sites More sharing options...
Rhonen Posted November 11, 2020 Report Share Posted November 11, 2020 yes, the animation control has been changed for 1.14 Sounds good that you got it. 1 Link to comment Share on other sites More sharing options...
Recommended Posts