-
Notifications
You must be signed in to change notification settings - Fork 6
Introduce serial and parallel caster modes with SoA simulation architecture #39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
weenachuangkud
wants to merge
63
commits into
main
Choose a base branch
from
major
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
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 945b5f8
Remove FastCastParallel.new and add docs to FastCast.new/newParallel
weenachuangkud 14d9753
Update TODO.md
weenachuangkud 8c01cc5
feat: Add ActiveCastSerial for main thread simulation
weenachuangkud 3774b17
feat: Add BaseCastSerial for serial caster implementation
weenachuangkud 2acf367
feat: Add FastCastSerial methods and remove FastCastEventsModule from…
weenachuangkud 87158c9
feat: Add SerialSimulation with SoA pattern and single RunService
weenachuangkud 51a5f24
refactor: ActiveCastSerial uses SerialSimulation
weenachuangkud 4f6340b
revert: Remove conflicting SerialSimulation reference from ActiveCast
weenachuangkud 11c458c
refactor: Serial uses SoA pattern with SerialSimulation
weenachuangkud 13d8f71
refactor: Parallel mode uses SoA with ParallelSimulation
weenachuangkud 2f423e5
refactor: Remove UpdateConnection and metatable from ActiveCast
weenachuangkud 4d7b209
perf: Remove xpcall/pcall from hot path for performance
weenachuangkud 4b45156
Update TODO.md
weenachuangkud 0bb5986
refactor: Change Trajectories to Trajectory (single object, not array)
weenachuangkud 47d3c21
feat: Add Motor6D transform feature
weenachuangkud 28d3420
feat: Add Motor6D support to Parallel mode
weenachuangkud 55abdb0
fix: Add MovementMethod to ActiveCast for Parallel mode
weenachuangkud 3afbe66
docs: Update TODO.md with completed items
weenachuangkud 3ef6be3
fix: HighFidelityBehavior=2 bug - subRayDir used delta instead of tim…
weenachuangkud b465441
docs: update comments
weenachuangkud 59a1f99
docs: Update TODO.md with all completed items including bug fixes
weenachuangkud 5b751e7
docs: Add comprehensive API documentation following devforum structure
weenachuangkud 87692f1
release: bump version to 0.1.0 with Serial/Parallel modes, Motor6D, SoA
weenachuangkud 82519af
chore: remove version comments from source files
weenachuangkud 0e2fa47
docs: add Rojo installation guide to README
weenachuangkud 5b2dad1
fix: resolve CodeRabbit issues from PR #39
weenachuangkud e816b67
Add return statement to guarding
weenachuangkud b495224
Add return statement to guarding
weenachuangkud ad03254
docs: Changed FastCast/.git to .git
weenachuangkud 51225b1
docs: Change speed to SPEED
weenachuangkud 5fb543f
fix: use Copy instead of reference
weenachuangkud d4c9576
fix: use castData.RayParams
weenachuangkud b9eaf04
resolve coderabbit: Validate acceleration before it is read for kinem…
weenachuangkud 2d7b353
fix: make BaseCastSerial state instance-local to prevent cross-instan…
weenachuangkud ca39f6a
chore: remove unused constants from ActiveCastSerial.luau
weenachuangkud 9a834ae
fix: add missing FastCastEnums require in serial code example
weenachuangkud 7e684d2
fix: replace undefined latestTrajectory with trajectory in SimulateCast
weenachuangkud c0003b2
fix: correct Init params, remove self.self.* patterns, rename BindObj…
weenachuangkud 16fa2cc
fix: check ParallelSimulation.StepConnection instead of SerialSimulat…
weenachuangkud 58c9792
fix: forward BindableEvent to Signals, fix GetVelocityCast, rebase tr…
weenachuangkud cb68225
add: architecture.md
weenachuangkud 4b8c63f
Update architecture.md
weenachuangkud 1b6d8fa
Update architecture.md
weenachuangkud bd45c11
fix: implement HighFidelitySegmentSize and HighFidelityBehavior in So…
weenachuangkud 8bfdad3
feat: implement RayPierce/CanPierce in SoA simulations
weenachuangkud edde9f8
feat: add event config/module gating to SoA simulations
weenachuangkud ea27c67
fix: correct CastFire event signature to match legacy API
weenachuangkud bc53d7a
Comment out unused functions in ActiveCast.lua(legacy code)
weenachuangkud b6fbb3e
remove: spacing
weenachuangkud 60bca8c
feat: add debug logging to SoA simulations matching legacy ActiveCast
weenachuangkud ad907eb
Update typedef
weenachuangkud dbe98f7
Comment out unused function
weenachuangkud c1742b8
Comment out unused function
weenachuangkud d045c0c
feat: add cast visualization matching legacy ActiveCast
weenachuangkud 0df246c
Add .md files
weenachuangkud 029690e
fix: remove legacy code
weenachuangkud 5819065
resolve: coderabbit 106-109
weenachuangkud d1273a2
fix: remove legacy code
weenachuangkud 6bb678e
fix: unneeded local variable
weenachuangkud 458896d
fix: Add .Acceleration
weenachuangkud 4afb6e8
Update init.luau
weenachuangkud 2625a8c
Merge branch 'major' of https://github.com/weenachuangkud/FastCast2 i…
weenachuangkud File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | ||
|
|
||
| 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") | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.