-
Notifications
You must be signed in to change notification settings - Fork 0
HyGuns Attachments Guide
This guide explains how to create custom weapon attachments in HyGuns, how to define a new attachment type from scratch, how to create an attachment item, how to connect it to a weapon, and how to use attachment-related interactions.
HyGuns attachments are built from three parts:
-
Attachment type definition
A standalone JSON file under:Server/HyGuns/AttachmentTypesThis defines the attachment category, for example
Scope,Silencer,Magazine,Grip, or any custom type you create. -
Attachment item asset
A normal item JSON with:"HyGuns": { "AttachmentSettings": { "Type": "YourAttachmentType" } }
This turns the item into a valid weapon attachment.
-
Weapon attachment slots
A weapon declares which attachment types it accepts through:"HyGuns": { "WeaponSettings": { "SupportedAttachments": { "YourAttachmentType": { "Count": 1 } } } }
When the player opens the attachment UI, HyGuns creates the attachment container from SupportedAttachments. Drag-and-drop then checks attachment type, wildcard rules, conflicts, and max-count limits.
Create a new JSON file inside:
Server/HyGuns/AttachmentTypes
The filename is only for organization. The real type id is the Type field.
Example:
{
"Type": "Laser",
"Icon": "Attachments/laser.png",
"AnyAllowed": true,
"ConflictsWith": [],
"MaxCount": 1
}| Field | Type | Required | Meaning |
|---|---|---|---|
Type |
string | Yes | Attachment type id. This is the id used by weapons and attachment items. |
Icon |
string | No | Slot icon path relative to Common/UI/Custom. |
AnyAllowed |
boolean | No | Whether this type can be placed into wildcard * slots. Defaults to true. |
ConflictsWith |
string array | No | Other attachment type ids that cannot be installed together with this type. |
MaxCount |
integer | No | Maximum number of installed attachments of this type on one weapon. |
{
"Type": "Scope",
"Icon": "Attachments/scope.png",
"AnyAllowed": false,
"ConflictsWith": ["ThermalScope"],
"MaxCount": 1
}AnyAllowed: false is useful for attachments like scopes. A weapon may have a dedicated Scope slot and also wildcard slots, but you may still want to prevent a second scope from being installed into a wildcard slot.
ConflictsWith is checked both ways. If either installed type declares a conflict with the other type, the combination is rejected.
An attachment item is a normal item asset with HyGuns.AttachmentSettings.
Example:
{
"Id": "Attachment_Laser_Red",
"TranslationProperties": {
"Name": "Red Laser"
},
"Quality": "Uncommon",
"HyGuns": {
"AttachmentSettings": {
"Type": "Laser",
"SettingsModifiers": {
"Projectiles": {
"Spread": "*0.85"
}
}
}
}
}This item:
- belongs to the
Laserattachment type; - can be installed only into weapons that support
Laseror compatible wildcard slots; - reduces weapon spread by multiplying it by
0.85while installed.
{
"HyGuns": {
"AttachmentSettings": {
"Type": "Scope",
"ZoomSettings": {
"MaxDistance": 20.0,
"MinDistance": 1.0,
"DefaultZoomMultiplier": 1.0,
"MaxZoomMultiplier": 6.0,
"ZoomMultiplierStep": 1.0,
"OverlayTexturePath": "Scopes/Scope_8x.png"
},
"FireSound": {
"Volume": "*0.05"
},
"SettingsModifiers": {
"Projectiles": {
"Spread": "*0.75"
},
"AutoGuidance": {
"Enabled": true
}
}
}
}
}| Field | Type | Required | Meaning |
|---|---|---|---|
Type |
string | Yes | Attachment type id loaded from Server/HyGuns/AttachmentTypes. |
SettingsModifiers |
object | No | Weapon stat modifiers applied while this attachment is installed. |
ZoomSettings |
object | No | Zoom settings provided by this attachment. |
FireSound |
object | No | Fire sound modifiers provided by this attachment. |
SettingsModifiers changes the effective weapon settings while the attachment is installed.
The block follows the same general shape as HyGuns.WeaponSettings, but numeric fields may also use operation strings.
Example:
{
"SettingsModifiers": {
"Projectiles": {
"Spread": "*0.75",
"Damage": "+2"
},
"Ammo": {
"Capacity": "+10",
"Reload": {
"Time": "-0.2"
}
},
"Fire": {
"Cooldown": "*0.9"
}
}
}| Token | Meaning | Example |
|---|---|---|
* |
multiply current value | "Spread": "*0.75" |
/ |
divide current value | "Cooldown": "/2" |
+ |
add to current value | "Damage": "+2" |
- |
subtract from current value | "Reload": { "Time": "-0.2" } |
= |
set final value | "Cooldown": "=0.15" |
Supported numeric modifier fields include:
Ammo.Capacity
Ammo.Reload.Amount
Ammo.Reload.Time
Fire.Cooldown
Projectiles.Spread
Projectiles.Count
Projectiles.Damage
AutoGuidance.ConeDegrees
AutoGuidance.MaxDistance
AutoGuidance.TurnRate
WallPenetration.Blocks
WallPenetration.DamageReductionModifier
WallPenetration.DamageReductionDistance
Non-numeric values are merged as normal partial weapon settings.
Example:
{
"SettingsModifiers": {
"AutoGuidance": {
"Enabled": true,
"ConeDegrees": 25.0,
"MaxDistance": 80.0,
"TurnRate": 240.0,
"EffectId": "MarkedTarget"
}
}
}File:
Server/HyGuns/AttachmentTypes/Scope.json
{
"Type": "Scope",
"Icon": "Attachments/scope.png",
"AnyAllowed": false,
"ConflictsWith": ["ThermalScope"],
"MaxCount": 1
}{
"Id": "Scope_8x",
"TranslationProperties": {
"Name": "8x Scope"
},
"Quality": "Rare",
"HyGuns": {
"AttachmentSettings": {
"Type": "Scope",
"ZoomSettings": {
"MaxDistance": 20.0,
"MinDistance": 1.0,
"DefaultZoomMultiplier": 1.0,
"MaxZoomMultiplier": 6.0,
"ZoomMultiplierStep": 1.0,
"OverlayTexturePath": "Scopes/Scope_8x.png"
},
"SettingsModifiers": {
"Projectiles": {
"Spread": "*0.9"
}
}
}
}
}ZoomSettings can be defined on any attachment type, not only scopes. When a zoom interaction runs, the first installed valid attachment with ZoomSettings overrides the interaction zoom settings.
{
"Type": "Silencer",
"Icon": "Attachments/silencer.png",
"AnyAllowed": true,
"ConflictsWith": ["MuzzleBrake"],
"MaxCount": 1
}{
"Id": "Silencer_Basic",
"TranslationProperties": {
"Name": "Basic Silencer"
},
"Quality": "Uncommon",
"HyGuns": {
"AttachmentSettings": {
"Type": "Silencer",
"FireSound": {
"Volume": "*0.05"
},
"SettingsModifiers": {
"Projectiles": {
"Spread": "*1.05"
},
"Fire": {
"Cooldown": "*1.1"
}
}
}
}
}FireSound.Volume uses the same numeric operation syntax as settings modifiers. For example, "*0.05" multiplies the current fire sound volume by 0.05.
To make FireSound work, use Hyguns_PlayWeaponFireSound in the weapon interaction instead of relying only on standard item effect sounds.
A weapon accepts attachments through HyGuns.WeaponSettings.SupportedAttachments.
Example:
{
"Id": "Weapon_Rifle_Custom",
"TranslationProperties": {
"Name": "Custom Rifle"
},
"HyGuns": {
"WeaponSettings": {
"WeaponIcon": "Weapons/CustomRifle.png",
"Ammo": {
"Family": "Bullet",
"WeaponClass": "Rifle",
"ItemId": "Ammo_Bullet_Base",
"Capacity": 30,
"Reload": {
"Time": 1.5,
"Amount": 30
}
},
"Fire": {
"Cooldown": 0.1
},
"Projectiles": {
"ConfigId": "Rifle",
"ProjectileId": "Projectile_Bullet_Base",
"Spread": 0.02,
"Count": 1,
"Damage": 8
},
"SupportedAttachments": {
"Scope": {
"Count": 1,
"Visual": true,
"Index": 0
},
"Silencer": {
"Count": 1,
"Visual": true,
"Index": 1
},
"Laser": {
"Count": 1
},
"*": {
"Count": 2
}
}
}
}
}| Field | Type | Meaning |
|---|---|---|
Count |
integer | Number of slots to create for this type. |
Visual |
boolean | Whether this type contributes to visual state key generation. |
Index |
integer | Ordering value for visual state keys and front-of-grid slot ordering. |
The special key * creates wildcard slots. Wildcard slots only accept valid attachment items whose attachment type has AnyAllowed enabled.
Wildcard slots do not bypass compatibility. They still reject:
- non-attachment items;
- attachment types with
AnyAllowed: false; - conflicting attachment types;
- attachments beyond
MaxCount.
DefaultAttachments creates attachment item stacks automatically when a weapon is initialized for the first time.
Important: values are real item asset ids, not attachment type ids.
{
"HyGuns": {
"WeaponSettings": {
"SupportedAttachments": {
"Scope": {
"Count": 1
},
"Magazine": {
"Count": 1
}
},
"DefaultAttachments": {
"Scope": "Scope_8x",
"Magazine": ["Magazine_Tier_II"]
}
}
}
}The key is the preferred slot type. The created item still has to pass normal attachment compatibility checks, including type, conflicts, wildcard rules, and MaxCount.
Visual state switching is driven by SupportedAttachments.
Every supported attachment type with:
"Visual": trueand an Index contributes its type id to the state key when a valid attachment of that type is installed.
The key is built in Index order and joined with _.
Example:
{
"HyGuns": {
"WeaponSettings": {
"SupportedAttachments": {
"Scope": {
"Count": 1,
"Visual": true,
"Index": 0
},
"Silencer": {
"Count": 1,
"Visual": true,
"Index": 1
},
"Magazine": {
"Count": 2
}
}
}
},
"State": {
"Scope": {
"Model": "Items/Weapons/Rifle/Rifle_Scope.blockymodel"
},
"Silencer": {
"Model": "Items/Weapons/Rifle/Rifle_Silencer.blockymodel"
},
"Scope_Silencer": {
"Model": "Items/Weapons/Rifle/Rifle_Scope_Silencer.blockymodel"
}
}
}In this example:
| Installed visual attachments | State key |
|---|---|
only Scope
|
Scope |
only Silencer
|
Silencer |
Scope + Silencer
|
Scope_Silencer |
| none | base item state |
The generated state key must exist in the item JSON State block.
Automatic visual state updates happen when default attachments are added during first weapon initialization and when the attachment window is closed.
Use the Hyguns_OpenAttachments interaction.
{
"Type": "Hyguns_OpenAttachments"
}This opens the held weapon attachment container.
A common pattern is to bind this interaction to a weapon action, for example a secondary use, radial menu entry, or another custom interaction path depending on how your item is configured.
Example:
{
"Interactions": {
"Use": [
{
"Type": "Hyguns_OpenAttachments"
}
]
}
}Use the exact interaction location supported by your item setup.
Use Hyguns_AttachmentsInstalled before a zoom interaction.
{
"Type": "Hyguns_AttachmentsInstalled",
"AttachmentTypes": ["Scope"],
"RequireAll": false,
"Next": {
"Type": "Scope_Zoom"
},
"Failed": {
"Type": "Hyguns_ResetZoom"
}
}Fields:
| Field | Type | Meaning |
|---|---|---|
AttachmentTypes |
string array | Attachment type ids to check. |
AttachmentsTypes |
string array | Alias for AttachmentTypes. |
RequireAll |
boolean |
false means at least one requested type is required; true means all requested types are required. |
If AttachmentTypes is omitted or empty, the check succeeds when any valid attachment is installed.
{
"Type": "Scope_Zoom"
}With explicit fallback settings:
{
"Type": "Scope_Zoom",
"OverlayTexturePath": "UI/Scope/ScopeOverlay.png",
"MaxDistance": 20.0,
"MinDistance": 1.0,
"DefaultZoomMultiplier": 1.0,
"MaxZoomMultiplier": 2.5,
"ZoomMultiplierStep": 0.5
}If the installed attachment has ZoomSettings, those settings override the interaction zoom settings.
{
"Type": "Scope_Zoom_In"
}{
"Type": "Scope_Zoom_Out"
}{
"Type": "Scope_Step_Zoom"
}{
"Type": "Hyguns_ResetZoom"
}Use Hyguns_PlayWeaponFireSound when silencers or other attachments should modify shot volume.
{
"Type": "Hyguns_PlayWeaponFireSound",
"WorldSoundEventId": "Rifle_Fire",
"LocalSoundEventId": "Rifle_Fire"
}Example silencer:
{
"HyGuns": {
"AttachmentSettings": {
"Type": "Silencer",
"FireSound": {
"Volume": "*0.05"
}
}
}
}Do not keep the same fire sound in the standard Effects.WorldSoundEventId or Effects.LocalSoundEventId on the same shot interaction, otherwise both the standard sound and the HyGuns-modified sound may play.
{
"Type": "Laser",
"Icon": "Attachments/laser.png",
"AnyAllowed": true,
"ConflictsWith": [],
"MaxCount": 1
}{
"Id": "Laser_Red",
"TranslationProperties": {
"Name": "Red Laser"
},
"Quality": "Uncommon",
"HyGuns": {
"AttachmentSettings": {
"Type": "Laser",
"SettingsModifiers": {
"Projectiles": {
"Spread": "*0.85"
}
}
}
}
}{
"Id": "Scope_8x",
"TranslationProperties": {
"Name": "8x Scope"
},
"Quality": "Rare",
"HyGuns": {
"AttachmentSettings": {
"Type": "Scope",
"ZoomSettings": {
"MaxDistance": 20.0,
"MinDistance": 1.0,
"DefaultZoomMultiplier": 1.0,
"MaxZoomMultiplier": 6.0,
"ZoomMultiplierStep": 1.0,
"OverlayTexturePath": "Scopes/Scope_8x.png"
},
"SettingsModifiers": {
"Projectiles": {
"Spread": "*0.9"
}
}
}
}
}{
"Id": "Silencer_Basic",
"TranslationProperties": {
"Name": "Basic Silencer"
},
"Quality": "Uncommon",
"HyGuns": {
"AttachmentSettings": {
"Type": "Silencer",
"FireSound": {
"Volume": "*0.05"
},
"SettingsModifiers": {
"Projectiles": {
"Spread": "*1.05"
},
"Fire": {
"Cooldown": "*1.1"
}
}
}
}
}{
"Id": "Weapon_Custom_Rifle",
"TranslationProperties": {
"Name": "Custom Rifle"
},
"HyGuns": {
"WeaponSettings": {
"WeaponIcon": "Weapons/CustomRifle.png",
"Ammo": {
"Family": "Bullet",
"WeaponClass": "Rifle",
"ItemId": "Ammo_Bullet_Base",
"Capacity": 30,
"Reload": {
"Time": 1.5,
"Amount": 30
}
},
"Fire": {
"Cooldown": 0.1
},
"Projectiles": {
"ConfigId": "Rifle",
"ProjectileId": "Projectile_Bullet_Base",
"Spread": 0.02,
"Count": 1,
"Damage": 8
},
"SupportedAttachments": {
"Scope": {
"Count": 1,
"Visual": true,
"Index": 0
},
"Silencer": {
"Count": 1,
"Visual": true,
"Index": 1
},
"Laser": {
"Count": 1
},
"*": {
"Count": 1
}
},
"DefaultAttachments": {
"Laser": "Laser_Red"
}
}
},
"State": {
"Scope": {
"Model": "Items/Weapons/CustomRifle/CustomRifle_Scope.blockymodel"
},
"Silencer": {
"Model": "Items/Weapons/CustomRifle/CustomRifle_Silencer.blockymodel"
},
"Scope_Silencer": {
"Model": "Items/Weapons/CustomRifle/CustomRifle_Scope_Silencer.blockymodel"
}
}
}{
"Type": "Hyguns_CanShoot",
"Next": {
"Type": "Hyguns_PlayWeaponFireSound",
"WorldSoundEventId": "CustomRifle_Fire",
"LocalSoundEventId": "CustomRifle_Fire",
"Next": {
"Type": "Hyguns_Shoot"
}
}
}{
"Type": "Hyguns_OpenAttachments"
}{
"Type": "Hyguns_AttachmentsInstalled",
"AttachmentTypes": ["Scope"],
"RequireAll": false,
"Next": {
"Type": "Scope_Zoom"
},
"Failed": {
"Type": "Hyguns_ResetZoom"
}
}When an attachment does not work, check the following:
- The attachment type JSON exists under
Server/HyGuns/AttachmentTypes. - The type JSON has the correct
Typevalue. - The attachment item has
HyGuns.AttachmentSettings.Type. - The weapon has a matching entry in
SupportedAttachments. - The attachment does not exceed
MaxCount. - The attachment type is not blocked by
ConflictsWith. - If installing into a wildcard
*slot, the type hasAnyAllowed: true. - If using visual states, the supported slot has
Visual: trueand anIndex. - If using visual states, the generated state key exists in the item
Stateblock. - If using silencer-like sound changes, the shot uses
Hyguns_PlayWeaponFireSound. - If using scope zoom, the interaction checks
Hyguns_AttachmentsInstalledbefore runningScope_Zoom. - Numeric modifier strings start with one of:
*,/,+,-,=.