Menu
CoddyTech
flag Ar iconالعربيةdown icon

لا تثق أبدًا بالعميل

الدرس 7 من 18 في دورة لعبة Roblox: محاكي الحيوانات الأليفة على Coddy.

يتحكم اللاعب بجهازه، لذا يمكن للمخترق أن يجعله يرسل أي استدعاء بعيد، بأي شيء، ومن أي مكان، بالسرعة التي يريدها. إن إرسال Hit:FireServer(pile) من الجهة الأخرى من الخريطة مئة مرة في الثانية سيفرغ كل كومة في اللعبة.

لذلك يتحقق الخادم من كل طلب قبل تنفيذه:

  • أن تكون كومة حقيقية (كائن Instance ضمن workspace.Piles)،
  • أن يكون اللاعب على بُعد لا يتجاوز Settings.Reach منها،
  • وأن يكون قد مرّ على آخر ضربة له Settings.HitCooldown ثانية على الأقل.
if typeof(pile) ~= "Instance" or pile.Parent ~= piles then
	return
end

عندما تضغط على «تحقّق»، تنفّذ الاختبارات ما قد يفعله المخترق. القاعدة لكل استدعاء بعيد تكتبه: يطلب العميل، والخادم يقرر.

challenge icon

التحدي

متوسط

في PetServer، في بداية معالج Hit، أوقف التنفيذ دون تسجيل ضربة عندما:

  1. لا تكون الكومة عنصرًا من نوع Instance ضمن piles،
  2. لا يملك اللاعب شخصية، أو يكون HumanoidRootPart الخاص به على بُعد أكثر من Settings.Reach من الكومة بوحدة studs،
  3. تكون الضربة السابقة قبل أقل من Settings.HitCooldown ثانية (أبقِ local lastHit = {} قرب الأعلى، وسجّل time() عندما يُسمح بالضربة).

اضغط Play، ثم Check: الاختبارات تُشغّل المستغِل.

جرّب بنفسك

local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local Settings = require(game.ReplicatedStorage.Settings)

local remotes = game.ReplicatedStorage.Remotes
local piles = workspace.Piles
local pileSpot = {} -- كل كومة -> الموقع الذي تقف عليه

print("A Meadow pile gives " .. Settings.PileValue .. " coins")

-- يحصل كل لاعب على Coins في لوحة المتصدرين
Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local coins = Instance.new("IntValue")
	coins.Name = "Coins"
	coins.Parent = leaderstats
end)

-- كومة عملات في موقع: نسخة من ServerStorage.CoinPile مع صحتها
-- وقيمتها بوصفهما خاصيتين
local function spawnPile(spot)
	local pile = ServerStorage.CoinPile:Clone()
	pile.Position = spot.Position
	pile:SetAttribute("MaxHealth", Settings.PileHealth)
	pile:SetAttribute("Health", Settings.PileHealth)
	pile:SetAttribute("Value", Settings.PileValue)
	pileSpot[pile] = spot
	pile.Parent = piles
	return pile
end

-- تنقص الضربة 1 من صحة الكومة؛
-- عند 0 تتحطم الكومة وتمنح قيمتها
local function hitPile(player, pile)
	local health = pile:GetAttribute("Health") - 1
	if health > 0 then
		pile:SetAttribute("Health", health)
		return
	end
	player.leaderstats.Coins.Value += pile:GetAttribute("Value")
	local spot = pileSpot[pile]
	pileSpot[pile] = nil
	pile:Destroy()
	-- كومة جديدة في الموقع نفسه بعد بضع ثوانٍ
	task.delay(Settings.RespawnTime, spawnPile, spot)
end

-- كومة في كل موقع في Meadow
for _, spot in workspace.Zones.Meadow.Spawns:GetChildren() do
	spawnPile(spot)
end

-- يطلب العميل ضرب كومة
remotes.Hit.OnServerEvent:Connect(function(player, pile)
	hitPile(player, pile)
end)
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس لعبة Roblox: محاكي الحيوانات الأليفة