Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
1d371ac
Add .newParallel and .new() feature
weenachuangkud May 7, 2026
945b5f8
Remove FastCastParallel.new and add docs to FastCast.new/newParallel
weenachuangkud May 7, 2026
14d9753
Update TODO.md
weenachuangkud May 7, 2026
8c01cc5
feat: Add ActiveCastSerial for main thread simulation
weenachuangkud May 7, 2026
3774b17
feat: Add BaseCastSerial for serial caster implementation
weenachuangkud May 7, 2026
2acf367
feat: Add FastCastSerial methods and remove FastCastEventsModule from…
weenachuangkud May 7, 2026
87158c9
feat: Add SerialSimulation with SoA pattern and single RunService
weenachuangkud May 7, 2026
51a5f24
refactor: ActiveCastSerial uses SerialSimulation
weenachuangkud May 7, 2026
4f6340b
revert: Remove conflicting SerialSimulation reference from ActiveCast
weenachuangkud May 7, 2026
11c458c
refactor: Serial uses SoA pattern with SerialSimulation
weenachuangkud May 7, 2026
13d8f71
refactor: Parallel mode uses SoA with ParallelSimulation
weenachuangkud May 7, 2026
2f423e5
refactor: Remove UpdateConnection and metatable from ActiveCast
weenachuangkud May 7, 2026
4d7b209
perf: Remove xpcall/pcall from hot path for performance
weenachuangkud May 7, 2026
4b45156
Update TODO.md
weenachuangkud May 7, 2026
0bb5986
refactor: Change Trajectories to Trajectory (single object, not array)
weenachuangkud May 7, 2026
47d3c21
feat: Add Motor6D transform feature
weenachuangkud May 7, 2026
28d3420
feat: Add Motor6D support to Parallel mode
weenachuangkud May 7, 2026
55abdb0
fix: Add MovementMethod to ActiveCast for Parallel mode
weenachuangkud May 7, 2026
3afbe66
docs: Update TODO.md with completed items
weenachuangkud May 7, 2026
3ef6be3
fix: HighFidelityBehavior=2 bug - subRayDir used delta instead of tim…
weenachuangkud May 7, 2026
b465441
docs: update comments
weenachuangkud May 7, 2026
59a1f99
docs: Update TODO.md with all completed items including bug fixes
weenachuangkud May 7, 2026
5b751e7
docs: Add comprehensive API documentation following devforum structure
weenachuangkud May 7, 2026
87692f1
release: bump version to 0.1.0 with Serial/Parallel modes, Motor6D, SoA
weenachuangkud May 7, 2026
82519af
chore: remove version comments from source files
weenachuangkud May 7, 2026
0e2fa47
docs: add Rojo installation guide to README
weenachuangkud May 8, 2026
5b2dad1
fix: resolve CodeRabbit issues from PR #39
weenachuangkud May 8, 2026
e816b67
Add return statement to guarding
weenachuangkud May 8, 2026
b495224
Add return statement to guarding
weenachuangkud May 8, 2026
ad03254
docs: Changed FastCast/.git to .git
weenachuangkud May 8, 2026
51225b1
docs: Change speed to SPEED
weenachuangkud May 8, 2026
5fb543f
fix: use Copy instead of reference
weenachuangkud May 8, 2026
d4c9576
fix: use castData.RayParams
weenachuangkud May 8, 2026
b9eaf04
resolve coderabbit: Validate acceleration before it is read for kinem…
weenachuangkud May 8, 2026
2d7b353
fix: make BaseCastSerial state instance-local to prevent cross-instan…
weenachuangkud May 8, 2026
ca39f6a
chore: remove unused constants from ActiveCastSerial.luau
weenachuangkud May 8, 2026
9a834ae
fix: add missing FastCastEnums require in serial code example
weenachuangkud May 8, 2026
7e684d2
fix: replace undefined latestTrajectory with trajectory in SimulateCast
weenachuangkud May 8, 2026
c0003b2
fix: correct Init params, remove self.self.* patterns, rename BindObj…
weenachuangkud May 8, 2026
16fa2cc
fix: check ParallelSimulation.StepConnection instead of SerialSimulat…
weenachuangkud May 8, 2026
58c9792
fix: forward BindableEvent to Signals, fix GetVelocityCast, rebase tr…
weenachuangkud May 8, 2026
cb68225
add: architecture.md
weenachuangkud May 8, 2026
4b8c63f
Update architecture.md
weenachuangkud May 8, 2026
1b6d8fa
Update architecture.md
weenachuangkud May 8, 2026
bd45c11
fix: implement HighFidelitySegmentSize and HighFidelityBehavior in So…
weenachuangkud May 8, 2026
8bfdad3
feat: implement RayPierce/CanPierce in SoA simulations
weenachuangkud May 8, 2026
edde9f8
feat: add event config/module gating to SoA simulations
weenachuangkud May 8, 2026
ea27c67
fix: correct CastFire event signature to match legacy API
weenachuangkud May 8, 2026
bc53d7a
Comment out unused functions in ActiveCast.lua(legacy code)
weenachuangkud May 8, 2026
b6fbb3e
remove: spacing
weenachuangkud May 8, 2026
60bca8c
feat: add debug logging to SoA simulations matching legacy ActiveCast
weenachuangkud May 8, 2026
ad907eb
Update typedef
weenachuangkud May 8, 2026
dbe98f7
Comment out unused function
weenachuangkud May 8, 2026
c1742b8
Comment out unused function
weenachuangkud May 8, 2026
d045c0c
feat: add cast visualization matching legacy ActiveCast
weenachuangkud May 8, 2026
0df246c
Add .md files
weenachuangkud May 11, 2026
029690e
fix: remove legacy code
weenachuangkud May 11, 2026
5819065
resolve: coderabbit 106-109
weenachuangkud May 11, 2026
d1273a2
fix: remove legacy code
weenachuangkud May 11, 2026
6bb678e
fix: unneeded local variable
weenachuangkud May 11, 2026
458896d
fix: Add .Acceleration
weenachuangkud May 11, 2026
4afb6e8
Update init.luau
weenachuangkud May 11, 2026
2625a8c
Merge branch 'major' of https://github.com/weenachuangkud/FastCast2 i…
weenachuangkud May 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions Benchmarks/benchParallel.client.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
-- Services
local RS = game:GetService("RunService")
local Rep = game:GetService("ReplicatedStorage")
local UIS = game:GetService("UserInputService")
local RepFirst = game:GetService("ReplicatedFirst")

