Sahte Scriptlenmiş Varlık Oluşturma

Bu makale, bir sürü "hile" ile global fonksiyonları ve meta-metotları yeniden tanımlamanın kötü bir pratiğini anlatmaktadır. Bu durum, mevcut tüm Lua kodlarının ve tüm entity'lerin performansını doğrudan etkiler. Ayrıca, istemci ve sunucu arasındaki çalışmanın yanı sıra Lua ve motor arasındaki ayrımı da karıştırır! Bu, öngörülemeyen davranışlara yol açabilir. Lütfen kesinlikle gerekli olmadıkça bu kodu kullanmayın!
prop_dynamic çarpışma davranışını Entity:PhysicsInitStatic ve Entity:CreateBoneFollowers metotlarını kullanarak tekrarlayabilirsiniz.

Bazen bir motor entity'sine (yani betikli olmayan bir entity'ye) dayalı yeni bir entity oluşturmanız gerekebilir. Bir motor entity'sinin ilginç özelliklerini korumak ancak metotlar ekleyerek veya değiştirerek onu modifiye etmek istiyorsanız bunu yapmak isteyebilirsiniz.

Benim örneğimde, ENTITY hook'larını kullanamayacaksınız. Herhangi bir hook'un tetiklenmesi için, diğer motor entity'lerinde olduğu gibi, kodun altbilgi kısmına sabit olarak kodlanması gerekir. Örneğin, çalışmalarını sağlamak için basitçe bir ENTITY:Use veya bir ENTITY:Think metodu ekleyemezsiniz: onları tetikleyecek kodu sizin yazmanız gerekir. (Gelecekte bazı örnekler ekleyebilirim.)

