roblox-opencode 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/README.md +122 -0
- package/commands/setup-game.md +108 -0
- package/commands/sync-check.md +53 -0
- package/core/roblox-core.md +93 -0
- package/dist/server.js +167 -0
- package/package.json +35 -0
- package/skills/roblox-analytics/SKILL.md +277 -0
- package/skills/roblox-analytics/references/event-batcher.luau +75 -0
- package/skills/roblox-animation-vfx/SKILL.md +1325 -0
- package/skills/roblox-architecture/SKILL.md +863 -0
- package/skills/roblox-architecture/references/combat-systems.md +1381 -0
- package/skills/roblox-code-review/SKILL.md +687 -0
- package/skills/roblox-data/SKILL.md +889 -0
- package/skills/roblox-data/references/inventory-systems.md +1729 -0
- package/skills/roblox-debug/SKILL.md +99 -0
- package/skills/roblox-gui/SKILL.md +1103 -0
- package/skills/roblox-gui-fusion/SKILL.md +150 -0
- package/skills/roblox-gui-fusion/references/inventory.luau +427 -0
- package/skills/roblox-gui-fusion/references/settings-menu.luau +579 -0
- package/skills/roblox-gui-fusion/references/shop.luau +411 -0
- package/skills/roblox-luau-mastery/SKILL.md +1519 -0
- package/skills/roblox-monetization/SKILL.md +1084 -0
- package/skills/roblox-monetization/references/process-receipt.luau +131 -0
- package/skills/roblox-networking/SKILL.md +669 -0
- package/skills/roblox-networking/references/remote-validator.luau +193 -0
- package/skills/roblox-publish-checklist/SKILL.md +128 -0
- package/skills/roblox-runtime/SKILL.md +753 -0
- package/skills/roblox-sharp-edges/SKILL.md +295 -0
- package/skills/roblox-sync/SKILL.md +126 -0
- package/skills/roblox-testing/SKILL.md +943 -0
- package/skills/roblox-tooling/SKILL.md +150 -0
- package/vendor/LICENSES/ProfileStore-LICENSE +201 -0
- package/vendor/LICENSES/RbxUtil-LICENSE +7 -0
- package/vendor/LICENSES/promise-LICENSE +21 -0
- package/vendor/LICENSES/t-LICENSE +21 -0
- package/vendor/LICENSES/testez-LICENSE +201 -0
- package/vendor/README.md +84 -0
- package/vendor/fusion/Animation/ExternalTime.luau +84 -0
- package/vendor/fusion/Animation/Spring.luau +322 -0
- package/vendor/fusion/Animation/Stopwatch.luau +128 -0
- package/vendor/fusion/Animation/Tween.luau +187 -0
- package/vendor/fusion/Animation/getTweenDuration.luau +27 -0
- package/vendor/fusion/Animation/getTweenRatio.luau +47 -0
- package/vendor/fusion/Animation/lerpType.luau +164 -0
- package/vendor/fusion/Animation/packType.luau +100 -0
- package/vendor/fusion/Animation/springCoefficients.luau +80 -0
- package/vendor/fusion/Animation/unpackType.luau +103 -0
- package/vendor/fusion/Colour/Oklab.luau +70 -0
- package/vendor/fusion/Colour/sRGB.luau +55 -0
- package/vendor/fusion/External.luau +168 -0
- package/vendor/fusion/ExternalDebug.luau +70 -0
- package/vendor/fusion/Graph/Observer.luau +114 -0
- package/vendor/fusion/Graph/castToGraph.luau +29 -0
- package/vendor/fusion/Graph/change.luau +81 -0
- package/vendor/fusion/Graph/depend.luau +33 -0
- package/vendor/fusion/Graph/evaluate.luau +56 -0
- package/vendor/fusion/Instances/Attribute.luau +58 -0
- package/vendor/fusion/Instances/AttributeChange.luau +47 -0
- package/vendor/fusion/Instances/AttributeOut.luau +63 -0
- package/vendor/fusion/Instances/Child.luau +21 -0
- package/vendor/fusion/Instances/Children.luau +148 -0
- package/vendor/fusion/Instances/Hydrate.luau +33 -0
- package/vendor/fusion/Instances/New.luau +53 -0
- package/vendor/fusion/Instances/OnChange.luau +50 -0
- package/vendor/fusion/Instances/OnEvent.luau +54 -0
- package/vendor/fusion/Instances/Out.luau +69 -0
- package/vendor/fusion/Instances/applyInstanceProps.luau +149 -0
- package/vendor/fusion/Instances/defaultProps.luau +194 -0
- package/vendor/fusion/LICENSE +21 -0
- package/vendor/fusion/Logging/formatError.luau +49 -0
- package/vendor/fusion/Logging/messages.luau +52 -0
- package/vendor/fusion/Logging/parseError.luau +25 -0
- package/vendor/fusion/Memory/checkLifetime.luau +134 -0
- package/vendor/fusion/Memory/deriveScope.luau +24 -0
- package/vendor/fusion/Memory/deriveScopeImpl.luau +45 -0
- package/vendor/fusion/Memory/doCleanup.luau +79 -0
- package/vendor/fusion/Memory/innerScope.luau +34 -0
- package/vendor/fusion/Memory/legacyCleanup.luau +18 -0
- package/vendor/fusion/Memory/needsDestruction.luau +17 -0
- package/vendor/fusion/Memory/poisonScope.luau +34 -0
- package/vendor/fusion/Memory/scopePool.luau +55 -0
- package/vendor/fusion/Memory/scoped.luau +27 -0
- package/vendor/fusion/Memory/whichLivesLonger.luau +75 -0
- package/vendor/fusion/RobloxExternal.luau +98 -0
- package/vendor/fusion/State/Computed.luau +139 -0
- package/vendor/fusion/State/For/Disassembly.luau +211 -0
- package/vendor/fusion/State/For/ForTypes.luau +30 -0
- package/vendor/fusion/State/For/init.luau +110 -0
- package/vendor/fusion/State/ForKeys.luau +94 -0
- package/vendor/fusion/State/ForPairs.luau +97 -0
- package/vendor/fusion/State/ForValues.luau +94 -0
- package/vendor/fusion/State/Value.luau +88 -0
- package/vendor/fusion/State/castToState.luau +26 -0
- package/vendor/fusion/State/peek.luau +31 -0
- package/vendor/fusion/State/updateAll.luau +1 -0
- package/vendor/fusion/Types.luau +314 -0
- package/vendor/fusion/Utility/Contextual.luau +91 -0
- package/vendor/fusion/Utility/Safe.luau +23 -0
- package/vendor/fusion/Utility/isSimilar.luau +29 -0
- package/vendor/fusion/Utility/merge.luau +35 -0
- package/vendor/fusion/Utility/nameOf.luau +35 -0
- package/vendor/fusion/Utility/never.luau +14 -0
- package/vendor/fusion/Utility/nicknames.luau +11 -0
- package/vendor/fusion/Utility/xtypeof.luau +27 -0
- package/vendor/fusion/init.luau +82 -0
- package/vendor/profilestore/init.luau +2243 -0
- package/vendor/promise/init.luau +1982 -0
- package/vendor/rbxutil/buffer-util/Buffer.test.luau +25 -0
- package/vendor/rbxutil/buffer-util/BufferReader.luau +228 -0
- package/vendor/rbxutil/buffer-util/BufferWriter.luau +269 -0
- package/vendor/rbxutil/buffer-util/DataTypeBuffer.luau +223 -0
- package/vendor/rbxutil/buffer-util/Types.luau +60 -0
- package/vendor/rbxutil/buffer-util/index.d.ts +153 -0
- package/vendor/rbxutil/buffer-util/init.luau +41 -0
- package/vendor/rbxutil/buffer-util/package.json +16 -0
- package/vendor/rbxutil/buffer-util/wally.toml +9 -0
- package/vendor/rbxutil/comm/Client/ClientComm.luau +232 -0
- package/vendor/rbxutil/comm/Client/ClientRemoteProperty.luau +156 -0
- package/vendor/rbxutil/comm/Client/ClientRemoteSignal.luau +109 -0
- package/vendor/rbxutil/comm/Client/init.luau +135 -0
- package/vendor/rbxutil/comm/Server/RemoteProperty.luau +295 -0
- package/vendor/rbxutil/comm/Server/RemoteSignal.luau +211 -0
- package/vendor/rbxutil/comm/Server/ServerComm.luau +211 -0
- package/vendor/rbxutil/comm/Server/init.luau +140 -0
- package/vendor/rbxutil/comm/Types.luau +18 -0
- package/vendor/rbxutil/comm/Util.luau +27 -0
- package/vendor/rbxutil/comm/init.luau +35 -0
- package/vendor/rbxutil/comm/wally.toml +13 -0
- package/vendor/rbxutil/component/init.luau +759 -0
- package/vendor/rbxutil/component/init.test.luau +311 -0
- package/vendor/rbxutil/component/wally.toml +14 -0
- package/vendor/rbxutil/concur/init.luau +542 -0
- package/vendor/rbxutil/concur/init.test.luau +364 -0
- package/vendor/rbxutil/concur/wally.toml +8 -0
- package/vendor/rbxutil/enum-list/init.luau +101 -0
- package/vendor/rbxutil/enum-list/init.test.luau +91 -0
- package/vendor/rbxutil/enum-list/wally.toml +8 -0
- package/vendor/rbxutil/find/index.d.ts +20 -0
- package/vendor/rbxutil/find/init.luau +44 -0
- package/vendor/rbxutil/find/package.json +17 -0
- package/vendor/rbxutil/find/wally.toml +8 -0
- package/vendor/rbxutil/input/Gamepad.luau +559 -0
- package/vendor/rbxutil/input/Keyboard.luau +124 -0
- package/vendor/rbxutil/input/Mouse.luau +278 -0
- package/vendor/rbxutil/input/PreferredInput.luau +91 -0
- package/vendor/rbxutil/input/Touch.luau +120 -0
- package/vendor/rbxutil/input/init.luau +33 -0
- package/vendor/rbxutil/input/wally.toml +12 -0
- package/vendor/rbxutil/loader/index.d.ts +15 -0
- package/vendor/rbxutil/loader/init.luau +137 -0
- package/vendor/rbxutil/loader/wally.toml +8 -0
- package/vendor/rbxutil/log/index.d.ts +38 -0
- package/vendor/rbxutil/log/init.luau +746 -0
- package/vendor/rbxutil/log/wally.toml +8 -0
- package/vendor/rbxutil/net/init.luau +190 -0
- package/vendor/rbxutil/net/wally.toml +8 -0
- package/vendor/rbxutil/option/index.d.ts +44 -0
- package/vendor/rbxutil/option/init.luau +489 -0
- package/vendor/rbxutil/option/init.test.luau +342 -0
- package/vendor/rbxutil/option/wally.toml +8 -0
- package/vendor/rbxutil/pid/index.d.ts +53 -0
- package/vendor/rbxutil/pid/init.luau +195 -0
- package/vendor/rbxutil/pid/package.json +16 -0
- package/vendor/rbxutil/pid/wally.toml +9 -0
- package/vendor/rbxutil/quaternion/index.d.ts +117 -0
- package/vendor/rbxutil/quaternion/init.luau +570 -0
- package/vendor/rbxutil/quaternion/package.json +16 -0
- package/vendor/rbxutil/quaternion/wally.toml +9 -0
- package/vendor/rbxutil/query/index.d.ts +43 -0
- package/vendor/rbxutil/query/init.luau +117 -0
- package/vendor/rbxutil/query/package.json +18 -0
- package/vendor/rbxutil/query/wally.toml +9 -0
- package/vendor/rbxutil/sequent/index.d.ts +28 -0
- package/vendor/rbxutil/sequent/init.luau +340 -0
- package/vendor/rbxutil/sequent/package.json +16 -0
- package/vendor/rbxutil/sequent/wally.toml +9 -0
- package/vendor/rbxutil/ser/init.luau +175 -0
- package/vendor/rbxutil/ser/init.test.luau +50 -0
- package/vendor/rbxutil/ser/wally.toml +11 -0
- package/vendor/rbxutil/shake/index.d.ts +36 -0
- package/vendor/rbxutil/shake/init.luau +532 -0
- package/vendor/rbxutil/shake/init.test.luau +267 -0
- package/vendor/rbxutil/shake/package.json +16 -0
- package/vendor/rbxutil/shake/wally.toml +9 -0
- package/vendor/rbxutil/signal/index.d.ts +100 -0
- package/vendor/rbxutil/signal/init.luau +432 -0
- package/vendor/rbxutil/signal/init.test.luau +190 -0
- package/vendor/rbxutil/signal/package.json +17 -0
- package/vendor/rbxutil/signal/wally.toml +9 -0
- package/vendor/rbxutil/silo/TableWatcher.luau +65 -0
- package/vendor/rbxutil/silo/Util.luau +55 -0
- package/vendor/rbxutil/silo/init.luau +338 -0
- package/vendor/rbxutil/silo/init.test.luau +215 -0
- package/vendor/rbxutil/silo/wally.toml +8 -0
- package/vendor/rbxutil/spring/index.d.ts +40 -0
- package/vendor/rbxutil/spring/init.luau +97 -0
- package/vendor/rbxutil/spring/package.json +17 -0
- package/vendor/rbxutil/spring/wally.toml +8 -0
- package/vendor/rbxutil/stream/index.d.ts +88 -0
- package/vendor/rbxutil/stream/init.luau +597 -0
- package/vendor/rbxutil/stream/package.json +18 -0
- package/vendor/rbxutil/stream/wally.toml +9 -0
- package/vendor/rbxutil/streamable/Streamable.luau +202 -0
- package/vendor/rbxutil/streamable/StreamableUtil.luau +80 -0
- package/vendor/rbxutil/streamable/init.luau +8 -0
- package/vendor/rbxutil/streamable/wally.toml +12 -0
- package/vendor/rbxutil/symbol/init.luau +56 -0
- package/vendor/rbxutil/symbol/init.test.luau +37 -0
- package/vendor/rbxutil/symbol/wally.toml +8 -0
- package/vendor/rbxutil/table-util/init.luau +938 -0
- package/vendor/rbxutil/table-util/init.test.luau +439 -0
- package/vendor/rbxutil/table-util/wally.toml +8 -0
- package/vendor/rbxutil/task-queue/index.d.ts +27 -0
- package/vendor/rbxutil/task-queue/init.luau +97 -0
- package/vendor/rbxutil/task-queue/wally.toml +8 -0
- package/vendor/rbxutil/timer/index.d.ts +81 -0
- package/vendor/rbxutil/timer/init.luau +249 -0
- package/vendor/rbxutil/timer/init.test.luau +73 -0
- package/vendor/rbxutil/timer/wally.toml +11 -0
- package/vendor/rbxutil/tree/index.d.ts +15 -0
- package/vendor/rbxutil/tree/init.luau +137 -0
- package/vendor/rbxutil/tree/wally.toml +8 -0
- package/vendor/rbxutil/trove/index.d.ts +46 -0
- package/vendor/rbxutil/trove/init.luau +787 -0
- package/vendor/rbxutil/trove/init.test.luau +203 -0
- package/vendor/rbxutil/trove/wally.toml +8 -0
- package/vendor/rbxutil/typed-remote/init.luau +196 -0
- package/vendor/rbxutil/typed-remote/wally.toml +8 -0
- package/vendor/rbxutil/wait-for/index.d.ts +17 -0
- package/vendor/rbxutil/wait-for/init.luau +257 -0
- package/vendor/rbxutil/wait-for/init.test.luau +182 -0
- package/vendor/rbxutil/wait-for/wally.toml +11 -0
- package/vendor/t/t.lua +1350 -0
- package/vendor/testez/Context.lua +26 -0
- package/vendor/testez/Expectation.lua +311 -0
- package/vendor/testez/ExpectationContext.lua +38 -0
- package/vendor/testez/LifecycleHooks.lua +89 -0
- package/vendor/testez/Reporters/TeamCityReporter.lua +102 -0
- package/vendor/testez/Reporters/TextReporter.lua +106 -0
- package/vendor/testez/Reporters/TextReporterQuiet.lua +97 -0
- package/vendor/testez/TestBootstrap.lua +147 -0
- package/vendor/testez/TestEnum.lua +28 -0
- package/vendor/testez/TestPlan.lua +304 -0
- package/vendor/testez/TestPlanner.lua +40 -0
- package/vendor/testez/TestResults.lua +112 -0
- package/vendor/testez/TestRunner.lua +188 -0
- package/vendor/testez/TestSession.lua +243 -0
- package/vendor/testez/init.lua +40 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
A specialised state object for following a goal state smoothly over time,
|
|
8
|
+
using a TweenInfo to shape the motion.
|
|
9
|
+
|
|
10
|
+
https://elttob.uk/Fusion/0.3/api-reference/animation/types/tween/
|
|
11
|
+
]]
|
|
12
|
+
|
|
13
|
+
local Package = script.Parent.Parent
|
|
14
|
+
local Types = require(Package.Types)
|
|
15
|
+
local External = require(Package.External)
|
|
16
|
+
-- Memory
|
|
17
|
+
local checkLifetime = require(Package.Memory.checkLifetime)
|
|
18
|
+
-- Graph
|
|
19
|
+
local depend = require(Package.Graph.depend)
|
|
20
|
+
local evaluate = require(Package.Graph.evaluate)
|
|
21
|
+
-- State
|
|
22
|
+
local castToState = require(Package.State.castToState)
|
|
23
|
+
local peek = require(Package.State.peek)
|
|
24
|
+
-- Animation
|
|
25
|
+
local ExternalTime = require(Package.Animation.ExternalTime)
|
|
26
|
+
local Stopwatch = require(Package.Animation.Stopwatch)
|
|
27
|
+
local lerpType = require(Package.Animation.lerpType)
|
|
28
|
+
local getTweenRatio = require(Package.Animation.getTweenRatio)
|
|
29
|
+
local getTweenDuration = require(Package.Animation.getTweenDuration)
|
|
30
|
+
-- Utility
|
|
31
|
+
local nicknames = require(Package.Utility.nicknames)
|
|
32
|
+
|
|
33
|
+
export type Self<T> = Types.Tween<T> & {
|
|
34
|
+
_activeDuration: number,
|
|
35
|
+
_activeElapsed: number,
|
|
36
|
+
_activeFrom: T,
|
|
37
|
+
_activeTo: T,
|
|
38
|
+
_activeTweenInfo: TweenInfo,
|
|
39
|
+
_goal: Types.UsedAs<T>,
|
|
40
|
+
_stopwatch: Stopwatch.Stopwatch?,
|
|
41
|
+
_tweenInfo: Types.UsedAs<TweenInfo>,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
local class = {}
|
|
45
|
+
class.type = "State"
|
|
46
|
+
class.kind = "Tween"
|
|
47
|
+
class.timeliness = "eager"
|
|
48
|
+
|
|
49
|
+
local METATABLE = table.freeze {__index = class}
|
|
50
|
+
|
|
51
|
+
local function Tween<T>(
|
|
52
|
+
scope: Types.Scope<unknown>,
|
|
53
|
+
goal: Types.UsedAs<T>,
|
|
54
|
+
tweenInfo: Types.UsedAs<TweenInfo>?
|
|
55
|
+
): Types.Tween<T>
|
|
56
|
+
local createdAt = os.clock()
|
|
57
|
+
if castToState(scope) then
|
|
58
|
+
External.logError("scopeMissing", nil, "Tweens", "myScope:Tween(goalState, tweenInfo)")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
local goalState = castToState(goal)
|
|
62
|
+
local stopwatch = nil
|
|
63
|
+
if goalState ~= nil then
|
|
64
|
+
stopwatch = Stopwatch(scope, ExternalTime(scope))
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
local self: Self<T> = setmetatable(
|
|
68
|
+
{
|
|
69
|
+
createdAt = createdAt,
|
|
70
|
+
dependencySet = {},
|
|
71
|
+
dependentSet = {},
|
|
72
|
+
lastChange = nil,
|
|
73
|
+
scope = scope,
|
|
74
|
+
validity = "invalid",
|
|
75
|
+
_activeDuration = nil,
|
|
76
|
+
_activeElapsed = nil,
|
|
77
|
+
_activeFrom = nil,
|
|
78
|
+
_activeTo = nil,
|
|
79
|
+
_activeTweenInfo = nil,
|
|
80
|
+
_EXTREMELY_DANGEROUS_usedAsValue = peek(goal),
|
|
81
|
+
_goal = goal,
|
|
82
|
+
_stopwatch = stopwatch,
|
|
83
|
+
_tweenInfo = tweenInfo or TweenInfo.new()
|
|
84
|
+
},
|
|
85
|
+
METATABLE
|
|
86
|
+
) :: any
|
|
87
|
+
local destroy = function()
|
|
88
|
+
self.scope = nil
|
|
89
|
+
for dependency in pairs(self.dependencySet) do
|
|
90
|
+
dependency.dependentSet[self] = nil
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
self.oldestTask = destroy
|
|
94
|
+
nicknames[self.oldestTask] = "Tween"
|
|
95
|
+
table.insert(scope, destroy)
|
|
96
|
+
|
|
97
|
+
if goalState ~= nil then
|
|
98
|
+
checkLifetime.bOutlivesA(
|
|
99
|
+
scope, self.oldestTask,
|
|
100
|
+
goalState.scope, goalState.oldestTask,
|
|
101
|
+
checkLifetime.formatters.animationGoal
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
local tweenInfoState = castToState(tweenInfo)
|
|
106
|
+
if tweenInfoState ~= nil then
|
|
107
|
+
checkLifetime.bOutlivesA(
|
|
108
|
+
scope, self.oldestTask,
|
|
109
|
+
tweenInfoState.scope, tweenInfoState.oldestTask,
|
|
110
|
+
checkLifetime.formatters.parameter, "tween info"
|
|
111
|
+
)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
-- Eagerly evaluated objects need to evaluate themselves so that they're
|
|
115
|
+
-- valid at all times.
|
|
116
|
+
evaluate(self, true)
|
|
117
|
+
|
|
118
|
+
return self
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
function class.get<T>(
|
|
122
|
+
self: Self<T>
|
|
123
|
+
): never
|
|
124
|
+
return External.logError("stateGetWasRemoved")
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
function class._evaluate<T>(
|
|
128
|
+
self: Self<T>
|
|
129
|
+
): boolean
|
|
130
|
+
local goal = castToState(self._goal)
|
|
131
|
+
-- Allow non-state goals to pass through transparently.
|
|
132
|
+
if goal == nil then
|
|
133
|
+
self._EXTREMELY_DANGEROUS_usedAsValue = self._goal :: T
|
|
134
|
+
return false
|
|
135
|
+
end
|
|
136
|
+
depend(self, goal)
|
|
137
|
+
local newTweenTo = peek(goal)
|
|
138
|
+
-- Protect against NaN goals.
|
|
139
|
+
if newTweenTo ~= newTweenTo then
|
|
140
|
+
External.logWarn("tweenNanGoal")
|
|
141
|
+
return false
|
|
142
|
+
end
|
|
143
|
+
local stopwatch = self._stopwatch :: Stopwatch.Stopwatch
|
|
144
|
+
local tweenInfo = peek(self._tweenInfo) :: TweenInfo
|
|
145
|
+
-- Restart animation when the goal changes, or if the tween info changes
|
|
146
|
+
-- partway through another animation.
|
|
147
|
+
if
|
|
148
|
+
self._activeTo ~= newTweenTo or
|
|
149
|
+
(self._activeElapsed < self._activeDuration and self._activeTweenInfo ~= tweenInfo)
|
|
150
|
+
then
|
|
151
|
+
self._activeDuration = getTweenDuration(tweenInfo)
|
|
152
|
+
self._activeFrom = self._EXTREMELY_DANGEROUS_usedAsValue
|
|
153
|
+
self._activeTo = newTweenTo
|
|
154
|
+
self._activeTweenInfo = tweenInfo
|
|
155
|
+
stopwatch:zero()
|
|
156
|
+
stopwatch:unpause()
|
|
157
|
+
end
|
|
158
|
+
depend(self, stopwatch)
|
|
159
|
+
self._activeElapsed = peek(stopwatch)
|
|
160
|
+
if
|
|
161
|
+
self._activeFrom == self._activeTo or -- endpoints match
|
|
162
|
+
self._activeElapsed >= self._activeDuration or -- animation is done
|
|
163
|
+
typeof(self._activeTo) ~= typeof(self._activeFrom) -- type difference
|
|
164
|
+
then
|
|
165
|
+
self._activeFrom = self._activeTo
|
|
166
|
+
self._activeElapsed = self._activeDuration
|
|
167
|
+
stopwatch:pause()
|
|
168
|
+
end
|
|
169
|
+
-- Compute actual tweened value.
|
|
170
|
+
local ratio = getTweenRatio(tweenInfo, self._activeElapsed)
|
|
171
|
+
local oldValue = self._EXTREMELY_DANGEROUS_usedAsValue
|
|
172
|
+
local newValue = lerpType(self._activeFrom, self._activeTo, ratio) :: T
|
|
173
|
+
-- Protect against NaN after motion.
|
|
174
|
+
if newValue ~= newValue then
|
|
175
|
+
External.logWarn("tweenNanMotion")
|
|
176
|
+
newValue = self._activeTo
|
|
177
|
+
end
|
|
178
|
+
-- Push update and check for similarity.
|
|
179
|
+
-- Don't need to use the similarity test here because this code doesn't
|
|
180
|
+
-- deal with tables, and NaN is already guarded against, so the similarity
|
|
181
|
+
-- test doesn't actually add any new safety here.
|
|
182
|
+
self._EXTREMELY_DANGEROUS_usedAsValue = newValue
|
|
183
|
+
return oldValue ~= newValue
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
table.freeze(class)
|
|
187
|
+
return Tween :: Types.TweenConstructor
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
Given a `tweenInfo`, returns how many seconds it will take before the tween
|
|
8
|
+
finishes moving. The result may be infinite if the tween repeats forever.
|
|
9
|
+
]]
|
|
10
|
+
|
|
11
|
+
local TweenService = game:GetService("TweenService")
|
|
12
|
+
|
|
13
|
+
local function getTweenDuration(
|
|
14
|
+
tweenInfo: TweenInfo
|
|
15
|
+
): number
|
|
16
|
+
if tweenInfo.RepeatCount <= -1 then
|
|
17
|
+
return math.huge
|
|
18
|
+
end
|
|
19
|
+
local tweenDuration = tweenInfo.DelayTime + tweenInfo.Time
|
|
20
|
+
if tweenInfo.Reverses then
|
|
21
|
+
tweenDuration += tweenInfo.Time
|
|
22
|
+
end
|
|
23
|
+
tweenDuration *= tweenInfo.RepeatCount + 1
|
|
24
|
+
return tweenDuration
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
return getTweenDuration
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
Given a `tweenInfo` and `currentTime`, returns a ratio which can be used to
|
|
8
|
+
tween between two values over time.
|
|
9
|
+
]]
|
|
10
|
+
|
|
11
|
+
local TweenService = game:GetService("TweenService")
|
|
12
|
+
|
|
13
|
+
local function getTweenRatio(
|
|
14
|
+
tweenInfo: TweenInfo,
|
|
15
|
+
currentTime: number
|
|
16
|
+
): number
|
|
17
|
+
local delay = tweenInfo.DelayTime
|
|
18
|
+
local duration = tweenInfo.Time
|
|
19
|
+
local reverses = tweenInfo.Reverses
|
|
20
|
+
local numCycles = 1 + tweenInfo.RepeatCount
|
|
21
|
+
local easeStyle = tweenInfo.EasingStyle
|
|
22
|
+
local easeDirection = tweenInfo.EasingDirection
|
|
23
|
+
local cycleDuration = delay + duration
|
|
24
|
+
if reverses then
|
|
25
|
+
cycleDuration += duration
|
|
26
|
+
end
|
|
27
|
+
-- If currentTime is infinity, then presumably the tween should be over.
|
|
28
|
+
-- This avoids NaN when the duration of an infinitely repeating tween is given.
|
|
29
|
+
if currentTime == math.huge then
|
|
30
|
+
return 1
|
|
31
|
+
end
|
|
32
|
+
if currentTime >= cycleDuration * numCycles and tweenInfo.RepeatCount > -1 then
|
|
33
|
+
return 1
|
|
34
|
+
end
|
|
35
|
+
local cycleTime = currentTime % cycleDuration
|
|
36
|
+
if cycleTime <= delay then
|
|
37
|
+
return 0
|
|
38
|
+
end
|
|
39
|
+
local tweenProgress = (cycleTime - delay) / duration
|
|
40
|
+
if tweenProgress > 1 then
|
|
41
|
+
tweenProgress = 2 - tweenProgress
|
|
42
|
+
end
|
|
43
|
+
local ratio = TweenService:GetValue(tweenProgress, easeStyle, easeDirection)
|
|
44
|
+
return ratio
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
return getTweenRatio
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
Linearly interpolates the given animatable types by a ratio.
|
|
8
|
+
If the types are different or not animatable, then the first value will be
|
|
9
|
+
returned for ratios below 0.5, and the second value for 0.5 and above.
|
|
10
|
+
]]
|
|
11
|
+
|
|
12
|
+
local Package = script.Parent.Parent
|
|
13
|
+
local Oklab = require(Package.Colour.Oklab)
|
|
14
|
+
|
|
15
|
+
local function lerpType(
|
|
16
|
+
from: unknown,
|
|
17
|
+
to: unknown,
|
|
18
|
+
ratio: number
|
|
19
|
+
): unknown
|
|
20
|
+
local typeString = typeof(from)
|
|
21
|
+
|
|
22
|
+
if typeof(to) == typeString then
|
|
23
|
+
-- both types must match for interpolation to make sense
|
|
24
|
+
if typeString == "number" then
|
|
25
|
+
local to, from = to :: number, from :: number
|
|
26
|
+
return (to - from) * ratio + from
|
|
27
|
+
|
|
28
|
+
elseif typeString == "CFrame" then
|
|
29
|
+
local to, from = to :: CFrame, from :: CFrame
|
|
30
|
+
return from:Lerp(to, ratio)
|
|
31
|
+
|
|
32
|
+
elseif typeString == "Color3" then
|
|
33
|
+
local to, from = to :: Color3, from :: Color3
|
|
34
|
+
local fromLab = Oklab.fromSRGB(from)
|
|
35
|
+
local toLab = Oklab.fromSRGB(to)
|
|
36
|
+
return Oklab.toSRGB(
|
|
37
|
+
fromLab:Lerp(toLab, ratio),
|
|
38
|
+
false
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
elseif typeString == "ColorSequenceKeypoint" then
|
|
42
|
+
local to, from = to :: ColorSequenceKeypoint, from :: ColorSequenceKeypoint
|
|
43
|
+
local fromLab = Oklab.fromSRGB(from.Value)
|
|
44
|
+
local toLab = Oklab.fromSRGB(to.Value)
|
|
45
|
+
return ColorSequenceKeypoint.new(
|
|
46
|
+
(to.Time - from.Time) * ratio + from.Time,
|
|
47
|
+
Oklab.toSRGB(
|
|
48
|
+
fromLab:Lerp(toLab, ratio),
|
|
49
|
+
false
|
|
50
|
+
)
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
elseif typeString == "DateTime" then
|
|
54
|
+
local to, from = to :: DateTime, from :: DateTime
|
|
55
|
+
return DateTime.fromUnixTimestampMillis(
|
|
56
|
+
(to.UnixTimestampMillis - from.UnixTimestampMillis) * ratio + from.UnixTimestampMillis
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
elseif typeString == "NumberRange" then
|
|
60
|
+
local to, from = to :: NumberRange, from :: NumberRange
|
|
61
|
+
return NumberRange.new(
|
|
62
|
+
(to.Min - from.Min) * ratio + from.Min,
|
|
63
|
+
(to.Max - from.Max) * ratio + from.Max
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
elseif typeString == "NumberSequenceKeypoint" then
|
|
67
|
+
local to, from = to :: NumberSequenceKeypoint, from :: NumberSequenceKeypoint
|
|
68
|
+
return NumberSequenceKeypoint.new(
|
|
69
|
+
(to.Time - from.Time) * ratio + from.Time,
|
|
70
|
+
(to.Value - from.Value) * ratio + from.Value,
|
|
71
|
+
(to.Envelope - from.Envelope) * ratio + from.Envelope
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
elseif typeString == "PhysicalProperties" then
|
|
75
|
+
local to, from = to :: PhysicalProperties, from :: PhysicalProperties
|
|
76
|
+
return PhysicalProperties.new(
|
|
77
|
+
(to.Density - from.Density) * ratio + from.Density,
|
|
78
|
+
(to.Friction - from.Friction) * ratio + from.Friction,
|
|
79
|
+
(to.Elasticity - from.Elasticity) * ratio + from.Elasticity,
|
|
80
|
+
(to.FrictionWeight - from.FrictionWeight) * ratio + from.FrictionWeight,
|
|
81
|
+
(to.ElasticityWeight - from.ElasticityWeight) * ratio + from.ElasticityWeight
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
elseif typeString == "Ray" then
|
|
85
|
+
local to, from = to :: Ray, from :: Ray
|
|
86
|
+
return Ray.new(
|
|
87
|
+
from.Origin:Lerp(to.Origin, ratio),
|
|
88
|
+
from.Direction:Lerp(to.Direction, ratio)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
elseif typeString == "Rect" then
|
|
92
|
+
local to, from = to :: Rect, from :: Rect
|
|
93
|
+
return Rect.new(
|
|
94
|
+
from.Min:Lerp(to.Min, ratio),
|
|
95
|
+
from.Max:Lerp(to.Max, ratio)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
elseif typeString == "Region3" then
|
|
99
|
+
local to, from = to :: Region3, from :: Region3
|
|
100
|
+
-- FUTURE: support rotated Region3s if/when they become constructable
|
|
101
|
+
local position = from.CFrame.Position:Lerp(to.CFrame.Position, ratio)
|
|
102
|
+
local halfSize = from.Size:Lerp(to.Size, ratio) / 2
|
|
103
|
+
return Region3.new(position - halfSize, position + halfSize)
|
|
104
|
+
|
|
105
|
+
elseif typeString == "Region3int16" then
|
|
106
|
+
local to, from = to :: Region3int16, from :: Region3int16
|
|
107
|
+
return Region3int16.new(
|
|
108
|
+
Vector3int16.new(
|
|
109
|
+
(to.Min.X - from.Min.X) * ratio + from.Min.X,
|
|
110
|
+
(to.Min.Y - from.Min.Y) * ratio + from.Min.Y,
|
|
111
|
+
(to.Min.Z - from.Min.Z) * ratio + from.Min.Z
|
|
112
|
+
),
|
|
113
|
+
Vector3int16.new(
|
|
114
|
+
(to.Max.X - from.Max.X) * ratio + from.Max.X,
|
|
115
|
+
(to.Max.Y - from.Max.Y) * ratio + from.Max.Y,
|
|
116
|
+
(to.Max.Z - from.Max.Z) * ratio + from.Max.Z
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
elseif typeString == "UDim" then
|
|
121
|
+
local to, from = to :: UDim, from :: UDim
|
|
122
|
+
return UDim.new(
|
|
123
|
+
(to.Scale - from.Scale) * ratio + from.Scale,
|
|
124
|
+
(to.Offset - from.Offset) * ratio + from.Offset
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
elseif typeString == "UDim2" then
|
|
128
|
+
local to, from = to :: UDim2, from :: UDim2
|
|
129
|
+
return from:Lerp(to, ratio)
|
|
130
|
+
|
|
131
|
+
elseif typeString == "Vector2" then
|
|
132
|
+
local to, from = to :: Vector2, from :: Vector2
|
|
133
|
+
return from:Lerp(to, ratio)
|
|
134
|
+
|
|
135
|
+
elseif typeString == "Vector2int16" then
|
|
136
|
+
local to, from = to :: Vector2int16, from :: Vector2int16
|
|
137
|
+
return Vector2int16.new(
|
|
138
|
+
(to.X - from.X) * ratio + from.X,
|
|
139
|
+
(to.Y - from.Y) * ratio + from.Y
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
elseif typeString == "Vector3" then
|
|
143
|
+
local to, from = to :: Vector3, from :: Vector3
|
|
144
|
+
return from:Lerp(to, ratio)
|
|
145
|
+
|
|
146
|
+
elseif typeString == "Vector3int16" then
|
|
147
|
+
local to, from = to :: Vector3int16, from :: Vector3int16
|
|
148
|
+
return Vector3int16.new(
|
|
149
|
+
(to.X - from.X) * ratio + from.X,
|
|
150
|
+
(to.Y - from.Y) * ratio + from.Y,
|
|
151
|
+
(to.Z - from.Z) * ratio + from.Z
|
|
152
|
+
)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
-- fallback case: the types are different or not animatable
|
|
157
|
+
if ratio < 0.5 then
|
|
158
|
+
return from
|
|
159
|
+
else
|
|
160
|
+
return to
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
return lerpType
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
Packs an array of numbers into a given animatable data type.
|
|
8
|
+
If the type is not animatable, nil will be returned.
|
|
9
|
+
]]
|
|
10
|
+
|
|
11
|
+
local Package = script.Parent.Parent
|
|
12
|
+
local Types = require(Package.Types)
|
|
13
|
+
local Oklab = require(Package.Colour.Oklab)
|
|
14
|
+
|
|
15
|
+
local function packType(
|
|
16
|
+
numbers: {number},
|
|
17
|
+
typeString: string
|
|
18
|
+
): Types.Animatable?
|
|
19
|
+
if typeString == "number" then
|
|
20
|
+
return numbers[1]
|
|
21
|
+
|
|
22
|
+
elseif typeString == "CFrame" then
|
|
23
|
+
return
|
|
24
|
+
CFrame.new(numbers[1], numbers[2], numbers[3]) *
|
|
25
|
+
CFrame.fromAxisAngle(
|
|
26
|
+
Vector3.new(numbers[4], numbers[5], numbers[6]).Unit,
|
|
27
|
+
numbers[7]
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
elseif typeString == "Color3" then
|
|
31
|
+
return Oklab.toSRGB(
|
|
32
|
+
Vector3.new(numbers[1], numbers[2], numbers[3]),
|
|
33
|
+
false
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
elseif typeString == "ColorSequenceKeypoint" then
|
|
37
|
+
return ColorSequenceKeypoint.new(
|
|
38
|
+
numbers[4],
|
|
39
|
+
Oklab.toSRGB(
|
|
40
|
+
Vector3.new(numbers[1], numbers[2], numbers[3]),
|
|
41
|
+
false
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
elseif typeString == "DateTime" then
|
|
46
|
+
return DateTime.fromUnixTimestampMillis(numbers[1])
|
|
47
|
+
|
|
48
|
+
elseif typeString == "NumberRange" then
|
|
49
|
+
return NumberRange.new(numbers[1], numbers[2])
|
|
50
|
+
|
|
51
|
+
elseif typeString == "NumberSequenceKeypoint" then
|
|
52
|
+
return NumberSequenceKeypoint.new(numbers[2], numbers[1], numbers[3])
|
|
53
|
+
|
|
54
|
+
elseif typeString == "PhysicalProperties" then
|
|
55
|
+
return PhysicalProperties.new(numbers[1], numbers[2], numbers[3], numbers[4], numbers[5])
|
|
56
|
+
|
|
57
|
+
elseif typeString == "Ray" then
|
|
58
|
+
return Ray.new(
|
|
59
|
+
Vector3.new(numbers[1], numbers[2], numbers[3]),
|
|
60
|
+
Vector3.new(numbers[4], numbers[5], numbers[6])
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
elseif typeString == "Rect" then
|
|
64
|
+
return Rect.new(numbers[1], numbers[2], numbers[3], numbers[4])
|
|
65
|
+
|
|
66
|
+
elseif typeString == "Region3" then
|
|
67
|
+
-- FUTURE: support rotated Region3s if/when they become constructable
|
|
68
|
+
local position = Vector3.new(numbers[1], numbers[2], numbers[3])
|
|
69
|
+
local halfSize = Vector3.new(numbers[4] / 2, numbers[5] / 2, numbers[6] / 2)
|
|
70
|
+
return Region3.new(position - halfSize, position + halfSize)
|
|
71
|
+
|
|
72
|
+
elseif typeString == "Region3int16" then
|
|
73
|
+
return Region3int16.new(
|
|
74
|
+
Vector3int16.new(numbers[1], numbers[2], numbers[3]),
|
|
75
|
+
Vector3int16.new(numbers[4], numbers[5], numbers[6])
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
elseif typeString == "UDim" then
|
|
79
|
+
return UDim.new(numbers[1], numbers[2])
|
|
80
|
+
|
|
81
|
+
elseif typeString == "UDim2" then
|
|
82
|
+
return UDim2.new(numbers[1], numbers[2], numbers[3], numbers[4])
|
|
83
|
+
|
|
84
|
+
elseif typeString == "Vector2" then
|
|
85
|
+
return Vector2.new(numbers[1], numbers[2])
|
|
86
|
+
|
|
87
|
+
elseif typeString == "Vector2int16" then
|
|
88
|
+
return Vector2int16.new(numbers[1], numbers[2])
|
|
89
|
+
|
|
90
|
+
elseif typeString == "Vector3" then
|
|
91
|
+
return Vector3.new(numbers[1], numbers[2], numbers[3])
|
|
92
|
+
|
|
93
|
+
elseif typeString == "Vector3int16" then
|
|
94
|
+
return Vector3int16.new(numbers[1], numbers[2], numbers[3])
|
|
95
|
+
else
|
|
96
|
+
return nil
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
return packType
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
Returns a 2x2 matrix of coefficients for a given time, damping and angular
|
|
8
|
+
frequency (aka 'speed').
|
|
9
|
+
|
|
10
|
+
Specifically, this returns four coefficients - posPos, posVel, velPos, and
|
|
11
|
+
velVel - which can be multiplied with position and velocity like so:
|
|
12
|
+
|
|
13
|
+
local newPosition = oldPosition * posPos + oldVelocity * posVel
|
|
14
|
+
local newVelocity = oldPosition * velPos + oldVelocity * velVel
|
|
15
|
+
|
|
16
|
+
For speed = 1 and damping = 0, the result is a simple harmonic oscillator
|
|
17
|
+
with a period of tau.
|
|
18
|
+
|
|
19
|
+
Special thanks to AxisAngle for helping to improve numerical precision.
|
|
20
|
+
]]
|
|
21
|
+
|
|
22
|
+
local function springCoefficients(
|
|
23
|
+
time: number,
|
|
24
|
+
damping: number,
|
|
25
|
+
speed: number
|
|
26
|
+
): (number, number, number, number)
|
|
27
|
+
-- if time or speed is 0, then the spring won't move
|
|
28
|
+
if time == 0 or speed == 0 then
|
|
29
|
+
return 1, 0, 0, 1
|
|
30
|
+
end
|
|
31
|
+
local posPos, posVel, velPos, velVel
|
|
32
|
+
|
|
33
|
+
if damping > 1 then
|
|
34
|
+
-- overdamped spring
|
|
35
|
+
|
|
36
|
+
local alpha = math.sqrt(damping^2 - 1)
|
|
37
|
+
local negHalf_over_alpha_speed = -0.5 / (alpha * speed)
|
|
38
|
+
local z1 = speed * (alpha + damping) * -1
|
|
39
|
+
local z2 = speed * (alpha - damping)
|
|
40
|
+
local exp1 = math.exp(time * z1)
|
|
41
|
+
local exp2 = math.exp(time * z2)
|
|
42
|
+
|
|
43
|
+
posPos = (exp2 * z1 - exp1 * z2) * negHalf_over_alpha_speed
|
|
44
|
+
posVel = (exp1 - exp2) * negHalf_over_alpha_speed / speed
|
|
45
|
+
velPos = (exp2 - exp1) * negHalf_over_alpha_speed * speed
|
|
46
|
+
velVel = (exp1 * z1 - exp2 * z2) * negHalf_over_alpha_speed
|
|
47
|
+
|
|
48
|
+
elseif damping == 1 then
|
|
49
|
+
-- critically damped spring
|
|
50
|
+
|
|
51
|
+
local time_speed = time * speed
|
|
52
|
+
local time_speed_neg1 = time_speed * -1
|
|
53
|
+
local exp = math.exp(time_speed_neg1)
|
|
54
|
+
|
|
55
|
+
posPos = exp * (time_speed + 1)
|
|
56
|
+
posVel = exp * time
|
|
57
|
+
velPos = exp * (time_speed_neg1 * speed)
|
|
58
|
+
velVel = exp * (time_speed_neg1 + 1)
|
|
59
|
+
else
|
|
60
|
+
-- underdamped spring
|
|
61
|
+
|
|
62
|
+
local alpha = speed * math.sqrt(1 - damping^2)
|
|
63
|
+
local overAlpha = 1 / alpha
|
|
64
|
+
local exp = math.exp(-1 * time * speed * damping)
|
|
65
|
+
local sin = math.sin(alpha * time)
|
|
66
|
+
local cos = math.cos(alpha * time)
|
|
67
|
+
local exp_sin = exp * sin
|
|
68
|
+
local exp_cos = exp * cos
|
|
69
|
+
local exp_sin_speed_damping_overAlpha = exp_sin * speed * damping * overAlpha
|
|
70
|
+
|
|
71
|
+
posPos = exp_sin_speed_damping_overAlpha + exp_cos
|
|
72
|
+
posVel = exp_sin * overAlpha
|
|
73
|
+
velPos = -1 * ( exp_sin * alpha + speed * damping * exp_sin_speed_damping_overAlpha )
|
|
74
|
+
velVel = exp_cos - exp_sin_speed_damping_overAlpha
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
return posPos, posVel, velPos, velVel
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
return springCoefficients
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
--!strict
|
|
2
|
+
--!nolint LocalUnused
|
|
3
|
+
--!nolint LocalShadow
|
|
4
|
+
local task = nil -- Disable usage of Roblox's task scheduler
|
|
5
|
+
|
|
6
|
+
--[[
|
|
7
|
+
Unpacks an animatable type into an array of numbers.
|
|
8
|
+
If the type is not animatable, an empty array will be returned.
|
|
9
|
+
]]
|
|
10
|
+
|
|
11
|
+
local Package = script.Parent.Parent
|
|
12
|
+
local Oklab = require(Package.Colour.Oklab)
|
|
13
|
+
|
|
14
|
+
local function unpackType(
|
|
15
|
+
value: unknown,
|
|
16
|
+
typeString: string
|
|
17
|
+
): {number}
|
|
18
|
+
if typeString == "number" then
|
|
19
|
+
local value = value :: number
|
|
20
|
+
return {value}
|
|
21
|
+
|
|
22
|
+
elseif typeString == "CFrame" then
|
|
23
|
+
local value = value :: CFrame
|
|
24
|
+
-- FUTURE: is there a better way of doing this? doing distance
|
|
25
|
+
-- calculations on `angle` may be incorrect
|
|
26
|
+
local axis, angle = value:ToAxisAngle()
|
|
27
|
+
return {value.X, value.Y, value.Z, axis.X, axis.Y, axis.Z, angle}
|
|
28
|
+
|
|
29
|
+
elseif typeString == "Color3" then
|
|
30
|
+
local value = value :: Color3
|
|
31
|
+
local lab = Oklab.fromSRGB(value)
|
|
32
|
+
return {lab.X, lab.Y, lab.Z}
|
|
33
|
+
|
|
34
|
+
elseif typeString == "ColorSequenceKeypoint" then
|
|
35
|
+
local value = value :: ColorSequenceKeypoint
|
|
36
|
+
local lab = Oklab.fromSRGB(value.Value)
|
|
37
|
+
return {lab.X, lab.Y, lab.Z, value.Time}
|
|
38
|
+
|
|
39
|
+
elseif typeString == "DateTime" then
|
|
40
|
+
local value = value :: DateTime
|
|
41
|
+
return {value.UnixTimestampMillis}
|
|
42
|
+
|
|
43
|
+
elseif typeString == "NumberRange" then
|
|
44
|
+
local value = value :: NumberRange
|
|
45
|
+
return {value.Min, value.Max}
|
|
46
|
+
|
|
47
|
+
elseif typeString == "NumberSequenceKeypoint" then
|
|
48
|
+
local value = value :: NumberSequenceKeypoint
|
|
49
|
+
return {value.Value, value.Time, value.Envelope}
|
|
50
|
+
|
|
51
|
+
elseif typeString == "PhysicalProperties" then
|
|
52
|
+
local value = value :: PhysicalProperties
|
|
53
|
+
return {value.Density, value.Friction, value.Elasticity, value.FrictionWeight, value.ElasticityWeight}
|
|
54
|
+
|
|
55
|
+
elseif typeString == "Ray" then
|
|
56
|
+
local value = value :: Ray
|
|
57
|
+
return {value.Origin.X, value.Origin.Y, value.Origin.Z, value.Direction.X, value.Direction.Y, value.Direction.Z}
|
|
58
|
+
|
|
59
|
+
elseif typeString == "Rect" then
|
|
60
|
+
local value = value :: Rect
|
|
61
|
+
return {value.Min.X, value.Min.Y, value.Max.X, value.Max.Y}
|
|
62
|
+
|
|
63
|
+
elseif typeString == "Region3" then
|
|
64
|
+
local value = value :: Region3
|
|
65
|
+
-- FUTURE: support rotated Region3s if/when they become constructable
|
|
66
|
+
return {
|
|
67
|
+
value.CFrame.X, value.CFrame.Y, value.CFrame.Z,
|
|
68
|
+
value.Size.X, value.Size.Y, value.Size.Z
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
elseif typeString == "Region3int16" then
|
|
72
|
+
local value = value :: Region3int16
|
|
73
|
+
return {value.Min.X, value.Min.Y, value.Min.Z, value.Max.X, value.Max.Y, value.Max.Z}
|
|
74
|
+
|
|
75
|
+
elseif typeString == "UDim" then
|
|
76
|
+
local value = value :: UDim
|
|
77
|
+
return {value.Scale, value.Offset}
|
|
78
|
+
|
|
79
|
+
elseif typeString == "UDim2" then
|
|
80
|
+
local value = value :: UDim2
|
|
81
|
+
return {value.X.Scale, value.X.Offset, value.Y.Scale, value.Y.Offset}
|
|
82
|
+
|
|
83
|
+
elseif typeString == "Vector2" then
|
|
84
|
+
local value = value :: Vector2
|
|
85
|
+
return {value.X, value.Y}
|
|
86
|
+
|
|
87
|
+
elseif typeString == "Vector2int16" then
|
|
88
|
+
local value = value :: Vector2int16
|
|
89
|
+
return {value.X, value.Y}
|
|
90
|
+
|
|
91
|
+
elseif typeString == "Vector3" then
|
|
92
|
+
local value = value :: Vector3
|
|
93
|
+
return {value.X, value.Y, value.Z}
|
|
94
|
+
|
|
95
|
+
elseif typeString == "Vector3int16" then
|
|
96
|
+
local value = value :: Vector3int16
|
|
97
|
+
return {value.X, value.Y, value.Z}
|
|
98
|
+
else
|
|
99
|
+
return {}
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
return unpackType
|