# Sahte Scriptlenmiş Varlık Oluşturma

- **İngilizce aslı:** https://wiki.facepunch.com/gmod/Fake_Scripted_Entity_Creation
- **Çeviri tarihi:** 2025-09-08

> **UYARI:** 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**!

> **NOT:** `prop_dynamic` çarpışma davranışını [Entity:PhysicsInitStatic](https://gmod.tr/wiki/Entity:PhysicsInitStatic) ve [Entity:CreateBoneFollowers](https://gmod.tr/wiki/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](https://gmod.tr/wiki/ENTITY:Use) veya bir [ENTITY:Think](https://gmod.tr/wiki/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](https://gmod.tr/wiki/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.

```lua
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](https://gmod.tr/wiki/Global.AddCSLuaFile)**

```lua
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.

```lua
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:

```lua
MyEntity.DefaultMaterial = "materialname"
```

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

```lua
function ENT:Initialize ()
end
```

Bu örnekte, altbilgideki [ENTITY:Initialize](https://gmod.tr/wiki/ENTITY:Initialize) hook'unun uygulanması, [Entity:Spawn](https://gmod.tr/wiki/Entity:Spawn) kullandığınızda çağrıl**mama**sını sağlar. Bunun yerine, [ents.Create](https://gmod.tr/wiki/ents.Create) kullanıldığında hemen çağrılır.

Bu hook'ta sahte SENT'in kendisi üzerinde [Entity:Spawn](https://gmod.tr/wiki/Entity:Spawn) kullanmaktan kaçının, çünkü bu, entity'yi oluşturan script tarafından yapılmalıdır. Risk, [Entity:Spawn](https://gmod.tr/wiki/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.

```lua
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](https://gmod.tr/wiki/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](https://gmod.tr/wiki/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](https://gmod.tr/wiki/ents.FindByClass) eskisi gibi çalışacaktır.

```lua
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](https://gmod.tr/wiki/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.

```lua
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](https://gmod.tr/wiki/ents.Create) tarafından eklenecek bir tabloya ekleriz.

Tüm özellikleri [ents.Create](https://gmod.tr/wiki/ents.Create) tarafından eklenecek bir tabloya ekleriz.

```lua
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](https://gmod.tr/wiki/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:

```lua
-- 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
```

- [GMod Wiki ana sayfası](https://gmod.tr/wiki)

---

[Tüm sunucular](https://gmod.tr/) · [GmodTR Launcher](https://gmod.tr/launcher) · [Rehber](https://gmod.tr/rehber) · [GMod Wiki](https://gmod.tr/wiki) · [GmodTR nedir?](https://gmod.tr/hakkinda) · [Sunucu ekle](https://gmod.tr/sunucu-ekle) · [Discord](https://discord.gg/gmodtr)

Kaynak: https://gmod.tr/wiki/Fake_Scripted_Entity_Creation
