ItemSightAsset — Sight Attachments
ItemSightAsset defines optical attachments that provide zoom, night vision, and reticle features. It inherits from ItemCaliberAsset, giving it access to the full stat modifier system. At 230 lines it is the second-largest attachment class after ItemTacticalAsset. It covers zoom configuration, night vision modes with per-type default colors and fog settings, aim alignment transform routing (sight-based vs gun-based), holographic reticles, scope overlay texel alignment, third-person zoom, and distance marker markings rendered on the scope view.
Source code location: Unturned/Bundles/ItemSightAsset.cs
Inheritance Chain
ItemAsset
→ ItemCaliberAsset
→ ItemSightAssetClass Definition
csharp
public class ItemSightAsset : ItemCaliberAsset
{
protected GameObject _sight;
public GameObject sight => _sight;
private ELightingVision _vision;
public ELightingVision vision => _vision;
public Color nightvisionColor;
public float nightvisionFogIntensity;
public float zoom { get; private set; }
public float thirdPersonZoomFactor { get; private set; }
private bool _isHolographic;
public bool isHolographic => _isHolographic;
public bool shouldZoomUsingEyes;
public bool shouldOffsetScopeOverlayByOneTexel;
public EAimAlignmentTransformOwner AimAlignmentTransformOwner { get; set; }
public string AimAlignmentTransformPath { get; set; }
public Vector3 AimAlignmentLocalOffset { get; set; }
public List<DistanceMarker> distanceMarkers;
}Core Fields
Prefab Loading
| Field | Type | .dat Key | Default | Description |
|---|---|---|---|---|
_sight | GameObject | Bundle "Sight" | — | Sight attachment prefab |
Zoom Configuration
| Field | Type | .dat Key | Default | Description |
|---|---|---|---|---|
zoom | float | Zoom | 1.0 (clamped) | Zoom factor (e.g., 2 = 2x magnification) |
thirdPersonZoomFactor | float | ThirdPerson_Zoom | UseableGun.DEFAULT_THIRD_PERSON_ZOOM_FACTOR (~0.375) | Third-person FOV zoom |
Both values are clamped to a minimum of 1.0 via Mathf.Max(1.0f, ...). The zoom field was originally a target field of view (90/fov) prior to 2022-04-11; it was refactored to be a straightforward zoom factor.
Night Vision
| Field | Type | .dat Key | Default | Description |
|---|---|---|---|---|
_vision | ELightingVision | Vision | NONE | Night vision type |
nightvisionColor | Color | Nightvision_Color | Per-type default | NV filter color |
nightvisionFogIntensity | float | Nightvision_Fog_Intensity | 0.5 (civilian) / 0.25 (military) | NV fog override |
The ELightingVision enum values are NONE, CIVILIAN, and MILITARY. When the vision type is CIVILIAN or MILITARY, default values for color and fog intensity are applied:
csharp
if (vision == ELightingVision.CIVILIAN)
{
nightvisionColor = p.data.LegacyParseColor32RGB("Nightvision_Color",
defaultValue: LevelLighting.NIGHTVISION_CIVILIAN);
nightvisionFogIntensity = p.data.ParseFloat("Nightvision_Fog_Intensity",
defaultValue: 0.5f);
}
else if (vision == ELightingVision.MILITARY)
{
nightvisionColor = p.data.LegacyParseColor32RGB("Nightvision_Color",
defaultValue: LevelLighting.NIGHTVISION_MILITARY);
nightvisionFogIntensity = p.data.ParseFloat("Nightvision_Fog_Intensity",
defaultValue: 0.25f);
}Military night vision has lower default fog intensity (0.25 vs 0.5), providing clearer vision in foggy conditions. The color uses LegacyParseColor32RGB which expects comma-separated R,G,B values without alpha.
Holographic and Scope Rendering
| Field | Type | .dat Key | Default | Description |
|---|---|---|---|---|
_isHolographic | bool | Holographic (flag) | false | Holographic reticle |
shouldZoomUsingEyes | bool | Zoom_Using_Eyes | false | Zoom via camera FOV instead of scope overlay |
shouldOffsetScopeOverlayByOneTexel | bool | Offset_Scope_Overlay_By_One_Texel | false | Fix scope overlay alignment |
Holographic sights typically use shouldZoomUsingEyes = true to zoom the main camera FOV rather than rendering a separate scope camera with an overlay. The shouldOffsetScopeOverlayByOneTexel flag shifts the scope overlay by one texel to keep the center pixel aligned — a precision fix for certain scope textures.
Aim Alignment System
The aim alignment system controls where the camera is positioned when aiming down sights with this scope:
csharp
public enum EAimAlignmentTransformOwner
{
Sight, // Look for aim alignment transform relative to sight model.
Gun, // Look for aim alignment transform relative to equipable prefab.
}| Field | .dat Key | Default | Description |
|---|---|---|---|
AimAlignmentTransformOwner | AimAlignment_Owner | Sight | Where to find the alignment transform |
AimAlignmentTransformPath | AimAlignment_Path | null | Custom hierarchy path relative to owner |
AimAlignmentLocalOffset | AimAlignment_LocalOffset | (0,0,0) | Fine-tuning position offset |
When the owner is Sight, the default path is Model_0/Aim relative to the sight prefab. When the owner is Gun, a custom AimAlignment_Path must be provided relative to the equipable weapon prefab. The AimAlignmentLocalOffset provides a final position tweak applied to the resolved transform.
Distance Markers
The distanceMarkers list defines rangefinder markings rendered on the sight overlay. Each marker is a struct:
csharp
public struct DistanceMarker : IDatParseable
{
public enum ESide { Left, Right }
public float distance; // Target distance for this marker
public float lineOffset; // [0,1] offset from center
public float lineWidth; // [0,1] line width
public ESide side; // Left or Right
public bool hasLabel; // Show distance text
public Color32 color; // Marker color
}Markers are parsed from the .dat using the generic list-of-structs deserializer:
csharp
distanceMarkers = p.data.ParseListOfStructs<DistanceMarker>("DistanceMarkers");Each marker's TryParse method reads an IDatDictionary:
Distance(required): the range for this mark.LineOffset: [0, 1] distance from center to start of line.LineWidth: [0, 1] local width of the horizontal line (default 0.05).Side: Left or Right of the center line (default Right).HasLabel: whether the distance text is visible (default true).Color: the marker color.
BuildDescription
ItemSightAsset overrides BuildDescription to add zoom-specific information:
csharp
public override void BuildDescription(ItemDescriptionBuilder builder, Item itemInstance)
{
base.BuildDescription(builder, itemInstance);
if (!builder.HasFlag(EItemDescriptionFlags.Uncategorized))
return;
if (zoom != 1.0f)
builder.Append(localization.format("ItemDescription_ZoomFactor", zoom),
DescSort_GunAttachmentStat);
if (thirdPersonZoomFactor != UseableGun.DEFAULT_THIRD_PERSON_ZOOM_FACTOR)
builder.Append(localization.format("ItemDescription_ThirdPersonZoomFactor",
thirdPersonZoomFactor), DescSort_GunAttachmentStat + 1);
}The base class (ItemCaliberAsset.BuildDescription) renders all inherited stat modifiers (recoil, spread, sway, shake, aim duration, movement speed, damage, gravity).
PopulateAsset
csharp
public override void PopulateAsset(in PopulateAssetParameters p)
{
base.PopulateAsset(in p);
_sight = loadRequiredAsset<GameObject>(p.bundle, "Sight");
if (p.data.ContainsKey("Vision"))
{
_vision = (ELightingVision)Enum.Parse(typeof(ELightingVision),
p.data.GetString("Vision"), true);
// Set nightvision defaults based on vision type...
}
else
{
_vision = ELightingVision.NONE;
}
zoom = Mathf.Max(1.0f, p.data.ParseFloat("Zoom"));
thirdPersonZoomFactor = Mathf.Max(1.0f,
p.data.ParseFloat("ThirdPerson_Zoom",
defaultValue: UseableGun.DEFAULT_THIRD_PERSON_ZOOM_FACTOR));
shouldZoomUsingEyes = p.data.ParseBool("Zoom_Using_Eyes");
shouldOffsetScopeOverlayByOneTexel =
p.data.ParseBool("Offset_Scope_Overlay_By_One_Texel");
AimAlignmentTransformOwner = p.data.ParseEnum("AimAlignment_Owner",
EAimAlignmentTransformOwner.Sight);
AimAlignmentTransformPath = p.data.GetString("AimAlignment_Path");
AimAlignmentLocalOffset = p.data.ParseVector3("AimAlignment_LocalOffset");
_isHolographic = p.data.ContainsKey("Holographic");
distanceMarkers = p.data.ParseListOfStructs<DistanceMarker>("DistanceMarkers");
}Cargo Data Export
BuildCargoData writes sight-specific fields to the Sight table:
csharp
CargoDeclaration data = builder.GetOrAddDeclaration("Sight");
data.Append("GUID", GUID);
data.Append("Vision", vision);
data.Append("Nightvision_Color", nightvisionColor);
data.Append("Nightvision_Fog_Intensity", nightvisionFogIntensity);
data.Append("Zoom", zoom);
data.Append("ThirdPerson_Zoom", thirdPersonZoomFactor);
data.Append("Zoom_Using_Eyes", shouldZoomUsingEyes);
data.Append("Holographic", isHolographic);The base class appends caliber fields to the Caliber table.
Inherited Stat Modifiers (ItemCaliberAsset)
All sight assets inherit the full stat modifier system. Common sight configurations:
| Stat | Typical Scope Value | Typical Red Dot Value |
|---|---|---|
Recoil_X | 1.0 (no change) | 1.0 |
Recoil_Y | 1.0 | 1.0 |
Spread | 1.0 | 1.0 |
Sway | 1.3-1.5 (more sway) | 0.9-1.0 (less sway) |
Shake | 1.0 | 1.0 |
Aim_Duration_Multiplier | 1.3-1.5 (slower ADS) | 0.8-0.9 (faster ADS) |
Aiming_Movement_Speed_Multiplier | 0.8-0.9 | 1.0 |
High-magnification scopes typically increase sway and slow down ADS time to balance the zoom advantage. Red dot and holographic sights often reduce sway slightly for faster target acquisition.
Attachment Integration
When a sight is attached to a gun, UseableGun applies its effects:
- Zoom application: If
shouldZoomUsingEyesis false, a scope camera renders the zoomed view with an overlay texture. If true, the main camera FOV is reduced. - Night vision activation: If
_visionis notNONE, the night vision post-process effect is enabled with the sight's color and fog intensity. - Aim alignment: The player's camera position during ADS is determined by the sight's aim alignment transform.
- Distance markers: If markers are defined, they are rendered as lines and labels on the scope overlay.
- Prefab instantiation: The
_sightGameObject is instantiated and parented to the weapon'sHook_Sighttransform.
Common Issues
- Zoom minimum clamp — The
zoomvalue is clamped toMathf.Max(1.0f, ...). SettingZoomto 0.5 produces 1x zoom, not 0.5x. There is no way to create a de-magnified sight. - Night vision without Zoom — A sight with
Vision=CIVILIANbutZoom=1.0provides night vision with no magnification. The night vision effect is independent of the zoom system. - AimAlignment_Owner=Gun without path — When the owner is
Gunbut noAimAlignment_Pathis set, the alignment transform resolves to the gun's root, which may produce incorrect camera positioning. - ThirdPerson_Zoom defaults — The default third-person zoom factor is approximately 0.375, which matches the standard third-person camera. Customizing this value only matters for sights with non-standard first-person zoom behavior.
- Distance marker parsing failures — If a marker's
Distancefield is missing or invalid,TryParsereturnsfalseand the marker is silently skipped. No error is reported for malformed marker entries. - Holographic and Eyes Zoom — Holographic sights typically use
Zoom_Using_Eyeswith a modest zoom value. UsingHolographicwithoutZoom_Using_Eyesrenders the scope overlay over the holographic reticle, which may look incorrect.
