Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
129 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
78a9cd9
Add AGENTS.md
weenachuangkud May 11, 2026
174c3ee
Move src path
weenachuangkud May 12, 2026
e458c4e
Update wally.tom version
weenachuangkud May 12, 2026
adcdba1
fix: change date
weenachuangkud May 12, 2026
43f5fa0
remove: unnec comment
weenachuangkud May 12, 2026
697c32f
No need to use variable
weenachuangkud May 12, 2026
3009a15
Use legacy code
weenachuangkud May 12, 2026
26a522d
FastCastSerial doesn't use FastCastModule
weenachuangkud May 12, 2026
1b446c9
Change event handle to legacy style code
weenachuangkud May 12, 2026
0269fc2
Update sourcemap.json
weenachuangkud May 12, 2026
7f30f92
Use function instead of signal | function to reduce complexity
weenachuangkud May 12, 2026
5402f55
Update init.luau
weenachuangkud May 12, 2026
b48ee41
Fix type error
weenachuangkud May 12, 2026
13b069a
Add some note
weenachuangkud May 12, 2026
06b6a77
Reimplement in OOP
weenachuangkud May 12, 2026
055127c
fix: types error
weenachuangkud May 12, 2026
5767fa3
Use Movement mode for FastCastSerial
weenachuangkud May 12, 2026
1d1383a
Simplify to FastCast.newBehavior
weenachuangkud May 12, 2026
deca9d5
Update init.luau
weenachuangkud May 12, 2026
aebe66b
Update init.luau
weenachuangkud May 12, 2026
7489844
add BaseCast:SetMovementMode
weenachuangkud May 12, 2026
33e6f5b
Update ClientVM
weenachuangkud May 12, 2026
f521d56
Update VMs
weenachuangkud May 12, 2026
c05f279
Simplify Utility methods
weenachuangkud May 12, 2026
c713067
fix: FastCastM.TerminateCast
weenachuangkud May 12, 2026
1dcde6d
Remove unused if statement
weenachuangkud May 12, 2026
97a7a45
Remove DestroySignal from init.luau
weenachuangkud May 12, 2026
9322f94
Add src/*.legacy.luau to .gitignore
weenachuangkud May 12, 2026
5bb64f8
Remove: AutomaticPerformance
weenachuangkud May 12, 2026
f6befcb
Update ParallelSimulation
weenachuangkud May 12, 2026
284f8fc
Clean up ActiveCastSerial.luau
weenachuangkud May 13, 2026
4d3bec4
Replace legacy ActiveCast with new ActiveCast file
weenachuangkud May 13, 2026
0b591ea
Change .new to .createCastData
weenachuangkud May 13, 2026
5944fc0
Change BaseCast to BaseCastParallel name
weenachuangkud May 13, 2026
32c7e25
Update init.luau
weenachuangkud May 13, 2026
0c114f5
Add _parallel
weenachuangkud May 13, 2026
1f08cfb
Add CanPierce to FastCastEventsConfig
weenachuangkud May 13, 2026
c441a8b
feat: ObjectCache in each actors instead of 1 host
weenachuangkud May 13, 2026
a519c34
Update init.luau
weenachuangkud May 13, 2026
b76e840
Add TODO note
weenachuangkud May 13, 2026
4cc00fa
Update init.luau
weenachuangkud May 13, 2026
cf51c74
Update init.luau
weenachuangkud May 13, 2026
9741824
Update BaseCastParallel.luau
weenachuangkud May 13, 2026
529765b
Update BaseCastParallel.luau
weenachuangkud May 13, 2026
0383d10
Update BaseCastParallel.luau
weenachuangkud May 13, 2026
0b65c85
Update sourcemap.json
weenachuangkud May 13, 2026
80d5d02
Update BaseCastParallel.luau
weenachuangkud May 13, 2026
402018d
Add TODO
weenachuangkud May 13, 2026
3f09107
fix: incorect docs comment method
weenachuangkud May 13, 2026
6161e33
Use unused parameters
weenachuangkud May 13, 2026
3bd6812
Add some boilerplate
weenachuangkud May 13, 2026
f0edf11
Add some boilerplate
weenachuangkud May 13, 2026
191bdc3
Add some boilerplate
weenachuangkud May 13, 2026
ac8de31
Add some boilerplate
weenachuangkud May 13, 2026
1b48f86
Add some boilerplate
weenachuangkud May 13, 2026
1304d0d
Add some boilerplate
weenachuangkud May 13, 2026
6e647ff
Update ParallelSimulation
weenachuangkud May 13, 2026
6599544
Implement ParallelSimulation boilerplate and fix legacy bugs in BaseC…
weenachuangkud May 13, 2026
c348dab
Refactor QueueEvent to accept varargs and use castID instead of cast …
weenachuangkud May 13, 2026
534f79f
Refactor event handling and cosmetic movement to use ParallelSimulati…
weenachuangkud May 13, 2026
62c7a9d
Add casts_ID array for efficient iteration in UpdateCasts
weenachuangkud May 13, 2026
79a6b65
Update ParallelSimulation.luau to match legacy code
weenachuangkud May 13, 2026
22e7a83
Make BaseParallel shares self.Actives with ParallelSimulation
weenachuangkud May 13, 2026
0c4ea92
draft: FireQueuedEvents
weenachuangkud May 13, 2026
9bfce7a
Add luau language server and .aider to gitignore
weenachuangkud May 13, 2026
175939b
Add opencode.json
weenachuangkud May 13, 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
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@

# Moonwave related stuff
/node_modules
/package-lock.json
/package-lock.json

# FastCast2 related stuff
/src/*.legacy.luau
.aider*
44 changes: 44 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# AGENTS.md

## Project Overview

FastCast2 is a Roblox projectile library written in Luau, providing high-performance raycasting, blockcasting, and spherecasting with parallel scripting support. It is an unofficial continuation of the original FastCast library.

- **Language**: Luau (Roblox)
- **Build Tool**: Rojo (`rojo sync`, `rojo serve`)
- **Documentation**: Moonwave
- **Repository**: https://github.com/weenachuangkud/FastCast2

## Development Commands

- **Sync to Roblox**: `rojo sync -o <place-name>`
- **Serve live**: `rojo serve` (then connect via Studio → Plugins → Rojo)
- **Build docs**: `moonwave build`
- **Publish docs**: `moonwave build --publish`

## Project Structure

```
src/FastCast2/ # Main source code (synced to ReplicatedStorage)
.default.project.json # Rojo project configuration
```

## Testing

There are no automated tests in this project. Testing is done manually through Roblox Studio.

## Code Style

- Uses Luau static typing
- Follows standard Luau conventions (PascalCase for types, camelCase for variables)
- Modules are required via `require(path)`

## Important Notes

- Requires Roblox Studio to run/test code
- Parallel casting requires `VMsDispatcher` module
- Cosmetic bullets should have `CanTouch = false`, `CanCollide = false`, `CanQuery = false`

## Agent Skills
To understand specific project workflows, refer to the skills defined here:
- @skills/architecture.md
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