For designers
Change damage, recovery, attack speeds, FOV, crouch depth, and character assets without touching validation code.
A modular, server-checked first-person melee foundation. Swap in your own swords, animation assets, rig, inventory, effects, and game rules—without rewriting everything when one part changes.
Install the entire framework once; afterwards most changes are just editing Config, MoveSets, and Weapons. The ZIP also contains a ready-to-open demo place.
DarkCombatV3_Demo.rbxlx with Roblox Studio → File → Open from File.DarkCombatV3_Package.rbxmx into Workspace, then run the short Install_Existing_Place.lua in the Command Bar while not playing.StarterPlayer: set AvatarJointUpgrade = Disabled, configure R15, and set LoadCharacterAppearance = false if using the included warrior rig.DarkCombatServer, DarkFirstPerson, CombatMotion, DarkCombatRemotes, PracticeSword, and StarterCharacter before installing, to avoid competing scripts. The installer intentionally warns instead of silently overwriting existing objects.The package contains a demo rig (block-based tall R15 / Rthro-style proportions), not a licensed official Rthro mesh asset. You may replace it with your team's own R15 character.
Each ModuleScript has one responsibility. Client input requests attacks; only the server advances combo stages and applies damage.
Change damage, recovery, attack speeds, FOV, crouch depth, and character assets without touching validation code.
Add server extension modules, replace UI/camera modules, or implement new weapon classes using the same folder boundaries.
Open ReplicatedStorage → DarkCombat → Config. The following are examples, not separate scripts; edit the values inside the provided module.
Config.Features = {
Combat = true,
Camera = true,
Movement = true,
CustomHUD = true, -- false if your team supplies its own GUI
ProceduralFallback = true, -- false after you finish all animations
DisableDefaultAnimate = true,
FriendlyFire = false,
DebugHitboxes = false,
}
Config.Camera = {
FOV = 80,
Sensitivity = 0.18,
MaxPitch = 89,
Smoothness = 22,
EyeOffset = Vector3.new(0, 0.13, -0.12),
HideHead = true,
}The remaining groups cover Movement (speed, crouch depth, keys), Combat (headshots, queue timing, blade samples, sanity limits), and UI (inventory/menu keys, cursor attribute).
A Tool can have any visual mesh/model. You only need a simple moving hitbox part and two attachments. There is no per-weapon input script to copy.
Tool with a Handle. Weld your art parts to the Handle and align the tool Grip.BasePart named Blade matching the damaging area. Make it CanCollide=false, CanQuery=true, Massless=true, and weld it to your weapon.Attachment objects BladeStart and BladeEnd inside that Blade part, at the base and tip of its damaging edge.DC_WeaponId to your registered ID. A StringValue with that name or a matching Tool.Name also works.Weapons and reference a MoveSets name. Place Tool in StarterPack (or give it via your inventory system).-- Add to ReplicatedStorage/DarkCombat/Weapons:
Weapons.MyLongsword = {
DisplayName = "Knight's Longsword",
MoveSet = "SwordThreeHit",
BladePart = "Blade", BladeStart = "BladeStart", BladeEnd = "BladeEnd",
BladeRadius = 0.15,
SwingSoundId = "", HitSoundId = "",
}
-- Tool Attribute: DC_WeaponId = "MyLongsword"Remove a weapon: remove its Tool from your inventory/starter packs and remove or disable its registry entry. Unsupported tools are ignored by DarkCombat and can still be used by other systems.
To make a 2-hit, 3-hit, or 5-hit combo, edit the list in MoveSets. Each attack defines the same three timing windows. All timing and damage are server-owned.
MoveSets.MyCombo = {
{ Name = "Slash", Damage = 20, Windup = .20, Active = .25, Recovery = .30,
AnimationId = "", ProceduralPose = 1 },
{ Name = "Backslash", Damage = 25, Windup = .26, Active = .27, Recovery = .33,
AnimationId = "", ProceduralPose = 2 },
{ Name = "Finisher", Damage = 50, Windup = .50, Active = .35, Recovery = .62,
AnimationId = "", ProceduralPose = 3 },
}
Weapons.MyLongsword.MoveSet = "MyCombo"Character prepares attack. Blade cannot deal damage.
Weapon blade sweeps can hit valid targets once per swing.
Blade cannot damage. Input during attack can queue next stage.
After the last attack, the sequence restarts. ComboResetSeconds controls reset on idle. The third stage is your mighty forward cleave by default.
Animation creation belongs to your animators; this package does not ship uploaded animation assets. To connect an authored animation, publish it from Roblox Studio's Animation Editor for the exact R15 rig your game uses. Copy the published asset ID.
MoveSets as rbxassetid://123456789.Windup, Active, and Recovery to the clip so that the blade's real motion occurs during Active.ProceduralFallback once all of your attack clips exist.-- Example: paste a REAL animation ID from your animator
MoveSets.SwordThreeHit[1].AnimationId = "rbxassetid://123456789"
MoveSets.SwordThreeHit[2].AnimationId = "rbxassetid://234567890"
MoveSets.SwordThreeHit[3].AnimationId = "rbxassetid://345678901"
-- Server AnimationService loads and plays authored animation tracks.
-- The fallback procedural attack pose is automatically skipped for that stage.
-- Damage windows ALWAYS use the configured Windup/Active/Recovery values.You can still use Animation Editor keyframe markers like Whoosh and Footstep in your separate effects code, but this starter framework does not wire those markers to damage.
The demo's StarterCharacter is tall and proportioned like a stylized Rthro warrior, but uses legacy R15 Motor6D joints. To use your own rig, replace StarterPlayer → StarterCharacter with a correctly assembled 15-part R15 rig.
Head, HumanoidRootPart, UpperTorso, LowerTorso, arms, legs, hands and feet.Root, Waist, Neck, RightShoulder, and their equivalents.StarterPlayer.AvatarJointUpgrade to Disabled for this Motor6D implementation. The new AnimationConstraint joint system is not implemented here.Humanoid, Animator, and HumanoidRootPart exist.Config.Camera.EyeOffset and Config.Movement.CrouchHipDrop for your final dimensions.For full authored locomotion and crouch animation packs, your team may replace BodyController and PoseService to blend Animator tracks. Keep the interface contract and server validations when doing so.
The camera only needs one signal: LocalPlayer's boolean attribute DC_CursorFree. Set it to true when your UI opens, then false when it closes. The camera remains in first person without moving the look direction.
-- In YOUR inventory LocalScript
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local function openInventory()
myInventoryFrame.Visible = true
player:SetAttribute("DC_CursorFree", true)
end
local function closeInventory()
myInventoryFrame.Visible = false
player:SetAttribute("DC_CursorFree", false)
endSet Config.Features.CustomHUD = false to disable the placeholder I/M panels. Other UI systems should coordinate ownership of this attribute, especially if multiple panels can overlap: use one central UI manager to set it based on whether any blocking panel is open.
The camera also respects the built-in Roblox Escape menu. Keep only one script in control of UserInputService.MouseBehavior when integrating other first-person camera frameworks.
Server extensions live in ServerScriptService → DarkCombatServer → Extensions. Each is a ModuleScript that returns a table. This is ideal for armor, buffs, hit rewards, durability, abilities, and combat logging. The loader automatically discovers new modules at server startup.
-- Example: Extensions/ArmorRules (ModuleScript)
local Extension = { Enabled = true }
function Extension.BeforeDamage(info)
if info.Target:GetAttribute("Armored") then
info.Damage = info.Damage * 0.75
end
end
function Extension.OnHit(info)
print(info.Player.Name, "hit", info.Target.Name, info.Damage)
end
return ExtensionInit(api), OnAttackStart(info), BeforeDamage(info), OnHit(info), OnAttackEnd(info).
Hooks execute server-side. BeforeDamage can adjust info.Damage or return false to block a hit. Add only trusted team modules.
Init(api) receives api.Config, api.Shared, api.Remotes, and api.GetState(player). Extensions are loaded once on server start. Keep extensions small, independently switchable, and non-blocking.
Put the source in your team's source control. A Rojo default.project.json is included for teams with Rojo; everyone else can edit the corresponding ModuleScripts directly in Studio. Split ownership by subsystem instead of editing one 1,000-line script.
CombatService, HitboxService, MoveSets.
Rig, Tool art, animation asset IDs, blade attachments.
UIController, your own ScreenGuis, DC_CursorFree.
Config, Weapons, extension toggles and balancing.
Modularity is not automatic compatibility with every system. This release implements melee Tools and legacy R15 joints. Bows, spells, shields, blocking, dodge i-frames, custom physics controllers, and AnimationConstraint rigs require additional modules. Keep input→server authorization→hit processing separate as you expand.
| Problem | Likely cause / fix |
|---|---|
| No damage | Tool not equipped, ID missing from registry, wrong BladePart/attachments, or Blade proxy not moving with weapon. |
| Animation doesn't play | Wrong/unpublished asset ID, wrong ownership or rig, or asset permissions. Check Studio Output. |
| Limbs won't bend | AvatarJointUpgrade must be Disabled; use legacy R15 Motor6Ds. |
| Two cameras fight | Disable the old DarkFirstPerson and other custom camera scripts. |
| Cursor won't stay free | Your UI needs to set DC_CursorFree to true for its whole open state. |
| Imported mesh sword misses | Use a welded invisible Blade proxy with real attachments. |
| Crouch clips through roof | This version doesn't resize physical collision bounds. |
Code validation: package source and XML are generated and checked outside Studio; Roblox play testing, animation permissions, netcode tuning, and live collision behavior still need your team's Studio tests.