# GSR Testing System

### **Features**

* ✅ **Automatic Weapon Fire Detection** – Detects all firearms and logs weapon usage.
* ✅ **Real-time GSR Status Tracking** – Maintains player GSR positive/negative status.
* ✅ **Hand Washing Mechanic** – 60-second hand wash animation to reset GSR.
* ✅ **LEO Testing Interface** – Beautiful NUI interface for police testing.
* ✅ **Comprehensive Logging** – All events logged to console and file (`data/gsr_logs.txt`).
* ✅ **Server-side Data Persistence** – GSR data saved to JSON (`data/gsr.json`).
* ✅ **Enhanced UI/UX** – Modern gradient design with smooth animations.
* ✅ **Anti-Exploit Measures** – Server ID verification on all events.

***

### **Installation**

1. Place the `CJ-GSR` folder in your `resources` directory.
2. Add to your `server.cfg`:

```cfg
ensure CJ-GSR
```

3. Restart your server or run:

```cfg
start CJ-GSR
```

***

### **Commands**

#### **Player Commands**

| Command      | Description                                         |
| ------------ | --------------------------------------------------- |
| `/washhands` | Start hand washing (60 seconds) to reset GSR status |
| `/stopwash`  | Stop washing hands early                            |
| `/testgsr`   | Open GSR testing interface (LEO use)                |

#### **Console Commands (Admin Only)**

| Command                | Description                      |
| ---------------------- | -------------------------------- |
| `checkgsr <server_id>` | Check player's GSR status        |
| `resetgsr <server_id>` | Reset player's GSR status        |
| `listgsr`              | List all GSR records in database |

***

### **Configuration**

Edit `config.lua` to customize:

```lua
Config = {
    Enabled = true,                    -- Enable/disable the system
    GSRTimeout = -1,                   -- -1 for permanent, otherwise minutes
    
    Commands = {
        WashHands = 'washhands',
        TestGSR = 'testgsr',
    },
    
    Weapons = {
        DetectMelee = false,           -- Include melee weapons
        TriggerWeapons = {},           -- Empty = all guns
    },
    
    Notifications = {
        ShowWhenPositive = true,
        ShowWhenWashed = true,
        Duration = 5000,
    },
    
    Debug = false,                     -- Enable debug mode
}
```

***

### **Logging**

All events are logged to three places:

1. **Server Console** – Color-coded console messages
2. **Log File** – `data/gsr_logs.txt` with timestamps
3. **Data File** – `data/gsr.json` with persistent player data

#### **Log Events Tracked**

| Event             | Description                      |
| ----------------- | -------------------------------- |
| `WEAPON_FIRE`     | Player fired a weapon            |
| `HANDS_WASHED`    | Player washed hands              |
| `GSR_CHECK`       | Officer tested a player          |
| `EXPLOIT_ATTEMPT` | Server ID mismatch (anti-cheat)  |
| `SYSTEM`          | System initialization and errors |

***

### **Data Files**

#### **`data/gsr.json`**

Stores all player GSR records:

```json
[
  {
    "serverID": 1,
    "licenseID": "license:xxx",
    "discordID": "discord:xxx",
    "status": true,
    "lastUpdated": 1234567890
  }
]
```

#### **`data/gsr_logs.txt`**

Plain text log file with timestamps of all events.

***

### **NUI Interface**

The testing interface features:

* Clean, modern dark theme
* Real-time loading indicator
* Result display with status colors
* Instant feedback notifications
* Responsive mobile design

#### **Result Colors**

| Result    | Color     | Description                    |
| --------- | --------- | ------------------------------ |
| POSITIVE  | 🔴 Red    | Player tested positive for GSR |
| NEGATIVE  | 🟢 Green  | Player tested negative         |
| NOT FOUND | 🟡 Yellow | Player not in database         |
| ERROR     | 🟠 Orange | Server error occurred          |

***

### **API Exports**

```lua
-- Check if player has GSR
exports('CheckGSRStatus', function(serverID)
    return CheckGSRStatus(serverID)
end)

-- Set player as positive
exports('SetGSRStatus', function(serverID, licenseID, discordID)
    SetPlayerGSRData(serverID, licenseID, discordID, true)
end)

-- Reset player GSR
exports('ResetGSRStatus', function(serverID)
    ResetPlayerGSR(serverID)
end)
```

***

### **Events**

#### **Client Events**

| Event                    | Description                           |
| ------------------------ | ------------------------------------- |
| `gsr:setPositive`        | Set player GSR positive (fired)       |
| `gsr:resetGSR`           | Reset player GSR (hand wash)          |
| `gsr:requestCheck`       | Request GSR check from server         |
| `gsr:receiveCheckResult` | Receive check result                  |
| `gsr:playAnimation`      | Play GSR test animation               |
| `gsr:notifyPositive`     | Notify all players of positive result |

#### **Server Events**

| Event                 | Description                      |
| --------------------- | -------------------------------- |
| `gsr:sendServerID`    | Client sends their server ID     |
| `gsr:requestServerID` | Server requests client server ID |

***

###

***

### **Performance**

* Minimal CPU impact (<1ms per tick)
* Efficient JSON encoding/decoding
* Optimized network event throttling
* File I/O only on data changes

***

### **Support**

For issues or feature requests, check:

1. Server console output
2. `data/gsr_logs.txt`
3. `data/gsr.json` for data integrity

***

###

***

### **License**

Created for educational and roleplay server use.

***

**Enjoy your enhanced GSR system! 🎯**


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.cashjundi.xo.je/gsr-testing-system.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