-- Requires
local FastCast = require(Rep:WaitForChild("FastCast2"))

-- Variables
local ProjectileContainer = Instance.new("Folder")
ProjectileContainer.Name = "FastCast2PJ_Parallel"
ProjectileContainer.Parent = workspace
local ProjectileTemplate = Instance.new("Part")
ProjectileTemplate.Name = "Projectile"
ProjectileTemplate.Parent = Rep
ProjectileTemplate.Size = Vector3.new(1,1,1)
ProjectileTemplate.CanCollide = false
ProjectileTemplate.Anchored = true
ProjectileTemplate.CanQuery = false
ProjectileTemplate.CanTouch = false
ProjectileTemplate.Position = Vector3.new(1,1,1)
ProjectileTemplate.Massless = true

-- FPS tracking
local startTime = tick()
local updateRate = 0.5
local fpsTable = {}
local averageFps = 0
local maxFps = 0
local minFps = math.huge
local currentFps = 0

RS.Heartbeat:Connect(function(dt: number)
local fps = 1/dt
currentFps = fps
if fps > maxFps then
maxFps = fps
end
if fps < minFps then
minFps = fps
end
table.insert(fpsTable, fps)

if tick() >= startTime + updateRate then
local totalFps = 0
for _, vFps in fpsTable do
totalFps += vFps
end
averageFps = totalFps / #fpsTable
fpsTable = {}
startTime = tick()
end
end)

-- CastParams
local CastParams = RaycastParams.new()
CastParams.FilterDescendantsInstances = {}
CastParams.FilterType = Enum.RaycastFilterType.Exclude
CastParams.IgnoreWater = true

-- Behavior
local castBehavior = FastCast.newBehavior()
castBehavior.MaxDistance = 999999999
castBehavior.RaycastParams = CastParams
castBehavior.HighFidelityBehavior = 1
castBehavior.HighFidelitySegmentSize = 1
castBehavior.Acceleration = Vector3.new(0, 0, 0)
castBehavior.AutoIgnoreContainer = true
castBehavior.CosmeticBulletContainer = ProjectileContainer
castBehavior.CosmeticBulletTemplate = ProjectileTemplate

-- Parallel Caster
local Caster = FastCast.newParallel()
Caster:Init(
4, -- numWorkers
RepFirst, -- newParent
"CastVMs", -- newName
RepFirst, -- ContainerParent
"CastVMContainer", -- VMContainerName
"CastVM", -- VMname
true, -- useBulkMoveTo
nil, -- FastCastEventsModule (optional for parallel)
false, -- useObjectCache
nil, -- Template
500, -- CacheSize
workspace -- CacheHolder
)

local activeCasts = {}

Caster.CastFire:Connect(function(cast)
table.insert(activeCasts, cast)
end)

-- Functions
local function summary()
print(string.format("Delta: %.2f ms", 1000 / currentFps))
print(string.format("Average FPS: %.2f", averageFps))
print(string.format("Max FPS: %.2f", maxFps))
print(string.format("Min FPS: %.2f", minFps))
end

-- Benchmark
local isBenchmarking = false
local AMOUNT = 5000
local BENCH_TIME = 5

