إدارة الكيانات في FiveM: التعامل مع الشخصيات، المركبات، الأجسام
اتقن إدارة الكيانات في FiveM. التوليد، الملكية، التصفية والتنظيف للمشاة، المركبات والأشياء للحفاظ على استقرار وسرعة الخادم.
Agency Scripts
المؤسس والمطور الرئيسي في Agency Scripts
فهم الكيانات في FiveM
في FiveM، الكيان هو أي جسم موجود في عالم اللعبة: مركبات، شخصيات، أشياء، مقتنيات، وحتى شخصية اللاعب. لكل كيان مقبض (معرف صحيح) تستخدمه للتفاعل معه من خلال الدوال الأصلية. إدارة الكيانات هي من أهم المهارات الأساسية في تطوير FiveM لأن كل سكريبت تقريباً يتفاعل مع الكيانات بطريقة ما. الإدارة السيئة تؤدي إلى تسريبات في الذاكرة، أشياء شبحية تبقى بعد إعادة تشغيل المورد، عدم تزامن بين اللاعبين، وفي النهاية عدم استقرار الخادم. يغطي هذا الدليل الأنماط الصحيحة لإنشاء الكيانات، تتبعها، وتنظيفها.
ظهور الأجسام والدعائم
الأمر الأصلي الأساسي لإنشاء العناصر هو CreateObject (أو CreateObjectNoOffset ). قبل إنشاء أي كائن، يجب عليك طلب النموذج والانتظار حتى يتم تحميله. عدم طلب النموذج أولاً سيؤدي إلى كيان غير مرئي أو مفقود. قم دائمًا بإطلاق النموذج بعد إنشاء الكائن لتحرير الذاكرة.
-- client/entity_spawner.lua
local function SpawnProp(modelName, coords, rotation, isNetwork)
local model = joaat(modelName)
-- Request the model and wait for it to load
RequestModel(model)
local timeout = 0
while not HasModelLoaded(model) do
Wait(10)
timeout = timeout + 10
if timeout > 5000 then
print(('[ERROR] Model %s failed to load after 5s'):format(modelName))
return nil
end
end
local obj = CreateObject(model, coords.x, coords.y, coords.z, isNetwork, true, false)
if rotation then
SetEntityRotation(obj, rotation.x, rotation.y, rotation.z, 2, true)
end
-- Freeze the object so it does not fall through the ground
FreezeEntityPosition(obj, true)
-- Release the model from memory
SetModelAsNoLongerNeeded(model)
return obj
end
-- Usage
local chair = SpawnProp('prop_chair_01a', vector3(200.0, -800.0, 31.0), nil, false)
ظهور المركبات
تتبع عملية إنشاء المركبات نمطًا مشابهًا لكنها تستخدم CreateVehicle وله اعتبارات إضافية لملكية الشبكة، مستويات الوقود، ونص اللوحة. دائمًا قم بإنشاء المركبات على جانب الخادم عندما يكون ذلك ممكنًا، أو استخدم ردود نداء على جانب الخادم للتحقق من طلبات إنشاء المركبات من العملاء.
-- client/vehicle_spawner.lua
local function SpawnVehicle(modelName, coords, heading)
local model = joaat(modelName)
RequestModel(model)
while not HasModelLoaded(model) do
Wait(10)
end
local vehicle = CreateVehicle(model, coords.x, coords.y, coords.z, heading, true, false)
-- Basic vehicle setup
SetVehicleOnGroundProperly(vehicle)
SetEntityAsMissionEntity(vehicle, true, true)
SetVehicleHasBeenOwnedByPlayer(vehicle, true)
SetVehicleNeedsToBeHotwired(vehicle, false)
SetVehRadioStation(vehicle, 'OFF')
-- Set fuel if using a fuel system
Entity(vehicle).state:set('fuel', 100.0, true)
SetModelAsNoLongerNeeded(model)
return vehicle
end
تتبع وتنظيف الكيانات
أهم جانب في إدارة الكيانات هو تتبع كل كيان ينشئه سكربتك وتنظيفهم عند توقف المورد. بدون تنظيف مناسب، تستمر الكيانات في عالم اللعبة كيتامى يستهلكون الذاكرة ويعيقون الموارد. استخدم جدول تتبع لتخزين كل مقابض الكيانات وسجل onResourceStop المعالج الذي يزيلها.
-- client/entity_manager.lua
local ManagedEntities = {}
function RegisterEntity(entity, category)
if not DoesEntityExist(entity) then return end
ManagedEntities[entity] = {
category = category or 'default',
created = GetGameTimer(),
model = GetEntityModel(entity),
}
end
function UnregisterEntity(entity)
if ManagedEntities[entity] then
if DoesEntityExist(entity) then
SetEntityAsMissionEntity(entity, false, true)
DeleteEntity(entity)
end
ManagedEntities[entity] = nil
end
end
function CleanupCategory(category)
for entity, data in pairs(ManagedEntities) do
if data.category == category then
UnregisterEntity(entity)
end
end
end
function CleanupAllEntities()
for entity, _ in pairs(ManagedEntities) do
UnregisterEntity(entity)
end
ManagedEntities = {}
end
-- Critical: Clean up when resource stops
AddEventHandler('onResourceStop', function(resourceName)
if GetCurrentResourceName() ~= resourceName then return end
CleanupAllEntities()
end)
ملكية كيان الشبكة
في بيئة FiveM الشبكية، لكل كيان مالك، وهو العميل المسؤول عن محاكاة فيزياءه وموقعه. تحدد ملكية الشبكة أي عميل لاعب يتحكم في حركة الكيان وتصادمه. فهم وإدارة ملكية الشبكة ضروريان لسلوك الكيانات المتزامن، خاصة للسكريبتات التي تحتاج للتحكم عن بعد في NPCs أو المركبات.
-- server/ownership.lua
-- Request control of a networked entity
local function RequestEntityOwnership(src, netId)
local entity = NetworkGetEntityFromNetworkId(netId)
if not DoesEntityExist(entity) then return false end
-- Set the requesting player as the owner
SetEntityRoutingBucket(entity, GetPlayerRoutingBucket(src))
return true
end
-- client/ownership.lua
-- Request network control of an entity
local function TakeEntityControl(entity, timeout)
timeout = timeout or 2000
local start = GetGameTimer()
NetworkRequestControlOfEntity(entity)
while not NetworkHasControlOfEntity(entity) do
Wait(100)
NetworkRequestControlOfEntity(entity)
if GetGameTimer() - start > timeout then
return false
end
end
return true
end
-- Usage: Move an entity you need control of
local function MoveEntity(entity, targetCoords)
if TakeEntityControl(entity) then
SetEntityCoords(entity, targetCoords.x, targetCoords.y, targetCoords.z, false, false, false, false)
return true
end
print('[WARN] Could not get control of entity')
return false
end
إنشاء وإدارة الشخصيات غير القابلة للعب
الكيانات Ped (المشاة) تُستخدم للشخصيات غير القابلة للعب، بائعي المتاجر، معطِي المهام، والشخصيات المحيطة. تتطلب معالجة خاصة لأنها تحتوي على ذكاء اصطناعي يمكن أن يجعلها تتجول، تتفاعل مع البيئة، أو تهاجم اللاعبين إذا لم تُضبط بشكل صحيح. دائمًا جمد وعطّل الذكاء الاصطناعي للشخصيات الثابتة.
-- client/ped_spawner.lua
local function SpawnStaticPed(modelName, coords, heading, scenario)
local model = joaat(modelName)
RequestModel(model)
while not HasModelLoaded(model) do
Wait(10)
end
local ped = CreatePed(0, model, coords.x, coords.y, coords.z - 1.0, heading, false, true)
-- Make the ped static and non-interactive with ambient AI
SetEntityAsMissionEntity(ped, true, true)
SetBlockingOfNonTemporaryEvents(ped, true)
SetPedFleeAttributes(ped, 0, false)
SetPedCombatAttributes(ped, 17, true)
SetPedDiesWhenInjured(ped, false)
SetEntityInvincible(ped, true)
FreezeEntityPosition(ped, true)
-- Play a scenario animation if specified
if scenario then
TaskStartScenarioInPlace(ped, scenario, 0, true)
end
SetModelAsNoLongerNeeded(model)
RegisterEntity(ped, 'npc')
return ped
end
-- Spawn a shop vendor
local vendor = SpawnStaticPed(
's_m_y_ammucity_01',
vector3(22.0, -1105.0, 29.8),
160.0,
'WORLD_HUMAN_STAND_IMPATIENT'
)
نصائح الأداء لإدارة الكيانات
- تحديد الكيانات النشطة. تستهلك كل كيان ذاكرة ودورات عرض. استخدم أنظمة البث لتحميل الكيانات عندما يكون اللاعب قريبًا وتفريغها عندما يغادر المنطقة.
- استخدم تجمعات الكائنات. للكيانات التي تظهر وتختفي بشكل متكرر مثل أغطية الرصاص أو تأثيرات الجسيمات، أعد استخدام مقابض الكيانات بدلاً من إنشاء وحذف جديدة باستمرار.
- يفضل الكيانات على جانب العميل. إذا كان الكيان يحتاج فقط لأن يكون مرئيًا للاعب واحد (مثل عنصر واجهة مستخدم أو كائن معاينة)، فأنشئه كغير متصل بالشبكة لتقليل حمل الخادم.
- استدعِ دائمًا SetModelAsNoLongerNeeded. النماذج المحملة تبقى في الذاكرة حتى يتم تحريرها صراحة. نسيان هذا الاستدعاء هو أحد أكثر الأسباب شيوعًا لتسرب الذاكرة في سكربتات FiveM.
- تحقق من DoesEntityExist قبل العمليات. يمكن حذف الكيانات بواسطة محرك اللعبة أو سكربتات أخرى أو بسبب عدم التزامن. تحقق دائمًا من وجود الكيان قبل محاولة تعديله.
- استخدم حقائب حالة الكيان للبيانات الوصفية. بدلاً من الحفاظ على جداول بحث منفصلة لبيانات الكيانات، استخدم
Entity(entity).stateلتخزين خصائص مخصصة مباشرة على الكيان.