ROBLOX STUDIO / LUAU / MODULAR SYSTEMS

Build the fight.
Own the framework.

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.

3-hit sword comboReal blade attachment sweepsOptional authored animationsConfigurable R15 bodyTeam extension API
START

Install and test in 5 steps

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.

  1. Make a backup of your Roblox place.
  2. Easiest: open DarkCombatV3_Demo.rbxlx with Roblox Studio → File → Open from File.
  3. For your own place, insert DarkCombatV3_Package.rbxmx into Workspace, then run the short Install_Existing_Place.lua in the Command Bar while not playing.
  4. Select StarterPlayer: set AvatarJointUpgrade = Disabled, configure R15, and set LoadCharacterAppearance = false if using the included warrior rig.
  5. Press Play. Equip the Practice Sword, click to chain a three-hit combo. Ctrl/C crouches; I and M open the demo UI.
Migrate from V2: remove the old 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.

STRUCTURE

How the pieces fit together

ReplicatedStorage / DarkCombat
  ├─ Config settings / flags
  ├─ Weapons weapon registry
  ├─ MoveSets combo timing & animation IDs
  ├─ CombatMotion procedural fallback
  └─ Remotes / Attack, Pose, FX

ServerScriptService / DarkCombatServer
  ├─ CombatService combos, validation, server damage
  ├─ HitboxService weapon attachment sweep
  ├─ PoseService crouch, look pose replication
  ├─ AnimationService authored animation playback
  ├─ ExtensionService server hook discovery
  └─ Extensions team-owned modules

StarterPlayer / StarterPlayerScripts / DarkCombatClient
  ├─ CameraController first-person view + cursor
  ├─ BodyController local poses and crouch
  ├─ InputController equipment + keyboard/mouse
  ├─ UIController optional demo panels
  └─ FXController sound + hit feedback

StarterPlayer / StarterCharacter optional demo rig
StarterPack / PracticeSword example Tool

Each ModuleScript has one responsibility. Client input requests attacks; only the server advances combo stages and applies damage.

For designers

Change damage, recovery, attack speeds, FOV, crouch depth, and character assets without touching validation code.

For programmers

Add server extension modules, replace UI/camera modules, or implement new weapon classes using the same folder boundaries.

CONFIG

One central configuration

Open ReplicatedStorage → DarkCombat → Config. The following are examples, not separate scripts; edit the values inside the provided module.

LUA
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).

Config values are required at startup. Changing them during Play is not guaranteed to hot-reload. Edit in Studio, stop, and press Play again.
WEAPONS

Add your own weapon Tool

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.

  1. Create a Roblox Tool with a Handle. Weld your art parts to the Handle and align the tool Grip.
  2. Add a small, transparent BasePart named Blade matching the damaging area. Make it CanCollide=false, CanQuery=true, Massless=true, and weld it to your weapon.
  3. Add Attachment objects BladeStart and BladeEnd inside that Blade part, at the base and tip of its damaging edge.
  4. On the Tool, set a string Attribute named DC_WeaponId to your registered ID. A StringValue with that name or a matching Tool.Name also works.
  5. Make an entry in Weapons and reference a MoveSets name. Place Tool in StarterPack (or give it via your inventory system).
LUA
-- 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"
No hitbox at the right location = no hit. Use Studio's Show Constraints/attachments and test the Blade part while swinging. The server scans the line between attachments and overlaps the Blade part; it does not use a generic box in front of your character.

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.

MOVES

Define combos as data

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.

LUA
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"

Windup

Character prepares attack. Blade cannot deal damage.

Active

Weapon blade sweeps can hit valid targets once per swing.

Recovery

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

Plug in animator-created attacks

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.

  1. Have an animator create three attack animations on the tall warrior or final production rig.
  2. Publish each clip and verify the animation is accessible to the experience's owner/group.
  3. Paste the IDs into MoveSets as rbxassetid://123456789.
  4. Match Windup, Active, and Recovery to the clip so that the blade's real motion occurs during Active.
  5. Test hits against the training dummy and another player. Disable ProceduralFallback once all of your attack clips exist.
LUA
-- 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.
Replace the numeric example IDs with your real uploads. The server starts an authored track when it accepts an attack. It does not trust client-reported animation markers to apply damage. Animation clip motion must line up with the server's active time. An R15 animation made for different limb proportions may look wrong.

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.

CHARACTERS

Import a custom R15 / Rthro character

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.

  • Keep the standard R15 names: Head, HumanoidRootPart, UpperTorso, LowerTorso, arms, legs, hands and feet.
  • Preserve conventional joint names: Root, Waist, Neck, RightShoulder, and their equivalents.
  • Set StarterPlayer.AvatarJointUpgrade to Disabled for this Motor6D implementation. The new AnimationConstraint joint system is not implemented here.
  • Make sure Humanoid, Animator, and HumanoidRootPart exist.
  • Adjust Config.Camera.EyeOffset and Config.Movement.CrouchHipDrop for your final dimensions.
Camera behavior: ±89° vertical look, body pitch distributed between torso and neck, first-person mouse lock, actual crouch hip drop. This is visual/rig movement; crouching does not yet provide ceiling clearance or dynamic collision capsule resizing.

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.

UI

Mouse unlock for any UI

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.

LUA
-- 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)
end

Set 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.

EXTENSIONS

Plug-in hooks for team gameplay

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.

LUA
-- 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 Extension

Available hooks

Init(api), OnAttackStart(info), BeforeDamage(info), OnHit(info), OnAttackEnd(info).

Data / security

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.

CUSTOMIZE

Team ownership and safe changes

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.

Combat programmer

CombatService, HitboxService, MoveSets.

Animator / character artist

Rig, Tool art, animation asset IDs, blade attachments.

UI programmer

UIController, your own ScreenGuis, DC_CursorFree.

Gameplay designer

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.

TESTING

Verify gameplay before shipping

ProblemLikely cause / fix
No damageTool not equipped, ID missing from registry, wrong BladePart/attachments, or Blade proxy not moving with weapon.
Animation doesn't playWrong/unpublished asset ID, wrong ownership or rig, or asset permissions. Check Studio Output.
Limbs won't bendAvatarJointUpgrade must be Disabled; use legacy R15 Motor6Ds.
Two cameras fightDisable the old DarkFirstPerson and other custom camera scripts.
Cursor won't stay freeYour UI needs to set DC_CursorFree to true for its whole open state.
Imported mesh sword missesUse a welded invisible Blade proxy with real attachments.
Crouch clips through roofThis version doesn't resize physical collision bounds.
Security and precision limits: damage is server-run and ignores client-reported targets, but it is not an anti-cheat solution. Network ownership, fast-moving thin weapons, walls, multi-hit obstructions, and latency need additional production validation. Blade sample sweeps are an approximation rather than exact mesh collision.

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.