الوثائق 9.6.24
الأحداث والمشغّلات (triggers)
الأحداث التي يطلقها Tosun AntiCheat لكي تستمع لها سكربتاتك، والأحداث التي يمكنك إطلاقها للتكامل معه، وقوائم الإعدادات التي تربط أحداثك الخاصة بالإعفاءات وفحص المفاتيح وحدود المعدل والمصائد. أحداث مكافحة الغش الداخلية محمية ويجب عدم استدعائها.
نظرة عامة#
في FiveM توجد أحداث محلية (local) وأحداث شبكة (net). الحدث المحلي يبقى في جانب واحد من اللعبة: يطلقه TriggerEvent ويستقبله AddEventHandler. حدث الشبكة يعبر الشبكة: يرسله الخادم عبر TriggerClientEvent، ويرسله العميل عبر TriggerServerEvent، ويجب على الجانب المستقبِل تسجيله عبر RegisterNetEvent. يستخدم Tosun AntiCheat النوعين، على الخادم وعلى العميل.
تعرض هذه الصفحة الأحداث التي يطلقها مكافح الغش لتستمع لها، والأحداث التي يمكنك إطلاقها لدمج سكربتاتك، وقوائم الإعدادات (ts.DetectionExempt و ts.ProtectedEvents و ts.EventLimiter و ts.triggerList) التي تحوّل أسماء أحداثك الخاصة إلى إعفاءات أو فحوص مفاتيح أو حدود معدل أو مصائد.
يسجّل مكافح الغش أيضًا أحداثًا داخلية كثيرة من أجل مصافحة الانضمام وتبادل المفاتيح و Shield وقائمة الإدارة وإجراءات لوحة الويب. هي محمية بـ nonces أو مفاتيح أو تواقيع أو حدود معدل أو فحوص الطاقم، وبعضها مصائد. ليست جزءًا من واجهة التكامل: لا تطلقها، ولا تسجّل معالجات عليها، ولا تعِد استخدام أسمائها. استخدم الـ exports بدلًا منها.
| النوع | يُطلق بواسطة | يُستقبل بواسطة | من يمكنه إطلاقه |
|---|---|---|---|
| حدث محلي على الخادم | TriggerEvent | AddEventHandler | أي مورد على الخادم. |
| حدث محلي على العميل | TriggerEvent | AddEventHandler | أي سكربت عميل في لعبة ذلك اللاعب، بما في ذلك كود الغش المحقون. |
| حدث شبكة، من العميل إلى الخادم | TriggerServerEvent | RegisterNetEvent + AddEventHandler | أي لاعب متصل، مع أي وسائط. |
| حدث شبكة، من الخادم إلى العميل | TriggerClientEvent | RegisterNetEvent + AddEventHandler | أي مورد على الخادم. يمكن لسكربت العميل أيضًا إطلاق الاسم نفسه محليًا عبر TriggerEvent. |
مهام التكامل الشائعة#
اختر الحدث أو الإعداد الذي يطابق ما تريد فعله. كل منها موصوف بالتفصيل في الأسفل من هذه الصفحة.
| الهدف | استخدم |
|---|---|
| التفاعل عندما ينتهي اكتشاف بحظر أو طرد أو سطر سجل | ts_anticheat:playerBanned |
| التفاعل فقط عند إصدار حظر فعلي | ts_anticheat:banCommitted |
| التفاعل مع رفع الحظر | ts_anticheat:playerUnbanned |
| نسخ موجز السجل المباشر | ts_anticheat:newLog |
| تحديث ذاكرتك المؤقتة عندما يعيد مكافح الغش تطبيق الإعدادات | tosun-ac:settingsReloaded / ts_anticheat:configUpdated |
| تطبيق إعادة تسمية شخصية من اللوحة على إطار عمل مخصص | tosun-ac:renameCharacter |
| تشغيل فحوص العميل بعد ظهور (spawn) مخصص | playerSpawned |
| تحديث اللوحة بعد اختيار شخصية مخصص | tosun-ac:panel:characterReady |
| جعل العميل يعيد فحص حالة الطاقم | ts_anticheat:adminStateChanged |
| إعفاء لاعب على العميل من سكربت الخادم الخاص بك | tosun-ac:bridge:clientExempt |
| إعفاء اللاعبين تلقائيًا عند إطلاق حدث القائمة أو الإجراء الخاص بك | ts.DetectionExempt |
| اشتراط مفتاح لكل لاعب على حدثك الخاص من العميل إلى الخادم | ts.ProtectedEvents + <name>:safe |
أحداث الخادم التي يطلقها مكافح الغش#
هذه أحداث محلية على الخادم. استمع لها عبر AddEventHandler في أي سكربت خادم. لا تطلقها بنفسك؛ راجع أقسام الأمان أدناه.
| الحدث | متى يُطلق | البيانات |
|---|---|---|
ts_anticheat:playerBanned | مع كل نتيجة اكتشاف: BAN و KICK و LOG. يُطلق قبل الطرد وإدراج الحظر والسجلات. لا يُطلق للاعبين المتخطَّين لأنهم من الطاقم أو في القائمة البيضاء. | جدول data: playerId (string)، playerName، reason، banID، side ('server')، punishment ('BAN' أو 'KICK' أو 'LOG') |
ts_anticheat:banCommitted | مع نتائج BAN فقط (الاكتشافات و exports ban و punish)، مباشرة بعد وضع إدراج سجل الحظر في الطابور وقبل webhook اللوحة والطرد. | playerId (number)، جدول row: banID، playerName، reason، license، steam، discord، ip، HWID، من HWID2 إلى HWID5، config (مفتاح إعداد الاكتشاف) |
ts_anticheat:playerUnbanned | بعد أن يزيل export unban أو الأمر /ts unban أو القائمة داخل اللعبة حظرًا. رفع الحظر من لوحة الويب لا يطلقه. | banID (القيمة الممرَّرة إلى export unban، دون تغيير) |
ts_anticheat:newLog | مع كل سطر سجل مباشر: الاكتشافات، وأسطر سجل العميل، وإجراءات قائمة الإدارة، وبعض الأسطر الداخلية لمكافح الغش. | جدول payload: src (تسمية فئة، وليس معرّف لاعب)، event (نص الرسالة)، status (الافتراضي 'Info')، playerName، time (os.time()) |
tosun-ac:settingsReloaded | بعد أن تعيد مزامنة الإعدادات تطبيقها. يحدث هذا عند بدء التشغيل وفي كل دورة مزامنة تقريبًا، وليس فقط عند تغيّر شيء. | لا يوجد |
ts_anticheat:shield:screenshot_saved | وصلت لقطة شاشة Shield مطلوبة واجتازت الفحوص. | src (number)، b64 (صورة base64، من 64 إلى 2,500,000 حرف) |
ts_anticheat:shield:ban_video_saved | تم رفع فيديو اللعب للاعب مطرود أو محظور خلال 120 ثانية. | src (number)، videoUrl، reason، config (القيمتان reason و config تأتيان من العميل) |
<name>:safe | اجتاز استدعاء لحدث مدرج في ts.ProtectedEvents فحص المفتاح والبيانات. | src (number، معرّف لاعب متصل)، ثم الوسائط الأصلية بعد المفتاح |
tosun-ac:renameCharacter | إعادة تسمية شخصية من لوحة الويب على إطار عمل غير qb و qbcore و qbox و qbx و esx. | citizenid (string)، firstName (الكلمة الأولى)، lastName (بقية الاسم، وقد يكون '') |
أحداث العميل التي يطلقها مكافح الغش#
تصل هذه الأحداث إلى سكربتات العميل. ts_anticheat:configUpdated حدث محلي على العميل؛ استمع له عبر AddEventHandler. ts_anticheat:receiveEventKey حدث شبكة من الخادم؛ سجّله عبر RegisterNetEvent في سكربت العميل الخاص بك.
| الحدث | النوع | متى يُطلق | البيانات |
|---|---|---|---|
ts_anticheat:configUpdated | حدث محلي على العميل | بعد أن يطبّق العميل الإعدادات القادمة من الخادم ويعيد فحص روابط DetectionExempt الخاصة به. توقّعه مرة واحدة تقريبًا في كل فترة مزامنة. | لا يوجد |
ts_anticheat:receiveEventKey | حدث شبكة، من الخادم إلى العميل | ردًا على ts_anticheat:requestEventKey (طلبك أو طلب مكافح الغش نفسه)، وكلما أصدر الخادم مفتاحًا جديدًا للاعب. يصل بعد مصافحة الانضمام. | key (string، مفتاح SafeEvents الخاص باللاعب) |
مثال على مستمع#
سكربت خادم يتفاعل مع الطرد والحظر، وسكربت عميل يُفرغ ذاكرة مؤقتة عندما يعيد مكافح الغش تطبيق الإعدادات. كل مستمع على الخادم يتحقق أولًا من أن مكافح الغش هو من أطلق الحدث.
-- server.lua (المورد الخاص بك)
local AC = 'tosun-ac' -- اسم مورد (مجلد) مكافح الغش
AddEventHandler('ts_anticheat:playerBanned', function(d)
if GetInvokingResource() ~= AC then return end -- تجاهل الاستدعاءات المزوّرة
if d.punishment == 'LOG' then return end
print(('[AC] %s %s: %s'):format(d.punishment, d.playerName, d.reason))
end)
AddEventHandler('ts_anticheat:banCommitted', function(playerId, row)
if GetInvokingResource() ~= AC then return end
print('AC ban', row.banID, row.license, row.reason)
end)
-- client.lua (المورد الخاص بك)
local myCache
AddEventHandler('ts_anticheat:configUpdated', function()
myCache = nil
end)playerBanned بالتفصيل#
الاسم تاريخي. ts_anticheat:playerBanned يُطلق مع كل نتيجة اكتشاف، وليس مع الحظر فقط. رشّح حسب data.punishment.
data.playerId من نوع string. حوّله عبر tonumber قبل استخدامه كمعرّف خادم.
يُطلق الحدث قبل الإجراء. البث في الدردشة والسجلات و DropPlayer وإدراج الحظر تعمل بعد المعالج الخاص بك.
لا يُطلق عندما يكون الهدف غير متصل، أو عندما يُتخطّى اللاعب لأنه من الطاقم (يُتخطّى الطاقم ما لم يكن ts.AdminBypassDetections هو false أو كان ts.Debug مفعّلًا)، أو عندما يكون اللاعب في القائمة البيضاء المؤقتة أو القائمة البيضاء للوحة.
يُولَّد banID لكل نتيجة لكنه يُحفظ فقط مع BAN. طرد (KICK) عضو من الطاقم يُلغى بعد أن يكون الحدث قد أُطلق بالفعل.
أثناء عرض شاشة الحظر (editable/server/sv_banscreen.lua) على لاعب، تُبتلع معظم الاكتشافات التالية لذلك اللاعب ولا يُطلق أي حدث لها.
banCommitted بالتفصيل#
ts_anticheat:banCommitted هو أفضل نقطة ربط لحالة 'تم إصدار حظر فعلي'. استخدم playerBanned للطرد وأسطر السجل.
يُطلق مع كل نتيجة BAN في مسار العقوبات لمكافح الغش: الاكتشافات و exports ban و punish. الحظر دون اتصال (exports offlineBan و offlineBanByLicense) والحظر من لوحة الويب لا يطلقانه.
يوضع إدراج سجل الحظر في الطابور عبر MySQL.Async.execute دون انتظاره، لذا قد لا يكون السجل في قاعدة البيانات بعد عند تشغيل المعالج الخاص بك.
المعرّفات في row تُزال بادئتها (license: و license2: و steam: و discord: و ip:). المعرّف أو الرمز المفقود يكون النص الإنجليزي 'Not found'؛ والـ ip المفقود يكون 'Hidden'. القيم من HWID إلى HWID5 هي رموز اللاعب الخام.
newLog و settingsReloaded بالتفصيل#
يُطلق الحدثان كثيرًا. اجعل معالجاتهما خفيفة.
ts_anticheat:newLog: الحقل src تسمية فئة، وليس معرّف لاعب. الاكتشافات تستخدم 'DETECTION' مع status من BAN أو KICK أو LOG. أسطر سجل العميل تستخدم وسمًا وحالة ثابتين: 'AntiCheat' مع 'Tespit' (كلمة تركية ثابتة تعني 'Detection')، و 'AC-Grace' مع 'Info'، و 'AC-FakeTrigger' مع 'Warning'. إدخالات قائمة الإدارة تستخدم عادةً اسم المشرف مع status من BAN أو KICK أو INFO أو SUCCESS. بعض الأسطر الداخلية تستخدم فئات أخرى.
tosun-ac:settingsReloaded: لا يقارن مكافح الغش القيم القديمة بالجديدة، لذا يُطلق الحدث بعد مزامنة البدء وفي معظم دورات المزامنة، كل ts.ServerPerf.configSyncIntervalSec ثانية (120 في الإعدادات المرفقة، و 60 إذا كان المفتاح مفقودًا، والحد الأدنى 20). افهمه على أنه 'أُعيد تطبيق الإعدادات' وليس 'تغيّرت الإعدادات'.
بعد كل مزامنة من هذا النوع يرسل الخادم أيضًا الإعدادات إلى كل العملاء، ثم يطلق كل عميل ts_anticheat:configUpdated.
إذا أطلق مورد آخر على الخادم tosun-ac:settingsReloaded، يُجري مكافح الغش تحديثًا كاملًا لصلاحيات الطاقم لكل لاعب متصل.
أحداث لقطات الشاشة والفيديو في Shield#
يتطلب الحدثان Shield (ts.shield.enabled ليس false؛ وهو مفعّل في الإعدادات المرفقة).
ts_anticheat:shield:screenshot_saved: اطلب لقطة شاشة عبر export الخادم RequestShieldScreenshot(src). يجب أن تصل الصورة خلال 60 ثانية من الطلب، ويقبل مكافح الغش لقطة واحدة على الأكثر كل 20 ثانية لكل لاعب. يمكن للوحة الويب طلب لقطات شاشة أيضًا، وهي تطلق الحدث كذلك.
ts_anticheat:shield:ban_video_saved: يتطلب ts.shield.banGameplayVideo ليس false (مفعّل في الإعدادات المرفقة). تُفتح نافذة الرفع لمدة 120 ثانية بعد KICK أو BAN، ويجب أن يطابق مضيف رابط الفيديو مضيف اللوحة.
القيمتان reason و config في ban_video_saved تأتيان من العميل ولا يُتحقق من نوعهما ولا تُقتطعان. تعامل معهما كنص غير موثوق.
local AC = 'tosun-ac'
-- الخادم: اطلب لقطة شاشة من لعبة اللاعب
exports[AC]:RequestShieldScreenshot(src)
AddEventHandler('ts_anticheat:shield:screenshot_saved', function(src, b64)
if GetInvokingResource() ~= AC then return end
-- b64 نص صورة بترميز base64
end)إعادة تسمية الشخصية على إطار عمل مخصص#
يمكن للوحة الويب إعادة تسمية شخصية. مع qb و qbcore و qbox و qbx يحدّث مكافح الغش players.charinfo؛ ومع esx يحدّث users.firstname و users.lastname. ومع أي قيمة أخرى لـ ts.Framework.framework يطلق tosun-ac:renameCharacter لتطبّق إعادة التسمية بنفسك.
يُبلغ مكافح الغش اللوحة بـ 'event_emitted_unknown_fw' سواء وُجد مستمع أم لا.
تُزال أحرف التحكم من الاسم الجديد، ويُحدّ بـ 64 حرفًا، ويجب ألا يقل عن 3 أحرف. firstName هي الكلمة الأولى؛ و lastName هو الباقي وقد يكون فارغًا.
يستخدم المثال استدعاء MySQL.update من oxmysql وجدول characters مفترضًا. عدّل الاستعلام ليناسب مخطط قاعدة بياناتك.
AddEventHandler('tosun-ac:renameCharacter', function(cid, first, last)
if GetInvokingResource() ~= 'tosun-ac' then return end
MySQL.update('UPDATE characters SET first = ?, last = ? WHERE cid = ?', { first, last, cid })
end)أحداث يمكنك إطلاقها#
هذه أحداث مكافح الغش المخصّصة لتطلقها سكربتاتك. أحداث الموت والإحياء الخاصة بإطار العمل وأحداث ts.DetectionExempt الخاصة بك مشروحة في أقسامها.
| الحدث | يُطلق من | التأثير | الحدود |
|---|---|---|---|
tosun-ac:panel:characterReady | العميل، عبر TriggerServerEvent. | يحدّث بيانات شخصية اللاعب في قائمة اللاعبين المتصلين في اللوحة. | استدعاء واحد كل 20 ثانية لكل لاعب. |
ts_anticheat:locale:setSelf | العميل، عبر TriggerServerEvent مع رمز لغة. | يضبط لغة رسائل خادم مكافح الغش لذلك اللاعب فقط. يطبع سطرًا في وحدة تحكم الخادم. | لا يوجد حد للمعدل. يجب أن يكون الرمز حرفين أو 3 أحرف صغيرة مع وجود ملف locales/<lang>.json. |
ts_anticheat:requestEventKey | العميل، عبر TriggerServerEvent. | يعيد إرسال مفتاح SafeEvents الخاص باللاعب عبر ts_anticheat:receiveEventKey. | استدعاء واحد كل 3 ثوانٍ لكل لاعب. يذهب المفتاح فقط إلى اللاعب الطالب. |
playerSpawned | العميل، عبر TriggerEvent (محلي). | يشغّل معظم فحوص العميل ويبدأ نافذة السماح بعد الظهور (spawn). | كل مورد آخر على ذلك العميل يستقبله أيضًا. |
ts_anticheat:adminStateChanged | الخادم، عبر TriggerClientEvent إلى لاعب واحد. | يطلب العميل من الخادم مجددًا حالة الطاقم الحقيقية الخاصة به. | يجيب الخادم مرة واحدة على الأكثر في الثانية لكل لاعب. |
tosun-ac:bridge:clientExempt | الخادم، عبر TriggerClientEvent؛ يتطلب ملف الجسر (bridge) في موردك. | إعفاء على جانب العميل لذلك اللاعب. | من 500 إلى 300000 ms. |
ظهور مخصص: playerSpawned#
تبقى معظم فحوص العميل متوقفة حتى يرى مكافح الغش الحدث المحلي playerSpawned: regen و godmode و teleport و invisibility و freecam و weapons و OCR و native و coords و vehicle godmode. عادةً يطلقه spawnmanager.
إذا كان نظام الظهور أو تعدد الشخصيات لديك لا يستخدم spawnmanager، فأطلق playerSpawned محليًا بمجرد أن يصبح اللاعب في العالم، أو استدعِ export العميل SetSpawned(true).
يبدأ playerSpawned أيضًا نافذة السماح بعد الظهور ts.spawnGraceSecondsMs. القيمة المرفقة 500، ويرفعها الكود إلى حدها الأدنى 5000 ms؛ وبدون المفتاح يستخدم الكود 25000. الاكتشاف داخل النافذة لا يُلغى، بل يضيف فقط سطر سجل 'AC-Grace'.
يمسح playerSpawned أيضًا حالة الموت لدى مكافح الغش ويعلّم نقلًا (teleport) على العميل.
قائمة ts.DetectionExempt.clientEvents المرفقة تحتوي playerSpawned، لذا يبدأ كل playerSpawned أيضًا إعفاءً للعميل لمدة defaultDurationMs (60 ثانية).
يسري SetSpawned(false) مرة واحدة على الأكثر كل 5 دقائق، وتعود الفحوص للعمل بعد نحو 30 ثانية من الحركة المرئية.
-- العميل، بعد منطق الظهور الخاص بك
TriggerEvent('playerSpawned')
-- أو، دون الآثار الجانبية على الموارد الأخرى
exports['tosun-ac']:SetSpawned(true)تعدد شخصيات مخصص: characterReady#
على الخادم يستمع مكافح الغش إلى QBCore:Server:OnPlayerLoaded و QBCore:Server:PlayerLoaded و esx:playerLoaded و qbx_core:server:playerLoaded. كل منها يدفع الشخصية المحمّلة إلى قائمة اللاعبين المتصلين في اللوحة فورًا. سكربت تعدد الشخصيات المخصص الذي لا يطلق أيًا منها يجب أن يطلق tosun-ac:panel:characterReady من العميل بعد اختيار الشخصية.
كل استدعاء يكتب سجل اللاعب في قاعدة البيانات، وعندما يكون رابط اللوحة ومفتاحها مضبوطين يرسل طلب HTTPS إلى اللوحة. لذلك يقبل الخادم استدعاءً واحدًا كل 20 ثانية لكل لاعب ويتجاهل الباقي.
-- العميل، بعد انتهاء اختيار الشخصية
TriggerServerEvent('tosun-ac:panel:characterReady')لغة اللاعب: locale:setSelf#
يمكن للعميل اختيار لغة رسائل خادم مكافح الغش لنفسه. عند النجاح يطبع الخادم سطرًا في وحدة تحكم الخادم.
يغيّر فقط رسائل الخادم المرسلة إلى ذلك اللاعب. لا يغيّر لغة جانب العميل.
عميل مكافح الغش نفسه لا يرسل هذا الحدث. البدائل على جانب الخادم هي export setPlayerLocale والأمر ts_setlang.
-- العميل
TriggerServerEvent('ts_anticheat:locale:setSelf', 'en')تغييرات الطاقم: adminStateChanged#
بعد أن يمنح سكربت الإدارة الخاص بك صلاحيات الطاقم أو يزيلها، اطلب من عميل اللاعب إعادة فحص حالة الطاقم. لا يستطيع الحدث تغيير الحالة بنفسه: يرسل العميل nonce جديدًا إلى الخادم، ورد الخادم وحده هو الذي يقرر.
لا شيء في مكافح الغش يرسل هذا الحدث. العميل يعيد الفحص من تلقاء نفسه كل 20 ثانية، لذا يزيل الاستدعاء هذا التأخير فقط.
الغش الذي يطلقه محليًا لا يكسب شيئًا؛ يجيب الخادم على الفحص مرة واحدة على الأكثر في الثانية لكل لاعب.
-- الخادم، بعد تغيير صلاحيات الطاقم لـ src
TriggerClientEvent('ts_anticheat:adminStateChanged', src)حدث الجسر: tosun-ac:bridge:clientExempt#
ملف الجسر الخاص بالعميل يسجّل حدث الشبكة هذا داخل موردك. يرسله سكربت الخادم الخاص بك إلى لاعب، ويستدعي الجسر export العميل SetExempt الخاص بمكافح الغش لذلك اللاعب.
durationMs رقم بالـ ms أو اسم إعداد مسبق بأي حالة أحرف: SHORT أو MEDIUM أو LONG أو XL (30 أو 60 أو 120 أو 180 ثانية). تُحصر القيم بين 500 و 300000 ms. بدون قيمة يُطبَّق الافتراضي من الـ convar (60000).
مفتاح الإعفاء هو 'bridge:' متبوعًا بـ tag، أو باسم موردك عندما يكون tag هو nil.
هذا إعفاء على جانب العميل فقط. فحوص الخادم تستمر في العمل.
مكافح الغش لا يرسل هذا الحدث أبدًا. إذا كانت عدة موارد لديك تتضمن ملف الجسر، فإن TriggerClientEvent واحدًا يعمل مرة في كل منها.
- أضف client_script '@tosun-ac/bridge/tosun_ac_client.lua' إلى ملف fxmanifest.lua الخاص بموردك.
- اختياري، في server.cfg: إذا غيّرت اسم مجلد مكافح الغش، فأضف setr tosun_ac_resource بالاسم الجديد (الافتراضي tosun-ac). لتغيير المدة الافتراضية، أضف setr tosun_ac_bridge_client_ms بقيمة بالـ ms (الافتراضي 60000).
- من سكربت الخادم الخاص بك، أرسل TriggerClientEvent('tosun-ac:bridge:clientExempt', src, durationMs, tag).
-- الخادم: أعفِ اللاعب لمدة دقيقتين أثناء فتح قائمة الحلاق
TriggerClientEvent('tosun-ac:bridge:clientExempt', src, 'LONG', 'barber')أحداث الموت والإحياء في إطار العمل#
يستمع العميل إلى هذه الأحداث ليعرف متى يكون اللاعب ميتًا أو ساقطًا (downed). أثناء هذه الحالة تُتخطّى فحوص قفزات التجدد (regen-spike) و godmode و teleport و invisibility و spectate وعدة فحوص أخرى على العميل. الموت الأصلي (native) يُلتقط أيضًا عبر حدث الضرر gameEventTriggered.
منذ الإصدار 9.5.9، ينهي مضاد الغش هذه الحالة تلقائيًا بمجرد أن يعود اللاعب إلى نشاط واضح.
يمكن لسكربت إسعاف مخصص إطلاق أحد هذه الأسماء محليًا لمواءمة حالة مكافح الغش. هذه أسماء مشتركة في أطر العمل، لذا يعمل أيضًا كل مورد آخر على ذلك العميل يستمع لها (مثل شاشات الموت في ESX).
| الحدث | النوع | التأثير |
|---|---|---|
hospital:client:isDead | شبكة (Net) | ساقط؛ يبدأ نافذة ما بعد الموت لمدة 25 ثانية. |
hospital:client:SetDeathState | شبكة، مع وسيط boolean | true: ساقط مع نافذة ما بعد الموت لمدة 25 ثانية. false: تم إحياؤه مع نافذة ما بعد الإحياء لمدة 10 ثوانٍ. |
hospital:client:SetLaststand | شبكة، مع وسيط boolean | true: ساقط مع نافذة ما بعد الموت لمدة 25 ثانية (القيمة false تُتجاهل). إضافة إلى إعفاء تلقائي لمدة 45 ثانية. |
qb-medical:client:OnDeath | شبكة (Net) | ساقط؛ يبدأ نافذة ما بعد الموت لمدة 25 ثانية. |
esx:onPlayerDeath | شبكة (Net) | ساقط؛ يبدأ نافذة ما بعد الموت لمدة 25 ثانية. إضافة إلى إعفاء تلقائي لمدة 45 ثانية. |
baseevents:onPlayerDied | محلي (شبكة ما دام autoExempt مفعّلًا) | يبدأ نافذة ما بعد الموت لمدة 25 ثانية. إضافة إلى إعفاء تلقائي لمدة 45 ثانية. |
baseevents:onPlayerKilled | محلي فقط | يبدأ نافذة ما بعد الموت لمدة 25 ثانية. |
hospital:client:Revive | شبكة (Net) | تم إحياؤه؛ يبدأ نافذة ما بعد الإحياء لمدة 10 ثوانٍ. |
qb-ambulancejob:client:RevivePlayer | شبكة (Net) | تم إحياؤه؛ يبدأ نافذة ما بعد الإحياء لمدة 10 ثوانٍ. |
qb-medical:client:OnRevive | شبكة (Net) | تم إحياؤه؛ يبدأ نافذة ما بعد الإحياء لمدة 10 ثوانٍ. |
esx_ambulancejob:revive | شبكة (Net) | تم إحياؤه؛ يبدأ نافذة ما بعد الإحياء لمدة 10 ثوانٍ. |
esx_basicneeds:onRevive | شبكة (Net) | تم إحياؤه؛ يبدأ نافذة ما بعد الإحياء لمدة 10 ثوانٍ. |
playerSpawned | محلي | يمسح حالة السقوط ويُبقي نحو 17 ثانية من نافذة ما بعد الموت. |
-- إسعاف مخصص (العميل)، بعد منطق الإحياء الخاص بك
TriggerEvent('esx_ambulancejob:revive')أحداث الإعفاء التلقائي (autoExempt)#
مع ts.autoExempt.enabled (true في الإعدادات المرفقة) يستمع العميل إلى أحداث أطر العمل الشائعة ويمنح إعفاءً قصيرًا للعميل عبر export SetExempt. اكتشافات العميل أثناء الإعفاء لا تُعاقَب؛ بل يُبلَّغ عنها كأسطر LOG معلَّمة بـ '[exempt]'. اضبط ts.autoExempt.enabled = false لإيقاف ذلك.
التعليق في رأس الملف client/anticheat_auto_exempt.lua يقول إن هذه الأحداث لا يمكن إطلاقها عن بُعد. هذا خطأ: فهي مسجّلة عبر RegisterNetEvent، لذا يمكن للخادم إطلاقها أيضًا. ومع ذلك يبقى التأثير إعفاءً للعميل فقط.
| الحالة | المدة | الأحداث |
|---|---|---|
| قوائم المظهر | 180 ثانية | illenium-appearance:client:openMenu, appearance:client:openMenu, fivem-appearance:client:openMenu, ox_appearance:openMenu |
| قوائم الملابس | 180 ثانية | qb-clothing:client:openMenu, qb-clothes:client:openMenu, rcore_clothing:openClothingShop, clothing:client:openMenu |
| قوائم المظهر (skin) والحلاق في ESX | 180 ثانية | esx_skin:openSaveableMenu, esx_skin:openRestrictedMenu, skinchanger:model:loaded, tgg_barber:open, barbershop:client:open |
| اختيار الشخصية | 30 ثانية | qb-multicharacter:client:chooseChar, qb-multicharacter:client:closeNUIdefault, esx_multicharacter:SetupCharacters, esx:restoreLoadout, ox:playerLoaded, qbx_core:client:playerLoggedOut |
| الموت و laststand (QB، ESX) | 45 ثانية | esx_ambulancejob:setDeathStatus, esx:onPlayerDeath, hospital:client:SetLaststand, hospital:client:OnPlayerLaststand, qb-ambulancejob:client:playerDead |
| الموت (سكربتات أخرى) | 45 ثانية | wasabi_ambulance:clientDeath, ars_ambulancejob:client:dead, baseevents:onPlayerDied, baseevents:onPlayerWasted |
| تحميل الشخصية | 15 ثانية | QBCore:Client:OnPlayerLoaded, qbx_core:client:playerLoaded, esx:playerLoaded, ox:playerLoaded |
| بدء مكافح الغش على العميل | 60 ثانية | onClientResourceStart |
بوابة الانضمام: أحداث تحميل إطار العمل#
مع ts.NetworkJoin.waitForFrameworkLoaded (true في الإعدادات المرفقة) وإطار عمل qb أو qbox أو esx، ينتظر العميل حدث تحميل إطار العمل قبل أن يُكمل الانضمام إلى مكافح الغش. هذا يؤخر بدء كل حماية العميل لذلك اللاعب. قيم إطار العمل الأخرى تتخطى الانتظار.
بعد minReadyDelayMs (15 ثانية في الإعدادات المرفقة) وانتهاء شاشة التحميل، ينتظر العميل أحد أحداث التحميل، أو LocalPlayer.state.isLoggedIn (qb، qbox) أو ESX.PlayerLoaded (esx)، حتى 180 ثانية إجمالًا. ثم ينتظر postFrameworkSettleMs (5 ثوانٍ في الإعدادات المرفقة) وتحميل التصادم (collision) قبل أن يُبلغ بأنه جاهز.
| إطار العمل | أحداث التحميل | أحداث إعادة الضبط |
|---|---|---|
qb | QBCore:Client:OnPlayerLoaded | QBCore:Client:OnPlayerUnload |
qbox | QBCore:Client:OnPlayerLoaded, qbx_core:client:playerLoggedIn, qbx_multicharacter:client:chooseChar | QBCore:Client:OnPlayerUnload |
esx | esx:playerLoaded | esx:onPlayerLogout |
الأحداث المحمية (SafeEvents)#
يجعل ts.ProtectedEvents مكافح الغش يتحقق من مفتاح خاص بكل لاعب على أحداثك الخاصة من العميل إلى الخادم. الاستدعاء الذي ينجح يُطلق مجددًا على الخادم كحدث محلي '<name>:safe' مع معرّف اللاعب أولًا. القائمة المرفقة تحتوي فقط 'test:event'.
TriggerSafeServerEvent موجود فقط داخل عميل مكافح الغش نفسه وليس export، لذا يجب على الموارد الأخرى استخدام نمط receiveEventKey أعلاه. يطلب عميل مكافح الغش المفتاح كل 5 ثوانٍ حتى يصل (12 محاولة على الأكثر).
يجيب الخادم على طلب مفتاح واحد على الأكثر كل 3 ثوانٍ لكل لاعب، وطلبات مكافح الغش نفسه تُحتسب أيضًا. إذا لم يصل مفتاح، فاطلبه مجددًا بعد بضع ثوانٍ. أبقِ المعالج الخاص بك مسجّلًا وأرسل دائمًا أحدث مفتاح استلمته.
- أضف اسم حدثك إلى ts.ProtectedEvents في configs/anticheat_config.lua. تُقرأ القائمة مرة واحدة عند البدء، لذا أعد تشغيل مكافح الغش بعد التغييرات.
- في سكربت العميل الخاص بك، سجّل ts_anticheat:receiveEventKey لحفظ المفتاح، ثم أرسل ts_anticheat:requestEventKey.
- أرسل حدثك مع المفتاح كأول وسيط: TriggerServerEvent(name, key, ...).
- في سكربت الخادم الخاص بك، عالج '<name>:safe' عبر AddEventHandler. الوسيط الأول هو معرّف اللاعب على الخادم، تليه وسائطك.
-- configs/anticheat_config.lua
ts.ProtectedEvents = { ['my-shop:buy'] = true }
-- العميل (المورد الخاص بك)
local key
RegisterNetEvent('ts_anticheat:receiveEventKey', function(k) key = k end)
TriggerServerEvent('ts_anticheat:requestEventKey')
-- لاحقًا، بعد ضبط key:
TriggerServerEvent('my-shop:buy', key, 'bread')
-- الخادم (المورد الخاص بك)
AddEventHandler('my-shop:buy:safe', function(src, item)
if GetInvokingResource() ~= 'tosun-ac' then return end
-- تحقق هنا من المال والمخزون والصلاحيات
end)ما يتحقق منه SafeEvents وما لا يتحقق منه#
يتحقق SafeEvents من صحة النقل فقط. لا يعاقب أحدًا أبدًا، ولا يحل محل الفحوص في المعالج الخاص بك.
- كل استدعاء من العميل يُحتسب أولًا ضمن ts.SafeEventRateLimit لكل ts.SafeEventRateWindow ثانية (30 استدعاء كل 10 ثوانٍ افتراضيًا)، حتى بدون مفتاح.
- إذا لم يكن لدى اللاعب مفتاح بعد، يُسقط الاستدعاء بصمت.
- المفتاح الخاطئ، أو تجاوز حد المعدل، أو أكثر من ts.SafeEventMaxArgs وسيطًا (64 افتراضيًا)، أو بيانات غير صالحة، يُسقط الاستدعاء ويكتب سطر سجل واحدًا في قاعدة البيانات لكل لاعب وحدث ونافذة.
- الاستدعاءات من الخادم (source 0) تُتجاهل ولا تطلق أي حدث ':safe'.
- حدث الشبكة الخام ما زال يصل إلى أي معالج سجّله موردك عبر RegisterNetEvent. نسخة ':safe' وحدها هي المحمية.
- لا تستخدم RegisterNetEvent أبدًا مع اسم ':safe'؛ فذلك يسمح للعملاء باستدعائه مباشرة.
- SafeEvents طبقة إضافية فقط؛ يجب أن يظل المعالج الخاص بك يتحقق من الصلاحيات والأرصدة والملكية.
- لا تضف أحداث أطر العمل (esx، qb) إلى القائمة. مستدعوها لا يرسلون مفتاحًا، لذا يرفض SafeEvents تلك الاستدعاءات ويكتب أسطر سجل ولا يطلق ':safe' أبدًا. معالجات إطار العمل نفسها تستمر في العمل.
- التعليق التركي في configs/anticheat_config.lua يقول إن الاستدعاءات بدون مفتاح تسبب حظرًا خاطئًا. في هذا الإصدار تُسقط فقط.
ts.DetectionExempt: ربط أحداثك بالإعفاءات#
يحوّل ts.DetectionExempt أسماء أحداثك الخاصة إلى إعفاءات مؤقتة من الاكتشاف. استخدمه للقوائم وإجراءات الخادم التي تغيّر بشكل مشروع مظهر اللاعب أو موقعه أو حالته: الملابس، والحلاقون، والسكن، والمرائب، واختيار الشخصية، والإحياء. تُقرأ القوائم من configs/anticheat_config.lua؛ وإعدادات اللوحة لا تغيّرها. ts.MenuDetectionExempt اسم بديل محفوظ للإعدادات القديمة.
| المفتاح | النوع | القيمة المرفقة | التأثير |
|---|---|---|---|
enabled | boolean | true | القيمة false توقف كل روابط DetectionExempt. |
defaultDurationMs | number (ms) | 60000 | مدة الإعفاء للإدخالات التي ليس لها durationMs خاص. إدخالات الخادم تُحصر بين 1000 و 120000 ms، وإدخالات العميل بين 1000 و 300000 ms. |
budgetMsPer10Min | number (ms) | 240000 | أقصى مدة إعفاء جزئي (soft) يمكن أن يجمعها لاعب واحد من serverEvents خلال 10 دقائق. |
clientEvents | قائمة من strings | 153 إدخالًا (142 اسمًا فريدًا) | أحداث شبكة على العميل. عندما يُطلق أحدها، تُعفى فحوص العميل لذلك اللاعب. |
localEvents | قائمة من strings | 11 إدخالًا | أحداث محلية على العميل (TriggerEvent على العميل فقط). التأثير نفسه كـ clientEvents. |
serverEvents | قائمة من strings أو tables | 34 إدخالًا | أحداث شبكة من العميل إلى الخادم. عندما يطلق لاعب أحدها، يحصل ذلك اللاعب على إعفاء جزئي. |
DetectionExempt.serverEvents#
يسجّل مكافح الغش كل اسم مدرج عبر RegisterNetEvent. عندما يطلقه لاعب، يحصل ذلك اللاعب على إعفاء جزئي: تُخفَّف فحوص الحركة على الخادم وفحوص godmode و invisibility و noclip والكاميرا على جانب الخادم، وتُعفى فحوص العميل لذلك اللاعب عبر state bag. وهو لا يعني أبدًا الحصانة من العقوبة.
الإدخال إما string أو table: { event = 'name', durationMs = 60000, resource = 'owner-resource', always = true }. تُحصر durationMs بين 1000 و 120000 ms.
يُثبَّت الربط فقط ما دام المورد المالك قيد التشغيل أو في طور البدء. المالك هو بادئة الحدث قبل أول نقطتين (:)؛ و qb-clothes تُربط بـ qb-clothing و hospital تُربط بـ qb-ambulancejob. اضبط resource عندما تختلف البادئة عن اسم المورد. always = true يثبّت الربط حتى عندما لا يكون المالك قيد التشغيل.
تُثبَّت الروابط بعد 2.5 ثانية من بدء مكافح الغش، ومجددًا بعد ثانية واحدة (1 s) من بدء أي مورد آخر.
يمكن للاعبين إطلاق هذه الأحداث بأنفسهم، ولهذا لكل لاعب ميزانية (budgetMsPer10Min). عندما يستنفدها لاعب، يكتب مكافح الغش تحذيرًا واحدًا في وحدة التحكم وسطر سجل واحدًا في قاعدة البيانات، ويتجاهل الطلبات الإضافية من ذلك اللاعب لبقية الدقائق العشر.
شغّل tosunac_integration في وحدة تحكم الخادم لترى عدد أحداث إعفاء الخادم المربوطة. يعمل من وحدة تحكم الخادم فقط، والمخرجات تذهب إليها.
DetectionExempt.clientEvents و localEvents#
أسماء clientEvents تُسجَّل عبر RegisterNetEvent على العميل. عندما يُطلق أحدها، من الخادم أو من TriggerEvent محلي، يُعفى العميل لمدة defaultDurationMs.
تقبل clientEvents قيم string فقط. إدخالات table، بما فيها التي تحتوي durationMs، تُتجاهل بصمت على العميل.
أثناء الإعفاء لا تُعاقَب اكتشافات العميل. يُبلَّغ عنها كأسطر LOG معلَّمة بـ '[exempt]'، مرة واحدة في الدقيقة على الأكثر لكل فحص، لكي تبقى إساءة الاستخدام ظاهرة في اللوحة. فحوص الخادم لا تتأثر.
تعمل localEvents بالطريقة نفسها لكنها تستخدم AddEventHandler فقط، لذا تتفاعل فقط مع TriggerEvent على العميل.
يفحص العميل القائمتين بعد 3.5 ثانية من تحميله ومجددًا مع كل مزامنة للإعدادات.
حدث سكربت لا تشغّله لا يُطلق أبدًا، لذا لا تضر الأسماء الإضافية في القائمة. قائمة clientEvents المرفقة تكرر 11 اسمًا؛ والتكرارات غير ضارة.
مثال DetectionExempt#
أضف أسماءك إلى القوائم الموجودة في configs/anticheat_config.lua، ثم أعد تشغيل مكافح الغش. استبدال الجدول بالكامل يزيل الإدخالات المرفقة. المثال يعرض الإدخالات الجديدة فقط.
فضّل الـ exports عندما تتحكم في الكود: export العميل SetExempt(true, ms, reason)، و export الخادم SetExempt(src, ms, reason) من مورد موثوق، و export الخادم MarkTeleport(src, ms) مباشرة قبل نقل لاعب.
ts.DetectionExempt = {
enabled = true,
defaultDurationMs = 60000,
budgetMsPer10Min = 240000,
-- أحداث شبكة على العميل: strings فقط
clientEvents = {
-- ...الإدخالات المرفقة...
'my-clothing:client:openMenu',
},
-- أحداث محلية على العميل (TriggerEvent على العميل)
localEvents = {
-- ...الإدخالات المرفقة...
'my-menu:opened',
},
-- أحداث من العميل إلى الخادم: إعفاء جزئي للمرسل
serverEvents = {
-- ...الإدخالات المرفقة...
'my-clothing:server:saveOutfit',
{ event = 'my-housing:server:enter', durationMs = 60000 },
{ event = 'myhouse:server:enter', resource = 'my-housing' },
{ event = 'my-garage:server:takeOut', durationMs = 45000, always = true },
},
}ts.EventLimiter: حدود المعدل لأحداث الشبكة#
يربط ts.EventLimiter أسماء الأحداث بحد أقصى لعدد الاستدعاءات لكل لاعب خلال 5 ثوانٍ. يسجّل مكافح الغش كل اسم عبر RegisterServerEvent عند التحميل ويعدّ الاستدعاءات لكل لاعب؛ وتُصفَّر كل العدادات كل 5 ثوانٍ. المعالج الخاص بك للحدث يستمر في العمل.
عندما يبلغ العدد حده، يحاول مكافح الغش تسجيل اكتشاف بالإعداد ts.EventLimiter (server_event_spam، و KICK افتراضيًا).
القائمة المرفقة تحتوي 25 إدخالًا: test:event و esx:getSharedObject وأحداث البنك والمال في QBCore والإحياء وظهور المركبات والمخزون والسجن والأصفاد و HCheat:TempDisableDetection.
تُقرأ الأسماء والحدود عند التحميل. جدول قاعدة البيانات ac_event_limits يستبدل ts.EventLimiter عند المزامنة لكنه لا يغيّر المعالجات المسجّلة، لذا أعد تشغيل مكافح الغش بعد تعديل أي منهما.
ts.EventLimiter = {
-- ...الإدخالات المرفقة...
['my-shop:buy'] = 10,
}أحداث المصائد: لا تستخدم هذه الأسماء أبدًا#
بعض الأحداث موجودة فقط للإيقاع بالغشاشين. اتبع هذه القواعد كي لا تطلق سكربتاتك الخاصة أيًا منها أبدًا.
- يسجّل مكافح الغش أحداث مصائد لا تطلقها إلا برامج الغش. لا تطلقها أبدًا ولا تُعِد استخدام أسمائها.
- لرؤية أسماء المصائد على خادمك، شغّل /ts evtlist (تُطبع القائمة في وحدة تحكم الخادم). ولإيقاف معاملة حدث ما كمصيدة، استخدم /ts evtwhitelist <eventName>. راجع موضوع الأوامر.
- اجعل اسم موردك بادئةً لأحداثك الخاصة، مثل myresource:doThing، كي لا تتعارض أبدًا مع أي مصيدة.
حارس معدل أحداث الصوت#
يسجّل مكافح الغش أحداث الصوت هذه كأحداث شبكة في مورده الخاص ويعدّها لكل لاعب. فوق ts.premiumGuard.soundPerSec (6 في الثانية افتراضيًا) يطبّق soundAction ('log' افتراضيًا). يلغي الحدث فقط عندما يكون soundCancel = true (false افتراضيًا). معالجات مورد الصوت لديك تستمر في العمل إذا كان ذلك المورد قد سجّل الحدث بنفسه.
يعمل الحارس فقط ما دام ts.premiumGuard.enabled و ts.premiumGuard.soundGuard هما true (كلاهما true في الإعدادات المرفقة). أبقِ soundCancel على false حتى تتحقق من أن سكربتات الصوت لديك تبقى تحت الحد.
| الحدث | المورد |
|---|---|
InteractSound_SV:PlayOnAll | InteractSound |
InteractSound_SV:PlayWithinDistance | InteractSound |
InteractSound_SV:PlayOnOne | InteractSound |
xsound:stateSound | xsound |
xsound:server:play | xsound |
xsound:server:playUrl | xsound |
xsound:server:playUrlPos | xsound |
أحداث يرسلها مكافح الغش إلى موارد أخرى#
بعد إجراءات الطاقم أو اللوحة أو الاكتشاف، يطلق مكافح الغش أحداثًا تخص موارد أخرى. إذا كنت تشغّل أحد هذه الموارد، فتوقّع هذه الاستدعاءات.
الطقس والوقت يستخدمان فقط أول مورد مزامنة قيد التشغيل، بهذا الترتيب: qb-weather و Renewed-Weathersync (عبر export فقط) و cd_easytime و wd_weather و weathersync و vSync و qb-weathersync. إذا لم يكن أي منها قيد التشغيل، يضبط مكافح الغش الطقس والوقت مباشرة على كل عميل.
hospital:client:Revive و esx_ambulancejob:revive هما أيضًا من مستمعي مكافح الغش (راجع أحداث الموت والإحياء في إطار العمل)، لذا يفتح هذا الإحياء أيضًا نافذة ما بعد الإحياء لمدة 10 ثوانٍ.
| الحدث | الجانب | يُرسل عندما |
|---|---|---|
qb-weather:server:RequestStateChange | محلي على الخادم | تغيير الطقس أو الوقت عندما لا يملك qb-weather export setWeather أو setTime. في الوقت تكون القيمة جدول { hour, minute }. |
cd_easytime:setWeather, cd_easytime:setTime | محلي على الخادم | تغيير الطقس أو الوقت مع cd_easytime. |
<res>:setWeather, <res>:setTime | محلي على الخادم | تغيير الطقس أو الوقت مع wd_weather أو weathersync أو vSync أو qb-weathersync عندما لا يملك ذلك المورد export مطابقًا. |
wasabi_ambulance:revive | محلي على العميل | إحياء من الطاقم أو اللوحة عندما يكون wasabi_ambulance قيد التشغيل. |
hospital:client:Revive | محلي على العميل | إحياء من الطاقم أو اللوحة مع qb-ambulancejob أو Starter-Hospital. |
esx_ambulancejob:revive | محلي على العميل | إحياء من الطاقم أو اللوحة مع esx_ambulancejob. |
<res>:revive, <res>:client:Revive, <res>:client:revive | محلي على العميل | إحياء من الطاقم أو اللوحة في غير ذلك: أول مورد قيد التشغيل من ambulance و qb-ambulancejob و cd_ambulance و ars_ambulancejob يتلقى الأسماء الثلاثة كلها. يتبعه إحياء native إذا كان اللاعب لا يزال ميتًا. |
QBCore:Notify | محلي على العميل؛ من الخادم إلى العميل | كل علاج يجريه مكافح الغش، حتى بدون qb-core (فحص qb-core لديه يعيد true دائمًا). وأيضًا إجراءات المال والمخزون والإشعارات من اللوحة. |
esx:showNotification, QBCore:Player:SetPlayerData, inventory:client:ItemBox | من الخادم إلى العميل | إجراءات المال والمخزون والإشعارات من اللوحة، ومنح الأسلحة كعناصر. |
chat:addMessage | من الخادم إلى العميل؛ محلي على العميل | رسائل الدردشة وبث اللوحة. مع ts.chatMessages = true (false افتراضيًا)، تذهب كل نتيجة اكتشاف، بما فيها LOG، إلى كل اللاعبين بالتركية الثابتة في الكود (editable/server/sv_editme.lua). |
chat:addSuggestion | محلي على العميل | يضيف اقتراح /unspectate عند تحميل ملف قائمة الإدارة. |
qb-phone:client:CustomNotification, qs-smartphone:client:sendNotification, lb-phone:notification, yseries:notification, gks-phone:client:notification, roadphone:notify | من الخادم إلى العميل | تنبيهات الطاقم عند الطرد والحظر، و exports phoneNotify و phoneNotifyAdmins. يتلقاها فقط أول هاتف قيد التشغيل (npwd يستخدم export؛ والدردشة إن لم يوجد أي منها). يتطلب ts.AdminMenu.enable = true. |
الأمان: من يحق له إطلاق كل حدث#
مكافح الغش وحده يحق له إطلاق الأحداث التي يصدرها، ولا يجوز للموارد الأخرى إطلاقها. يوضّح الجدول من يحق له إطلاق كل حدث.
| الحدث | من يحق له إطلاقه |
|---|---|
ts_anticheat:playerBanned | مكافح الغش فقط. |
ts_anticheat:banCommitted | مكافح الغش فقط. |
ts_anticheat:newLog | مكافح الغش فقط. |
ts_anticheat:shield:ban_video_saved | مكافح الغش فقط. |
tosun-ac:settingsReloaded | مكافح الغش فقط. |
ts_anticheat:configUpdated | مكافح الغش فقط. |
ts_anticheat:adminStateChanged | أي مورد على الخادم. |
tosun-ac:panel:characterReady | أي عميل. محدود باستدعاء واحد كل 20 ثانية لكل لاعب. |
ts_anticheat:locale:setSelf | أي عميل. يؤثر في المستدعي فقط. |
ts_anticheat:requestEventKey | أي عميل. يذهب المفتاح فقط إلى اللاعب الطالب. |
tosun-ac:bridge:clientExempt | سكربتات الخادم الخاصة بك. |
الأمان: تحقق من GetInvokingResource#
يمكن لأي مورد على الخادم إطلاق حدث محلي على الخادم. في مستمعيك، تحقق من أن مكافح الغش هو من أطلقه قبل أن تتصرف. مستمع شاشة الحظر الخاص بمكافح الغش نفسه يستخدم فحصًا مشابهًا.
طبّق الفحص على playerBanned و banCommitted و playerUnbanned و newLog و settingsReloaded وأحداث Shield و renameCharacter ومعالجات '<name>:safe' الخاصة بك.
لا تطلق أبدًا أحداث مكافح الغش من مواردك الخاصة، ولو للاختبار. عدة مستمعين مضمّنين لا يتحققون من المستدعي.
AddEventHandler('ts_anticheat:banCommitted', function(playerId, row)
if GetInvokingResource() ~= 'tosun-ac' then return end -- اسم مجلدك إن غيّرته
-- يمكنك التصرف بأمان مع row هنا
end)الأمان: تصميم يكون فيه الخادم صاحب السلطة#
كل ما يمكن للعميل إطلاقه يُعامل كتلميح، لا كسلطة. اتبع القاعدة نفسها في معالجاتك.
- إعفاءات العميل (clientEvents و localEvents و autoExempt وحدث الجسر و export العميل SetExempt) لا تغيّر أبدًا الفرض على الخادم. أثناء نشاطها، تُسجَّل اكتشافات العميل كـ '[exempt]' بدل معاقبتها.
- إعفاءات serverEvents جزئية (soft): على الخادم تخفّف فقط فحوص الحركة والظهور (عقوبات الأسلحة والمال والضرر وإساءة استخدام الأحداث والحقن والتعطيل ما زالت تُطبَّق)، وكل لاعب محدود بـ budgetMsPer10Min.
- حالة الطاقم يقررها رد الخادم المحمي بـ nonce. دفع علامة طاقم إلى العميل لا يمكنه منح صلاحيات الإدارة.
- مفتاح SafeEvents يتحقق من النقل فقط. يجب أن يتحقق معالج ':safe' الخاص بك من الصلاحيات والأرصدة والملكية على الخادم.
- يمكن للغش إطلاق أحداث الموت الخاصة بإطار العمل محليًا. علامة السقوط تُمسح بعد نحو 20 ثانية من اللعب النشط الواضح.
- لإعفاء لاعب من جانب الخادم، استخدم الـ exports: SetExempt(src, ms, reason) من مورد موثوق، أو MarkTeleport(src, ms) قبل النقل.
الأحداث الداخلية#
إلى جانب الأحداث في هذه الصفحة، يسجّل مكافح الغش أحداثًا داخلية لمصافحة الانضمام وتبادل المفاتيح و Shield وقائمة الإدارة وإجراءات لوحة الويب ومورد مرافق. هي محمية بـ nonces أو مفاتيح أو تواقيع أو حدود معدل أو فحوص الطاقم، وعدة منها مصائد تعاقب المستدعي. لم تُوثَّق هنا عن قصد.
- لا تطلق الأحداث الداخلية، لا من الخادم ولا من العميل.
- لا تسجّل معالجات عليها ولا تعِد استخدام أسمائها.
- لا تطلق أي حدث يبدأ اسمه بـ ts_anticheat: أو tosun-ac: ما لم تذكره هذه الصفحة كحدث يمكنك إطلاقه.
- استخدم الـ exports للإجراءات: مثل punish و MarkTeleport و freezePlayer و setPlayerHealth و RequestShieldScreenshot و quarantine.
مشكلات معروفة في 9.6.15#
هذه السلوكيات موجودة في الكود المرفق. خطّط مع أخذها في الحسبان.
- tosun-ac:settingsReloaded و ts_anticheat:configUpdated يُطلقان في كل دورة مزامنة تقريبًا، وليس فقط عند تغيّر الإعدادات.
- ts_anticheat:playerBanned يُطلق مع KICK و LOG إضافة إلى BAN.
- تنبيه الهاتف للطاقم الخاص بالسجلات المباشرة يستمع إلى status بقيمة 'TESPİT' أو 'Detection' في ts_anticheat:newLog، لكن لا شيء يصدر أيًا من القيمتين، لذا لا يُطلق هذا التنبيه أبدًا.
- كل علاج يجريه مكافح الغش يطلق QBCore:Notify على العميل، حتى على الخوادم التي لا تحتوي qb-core.
- ts.quarantine.autoQuarantine بلا أي تأثير: مدخله الوحيد حدث داخلي لا يصدره أي شيء. استخدم export quarantine بدلًا منه.
- عدة تعليقات في configs/anticheat_config.lua مكتوبة بالتركية وبعضها قديم: استدعاءات ts.ProtectedEvents بدون مفتاح تُسقط ولا تُحظر، و ts.EventLimiter لا يطرد.
تجنب تكرار التحليل المكلف بعد إعادة التشغيل#
يتم فحص بصمات SHA256 لمحتوى الموارد عند كل تشغيل. تعيد الملفات وقواعد الفحص غير المتغيرة استخدام نتائج موثقة في KVP الخادم بدلاً من تكرار تحليل التواقيع والأحداث المكلف. تغييرات الملفات أو الاستثناءات أو القواعد تستدعي تحليلاً جديداً. ما زالت البصمات تقرأ الملفات؛ لا نضمن قيمة resmon ثابتة.
- احتفظ بذاكرة KVP في التحديث العادي؛ تُحلل السجلات التالفة أو غير القابلة للتحقق مجدداً.
- يجمع كتالوج البداية أسماء الأحداث المكتوبة صراحة في Lua/JS. الأسماء الديناميكية والملفات غير المقروءة أو escrow وDLL لا تُعتمد كفحص كامل.
- تنتظر التهيئة التلقائية اليدوية اكتمال التحليل. الموارد الناقصة أو المشبوهة أو المتغيرة أو المنتهية المهلة لا تُعتمد تلقائياً.
- اختبر دخول اللاعبين واللعب العادي وإجراءات المدير على خادم تجريبي، وقيّم resmon مع عدد اللاعبين وحمل الإطار.