### Server and Client Setup for VetraNet Source: https://context7.com/vel136/vetra/llms.txt This code demonstrates the required setup for both the server and client to use VetraNet. Ensure SharedBehaviors.lua is required by both. The server setup includes network configuration and event handling for validated hits and rejected fires. The client setup initializes the network and demonstrates firing a projectile. ```lua -- SharedBehaviors.lua (required by BOTH server and client) local Vetra = require(ReplicatedStorage.Vetra) local BehaviorBuilder = Vetra.BehaviorBuilder local Registry = Vetra.VetraNet.BehaviorRegistry.new() Registry:Register("Rifle", BehaviorBuilder.Sniper():Build()) Registry:Register("Shotgun", BehaviorBuilder.Pistol():Bounce():Max(0):Done():Build()) Registry:Register("Grenade", BehaviorBuilder.Grenade():Build()) return Registry -- SERVER SETUP local SharedRegistry = require(ReplicatedStorage.SharedBehaviors) local Net = Vetra.VetraNet.new(ServerSolver, SharedRegistry, { MaxOriginTolerance = 20, MaxConcurrentPerPlayer = 20, TokensPerSecond = 10, BurstLimit = 20, ReplicateState = true, Mode = Vetra.Enums.NetworkMode.ClientAuthoritative, }) Net.OnValidatedHit:Connect(function(owner, context, result, velocity, impactForce) -- Safe to apply damage, update leaderboard, etc. local damage = context.UserData.Damage ApplyDamage(result.Instance, damage, owner) end) Net.OnFireRejected:Connect(function(player, reason) warn(player.Name .. " fire rejected: " .. reason) -- Reasons: RejectedRateLimit, RejectedConcurrentLimit, RejectedUnknownBehavior, -- RejectedOriginTolerance, RejectedInvalidSpeed, RejectedNoSession end) -- CLIENT SETUP local SharedRegistry = require(ReplicatedStorage.SharedBehaviors) local Net = Vetra.VetraNet.new(ClientSolver, SharedRegistry) -- Fire over network local context = BulletContext.new({ Origin = tool.Handle.Position, Direction = direction.Unit, Speed = 900, }) Net:Fire(context, "Rifle") -- Behavior name, not hash ``` -------------------------------- ### Basic Vetra Bullet Simulation Setup Source: https://github.com/vel136/vetra/blob/master/readme.md Demonstrates the basic setup for firing a projectile using Vetra. It involves initializing the solver, connecting to hit signals, defining bullet behavior, and creating a bullet context before firing. ```lua local Vetra = require(ReplicatedStorage.Vetra) local BulletContext = Vetra.BulletContext local Solver = Vetra.new() local Signals = Solver:GetSignals() Signals.OnHit:Connect(function(context, result, velocity) if result then print("Hit", result.Instance.Name) end end) local Behavior = Vetra.BehaviorBuilder.Sniper():Build() local context = BulletContext.new({ Origin = muzzlePosition, Direction = direction, Speed = 900, }) Solver:Fire(context, Behavior) ``` -------------------------------- ### Live Benchmarking Output Example Source: https://github.com/vel136/vetra/blob/master/docs/guides/benchmarks.md This is an example of the live output displayed as each cell completes during benchmarking. Pay attention to the standard deviation (σ) column for performance consistency. ```text serial | Travel-only | 500 bullets | avg 25.885 ms min 23.099 max 41.11 σ 2.614 | 19316 cast-steps/s parallel | Travel-only | 500 bullets | avg 4.159 ms min 2.19 max 5.828 σ 0.765 | 120215 cast-steps/s → parallel/serial ratio: 0.161x [PARALLEL FASTER] ``` -------------------------------- ### Complete Rifle Behavior Example Source: https://context7.com/vel136/vetra/llms.txt This example demonstrates how to configure a realistic rifle behavior using Vetra's BehaviorBuilder API, including physics, drag, piercing, Magnus effect, speed profiles, and cosmetic settings. It also shows how to connect signals for hit and pierce events and implement a fire function. ```lua local Vetra = require(ReplicatedStorage.Vetra) local BehaviorBuilder = Vetra.BehaviorBuilder local BulletContext = Vetra.BulletContext -- Create solver local Solver = Vetra.new() local Signals = Solver:GetSignals() -- Build realistic rifle behavior local RifleBehavior = BehaviorBuilder.new() :Physics() :MaxDistance(1200) :MinSpeed(30) :BulletMass(0.008) :Done() :Drag() :Coefficient(0.003) :Model(BehaviorBuilder.DragModel.G7) :SegmentInterval(0.05) :Done() :Pierce() :Max(2) :SpeedRetention(0.85) :SpeedThreshold(200) :Filter(function(ctx, result, vel) return result.Instance:HasTag("Pierceable") end) :Done() :Magnus() :SpinVector(Vector3.new(0, 0, 300)) :Coefficient(0.00005) :Done() :SpeedProfiles() :Thresholds({ 343 }) :Subsonic() :DragCoefficient(0.004) :Done() :Done() :Cosmetic() :Template(workspace.BulletTemplate) :Done() :Build() -- Connect signals Signals.OnHit:Connect(function(context, result, velocity) if result then local damage = context.UserData.Damage * (velocity.Magnitude / context.Speed) DealDamage(result.Instance, damage) end end) Signals.OnPierce:Connect(function(context, result, velocity, pierceCount) SpawnPierceEffect(result.Position, result.Normal) end) -- Fire function local function Fire(muzzle, direction) local context = BulletContext.new({ Origin = muzzle.Position, Direction = direction, Speed = 900, }) context.UserData.Damage = 45 context.UserData.Shooter = Players.LocalPlayer Solver:Fire(context, RifleBehavior) end ``` -------------------------------- ### Server Setup and Configuration Source: https://github.com/vel136/vetra/blob/master/docs/guides/networking.md Configures the VetraNet server with various parameters for fire request validation and replication. Connects to event handlers for validated hits and rejected fires. ```lua -- Server setup local Net = Vetra.VetraNet.new(ServerSolver, SharedRegistry, { MaxOriginTolerance = 20, -- studs; wider = more lag tolerance, less precise exploit detection TokensPerSecond = 10, -- fire rate limit (refill rate) BurstLimit = 20, -- max burst before throttling kicks in MaxConcurrentPerPlayer = 15, -- max in-flight bullets per player ReplicateState = true, -- broadcast state to clients each Heartbeat DriftThreshold = 2, -- studs before cosmetic correction begins CorrectionRate = 8, -- studs/s lerp rate for correction }) Net.OnValidatedHit:Connect(function(player, context, result, velocity, impactForce) if result then local damage = context.UserData.Damage or 0 -- apply damage to result.Instance here end end) Net.OnFireRejected:Connect(function(player, reason) -- log this for telemetry; multiple RejectedRateLimit events from the same player -- might warrant investigation warn(player.Name, "fire rejected:", reason) end) ``` -------------------------------- ### Register VetraNet Behaviors Source: https://github.com/vel136/vetra/blob/master/docs/documentation.md Shared setup for VetraNet. Both server and client must register behaviors in the same order with the same names using a shared ModuleScript to avoid rejections. ```lua local Registry = Vetra.VetraNet.BehaviorRegistry.new() Registry:Register("Rifle", RifleBehavior) Registry:Register("Shotgun", ShotgunBehavior) return Registry ``` -------------------------------- ### Configure Vetra Solver Tolerances Source: https://github.com/vel136/vetra/blob/master/docs/guides/networking.md Use `Vetra.WithValidator` to set tolerances for fire origin, hit position, velocity, and timestamp. Start with generous values and adjust based on telemetry to reduce false rejections. ```lua local Solver = Vetra.WithValidator(Vetra.new(), { MaxOriginTolerance = 20, -- fire origin PositionTolerance = 15, -- hit position VelocityTolerance = 80, -- velocity at hit time (studs/s) TimeTolerance = 0.15 -- timestamp (seconds) }) ``` -------------------------------- ### Clone and Modify Sniper Behavior for Variants Source: https://context7.com/vel136/vetra/llms.txt Create variants of existing behaviors by cloning and applying specific modifications. This example clones the Sniper behavior to add enhanced piercing capabilities and adjust speed retention. ```lua local APVariant = BehaviorBuilder.Sniper():Clone() :Pierce():Max(5):SpeedRetention(0.95):Done() :Build() ``` -------------------------------- ### Server-Side Hit Validation with Vetra.WithValidator Source: https://github.com/vel136/vetra/blob/master/docs/documentation.md Wrap a solver with `WithValidator` to enable authoritative hit checks on the server. This is useful for preventing client-side exploits. The setup code is safe to include on the client. ```lua -- Server only; safe no-op on the client so setup code can be shared local Solver = Vetra.WithValidator(Vetra.new(), { MaxOriginTolerance = 20, PositionTolerance = 15, VelocityTolerance = 80, TimeTolerance = 0.15, }) ``` -------------------------------- ### Configure Server-Side Hit Validation Source: https://context7.com/vel136/vetra/llms.txt Attach a HitValidator for authoritative hit checks on the server. Use `Vetra.WithValidator` to set tolerances for origin, position, velocity, and time. This setup is a safe no-op on the client. ```lua -- Server-side validation setup local Solver = Vetra.WithValidator(Vetra.new(), { MaxOriginTolerance = 20, -- Max studs from reconstructed origin PositionTolerance = 15, -- Max studs from reconstructed hit position VelocityTolerance = 80, -- Max studs/s velocity error TimeTolerance = 0.15, -- Max seconds timing error }) -- WithValidator is a safe no-op on client, so setup code can be shared -- Invalid hits are silently rejected and logged ``` -------------------------------- ### Attach UserData to Bullet Context Source: https://github.com/vel136/vetra/blob/master/docs/documentation.md This example demonstrates how to attach custom data (UserData) to a bullet's context, making it available in signal handlers. This is useful for passing weapon-specific information like damage or shooter ID. ```lua context.UserData.Damage = 75 context.UserData.ShooterId = Players.LocalPlayer.UserId Signals.OnHit:Connect(function(context, result, velocity) print("Damage:", context.UserData.Damage) print("Fired by:", context.UserData.ShooterId) end) ``` -------------------------------- ### Custom CastFunction with Blockcast Source: https://github.com/vel136/vetra/blob/master/docs/documentation.md Utilize `workspace:Blockcast` for wide projectiles like shotgun pellets. The example demonstrates offsetting the box center to ensure the front face is flush with the origin, preventing initial overlaps from being missed. ```lua -- Blockcast, useful for shotgun pellets or wide projectiles -- Box center is offset back so the front face is flush with origin. -- If the center were at origin, the front face would start direction.Magnitude/2 -- ahead of the bullet — any wall closer than that would be inside the starting -- shape and silently skipped by Roblox's overlap rule. Solver:Fire(context, { CastFunction = function(origin, direction, params) local BoxZ = 0.01 local dirUnit = direction.Unit local center = origin - dirUnit * (BoxZ / 2) local size = Vector3.new(0.2, 0.2, BoxZ) local cframe = CFrame.lookAt(center, center + direction) return workspace:Blockcast(cframe, size, direction, params) end, }) ``` -------------------------------- ### Initialize Vetra Solver and Connect Signals Source: https://github.com/vel136/vetra/blob/master/docs/documentation.md This snippet shows how to initialize the Vetra solver and connect to its OnHit and OnBounce signals. Connect to signals once during initialization. ```lua local Vetra = require(ReplicatedStorage.Vetra) local BulletContext = Vetra.BulletContext -- Create the solver once (connects the frame loop) local Solver = Vetra.new() local Signals = Solver:GetSignals() -- Connect to signals once at initialisation Signals.OnHit:Connect(function(context, result, velocity) if result then print("Hit", result.Instance.Name, "at", result.Position) else -- result is nil on distance/speed expiry print("Bullet expired") end end) Signals.OnBounce:Connect(function(context, result, velocity, bounceCount) print("Bounce #" .. bounceCount) end) ``` -------------------------------- ### Initialize Vetra Parallel Solver Source: https://github.com/vel136/vetra/blob/master/docs/guides/performance.md Instantiate the parallel solver, tuning ShardCount to match your server's core count. The API is identical to Vetra.new(). ```lua local Solver = Vetra.newParallel({ ShardCount = 6, -- tune to your server's core count; 4–8 is typical }) -- The API is identical to Vetra.new(), no code changes needed Solver:Fire(context, Behavior) ``` -------------------------------- ### Require Vetra Module in Roblox Source: https://github.com/vel136/vetra/blob/master/readme.md This snippet shows how to require the Vetra module from ReplicatedStorage in your Roblox scripts after installation. ```lua local Vetra = require(game.ReplicatedStorage.Vetra) ``` -------------------------------- ### Initialize Solver with Spatial Partitioning Source: https://github.com/vel136/vetra/blob/master/docs/guides/performance.md Initialize the Vetra solver with spatial partitioning settings. This includes defining radii for HOT, WARM, and COLD tiers, a fallback tier, and the interval for rebuilding the partition. ```lua local Solver = Vetra.new({ SpatialPartition = { HotRadius = 150, -- full simulation within 150 studs of a player WarmRadius = 400, -- reduced simulation within 400 studs FallbackTier = "COLD", -- everything beyond 400 studs gets COLD UpdateInterval = 3, -- rebuild every 3 frames } }) ``` -------------------------------- ### Set Pitch Damping for Stability Source: https://github.com/vel136/vetra/blob/master/docs/faq.md Add pitch damping to prevent the bullet from tumbling. A value of 0.02 is a safe starting point. Adjust MomentOfInertia for wobble response. ```lua PitchDampingCoeff = 0.02 ``` -------------------------------- ### Initialize VetraNet in ClientAuthoritative Mode Source: https://github.com/vel136/vetra/blob/master/docs/guides/networking.md Initialize VetraNet with `Vetra.VetraNet.new`. ClientAuthoritative is the default mode, where clients send fire requests that the server validates. ```lua local Net = Vetra.VetraNet.new(ServerSolver, SharedRegistry, { -- Mode defaults to ClientAuthoritative; no need to set it explicitly }) ``` -------------------------------- ### Initialize VetraNet Server Source: https://github.com/vel136/vetra/blob/master/docs/documentation.md Server-side initialization of VetraNet. Configure network parameters like MaxOriginTolerance and TokensPerSecond. Handles validated hits and rejected fires. ```lua local Net = Vetra.VetraNet.new(ServerSolver, SharedRegistry, { MaxOriginTolerance = 20, TokensPerSecond = 10, BurstLimit = 20, ReplicateState = true, }) Net.OnValidatedHit:Connect(function(owner, context, result, velocity, impactForce) -- apply damage, update leaderboard, etc. end) Net.OnFireRejected:Connect(function(player, reason) warn(player.Name .. " fire rejected: " .. reason) end) ``` -------------------------------- ### Use Custom Cast Functions for Wide Projectiles Source: https://context7.com/vel136/vetra/llms.txt Replace the default workspace:Raycast with custom functions like Spherecast for wide projectiles. This example demonstrates setting up a Spherecast behavior. ```lua -- Spherecast for wide projectiles local SphereBehavior = { MaxDistance = 500, CastFunction = function(origin, direction, params) return workspace:Spherecast(origin, 0.5, direction, params) end } -- Blockcast for shotgun pellets local BlockBehavior = { MaxDistance = 200, CastFunction = function(origin, direction, params) local BoxZ = 0.01 local dirUnit = direction.Unit local center = origin - dirUnit * (BoxZ / 2) -- Offset back to avoid overlap local size = Vector3.new(0.2, 0.2, BoxZ) local cframe = CFrame.lookAt(center, center + direction) return workspace:Blockcast(cframe, size, direction, params) end } -- Custom filter wrapper local FilteredBehavior = { MaxDistance = 500, CastFunction = function(origin, direction, params) local result = workspace:Raycast(origin, direction, params) if result and result.Instance:HasTag("Ignored") then return nil end return result end } -- Note: CastFunction only works with serial solver (Vetra.new) Solver:Fire(context, SphereBehavior) ``` -------------------------------- ### Configure Vetra Benchmark Defaults Source: https://github.com/vel136/vetra/blob/master/docs/guides/benchmarks.md Customize benchmark parameters like bullet counts, sample frames, and parallel solver settings using a configuration table. ```lua local Bench = VetraBenchmark.new({ BulletCounts = { 10, 50, 100, 500, 1000 }, -- which counts to test SampleFrames = 120, -- Heartbeat frames sampled per cell WarmupFrames = 30, -- frames to discard before sampling ShardCount = 8, -- Actor shards for the parallel solver ParallelOnlyThreshold = 500, -- skip serial above this count Origin = Vector3.new(0, 50, 0), -- fire origin SpreadDeg = 25, -- cone spread in degrees }) ``` -------------------------------- ### Custom Gravity for Vetra Behaviors Source: https://github.com/vel136/vetra/blob/master/docs/guides/physics-features.md Override the default gravity setting in Vetra behaviors to simulate environments like zero-gravity maps or underwater areas. This example sets a custom downward acceleration. ```lua local Behavior = Vetra.BehaviorBuilder.new() :Physics() :Gravity(Vector3.new(0, -5, 0)) -- 5 studs/s² downward, floaty, underwater feel :Done() :Build() ``` -------------------------------- ### Registering and Looking Up Behaviors with BehaviorRegistry Source: https://context7.com/vel136/vetra/llms.txt This snippet shows how to use BehaviorRegistry to map string names to behaviors, which are then converted to efficient hash-based lookups. It covers registration, lookup by hash (server-side), and lookup by name (client-side). Crucially, both server and client must register behaviors in the same order with identical names. ```lua local Registry = Vetra.VetraNet.BehaviorRegistry.new() -- Register behaviors (returns u16 hash) local rifleHash = Registry:Register("Rifle", RifleBehavior) local shotgunHash = Registry:Register("Shotgun", ShotgunBehavior) -- Lookup by hash (server uses this) local behavior = Registry:Get(rifleHash) -- Lookup hash by name (client uses this) local hash = Registry:GetHash("Rifle") -- Clean up Registry:Destroy() -- IMPORTANT: Server and client MUST register in the same order with same names! ``` -------------------------------- ### Initialize VetraNet in ServerAuthority Mode Source: https://github.com/vel136/vetra/blob/master/docs/guides/networking.md Configure VetraNet for ServerAuthority mode to ensure only the server can initiate bullets. Client fire requests are ignored in this mode, making it suitable for NPC projectiles or environmental hazards. ```lua local Net = Vetra.VetraNet.new(ServerSolver, SharedRegistry, { Mode = Vetra.Enums.NetworkMode.ServerAuthority, }) ``` -------------------------------- ### Create a Serial Vetra Solver Source: https://context7.com/vel136/vetra/llms.txt Instantiates a serial solver for managing projectiles. Connects to Heartbeat on the server and RenderStepped on the client. Handles hit and bounce events via signals. ```lua local Vetra = require(ReplicatedStorage.Vetra) local BulletContext = Vetra.BulletContext -- Create a serial solver (connects to Heartbeat on server, RenderStepped on client) local Solver = Vetra.new() -- Get signals for handling events local Signals = Solver:GetSignals() -- Connect to hit events Signals.OnHit:Connect(function(context, result, velocity) if result then print("Hit", result.Instance.Name, "at", result.Position) else print("Bullet expired (no surface impact)") end end) Signals.OnBounce:Connect(function(context, result, velocity, bounceCount) print("Bounce #" .. bounceCount .. " at " .. tostring(result.Position)) end) ``` -------------------------------- ### Initialize VetraNet in SharedAuthority Mode Source: https://github.com/vel136/vetra/blob/master/docs/guides/networking.md Set VetraNet to SharedAuthority mode to allow both clients and servers to initiate bullets. Client requests undergo full validation, while server calls bypass it. ```lua local Net = Vetra.VetraNet.new(ServerSolver, SharedRegistry, { Mode = Vetra.Enums.NetworkMode.SharedAuthority, }) ``` -------------------------------- ### Implement Magnus Effect for Bullet Curve Source: https://github.com/vel136/vetra/blob/master/docs/guides/physics-features.md Configure the Magnus effect to simulate the curving of a spinning bullet. Start with a very small `MagnusCoefficient` (e.g., 0.00005) and increase incrementally, as this value is highly sensitive and can lead to unrealistic "homing missile" behavior if set too high. ```lua local Behavior = BehaviorBuilder.new() :Magnus() :SpinVector(Vector3.new(0, 0, 1) * 300) -- rightward spin, 300 rad/s :Coefficient(0.0001) :SpinDecayRate(0.05) -- spin decays 5% per second as air slows it :Done() :Build() ``` -------------------------------- ### Quick Sanity Check Benchmark Source: https://github.com/vel136/vetra/blob/master/docs/guides/benchmarks.md Perform a quick benchmark run with a limited set of bullet counts and disable the serial solver skip. ```lua local Bench = VetraBenchmark.new({ BulletCounts = { 50, 200, 500 }, SampleFrames = 60, ParallelOnlyThreshold = 9999, -- never skip serial }) Bench:Run() ``` -------------------------------- ### Build Sniper, Grenade, and Pistol Behaviors Source: https://context7.com/vel136/vetra/llms.txt Use preset behaviors for common weapon archetypes. These presets can be directly built or further customized. ```lua local SniperBehavior = BehaviorBuilder.Sniper():Build() local GrenadeBehavior = BehaviorBuilder.Grenade():Build() local PistolBehavior = BehaviorBuilder.Pistol():Build() ``` -------------------------------- ### Enable Vetra Visualizer Source: https://github.com/vel136/vetra/blob/master/docs/faq.md Enable the visualizer to see cast segments, hit normals, bounce vectors, and corner-trap markers in the world. This has zero runtime cost when disabled. ```lua local Behavior = Vetra.BehaviorBuilder.new() :Debug() :Visualize(true) :Done() :Build() ``` -------------------------------- ### Run Vetra Benchmark Source: https://github.com/vel136/vetra/blob/master/docs/guides/benchmarks.md Require the VetraBenchmark ModuleScript and run the benchmark in a task.spawn. Ensure VetraReference ObjectValue points to the Vetra ModuleScript. ```lua local VetraBenchmark = require(script.Parent.VetraBenchmark) task.spawn(function() local Bench = VetraBenchmark.new() Bench:Run() end) ``` -------------------------------- ### Client Fire Initiation Source: https://github.com/vel136/vetra/blob/master/docs/guides/networking.md Initiates a fire request from the client using VetraNet. Requires the tool's position, direction, projectile speed, and behavior name. ```lua -- Client setup (same SharedRegistry required) local Net = Vetra.VetraNet.new(ClientSolver, SharedRegistry) -- In your tool's activation code: Net:Fire( tool.Handle.CFrame.Position, (mouseHitPosition - tool.Handle.CFrame.Position).Unit, RifleBehavior.MaxSpeed, "Rifle" ) ``` -------------------------------- ### Create a Parallel Vetra Solver Source: https://context7.com/vel136/vetra/llms.txt Instantiates a parallel solver for high bullet-count scenarios, distributing physics across multiple Roblox Actors. API is identical to the serial solver. ```lua -- Parallel solver for high-performance scenarios (50+ bullets) local Solver = Vetra.newParallel({ ShardCount = 6, -- Number of Actor shards (tune to server core count) SpatialPartition = { HotRadius = 150, WarmRadius = 400, FallbackTier = "COLD" } }) -- API is identical to serial solver Signals.OnHit:Connect(function(context, result, velocity) -- Handle hit end) -- Performance: ~flat 4-10ms up to 20,000 bullets -- Note: CastFunction overrides are ignored in parallel mode ``` -------------------------------- ### Configure Supersonic and Subsonic Profiles Source: https://github.com/vel136/vetra/blob/master/docs/documentation.md Override drag, restitution, and normal perturbation based on speed regimes. The solver blends profiles based on SpeedThresholds. ```lua Solver:Fire(context, { DragCoefficient = 0.002, DragModel = "G7", SupersonicProfile = { DragCoefficient = 0.0015, }, SubsonicProfile = { DragCoefficient = 0.004, Restitution = 0.5, NormalPerturbation = 0.05, }, SpeedThresholds = { 343 }, -- fire OnSpeedThresholdCrossed when crossing this }) ``` ```lua Signals.OnSpeedThresholdCrossed:Connect(function(context, threshold, velocity) if threshold == 343 then print("Went subsonic") end end) ``` -------------------------------- ### Apply Conditional Configuration with :When() Source: https://github.com/vel136/vetra/blob/master/docs/faq.md Use the :When(condition, fn) method to apply configuration changes conditionally within a fluent builder chain. The callback function receives the builder instance if the condition is truthy. ```lua local Behavior = BehaviorBuilder.Sniper() :When(isRaining, function(b) b:Wind():Response(1.5):Done() end) :When(isHeavyAmmo, function(b) b:Pierce():Max(5):Done() end) :When(isDebug, function(b) b:Debug():Visualize(true):Done() end) :Build() ``` -------------------------------- ### Build Projectile Behaviors with BehaviorBuilder Source: https://context7.com/vel136/vetra/llms.txt Configures projectile physics using a fluent API provided by BehaviorBuilder. Allows detailed customization of physics, bounce, pierce, and drag properties with build-time validation. ```lua local BehaviorBuilder = Vetra.BehaviorBuilder -- Build custom behavior with fluent API local Behavior = BehaviorBuilder.new() :Physics() :MaxDistance(800) :MinSpeed(5) :Gravity(Vector3.new(0, -workspace.Gravity, 0)) :Done() :Bounce() :Max(3) :Restitution(0.7) :Filter(function(context, result, vel) return result.Instance:HasTag("Bouncy") end) :Done() :Pierce() :Max(2) :SpeedRetention(0.85) :Filter(function(context, result, vel) return result.Instance:HasTag("Pierceable") end) :Done() :Drag() :Coefficient(0.003) :Model(BehaviorBuilder.DragModel.G7) -- Long boat-tail, sniper standard :SegmentInterval(0.05) :Done() :Build() -- Fire with the behavior Solver:Fire(context, Behavior) ``` -------------------------------- ### Define Custom Weapon Profiles Source: https://github.com/vel136/vetra/blob/master/docs/guides/benchmarks.md Create custom simulation profiles for specific weapons, including behaviors like drag, pierce, and bounce, by passing a profile table as the second argument to VetraBenchmark.new(). ```lua local Bench = VetraBenchmark.new(nil, { { name = "Sniper with drag", behavior = { MaxDistance = 1500, DragCoefficient = 0.003, DragModel = "G7", MaxPierceCount = 3, CanPierceFunction = function(ctx, result, vel) return true end, }, }, { name = "Grenade", behavior = { MaxDistance = 400, MaxBounces = 6, Restitution = 0.55, CanBounceFunction = function(ctx, result, vel) return true end, }, }, }) Bench:Run() ``` -------------------------------- ### Enable 6DOF Physics Source: https://github.com/vel136/vetra/blob/master/docs/faq.md Enable 6DOF physics for a bullet. Ensure LiftCoefficientSlope and ReferenceArea are greater than zero for lift to function. ```lua :SixDOF():Enabled(true) ``` -------------------------------- ### Configure Solver-Level Environmental Properties Source: https://context7.com/vel136/vetra/llms.txt Set global wind vectors and Coriolis deflection for all bullets. Configure per-bullet wind sensitivity via behavior and set LOD origin or interest points for performance. ```lua -- Set global wind vector (affects all bullets with WindResponse > 0) Solver:SetWind(Vector3.new(10, 0, 0)) -- 10 studs/s eastward -- Per-bullet wind sensitivity via behavior local WindyBehavior = BehaviorBuilder.new() :Wind() :Response(0.5) -- 50% of wind applied (1.0 = full, 0.0 = immune) :Done() :Build() -- Configure Coriolis deflection (solver-level, affects all bullets) Solver:SetCoriolisConfig(75, 1200) -- Arctic: latitude 75°, 1200x exaggeration Solver:SetCoriolisConfig(0, 800) -- Equator: horizontal drift only Solver:SetCoriolisConfig(45, 0) -- Disable (default) -- Scale reference: -- 0 = disabled, 500 = subtle, 1000 = perceptible at 300 studs, 3000 = dominant -- Set LOD origin for performance optimization RunService.RenderStepped:Connect(function() Solver:SetLODOrigin(workspace.CurrentCamera.CFrame.Position) end) -- Set interest points for spatial partitioning Solver:SetInterestPoints({ player1.Position, player2.Position }) ``` -------------------------------- ### Configure 6DOF Aerodynamics Source: https://context7.com/vel136/vetra/llms.txt Enable full six-degrees-of-freedom aerodynamics for realistic pitch, yaw, and roll dynamics. This requires defining mass, reference area, and various aerodynamic coefficients. ```lua local Behavior = BehaviorBuilder.new() :Physics() :BulletMass(0.01) -- Required for 6DOF (F = ma) :MinSpeed(10) :Done() :Drag() :Coefficient(0.003) :Done() :Magnus() :SpinVector(Vector3.new(0, 0, 500)) -- 500 rad/s spin :Done() :SixDOF() :Enabled(true) -- Required fields :ReferenceArea(0.008) -- Cross-sectional area in studs² :ReferenceLength(0.05) -- Caliber in studs :MomentOfInertia(0.001) -- Transverse MOI -- Aerodynamic coefficients :LiftCoefficientSlope(2.0) -- dCL/dα, lift proportional to AoA :PitchingMomentSlope(-0.5) -- Negative = statically stable :PitchDampingCoeff(0.02) -- Kills wobble :RollDampingCoeff(0.01) -- Spin decay :AoADragFactor(3.0) -- Extra drag at high AoA -- For gyroscopic precession :SpinMOI(0.0003) -- Axial MOI :Done() :Build() ``` -------------------------------- ### Register Behaviors with VetraNet Source: https://github.com/vel136/vetra/blob/master/docs/guides/networking.md Register shared behaviors for client and server using a registry. Both sides must register the same behaviors in the same order for the hashing system to work correctly. This prevents clients from forging behavior configurations. ```lua -- SharedBehaviors.lua, required by both server and client local Registry = Vetra.VetraNet.BehaviorRegistry.new() Registry:Register("Rifle", RifleBehavior) Registry:Register("Shotgun", ShotgunBehavior) return Registry ``` -------------------------------- ### Create Preset Behaviors Source: https://github.com/vel136/vetra/blob/master/docs/documentation.md Vetra provides preset constructors for common weapon types like Sniper, Grenade, and Pistol. These can be chained with additional overrides before building. ```lua -- Sniper: 1500 studs, pierce-capable, high fidelity local SniperBehavior = Vetra.BehaviorBuilder.Sniper():Build() -- Grenade: low speed, bouncy, corner-trap aware local GrenadeBehavior = Vetra.BehaviorBuilder.Grenade():Build() -- Pistol: 300 studs, single pierce local PistolBehavior = Vetra.BehaviorBuilder.Pistol():Build() ``` ```lua local Behavior = Vetra.BehaviorBuilder.Sniper() :Physics() :MaxDistance(2000) :Done() :Build() ``` -------------------------------- ### Fire Bullet from Client Source: https://github.com/vel136/vetra/blob/master/docs/documentation.md Client-side initiation of a bullet fire request using VetraNet. Specify muzzle position, direction, speed, and the registered behavior name. ```lua local Net = Vetra.VetraNet.new(ClientSolver, SharedRegistry) Net:Fire(muzzlePosition, direction, speed, "Rifle") ``` -------------------------------- ### Connect to OnTravelBatch for Batched Events Source: https://github.com/vel136/vetra/blob/master/docs/guides/performance.md Use OnTravelBatch to receive all travelling casts in a single event for batch processing. This is more efficient than OnTravel for numerous active casts and uses FireSafe handlers. ```lua Signals.OnTravelBatch:Connect(function(contexts) for _, context in contexts do -- update cosmetics, check proximity, etc. end end) ``` -------------------------------- ### Build Behavior with LOD Enabled Source: https://github.com/vel136/vetra/blob/master/docs/guides/performance.md Configure a behavior with LOD enabled by setting the maximum distance. This behavior can then be passed to the Solver. ```lua local Behavior = Vetra.BehaviorBuilder.new() :Physics() :MaxDistance(800) :Done() :Build() ``` -------------------------------- ### Configure Homing Projectile Behavior Source: https://context7.com/vel136/vetra/llms.txt Implement homing behavior for projectiles that steer towards a dynamic target. Configure the target position provider, steering strength, maximum duration, acquisition radius, and a filter function. ```lua local target = workspace.Enemy.HumanoidRootPart local HomingBehavior = BehaviorBuilder.new() :Physics() :MaxDistance(1000) :Done() :Homing() :PositionProvider(function(pos, vel) -- Return target position, or nil to disengage if target and target.Parent then return target.Position end return nil end) :Strength(90) -- Steering force in degrees/second :MaxDuration(5) -- Auto-disengage after 5 seconds :AcquisitionRadius(0) -- 0 = engage immediately :Filter(function(ctx, pos, vel) return not ctx.UserData.HomingDisabled end) :Done() :Build() Signals.OnHomingDisengaged:Connect(function(context, reason) print("Homing ended:", reason) -- "timeout", "provider_nil", "filter", etc. end) ``` -------------------------------- ### Create Weapon Variants with Clone and Merge Source: https://github.com/vel136/vetra/blob/master/docs/faq.md Use :Clone() to create independent copies of a base behavior for modification, or :Merge() to apply multiple reusable modifiers non-destructively. The original base behavior remains untouched. ```lua local Base = BehaviorBuilder.Sniper() local Heavy = Base:Clone():Pierce():Max(5):Done():Build() local Light = Base:Clone():Physics():MaxDistance(800):Done():Build() -- Base is untouched ``` ```lua local APMod = BehaviorBuilder.new() :Pierce():Max(5):SpeedRetention(0.95):Done() local HollowMod = BehaviorBuilder.new() :Tumble():OnPierce(true):DragMultiplier(5):Done() -- Neither the preset nor the modifiers are mutated local Behavior = BehaviorBuilder.Sniper():Merge(APMod, HollowMod):Build() ``` -------------------------------- ### Fix Blockcast Tunneling with Offset Center Source: https://github.com/vel136/vetra/blob/master/docs/faq.md Adjust the Blockcast size and center to ensure the front face is flush with the origin, preventing thin walls from being missed. `BoxZ` should be small and non-zero. ```lua local size = Vector3.new(0.2, 0.2, direction.Magnitude) local cframe = CFrame.lookAt(origin, origin + direction) workspace:Blockcast(cframe, size, direction, params) ``` ```lua CastFunction = function(origin, direction, params) local BoxZ = 0.01 local dirUnit = direction.Unit local center = origin - dirUnit * (BoxZ / 2) local size = Vector3.new(0.2, 0.2, BoxZ) local cframe = CFrame.lookAt(center, center + direction) return workspace:Blockcast(cframe, size, direction, params) end ``` -------------------------------- ### Configuring Network Authority Modes in VetraNet Source: https://context7.com/vel136/vetra/llms.txt VetraNet supports multiple authority modes for network control. ClientAuthoritative is the default, where clients send requests validated by the server. ServerAuthority restricts firing to the server only, suitable for NPCs or hazards. SharedAuthority allows both client and server to initiate actions. A player filter can also be applied to control replication. ```lua -- ClientAuthoritative (default): Clients send requests, server validates local Net = Vetra.VetraNet.new(ServerSolver, SharedRegistry, { Mode = Vetra.Enums.NetworkMode.ClientAuthoritative, }) -- ServerAuthority: Only server can fire (NPC projectiles, hazards) local Net = Vetra.VetraNet.new(ServerSolver, SharedRegistry, { Mode = Vetra.Enums.NetworkMode.ServerAuthority, }) -- Server fires directly: local context = BulletContext.new({ Origin = npc.Position, Direction = dir, Speed = 600 }) Net:Fire(context, SharedRegistry:GetHash("Rifle")) -- SharedAuthority: Both can fire (player weapons + server projectiles) local Net = Vetra.VetraNet.new(ServerSolver, SharedRegistry, { Mode = Vetra.Enums.NetworkMode.SharedAuthority, }) -- Filter replication to specific players Net:SetPlayerFilter(function(player) return player.Team == Teams.Blue end) Net:SetPlayerFilter(nil) -- Clear filter, broadcast to all ``` -------------------------------- ### Configure Pistol Behavior with G8 Drag Model Source: https://context7.com/vel136/vetra/llms.txt Set up a pistol behavior using the G8 drag model, appropriate for hollow-point or flat-base semi-spitzer projectiles. Adjust the drag coefficient and G8 model. ```lua local PistolBehavior = BehaviorBuilder.new() :Drag() :Coefficient(0.004) :Model(DragModel.G8) :Done() :Build() ``` -------------------------------- ### Connect to OnPreTermination Signal Source: https://github.com/vel136/vetra/blob/master/docs/intro.md Connect to the OnPreTermination signal to intercept and potentially cancel termination events. Use enum values for termination reasons for type safety. ```lua Signals.OnPreTermination:Connect(function(context, reason, mutate) if reason == Vetra.Enums.TerminateReason.Hit then mutate(true, nil) -- cancel termination end end) ``` -------------------------------- ### Enabling Debug Visualization in VetraNet Behaviors Source: https://context7.com/vel136/vetra/llms.txt This snippet demonstrates how to enable debug visualization for VetraNet behaviors. Setting ':Visualize(true)' within the ':Debug()' section will draw cast segments, hit normals, and bounce vectors. This feature has zero runtime cost when disabled (Visualize(false)). ```lua local DebugBehavior = BehaviorBuilder.new() :Physics() :MaxDistance(500) :Done() :Debug() :Visualize(true) -- Zero runtime cost when false :Done() :Build() -- Draws: cast segments, hit normals, bounce vectors, corner-trap markers ``` -------------------------------- ### Customize Sniper Behavior with Physics and Drag Source: https://context7.com/vel136/vetra/llms.txt Extend the default Sniper behavior by chaining physics and drag configurations. This allows fine-tuning parameters like max distance, min speed, drag coefficient, and drag model. ```lua local CustomSniper = BehaviorBuilder.Sniper() :Physics() :MaxDistance(2000) :MinSpeed(50) :Done() :Drag() :Coefficient(0.002) :Model(BehaviorBuilder.DragModel.G7) :Done() :Build() ``` -------------------------------- ### Implement Custom Trajectory Source: https://github.com/vel136/vetra/blob/master/docs/documentation.md Replace Vetra's kinematic physics with a custom position function for scripted paths or spline-driven projectiles. Return nil to end the custom path and terminate the cast. ```lua Solver:Fire(context, { TrajectoryPositionProvider = function(elapsed) -- elapsed = seconds since this cast was fired -- Return nil to end the custom path and terminate the cast return CFrame.new(origin) * CFrame.Angles(0, elapsed, 0) * CFrame.new(0, 0, -elapsed * speed) end, }) ```