@rbxts/gravity-controller 1.0.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/GravityController.rbxmx +3208 -0
- package/README.md +65 -0
- package/out/index.d.ts +22 -0
- package/out/init.lua +174 -0
- package/package.json +50 -0
|
@@ -0,0 +1,3208 @@
|
|
|
1
|
+
<roblox version="4">
|
|
2
|
+
<Item class="Script" referent="0">
|
|
3
|
+
<Properties>
|
|
4
|
+
<string name="Name">GravityController</string>
|
|
5
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
6
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
7
|
+
<bool name="Disabled">false</bool>
|
|
8
|
+
<Content name="LinkedSource">
|
|
9
|
+
<null>
|
|
10
|
+
</null>
|
|
11
|
+
</Content>
|
|
12
|
+
<token name="RunContext">0</token>
|
|
13
|
+
<string name="Source">local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
14
|
+
local StarterPlayerScripts = game:GetService("StarterPlayer"):WaitForChild("StarterPlayerScripts")
|
|
15
|
+
local StarterCharacterScripts = game:GetService("StarterPlayer"):WaitForChild("StarterCharacterScripts")
|
|
16
|
+
|
|
17
|
+
local Client = script:WaitForChild("Client")
|
|
18
|
+
|
|
19
|
+
local function replace(child, parent)
|
|
20
|
+
local found = parent:FindFirstChild(child.Name)
|
|
21
|
+
if found then found:Destroy() end
|
|
22
|
+
child.Parent = parent
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
replace(Client:WaitForChild("PlayerScriptsLoader"), StarterPlayerScripts)
|
|
26
|
+
replace(Client:WaitForChild("RbxCharacterSounds"), StarterPlayerScripts)
|
|
27
|
+
replace(Client:WaitForChild("Animate"), StarterCharacterScripts)
|
|
28
|
+
|
|
29
|
+
script:WaitForChild("GravityController").Parent = ReplicatedStorage</string>
|
|
30
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
31
|
+
<BinaryString name="Tags"></BinaryString>
|
|
32
|
+
</Properties>
|
|
33
|
+
<Item class="Folder" referent="1">
|
|
34
|
+
<Properties>
|
|
35
|
+
<string name="Name">Client</string>
|
|
36
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
37
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
38
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
39
|
+
<BinaryString name="Tags"></BinaryString>
|
|
40
|
+
</Properties>
|
|
41
|
+
<Item class="LocalScript" referent="2">
|
|
42
|
+
<Properties>
|
|
43
|
+
<string name="Name">Animate</string>
|
|
44
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
45
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
46
|
+
<bool name="Disabled">false</bool>
|
|
47
|
+
<Content name="LinkedSource">
|
|
48
|
+
<null>
|
|
49
|
+
</null>
|
|
50
|
+
</Content>
|
|
51
|
+
<token name="RunContext">0</token>
|
|
52
|
+
<string name="Source">require(script:WaitForChild("Controller"))</string>
|
|
53
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
54
|
+
<BinaryString name="Tags"></BinaryString>
|
|
55
|
+
</Properties>
|
|
56
|
+
<Item class="ModuleScript" referent="3">
|
|
57
|
+
<Properties>
|
|
58
|
+
<string name="Name">Controller</string>
|
|
59
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
60
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
61
|
+
<Content name="LinkedSource">
|
|
62
|
+
<null>
|
|
63
|
+
</null>
|
|
64
|
+
</Content>
|
|
65
|
+
<string name="Source">local animate = script.Parent
|
|
66
|
+
local humanoid = animate.Parent:WaitForChild("Humanoid")
|
|
67
|
+
local loaded = animate:WaitForChild("Loaded")
|
|
68
|
+
|
|
69
|
+
require(animate:WaitForChild("VerifyAnims"))(humanoid, animate)
|
|
70
|
+
|
|
71
|
+
local output
|
|
72
|
+
if humanoid.RigType == Enum.HumanoidRigType.R6 then
|
|
73
|
+
output = require(animate:WaitForChild("R6"))
|
|
74
|
+
else
|
|
75
|
+
output = require(animate:WaitForChild("R15"))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
loaded.Value = true
|
|
79
|
+
|
|
80
|
+
return output</string>
|
|
81
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
82
|
+
<BinaryString name="Tags"></BinaryString>
|
|
83
|
+
</Properties>
|
|
84
|
+
</Item>
|
|
85
|
+
<Item class="BoolValue" referent="4">
|
|
86
|
+
<Properties>
|
|
87
|
+
<string name="Name">Loaded</string>
|
|
88
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
89
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
90
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
91
|
+
<BinaryString name="Tags"></BinaryString>
|
|
92
|
+
<bool name="Value">false</bool>
|
|
93
|
+
</Properties>
|
|
94
|
+
</Item>
|
|
95
|
+
<Item class="BindableFunction" referent="5">
|
|
96
|
+
<Properties>
|
|
97
|
+
<string name="Name">PlayEmote</string>
|
|
98
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
99
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
100
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
101
|
+
<BinaryString name="Tags"></BinaryString>
|
|
102
|
+
</Properties>
|
|
103
|
+
</Item>
|
|
104
|
+
<Item class="ModuleScript" referent="6">
|
|
105
|
+
<Properties>
|
|
106
|
+
<string name="Name">R15</string>
|
|
107
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
108
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
109
|
+
<Content name="LinkedSource">
|
|
110
|
+
<null>
|
|
111
|
+
</null>
|
|
112
|
+
</Content>
|
|
113
|
+
<string name="Source"><![CDATA[local script = script.Parent
|
|
114
|
+
|
|
115
|
+
local Character = script.Parent
|
|
116
|
+
local Humanoid = Character:WaitForChild("Humanoid")
|
|
117
|
+
local pose = "Standing"
|
|
118
|
+
|
|
119
|
+
local userNoUpdateOnLoopSuccess, userNoUpdateOnLoopValue = pcall(function() return UserSettings():IsUserFeatureEnabled("UserNoUpdateOnLoop") end)
|
|
120
|
+
local userNoUpdateOnLoop = userNoUpdateOnLoopSuccess and userNoUpdateOnLoopValue
|
|
121
|
+
local userAnimationSpeedDampeningSuccess, userAnimationSpeedDampeningValue = pcall(function() return UserSettings():IsUserFeatureEnabled("UserAnimationSpeedDampening") end)
|
|
122
|
+
local userAnimationSpeedDampening = userAnimationSpeedDampeningSuccess and userAnimationSpeedDampeningValue
|
|
123
|
+
|
|
124
|
+
local animateScriptEmoteHookFlagExists, animateScriptEmoteHookFlagEnabled = pcall(function()
|
|
125
|
+
return UserSettings():IsUserFeatureEnabled("UserAnimateScriptEmoteHook")
|
|
126
|
+
end)
|
|
127
|
+
local FFlagAnimateScriptEmoteHook = animateScriptEmoteHookFlagExists and animateScriptEmoteHookFlagEnabled
|
|
128
|
+
|
|
129
|
+
local AnimationSpeedDampeningObject = script:FindFirstChild("ScaleDampeningPercent")
|
|
130
|
+
local HumanoidHipHeight = 2
|
|
131
|
+
|
|
132
|
+
local EMOTE_TRANSITION_TIME = 0.1
|
|
133
|
+
|
|
134
|
+
local currentAnim = ""
|
|
135
|
+
local currentAnimInstance = nil
|
|
136
|
+
local currentAnimTrack = nil
|
|
137
|
+
local currentAnimKeyframeHandler = nil
|
|
138
|
+
local currentAnimSpeed = 1.0
|
|
139
|
+
|
|
140
|
+
local runAnimTrack = nil
|
|
141
|
+
local runAnimKeyframeHandler = nil
|
|
142
|
+
|
|
143
|
+
local animTable = {}
|
|
144
|
+
local animNames = {
|
|
145
|
+
idle = {
|
|
146
|
+
{ id = "http://www.roblox.com/asset/?id=507766666", weight = 1 },
|
|
147
|
+
{ id = "http://www.roblox.com/asset/?id=507766951", weight = 1 },
|
|
148
|
+
{ id = "http://www.roblox.com/asset/?id=507766388", weight = 9 }
|
|
149
|
+
},
|
|
150
|
+
walk = {
|
|
151
|
+
{ id = "http://www.roblox.com/asset/?id=507777826", weight = 10 }
|
|
152
|
+
},
|
|
153
|
+
run = {
|
|
154
|
+
{ id = "http://www.roblox.com/asset/?id=507767714", weight = 10 }
|
|
155
|
+
},
|
|
156
|
+
swim = {
|
|
157
|
+
{ id = "http://www.roblox.com/asset/?id=507784897", weight = 10 }
|
|
158
|
+
},
|
|
159
|
+
swimidle = {
|
|
160
|
+
{ id = "http://www.roblox.com/asset/?id=507785072", weight = 10 }
|
|
161
|
+
},
|
|
162
|
+
jump = {
|
|
163
|
+
{ id = "http://www.roblox.com/asset/?id=507765000", weight = 10 }
|
|
164
|
+
},
|
|
165
|
+
fall = {
|
|
166
|
+
{ id = "http://www.roblox.com/asset/?id=507767968", weight = 10 }
|
|
167
|
+
},
|
|
168
|
+
climb = {
|
|
169
|
+
{ id = "http://www.roblox.com/asset/?id=507765644", weight = 10 }
|
|
170
|
+
},
|
|
171
|
+
sit = {
|
|
172
|
+
{ id = "http://www.roblox.com/asset/?id=2506281703", weight = 10 }
|
|
173
|
+
},
|
|
174
|
+
toolnone = {
|
|
175
|
+
{ id = "http://www.roblox.com/asset/?id=507768375", weight = 10 }
|
|
176
|
+
},
|
|
177
|
+
toolslash = {
|
|
178
|
+
{ id = "http://www.roblox.com/asset/?id=522635514", weight = 10 }
|
|
179
|
+
},
|
|
180
|
+
toollunge = {
|
|
181
|
+
{ id = "http://www.roblox.com/asset/?id=522638767", weight = 10 }
|
|
182
|
+
},
|
|
183
|
+
wave = {
|
|
184
|
+
{ id = "http://www.roblox.com/asset/?id=507770239", weight = 10 }
|
|
185
|
+
},
|
|
186
|
+
point = {
|
|
187
|
+
{ id = "http://www.roblox.com/asset/?id=507770453", weight = 10 }
|
|
188
|
+
},
|
|
189
|
+
dance = {
|
|
190
|
+
{ id = "http://www.roblox.com/asset/?id=507771019", weight = 10 },
|
|
191
|
+
{ id = "http://www.roblox.com/asset/?id=507771955", weight = 10 },
|
|
192
|
+
{ id = "http://www.roblox.com/asset/?id=507772104", weight = 10 }
|
|
193
|
+
},
|
|
194
|
+
dance2 = {
|
|
195
|
+
{ id = "http://www.roblox.com/asset/?id=507776043", weight = 10 },
|
|
196
|
+
{ id = "http://www.roblox.com/asset/?id=507776720", weight = 10 },
|
|
197
|
+
{ id = "http://www.roblox.com/asset/?id=507776879", weight = 10 }
|
|
198
|
+
},
|
|
199
|
+
dance3 = {
|
|
200
|
+
{ id = "http://www.roblox.com/asset/?id=507777268", weight = 10 },
|
|
201
|
+
{ id = "http://www.roblox.com/asset/?id=507777451", weight = 10 },
|
|
202
|
+
{ id = "http://www.roblox.com/asset/?id=507777623", weight = 10 }
|
|
203
|
+
},
|
|
204
|
+
laugh = {
|
|
205
|
+
{ id = "http://www.roblox.com/asset/?id=507770818", weight = 10 }
|
|
206
|
+
},
|
|
207
|
+
cheer = {
|
|
208
|
+
{ id = "http://www.roblox.com/asset/?id=507770677", weight = 10 }
|
|
209
|
+
},
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
-- Existance in this list signifies that it is an emote, the value indicates if it is a looping emote
|
|
213
|
+
local emoteNames = { wave = false, point = false, dance = true, dance2 = true, dance3 = true, laugh = false, cheer = false}
|
|
214
|
+
|
|
215
|
+
local PreloadAnimsUserFlag = false
|
|
216
|
+
local PreloadedAnims = {}
|
|
217
|
+
local successPreloadAnim, msgPreloadAnim = pcall(function()
|
|
218
|
+
PreloadAnimsUserFlag = UserSettings():IsUserFeatureEnabled("UserPreloadAnimations")
|
|
219
|
+
end)
|
|
220
|
+
if not successPreloadAnim then
|
|
221
|
+
PreloadAnimsUserFlag = false
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
math.randomseed(tick())
|
|
225
|
+
|
|
226
|
+
function findExistingAnimationInSet(set, anim)
|
|
227
|
+
if set == nil or anim == nil then
|
|
228
|
+
return 0
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
for idx = 1, set.count, 1 do
|
|
232
|
+
if set[idx].anim.AnimationId == anim.AnimationId then
|
|
233
|
+
return idx
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
return 0
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
function configureAnimationSet(name, fileList)
|
|
241
|
+
if (animTable[name] ~= nil) then
|
|
242
|
+
for _, connection in pairs(animTable[name].connections) do
|
|
243
|
+
connection:disconnect()
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
animTable[name] = {}
|
|
247
|
+
animTable[name].count = 0
|
|
248
|
+
animTable[name].totalWeight = 0
|
|
249
|
+
animTable[name].connections = {}
|
|
250
|
+
|
|
251
|
+
local allowCustomAnimations = true
|
|
252
|
+
|
|
253
|
+
local success, msg = pcall(function() allowCustomAnimations = game:GetService("StarterPlayer").AllowCustomAnimations end)
|
|
254
|
+
if not success then
|
|
255
|
+
allowCustomAnimations = true
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
-- check for config values
|
|
259
|
+
local config = script:FindFirstChild(name)
|
|
260
|
+
if (allowCustomAnimations and config ~= nil) then
|
|
261
|
+
table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end))
|
|
262
|
+
table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end))
|
|
263
|
+
|
|
264
|
+
local idx = 0
|
|
265
|
+
for _, childPart in pairs(config:GetChildren()) do
|
|
266
|
+
if (childPart:IsA("Animation")) then
|
|
267
|
+
local newWeight = 1
|
|
268
|
+
local weightObject = childPart:FindFirstChild("Weight")
|
|
269
|
+
if (weightObject ~= nil) then
|
|
270
|
+
newWeight = weightObject.Value
|
|
271
|
+
end
|
|
272
|
+
animTable[name].count = animTable[name].count + 1
|
|
273
|
+
idx = animTable[name].count
|
|
274
|
+
animTable[name][idx] = {}
|
|
275
|
+
animTable[name][idx].anim = childPart
|
|
276
|
+
animTable[name][idx].weight = newWeight
|
|
277
|
+
animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
|
|
278
|
+
table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
|
|
279
|
+
table.insert(animTable[name].connections, childPart.ChildAdded:connect(function(property) configureAnimationSet(name, fileList) end))
|
|
280
|
+
table.insert(animTable[name].connections, childPart.ChildRemoved:connect(function(property) configureAnimationSet(name, fileList) end))
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
-- fallback to defaults
|
|
286
|
+
if (animTable[name].count <= 0) then
|
|
287
|
+
for idx, anim in pairs(fileList) do
|
|
288
|
+
animTable[name][idx] = {}
|
|
289
|
+
animTable[name][idx].anim = Instance.new("Animation")
|
|
290
|
+
animTable[name][idx].anim.Name = name
|
|
291
|
+
animTable[name][idx].anim.AnimationId = anim.id
|
|
292
|
+
animTable[name][idx].weight = anim.weight
|
|
293
|
+
animTable[name].count = animTable[name].count + 1
|
|
294
|
+
animTable[name].totalWeight = animTable[name].totalWeight + anim.weight
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
-- preload anims
|
|
299
|
+
if PreloadAnimsUserFlag then
|
|
300
|
+
for i, animType in pairs(animTable) do
|
|
301
|
+
for idx = 1, animType.count, 1 do
|
|
302
|
+
if PreloadedAnims[animType[idx].anim.AnimationId] == nil then
|
|
303
|
+
Humanoid:LoadAnimation(animType[idx].anim)
|
|
304
|
+
PreloadedAnims[animType[idx].anim.AnimationId] = true
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
------------------------------------------------------------------------------------------------------------
|
|
312
|
+
|
|
313
|
+
function configureAnimationSetOld(name, fileList)
|
|
314
|
+
if (animTable[name] ~= nil) then
|
|
315
|
+
for _, connection in pairs(animTable[name].connections) do
|
|
316
|
+
connection:disconnect()
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
animTable[name] = {}
|
|
320
|
+
animTable[name].count = 0
|
|
321
|
+
animTable[name].totalWeight = 0
|
|
322
|
+
animTable[name].connections = {}
|
|
323
|
+
|
|
324
|
+
local allowCustomAnimations = true
|
|
325
|
+
|
|
326
|
+
local success, msg = pcall(function() allowCustomAnimations = game:GetService("StarterPlayer").AllowCustomAnimations end)
|
|
327
|
+
if not success then
|
|
328
|
+
allowCustomAnimations = true
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
-- check for config values
|
|
332
|
+
local config = script:FindFirstChild(name)
|
|
333
|
+
if (allowCustomAnimations and config ~= nil) then
|
|
334
|
+
table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end))
|
|
335
|
+
table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end))
|
|
336
|
+
local idx = 1
|
|
337
|
+
for _, childPart in pairs(config:GetChildren()) do
|
|
338
|
+
if (childPart:IsA("Animation")) then
|
|
339
|
+
table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
|
|
340
|
+
animTable[name][idx] = {}
|
|
341
|
+
animTable[name][idx].anim = childPart
|
|
342
|
+
local weightObject = childPart:FindFirstChild("Weight")
|
|
343
|
+
if (weightObject == nil) then
|
|
344
|
+
animTable[name][idx].weight = 1
|
|
345
|
+
else
|
|
346
|
+
animTable[name][idx].weight = weightObject.Value
|
|
347
|
+
end
|
|
348
|
+
animTable[name].count = animTable[name].count + 1
|
|
349
|
+
animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
|
|
350
|
+
idx = idx + 1
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
-- fallback to defaults
|
|
356
|
+
if (animTable[name].count <= 0) then
|
|
357
|
+
for idx, anim in pairs(fileList) do
|
|
358
|
+
animTable[name][idx] = {}
|
|
359
|
+
animTable[name][idx].anim = Instance.new("Animation")
|
|
360
|
+
animTable[name][idx].anim.Name = name
|
|
361
|
+
animTable[name][idx].anim.AnimationId = anim.id
|
|
362
|
+
animTable[name][idx].weight = anim.weight
|
|
363
|
+
animTable[name].count = animTable[name].count + 1
|
|
364
|
+
animTable[name].totalWeight = animTable[name].totalWeight + anim.weight
|
|
365
|
+
-- print(name .. " [" .. idx .. "] " .. anim.id .. " (" .. anim.weight .. ")")
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
-- preload anims
|
|
370
|
+
if PreloadAnimsUserFlag then
|
|
371
|
+
for i, animType in pairs(animTable) do
|
|
372
|
+
for idx = 1, animType.count, 1 do
|
|
373
|
+
Humanoid:LoadAnimation(animType[idx].anim)
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
-- Setup animation objects
|
|
380
|
+
function scriptChildModified(child)
|
|
381
|
+
local fileList = animNames[child.Name]
|
|
382
|
+
if (fileList ~= nil) then
|
|
383
|
+
configureAnimationSet(child.Name, fileList)
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
script.ChildAdded:connect(scriptChildModified)
|
|
388
|
+
script.ChildRemoved:connect(scriptChildModified)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
for name, fileList in pairs(animNames) do
|
|
392
|
+
configureAnimationSet(name, fileList)
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
-- ANIMATION
|
|
396
|
+
|
|
397
|
+
-- declarations
|
|
398
|
+
local toolAnim = "None"
|
|
399
|
+
local toolAnimTime = 0
|
|
400
|
+
|
|
401
|
+
local jumpAnimTime = 0
|
|
402
|
+
local jumpAnimDuration = 0.31
|
|
403
|
+
|
|
404
|
+
local toolTransitionTime = 0.1
|
|
405
|
+
local fallTransitionTime = 0.2
|
|
406
|
+
|
|
407
|
+
local currentlyPlayingEmote = false
|
|
408
|
+
|
|
409
|
+
-- functions
|
|
410
|
+
|
|
411
|
+
function stopAllAnimations()
|
|
412
|
+
local oldAnim = currentAnim
|
|
413
|
+
|
|
414
|
+
-- return to idle if finishing an emote
|
|
415
|
+
if (emoteNames[oldAnim] ~= nil and emoteNames[oldAnim] == false) then
|
|
416
|
+
oldAnim = "idle"
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
if FFlagAnimateScriptEmoteHook and currentlyPlayingEmote then
|
|
420
|
+
oldAnim = "idle"
|
|
421
|
+
currentlyPlayingEmote = false
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
currentAnim = ""
|
|
425
|
+
currentAnimInstance = nil
|
|
426
|
+
if (currentAnimKeyframeHandler ~= nil) then
|
|
427
|
+
currentAnimKeyframeHandler:disconnect()
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
if (currentAnimTrack ~= nil) then
|
|
431
|
+
currentAnimTrack:Stop()
|
|
432
|
+
currentAnimTrack:Destroy()
|
|
433
|
+
currentAnimTrack = nil
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
-- clean up walk if there is one
|
|
437
|
+
if (runAnimKeyframeHandler ~= nil) then
|
|
438
|
+
runAnimKeyframeHandler:disconnect()
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
if (runAnimTrack ~= nil) then
|
|
442
|
+
runAnimTrack:Stop()
|
|
443
|
+
runAnimTrack:Destroy()
|
|
444
|
+
runAnimTrack = nil
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
return oldAnim
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
function getHeightScale()
|
|
451
|
+
if Humanoid then
|
|
452
|
+
if not Humanoid.AutomaticScalingEnabled then
|
|
453
|
+
return 1
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
local scale = Humanoid.HipHeight / HumanoidHipHeight
|
|
457
|
+
if userAnimationSpeedDampening then
|
|
458
|
+
if AnimationSpeedDampeningObject == nil then
|
|
459
|
+
AnimationSpeedDampeningObject = script:FindFirstChild("ScaleDampeningPercent")
|
|
460
|
+
end
|
|
461
|
+
if AnimationSpeedDampeningObject ~= nil then
|
|
462
|
+
scale = 1 + (Humanoid.HipHeight - HumanoidHipHeight) * AnimationSpeedDampeningObject.Value / HumanoidHipHeight
|
|
463
|
+
end
|
|
464
|
+
end
|
|
465
|
+
return scale
|
|
466
|
+
end
|
|
467
|
+
return 1
|
|
468
|
+
end
|
|
469
|
+
|
|
470
|
+
local smallButNotZero = 0.0001
|
|
471
|
+
function setRunSpeed(speed)
|
|
472
|
+
local speedScaled = speed * 1.25
|
|
473
|
+
local heightScale = getHeightScale()
|
|
474
|
+
local runSpeed = speedScaled / heightScale
|
|
475
|
+
|
|
476
|
+
if runSpeed ~= currentAnimSpeed then
|
|
477
|
+
if runSpeed < 0.33 then
|
|
478
|
+
currentAnimTrack:AdjustWeight(1.0)
|
|
479
|
+
runAnimTrack:AdjustWeight(smallButNotZero)
|
|
480
|
+
elseif runSpeed < 0.66 then
|
|
481
|
+
local weight = ((runSpeed - 0.33) / 0.33)
|
|
482
|
+
currentAnimTrack:AdjustWeight(1.0 - weight + smallButNotZero)
|
|
483
|
+
runAnimTrack:AdjustWeight(weight + smallButNotZero)
|
|
484
|
+
else
|
|
485
|
+
currentAnimTrack:AdjustWeight(smallButNotZero)
|
|
486
|
+
runAnimTrack:AdjustWeight(1.0)
|
|
487
|
+
end
|
|
488
|
+
currentAnimSpeed = runSpeed
|
|
489
|
+
runAnimTrack:AdjustSpeed(runSpeed)
|
|
490
|
+
currentAnimTrack:AdjustSpeed(runSpeed)
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
function setAnimationSpeed(speed)
|
|
495
|
+
if currentAnim == "walk" then
|
|
496
|
+
setRunSpeed(speed)
|
|
497
|
+
else
|
|
498
|
+
if speed ~= currentAnimSpeed then
|
|
499
|
+
currentAnimSpeed = speed
|
|
500
|
+
currentAnimTrack:AdjustSpeed(currentAnimSpeed)
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
function keyFrameReachedFunc(frameName)
|
|
506
|
+
if (frameName == "End") then
|
|
507
|
+
if currentAnim == "walk" then
|
|
508
|
+
if userNoUpdateOnLoop == true then
|
|
509
|
+
if runAnimTrack.Looped ~= true then
|
|
510
|
+
runAnimTrack.TimePosition = 0.0
|
|
511
|
+
end
|
|
512
|
+
if currentAnimTrack.Looped ~= true then
|
|
513
|
+
currentAnimTrack.TimePosition = 0.0
|
|
514
|
+
end
|
|
515
|
+
else
|
|
516
|
+
runAnimTrack.TimePosition = 0.0
|
|
517
|
+
currentAnimTrack.TimePosition = 0.0
|
|
518
|
+
end
|
|
519
|
+
else
|
|
520
|
+
local repeatAnim = currentAnim
|
|
521
|
+
-- return to idle if finishing an emote
|
|
522
|
+
if (emoteNames[repeatAnim] ~= nil and emoteNames[repeatAnim] == false) then
|
|
523
|
+
repeatAnim = "idle"
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
if FFlagAnimateScriptEmoteHook and currentlyPlayingEmote then
|
|
527
|
+
if currentAnimTrack.Looped then
|
|
528
|
+
-- Allow the emote to loop
|
|
529
|
+
return
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
repeatAnim = "idle"
|
|
533
|
+
currentlyPlayingEmote = false
|
|
534
|
+
end
|
|
535
|
+
|
|
536
|
+
local animSpeed = currentAnimSpeed
|
|
537
|
+
playAnimation(repeatAnim, 0.15, Humanoid)
|
|
538
|
+
setAnimationSpeed(animSpeed)
|
|
539
|
+
end
|
|
540
|
+
end
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
function rollAnimation(animName)
|
|
544
|
+
local roll = math.random(1, animTable[animName].totalWeight)
|
|
545
|
+
local origRoll = roll
|
|
546
|
+
local idx = 1
|
|
547
|
+
while (roll > animTable[animName][idx].weight) do
|
|
548
|
+
roll = roll - animTable[animName][idx].weight
|
|
549
|
+
idx = idx + 1
|
|
550
|
+
end
|
|
551
|
+
return idx
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
local function switchToAnim(anim, animName, transitionTime, humanoid)
|
|
555
|
+
-- switch animation
|
|
556
|
+
if (anim ~= currentAnimInstance) then
|
|
557
|
+
|
|
558
|
+
if (currentAnimTrack ~= nil) then
|
|
559
|
+
currentAnimTrack:Stop(transitionTime)
|
|
560
|
+
currentAnimTrack:Destroy()
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
if (runAnimTrack ~= nil) then
|
|
564
|
+
runAnimTrack:Stop(transitionTime)
|
|
565
|
+
runAnimTrack:Destroy()
|
|
566
|
+
if userNoUpdateOnLoop == true then
|
|
567
|
+
runAnimTrack = nil
|
|
568
|
+
end
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
currentAnimSpeed = 1.0
|
|
572
|
+
|
|
573
|
+
-- load it to the humanoid; get AnimationTrack
|
|
574
|
+
currentAnimTrack = humanoid:LoadAnimation(anim)
|
|
575
|
+
currentAnimTrack.Priority = Enum.AnimationPriority.Core
|
|
576
|
+
|
|
577
|
+
-- play the animation
|
|
578
|
+
currentAnimTrack:Play(transitionTime)
|
|
579
|
+
currentAnim = animName
|
|
580
|
+
currentAnimInstance = anim
|
|
581
|
+
|
|
582
|
+
-- set up keyframe name triggers
|
|
583
|
+
if (currentAnimKeyframeHandler ~= nil) then
|
|
584
|
+
currentAnimKeyframeHandler:disconnect()
|
|
585
|
+
end
|
|
586
|
+
currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
|
|
587
|
+
|
|
588
|
+
-- check to see if we need to blend a walk/run animation
|
|
589
|
+
if animName == "walk" then
|
|
590
|
+
local runAnimName = "run"
|
|
591
|
+
local runIdx = rollAnimation(runAnimName)
|
|
592
|
+
|
|
593
|
+
runAnimTrack = humanoid:LoadAnimation(animTable[runAnimName][runIdx].anim)
|
|
594
|
+
runAnimTrack.Priority = Enum.AnimationPriority.Core
|
|
595
|
+
runAnimTrack:Play(transitionTime)
|
|
596
|
+
|
|
597
|
+
if (runAnimKeyframeHandler ~= nil) then
|
|
598
|
+
runAnimKeyframeHandler:disconnect()
|
|
599
|
+
end
|
|
600
|
+
runAnimKeyframeHandler = runAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
|
|
601
|
+
end
|
|
602
|
+
end
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
function playAnimation(animName, transitionTime, humanoid)
|
|
606
|
+
local idx = rollAnimation(animName)
|
|
607
|
+
local anim = animTable[animName][idx].anim
|
|
608
|
+
|
|
609
|
+
switchToAnim(anim, animName, transitionTime, humanoid)
|
|
610
|
+
currentlyPlayingEmote = false
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
function playEmote(emoteAnim, transitionTime, humanoid)
|
|
614
|
+
switchToAnim(emoteAnim, emoteAnim.Name, transitionTime, humanoid)
|
|
615
|
+
currentlyPlayingEmote = true
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
-------------------------------------------------------------------------------------------
|
|
619
|
+
-------------------------------------------------------------------------------------------
|
|
620
|
+
|
|
621
|
+
local toolAnimName = ""
|
|
622
|
+
local toolAnimTrack = nil
|
|
623
|
+
local toolAnimInstance = nil
|
|
624
|
+
local currentToolAnimKeyframeHandler = nil
|
|
625
|
+
|
|
626
|
+
function toolKeyFrameReachedFunc(frameName)
|
|
627
|
+
if (frameName == "End") then
|
|
628
|
+
playToolAnimation(toolAnimName, 0.0, Humanoid)
|
|
629
|
+
end
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
function playToolAnimation(animName, transitionTime, humanoid, priority)
|
|
634
|
+
local idx = rollAnimation(animName)
|
|
635
|
+
local anim = animTable[animName][idx].anim
|
|
636
|
+
|
|
637
|
+
if (toolAnimInstance ~= anim) then
|
|
638
|
+
|
|
639
|
+
if (toolAnimTrack ~= nil) then
|
|
640
|
+
toolAnimTrack:Stop()
|
|
641
|
+
toolAnimTrack:Destroy()
|
|
642
|
+
transitionTime = 0
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
-- load it to the humanoid; get AnimationTrack
|
|
646
|
+
toolAnimTrack = humanoid:LoadAnimation(anim)
|
|
647
|
+
if priority then
|
|
648
|
+
toolAnimTrack.Priority = priority
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
-- play the animation
|
|
652
|
+
toolAnimTrack:Play(transitionTime)
|
|
653
|
+
toolAnimName = animName
|
|
654
|
+
toolAnimInstance = anim
|
|
655
|
+
|
|
656
|
+
currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc)
|
|
657
|
+
end
|
|
658
|
+
end
|
|
659
|
+
|
|
660
|
+
function stopToolAnimations()
|
|
661
|
+
local oldAnim = toolAnimName
|
|
662
|
+
|
|
663
|
+
if (currentToolAnimKeyframeHandler ~= nil) then
|
|
664
|
+
currentToolAnimKeyframeHandler:disconnect()
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
toolAnimName = ""
|
|
668
|
+
toolAnimInstance = nil
|
|
669
|
+
if (toolAnimTrack ~= nil) then
|
|
670
|
+
toolAnimTrack:Stop()
|
|
671
|
+
toolAnimTrack:Destroy()
|
|
672
|
+
toolAnimTrack = nil
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
return oldAnim
|
|
676
|
+
end
|
|
677
|
+
|
|
678
|
+
-------------------------------------------------------------------------------------------
|
|
679
|
+
-------------------------------------------------------------------------------------------
|
|
680
|
+
-- STATE CHANGE HANDLERS
|
|
681
|
+
|
|
682
|
+
function onRunning(speed)
|
|
683
|
+
if speed > 0.75 then
|
|
684
|
+
local scale = 16.0
|
|
685
|
+
playAnimation("walk", 0.2, Humanoid)
|
|
686
|
+
setAnimationSpeed(speed / scale)
|
|
687
|
+
pose = "Running"
|
|
688
|
+
else
|
|
689
|
+
if emoteNames[currentAnim] == nil and not currentlyPlayingEmote then
|
|
690
|
+
playAnimation("idle", 0.2, Humanoid)
|
|
691
|
+
pose = "Standing"
|
|
692
|
+
end
|
|
693
|
+
end
|
|
694
|
+
end
|
|
695
|
+
|
|
696
|
+
function onDied()
|
|
697
|
+
pose = "Dead"
|
|
698
|
+
end
|
|
699
|
+
|
|
700
|
+
function onJumping()
|
|
701
|
+
playAnimation("jump", 0.1, Humanoid)
|
|
702
|
+
jumpAnimTime = jumpAnimDuration
|
|
703
|
+
pose = "Jumping"
|
|
704
|
+
end
|
|
705
|
+
|
|
706
|
+
function onClimbing(speed)
|
|
707
|
+
local scale = 5.0
|
|
708
|
+
playAnimation("climb", 0.1, Humanoid)
|
|
709
|
+
setAnimationSpeed(speed / scale)
|
|
710
|
+
pose = "Climbing"
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
function onGettingUp()
|
|
714
|
+
pose = "GettingUp"
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
function onFreeFall()
|
|
718
|
+
if (jumpAnimTime <= 0) then
|
|
719
|
+
playAnimation("fall", fallTransitionTime, Humanoid)
|
|
720
|
+
end
|
|
721
|
+
pose = "FreeFall"
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
function onFallingDown()
|
|
725
|
+
pose = "FallingDown"
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
function onSeated()
|
|
729
|
+
pose = "Seated"
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
function onPlatformStanding()
|
|
733
|
+
pose = "PlatformStanding"
|
|
734
|
+
end
|
|
735
|
+
|
|
736
|
+
-------------------------------------------------------------------------------------------
|
|
737
|
+
-------------------------------------------------------------------------------------------
|
|
738
|
+
|
|
739
|
+
function onSwimming(speed)
|
|
740
|
+
if speed > 1.00 then
|
|
741
|
+
local scale = 10.0
|
|
742
|
+
playAnimation("swim", 0.4, Humanoid)
|
|
743
|
+
setAnimationSpeed(speed / scale)
|
|
744
|
+
pose = "Swimming"
|
|
745
|
+
else
|
|
746
|
+
playAnimation("swimidle", 0.4, Humanoid)
|
|
747
|
+
pose = "Standing"
|
|
748
|
+
end
|
|
749
|
+
end
|
|
750
|
+
|
|
751
|
+
function animateTool()
|
|
752
|
+
if (toolAnim == "None") then
|
|
753
|
+
playToolAnimation("toolnone", toolTransitionTime, Humanoid, Enum.AnimationPriority.Idle)
|
|
754
|
+
return
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
if (toolAnim == "Slash") then
|
|
758
|
+
playToolAnimation("toolslash", 0, Humanoid, Enum.AnimationPriority.Action)
|
|
759
|
+
return
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
if (toolAnim == "Lunge") then
|
|
763
|
+
playToolAnimation("toollunge", 0, Humanoid, Enum.AnimationPriority.Action)
|
|
764
|
+
return
|
|
765
|
+
end
|
|
766
|
+
end
|
|
767
|
+
|
|
768
|
+
function getToolAnim(tool)
|
|
769
|
+
for _, c in ipairs(tool:GetChildren()) do
|
|
770
|
+
if c.Name == "toolanim" and c.className == "StringValue" then
|
|
771
|
+
return c
|
|
772
|
+
end
|
|
773
|
+
end
|
|
774
|
+
return nil
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
local lastTick = 0
|
|
778
|
+
|
|
779
|
+
function stepAnimate(currentTime)
|
|
780
|
+
local amplitude = 1
|
|
781
|
+
local frequency = 1
|
|
782
|
+
local deltaTime = currentTime - lastTick
|
|
783
|
+
lastTick = currentTime
|
|
784
|
+
|
|
785
|
+
local climbFudge = 0
|
|
786
|
+
local setAngles = false
|
|
787
|
+
|
|
788
|
+
if (jumpAnimTime > 0) then
|
|
789
|
+
jumpAnimTime = jumpAnimTime - deltaTime
|
|
790
|
+
end
|
|
791
|
+
|
|
792
|
+
if (pose == "FreeFall" and jumpAnimTime <= 0) then
|
|
793
|
+
playAnimation("fall", fallTransitionTime, Humanoid)
|
|
794
|
+
elseif (pose == "Seated") then
|
|
795
|
+
playAnimation("sit", 0.5, Humanoid)
|
|
796
|
+
return
|
|
797
|
+
elseif (pose == "Running") then
|
|
798
|
+
playAnimation("walk", 0.2, Humanoid)
|
|
799
|
+
elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then
|
|
800
|
+
stopAllAnimations()
|
|
801
|
+
amplitude = 0.1
|
|
802
|
+
frequency = 1
|
|
803
|
+
setAngles = true
|
|
804
|
+
end
|
|
805
|
+
|
|
806
|
+
-- Tool Animation handling
|
|
807
|
+
local tool = Character:FindFirstChildOfClass("Tool")
|
|
808
|
+
if tool and tool:FindFirstChild("Handle") then
|
|
809
|
+
local animStringValueObject = getToolAnim(tool)
|
|
810
|
+
|
|
811
|
+
if animStringValueObject then
|
|
812
|
+
toolAnim = animStringValueObject.Value
|
|
813
|
+
-- message recieved, delete StringValue
|
|
814
|
+
animStringValueObject.Parent = nil
|
|
815
|
+
toolAnimTime = currentTime + .3
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
if currentTime > toolAnimTime then
|
|
819
|
+
toolAnimTime = 0
|
|
820
|
+
toolAnim = "None"
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
animateTool()
|
|
824
|
+
else
|
|
825
|
+
stopToolAnimations()
|
|
826
|
+
toolAnim = "None"
|
|
827
|
+
toolAnimInstance = nil
|
|
828
|
+
toolAnimTime = 0
|
|
829
|
+
end
|
|
830
|
+
end
|
|
831
|
+
|
|
832
|
+
-- connect events
|
|
833
|
+
|
|
834
|
+
local events = {}
|
|
835
|
+
local eventHum = Humanoid
|
|
836
|
+
local RepHumanoid = script:WaitForChild("ReplicatedHumanoid")
|
|
837
|
+
|
|
838
|
+
local function onUnhook()
|
|
839
|
+
for i = 1, #events do
|
|
840
|
+
events[i]:Disconnect()
|
|
841
|
+
end
|
|
842
|
+
events = {}
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
local function onHook()
|
|
846
|
+
onUnhook()
|
|
847
|
+
|
|
848
|
+
pose = Humanoid.Sit and "Seated" or "Standing"
|
|
849
|
+
|
|
850
|
+
events = {
|
|
851
|
+
eventHum.Died:connect(onDied),
|
|
852
|
+
eventHum.Running:connect(onRunning),
|
|
853
|
+
eventHum.Jumping:connect(onJumping),
|
|
854
|
+
eventHum.Climbing:connect(onClimbing),
|
|
855
|
+
eventHum.GettingUp:connect(onGettingUp),
|
|
856
|
+
eventHum.FreeFalling:connect(onFreeFall),
|
|
857
|
+
eventHum.FallingDown:connect(onFallingDown),
|
|
858
|
+
eventHum.Seated:connect(onSeated),
|
|
859
|
+
eventHum.PlatformStanding:connect(onPlatformStanding),
|
|
860
|
+
eventHum.Swimming:connect(onSwimming)
|
|
861
|
+
}
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
RepHumanoid.Changed:Connect(function()
|
|
865
|
+
eventHum = RepHumanoid.Value
|
|
866
|
+
onHook()
|
|
867
|
+
end)
|
|
868
|
+
|
|
869
|
+
RepHumanoid.Value = Humanoid
|
|
870
|
+
|
|
871
|
+
-- setup emote chat hook
|
|
872
|
+
game:GetService("Players").LocalPlayer.Chatted:connect(function(msg)
|
|
873
|
+
local emote = ""
|
|
874
|
+
if (string.sub(msg, 1, 3) == "/e ") then
|
|
875
|
+
emote = string.sub(msg, 4)
|
|
876
|
+
elseif (string.sub(msg, 1, 7) == "/emote ") then
|
|
877
|
+
emote = string.sub(msg, 8)
|
|
878
|
+
end
|
|
879
|
+
|
|
880
|
+
if (pose == "Standing" and emoteNames[emote] ~= nil) then
|
|
881
|
+
playAnimation(emote, EMOTE_TRANSITION_TIME, Humanoid)
|
|
882
|
+
end
|
|
883
|
+
end)
|
|
884
|
+
|
|
885
|
+
-- emote bindable hook
|
|
886
|
+
if FFlagAnimateScriptEmoteHook then
|
|
887
|
+
script:WaitForChild("PlayEmote").OnInvoke = function(emote)
|
|
888
|
+
-- Only play emotes when idling
|
|
889
|
+
if pose ~= "Standing" then
|
|
890
|
+
return
|
|
891
|
+
end
|
|
892
|
+
|
|
893
|
+
if emoteNames[emote] ~= nil then
|
|
894
|
+
-- Default emotes
|
|
895
|
+
playAnimation(emote, EMOTE_TRANSITION_TIME, Humanoid)
|
|
896
|
+
|
|
897
|
+
return true
|
|
898
|
+
elseif typeof(emote) == "Instance" and emote:IsA("Animation") then
|
|
899
|
+
-- Non-default emotes
|
|
900
|
+
playEmote(emote, EMOTE_TRANSITION_TIME, Humanoid)
|
|
901
|
+
return true
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
-- Return false to indicate that the emote could not be played
|
|
905
|
+
return false
|
|
906
|
+
end
|
|
907
|
+
end
|
|
908
|
+
|
|
909
|
+
-- initialize to idle
|
|
910
|
+
playAnimation("idle", 0.1, Humanoid)
|
|
911
|
+
pose = "Standing"
|
|
912
|
+
|
|
913
|
+
-- loop to handle timed state transitions and tool animations
|
|
914
|
+
spawn(function()
|
|
915
|
+
while Character.Parent ~= nil do
|
|
916
|
+
local _, currentGameTime = wait(0.1)
|
|
917
|
+
stepAnimate(currentGameTime)
|
|
918
|
+
end
|
|
919
|
+
end)
|
|
920
|
+
|
|
921
|
+
return {
|
|
922
|
+
onRunning = onRunning,
|
|
923
|
+
onDied = onDied,
|
|
924
|
+
onJumping = onJumping,
|
|
925
|
+
onClimbing = onClimbing,
|
|
926
|
+
onGettingUp = onGettingUp,
|
|
927
|
+
onFreeFall = onFreeFall,
|
|
928
|
+
onFallingDown = onFallingDown,
|
|
929
|
+
onSeated = onSeated,
|
|
930
|
+
onPlatformStanding = onPlatformStanding,
|
|
931
|
+
onHook = onHook,
|
|
932
|
+
onUnhook = onUnhook
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
]]></string>
|
|
936
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
937
|
+
<BinaryString name="Tags"></BinaryString>
|
|
938
|
+
</Properties>
|
|
939
|
+
</Item>
|
|
940
|
+
<Item class="ModuleScript" referent="7">
|
|
941
|
+
<Properties>
|
|
942
|
+
<string name="Name">R6</string>
|
|
943
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
944
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
945
|
+
<Content name="LinkedSource">
|
|
946
|
+
<null>
|
|
947
|
+
</null>
|
|
948
|
+
</Content>
|
|
949
|
+
<string name="Source">local script = script.Parent
|
|
950
|
+
|
|
951
|
+
local Figure = script.Parent
|
|
952
|
+
local Torso = Figure:WaitForChild("Torso")
|
|
953
|
+
local RightShoulder = Torso:WaitForChild("Right Shoulder")
|
|
954
|
+
local LeftShoulder = Torso:WaitForChild("Left Shoulder")
|
|
955
|
+
local RightHip = Torso:WaitForChild("Right Hip")
|
|
956
|
+
local LeftHip = Torso:WaitForChild("Left Hip")
|
|
957
|
+
local Neck = Torso:WaitForChild("Neck")
|
|
958
|
+
local Humanoid = Figure:WaitForChild("Humanoid")
|
|
959
|
+
local pose = "Standing"
|
|
960
|
+
|
|
961
|
+
local currentAnim = ""
|
|
962
|
+
local currentAnimInstance = nil
|
|
963
|
+
local currentAnimTrack = nil
|
|
964
|
+
local currentAnimKeyframeHandler = nil
|
|
965
|
+
local currentAnimSpeed = 1.0
|
|
966
|
+
local animTable = {}
|
|
967
|
+
local animNames = {
|
|
968
|
+
idle = {
|
|
969
|
+
{ id = "http://www.roblox.com/asset/?id=180435571", weight = 9 },
|
|
970
|
+
{ id = "http://www.roblox.com/asset/?id=180435792", weight = 1 }
|
|
971
|
+
},
|
|
972
|
+
walk = {
|
|
973
|
+
{ id = "http://www.roblox.com/asset/?id=180426354", weight = 10 }
|
|
974
|
+
},
|
|
975
|
+
run = {
|
|
976
|
+
{ id = "run.xml", weight = 10 }
|
|
977
|
+
},
|
|
978
|
+
jump = {
|
|
979
|
+
{ id = "http://www.roblox.com/asset/?id=125750702", weight = 10 }
|
|
980
|
+
},
|
|
981
|
+
fall = {
|
|
982
|
+
{ id = "http://www.roblox.com/asset/?id=180436148", weight = 10 }
|
|
983
|
+
},
|
|
984
|
+
climb = {
|
|
985
|
+
{ id = "http://www.roblox.com/asset/?id=180436334", weight = 10 }
|
|
986
|
+
},
|
|
987
|
+
sit = {
|
|
988
|
+
{ id = "http://www.roblox.com/asset/?id=178130996", weight = 10 }
|
|
989
|
+
},
|
|
990
|
+
toolnone = {
|
|
991
|
+
{ id = "http://www.roblox.com/asset/?id=182393478", weight = 10 }
|
|
992
|
+
},
|
|
993
|
+
toolslash = {
|
|
994
|
+
{ id = "http://www.roblox.com/asset/?id=129967390", weight = 10 }
|
|
995
|
+
-- { id = "slash.xml", weight = 10 }
|
|
996
|
+
},
|
|
997
|
+
toollunge = {
|
|
998
|
+
{ id = "http://www.roblox.com/asset/?id=129967478", weight = 10 }
|
|
999
|
+
},
|
|
1000
|
+
wave = {
|
|
1001
|
+
{ id = "http://www.roblox.com/asset/?id=128777973", weight = 10 }
|
|
1002
|
+
},
|
|
1003
|
+
point = {
|
|
1004
|
+
{ id = "http://www.roblox.com/asset/?id=128853357", weight = 10 }
|
|
1005
|
+
},
|
|
1006
|
+
dance1 = {
|
|
1007
|
+
{ id = "http://www.roblox.com/asset/?id=182435998", weight = 10 },
|
|
1008
|
+
{ id = "http://www.roblox.com/asset/?id=182491037", weight = 10 },
|
|
1009
|
+
{ id = "http://www.roblox.com/asset/?id=182491065", weight = 10 }
|
|
1010
|
+
},
|
|
1011
|
+
dance2 = {
|
|
1012
|
+
{ id = "http://www.roblox.com/asset/?id=182436842", weight = 10 },
|
|
1013
|
+
{ id = "http://www.roblox.com/asset/?id=182491248", weight = 10 },
|
|
1014
|
+
{ id = "http://www.roblox.com/asset/?id=182491277", weight = 10 }
|
|
1015
|
+
},
|
|
1016
|
+
dance3 = {
|
|
1017
|
+
{ id = "http://www.roblox.com/asset/?id=182436935", weight = 10 },
|
|
1018
|
+
{ id = "http://www.roblox.com/asset/?id=182491368", weight = 10 },
|
|
1019
|
+
{ id = "http://www.roblox.com/asset/?id=182491423", weight = 10 }
|
|
1020
|
+
},
|
|
1021
|
+
laugh = {
|
|
1022
|
+
{ id = "http://www.roblox.com/asset/?id=129423131", weight = 10 }
|
|
1023
|
+
},
|
|
1024
|
+
cheer = {
|
|
1025
|
+
{ id = "http://www.roblox.com/asset/?id=129423030", weight = 10 }
|
|
1026
|
+
},
|
|
1027
|
+
}
|
|
1028
|
+
local dances = {"dance1", "dance2", "dance3"}
|
|
1029
|
+
|
|
1030
|
+
-- Existance in this list signifies that it is an emote, the value indicates if it is a looping emote
|
|
1031
|
+
local emoteNames = { wave = false, point = false, dance1 = true, dance2 = true, dance3 = true, laugh = false, cheer = false}
|
|
1032
|
+
|
|
1033
|
+
function configureAnimationSet(name, fileList)
|
|
1034
|
+
if (animTable[name] ~= nil) then
|
|
1035
|
+
for _, connection in pairs(animTable[name].connections) do
|
|
1036
|
+
connection:disconnect()
|
|
1037
|
+
end
|
|
1038
|
+
end
|
|
1039
|
+
animTable[name] = {}
|
|
1040
|
+
animTable[name].count = 0
|
|
1041
|
+
animTable[name].totalWeight = 0
|
|
1042
|
+
animTable[name].connections = {}
|
|
1043
|
+
|
|
1044
|
+
-- check for config values
|
|
1045
|
+
local config = script:FindFirstChild(name)
|
|
1046
|
+
if (config ~= nil) then
|
|
1047
|
+
-- print("Loading anims " .. name)
|
|
1048
|
+
table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end))
|
|
1049
|
+
table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end))
|
|
1050
|
+
local idx = 1
|
|
1051
|
+
for _, childPart in pairs(config:GetChildren()) do
|
|
1052
|
+
if (childPart:IsA("Animation")) then
|
|
1053
|
+
table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end))
|
|
1054
|
+
animTable[name][idx] = {}
|
|
1055
|
+
animTable[name][idx].anim = childPart
|
|
1056
|
+
local weightObject = childPart:FindFirstChild("Weight")
|
|
1057
|
+
if (weightObject == nil) then
|
|
1058
|
+
animTable[name][idx].weight = 1
|
|
1059
|
+
else
|
|
1060
|
+
animTable[name][idx].weight = weightObject.Value
|
|
1061
|
+
end
|
|
1062
|
+
animTable[name].count = animTable[name].count + 1
|
|
1063
|
+
animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight
|
|
1064
|
+
-- print(name .. " [" .. idx .. "] " .. animTable[name][idx].anim.AnimationId .. " (" .. animTable[name][idx].weight .. ")")
|
|
1065
|
+
idx = idx + 1
|
|
1066
|
+
end
|
|
1067
|
+
end
|
|
1068
|
+
end
|
|
1069
|
+
|
|
1070
|
+
-- fallback to defaults
|
|
1071
|
+
if (animTable[name].count <= 0) then
|
|
1072
|
+
for idx, anim in pairs(fileList) do
|
|
1073
|
+
animTable[name][idx] = {}
|
|
1074
|
+
animTable[name][idx].anim = Instance.new("Animation")
|
|
1075
|
+
animTable[name][idx].anim.Name = name
|
|
1076
|
+
animTable[name][idx].anim.AnimationId = anim.id
|
|
1077
|
+
animTable[name][idx].weight = anim.weight
|
|
1078
|
+
animTable[name].count = animTable[name].count + 1
|
|
1079
|
+
animTable[name].totalWeight = animTable[name].totalWeight + anim.weight
|
|
1080
|
+
-- print(name .. " [" .. idx .. "] " .. anim.id .. " (" .. anim.weight .. ")")
|
|
1081
|
+
end
|
|
1082
|
+
end
|
|
1083
|
+
end
|
|
1084
|
+
|
|
1085
|
+
-- Setup animation objects
|
|
1086
|
+
function scriptChildModified(child)
|
|
1087
|
+
local fileList = animNames[child.Name]
|
|
1088
|
+
if (fileList ~= nil) then
|
|
1089
|
+
configureAnimationSet(child.Name, fileList)
|
|
1090
|
+
end
|
|
1091
|
+
end
|
|
1092
|
+
|
|
1093
|
+
script.ChildAdded:connect(scriptChildModified)
|
|
1094
|
+
script.ChildRemoved:connect(scriptChildModified)
|
|
1095
|
+
|
|
1096
|
+
|
|
1097
|
+
for name, fileList in pairs(animNames) do
|
|
1098
|
+
configureAnimationSet(name, fileList)
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1101
|
+
-- ANIMATION
|
|
1102
|
+
|
|
1103
|
+
-- declarations
|
|
1104
|
+
local toolAnim = "None"
|
|
1105
|
+
local toolAnimTime = 0
|
|
1106
|
+
|
|
1107
|
+
local jumpAnimTime = 0
|
|
1108
|
+
local jumpAnimDuration = 0.3
|
|
1109
|
+
|
|
1110
|
+
local toolTransitionTime = 0.1
|
|
1111
|
+
local fallTransitionTime = 0.3
|
|
1112
|
+
local jumpMaxLimbVelocity = 0.75
|
|
1113
|
+
|
|
1114
|
+
-- functions
|
|
1115
|
+
|
|
1116
|
+
function stopAllAnimations()
|
|
1117
|
+
local oldAnim = currentAnim
|
|
1118
|
+
|
|
1119
|
+
-- return to idle if finishing an emote
|
|
1120
|
+
if (emoteNames[oldAnim] ~= nil and emoteNames[oldAnim] == false) then
|
|
1121
|
+
oldAnim = "idle"
|
|
1122
|
+
end
|
|
1123
|
+
|
|
1124
|
+
currentAnim = ""
|
|
1125
|
+
currentAnimInstance = nil
|
|
1126
|
+
if (currentAnimKeyframeHandler ~= nil) then
|
|
1127
|
+
currentAnimKeyframeHandler:disconnect()
|
|
1128
|
+
end
|
|
1129
|
+
|
|
1130
|
+
if (currentAnimTrack ~= nil) then
|
|
1131
|
+
currentAnimTrack:Stop()
|
|
1132
|
+
currentAnimTrack:Destroy()
|
|
1133
|
+
currentAnimTrack = nil
|
|
1134
|
+
end
|
|
1135
|
+
return oldAnim
|
|
1136
|
+
end
|
|
1137
|
+
|
|
1138
|
+
function setAnimationSpeed(speed)
|
|
1139
|
+
if speed ~= currentAnimSpeed then
|
|
1140
|
+
currentAnimSpeed = speed
|
|
1141
|
+
currentAnimTrack:AdjustSpeed(currentAnimSpeed)
|
|
1142
|
+
end
|
|
1143
|
+
end
|
|
1144
|
+
|
|
1145
|
+
function keyFrameReachedFunc(frameName)
|
|
1146
|
+
if (frameName == "End") then
|
|
1147
|
+
|
|
1148
|
+
local repeatAnim = currentAnim
|
|
1149
|
+
-- return to idle if finishing an emote
|
|
1150
|
+
if (emoteNames[repeatAnim] ~= nil and emoteNames[repeatAnim] == false) then
|
|
1151
|
+
repeatAnim = "idle"
|
|
1152
|
+
end
|
|
1153
|
+
|
|
1154
|
+
local animSpeed = currentAnimSpeed
|
|
1155
|
+
playAnimation(repeatAnim, 0.0, Humanoid)
|
|
1156
|
+
setAnimationSpeed(animSpeed)
|
|
1157
|
+
end
|
|
1158
|
+
end
|
|
1159
|
+
|
|
1160
|
+
-- Preload animations
|
|
1161
|
+
function playAnimation(animName, transitionTime, humanoid)
|
|
1162
|
+
|
|
1163
|
+
local roll = math.random(1, animTable[animName].totalWeight)
|
|
1164
|
+
local origRoll = roll
|
|
1165
|
+
local idx = 1
|
|
1166
|
+
while (roll > animTable[animName][idx].weight) do
|
|
1167
|
+
roll = roll - animTable[animName][idx].weight
|
|
1168
|
+
idx = idx + 1
|
|
1169
|
+
end
|
|
1170
|
+
-- print(animName .. " " .. idx .. " [" .. origRoll .. "]")
|
|
1171
|
+
local anim = animTable[animName][idx].anim
|
|
1172
|
+
|
|
1173
|
+
-- switch animation
|
|
1174
|
+
if (anim ~= currentAnimInstance) then
|
|
1175
|
+
|
|
1176
|
+
if (currentAnimTrack ~= nil) then
|
|
1177
|
+
currentAnimTrack:Stop(transitionTime)
|
|
1178
|
+
currentAnimTrack:Destroy()
|
|
1179
|
+
end
|
|
1180
|
+
|
|
1181
|
+
currentAnimSpeed = 1.0
|
|
1182
|
+
|
|
1183
|
+
-- load it to the humanoid; get AnimationTrack
|
|
1184
|
+
currentAnimTrack = humanoid:LoadAnimation(anim)
|
|
1185
|
+
currentAnimTrack.Priority = Enum.AnimationPriority.Core
|
|
1186
|
+
|
|
1187
|
+
-- play the animation
|
|
1188
|
+
currentAnimTrack:Play(transitionTime)
|
|
1189
|
+
currentAnim = animName
|
|
1190
|
+
currentAnimInstance = anim
|
|
1191
|
+
|
|
1192
|
+
-- set up keyframe name triggers
|
|
1193
|
+
if (currentAnimKeyframeHandler ~= nil) then
|
|
1194
|
+
currentAnimKeyframeHandler:disconnect()
|
|
1195
|
+
end
|
|
1196
|
+
currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc)
|
|
1197
|
+
|
|
1198
|
+
end
|
|
1199
|
+
|
|
1200
|
+
end
|
|
1201
|
+
|
|
1202
|
+
-------------------------------------------------------------------------------------------
|
|
1203
|
+
-------------------------------------------------------------------------------------------
|
|
1204
|
+
|
|
1205
|
+
local toolAnimName = ""
|
|
1206
|
+
local toolAnimTrack = nil
|
|
1207
|
+
local toolAnimInstance = nil
|
|
1208
|
+
local currentToolAnimKeyframeHandler = nil
|
|
1209
|
+
|
|
1210
|
+
function toolKeyFrameReachedFunc(frameName)
|
|
1211
|
+
if (frameName == "End") then
|
|
1212
|
+
-- print("Keyframe : ".. frameName)
|
|
1213
|
+
playToolAnimation(toolAnimName, 0.0, Humanoid)
|
|
1214
|
+
end
|
|
1215
|
+
end
|
|
1216
|
+
|
|
1217
|
+
|
|
1218
|
+
function playToolAnimation(animName, transitionTime, humanoid, priority)
|
|
1219
|
+
|
|
1220
|
+
local roll = math.random(1, animTable[animName].totalWeight)
|
|
1221
|
+
local origRoll = roll
|
|
1222
|
+
local idx = 1
|
|
1223
|
+
while (roll > animTable[animName][idx].weight) do
|
|
1224
|
+
roll = roll - animTable[animName][idx].weight
|
|
1225
|
+
idx = idx + 1
|
|
1226
|
+
end
|
|
1227
|
+
-- print(animName .. " * " .. idx .. " [" .. origRoll .. "]")
|
|
1228
|
+
local anim = animTable[animName][idx].anim
|
|
1229
|
+
|
|
1230
|
+
if (toolAnimInstance ~= anim) then
|
|
1231
|
+
|
|
1232
|
+
if (toolAnimTrack ~= nil) then
|
|
1233
|
+
toolAnimTrack:Stop()
|
|
1234
|
+
toolAnimTrack:Destroy()
|
|
1235
|
+
transitionTime = 0
|
|
1236
|
+
end
|
|
1237
|
+
|
|
1238
|
+
-- load it to the humanoid; get AnimationTrack
|
|
1239
|
+
toolAnimTrack = humanoid:LoadAnimation(anim)
|
|
1240
|
+
if priority then
|
|
1241
|
+
toolAnimTrack.Priority = priority
|
|
1242
|
+
end
|
|
1243
|
+
|
|
1244
|
+
-- play the animation
|
|
1245
|
+
toolAnimTrack:Play(transitionTime)
|
|
1246
|
+
toolAnimName = animName
|
|
1247
|
+
toolAnimInstance = anim
|
|
1248
|
+
|
|
1249
|
+
currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc)
|
|
1250
|
+
end
|
|
1251
|
+
end
|
|
1252
|
+
|
|
1253
|
+
function stopToolAnimations()
|
|
1254
|
+
local oldAnim = toolAnimName
|
|
1255
|
+
|
|
1256
|
+
if (currentToolAnimKeyframeHandler ~= nil) then
|
|
1257
|
+
currentToolAnimKeyframeHandler:disconnect()
|
|
1258
|
+
end
|
|
1259
|
+
|
|
1260
|
+
toolAnimName = ""
|
|
1261
|
+
toolAnimInstance = nil
|
|
1262
|
+
if (toolAnimTrack ~= nil) then
|
|
1263
|
+
toolAnimTrack:Stop()
|
|
1264
|
+
toolAnimTrack:Destroy()
|
|
1265
|
+
toolAnimTrack = nil
|
|
1266
|
+
end
|
|
1267
|
+
|
|
1268
|
+
|
|
1269
|
+
return oldAnim
|
|
1270
|
+
end
|
|
1271
|
+
|
|
1272
|
+
-------------------------------------------------------------------------------------------
|
|
1273
|
+
-------------------------------------------------------------------------------------------
|
|
1274
|
+
|
|
1275
|
+
|
|
1276
|
+
function onRunning(speed)
|
|
1277
|
+
if speed > 0.01 then
|
|
1278
|
+
playAnimation("walk", 0.1, Humanoid)
|
|
1279
|
+
if currentAnimInstance and currentAnimInstance.AnimationId == "http://www.roblox.com/asset/?id=180426354" then
|
|
1280
|
+
setAnimationSpeed(speed / 14.5)
|
|
1281
|
+
end
|
|
1282
|
+
pose = "Running"
|
|
1283
|
+
else
|
|
1284
|
+
if emoteNames[currentAnim] == nil then
|
|
1285
|
+
playAnimation("idle", 0.1, Humanoid)
|
|
1286
|
+
pose = "Standing"
|
|
1287
|
+
end
|
|
1288
|
+
end
|
|
1289
|
+
end
|
|
1290
|
+
|
|
1291
|
+
function onDied()
|
|
1292
|
+
pose = "Dead"
|
|
1293
|
+
end
|
|
1294
|
+
|
|
1295
|
+
function onJumping()
|
|
1296
|
+
playAnimation("jump", 0.1, Humanoid)
|
|
1297
|
+
jumpAnimTime = jumpAnimDuration
|
|
1298
|
+
pose = "Jumping"
|
|
1299
|
+
end
|
|
1300
|
+
|
|
1301
|
+
function onClimbing(speed)
|
|
1302
|
+
playAnimation("climb", 0.1, Humanoid)
|
|
1303
|
+
setAnimationSpeed(speed / 12.0)
|
|
1304
|
+
pose = "Climbing"
|
|
1305
|
+
end
|
|
1306
|
+
|
|
1307
|
+
function onGettingUp()
|
|
1308
|
+
pose = "GettingUp"
|
|
1309
|
+
end
|
|
1310
|
+
|
|
1311
|
+
function onFreeFall()
|
|
1312
|
+
if (jumpAnimTime <= 0) then
|
|
1313
|
+
playAnimation("fall", fallTransitionTime, Humanoid)
|
|
1314
|
+
end
|
|
1315
|
+
pose = "FreeFall"
|
|
1316
|
+
end
|
|
1317
|
+
|
|
1318
|
+
function onFallingDown()
|
|
1319
|
+
pose = "FallingDown"
|
|
1320
|
+
end
|
|
1321
|
+
|
|
1322
|
+
function onSeated()
|
|
1323
|
+
pose = "Seated"
|
|
1324
|
+
end
|
|
1325
|
+
|
|
1326
|
+
function onPlatformStanding()
|
|
1327
|
+
pose = "PlatformStanding"
|
|
1328
|
+
end
|
|
1329
|
+
|
|
1330
|
+
function onSwimming(speed)
|
|
1331
|
+
if speed > 0 then
|
|
1332
|
+
pose = "Running"
|
|
1333
|
+
else
|
|
1334
|
+
pose = "Standing"
|
|
1335
|
+
end
|
|
1336
|
+
end
|
|
1337
|
+
|
|
1338
|
+
function getTool()
|
|
1339
|
+
for _, kid in ipairs(Figure:GetChildren()) do
|
|
1340
|
+
if kid.className == "Tool" then return kid end
|
|
1341
|
+
end
|
|
1342
|
+
return nil
|
|
1343
|
+
end
|
|
1344
|
+
|
|
1345
|
+
function getToolAnim(tool)
|
|
1346
|
+
for _, c in ipairs(tool:GetChildren()) do
|
|
1347
|
+
if c.Name == "toolanim" and c.className == "StringValue" then
|
|
1348
|
+
return c
|
|
1349
|
+
end
|
|
1350
|
+
end
|
|
1351
|
+
return nil
|
|
1352
|
+
end
|
|
1353
|
+
|
|
1354
|
+
function animateTool()
|
|
1355
|
+
|
|
1356
|
+
if (toolAnim == "None") then
|
|
1357
|
+
playToolAnimation("toolnone", toolTransitionTime, Humanoid, Enum.AnimationPriority.Idle)
|
|
1358
|
+
return
|
|
1359
|
+
end
|
|
1360
|
+
|
|
1361
|
+
if (toolAnim == "Slash") then
|
|
1362
|
+
playToolAnimation("toolslash", 0, Humanoid, Enum.AnimationPriority.Action)
|
|
1363
|
+
return
|
|
1364
|
+
end
|
|
1365
|
+
|
|
1366
|
+
if (toolAnim == "Lunge") then
|
|
1367
|
+
playToolAnimation("toollunge", 0, Humanoid, Enum.AnimationPriority.Action)
|
|
1368
|
+
return
|
|
1369
|
+
end
|
|
1370
|
+
end
|
|
1371
|
+
|
|
1372
|
+
function moveSit()
|
|
1373
|
+
RightShoulder.MaxVelocity = 0.15
|
|
1374
|
+
LeftShoulder.MaxVelocity = 0.15
|
|
1375
|
+
RightShoulder:SetDesiredAngle(3.14 /2)
|
|
1376
|
+
LeftShoulder:SetDesiredAngle(-3.14 /2)
|
|
1377
|
+
RightHip:SetDesiredAngle(3.14 /2)
|
|
1378
|
+
LeftHip:SetDesiredAngle(-3.14 /2)
|
|
1379
|
+
end
|
|
1380
|
+
|
|
1381
|
+
local lastTick = 0
|
|
1382
|
+
|
|
1383
|
+
function move(time)
|
|
1384
|
+
local amplitude = 1
|
|
1385
|
+
local frequency = 1
|
|
1386
|
+
local deltaTime = time - lastTick
|
|
1387
|
+
lastTick = time
|
|
1388
|
+
|
|
1389
|
+
local climbFudge = 0
|
|
1390
|
+
local setAngles = false
|
|
1391
|
+
|
|
1392
|
+
if (jumpAnimTime > 0) then
|
|
1393
|
+
jumpAnimTime = jumpAnimTime - deltaTime
|
|
1394
|
+
end
|
|
1395
|
+
|
|
1396
|
+
if (pose == "FreeFall" and jumpAnimTime <= 0) then
|
|
1397
|
+
playAnimation("fall", fallTransitionTime, Humanoid)
|
|
1398
|
+
elseif (pose == "Seated") then
|
|
1399
|
+
playAnimation("sit", 0.5, Humanoid)
|
|
1400
|
+
return
|
|
1401
|
+
elseif (pose == "Running") then
|
|
1402
|
+
playAnimation("walk", 0.1, Humanoid)
|
|
1403
|
+
elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then
|
|
1404
|
+
-- print("Wha " .. pose)
|
|
1405
|
+
stopAllAnimations()
|
|
1406
|
+
amplitude = 0.1
|
|
1407
|
+
frequency = 1
|
|
1408
|
+
setAngles = true
|
|
1409
|
+
end
|
|
1410
|
+
|
|
1411
|
+
if (setAngles) then
|
|
1412
|
+
local desiredAngle = amplitude * math.sin(time * frequency)
|
|
1413
|
+
|
|
1414
|
+
RightShoulder:SetDesiredAngle(desiredAngle + climbFudge)
|
|
1415
|
+
LeftShoulder:SetDesiredAngle(desiredAngle - climbFudge)
|
|
1416
|
+
RightHip:SetDesiredAngle(-desiredAngle)
|
|
1417
|
+
LeftHip:SetDesiredAngle(-desiredAngle)
|
|
1418
|
+
end
|
|
1419
|
+
|
|
1420
|
+
-- Tool Animation handling
|
|
1421
|
+
local tool = getTool()
|
|
1422
|
+
if tool and tool:FindFirstChild("Handle") then
|
|
1423
|
+
|
|
1424
|
+
local animStringValueObject = getToolAnim(tool)
|
|
1425
|
+
|
|
1426
|
+
if animStringValueObject then
|
|
1427
|
+
toolAnim = animStringValueObject.Value
|
|
1428
|
+
-- message recieved, delete StringValue
|
|
1429
|
+
animStringValueObject.Parent = nil
|
|
1430
|
+
toolAnimTime = time + .3
|
|
1431
|
+
end
|
|
1432
|
+
|
|
1433
|
+
if time > toolAnimTime then
|
|
1434
|
+
toolAnimTime = 0
|
|
1435
|
+
toolAnim = "None"
|
|
1436
|
+
end
|
|
1437
|
+
|
|
1438
|
+
animateTool()
|
|
1439
|
+
else
|
|
1440
|
+
stopToolAnimations()
|
|
1441
|
+
toolAnim = "None"
|
|
1442
|
+
toolAnimInstance = nil
|
|
1443
|
+
toolAnimTime = 0
|
|
1444
|
+
end
|
|
1445
|
+
end
|
|
1446
|
+
|
|
1447
|
+
|
|
1448
|
+
local events = {}
|
|
1449
|
+
local eventHum = Humanoid
|
|
1450
|
+
local RepHumanoid = script:WaitForChild("ReplicatedHumanoid")
|
|
1451
|
+
|
|
1452
|
+
local function onUnhook()
|
|
1453
|
+
for i = 1, #events do
|
|
1454
|
+
events[i]:Disconnect()
|
|
1455
|
+
end
|
|
1456
|
+
events = {}
|
|
1457
|
+
end
|
|
1458
|
+
|
|
1459
|
+
local function onHook()
|
|
1460
|
+
onUnhook()
|
|
1461
|
+
|
|
1462
|
+
pose = Humanoid.Sit and "Seated" or "Standing"
|
|
1463
|
+
|
|
1464
|
+
events = {
|
|
1465
|
+
eventHum.Died:connect(onDied),
|
|
1466
|
+
eventHum.Running:connect(onRunning),
|
|
1467
|
+
eventHum.Jumping:connect(onJumping),
|
|
1468
|
+
eventHum.Climbing:connect(onClimbing),
|
|
1469
|
+
eventHum.GettingUp:connect(onGettingUp),
|
|
1470
|
+
eventHum.FreeFalling:connect(onFreeFall),
|
|
1471
|
+
eventHum.FallingDown:connect(onFallingDown),
|
|
1472
|
+
eventHum.Seated:connect(onSeated),
|
|
1473
|
+
eventHum.PlatformStanding:connect(onPlatformStanding),
|
|
1474
|
+
eventHum.Swimming:connect(onSwimming)
|
|
1475
|
+
}
|
|
1476
|
+
end
|
|
1477
|
+
|
|
1478
|
+
RepHumanoid.Changed:Connect(function()
|
|
1479
|
+
eventHum = RepHumanoid.Value
|
|
1480
|
+
onHook()
|
|
1481
|
+
end)
|
|
1482
|
+
|
|
1483
|
+
RepHumanoid.Value = Humanoid
|
|
1484
|
+
|
|
1485
|
+
-- setup emote chat hook
|
|
1486
|
+
game:GetService("Players").LocalPlayer.Chatted:connect(function(msg)
|
|
1487
|
+
local emote = ""
|
|
1488
|
+
if msg == "/e dance" then
|
|
1489
|
+
emote = dances[math.random(1, #dances)]
|
|
1490
|
+
elseif (string.sub(msg, 1, 3) == "/e ") then
|
|
1491
|
+
emote = string.sub(msg, 4)
|
|
1492
|
+
elseif (string.sub(msg, 1, 7) == "/emote ") then
|
|
1493
|
+
emote = string.sub(msg, 8)
|
|
1494
|
+
end
|
|
1495
|
+
|
|
1496
|
+
if (pose == "Standing" and emoteNames[emote] ~= nil) then
|
|
1497
|
+
playAnimation(emote, 0.1, Humanoid)
|
|
1498
|
+
end
|
|
1499
|
+
|
|
1500
|
+
end)
|
|
1501
|
+
|
|
1502
|
+
|
|
1503
|
+
-- main program
|
|
1504
|
+
|
|
1505
|
+
-- initialize to idle
|
|
1506
|
+
playAnimation("idle", 0.1, Humanoid)
|
|
1507
|
+
pose = "Standing"
|
|
1508
|
+
|
|
1509
|
+
spawn(function()
|
|
1510
|
+
while Figure.Parent ~= nil do
|
|
1511
|
+
local _, time = wait(0.1)
|
|
1512
|
+
move(time)
|
|
1513
|
+
end
|
|
1514
|
+
end)
|
|
1515
|
+
|
|
1516
|
+
return {
|
|
1517
|
+
onRunning = onRunning,
|
|
1518
|
+
onDied = onDied,
|
|
1519
|
+
onJumping = onJumping,
|
|
1520
|
+
onClimbing = onClimbing,
|
|
1521
|
+
onGettingUp = onGettingUp,
|
|
1522
|
+
onFreeFall = onFreeFall,
|
|
1523
|
+
onFallingDown = onFallingDown,
|
|
1524
|
+
onSeated = onSeated,
|
|
1525
|
+
onPlatformStanding = onPlatformStanding,
|
|
1526
|
+
onHook = onHook,
|
|
1527
|
+
onUnhook = onUnhook
|
|
1528
|
+
}</string>
|
|
1529
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
1530
|
+
<BinaryString name="Tags"></BinaryString>
|
|
1531
|
+
</Properties>
|
|
1532
|
+
</Item>
|
|
1533
|
+
<Item class="ObjectValue" referent="8">
|
|
1534
|
+
<Properties>
|
|
1535
|
+
<string name="Name">ReplicatedHumanoid</string>
|
|
1536
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
1537
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
1538
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
1539
|
+
<BinaryString name="Tags"></BinaryString>
|
|
1540
|
+
<Ref name="Value">null</Ref>
|
|
1541
|
+
</Properties>
|
|
1542
|
+
</Item>
|
|
1543
|
+
<Item class="ModuleScript" referent="9">
|
|
1544
|
+
<Properties>
|
|
1545
|
+
<string name="Name">VerifyAnims</string>
|
|
1546
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
1547
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
1548
|
+
<Content name="LinkedSource">
|
|
1549
|
+
<null>
|
|
1550
|
+
</null>
|
|
1551
|
+
</Content>
|
|
1552
|
+
<string name="Source">local LENGTH = string.len("Animation")
|
|
1553
|
+
|
|
1554
|
+
local DESC_ANIM_PROPS = {
|
|
1555
|
+
["ClimbAnimation"] = true,
|
|
1556
|
+
["FallAnimation"] = true,
|
|
1557
|
+
["IdleAnimation"] = true,
|
|
1558
|
+
["JumpAnimation"] = true,
|
|
1559
|
+
["RunAnimation"] = true,
|
|
1560
|
+
["SwimAnimation"] = true,
|
|
1561
|
+
["WalkAnimation"] = true,
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
return function(humanoid, animate)
|
|
1565
|
+
local desc = humanoid:GetAppliedDescription()
|
|
1566
|
+
|
|
1567
|
+
if humanoid.RigType == Enum.HumanoidRigType.R6 then
|
|
1568
|
+
return
|
|
1569
|
+
end
|
|
1570
|
+
|
|
1571
|
+
for prop, _ in pairs(DESC_ANIM_PROPS) do
|
|
1572
|
+
if desc[prop] > 0 then
|
|
1573
|
+
local lookFor = prop:sub(1, #prop - LENGTH):lower()
|
|
1574
|
+
animate:WaitForChild(lookFor)
|
|
1575
|
+
end
|
|
1576
|
+
end
|
|
1577
|
+
end</string>
|
|
1578
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
1579
|
+
<BinaryString name="Tags"></BinaryString>
|
|
1580
|
+
</Properties>
|
|
1581
|
+
</Item>
|
|
1582
|
+
</Item>
|
|
1583
|
+
<Item class="LocalScript" referent="10">
|
|
1584
|
+
<Properties>
|
|
1585
|
+
<string name="Name">PlayerScriptsLoader</string>
|
|
1586
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
1587
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
1588
|
+
<bool name="Disabled">false</bool>
|
|
1589
|
+
<Content name="LinkedSource">
|
|
1590
|
+
<null>
|
|
1591
|
+
</null>
|
|
1592
|
+
</Content>
|
|
1593
|
+
<token name="RunContext">0</token>
|
|
1594
|
+
<string name="Source">--[[
|
|
1595
|
+
PlayerScriptsLoader - This script requires and instantiates the PlayerModule singleton
|
|
1596
|
+
|
|
1597
|
+
2018 PlayerScripts Update - AllYourBlox
|
|
1598
|
+
2020 CameraModule Public Access Override & modifications - EgoMoose
|
|
1599
|
+
--]]
|
|
1600
|
+
|
|
1601
|
+
local MIN_Y = math.rad(-80)
|
|
1602
|
+
local MAX_Y = math.rad(80)
|
|
1603
|
+
local ZERO3 = Vector3.new(0, 0, 0)
|
|
1604
|
+
|
|
1605
|
+
local PlayerModule = script.Parent:WaitForChild("PlayerModule")
|
|
1606
|
+
local CameraInjector = script:WaitForChild("CameraInjector")
|
|
1607
|
+
|
|
1608
|
+
require(CameraInjector)
|
|
1609
|
+
|
|
1610
|
+
-- Control Modifications
|
|
1611
|
+
|
|
1612
|
+
local Control = require(PlayerModule:WaitForChild("ControlModule"))
|
|
1613
|
+
local TouchJump = require(PlayerModule.ControlModule:WaitForChild("TouchJump"))
|
|
1614
|
+
|
|
1615
|
+
function Control:IsJumping()
|
|
1616
|
+
if self.activeController then
|
|
1617
|
+
return self.activeController:GetIsJumping()
|
|
1618
|
+
or (self.touchJumpController and self.touchJumpController:GetIsJumping())
|
|
1619
|
+
end
|
|
1620
|
+
return false
|
|
1621
|
+
end
|
|
1622
|
+
|
|
1623
|
+
local oldEnabled = TouchJump.UpdateEnabled
|
|
1624
|
+
|
|
1625
|
+
function TouchJump:UpdateEnabled()
|
|
1626
|
+
self.jumpStateEnabled = true
|
|
1627
|
+
oldEnabled(self)
|
|
1628
|
+
end
|
|
1629
|
+
|
|
1630
|
+
-- Camera Modifications
|
|
1631
|
+
|
|
1632
|
+
local CameraModule = PlayerModule:WaitForChild("CameraModule")
|
|
1633
|
+
|
|
1634
|
+
local UserSettings = require(script:WaitForChild("FakeUserSettings"))
|
|
1635
|
+
local UserGameSettings = UserSettings():GetService("UserGameSettings")
|
|
1636
|
+
|
|
1637
|
+
local FFlagUserFlagEnableNewVRSystem = UserSettings():SafeIsUserFeatureEnabled("UserFlagEnableNewVRSystem")
|
|
1638
|
+
|
|
1639
|
+
-- Camera variables
|
|
1640
|
+
|
|
1641
|
+
local transitionRate = 0.15
|
|
1642
|
+
local upVector = Vector3.new(0, 1, 0)
|
|
1643
|
+
local upCFrame = CFrame.new()
|
|
1644
|
+
|
|
1645
|
+
local spinPart = workspace.Terrain
|
|
1646
|
+
local prevSpinPart = spinPart
|
|
1647
|
+
local prevSpinCFrame = spinPart.CFrame
|
|
1648
|
+
local twistCFrame = CFrame.new()
|
|
1649
|
+
|
|
1650
|
+
-- Camera Utilities
|
|
1651
|
+
|
|
1652
|
+
local Utils = require(CameraModule:WaitForChild("CameraUtils"))
|
|
1653
|
+
|
|
1654
|
+
function Utils.GetAngleBetweenXZVectors(v1, v2)
|
|
1655
|
+
v1 = upCFrame:VectorToObjectSpace(v1)
|
|
1656
|
+
v2 = upCFrame:VectorToObjectSpace(v2)
|
|
1657
|
+
return math.atan2(v2.X*v1.Z-v2.Z*v1.X, v2.X*v1.X+v2.Z*v1.Z)
|
|
1658
|
+
end
|
|
1659
|
+
|
|
1660
|
+
-- Popper Camera
|
|
1661
|
+
|
|
1662
|
+
local Poppercam = require(CameraModule:WaitForChild("Poppercam"))
|
|
1663
|
+
local ZoomController = require(CameraModule:WaitForChild("ZoomController"))
|
|
1664
|
+
|
|
1665
|
+
function Poppercam:Update(renderDt, desiredCameraCFrame, desiredCameraFocus, cameraController)
|
|
1666
|
+
local rotatedFocus = desiredCameraFocus * (desiredCameraCFrame - desiredCameraCFrame.p)
|
|
1667
|
+
local extrapolation = self.focusExtrapolator:Step(renderDt, rotatedFocus)
|
|
1668
|
+
local zoom = ZoomController.Update(renderDt, rotatedFocus, extrapolation)
|
|
1669
|
+
return rotatedFocus*CFrame.new(0, 0, zoom), desiredCameraFocus
|
|
1670
|
+
end
|
|
1671
|
+
|
|
1672
|
+
-- Base Camera
|
|
1673
|
+
|
|
1674
|
+
local BaseCamera = require(CameraModule:WaitForChild("BaseCamera"))
|
|
1675
|
+
|
|
1676
|
+
function BaseCamera:CalculateNewLookCFrameFromArg(suppliedLookVector, rotateInput)
|
|
1677
|
+
local currLookVector = suppliedLookVector or self:GetCameraLookVector()
|
|
1678
|
+
currLookVector = upCFrame:VectorToObjectSpace(currLookVector)
|
|
1679
|
+
|
|
1680
|
+
local currPitchAngle = math.asin(currLookVector.y)
|
|
1681
|
+
local yTheta = math.clamp(rotateInput.y, -MAX_Y + currPitchAngle, -MIN_Y + currPitchAngle)
|
|
1682
|
+
local constrainedRotateInput = Vector2.new(rotateInput.x, yTheta)
|
|
1683
|
+
local startCFrame = CFrame.new(ZERO3, currLookVector)
|
|
1684
|
+
local newLookCFrame = CFrame.Angles(0, -constrainedRotateInput.x, 0) * startCFrame * CFrame.Angles(-constrainedRotateInput.y,0,0)
|
|
1685
|
+
|
|
1686
|
+
return newLookCFrame
|
|
1687
|
+
end
|
|
1688
|
+
|
|
1689
|
+
function BaseCamera:CalculateNewLookCFrame(suppliedLookVector)
|
|
1690
|
+
return self:CalculateNewLookCFrameFromArg(suppliedLookVector, self.rotateInput)
|
|
1691
|
+
end
|
|
1692
|
+
|
|
1693
|
+
local defaultUpdateMouseBehavior = BaseCamera.UpdateMouseBehavior
|
|
1694
|
+
|
|
1695
|
+
function BaseCamera:UpdateMouseBehavior()
|
|
1696
|
+
defaultUpdateMouseBehavior(self)
|
|
1697
|
+
if UserGameSettings.RotationType == Enum.RotationType.CameraRelative then
|
|
1698
|
+
UserGameSettings.RotationType = Enum.RotationType.MovementRelative
|
|
1699
|
+
end
|
|
1700
|
+
end
|
|
1701
|
+
|
|
1702
|
+
-- Vehicle Camera
|
|
1703
|
+
|
|
1704
|
+
local VehicleCamera = require(CameraModule:WaitForChild("VehicleCamera"))
|
|
1705
|
+
local VehicleCameraCore = require(CameraModule.VehicleCamera:WaitForChild("VehicleCameraCore"))
|
|
1706
|
+
local setTransform = VehicleCameraCore.setTransform
|
|
1707
|
+
|
|
1708
|
+
function VehicleCameraCore:setTransform(transform)
|
|
1709
|
+
transform = upCFrame:ToObjectSpace(transform - transform.p) + transform.p
|
|
1710
|
+
return setTransform(self, transform)
|
|
1711
|
+
end
|
|
1712
|
+
|
|
1713
|
+
-- Camera Module
|
|
1714
|
+
|
|
1715
|
+
local function getRotationBetween(u, v, axis)
|
|
1716
|
+
local dot, uxv = u:Dot(v), u:Cross(v)
|
|
1717
|
+
if dot < -0.99999 then return CFrame.fromAxisAngle(axis, math.pi) end
|
|
1718
|
+
return CFrame.new(0, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)
|
|
1719
|
+
end
|
|
1720
|
+
|
|
1721
|
+
local function twistAngle(cf, direction)
|
|
1722
|
+
local axis, theta = cf:ToAxisAngle()
|
|
1723
|
+
local w, v = math.cos(theta/2), math.sin(theta/2)*axis
|
|
1724
|
+
local proj = v:Dot(direction)*direction
|
|
1725
|
+
local twist = CFrame.new(0, 0, 0, proj.x, proj.y, proj.z, w)
|
|
1726
|
+
local nAxis, nTheta = twist:ToAxisAngle()
|
|
1727
|
+
return math.sign(v:Dot(direction))*nTheta
|
|
1728
|
+
end
|
|
1729
|
+
|
|
1730
|
+
local function calculateUpCFrame(self)
|
|
1731
|
+
local newUpVector = self:GetUpVector(upVector)
|
|
1732
|
+
|
|
1733
|
+
local axis = workspace.CurrentCamera.CFrame.RightVector
|
|
1734
|
+
local sphericalArc = getRotationBetween(upVector, newUpVector, axis)
|
|
1735
|
+
local transitionCF = CFrame.new():Lerp(sphericalArc, transitionRate)
|
|
1736
|
+
|
|
1737
|
+
upVector = transitionCF * upVector
|
|
1738
|
+
upCFrame = transitionCF * upCFrame
|
|
1739
|
+
end
|
|
1740
|
+
|
|
1741
|
+
local function calculateSpinCFrame(self)
|
|
1742
|
+
local theta = 0
|
|
1743
|
+
|
|
1744
|
+
if spinPart == prevSpinPart then
|
|
1745
|
+
local rotation = spinPart.CFrame - spinPart.CFrame.p
|
|
1746
|
+
local prevRotation = prevSpinCFrame - prevSpinCFrame.p
|
|
1747
|
+
|
|
1748
|
+
local spinAxis = rotation:VectorToObjectSpace(upVector)
|
|
1749
|
+
theta = twistAngle(prevRotation:ToObjectSpace(rotation), spinAxis)
|
|
1750
|
+
end
|
|
1751
|
+
|
|
1752
|
+
twistCFrame = CFrame.fromEulerAnglesYXZ(0, theta, 0)
|
|
1753
|
+
|
|
1754
|
+
prevSpinPart = spinPart
|
|
1755
|
+
prevSpinCFrame = spinPart.CFrame
|
|
1756
|
+
end
|
|
1757
|
+
|
|
1758
|
+
local Camera = require(CameraModule)
|
|
1759
|
+
local CameraInput = require(CameraModule:WaitForChild("CameraInput"))
|
|
1760
|
+
|
|
1761
|
+
function Camera:GetUpVector(oldUpVector)
|
|
1762
|
+
return oldUpVector
|
|
1763
|
+
end
|
|
1764
|
+
|
|
1765
|
+
function Camera:SetSpinPart(part)
|
|
1766
|
+
spinPart = part
|
|
1767
|
+
end
|
|
1768
|
+
|
|
1769
|
+
function Camera:SetTransitionRate(rate)
|
|
1770
|
+
transitionRate = rate
|
|
1771
|
+
end
|
|
1772
|
+
|
|
1773
|
+
function Camera:GetTransitionRate()
|
|
1774
|
+
return transitionRate
|
|
1775
|
+
end
|
|
1776
|
+
|
|
1777
|
+
function Camera:Update(dt)
|
|
1778
|
+
if self.activeCameraController then
|
|
1779
|
+
self.activeCameraController:UpdateMouseBehavior()
|
|
1780
|
+
|
|
1781
|
+
local newCameraCFrame, newCameraFocus = self.activeCameraController:Update(dt)
|
|
1782
|
+
newCameraFocus = CFrame.new(newCameraFocus.p) -- vehicle camera fix
|
|
1783
|
+
|
|
1784
|
+
-- if not FFlagUserFlagEnableNewVRSystem then
|
|
1785
|
+
--self.activeCameraController:ApplyVRTransform()
|
|
1786
|
+
-- end
|
|
1787
|
+
|
|
1788
|
+
calculateUpCFrame(self, dt)
|
|
1789
|
+
calculateSpinCFrame(self)
|
|
1790
|
+
|
|
1791
|
+
local lockOffset = Vector3.new(0, 0, 0)
|
|
1792
|
+
if self.activeMouseLockController and self.activeMouseLockController:GetIsMouseLocked() then
|
|
1793
|
+
lockOffset = self.activeMouseLockController:GetMouseLockOffset()
|
|
1794
|
+
end
|
|
1795
|
+
|
|
1796
|
+
local offset = newCameraFocus:ToObjectSpace(newCameraCFrame)
|
|
1797
|
+
local camRotation = upCFrame * twistCFrame * offset
|
|
1798
|
+
newCameraFocus = newCameraFocus - newCameraCFrame:VectorToWorldSpace(lockOffset) + camRotation:VectorToWorldSpace(lockOffset)
|
|
1799
|
+
newCameraCFrame = newCameraFocus * camRotation
|
|
1800
|
+
|
|
1801
|
+
if self.activeOcclusionModule then
|
|
1802
|
+
newCameraCFrame, newCameraFocus = self.activeOcclusionModule:Update(dt, newCameraCFrame, newCameraFocus)
|
|
1803
|
+
end
|
|
1804
|
+
|
|
1805
|
+
-- Here is where the new CFrame and Focus are set for this render frame
|
|
1806
|
+
game.Workspace.CurrentCamera.CFrame = newCameraCFrame
|
|
1807
|
+
game.Workspace.CurrentCamera.Focus = newCameraFocus
|
|
1808
|
+
|
|
1809
|
+
-- Update to character local transparency as needed based on camera-to-subject distance
|
|
1810
|
+
if self.activeTransparencyController then
|
|
1811
|
+
self.activeTransparencyController:Update(dt)
|
|
1812
|
+
end
|
|
1813
|
+
|
|
1814
|
+
if CameraInput.getInputEnabled() then
|
|
1815
|
+
CameraInput.resetInputForFrameEnd()
|
|
1816
|
+
end
|
|
1817
|
+
end
|
|
1818
|
+
end
|
|
1819
|
+
|
|
1820
|
+
function Camera:IsFirstPerson()
|
|
1821
|
+
if self.activeCameraController then
|
|
1822
|
+
return self.activeCameraController.inFirstPerson
|
|
1823
|
+
end
|
|
1824
|
+
return false
|
|
1825
|
+
end
|
|
1826
|
+
|
|
1827
|
+
function Camera:IsMouseLocked()
|
|
1828
|
+
if self.activeCameraController then
|
|
1829
|
+
return self.activeCameraController:GetIsMouseLocked()
|
|
1830
|
+
end
|
|
1831
|
+
return false
|
|
1832
|
+
end
|
|
1833
|
+
|
|
1834
|
+
function Camera:IsToggleMode()
|
|
1835
|
+
if self.activeCameraController then
|
|
1836
|
+
return self.activeCameraController.isCameraToggle
|
|
1837
|
+
end
|
|
1838
|
+
return false
|
|
1839
|
+
end
|
|
1840
|
+
|
|
1841
|
+
function Camera:IsCamRelative()
|
|
1842
|
+
return self:IsMouseLocked() or self:IsFirstPerson()
|
|
1843
|
+
--return self:IsToggleMode(), self:IsMouseLocked(), self:IsFirstPerson()
|
|
1844
|
+
end
|
|
1845
|
+
|
|
1846
|
+
--
|
|
1847
|
+
|
|
1848
|
+
require(PlayerModule)</string>
|
|
1849
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
1850
|
+
<BinaryString name="Tags"></BinaryString>
|
|
1851
|
+
</Properties>
|
|
1852
|
+
<Item class="ModuleScript" referent="11">
|
|
1853
|
+
<Properties>
|
|
1854
|
+
<string name="Name">CameraInjector</string>
|
|
1855
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
1856
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
1857
|
+
<Content name="LinkedSource">
|
|
1858
|
+
<null>
|
|
1859
|
+
</null>
|
|
1860
|
+
</Content>
|
|
1861
|
+
<string name="Source"><![CDATA[-- Injects into the CameraModule to override for public API access
|
|
1862
|
+
-- EgoMoose
|
|
1863
|
+
|
|
1864
|
+
local FakeUserSettingsFunc = require(script.Parent:WaitForChild("FakeUserSettings"))
|
|
1865
|
+
|
|
1866
|
+
-- Camera Injection
|
|
1867
|
+
|
|
1868
|
+
local PlayerModule = script.Parent.Parent:WaitForChild("PlayerModule")
|
|
1869
|
+
local CameraModule = PlayerModule:WaitForChild("CameraModule")
|
|
1870
|
+
local TransparencyController = require(CameraModule:WaitForChild("TransparencyController"))
|
|
1871
|
+
|
|
1872
|
+
local result = nil
|
|
1873
|
+
local copy = TransparencyController.Enable
|
|
1874
|
+
local bind = Instance.new("BindableEvent")
|
|
1875
|
+
|
|
1876
|
+
local CameraModuleSelf = nil
|
|
1877
|
+
local CameraModuleMeta = nil
|
|
1878
|
+
|
|
1879
|
+
local metasetmetatable = function(newTable:{}, newMeta:{})
|
|
1880
|
+
local env = getfenv(2)
|
|
1881
|
+
if env.script==CameraModule then
|
|
1882
|
+
CameraModuleSelf = newTable
|
|
1883
|
+
CameraModuleMeta = newMeta
|
|
1884
|
+
end
|
|
1885
|
+
return setmetatable(newTable, newMeta)
|
|
1886
|
+
end
|
|
1887
|
+
|
|
1888
|
+
local phaseTwoEnable = function(self, ...)
|
|
1889
|
+
local env = getfenv(3)
|
|
1890
|
+
env.setmetatable = nil
|
|
1891
|
+
setfenv(3, env)
|
|
1892
|
+
|
|
1893
|
+
TransparencyController.Enable = copy
|
|
1894
|
+
return copy(self, ...)
|
|
1895
|
+
end
|
|
1896
|
+
|
|
1897
|
+
TransparencyController.Enable = function(self, ...)
|
|
1898
|
+
copy(self, ...)
|
|
1899
|
+
|
|
1900
|
+
local env = getfenv(3)
|
|
1901
|
+
env.UserSettings = FakeUserSettingsFunc
|
|
1902
|
+
env.setmetatable = metasetmetatable
|
|
1903
|
+
local f = setfenv(3, env)
|
|
1904
|
+
|
|
1905
|
+
TransparencyController.Enable = phaseTwoEnable
|
|
1906
|
+
|
|
1907
|
+
result = f()
|
|
1908
|
+
if result.ActivateCameraController==nil
|
|
1909
|
+
and typeof(CameraModuleSelf)=="table"
|
|
1910
|
+
and typeof(CameraModuleSelf.ActivateCameraController)=="function" then
|
|
1911
|
+
result = CameraModuleSelf
|
|
1912
|
+
end
|
|
1913
|
+
bind.Event:Wait() -- infinite wait so no more connections can be made
|
|
1914
|
+
end
|
|
1915
|
+
|
|
1916
|
+
coroutine.wrap(function()
|
|
1917
|
+
require(CameraModule)
|
|
1918
|
+
end)()
|
|
1919
|
+
|
|
1920
|
+
-- Place children under injection
|
|
1921
|
+
|
|
1922
|
+
for _, child in pairs(CameraModule:GetChildren()) do
|
|
1923
|
+
child.Parent = script
|
|
1924
|
+
end
|
|
1925
|
+
|
|
1926
|
+
CameraModule.Name = "_CameraModule"
|
|
1927
|
+
script.Name = "CameraModule"
|
|
1928
|
+
script.Parent = PlayerModule
|
|
1929
|
+
|
|
1930
|
+
--
|
|
1931
|
+
|
|
1932
|
+
return result
|
|
1933
|
+
]]></string>
|
|
1934
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
1935
|
+
<BinaryString name="Tags"></BinaryString>
|
|
1936
|
+
</Properties>
|
|
1937
|
+
</Item>
|
|
1938
|
+
<Item class="ModuleScript" referent="12">
|
|
1939
|
+
<Properties>
|
|
1940
|
+
<string name="Name">FakeUserSettings</string>
|
|
1941
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
1942
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
1943
|
+
<Content name="LinkedSource">
|
|
1944
|
+
<null>
|
|
1945
|
+
</null>
|
|
1946
|
+
</Content>
|
|
1947
|
+
<string name="Source">local FFLAG_OVERRIDES = {
|
|
1948
|
+
["UserRemoveTheCameraApi"] = false
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
local FakeUserSettings = {}
|
|
1952
|
+
|
|
1953
|
+
function FakeUserSettings:IsUserFeatureEnabled(name)
|
|
1954
|
+
if FFLAG_OVERRIDES[name] ~= nil then
|
|
1955
|
+
return FFLAG_OVERRIDES[name]
|
|
1956
|
+
end
|
|
1957
|
+
return UserSettings():IsUserFeatureEnabled(name)
|
|
1958
|
+
end
|
|
1959
|
+
|
|
1960
|
+
function FakeUserSettings:SafeIsUserFeatureEnabled(name)
|
|
1961
|
+
local success, result = pcall(function()
|
|
1962
|
+
return self:IsUserFeatureEnabled(name)
|
|
1963
|
+
end)
|
|
1964
|
+
return success and result
|
|
1965
|
+
end
|
|
1966
|
+
|
|
1967
|
+
function FakeUserSettings:GetService(name)
|
|
1968
|
+
return UserSettings():GetService(name)
|
|
1969
|
+
end
|
|
1970
|
+
|
|
1971
|
+
local function FakeUserSettingsFunc()
|
|
1972
|
+
return FakeUserSettings
|
|
1973
|
+
end
|
|
1974
|
+
|
|
1975
|
+
return FakeUserSettingsFunc</string>
|
|
1976
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
1977
|
+
<BinaryString name="Tags"></BinaryString>
|
|
1978
|
+
</Properties>
|
|
1979
|
+
</Item>
|
|
1980
|
+
</Item>
|
|
1981
|
+
<Item class="LocalScript" referent="13">
|
|
1982
|
+
<Properties>
|
|
1983
|
+
<string name="Name">RbxCharacterSounds</string>
|
|
1984
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
1985
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
1986
|
+
<bool name="Disabled">false</bool>
|
|
1987
|
+
<Content name="LinkedSource">
|
|
1988
|
+
<null>
|
|
1989
|
+
</null>
|
|
1990
|
+
</Content>
|
|
1991
|
+
<token name="RunContext">0</token>
|
|
1992
|
+
<string name="Source"><![CDATA[-- Roblox character sound script
|
|
1993
|
+
|
|
1994
|
+
local Players = game:GetService("Players")
|
|
1995
|
+
local RunService = game:GetService("RunService")
|
|
1996
|
+
|
|
1997
|
+
local AnimationState = require(script:WaitForChild("AnimationState"))
|
|
1998
|
+
|
|
1999
|
+
local SOUND_DATA = {
|
|
2000
|
+
Climbing = {
|
|
2001
|
+
SoundId = "rbxasset://sounds/action_footsteps_plastic.mp3",
|
|
2002
|
+
Looped = true,
|
|
2003
|
+
},
|
|
2004
|
+
Died = {
|
|
2005
|
+
SoundId = "rbxasset://sounds/uuhhh.mp3",
|
|
2006
|
+
},
|
|
2007
|
+
FreeFalling = {
|
|
2008
|
+
SoundId = "rbxasset://sounds/action_falling.mp3",
|
|
2009
|
+
Looped = true,
|
|
2010
|
+
},
|
|
2011
|
+
GettingUp = {
|
|
2012
|
+
SoundId = "rbxasset://sounds/action_get_up.mp3",
|
|
2013
|
+
},
|
|
2014
|
+
Jumping = {
|
|
2015
|
+
SoundId = "rbxasset://sounds/action_jump.mp3",
|
|
2016
|
+
},
|
|
2017
|
+
Landing = {
|
|
2018
|
+
SoundId = "rbxasset://sounds/action_jump_land.mp3",
|
|
2019
|
+
},
|
|
2020
|
+
Running = {
|
|
2021
|
+
SoundId = "rbxasset://sounds/action_footsteps_plastic.mp3",
|
|
2022
|
+
Looped = true,
|
|
2023
|
+
Pitch = 1.85,
|
|
2024
|
+
},
|
|
2025
|
+
Splash = {
|
|
2026
|
+
SoundId = "rbxasset://sounds/impact_water.mp3",
|
|
2027
|
+
},
|
|
2028
|
+
Swimming = {
|
|
2029
|
+
SoundId = "rbxasset://sounds/action_swim.mp3",
|
|
2030
|
+
Looped = true,
|
|
2031
|
+
Pitch = 1.6,
|
|
2032
|
+
},
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
-- wait for the first of the passed signals to fire
|
|
2036
|
+
local function waitForFirst(...)
|
|
2037
|
+
local shunt = Instance.new("BindableEvent")
|
|
2038
|
+
local slots = {...}
|
|
2039
|
+
|
|
2040
|
+
local function fire(...)
|
|
2041
|
+
for i = 1, #slots do
|
|
2042
|
+
slots[i]:Disconnect()
|
|
2043
|
+
end
|
|
2044
|
+
|
|
2045
|
+
return shunt:Fire(...)
|
|
2046
|
+
end
|
|
2047
|
+
|
|
2048
|
+
for i = 1, #slots do
|
|
2049
|
+
slots[i] = slots[i]:Connect(fire)
|
|
2050
|
+
end
|
|
2051
|
+
|
|
2052
|
+
return shunt.Event:Wait()
|
|
2053
|
+
end
|
|
2054
|
+
|
|
2055
|
+
-- map a value from one range to another
|
|
2056
|
+
local function map(x, inMin, inMax, outMin, outMax)
|
|
2057
|
+
return (x - inMin)*(outMax - outMin)/(inMax - inMin) + outMin
|
|
2058
|
+
end
|
|
2059
|
+
|
|
2060
|
+
local function playSound(sound)
|
|
2061
|
+
sound.TimePosition = 0
|
|
2062
|
+
sound.Playing = true
|
|
2063
|
+
end
|
|
2064
|
+
|
|
2065
|
+
local function shallowCopy(t)
|
|
2066
|
+
local out = {}
|
|
2067
|
+
for k, v in pairs(t) do
|
|
2068
|
+
out[k] = v
|
|
2069
|
+
end
|
|
2070
|
+
return out
|
|
2071
|
+
end
|
|
2072
|
+
|
|
2073
|
+
local function initializeSoundSystem(player, humanoid, rootPart)
|
|
2074
|
+
local sounds = {}
|
|
2075
|
+
|
|
2076
|
+
-- initialize sounds
|
|
2077
|
+
for name, props in pairs(SOUND_DATA) do
|
|
2078
|
+
local sound = Instance.new("Sound")
|
|
2079
|
+
sound.Name = name
|
|
2080
|
+
|
|
2081
|
+
-- set default values
|
|
2082
|
+
sound.Archivable = false
|
|
2083
|
+
sound.EmitterSize = 5
|
|
2084
|
+
sound.MaxDistance = 150
|
|
2085
|
+
sound.Volume = 0.65
|
|
2086
|
+
|
|
2087
|
+
for propName, propValue in pairs(props) do
|
|
2088
|
+
sound[propName] = propValue
|
|
2089
|
+
end
|
|
2090
|
+
|
|
2091
|
+
sound.Parent = rootPart
|
|
2092
|
+
sounds[name] = sound
|
|
2093
|
+
end
|
|
2094
|
+
|
|
2095
|
+
local playingLoopedSounds = {}
|
|
2096
|
+
|
|
2097
|
+
local function stopPlayingLoopedSounds(except)
|
|
2098
|
+
for sound in pairs(shallowCopy(playingLoopedSounds)) do
|
|
2099
|
+
if sound ~= except then
|
|
2100
|
+
sound.Playing = false
|
|
2101
|
+
playingLoopedSounds[sound] = nil
|
|
2102
|
+
end
|
|
2103
|
+
end
|
|
2104
|
+
end
|
|
2105
|
+
|
|
2106
|
+
-- state transition callbacks
|
|
2107
|
+
local stateTransitions = {
|
|
2108
|
+
[Enum.HumanoidStateType.FallingDown] = function()
|
|
2109
|
+
stopPlayingLoopedSounds()
|
|
2110
|
+
end,
|
|
2111
|
+
|
|
2112
|
+
[Enum.HumanoidStateType.GettingUp] = function()
|
|
2113
|
+
stopPlayingLoopedSounds()
|
|
2114
|
+
playSound(sounds.GettingUp)
|
|
2115
|
+
end,
|
|
2116
|
+
|
|
2117
|
+
[Enum.HumanoidStateType.Jumping] = function()
|
|
2118
|
+
stopPlayingLoopedSounds()
|
|
2119
|
+
playSound(sounds.Jumping)
|
|
2120
|
+
end,
|
|
2121
|
+
|
|
2122
|
+
[Enum.HumanoidStateType.Swimming] = function()
|
|
2123
|
+
local verticalSpeed = math.abs(rootPart.Velocity.Y)
|
|
2124
|
+
if verticalSpeed > 0.1 then
|
|
2125
|
+
sounds.Splash.Volume = math.clamp(map(verticalSpeed, 100, 350, 0.28, 1), 0, 1)
|
|
2126
|
+
playSound(sounds.Splash)
|
|
2127
|
+
end
|
|
2128
|
+
stopPlayingLoopedSounds(sounds.Swimming)
|
|
2129
|
+
sounds.Swimming.Playing = true
|
|
2130
|
+
playingLoopedSounds[sounds.Swimming] = true
|
|
2131
|
+
end,
|
|
2132
|
+
|
|
2133
|
+
[Enum.HumanoidStateType.Freefall] = function()
|
|
2134
|
+
sounds.FreeFalling.Volume = 0
|
|
2135
|
+
stopPlayingLoopedSounds(sounds.FreeFalling)
|
|
2136
|
+
playingLoopedSounds[sounds.FreeFalling] = true
|
|
2137
|
+
end,
|
|
2138
|
+
|
|
2139
|
+
[Enum.HumanoidStateType.Landed] = function()
|
|
2140
|
+
stopPlayingLoopedSounds()
|
|
2141
|
+
local verticalSpeed = math.abs(rootPart.Velocity.Y)
|
|
2142
|
+
if verticalSpeed > 75 then
|
|
2143
|
+
sounds.Landing.Volume = math.clamp(map(verticalSpeed, 50, 100, 0, 1), 0, 1)
|
|
2144
|
+
playSound(sounds.Landing)
|
|
2145
|
+
end
|
|
2146
|
+
end,
|
|
2147
|
+
|
|
2148
|
+
[Enum.HumanoidStateType.Running] = function()
|
|
2149
|
+
stopPlayingLoopedSounds(sounds.Running)
|
|
2150
|
+
sounds.Running.Playing = true
|
|
2151
|
+
playingLoopedSounds[sounds.Running] = true
|
|
2152
|
+
end,
|
|
2153
|
+
|
|
2154
|
+
[Enum.HumanoidStateType.Climbing] = function()
|
|
2155
|
+
local sound = sounds.Climbing
|
|
2156
|
+
if math.abs(rootPart.Velocity.Y) > 0.1 then
|
|
2157
|
+
sound.Playing = true
|
|
2158
|
+
stopPlayingLoopedSounds(sound)
|
|
2159
|
+
else
|
|
2160
|
+
stopPlayingLoopedSounds()
|
|
2161
|
+
end
|
|
2162
|
+
playingLoopedSounds[sound] = true
|
|
2163
|
+
end,
|
|
2164
|
+
|
|
2165
|
+
[Enum.HumanoidStateType.Seated] = function()
|
|
2166
|
+
stopPlayingLoopedSounds()
|
|
2167
|
+
end,
|
|
2168
|
+
|
|
2169
|
+
[Enum.HumanoidStateType.Dead] = function()
|
|
2170
|
+
stopPlayingLoopedSounds()
|
|
2171
|
+
playSound(sounds.Died)
|
|
2172
|
+
end,
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
-- updaters for looped sounds
|
|
2176
|
+
local loopedSoundUpdaters = {
|
|
2177
|
+
[sounds.Climbing] = function(dt, sound, vel)
|
|
2178
|
+
sound.Playing = vel.Magnitude > 0.1
|
|
2179
|
+
end,
|
|
2180
|
+
|
|
2181
|
+
[sounds.FreeFalling] = function(dt, sound, vel)
|
|
2182
|
+
if vel.Magnitude > 75 then
|
|
2183
|
+
sound.Volume = math.clamp(sound.Volume + 0.9*dt, 0, 1)
|
|
2184
|
+
else
|
|
2185
|
+
sound.Volume = 0
|
|
2186
|
+
end
|
|
2187
|
+
end,
|
|
2188
|
+
|
|
2189
|
+
[sounds.Running] = function(dt, sound, vel)
|
|
2190
|
+
sound.Playing = vel.Magnitude > 0.5 and humanoid.MoveDirection.Magnitude > 0.5
|
|
2191
|
+
end,
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
-- state substitutions to avoid duplicating entries in the state table
|
|
2195
|
+
local stateRemap = {
|
|
2196
|
+
[Enum.HumanoidStateType.RunningNoPhysics] = Enum.HumanoidStateType.Running,
|
|
2197
|
+
}
|
|
2198
|
+
|
|
2199
|
+
local activeState = stateRemap[humanoid:GetState()] or humanoid:GetState()
|
|
2200
|
+
local animator = humanoid:WaitForChild("Animator")
|
|
2201
|
+
|
|
2202
|
+
local function onStateChange(_, state)
|
|
2203
|
+
state = stateRemap[state] or state
|
|
2204
|
+
|
|
2205
|
+
if state ~= activeState then
|
|
2206
|
+
local transitionFunc = stateTransitions[state]
|
|
2207
|
+
|
|
2208
|
+
if transitionFunc then
|
|
2209
|
+
transitionFunc()
|
|
2210
|
+
end
|
|
2211
|
+
|
|
2212
|
+
activeState = state
|
|
2213
|
+
end
|
|
2214
|
+
end
|
|
2215
|
+
|
|
2216
|
+
local stateChangedConn = humanoid.StateChanged:Connect(onStateChange)
|
|
2217
|
+
local animStateChangedConn = AnimationState(animator, function(_, state)
|
|
2218
|
+
if humanoid.PlatformStand then
|
|
2219
|
+
onStateChange(_, state)
|
|
2220
|
+
end
|
|
2221
|
+
end)
|
|
2222
|
+
|
|
2223
|
+
local steppedConn = RunService.Stepped:Connect(function(_, worldDt)
|
|
2224
|
+
-- update looped sounds on stepped
|
|
2225
|
+
for sound in pairs(playingLoopedSounds) do
|
|
2226
|
+
local updater = loopedSoundUpdaters[sound]
|
|
2227
|
+
|
|
2228
|
+
if updater then
|
|
2229
|
+
updater(worldDt, sound, rootPart.Velocity)
|
|
2230
|
+
end
|
|
2231
|
+
end
|
|
2232
|
+
end)
|
|
2233
|
+
|
|
2234
|
+
local humanoidAncestryChangedConn
|
|
2235
|
+
local rootPartAncestryChangedConn
|
|
2236
|
+
local characterAddedConn
|
|
2237
|
+
|
|
2238
|
+
local function terminate()
|
|
2239
|
+
stateChangedConn:Disconnect()
|
|
2240
|
+
animStateChangedConn:Disconnect()
|
|
2241
|
+
steppedConn:Disconnect()
|
|
2242
|
+
humanoidAncestryChangedConn:Disconnect()
|
|
2243
|
+
rootPartAncestryChangedConn:Disconnect()
|
|
2244
|
+
characterAddedConn:Disconnect()
|
|
2245
|
+
end
|
|
2246
|
+
|
|
2247
|
+
humanoidAncestryChangedConn = humanoid.AncestryChanged:Connect(function(_, parent)
|
|
2248
|
+
if not parent then
|
|
2249
|
+
terminate()
|
|
2250
|
+
end
|
|
2251
|
+
end)
|
|
2252
|
+
|
|
2253
|
+
rootPartAncestryChangedConn = rootPart.AncestryChanged:Connect(function(_, parent)
|
|
2254
|
+
if not parent then
|
|
2255
|
+
terminate()
|
|
2256
|
+
end
|
|
2257
|
+
end)
|
|
2258
|
+
|
|
2259
|
+
characterAddedConn = player.CharacterAdded:Connect(terminate)
|
|
2260
|
+
end
|
|
2261
|
+
|
|
2262
|
+
local function playerAdded(player)
|
|
2263
|
+
local function characterAdded(character)
|
|
2264
|
+
-- Avoiding memory leaks in the face of Character/Humanoid/RootPart lifetime has a few complications:
|
|
2265
|
+
-- * character deparenting is a Remove instead of a Destroy, so signals are not cleaned up automatically.
|
|
2266
|
+
-- ** must use a waitForFirst on everything and listen for hierarchy changes.
|
|
2267
|
+
-- * the character might not be in the dm by the time CharacterAdded fires
|
|
2268
|
+
-- ** constantly check consistency with player.Character and abort if CharacterAdded is fired again
|
|
2269
|
+
-- * Humanoid may not exist immediately, and by the time it's inserted the character might be deparented.
|
|
2270
|
+
-- * RootPart probably won't exist immediately.
|
|
2271
|
+
-- ** by the time RootPart is inserted and Humanoid.RootPart is set, the character or the humanoid might be deparented.
|
|
2272
|
+
|
|
2273
|
+
if not character.Parent then
|
|
2274
|
+
waitForFirst(character.AncestryChanged, player.CharacterAdded)
|
|
2275
|
+
end
|
|
2276
|
+
|
|
2277
|
+
if player.Character ~= character or not character.Parent then
|
|
2278
|
+
return
|
|
2279
|
+
end
|
|
2280
|
+
|
|
2281
|
+
local humanoid = character:FindFirstChildOfClass("Humanoid")
|
|
2282
|
+
while character:IsDescendantOf(game) and not humanoid do
|
|
2283
|
+
waitForFirst(character.ChildAdded, character.AncestryChanged, player.CharacterAdded)
|
|
2284
|
+
humanoid = character:FindFirstChildOfClass("Humanoid")
|
|
2285
|
+
end
|
|
2286
|
+
|
|
2287
|
+
if player.Character ~= character or not character:IsDescendantOf(game) then
|
|
2288
|
+
return
|
|
2289
|
+
end
|
|
2290
|
+
|
|
2291
|
+
-- must rely on HumanoidRootPart naming because Humanoid.RootPart does not fire changed signals
|
|
2292
|
+
local rootPart = character:FindFirstChild("HumanoidRootPart")
|
|
2293
|
+
while character:IsDescendantOf(game) and not rootPart do
|
|
2294
|
+
waitForFirst(character.ChildAdded, character.AncestryChanged, humanoid.AncestryChanged, player.CharacterAdded)
|
|
2295
|
+
rootPart = character:FindFirstChild("HumanoidRootPart")
|
|
2296
|
+
end
|
|
2297
|
+
|
|
2298
|
+
if rootPart and humanoid:IsDescendantOf(game) and character:IsDescendantOf(game) and player.Character == character then
|
|
2299
|
+
initializeSoundSystem(player, humanoid, rootPart)
|
|
2300
|
+
end
|
|
2301
|
+
end
|
|
2302
|
+
|
|
2303
|
+
if player.Character then
|
|
2304
|
+
characterAdded(player.Character)
|
|
2305
|
+
end
|
|
2306
|
+
player.CharacterAdded:Connect(characterAdded)
|
|
2307
|
+
end
|
|
2308
|
+
|
|
2309
|
+
Players.PlayerAdded:Connect(playerAdded)
|
|
2310
|
+
for _, player in ipairs(Players:GetPlayers()) do
|
|
2311
|
+
playerAdded(player)
|
|
2312
|
+
end
|
|
2313
|
+
]]></string>
|
|
2314
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
2315
|
+
<BinaryString name="Tags"></BinaryString>
|
|
2316
|
+
</Properties>
|
|
2317
|
+
<Item class="ModuleScript" referent="14">
|
|
2318
|
+
<Properties>
|
|
2319
|
+
<string name="Name">AnimationState</string>
|
|
2320
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
2321
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
2322
|
+
<Content name="LinkedSource">
|
|
2323
|
+
<null>
|
|
2324
|
+
</null>
|
|
2325
|
+
</Content>
|
|
2326
|
+
<string name="Source">local STATE_MAP = {
|
|
2327
|
+
["climb"] = Enum.HumanoidStateType.Climbing,
|
|
2328
|
+
["fall"] = Enum.HumanoidStateType.Freefall,
|
|
2329
|
+
["idle"] = Enum.HumanoidStateType.RunningNoPhysics,
|
|
2330
|
+
["jump"] = Enum.HumanoidStateType.Jumping,
|
|
2331
|
+
["run"] = Enum.HumanoidStateType.Running,
|
|
2332
|
+
["swim"] = Enum.HumanoidStateType.Swimming,
|
|
2333
|
+
["swimidle"] = Enum.HumanoidStateType.Swimming,
|
|
2334
|
+
["walk"] = Enum.HumanoidStateType.Running,
|
|
2335
|
+
}
|
|
2336
|
+
|
|
2337
|
+
return function(animator, callback)
|
|
2338
|
+
local humanoid = animator.Parent
|
|
2339
|
+
local prevState = humanoid:GetState()
|
|
2340
|
+
|
|
2341
|
+
return animator.AnimationPlayed:Connect(function(track)
|
|
2342
|
+
local state = STATE_MAP[track.Name]
|
|
2343
|
+
|
|
2344
|
+
if not state then
|
|
2345
|
+
local container = track.Animation.Parent
|
|
2346
|
+
state = container and STATE_MAP[container.Name]
|
|
2347
|
+
end
|
|
2348
|
+
|
|
2349
|
+
if state then
|
|
2350
|
+
callback(prevState, state)
|
|
2351
|
+
prevState = state
|
|
2352
|
+
end
|
|
2353
|
+
end)
|
|
2354
|
+
end</string>
|
|
2355
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
2356
|
+
<BinaryString name="Tags"></BinaryString>
|
|
2357
|
+
</Properties>
|
|
2358
|
+
</Item>
|
|
2359
|
+
</Item>
|
|
2360
|
+
</Item>
|
|
2361
|
+
<Item class="ModuleScript" referent="15">
|
|
2362
|
+
<Properties>
|
|
2363
|
+
<string name="Name">GravityController</string>
|
|
2364
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
2365
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
2366
|
+
<Content name="LinkedSource">
|
|
2367
|
+
<null>
|
|
2368
|
+
</null>
|
|
2369
|
+
</Content>
|
|
2370
|
+
<string name="Source">local RunService = game:GetService("RunService")
|
|
2371
|
+
|
|
2372
|
+
local Utility = script:WaitForChild("Utility")
|
|
2373
|
+
local CharacterModules = script:WaitForChild("CharacterModules")
|
|
2374
|
+
|
|
2375
|
+
local Maid = require(Utility:WaitForChild("Maid"))
|
|
2376
|
+
local Signal = require(Utility:WaitForChild("Signal"))
|
|
2377
|
+
local Camera = require(CharacterModules:WaitForChild("Camera"))
|
|
2378
|
+
local Control = require(CharacterModules:WaitForChild("Control"))
|
|
2379
|
+
local Collider = require(script:WaitForChild("Collider"))
|
|
2380
|
+
local StateTracker = require(script:WaitForChild("StateTracker"))
|
|
2381
|
+
|
|
2382
|
+
-- CONSTANTS
|
|
2383
|
+
|
|
2384
|
+
local TRANSITION = 0.15
|
|
2385
|
+
local WALK_FORCE = 200 / 3
|
|
2386
|
+
local JUMP_MODIFIER = 1.2
|
|
2387
|
+
|
|
2388
|
+
local ZERO3 = Vector3.new(0, 0, 0)
|
|
2389
|
+
local UNIT_Y = Vector3.new(0, 1, 0)
|
|
2390
|
+
|
|
2391
|
+
-- Class
|
|
2392
|
+
|
|
2393
|
+
local GravityControllerClass = {}
|
|
2394
|
+
GravityControllerClass.__index = GravityControllerClass
|
|
2395
|
+
GravityControllerClass.ClassName = "GravityController"
|
|
2396
|
+
|
|
2397
|
+
-- Public Constructors
|
|
2398
|
+
|
|
2399
|
+
function GravityControllerClass.new(player)
|
|
2400
|
+
local self = setmetatable({}, GravityControllerClass)
|
|
2401
|
+
|
|
2402
|
+
self.Player = player
|
|
2403
|
+
self.Character = player.Character
|
|
2404
|
+
self.Humanoid = player.Character:WaitForChild("Humanoid")
|
|
2405
|
+
self.HRP = self.Humanoid.RootPart
|
|
2406
|
+
|
|
2407
|
+
self._gravityUp = UNIT_Y
|
|
2408
|
+
self._characterMass = 0
|
|
2409
|
+
|
|
2410
|
+
self._camera = Camera.new(self)
|
|
2411
|
+
self._control = Control.new(self)
|
|
2412
|
+
self._collider = Collider.new(self)
|
|
2413
|
+
|
|
2414
|
+
self._fallStart = self.HRP.Position.y
|
|
2415
|
+
self._prevPart = workspace.Terrain
|
|
2416
|
+
self._prevCFrame = CFrame.new()
|
|
2417
|
+
|
|
2418
|
+
self.StateTracker = StateTracker.new(self)
|
|
2419
|
+
self.Maid = Maid.new()
|
|
2420
|
+
|
|
2421
|
+
init(self)
|
|
2422
|
+
|
|
2423
|
+
return self
|
|
2424
|
+
end
|
|
2425
|
+
|
|
2426
|
+
-- Private Methods
|
|
2427
|
+
|
|
2428
|
+
local function getRotationBetween(u, v, axis)
|
|
2429
|
+
local dot, uxv = u:Dot(v), u:Cross(v)
|
|
2430
|
+
if dot < -0.99999 then return CFrame.fromAxisAngle(axis, math.pi) end
|
|
2431
|
+
return CFrame.new(0, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)
|
|
2432
|
+
end
|
|
2433
|
+
|
|
2434
|
+
local function getModelMass(model)
|
|
2435
|
+
local mass = 0
|
|
2436
|
+
for _, part in pairs(model:GetDescendants()) do
|
|
2437
|
+
if part:IsA("BasePart") and not part.Massless then
|
|
2438
|
+
mass = mass + part:GetMass()
|
|
2439
|
+
end
|
|
2440
|
+
end
|
|
2441
|
+
return mass
|
|
2442
|
+
end
|
|
2443
|
+
|
|
2444
|
+
local function onJumpRequest(self)
|
|
2445
|
+
if not self.StateTracker.Jumped and self._collider:IsGrounded(true) then
|
|
2446
|
+
local vel = self.HRP.Velocity
|
|
2447
|
+
self.HRP.Velocity = vel + self._gravityUp*self.Humanoid.JumpPower*JUMP_MODIFIER
|
|
2448
|
+
self.StateTracker:RequestJump()
|
|
2449
|
+
end
|
|
2450
|
+
end
|
|
2451
|
+
|
|
2452
|
+
local function onHeartbeat(self, dt)
|
|
2453
|
+
local standingPart = self._collider:GetStandingPart()
|
|
2454
|
+
|
|
2455
|
+
if standingPart and self._prevPart and self._prevPart == standingPart then
|
|
2456
|
+
local offset = self._prevCFrame:ToObjectSpace(self.HRP.CFrame)
|
|
2457
|
+
self.HRP.CFrame = standingPart.CFrame * offset
|
|
2458
|
+
end
|
|
2459
|
+
|
|
2460
|
+
self._prevPart = standingPart
|
|
2461
|
+
self._prevCFrame = standingPart and standingPart.CFrame
|
|
2462
|
+
end
|
|
2463
|
+
|
|
2464
|
+
local function onGravityStep(self, dt)
|
|
2465
|
+
local camCF = workspace.CurrentCamera.CFrame
|
|
2466
|
+
|
|
2467
|
+
-- update the gravity vector
|
|
2468
|
+
local oldGravity = self._gravityUp
|
|
2469
|
+
local newGravity = self:GetGravityUp(oldGravity)
|
|
2470
|
+
|
|
2471
|
+
local sphericalArc = getRotationBetween(oldGravity, newGravity, camCF.XVector)
|
|
2472
|
+
local lerpedArc = CFrame.new():Lerp(sphericalArc, TRANSITION)
|
|
2473
|
+
|
|
2474
|
+
self._gravityUp = lerpedArc * oldGravity
|
|
2475
|
+
|
|
2476
|
+
-- get world move vector
|
|
2477
|
+
local fDot = camCF.ZVector:Dot(newGravity)
|
|
2478
|
+
local cForward = math.abs(fDot) > 0.5 and math.sign(fDot)*camCF.YVector or -camCF.ZVector
|
|
2479
|
+
|
|
2480
|
+
local left = -cForward:Cross(newGravity).Unit
|
|
2481
|
+
local forward = -left:Cross(newGravity).Unit
|
|
2482
|
+
|
|
2483
|
+
local move = self._control:GetMoveVector()
|
|
2484
|
+
local worldMove = forward*move.z - left*move.x
|
|
2485
|
+
|
|
2486
|
+
local isInputMoving = false
|
|
2487
|
+
local length = worldMove.Magnitude
|
|
2488
|
+
if length > 0 then
|
|
2489
|
+
isInputMoving = true
|
|
2490
|
+
worldMove = worldMove / length
|
|
2491
|
+
end
|
|
2492
|
+
|
|
2493
|
+
-- get the desired character cframe
|
|
2494
|
+
local hrpLook = -self.HRP.CFrame.ZVector
|
|
2495
|
+
local charForward = hrpLook:Dot(forward)*forward + hrpLook:Dot(left)*left
|
|
2496
|
+
local charRight = charForward:Cross(newGravity).Unit
|
|
2497
|
+
|
|
2498
|
+
local newCharRotation = CFrame.new()
|
|
2499
|
+
local newCharCF = CFrame.fromMatrix(ZERO3, charRight, newGravity, -charForward)
|
|
2500
|
+
|
|
2501
|
+
if self._camera.CameraModule:IsCamRelative() then
|
|
2502
|
+
newCharCF = CFrame.fromMatrix(ZERO3, -left, newGravity)
|
|
2503
|
+
elseif isInputMoving then
|
|
2504
|
+
newCharRotation = newCharRotation:Lerp(getRotationBetween(
|
|
2505
|
+
charForward,
|
|
2506
|
+
worldMove,
|
|
2507
|
+
newGravity
|
|
2508
|
+
), 0.7)
|
|
2509
|
+
end
|
|
2510
|
+
|
|
2511
|
+
-- calculate forces
|
|
2512
|
+
local g = workspace.Gravity
|
|
2513
|
+
local gForce = g * self._characterMass * (UNIT_Y - newGravity)
|
|
2514
|
+
|
|
2515
|
+
local cVelocity = self.HRP.Velocity
|
|
2516
|
+
local tVelocity = self.Humanoid.WalkSpeed * worldMove
|
|
2517
|
+
local gVelocity = cVelocity:Dot(newGravity)*newGravity
|
|
2518
|
+
local hVelocity = cVelocity - gVelocity
|
|
2519
|
+
|
|
2520
|
+
if hVelocity:Dot(hVelocity) < 1 then
|
|
2521
|
+
hVelocity = ZERO3
|
|
2522
|
+
end
|
|
2523
|
+
|
|
2524
|
+
local dVelocity = tVelocity - hVelocity
|
|
2525
|
+
local dVelocityM = dVelocity.Magnitude
|
|
2526
|
+
|
|
2527
|
+
local walkForceM = math.min(10000, WALK_FORCE * self._characterMass * dVelocityM / (dt*60))
|
|
2528
|
+
local walkForce = walkForceM > 0 and (dVelocity / dVelocityM)*walkForceM or ZERO3
|
|
2529
|
+
|
|
2530
|
+
local charRotation = newCharRotation * newCharCF
|
|
2531
|
+
|
|
2532
|
+
self.StateTracker:Update(self._gravityUp, self._collider:IsGrounded(false), isInputMoving)
|
|
2533
|
+
self._collider:Update(walkForce + gForce, charRotation)
|
|
2534
|
+
end
|
|
2535
|
+
|
|
2536
|
+
function init(self)
|
|
2537
|
+
self.Maid:Mark(self._camera)
|
|
2538
|
+
self.Maid:Mark(self._control)
|
|
2539
|
+
self.Maid:Mark(self._collider)
|
|
2540
|
+
|
|
2541
|
+
self._characterMass = getModelMass(self.Character)
|
|
2542
|
+
self.Maid:Mark(self.Character.AncestryChanged:Connect(function()
|
|
2543
|
+
self._characterMass = getModelMass(self.Character)
|
|
2544
|
+
end))
|
|
2545
|
+
|
|
2546
|
+
self.Humanoid.PlatformStand = true
|
|
2547
|
+
self.Maid:Mark(self.Humanoid:GetPropertyChangedSignal("Jump"):Connect(function()
|
|
2548
|
+
if self.Humanoid.Jump then
|
|
2549
|
+
onJumpRequest(self)
|
|
2550
|
+
self.Humanoid.Jump = false
|
|
2551
|
+
end
|
|
2552
|
+
end))
|
|
2553
|
+
|
|
2554
|
+
self.Maid:Mark(self.StateTracker.Changed:Connect(function(state, speed)
|
|
2555
|
+
if state == Enum.HumanoidStateType.Freefall then
|
|
2556
|
+
self._fallStart = self.HRP.Position:Dot(self._gravityUp)
|
|
2557
|
+
end
|
|
2558
|
+
end))
|
|
2559
|
+
|
|
2560
|
+
self.Maid:Mark(RunService.Heartbeat:Connect(function(dt)
|
|
2561
|
+
onHeartbeat(self, dt)
|
|
2562
|
+
end))
|
|
2563
|
+
|
|
2564
|
+
RunService:BindToRenderStep("GravityStep", Enum.RenderPriority.Camera.Value - 1, function(dt)
|
|
2565
|
+
onGravityStep(self, dt)
|
|
2566
|
+
end)
|
|
2567
|
+
|
|
2568
|
+
self.Humanoid.StateChanged:Wait()
|
|
2569
|
+
self.StateTracker.Changed:Fire(self.StateTracker.State, 0)
|
|
2570
|
+
end
|
|
2571
|
+
|
|
2572
|
+
-- Public Methods
|
|
2573
|
+
|
|
2574
|
+
function GravityControllerClass:ResetGravity(gravity)
|
|
2575
|
+
self._gravityUp = gravity
|
|
2576
|
+
self._fallStart = self.HRP.Position:Dot(gravity)
|
|
2577
|
+
end
|
|
2578
|
+
|
|
2579
|
+
function GravityControllerClass:GetFallHeight()
|
|
2580
|
+
if self.StateTracker.State == Enum.HumanoidStateType.Freefall then
|
|
2581
|
+
local height = self.HRP.Position:Dot(self._gravityUp)
|
|
2582
|
+
return height - self._fallStart
|
|
2583
|
+
end
|
|
2584
|
+
return 0
|
|
2585
|
+
end
|
|
2586
|
+
|
|
2587
|
+
function GravityControllerClass:GetGravityUp(oldGravity)
|
|
2588
|
+
return oldGravity
|
|
2589
|
+
end
|
|
2590
|
+
|
|
2591
|
+
function GravityControllerClass:Destroy()
|
|
2592
|
+
RunService:UnbindFromRenderStep("GravityStep")
|
|
2593
|
+
self.Maid:Sweep()
|
|
2594
|
+
self.Humanoid.PlatformStand = false
|
|
2595
|
+
end
|
|
2596
|
+
|
|
2597
|
+
--
|
|
2598
|
+
|
|
2599
|
+
return GravityControllerClass</string>
|
|
2600
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
2601
|
+
<BinaryString name="Tags"></BinaryString>
|
|
2602
|
+
</Properties>
|
|
2603
|
+
<Item class="Folder" referent="16">
|
|
2604
|
+
<Properties>
|
|
2605
|
+
<string name="Name">CharacterModules</string>
|
|
2606
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
2607
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
2608
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
2609
|
+
<BinaryString name="Tags"></BinaryString>
|
|
2610
|
+
</Properties>
|
|
2611
|
+
<Item class="ModuleScript" referent="17">
|
|
2612
|
+
<Properties>
|
|
2613
|
+
<string name="Name">Camera</string>
|
|
2614
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
2615
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
2616
|
+
<Content name="LinkedSource">
|
|
2617
|
+
<null>
|
|
2618
|
+
</null>
|
|
2619
|
+
</Content>
|
|
2620
|
+
<string name="Source">-- Class
|
|
2621
|
+
|
|
2622
|
+
local CameraClass = {}
|
|
2623
|
+
CameraClass.__index = CameraClass
|
|
2624
|
+
CameraClass.ClassName = "Camera"
|
|
2625
|
+
|
|
2626
|
+
-- Public Constructors
|
|
2627
|
+
|
|
2628
|
+
function CameraClass.new(controller)
|
|
2629
|
+
local self = setmetatable({}, CameraClass)
|
|
2630
|
+
|
|
2631
|
+
local player = controller.Player
|
|
2632
|
+
local playerModule = require(player.PlayerScripts:WaitForChild("PlayerModule"))
|
|
2633
|
+
|
|
2634
|
+
self.Controller = controller
|
|
2635
|
+
self.CameraModule = playerModule:GetCameras()
|
|
2636
|
+
|
|
2637
|
+
init(self)
|
|
2638
|
+
|
|
2639
|
+
return self
|
|
2640
|
+
end
|
|
2641
|
+
|
|
2642
|
+
-- Private methods
|
|
2643
|
+
|
|
2644
|
+
function init(self)
|
|
2645
|
+
--self.CameraModule:SetTransitionRate(1)
|
|
2646
|
+
function self.CameraModule.GetUpVector(this, upVector)
|
|
2647
|
+
return self.Controller._gravityUp
|
|
2648
|
+
end
|
|
2649
|
+
end
|
|
2650
|
+
|
|
2651
|
+
-- Public Methods
|
|
2652
|
+
|
|
2653
|
+
function CameraClass:Destroy()
|
|
2654
|
+
function self.CameraModule.GetUpVector(this, upVector)
|
|
2655
|
+
return Vector3.new(0, 1, 0)
|
|
2656
|
+
end
|
|
2657
|
+
end
|
|
2658
|
+
|
|
2659
|
+
--
|
|
2660
|
+
|
|
2661
|
+
return CameraClass</string>
|
|
2662
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
2663
|
+
<BinaryString name="Tags"></BinaryString>
|
|
2664
|
+
</Properties>
|
|
2665
|
+
</Item>
|
|
2666
|
+
<Item class="ModuleScript" referent="18">
|
|
2667
|
+
<Properties>
|
|
2668
|
+
<string name="Name">Control</string>
|
|
2669
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
2670
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
2671
|
+
<Content name="LinkedSource">
|
|
2672
|
+
<null>
|
|
2673
|
+
</null>
|
|
2674
|
+
</Content>
|
|
2675
|
+
<string name="Source">-- Class
|
|
2676
|
+
|
|
2677
|
+
local ControlClass = {}
|
|
2678
|
+
ControlClass.__index = ControlClass
|
|
2679
|
+
ControlClass.ClassName = "Control"
|
|
2680
|
+
|
|
2681
|
+
-- Public Constructors
|
|
2682
|
+
|
|
2683
|
+
function ControlClass.new(controller)
|
|
2684
|
+
local self = setmetatable({}, ControlClass)
|
|
2685
|
+
|
|
2686
|
+
local player = controller.Player
|
|
2687
|
+
local playerModule = require(player.PlayerScripts:WaitForChild("PlayerModule"))
|
|
2688
|
+
|
|
2689
|
+
self.Controller = controller
|
|
2690
|
+
self.ControlModule = playerModule:GetControls()
|
|
2691
|
+
|
|
2692
|
+
return self
|
|
2693
|
+
end
|
|
2694
|
+
|
|
2695
|
+
-- Public Methods
|
|
2696
|
+
|
|
2697
|
+
function ControlClass:GetMoveVector()
|
|
2698
|
+
return self.ControlModule:GetMoveVector()
|
|
2699
|
+
end
|
|
2700
|
+
|
|
2701
|
+
function ControlClass:Destroy()
|
|
2702
|
+
|
|
2703
|
+
end
|
|
2704
|
+
|
|
2705
|
+
--
|
|
2706
|
+
|
|
2707
|
+
return ControlClass</string>
|
|
2708
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
2709
|
+
<BinaryString name="Tags"></BinaryString>
|
|
2710
|
+
</Properties>
|
|
2711
|
+
</Item>
|
|
2712
|
+
</Item>
|
|
2713
|
+
<Item class="ModuleScript" referent="19">
|
|
2714
|
+
<Properties>
|
|
2715
|
+
<string name="Name">Collider</string>
|
|
2716
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
2717
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
2718
|
+
<Content name="LinkedSource">
|
|
2719
|
+
<null>
|
|
2720
|
+
</null>
|
|
2721
|
+
</Content>
|
|
2722
|
+
<string name="Source"><![CDATA[local Maid = require(script.Parent.Utility.Maid)
|
|
2723
|
+
|
|
2724
|
+
local params = RaycastParams.new()
|
|
2725
|
+
params.FilterType = Enum.RaycastFilterType.Whitelist
|
|
2726
|
+
|
|
2727
|
+
local params2 = RaycastParams.new()
|
|
2728
|
+
params2.FilterType = Enum.RaycastFilterType.Blacklist
|
|
2729
|
+
|
|
2730
|
+
-- CONSTANTS
|
|
2731
|
+
|
|
2732
|
+
local CUSTOM_PHYSICAL = PhysicalProperties.new (0.7, 0, 0, 1, 100)
|
|
2733
|
+
|
|
2734
|
+
-- Class
|
|
2735
|
+
|
|
2736
|
+
local ColliderClass = {}
|
|
2737
|
+
ColliderClass.__index = ColliderClass
|
|
2738
|
+
ColliderClass.ClassName = "Collider"
|
|
2739
|
+
|
|
2740
|
+
-- Public Constructors
|
|
2741
|
+
|
|
2742
|
+
function ColliderClass.new(controller)
|
|
2743
|
+
local self = setmetatable({}, ColliderClass)
|
|
2744
|
+
|
|
2745
|
+
self.Model = Instance.new("Model")
|
|
2746
|
+
|
|
2747
|
+
local sphere, vForce, floor, floor2, gryo = create(self, controller)
|
|
2748
|
+
|
|
2749
|
+
self._maid = Maid.new()
|
|
2750
|
+
|
|
2751
|
+
self.Controller = controller
|
|
2752
|
+
|
|
2753
|
+
self.Sphere = sphere
|
|
2754
|
+
self.VForce = vForce
|
|
2755
|
+
self.FloorDetector = floor
|
|
2756
|
+
self.JumpDetector = floor2
|
|
2757
|
+
self.Gyro = gryo
|
|
2758
|
+
|
|
2759
|
+
init(self)
|
|
2760
|
+
|
|
2761
|
+
return self
|
|
2762
|
+
end
|
|
2763
|
+
|
|
2764
|
+
-- Private Methods
|
|
2765
|
+
|
|
2766
|
+
local function getHipHeight(controller)
|
|
2767
|
+
if controller.Humanoid.RigType == Enum.HumanoidRigType.R15 then
|
|
2768
|
+
return controller.Humanoid.HipHeight + 0.05
|
|
2769
|
+
end
|
|
2770
|
+
return 2
|
|
2771
|
+
end
|
|
2772
|
+
|
|
2773
|
+
local function getAttachement(controller)
|
|
2774
|
+
if controller.Humanoid.RigType == Enum.HumanoidRigType.R15 then
|
|
2775
|
+
return controller.HRP:WaitForChild("RootRigAttachment")
|
|
2776
|
+
end
|
|
2777
|
+
return controller.HRP:WaitForChild("RootAttachment")
|
|
2778
|
+
end
|
|
2779
|
+
|
|
2780
|
+
function create(self, controller)
|
|
2781
|
+
local hipHeight = getHipHeight(controller)
|
|
2782
|
+
local attach = getAttachement(controller)
|
|
2783
|
+
|
|
2784
|
+
local sphere = Instance.new("Part")
|
|
2785
|
+
sphere.Name = "Sphere"
|
|
2786
|
+
sphere.Massless = true
|
|
2787
|
+
sphere.Size = Vector3.new(2, 2, 2)
|
|
2788
|
+
sphere.Shape = Enum.PartType.Ball
|
|
2789
|
+
sphere.Transparency = 1
|
|
2790
|
+
sphere.CustomPhysicalProperties = CUSTOM_PHYSICAL
|
|
2791
|
+
|
|
2792
|
+
local floor = Instance.new("Part")
|
|
2793
|
+
floor.Name = "FloorDectector"
|
|
2794
|
+
floor.CanCollide = false
|
|
2795
|
+
floor.Massless = true
|
|
2796
|
+
floor.Size = Vector3.new(2, 1, 1)
|
|
2797
|
+
floor.Transparency = 1
|
|
2798
|
+
|
|
2799
|
+
local floor2 = Instance.new("Part")
|
|
2800
|
+
floor2.Name = "JumpDectector"
|
|
2801
|
+
floor2.CanCollide = false
|
|
2802
|
+
floor2.Massless = true
|
|
2803
|
+
floor2.Size = Vector3.new(2, 0.2, 1)
|
|
2804
|
+
floor2.Transparency = 1
|
|
2805
|
+
|
|
2806
|
+
local weld = Instance.new("Weld")
|
|
2807
|
+
weld.C0 = CFrame.new(0, -hipHeight, 0.1)
|
|
2808
|
+
weld.Part0 = controller.HRP
|
|
2809
|
+
weld.Part1 = sphere
|
|
2810
|
+
weld.Parent = sphere
|
|
2811
|
+
|
|
2812
|
+
local weld = Instance.new("Weld")
|
|
2813
|
+
weld.C0 = CFrame.new(0, -hipHeight - 1.5, 0)
|
|
2814
|
+
weld.Part0 = controller.HRP
|
|
2815
|
+
weld.Part1 = floor
|
|
2816
|
+
weld.Parent = floor
|
|
2817
|
+
|
|
2818
|
+
local weld = Instance.new("Weld")
|
|
2819
|
+
weld.C0 = CFrame.new(0, -hipHeight - 1.1, 0)
|
|
2820
|
+
weld.Part0 = controller.HRP
|
|
2821
|
+
weld.Part1 = floor2
|
|
2822
|
+
weld.Parent = floor2
|
|
2823
|
+
|
|
2824
|
+
local vForce = Instance.new("VectorForce")
|
|
2825
|
+
vForce.Force = Vector3.new(0, 0, 0)
|
|
2826
|
+
vForce.ApplyAtCenterOfMass = true
|
|
2827
|
+
vForce.RelativeTo = Enum.ActuatorRelativeTo.World
|
|
2828
|
+
vForce.Attachment0 = attach
|
|
2829
|
+
vForce.Parent = controller.HRP
|
|
2830
|
+
|
|
2831
|
+
local gyro = Instance.new("BodyGyro")
|
|
2832
|
+
gyro.P = 25000
|
|
2833
|
+
gyro.MaxTorque = Vector3.new(100000, 100000, 100000)
|
|
2834
|
+
gyro.CFrame = controller.HRP.CFrame
|
|
2835
|
+
gyro.Parent = controller.HRP
|
|
2836
|
+
|
|
2837
|
+
floor.Touched:Connect(function() end)
|
|
2838
|
+
floor2.Touched:Connect(function() end)
|
|
2839
|
+
|
|
2840
|
+
sphere.Parent = self.Model
|
|
2841
|
+
floor.Parent = self.Model
|
|
2842
|
+
floor2.Parent = self.Model
|
|
2843
|
+
|
|
2844
|
+
return sphere, vForce, floor, floor2, gyro
|
|
2845
|
+
end
|
|
2846
|
+
|
|
2847
|
+
function init(self)
|
|
2848
|
+
self._maid:Mark(self.Model)
|
|
2849
|
+
self._maid:Mark(self.VForce)
|
|
2850
|
+
self._maid:Mark(self.FloorDetector)
|
|
2851
|
+
self._maid:Mark(self.Gyro)
|
|
2852
|
+
self.Model.Name = "Collider"
|
|
2853
|
+
self.Model.Parent = self.Controller.Character
|
|
2854
|
+
end
|
|
2855
|
+
|
|
2856
|
+
-- Public Methods
|
|
2857
|
+
|
|
2858
|
+
function ColliderClass:Update(force, cframe)
|
|
2859
|
+
self.VForce.Force = force
|
|
2860
|
+
self.Gyro.CFrame = cframe
|
|
2861
|
+
end
|
|
2862
|
+
|
|
2863
|
+
function ColliderClass:IsGrounded(isJumpCheck)
|
|
2864
|
+
local parts = (isJumpCheck and self.JumpDetector or self.FloorDetector):GetTouchingParts()
|
|
2865
|
+
for _, part in pairs(parts) do
|
|
2866
|
+
if not part:IsDescendantOf(self.Controller.Character) and part.CanCollide then
|
|
2867
|
+
return true
|
|
2868
|
+
end
|
|
2869
|
+
end
|
|
2870
|
+
end
|
|
2871
|
+
|
|
2872
|
+
function ColliderClass:GetStandingPart()
|
|
2873
|
+
params2.FilterDescendantsInstances = {self.Controller.Character}
|
|
2874
|
+
|
|
2875
|
+
local gravityUp = self.Controller._gravityUp
|
|
2876
|
+
local result = workspace:Raycast(self.Sphere.Position, -1.1*gravityUp, params2)
|
|
2877
|
+
|
|
2878
|
+
return result and result.Instance
|
|
2879
|
+
end
|
|
2880
|
+
|
|
2881
|
+
function ColliderClass:Destroy()
|
|
2882
|
+
self._maid:Sweep()
|
|
2883
|
+
end
|
|
2884
|
+
|
|
2885
|
+
--
|
|
2886
|
+
|
|
2887
|
+
return ColliderClass
|
|
2888
|
+
]]></string>
|
|
2889
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
2890
|
+
<BinaryString name="Tags"></BinaryString>
|
|
2891
|
+
</Properties>
|
|
2892
|
+
</Item>
|
|
2893
|
+
<Item class="ModuleScript" referent="20">
|
|
2894
|
+
<Properties>
|
|
2895
|
+
<string name="Name">StateTracker</string>
|
|
2896
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
2897
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
2898
|
+
<Content name="LinkedSource">
|
|
2899
|
+
<null>
|
|
2900
|
+
</null>
|
|
2901
|
+
</Content>
|
|
2902
|
+
<string name="Source">local Maid = require(script.Parent.Utility.Maid)
|
|
2903
|
+
local Signal = require(script.Parent.Utility.Signal)
|
|
2904
|
+
|
|
2905
|
+
-- CONSTANTS
|
|
2906
|
+
|
|
2907
|
+
local SPEED = {
|
|
2908
|
+
[Enum.HumanoidStateType.Running] = true,
|
|
2909
|
+
}
|
|
2910
|
+
|
|
2911
|
+
local IN_AIR = {
|
|
2912
|
+
[Enum.HumanoidStateType.Jumping] = true,
|
|
2913
|
+
[Enum.HumanoidStateType.Freefall] = true
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
local REMAP = {
|
|
2917
|
+
["onFreefall"] = "onFreeFall",
|
|
2918
|
+
}
|
|
2919
|
+
|
|
2920
|
+
-- Class
|
|
2921
|
+
|
|
2922
|
+
local StateTrackerClass = {}
|
|
2923
|
+
StateTrackerClass.__index = StateTrackerClass
|
|
2924
|
+
StateTrackerClass.ClassName = "StateTracker"
|
|
2925
|
+
|
|
2926
|
+
-- Public Constructors
|
|
2927
|
+
|
|
2928
|
+
function StateTrackerClass.new(controller)
|
|
2929
|
+
local self = setmetatable({}, StateTrackerClass)
|
|
2930
|
+
|
|
2931
|
+
self._maid = Maid.new()
|
|
2932
|
+
|
|
2933
|
+
self.Controller = controller
|
|
2934
|
+
self.State = Enum.HumanoidStateType.Running
|
|
2935
|
+
self.Speed = 0
|
|
2936
|
+
|
|
2937
|
+
self.Jumped = false
|
|
2938
|
+
self.JumpTick = os.clock()
|
|
2939
|
+
|
|
2940
|
+
self.Animation = require(controller.Character:WaitForChild("Animate"):WaitForChild("Controller"))
|
|
2941
|
+
self.Changed = Signal.new()
|
|
2942
|
+
|
|
2943
|
+
init(self)
|
|
2944
|
+
|
|
2945
|
+
return self
|
|
2946
|
+
end
|
|
2947
|
+
|
|
2948
|
+
-- Private Methods
|
|
2949
|
+
|
|
2950
|
+
function init(self)
|
|
2951
|
+
self._maid:Mark(self.Changed)
|
|
2952
|
+
self._maid:Mark(self.Changed:Connect(function(state, speed)
|
|
2953
|
+
local name = "on" .. state.Name
|
|
2954
|
+
local func = self.Animation[REMAP[name] or name]
|
|
2955
|
+
func(speed)
|
|
2956
|
+
end))
|
|
2957
|
+
end
|
|
2958
|
+
|
|
2959
|
+
-- Public Methods
|
|
2960
|
+
|
|
2961
|
+
function StateTrackerClass:Update(gravityUp, isGrounded, isInputMoving)
|
|
2962
|
+
local cVelocity = self.Controller.HRP.Velocity
|
|
2963
|
+
local gVelocity = cVelocity:Dot(gravityUp)
|
|
2964
|
+
|
|
2965
|
+
local oldState = self.State
|
|
2966
|
+
local oldSpeed = self.Speed
|
|
2967
|
+
|
|
2968
|
+
local newState = nil
|
|
2969
|
+
local newSpeed = cVelocity.Magnitude
|
|
2970
|
+
|
|
2971
|
+
if not isGrounded then
|
|
2972
|
+
if gVelocity > 0 then
|
|
2973
|
+
if self.Jumped then
|
|
2974
|
+
newState = Enum.HumanoidStateType.Jumping
|
|
2975
|
+
else
|
|
2976
|
+
newState = Enum.HumanoidStateType.Freefall
|
|
2977
|
+
end
|
|
2978
|
+
else
|
|
2979
|
+
if self.Jumped then
|
|
2980
|
+
self.Jumped = false
|
|
2981
|
+
end
|
|
2982
|
+
newState = Enum.HumanoidStateType.Freefall
|
|
2983
|
+
end
|
|
2984
|
+
else
|
|
2985
|
+
if self.Jumped and os.clock() - self.JumpTick > 0.1 then
|
|
2986
|
+
self.Jumped = false
|
|
2987
|
+
end
|
|
2988
|
+
newSpeed = (cVelocity - gVelocity*gravityUp).Magnitude
|
|
2989
|
+
newState = Enum.HumanoidStateType.Running
|
|
2990
|
+
end
|
|
2991
|
+
|
|
2992
|
+
newSpeed = isInputMoving and newSpeed or 0
|
|
2993
|
+
|
|
2994
|
+
if oldState ~= newState or (SPEED[newState] and math.abs(newSpeed - oldSpeed) > 0.1) then
|
|
2995
|
+
self.State = newState
|
|
2996
|
+
self.Speed = newSpeed
|
|
2997
|
+
self.Changed:Fire(newState, newSpeed)
|
|
2998
|
+
end
|
|
2999
|
+
end
|
|
3000
|
+
|
|
3001
|
+
function StateTrackerClass:RequestJump()
|
|
3002
|
+
self.Jumped = true
|
|
3003
|
+
self.JumpTick = os.clock()
|
|
3004
|
+
end
|
|
3005
|
+
|
|
3006
|
+
function StateTrackerClass:Destroy()
|
|
3007
|
+
self._maid:Sweep()
|
|
3008
|
+
end
|
|
3009
|
+
|
|
3010
|
+
return StateTrackerClass</string>
|
|
3011
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
3012
|
+
<BinaryString name="Tags"></BinaryString>
|
|
3013
|
+
</Properties>
|
|
3014
|
+
</Item>
|
|
3015
|
+
<Item class="Folder" referent="21">
|
|
3016
|
+
<Properties>
|
|
3017
|
+
<string name="Name">Utility</string>
|
|
3018
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
3019
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
3020
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
3021
|
+
<BinaryString name="Tags"></BinaryString>
|
|
3022
|
+
</Properties>
|
|
3023
|
+
<Item class="ModuleScript" referent="22">
|
|
3024
|
+
<Properties>
|
|
3025
|
+
<string name="Name">Maid</string>
|
|
3026
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
3027
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
3028
|
+
<Content name="LinkedSource">
|
|
3029
|
+
<null>
|
|
3030
|
+
</null>
|
|
3031
|
+
</Content>
|
|
3032
|
+
<string name="Source">-- CONSTANTS
|
|
3033
|
+
|
|
3034
|
+
local FORMAT_STR = "Maid does not support type \"%s\""
|
|
3035
|
+
|
|
3036
|
+
local DESTRUCTORS = {
|
|
3037
|
+
["function"] = function(item)
|
|
3038
|
+
item()
|
|
3039
|
+
end;
|
|
3040
|
+
["RBXScriptConnection"] = function(item)
|
|
3041
|
+
item:Disconnect()
|
|
3042
|
+
end;
|
|
3043
|
+
["Instance"] = function(item)
|
|
3044
|
+
item:Destroy()
|
|
3045
|
+
end;
|
|
3046
|
+
["table"] = function(item)
|
|
3047
|
+
item:Destroy()
|
|
3048
|
+
end
|
|
3049
|
+
}
|
|
3050
|
+
|
|
3051
|
+
-- Class
|
|
3052
|
+
|
|
3053
|
+
local MaidClass = {}
|
|
3054
|
+
MaidClass.__index = MaidClass
|
|
3055
|
+
MaidClass.ClassName = "Maid"
|
|
3056
|
+
|
|
3057
|
+
-- Public Constructors
|
|
3058
|
+
|
|
3059
|
+
function MaidClass.new(...)
|
|
3060
|
+
local self = setmetatable({}, MaidClass)
|
|
3061
|
+
|
|
3062
|
+
self.Trash = {}
|
|
3063
|
+
|
|
3064
|
+
for _, item in pairs({...}) do
|
|
3065
|
+
self:Mark(item)
|
|
3066
|
+
end
|
|
3067
|
+
|
|
3068
|
+
return self
|
|
3069
|
+
end
|
|
3070
|
+
|
|
3071
|
+
-- Public Methods
|
|
3072
|
+
|
|
3073
|
+
function MaidClass:Mark(item)
|
|
3074
|
+
local tof = typeof(item)
|
|
3075
|
+
|
|
3076
|
+
if DESTRUCTORS[tof] then
|
|
3077
|
+
self.Trash[item] = tof
|
|
3078
|
+
else
|
|
3079
|
+
error(FORMAT_STR:format(tof), 2)
|
|
3080
|
+
end
|
|
3081
|
+
end
|
|
3082
|
+
|
|
3083
|
+
function MaidClass:Unmark(item)
|
|
3084
|
+
if item then
|
|
3085
|
+
self.Trash[item] = nil
|
|
3086
|
+
else
|
|
3087
|
+
self.Trash = {}
|
|
3088
|
+
end
|
|
3089
|
+
end
|
|
3090
|
+
|
|
3091
|
+
function MaidClass:Sweep()
|
|
3092
|
+
for item, tof in pairs(self.Trash) do
|
|
3093
|
+
DESTRUCTORS[tof](item)
|
|
3094
|
+
end
|
|
3095
|
+
self.Trash = {}
|
|
3096
|
+
end
|
|
3097
|
+
|
|
3098
|
+
MaidClass.Destroy = MaidClass.Sweep
|
|
3099
|
+
|
|
3100
|
+
--
|
|
3101
|
+
|
|
3102
|
+
return MaidClass</string>
|
|
3103
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
3104
|
+
<BinaryString name="Tags"></BinaryString>
|
|
3105
|
+
</Properties>
|
|
3106
|
+
</Item>
|
|
3107
|
+
<Item class="ModuleScript" referent="23">
|
|
3108
|
+
<Properties>
|
|
3109
|
+
<string name="Name">Signal</string>
|
|
3110
|
+
<BinaryString name="AttributesSerialize"></BinaryString>
|
|
3111
|
+
<bool name="DefinesCapabilities">false</bool>
|
|
3112
|
+
<Content name="LinkedSource">
|
|
3113
|
+
<null>
|
|
3114
|
+
</null>
|
|
3115
|
+
</Content>
|
|
3116
|
+
<string name="Source">-- Taken from Quenty's nevermore engine
|
|
3117
|
+
-- https://github.com/Quenty/NevermoreEngine/blob/version2/LICENSE.md
|
|
3118
|
+
-- https://github.com/Quenty/NevermoreEngine
|
|
3119
|
+
|
|
3120
|
+
--- Lua-side duplication of the API of events on Roblox objects.
|
|
3121
|
+
-- Signals are needed for to ensure that for local events objects are passed by
|
|
3122
|
+
-- reference rather than by value where possible, as the BindableEvent objects
|
|
3123
|
+
-- always pass signal arguments by value, meaning tables will be deep copied.
|
|
3124
|
+
-- Roblox's deep copy method parses to a non-lua table compatable format.
|
|
3125
|
+
-- @classmod Signal
|
|
3126
|
+
|
|
3127
|
+
local ENABLE_TRACEBACK = false
|
|
3128
|
+
|
|
3129
|
+
local Signal = {}
|
|
3130
|
+
Signal.__index = Signal
|
|
3131
|
+
Signal.ClassName = "Signal"
|
|
3132
|
+
|
|
3133
|
+
--- Constructs a new signal.
|
|
3134
|
+
-- @constructor Signal.new()
|
|
3135
|
+
-- @treturn Signal
|
|
3136
|
+
function Signal.new()
|
|
3137
|
+
local self = setmetatable({}, Signal)
|
|
3138
|
+
|
|
3139
|
+
self._bindableEvent = Instance.new("BindableEvent")
|
|
3140
|
+
self._argData = nil
|
|
3141
|
+
self._argCount = nil -- Prevent edge case of :Fire("A", nil) --> "A" instead of "A", nil
|
|
3142
|
+
|
|
3143
|
+
self._source = ENABLE_TRACEBACK and debug.traceback() or ""
|
|
3144
|
+
|
|
3145
|
+
return self
|
|
3146
|
+
end
|
|
3147
|
+
|
|
3148
|
+
--- Fire the event with the given arguments. All handlers will be invoked. Handlers follow
|
|
3149
|
+
-- Roblox signal conventions.
|
|
3150
|
+
-- @param ... Variable arguments to pass to handler
|
|
3151
|
+
-- @treturn nil
|
|
3152
|
+
function Signal:Fire(...)
|
|
3153
|
+
if not self._bindableEvent then
|
|
3154
|
+
warn(("Signal is already destroyed. %s"):format(self._source))
|
|
3155
|
+
return
|
|
3156
|
+
end
|
|
3157
|
+
|
|
3158
|
+
self._argData = {...}
|
|
3159
|
+
self._argCount = select("#", ...)
|
|
3160
|
+
self._bindableEvent:Fire()
|
|
3161
|
+
-- self._argData = nil
|
|
3162
|
+
-- self._argCount = nil
|
|
3163
|
+
end
|
|
3164
|
+
|
|
3165
|
+
--- Connect a new handler to the event. Returns a connection object that can be disconnected.
|
|
3166
|
+
-- @tparam function handler Function handler called with arguments passed when `:Fire(...)` is called
|
|
3167
|
+
-- @treturn Connection Connection object that can be disconnected
|
|
3168
|
+
function Signal:Connect(handler)
|
|
3169
|
+
if not (type(handler) == "function") then
|
|
3170
|
+
error(("connect(%s)"):format(typeof(handler)), 2)
|
|
3171
|
+
end
|
|
3172
|
+
|
|
3173
|
+
return self._bindableEvent.Event:Connect(function()
|
|
3174
|
+
handler(unpack(self._argData, 1, self._argCount))
|
|
3175
|
+
end)
|
|
3176
|
+
end
|
|
3177
|
+
|
|
3178
|
+
--- Wait for fire to be called, and return the arguments it was given.
|
|
3179
|
+
-- @treturn ... Variable arguments from connection
|
|
3180
|
+
function Signal:Wait()
|
|
3181
|
+
self._bindableEvent.Event:Wait()
|
|
3182
|
+
assert(self._argData, "Missing arg data, likely due to :TweenSize/Position corrupting threadrefs.")
|
|
3183
|
+
return unpack(self._argData, 1, self._argCount)
|
|
3184
|
+
end
|
|
3185
|
+
|
|
3186
|
+
--- Disconnects all connected events to the signal. Voids the signal as unusable.
|
|
3187
|
+
-- @treturn nil
|
|
3188
|
+
function Signal:Destroy()
|
|
3189
|
+
if self._bindableEvent then
|
|
3190
|
+
self._bindableEvent:Destroy()
|
|
3191
|
+
self._bindableEvent = nil
|
|
3192
|
+
end
|
|
3193
|
+
|
|
3194
|
+
self._argData = nil
|
|
3195
|
+
self._argCount = nil
|
|
3196
|
+
|
|
3197
|
+
setmetatable(self, nil)
|
|
3198
|
+
end
|
|
3199
|
+
|
|
3200
|
+
return Signal</string>
|
|
3201
|
+
<int64 name="SourceAssetId">-1</int64>
|
|
3202
|
+
<BinaryString name="Tags"></BinaryString>
|
|
3203
|
+
</Properties>
|
|
3204
|
+
</Item>
|
|
3205
|
+
</Item>
|
|
3206
|
+
</Item>
|
|
3207
|
+
</Item>
|
|
3208
|
+
</roblox>
|