UIS.InputBegan:Connect(function(input, gp)
if gp then return end
if isBenchmarking then return end
if input.KeyCode == Enum.KeyCode.P then
isBenchmarking = true
print("=== PARALLEL MODE BENCHMARK ===")
print(string.format("Firing %d casts...", AMOUNT))

for i = 1, AMOUNT do
Caster:RaycastFire(
Vector3.new(
math.random(-1, 1) * 5000,
math.random(-1, 1) * 5000,
math.random(-1, 1) * 5000
),
Vector3.new(
math.random(-1, 1) * 5000,
math.random(-1, 1) * 5000,
math.random(-1, 1) * 5000
),
35,
castBehavior
)
end

print("=== CREATION COMPLETE ===")
summary()

task.wait(BENCH_TIME)

print("=== SIMULATION COMPLETE ===")
summary()

print("=== CLEANUP ===")
for i = #activeCasts, 1, -1 do
Caster:TerminateCast(activeCasts[i])
end
activeCasts = {}

print("=== DONE ===")
summary()
isBenchmarking = false
end
end)

print("Press P to start Parallel benchmark")
147 changes: 147 additions & 0 deletions Benchmarks/benchSerial.client.luau
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
-- Services
local RS = game:GetService("RunService")
local Rep = game:GetService("ReplicatedStorage")
local UIS = game:GetService("UserInputService")

-- Requires
local FastCast = require(Rep:WaitForChild("FastCast2"))

-- Variables
local ProjectileContainer = Instance.new("Folder")
ProjectileContainer.Name = "FastCast2PJ"
ProjectileContainer.Parent = workspace
local ProjectileTemplate = Instance.new("Part")
ProjectileTemplate.Name = "Projectile"
ProjectileTemplate.Parent = Rep
ProjectileTemplate.Size = Vector3.new(1,1,1)
ProjectileTemplate.CanCollide = false
ProjectileTemplate.Anchored = true
ProjectileTemplate.CanQuery = false
ProjectileTemplate.CanTouch = false
ProjectileTemplate.Position = Vector3.new(1,1,1)
ProjectileTemplate.Massless = true

-- FPS tracking
local startTime = tick()
local updateRate = 0.5
local fpsTable = {}
local averageFps = 0
local maxFps = 0
local minFps = math.huge
local currentFps = 0

RS.Heartbeat:Connect(function(dt: number)
local fps = 1/dt
currentFps = fps
if fps > maxFps then
maxFps = fps
end
if fps < minFps then
minFps = fps
end
table.insert(fpsTable, fps)

if tick() >= startTime + updateRate then
local totalFps = 0
for _, vFps in fpsTable do
totalFps += vFps
end
averageFps = totalFps / #fpsTable
fpsTable = {}
startTime = tick()
end
end)

-- CastParams
local CastParams = RaycastParams.new()
CastParams.FilterDescendantsInstances = {}
CastParams.FilterType = Enum.RaycastFilterType.Exclude
CastParams.IgnoreWater = true

-- Behavior
local castBehavior = FastCast.newBehavior()
castBehavior.MaxDistance = 999999999
castBehavior.RaycastParams = CastParams
castBehavior.HighFidelityBehavior = 1
castBehavior.HighFidelitySegmentSize = 1
castBehavior.Acceleration = Vector3.new(0, 0, 0)
castBehavior.AutoIgnoreContainer = true
castBehavior.CosmeticBulletContainer = ProjectileContainer
castBehavior.CosmeticBulletTemplate = ProjectileTemplate

-- Serial Caster
local Caster = FastCast.new()
Caster:Init(
true, -- useBulkMoveTo
false -- useObjectCache
)

local activeCasts = {}

Caster.CastFire:Connect(function(cast)
table.insert(activeCasts, cast)
end)

-- Functions
local function summary()
print(string.format("Delta: %.2f ms", 1000 / currentFps))
print(string.format("Average FPS: %.2f", averageFps))
print(string.format("Max FPS: %.2f", maxFps))
print(string.format("Min FPS: %.2f", minFps))
end

-- Benchmark
local isBenchmarking = false
local AMOUNT = 5000
local BENCH_TIME = 5

UIS.InputBegan:Connect(function(input, gp)
if gp then return end
if isBenchmarking then return end
if input.KeyCode == Enum.KeyCode.E then
isBenchmarking = true
print("=== SERIAL MODE BENCHMARK ===")
print(string.format("Firing %d casts...", AMOUNT))

for i = 1, AMOUNT do
local direction = Vector3.new(
math.random() * 2 - 1,
math.random() * 2 - 1,
math.random() * 2 - 1
)
if direction.Magnitude == 0 then
direction = Vector3.new(0, 0, 1)
end
Caster:RaycastFire(
Vector3.new(
math.random() * 2 - 1,
math.random() * 2 - 1,
math.random() * 2 - 1
) * 5000,
direction,
35,
castBehavior
)
end
Comment thread
weenachuangkud marked this conversation as resolved.

print("=== CREATION COMPLETE ===")
summary()

task.wait(BENCH_TIME)

print("=== SIMULATION COMPLETE ===")
summary()

print("=== CLEANUP ===")
for i = #activeCasts, 1, -1 do
Caster:TerminateCast(activeCasts[i])
end
activeCasts = {}

print("=== DONE ===")
summary()
isBenchmarking = false
end
end)

print("Press E to start benchmark")
Loading