@kunosyn/shatterbox 0.0.1
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/LICENSE +21 -0
- package/README.md +35 -0
- package/package.json +36 -0
- package/src/Effects.d.ts +134 -0
- package/src/Effects.luau +114 -0
- package/src/Settings.luau +75 -0
- package/src/index.d.ts +617 -0
- package/src/init.luau +2580 -0
- package/src/lib/Client.luau +4020 -0
- package/src/lib/InitializeShatterboxClients.client.luau +10 -0
- package/src/lib/ObjectCache.luau +198 -0
- package/src/lib/PartOperations.luau +673 -0
- package/src/lib/Server.luau +4425 -0
- package/src/lib/VertexMath.luau +403 -0
- package/src/types.ts +504 -0
- package/src/util/HitboxVisualizer.luau +101 -0
- package/src/util/TaggedArray.luau +66 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
--#selene: allow(unused_variable)
|
|
2
|
+
--#selene: allow(multiple_statements)
|
|
3
|
+
|
|
4
|
+
local RunService = game:GetService("RunService")
|
|
5
|
+
|
|
6
|
+
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
7
|
+
|
|
8
|
+
repeat RunService.Heartbeat:Wait() until ReplicatedStorage:FindFirstChild("BLINK_RELIABLE_REMOTE")
|
|
9
|
+
|
|
10
|
+
local Shatterbox = require(script.Parent.Parent:WaitForChild("Main"))
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
local RunService = game:GetService("RunService")
|
|
2
|
+
--!strict
|
|
3
|
+
--!native
|
|
4
|
+
local FAR_AWAY_CFRAME = CFrame.new(2^24, 2^24, 2^24)
|
|
5
|
+
local EXPAND_BY_AMOUNT = 50
|
|
6
|
+
|
|
7
|
+
local MovingParts = table.create(10_000)
|
|
8
|
+
local MovingCFrames = table.create(10_000)
|
|
9
|
+
|
|
10
|
+
local ScheduledUpdate = false
|
|
11
|
+
local function UpdateMovement()
|
|
12
|
+
while true do
|
|
13
|
+
workspace:BulkMoveTo(MovingParts, MovingCFrames, Enum.BulkMoveMode.FireCFrameChanged)
|
|
14
|
+
|
|
15
|
+
table.clear(MovingParts)
|
|
16
|
+
table.clear(MovingCFrames)
|
|
17
|
+
|
|
18
|
+
ScheduledUpdate = false
|
|
19
|
+
coroutine.yield()
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
local UpdateMovementThread = coroutine.create(UpdateMovement)
|
|
23
|
+
|
|
24
|
+
local Cache = {}
|
|
25
|
+
Cache.__index = Cache
|
|
26
|
+
|
|
27
|
+
function Cache:_GetNew(Amount: number, Warn: boolean)
|
|
28
|
+
if Warn then
|
|
29
|
+
warn(`ObjectCache: Cache retrieval exceeded preallocated amount! expanding by {Amount}...`)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
local FreeObjectsContainer = self._FreeObjects
|
|
33
|
+
local InitialLength = #self._FreeObjects
|
|
34
|
+
local CacheHolder = self.CacheHolder
|
|
35
|
+
|
|
36
|
+
local IsTemplateModel = self._IsTemplateModel
|
|
37
|
+
local Template: Model | BasePart = self._Template
|
|
38
|
+
|
|
39
|
+
local TargetParts = table.create(Amount)
|
|
40
|
+
local TargetCFrames = table.create(Amount)
|
|
41
|
+
local AddedObjects = table.create(Amount)
|
|
42
|
+
for Index = InitialLength + 1, InitialLength + Amount do
|
|
43
|
+
local Object = Template:Clone()
|
|
44
|
+
local ObjectRoot: BasePart = if IsTemplateModel then (Object:: Model).PrimaryPart:: BasePart else Object:: BasePart
|
|
45
|
+
|
|
46
|
+
FreeObjectsContainer[Index] = ObjectRoot
|
|
47
|
+
|
|
48
|
+
local OffsetIndex = Index - InitialLength
|
|
49
|
+
TargetParts[OffsetIndex] = ObjectRoot
|
|
50
|
+
TargetCFrames[OffsetIndex] = FAR_AWAY_CFRAME
|
|
51
|
+
AddedObjects[OffsetIndex] = Object
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
workspace:BulkMoveTo(TargetParts, TargetCFrames, Enum.BulkMoveMode.FireCFrameChanged)
|
|
55
|
+
|
|
56
|
+
for _, Object in AddedObjects do
|
|
57
|
+
(Object:: Instance).Parent = CacheHolder
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
return table.remove(FreeObjectsContainer)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
function Cache:GetPart(PartCFrame: CFrame?): BasePart
|
|
64
|
+
local Part = table.remove(self._FreeObjects) or self:_GetNew(self._ExpandAmount, true)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
for _, tag in ipairs(Part:GetTags()) do -- I added these two loops, not sure if it's the best placement
|
|
68
|
+
Part:RemoveTag(tag)
|
|
69
|
+
end
|
|
70
|
+
Part:AddTag("ObjectCache")
|
|
71
|
+
|
|
72
|
+
for att in pairs(Part:GetAttributes()) do
|
|
73
|
+
Part:SetAttribute(att)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
self._Objects[Part] = nil
|
|
78
|
+
if PartCFrame then
|
|
79
|
+
table.insert(MovingParts, Part)
|
|
80
|
+
table.insert(MovingCFrames, PartCFrame)
|
|
81
|
+
|
|
82
|
+
if not ScheduledUpdate then
|
|
83
|
+
ScheduledUpdate = true
|
|
84
|
+
task.defer(UpdateMovementThread)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
return Part
|
|
89
|
+
end
|
|
90
|
+
function Cache:ReturnPart(Part: BasePart)
|
|
91
|
+
if self._Objects[Part] then
|
|
92
|
+
return
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
Part:RemoveTag("ObjectCache")
|
|
96
|
+
|
|
97
|
+
Part.Parent = self.CacheHolder
|
|
98
|
+
Part.Anchored = true
|
|
99
|
+
|
|
100
|
+
self._Objects[Part] = true
|
|
101
|
+
|
|
102
|
+
table.insert(self._FreeObjects, Part)
|
|
103
|
+
table.insert(MovingParts, Part)
|
|
104
|
+
table.insert(MovingCFrames, FAR_AWAY_CFRAME)
|
|
105
|
+
|
|
106
|
+
if not ScheduledUpdate then
|
|
107
|
+
ScheduledUpdate = true
|
|
108
|
+
task.defer(UpdateMovementThread)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
function Cache:Update()
|
|
113
|
+
task.spawn(UpdateMovementThread)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
function Cache:ExpandCache(Amount: number)
|
|
117
|
+
assert(typeof(Amount) ~= "number" or Amount >= 0, `Invalid argument #1 to 'ObjectCache:ExpandCache' (positive number expected, got {typeof(Amount)})`)
|
|
118
|
+
self:_GetNew(Amount, false)
|
|
119
|
+
end
|
|
120
|
+
function Cache:SetExpandAmount(Amount: number)
|
|
121
|
+
assert(typeof(Amount) ~= "number" or Amount > 0, `Invalid argument #1 to 'ObjectCache:SetExpandAmount' (positive number expected, got {typeof(Amount)})`)
|
|
122
|
+
self._ExpandAmount = Amount
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
function Cache:IsInUse(Object: BasePart): boolean
|
|
126
|
+
return self._Objects[Object] == nil
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
function Cache:Destroy()
|
|
130
|
+
self.CacheHolder:Destroy()
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
local function GetCacheContainer()
|
|
134
|
+
local CacheHolder = Instance.new("Folder")
|
|
135
|
+
CacheHolder.Name = "ObjectCache"
|
|
136
|
+
|
|
137
|
+
return CacheHolder
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
local Constructor = {}
|
|
141
|
+
function Constructor.new(Template: BasePart | Model, CacheSize: number?, CachesContainer: Instance?)
|
|
142
|
+
local TemplateType = typeof(Template)
|
|
143
|
+
assert(TemplateType == "Instance", `Invalid argument #1 to 'ObjectCache.new' (BasePart expected, got {TemplateType})`)
|
|
144
|
+
|
|
145
|
+
assert(Template:IsA("BasePart") or Template:IsA("Model"), `Invalid argument #1 to 'ObjectCache.new' (BasePart or Model expected, got {Template.ClassName})`)
|
|
146
|
+
assert(Template.Archivable, `ObjectCache: Cannot use template object provided, as it has Archivable set to false.`)
|
|
147
|
+
if Template:IsA("Model") then
|
|
148
|
+
assert(Template.PrimaryPart ~= nil, `Invalid Template provided to 'ObjectCache.new': Model has no PrimaryPart set!`)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
local CacheSizeType = typeof(CacheSize)
|
|
152
|
+
assert(CacheSize == nil or CacheSizeType == "number", `Invalid argument #2 to 'ObjectCache.new' (number expected, got {CacheSizeType})`)
|
|
153
|
+
assert(CacheSize == nil or CacheSize >= 0, `Invalid argument #2 to 'ObjectCache.new' (positive number expected, got {CacheSize})`)
|
|
154
|
+
|
|
155
|
+
local ContainerType = typeof(CachesContainer)
|
|
156
|
+
assert(CachesContainer == nil or ContainerType == "Instance", `Invalid argument #3 to 'ObjectCache.new' (Instance expected, got {ContainerType})`)
|
|
157
|
+
|
|
158
|
+
local PreallocAmount = CacheSize or 10
|
|
159
|
+
local CacheParent = GetCacheContainer()
|
|
160
|
+
|
|
161
|
+
local Objects: {[BasePart]: boolean} = {}
|
|
162
|
+
local FreeObjects: {BasePart | Model} = table.create(PreallocAmount)
|
|
163
|
+
|
|
164
|
+
local TargetParts = table.create(PreallocAmount)
|
|
165
|
+
|
|
166
|
+
local IsTemplateModel = Template:IsA("Model")
|
|
167
|
+
task.spawn(function()
|
|
168
|
+
for Index = 1, PreallocAmount do
|
|
169
|
+
|
|
170
|
+
if Index % 100 == 0 then
|
|
171
|
+
RunService.Heartbeat:Wait()
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
local Object = Template:Clone()
|
|
175
|
+
local ObjectRoot: BasePart = if IsTemplateModel then (Object:: Model).PrimaryPart:: BasePart else Object:: BasePart
|
|
176
|
+
|
|
177
|
+
FreeObjects[Index] = Object
|
|
178
|
+
TargetParts[Index] = ObjectRoot
|
|
179
|
+
|
|
180
|
+
ObjectRoot.CFrame = FAR_AWAY_CFRAME;
|
|
181
|
+
(Object:: Instance).Parent = CacheParent
|
|
182
|
+
end
|
|
183
|
+
end)
|
|
184
|
+
|
|
185
|
+
CacheParent.Parent = CachesContainer or workspace
|
|
186
|
+
|
|
187
|
+
return setmetatable({
|
|
188
|
+
CacheHolder = CacheParent,
|
|
189
|
+
_ExpandAmount = EXPAND_BY_AMOUNT,
|
|
190
|
+
_Template = Template,
|
|
191
|
+
_FreeObjects = TargetParts,
|
|
192
|
+
_Objects = Objects,
|
|
193
|
+
_IsTemplateModel = IsTemplateModel,
|
|
194
|
+
_PreallocatedAmount = PreallocAmount,
|
|
195
|
+
}, Cache)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
return Constructor
|