Double Trigger Problem

Hey i have a Problem, my Clientside Trigger Clientevents sometime’s 2 times.

But i don’t know why

Here is a example

CLIENT SCRIPT STARTED
CLIENT SCRIPT STARTED
CLIENT SCRIPT STARTED
CLIENT SCRIPT STARTED
CLIENT SCRIPT STARTED
ShutDownLoadingScreen aufgerufen
ShutDownLoadingScreen aufgerufen

public class Events : BaseScript
{
    private static bool _initialized = false; 
    private int lastCleanup = 0;
    int npc;
    int cam;
    bool interactionActive = false;
    Vector3 npcPos = new Vector3(-506.089f, -255.642f, 35.648f);

    public Events()
    {
        EventHandlers.Add("onClientResourceStart", new Action<string>(OnClientResourceStart));
    }
    private void OnClientResourceStart(string resourceName)
    {
        Debug.WriteLine("CLIENT SCRIPT STARTED");
    }

Someone have a Idea to fix it ?

I have had wrongly placed the resource .dll in my resource folder twice after renaming the project and being used to it being overwritten. That didn’t break but doubled most of my msg’s etc.

The onClientResourceStart event fires once for every client resource that is started, not just the resource you registered the event handler in. To check for your current resource, you need to compare the resourceName parameter (which you have, but are not using) against API.GetCurrentResourceName().

That said though, if your aim is to execute code when the resource starts, all you need to do is have it inside your Events constructor :slightly_smiling_face:

@ChristopherM Yea i debug it and than i see it, bevor the Npc spawn 2 Time’s and it ShutDownLoadingScreen called 2 Time’s

CLIENT SCRIPT STARTED: monitor
CLIENT SCRIPT STARTED: chat
CLIENT SCRIPT STARTED: ReallifeGamemode
CLIENT SCRIPT STARTED (ONCE)
CLIENT SCRIPT STARTED: ReallifeGamemode
CLIENT SCRIPT STARTED: Map
ShutDownLoadingScreen aufgerufen

I doin’g now this an it’s fine

private void OnClientResourceStart(string resourceName)
{
    Debug.WriteLine($"CLIENT SCRIPT STARTED: {resourceName}");

    if (API.GetCurrentResourceName() != resourceName) return;

    if (_initialized) return;
    _initialized = true;

    Debug.WriteLine("CLIENT SCRIPT STARTED (ONCE)");

In FiveM C#, each BaseScript instance can attach handlers. If the class is constructed multiple times, then:

  • one event

  • multiple registered handlers

  • same callback prints multiple times

So the issue is usually not “triggered twice,” but “subscribed twice.”

public class Events : BaseScript
{
    private static bool _initialized = false;

    public Events()
    {
        if (_initialized)
            return;

        _initialized = true;
        EventHandlers["onClientResourceStart"] += new Action<string>(OnClientResourceStart);
    }

    private void OnClientResourceStart(string resourceName)
    {
        if (API.GetCurrentResourceName() != resourceName)
            return;

        Debug.WriteLine("CLIENT SCRIPT STARTED");
    }
}

If ShutDownLoadingScreen aufgerufen is coming from another event, that event is probably also being registered multiple times somewhere.

So check every place where you do:

EventHandlers.Add(...)

or

EventHandlers["eventName"] += ...
2 Likes

Good to hear, but as I mentioned, you don’t need to do all that; this will achieve the same thing:

public class Events : BaseScript
{
    private int lastCleanup = 0;
    int npc;
    int cam;
    bool interactionActive = false;
    Vector3 npcPos = new Vector3(-506.089f, -255.642f, 35.648f);

    public Events()
    {
        Debug.WriteLine("CLIENT SCRIPT STARTED");
    }
}

The constructor only runs once :+1:

Edit: Unless of course you instantiate the class multiple times, then of course the constructor wil also run multiple times, but you can avoid that by only instantiating the class once.

1 Like

Your event is firing multiple times because onClientResourceStart triggers for every resource that starts on the client, not just yours you need to add a check to make sure it only runs when your own resource starts also you already have that _initialized bool declared but never used it so use it to prevent any duplicate calls.

private void OnClientResourceStart(string resourceName)
{
if (resourceName != API.GetCurrentResourceName()) return;
if (_initialized) return;
_initialized = true;

Debug.WriteLine("CLIENT SCRIPT STARTED");

}

That should fix both issues.

1 Like

Thanks now it’s only start one time.

But i have a Problem with the Spawn from the Scooter. Somtime’s the Faggio Spawn and i am in the Car and the Numberplate is right but Sometime’s it’s not working.

I am Sitting i a NPC Car and the Number Plate is on this Car. But i don’t know the Reason.

The Call from the Client Side

TriggerServerEvent(“rentroller:spawn”, spawnPos);

The Rent Roller Server Side

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using CitizenFX.Core;
using CitizenFX.Core.Native;
using static CitizenFX.Core.Native.API;

namespace FiveMGamemodeServer.Rentroller
{
    internal class Rentroller : BaseScript
    {
        // Spieler → Fahrzeug
        private static Dictionary<int, int> playerVehicles = new Dictionary<int, int>();

        public Rentroller()
        {
            Debug.WriteLine("[Rentroller] Script geladen"); 
            EventHandlers["rentroller:spawn"] += new Action<Player, Vector3>(SpawnVehicle);
            EventHandlers["rentroller:return"] += new Action<Player>(ReturnVehicle);
            EventHandlers["playerDropped"] += new Action<Player, string>(OnPlayerDropped);
        }
        public void SpawnVehicle([FromSource] Player player, Vector3 pos)
        {
            int source = int.Parse(player.Handle);

            Debug.WriteLine($"[Rentroller] SpawnVehicle aufgerufen von {player.Name}");

            if (playerVehicles.ContainsKey(source))
            {
                int existingVehicle = playerVehicles[source];

                if (DoesEntityExist(existingVehicle))
                {
                    SendChat(player, "❌ Du hast bereits einen Rentroller.");
                    TriggerClientEvent(player, "fcnr:ShowNotification", "Roller Mieten", "❌ Du hast bereits ein Roller gemietet.", "error");
                    return;
                }

                playerVehicles.Remove(source);
            }

            int ped = GetPlayerPed(player.Handle);

            uint model = (uint)GetHashKey("faggio");

            int vehicle = CreateVehicle(model, pos.X, pos.Y, pos.Z, GetEntityHeading(ped), true, true);

            if (vehicle == 0)
            {
                Debug.WriteLine("[Rentroller] Vehicle Spawn fehlgeschlagen");
                return;
            }

            SetVehicleNumberPlateText(vehicle, "RENT");
            SetPedIntoVehicle(ped, vehicle, -1);

            playerVehicles[source] = vehicle;

            Debug.WriteLine($"[Rentroller] Roller gespawnt für {player.Name}");

            TriggerClientEvent(player, "Roller Mieten", "Du hast dir erfolreich ein Roller gemietet.", "success");
            SendChat(player, "🛴 Dein Rentroller wurde gespawnt.");
            return;
        }

        private void ReturnVehicle([FromSource] Player player)
        {
            int source = int.Parse(player.Handle);

            if (!playerVehicles.ContainsKey(source))
            {
                SendChat(player, "❌ Du hast keinen Rentroller.");
                return;
            }

            int vehicle = playerVehicles[source];

            if (DoesEntityExist(vehicle))
            {
                DeleteEntity(vehicle);
            }

            playerVehicles.Remove(source);

            SendChat(player, "🛴 Rentroller zurückgegeben.");
        }

        private void OnPlayerDropped(Player player, string reason)
        {
            int source = int.Parse(player.Handle);

            if (!playerVehicles.ContainsKey(source))
                return;

            int vehicle = playerVehicles[source];

            if (DoesEntityExist(vehicle))
            {
                DeleteEntity(vehicle);
            }

            playerVehicles.Remove(source);

            Debug.WriteLine($"[Rentroller] Roller gelöscht (Disconnect) {player.Name}");
        }

        private void SendChat(Player player, string message)
        {
            TriggerClientEvent(player, "chat:addMessage", new
            {
                args = new[] { "RENT", message }
            });
        }
    }

}

hey timing/sync issue CreateVehicle + SetPedIntoVehicle back to back doesn’t work because the vehicle hasn’t synced to the client yet so it either fails or puts you in the nearest car (the npc one) with the plate on it

server side (c#)

public async void SpawnVehicle([FromSource] Player player, Vector3 pos)
{
    int source = int.Parse(player.Handle);
    if (playerVehicles.ContainsKey(source))
    {
        int existingVehicle = playerVehicles[source];
        if (DoesEntityExist(existingVehicle))
        {
            TriggerClientEvent(player, "fcnr:ShowNotification", "Roller Mieten", "❌ Du hast bereits ein Roller gemietet.", "error");
            return;
        }
        playerVehicles.Remove(source);
    }
    int ped = GetPlayerPed(player.Handle);
    uint model = (uint)GetHashKey("faggio");
    int vehicle = CreateVehicle(model, pos.X, pos.Y, pos.Z, GetEntityHeading(ped), true, true);
    if (vehicle == 0) return;
    await Delay(500); // wait for entity to sync
    if (!DoesEntityExist(vehicle)) return;
    SetEntityAsMissionEntity(vehicle, true, true); // prevent cleanup
    SetVehicleNumberPlateText(vehicle, "RENT");
    SetPedIntoVehicle(ped, vehicle, -1);
    playerVehicles[source] = vehicle;
    int netId = NetworkGetNetworkIdFromEntity(vehicle);
    TriggerClientEvent(player, "rentroller:enterVehicle", netId); // client warp fallback
    TriggerClientEvent(player, "fcnr:ShowNotification", "Roller Mieten", "Du hast dir erfolgreich einen Roller gemietet.", "success");
    SendChat(player, "🛴 Dein Rentroller wurde gespawnt.");
}

client side (lua)

AddEventHandler("rentroller:enterVehicle", function(netId)
    local vehicle = NetToVeh(netId)
    if DoesEntityExist(vehicle) then
        TaskWarpPedIntoVehicle(PlayerPedId(), vehicle, -1)
    end
end)

async + await Delay(500) gives fivem time to sync the entity and SetEntityAsMissionEntity stops the vehicle getting garbage collected and client side enterVehicle fallback warp if server side fails

hope that helps

1 Like