Bu örnekte, bir prop_dynamic'e dayalı yeni bir prop_vehicle_mr sınıfı oluşturuyorum. Gerçek bir betikli entity oluşturamadım çünkü öyle yaparsam ve onu başka bir entity'ye (örneğin bir prop_vehicle_jeep'e) ebeveyn olarak atarsam, fizik nesnesi onunla birlikte hareket etmiyor! Bu yüzden prop_dynamic'ten türetilmiş yeni bir sınıf kullanmam gerekti, çünkü fizik nesnesi entity'nin kendisine yapışacaktır.

Ek olarak, bu sahte SENT altbilgisi, metatable'a dahil olan ve standart bir SENT'te değiştirilemeyen herhangi bir metodu değiştirebilecek şekilde yazılmıştır. Bu örnekte, sıfırlarken varsayılan materyali değiştirmek için Entity:SetMaterial metodunu değiştiriyorum.

Lütfen dikkat: metot ve özellikler sadece sunucu tarafında mevcuttur! Bu, sınıf adı hariç, istemci tarafında temel sınıfının bir entity'si olarak görüneceği anlamına gelir: metotlar ve özellikler temel sınıfınkiler olacaktır. (Bunu gelecekte bir hook aracılığıyla değiştirebilirim.)

Burada size adım adım sahte bir betikli entity'nin nasıl yazılacağını gösteriyorum. Bu, bir betikli entity dosyasında yapılabilir ancak başka herhangi bir yerde de çalışması beklenir. Bu örneğin dosyası: lua/entities/prop_vehicle_mr.lua


Birinci adım: Üstbilgi

Üstbilgi, sahte betikli entity'nin yapısını hazırlar.

ENT.Type = "anim" local ENT = {} local BaseClass = FindMetaTable("Entity") local BaseClassName = "prop_dynamic" local ClassName = "prop_vehicle_mr"

Önce sahte SENT'in türünü tanımlarız. Bu muhtemelen işe yaramaz.

Sonra temiz bir ENT tablosu oluştururuz, böylece SENT sisteminden hiçbir şey miras alınmaz.

Tüm varsayılan metotları ve entity'ler için varsayılan özellikleri içeren BaseClass'ı yükleriz. Bu, altbilgide değiştirilecektir.

Script'in ne ile uğraşacağını bilmesi için BaseClassName ve ClassName'i belirtiriz.


İkinci adım: klasik AddCSLuaFile


Üçüncü adım: İçerik

Sahte SENT'iniz için varsayılan özellikleri, metotları ve hook'ları buraya koyacaksınız.

Metatable'dan (BaseClass) metotları değiştirirken ne yaptığınızın farkında olun: bu tehlikelidir ve başka bir şeyle çakışabilir.

local old_SetMaterial = BaseClass.SetMaterial function ENT:SetMaterial (materialName) if materialName != nil and materialName != "" then return old_SetMaterial(self, materialName) else if self.DefaultMaterial != nil then return old_SetMaterial(self, self.DefaultMaterial) else return old_SetMaterial(self, "") end end end

Başka bir yerde, bu sınıftan bir entity oluşturduktan sonra, bu entity için varsayılan materyali değiştirebilirim:

MyEntity.DefaultMaterial = "materialname"

Kullanabileceğiniz bazı hook örnekleri burada. Unutmayın: bu örnekte olmayan hook'lar uygulanmamıştır, bu sizin işiniz.

function ENT:Initialize () end

Bu örnekte, altbilgideki ENTITY:Initialize hook'unun uygulanması, Entity:Spawn kullandığınızda çağrılmamasını sağlar. Bunun yerine, ents.Create kullanıldığında hemen çağrılır.

Bu hook'ta sahte SENT'in kendisi üzerinde Entity:Spawn kullanmaktan kaçının, çünkü bu, entity'yi oluşturan script tarafından yapılmalıdır. Risk, Entity:Spawn'ın iki kez çağrılabilmesidir.


Dördüncü adım: Altbilgi

Altbilgi, sahte SENT'in en önemli parçasıdır: beklenen entity'yi oluşturmak için Lua fonksiyonlarını değiştirir.

local old_FindByClass = ents.FindByClass function ents.FindByClass (class, ...) if class == ClassName then -- Diğer her şeyi hariç tutarak ClassName'i ara. local entities = {} for _, ent in pairs(old_FindByClass(BaseClassName)) do if ent:GetClass() == ClassName then entities[#entities+1] = ent end end return entities elseif class == BaseClassName then -- ClassName'i hariç tutarak BaseClassName'i ara. local entities = {} for _, ent in pairs(old_FindByClass(BaseClassName)) do if ent:GetClass() != ClassName then entities[#entities+1] = ent end end return entities else return old_FindByClass(class, ...) end end

ents.FindByClass("prop_vehicle_mr") çağrıldığında, prop_vehicle_mr sınıfındaki tüm entity'leri içeren bir tablo almak isteriz. Kod olmadan, tablo her zaman boş olurdu.

ents.FindByClass("prop_dynamic") çağrıldığında, prop_vehicle_mr sınıfındakiler hariç, prop_dynamic sınıfındaki tüm entity'leri içeren bir tablo almak isteriz. Kod olmadan, tablo prop_vehicle_mr sınıfındaki entity'leri de içerirdi.

Diğer durumlarda, ents.FindByClass eskisi gibi çalışacaktır.

local old_GetClass = BaseClass.GetClass function BaseClass:GetClass (...) -- if self[ClassName] then -- Networklenmemiş sınıf adı if self:GetNWBool(ClassName, false) then -- Networklenmiş sınıf adı return ClassName else return old_GetClass(self, ...) end end

Entity datatable'ındaki Entity:GetClass metodunu, sahte SENT'ler için doğru değerin döndürülmesi için değiştiririz.

Bazı nedenlerden dolayı, sahte SENT sınıfının istemciyle paylaşılması gerekmeyebilir. Bu durumda, buradaki ve aşağıdaki ents.Create bloğundaki uygun satırları yorum satırı yapın ve yorum satırından çıkarın.

local SENT_values = {} for FuncName, Func in pairs(ENT) do if isfunction(Func) then -- Bu bir fonksiyon değeridir. local old_Func = BaseClass[FuncName] if isfunction(old_Func) then -- Metot, temel sınıfta yeniden tanımlanmıştır. BaseClass[FuncName] = function (self, ...) if self:GetClass() == ClassName then return Func(self, ...) else return old_Func(self, ...) end end else -- Metot, temel sınıfta tanımlı değildir. SENT_values[FuncName] = Func end else -- Bu, fonksiyon olmayan bir değerdir. SENT_values[FuncName] = Func end end

İçerikte tanımlanan ve Entity datatable'ında bulunan tüm metotları değiştiririz.

Entity datatable'ında bulunmayan tüm metotları, ents.Create tarafından eklenecek bir tabloya ekleriz.

Tüm özellikleri ents.Create tarafından eklenecek bir tabloya ekleriz.

local old_Create = ents.Create function ents.Create (class, ...) if class == ClassName then local ent = old_Create(BaseClassName, ...) if IsValid(ent) then -- ent[ClassName] = true -- Networklenmemiş sınıf adı ent:SetNWBool(ClassName, true) -- Networklenmiş sınıf adı for k, v in pairs(SENT_values) do ent[k] = v end if isfunction(ent.Initialize) then ent:Initialize() end end return ent else return old_Create(class, ...) end end

ents.Create fonksiyonunu değiştiririz. Bu fonksiyon, sahte SENT'in adını işaretlemek için bir bayrak ekler ve SENT_values tablosundaki tüm özellikleri ve metotları ekler.


İşte kullanımı serbest, eksiksiz örnek:

-- Bu gerçek bir betikli sınıf değildir. prop_dynamic'ten türetilmiştir ve motor ile bazı Lua fonksiyonları tarafından bu şekilde tanınacaktır. -- prop_dynamic sınıfı, prop'un kendisi olmadan hareket edemeyen sabit bir fiziğe sahiptir. İhtiyacım olan şey bu. --## Üstbilgi verileri ##-- ENT.Type = "anim" local ENT = {} local BaseClass = FindMetaTable("Entity") local BaseClassName = "prop_dynamic" local ClassName = "prop_vehicle_mr" --## Normal bir betikli entity için neredeyse yazılacak olan kod ##-- AddCSLuaFile() -- Eğer varsayılan materyal modelin kendi materyali değilse, bir Materyal aracı varsayılan materyali ayarlamaya çalıştığında yeniden ayarlanmalıdır. local old_SetMaterial = BaseClass.SetMaterial function ENT:SetMaterial (materialName) if materialName != nil and materialName != "" then return old_SetMaterial(self, materialName) else if self.DefaultMaterial != nil then return old_SetMaterial(self, self.DefaultMaterial) else return old_SetMaterial(self, "") end end end function ENT:Initialize () end --## Altbilgi işlemleri ##-- local old_FindByClass = ents.FindByClass function ents.FindByClass (class, ...) if class == ClassName then -- Diğer her şeyi hariç tutarak ClassName'i ara. local entities = {} for _, ent in pairs(old_FindByClass(BaseClassName)) do if ent:GetClass() == ClassName then entities[#entities+1] = ent end end return entities elseif class == BaseClassName then -- ClassName'i hariç tutarak BaseClassName'i ara. local entities = {} for _, ent in pairs(old_FindByClass(BaseClassName)) do if ent:GetClass() != ClassName then entities[#entities+1] = ent end end return entities else return old_FindByClass(class, ...) end end local old_GetClass = BaseClass.GetClass function BaseClass:GetClass (...) -- if self[ClassName] then -- Networklenmemiş sınıf adı if self:GetNWBool(ClassName, false) then -- Networklenmiş sınıf adı return ClassName else return old_GetClass(self, ...) end end local SENT_values = {} for FuncName, Func in pairs(ENT) do if isfunction(Func) then -- Bu bir fonksiyon değeridir. local old_Func = BaseClass[FuncName] if isfunction(old_Func) then -- Metot, temel sınıfta yeniden tanımlanmıştır. BaseClass[FuncName] = function (self, ...) if self:GetClass() == ClassName then return Func(self, ...) else return old_Func(self, ...) end end else -- Metot, temel sınıfta tanımlı değildir. SENT_values[FuncName] = Func end else -- Bu, fonksiyon olmayan bir değerdir. SENT_values[FuncName] = Func end end local old_Create = ents.Create function ents.Create (class, ...) if class == ClassName then local ent = old_Create(BaseClassName, ...) if IsValid(ent) then -- ent[ClassName] = true -- Networklenmemiş sınıf adı ent:SetNWBool(ClassName, true) -- Networklenmiş sınıf adı for k, v in pairs(SENT_values) do ent[k] = v end end return ent else return old_Create(class, ...) end end

Tüm sunucular · GmodTR Launcher · Rehber · GMod Wiki · GmodTR nedir? · Sunucu ekle · Discord