Skip to content

Refactor: Improve Adjustments loop | Add: Ratelimiting for important Events#1779

Open
mattibat wants to merge 5 commits intoesx-framework:devfrom
mattibat:dev
Open

Refactor: Improve Adjustments loop | Add: Ratelimiting for important Events#1779
mattibat wants to merge 5 commits intoesx-framework:devfrom
mattibat:dev

Conversation

@mattibat
Copy link
Copy Markdown

@mattibat mattibat commented Apr 12, 2026

Description

Adjustments run in 1 loop instead of 2. Ratelimiting for important events with discord log


Motivation

Using 1 loop instead of 2 is self explaining for performance purposes. Idk why i made Rate limiting, since i did it for a project a year ago, wouldnt be bad to get it implemented since it has a purpose.


Usage Example

for the rate limiting:

if Config.EnableRateLimit then
    if IsRateLimited(source, event, maxRequests, windowMs) then
        return
    end
end

PR Checklist

  • My commit messages and PR title follow the Conventional Commits standard.
  • My changes have been tested locally and function as expected.
  • My PR does not introduce any breaking changes.
  • I have provided a clear explanation of what my PR does, including the reasoning behind the changes and any relevant context.

Copilot AI review requested due to automatic review settings April 12, 2026 21:24
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors client-side “Adjustments” to run frame-based tweaks in a single loop (instead of multiple threads) and introduces server-side per-player/per-event rate limiting with optional Discord logging for key inventory-related events.

Changes:

  • Consolidate ammo display, vehicle reward disabling, and density multiplier updates into one client frame loop.
  • Add an IsRateLimited helper and apply rate limiting to several ESX inventory/weapon-related server events.
  • Add a new Discord webhook category (RateLimit) for rate-limit logs.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
[core]/es_extended/shared/config/logs.lua Adds a RateLimit webhook entry to support Discord logging for rate-limit events.
[core]/es_extended/server/main.lua Implements rate limiting state + logic, cleanup on disconnect, and integrates checks into multiple net events.
[core]/es_extended/client/modules/adjustments.lua Refactors to a single persistent frame loop via FrameAdjustments() and reuses it from prior entrypoints.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +424 to +436
local function IsRateLimited(playerId, eventName, maxRequests, windowMs)
local now = GetGameTimer()
local playerEvents = EventRateLimit[playerId]

if not playerEvents then
playerEvents = {}
EventRateLimit[playerId] = playerEvents
end

local data = playerEvents[eventName]
if not data or now - data.windowStart > windowMs then
playerEvents[eventName] = {
count = 1,
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetGameTimer() wraps around (roughly every ~49 days), so now - data.windowStart > windowMs can become negative after wrap and prevent the window from ever resetting (effectively permanent rate-limit). Consider computing elapsed time with wrap-around handling or using a non-wrapping time source (e.g., os.time() with second granularity, or an explicit wrap-safe delta calculation).

Copilot uses AI. Check for mistakes.
Comment on lines +465 to +467
AddEventHandler("playerDropped", function()
EventRateLimit[source] = nil
end)
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EventRateLimit is only cleared on playerDropped. In multichar/logout flows (esx:playerLogout) the player can keep the same source, so rate-limit state can leak across characters and persist unnecessarily. Consider also clearing EventRateLimit[playerId] in the esx:playerLogout handler (and any other unload path).

Copilot uses AI. Check for mistakes.
Comment on lines 469 to +476
if not Config.CustomInventory then
RegisterNetEvent("esx:updateWeaponAmmo", function(weaponName, ammoCount)
if Config.EnableRateLimit then
if IsRateLimited(source, "esx:updateWeaponAmmo", 25, 1000) then
return
end
end

Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Config.EnableRateLimit is referenced but not defined in the shared config files (no occurrence under shared/config). As-is, the feature can’t be enabled via config without users adding a new key themselves. Consider adding Config.EnableRateLimit (default false) to the appropriate config file (likely shared/config/main.lua) and documenting it alongside the other toggles.

Copilot uses AI. Check for mistakes.
Comment thread [core]/es_extended/server/main.lua
Comment on lines 484 to +490
RegisterNetEvent("esx:giveInventoryItem", function(target, itemType, itemName, itemCount)
if Config.EnableRateLimit then
if IsRateLimited(source, "esx:giveInventoryItem", 8, 1000) then
return
end
end

Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rate-limit parameters are duplicated across multiple events (same if Config.EnableRateLimit + IsRateLimited(...) pattern with hardcoded thresholds). Consider centralizing per-event limits in a table/config and/or adding a small helper wrapper to reduce repetition and make tuning easier.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants