@quenty/animations 1.0.1-canary.385.c37a0ad.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/LICENSE.md +21 -0
- package/README.md +23 -0
- package/default.project.json +6 -0
- package/package.json +38 -0
- package/src/Shared/AnimationPromiseUtils.lua +32 -0
- package/src/Shared/AnimationUtils.lua +212 -0
- package/src/node_modules.project.json +7 -0
- package/test/default.project.json +21 -0
- package/test/scripts/Client/ClientMain.client.lua +14 -0
- package/test/scripts/Server/ServerMain.server.lua +8 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## 1.0.1-canary.385.c37a0ad.0 (2023-07-10)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Add utility package to play back animations easily ([46c33ea](https://github.com/Quenty/NevermoreEngine/commit/46c33ea401987b14ba9c674280e56cd5d4cfe530))
|
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014-2023 James Onnen (Quenty)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
## Animations
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
<a href="http://quenty.github.io/NevermoreEngine/">
|
|
5
|
+
<img src="https://github.com/Quenty/NevermoreEngine/actions/workflows/docs.yml/badge.svg" alt="Documentation status" />
|
|
6
|
+
</a>
|
|
7
|
+
<a href="https://discord.gg/mhtGUS8">
|
|
8
|
+
<img src="https://img.shields.io/discord/385151591524597761?color=5865F2&label=discord&logo=discord&logoColor=white" alt="Discord" />
|
|
9
|
+
</a>
|
|
10
|
+
<a href="https://github.com/Quenty/NevermoreEngine/actions">
|
|
11
|
+
<img src="https://github.com/Quenty/NevermoreEngine/actions/workflows/build.yml/badge.svg" alt="Build and release status" />
|
|
12
|
+
</a>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
Utility methods for playing back animations on Roblox
|
|
16
|
+
|
|
17
|
+
<div align="center"><a href="https://quenty.github.io/NevermoreEngine/api/AnimationsUtils">View docs →</a></div>
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
npm install @quenty/animations --save
|
|
23
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@quenty/animations",
|
|
3
|
+
"version": "1.0.1-canary.385.c37a0ad.0",
|
|
4
|
+
"description": "Utility methods for playing back animations on Roblox",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"Roblox",
|
|
7
|
+
"Nevermore",
|
|
8
|
+
"Lua",
|
|
9
|
+
"animations"
|
|
10
|
+
],
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/Quenty/NevermoreEngine/issues"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/Quenty/NevermoreEngine.git",
|
|
17
|
+
"directory": "src/animations/"
|
|
18
|
+
},
|
|
19
|
+
"funding": {
|
|
20
|
+
"type": "patreon",
|
|
21
|
+
"url": "https://www.patreon.com/quenty"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"contributors": [
|
|
25
|
+
"Quenty"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@quenty/enumutils": "3.1.0",
|
|
29
|
+
"@quenty/humanoidanimatorutils": "2.1.2-canary.385.c37a0ad.0",
|
|
30
|
+
"@quenty/loader": "6.2.1",
|
|
31
|
+
"@quenty/promisemaid": "1.1.0",
|
|
32
|
+
"@quenty/rbxasset": "1.0.1-canary.385.c37a0ad.0"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"gitHead": "c37a0ad3981a0e27d4d9db436a0f21e675b12bf0"
|
|
38
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
@class AnimationPromiseUtils
|
|
3
|
+
]=]
|
|
4
|
+
|
|
5
|
+
local require = require(script.Parent.loader).load(script)
|
|
6
|
+
|
|
7
|
+
local Promise = require("Promise")
|
|
8
|
+
local PromiseMaidUtils = require("PromiseMaidUtils")
|
|
9
|
+
|
|
10
|
+
local AnimationPromiseUtils = {}
|
|
11
|
+
|
|
12
|
+
function AnimationPromiseUtils.promiseFinished(animationTrack)
|
|
13
|
+
local promise = Promise.new()
|
|
14
|
+
|
|
15
|
+
PromiseMaidUtils.whilePromise(promise, function(maid)
|
|
16
|
+
maid:GiveTask(animationTrack.Ended:Connect(function()
|
|
17
|
+
promise:Resolve()
|
|
18
|
+
end))
|
|
19
|
+
|
|
20
|
+
maid:GiveTask(animationTrack.Stopped:Connect(function()
|
|
21
|
+
promise:Resolve()
|
|
22
|
+
end))
|
|
23
|
+
|
|
24
|
+
maid:GiveTask(animationTrack.Destroying:Connect(function()
|
|
25
|
+
promise:Resolve()
|
|
26
|
+
end))
|
|
27
|
+
end)
|
|
28
|
+
|
|
29
|
+
return promise
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
return AnimationPromiseUtils
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
@class AnimationUtils
|
|
3
|
+
]=]
|
|
4
|
+
|
|
5
|
+
local require = require(script.Parent.loader).load(script)
|
|
6
|
+
|
|
7
|
+
local RbxAssetUtils = require("RbxAssetUtils")
|
|
8
|
+
local HumanoidAnimatorUtils = require("HumanoidAnimatorUtils")
|
|
9
|
+
local EnumUtils = require("EnumUtils")
|
|
10
|
+
|
|
11
|
+
local AnimationUtils = {}
|
|
12
|
+
|
|
13
|
+
--[=[
|
|
14
|
+
Plays the animation on the target instance.
|
|
15
|
+
|
|
16
|
+
@return AnimationTrack?
|
|
17
|
+
]=]
|
|
18
|
+
function AnimationUtils.playAnimation(
|
|
19
|
+
target: Animator | Player | Model | AnimationController,
|
|
20
|
+
id: string | number,
|
|
21
|
+
fadeTime: number?,
|
|
22
|
+
weight: number?,
|
|
23
|
+
speed: number?,
|
|
24
|
+
priority: AnimationPriority?): AnimationTrack?
|
|
25
|
+
assert(typeof(target) == "Instance", "Bad target")
|
|
26
|
+
assert(RbxAssetUtils.isConvertableToRbxAsset(id), "Bad id")
|
|
27
|
+
assert(type(fadeTime) == "number" or fadeTime == nil, "Bad fadeTime")
|
|
28
|
+
assert(type(weight) == "number" or weight == nil, "Bad weight")
|
|
29
|
+
assert(type(speed) == "number" or speed == nil, "Bad speed")
|
|
30
|
+
assert(EnumUtils.isOfType(Enum.AnimationPriority, priority) or priority == nil, "Bad priority")
|
|
31
|
+
|
|
32
|
+
local animationTrack = AnimationUtils.getOrCreateAnimationTrack(target, id, priority)
|
|
33
|
+
|
|
34
|
+
if animationTrack then
|
|
35
|
+
animationTrack:Play(fadeTime, weight, speed)
|
|
36
|
+
|
|
37
|
+
if priority then
|
|
38
|
+
animationTrack.Priority = priority
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
warn(string.format("[AnimationUtils] - Failed to play animationTrack %q", tostring(id)))
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
return animationTrack
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
--[=[
|
|
48
|
+
Stops the animation on the target instance.
|
|
49
|
+
]=]
|
|
50
|
+
function AnimationUtils.stopAnimation(target: Animator | Player | Model | AnimationController, id: string | number, fadeTime: number?): AnimationTrack?
|
|
51
|
+
assert(typeof(target) == "Instance", "Bad target")
|
|
52
|
+
assert(RbxAssetUtils.isConvertableToRbxAsset(id), "Bad id")
|
|
53
|
+
assert(type(fadeTime) == "number" or fadeTime == nil, "Bad fadeTime")
|
|
54
|
+
|
|
55
|
+
local animationTrack = AnimationUtils.findAnimationTrack(target, id)
|
|
56
|
+
|
|
57
|
+
if animationTrack then
|
|
58
|
+
animationTrack:Stop(fadeTime)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
return animationTrack
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
--[=[
|
|
65
|
+
Gets or creates an animation track for the player
|
|
66
|
+
]=]
|
|
67
|
+
function AnimationUtils.getOrCreateAnimationTrack(
|
|
68
|
+
target: Animator | Player | Model | AnimationController,
|
|
69
|
+
id: string | number,
|
|
70
|
+
priority: AnimationPriority?): AnimationTrack?
|
|
71
|
+
assert(typeof(target) == "Instance", "Bad target")
|
|
72
|
+
assert(RbxAssetUtils.isConvertableToRbxAsset(id), "Bad id")
|
|
73
|
+
assert(EnumUtils.isOfType(Enum.AnimationPriority, priority) or priority == nil, "Bad priority")
|
|
74
|
+
|
|
75
|
+
local animator = AnimationUtils.getOrCreateAnimator(target)
|
|
76
|
+
if not animator then
|
|
77
|
+
return nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
assert(typeof(animator) == "Instance" and animator:IsA("Animator"), "Bad animator")
|
|
81
|
+
|
|
82
|
+
local foundAnimationTrack = AnimationUtils.findAnimationTrackInAnimator(animator, id)
|
|
83
|
+
if foundAnimationTrack then
|
|
84
|
+
return foundAnimationTrack
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
local animation = AnimationUtils.getOrCreateAnimationFromIdInAnimator(animator, id)
|
|
88
|
+
|
|
89
|
+
local animationTrack
|
|
90
|
+
local ok, err = pcall(function()
|
|
91
|
+
animationTrack = animator:LoadAnimation(animation)
|
|
92
|
+
end)
|
|
93
|
+
if not ok then
|
|
94
|
+
warn(string.format("[AnimationUtils] - Failed to load animation with id %q due to %q", tostring(id), tostring(err)))
|
|
95
|
+
return nil
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
return animationTrack
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
function AnimationUtils.getOrCreateAnimationFromIdInAnimator(animator: Animator, id: string | number)
|
|
102
|
+
assert(typeof(animator) == "Instance" and animator:IsA("Animator"), "Bad animator")
|
|
103
|
+
assert(RbxAssetUtils.isConvertableToRbxAsset(id), "Bad id")
|
|
104
|
+
|
|
105
|
+
local animationId = RbxAssetUtils.toRbxAssetId(id)
|
|
106
|
+
for _, animation in pairs(animator:GetChildren()) do
|
|
107
|
+
if animation:IsA("Animation") then
|
|
108
|
+
if animation.AnimationId == animationId then
|
|
109
|
+
return animation
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
local animation = AnimationUtils.createAnimationFromId(id)
|
|
115
|
+
animation.Parent = animator
|
|
116
|
+
|
|
117
|
+
return animation
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
function AnimationUtils.findAnimationTrack(
|
|
121
|
+
target: Animator | Player | Model | AnimationController,
|
|
122
|
+
id: string | number)
|
|
123
|
+
assert(typeof(target) == "Instance", "Bad target")
|
|
124
|
+
assert(RbxAssetUtils.isConvertableToRbxAsset(id), "Bad id")
|
|
125
|
+
|
|
126
|
+
local animator = AnimationUtils.getOrCreateAnimator(target)
|
|
127
|
+
if not animator then
|
|
128
|
+
return nil
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
return AnimationUtils.findAnimationTrackInAnimator(animator, id)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
function AnimationUtils.findAnimationTrackInAnimator(animator: Animator, id: string | number)
|
|
135
|
+
assert(typeof(animator) == "Instance" and animator:IsA("Animator"), "Bad animator")
|
|
136
|
+
assert(RbxAssetUtils.isConvertableToRbxAsset(id), "Bad id")
|
|
137
|
+
|
|
138
|
+
local animationId = RbxAssetUtils.toRbxAssetId(id)
|
|
139
|
+
|
|
140
|
+
for _, animationTrack in pairs(animator:GetPlayingAnimationTracks()) do
|
|
141
|
+
local animation = animationTrack.Animation
|
|
142
|
+
if animation and animation.AnimationId == animationId then
|
|
143
|
+
return animationTrack
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
return nil
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
--[=[
|
|
151
|
+
Finds an animator for the current instance
|
|
152
|
+
]=]
|
|
153
|
+
function AnimationUtils.getOrCreateAnimator(target: Animator | Player | Model | AnimationController)
|
|
154
|
+
assert(typeof(target) == "Instance", "Bad target")
|
|
155
|
+
|
|
156
|
+
if target:IsA("Animator") then
|
|
157
|
+
return target
|
|
158
|
+
elseif target:IsA("Humanoid") then
|
|
159
|
+
return HumanoidAnimatorUtils.getOrCreateAnimator(target)
|
|
160
|
+
elseif target:IsA("AnimationController") then
|
|
161
|
+
return HumanoidAnimatorUtils.getOrCreateAnimator(target)
|
|
162
|
+
elseif target:IsA("Player") then
|
|
163
|
+
local character = target.Character
|
|
164
|
+
if not character then
|
|
165
|
+
return nil
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
|
|
169
|
+
if not humanoid then
|
|
170
|
+
return nil
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
return HumanoidAnimatorUtils.getOrCreateAnimator(humanoid)
|
|
174
|
+
elseif target:IsA("Model") then
|
|
175
|
+
local humanoid = target:FindFirstChildWhichIsA("Humanoid")
|
|
176
|
+
if humanoid then
|
|
177
|
+
return HumanoidAnimatorUtils.getOrCreateAnimator(humanoid)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
local animationController = target:FindFirstChildWhichIsA("AnimationController")
|
|
181
|
+
if animationController then
|
|
182
|
+
return HumanoidAnimatorUtils.getOrCreateAnimator(animationController)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
return nil
|
|
186
|
+
else
|
|
187
|
+
return nil
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
function AnimationUtils.getAnimationId(animationId)
|
|
192
|
+
return string.format("Animation_%s", animationId)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
--[=[
|
|
196
|
+
Creates a new animation object from the given id
|
|
197
|
+
]=]
|
|
198
|
+
function AnimationUtils.createAnimationFromId(id: string | number): Animation
|
|
199
|
+
assert(RbxAssetUtils.isConvertableToRbxAsset(id), "Bad id")
|
|
200
|
+
|
|
201
|
+
local animationId = RbxAssetUtils.toRbxAssetId(id)
|
|
202
|
+
assert(type(animationId) == "string", "Bad id")
|
|
203
|
+
|
|
204
|
+
local animation = Instance.new("Animation")
|
|
205
|
+
animation.Name = AnimationUtils.getAnimationId(animationId)
|
|
206
|
+
animation.AnimationId = animationId
|
|
207
|
+
animation.Archivable = false
|
|
208
|
+
|
|
209
|
+
return animation
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
return AnimationUtils
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "AnimationTest",
|
|
3
|
+
"tree": {
|
|
4
|
+
"$className": "DataModel",
|
|
5
|
+
"ServerScriptService": {
|
|
6
|
+
"animations": {
|
|
7
|
+
"$path": ".."
|
|
8
|
+
},
|
|
9
|
+
"Script": {
|
|
10
|
+
"$path": "scripts/Server"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"StarterPlayer": {
|
|
14
|
+
"StarterPlayerScripts": {
|
|
15
|
+
"Main": {
|
|
16
|
+
"$path": "scripts/Client"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
--[[
|
|
2
|
+
@class ClientMain
|
|
3
|
+
]]
|
|
4
|
+
local packages = game:GetService("ReplicatedStorage"):WaitForChild("Packages")
|
|
5
|
+
|
|
6
|
+
local Players = game:GetService("Players")
|
|
7
|
+
|
|
8
|
+
local AnimationUtils = require(packages:WaitForChild("AnimationUtils"))
|
|
9
|
+
|
|
10
|
+
game.UserInputService.InputBegan:Connect(function(inputObject)
|
|
11
|
+
if inputObject.KeyCode == Enum.KeyCode.Q then
|
|
12
|
+
AnimationUtils.playAnimation(Players.LocalPlayer, "rbxassetid://14012074834", nil, nil, 1, Enum.AnimationPriority.Action3)
|
|
13
|
+
end
|
|
14
|
+
end)
|