I have worked on a server-side of a goods delivery system that will allow the player to deliver goods to different locations for a cash reward. Other players can target this player for a smaller reward.
I am currently unhappy with the amount of code I have used and believe there might be better practices I can use to achieve the same results.
I have added comments to some of the code but feel most can be slightly self-explanatory however if you need any further explaining of what some parts do let me know and Iāll edit the post to include more.
Rbxl file: CodeReview2.rbxl (24.3 KB)
Latest plain text code:
--[[
Name: Smuggle System
Description: To allow players to deliver different items to random locations for rewards
Created: 13/10/19
Writer: SovereignFrost
--]]
local module = {}
local debounces = {}
local replicated = game:GetService('ReplicatedStorage')
local players = game:GetService('Players')
local shared_modules = replicated.Shared.Modules
local smuggle_module = require(shared_modules.Activities.Smuggle)
local award_stat = require(shared_modules.AwardStat)
local teleport_player = require(shared_modules.TeleportPlayer)
local tagModel = script.TagModel
local REMOTE_DEBOUNCE_TIME = 3
module.RemoveRemoteDebounce = function(player)
delay(REMOTE_DEBOUNCE_TIME, function()
debounces[player] = nil
end)
end
module.JobCooldown = function(player, job) -- Each job has their own unique cooldown
delay(smuggle_module.JOB_PAY_INCREASE[job].cooldown, function()
player.Cooldowns[job].Value = false
end)
end
module.DistanceCheck = function(part1, part2, maxDistance)
if maxDistance then
return (part1.Position - part2.Position).magnitude < maxDistance
end
return (part1.Position - part2.Position).magnitude
end
module.CanContinue = function(player, job)
local SHOULD_CHECK_IF_BY_SPAWN = smuggle_module.SPAWN_CHECK
local SHOULD_CHECK_IF_VALID_TEAM = smuggle_module.TEAM_CHECK
local hrt = player.Character:FindFirstChild('HumanoidRootPart')
local function teamCheck()
local VALID_TEAMS = smuggle_module.WHITELISTED_TEAMS
for _, _team in next, VALID_TEAMS do
local whitelisted
if player.Team.Name == _team then
whitelisted = true
end
if not whitelisted then
return false
end
end
end
local function spawnCheck()
local smuggleStart = smuggle_module.spawns:FindFirstChildOfClass('Part')
local distance = module.DistanceCheck(hrt, smuggleStart, smuggle_module.SPAWN_MAX_DISTANCE)
if not distance then
return false
end
end
if not debounces[player] then
if SHOULD_CHECK_IF_BY_SPAWN then
return spawnCheck()
end
if SHOULD_CHECK_IF_VALID_TEAM then
return teamCheck()
end
if player.GlobalChecks.JobActivated.Value == false and player.Cooldowns[job].Value == false then
debounces[player] = true
return true
end
end
end
module.ActivateGodmode = function(player, Time)
local originalMax = player.Character.Humanoid.MaxHealth
player.Character.Humanoid.MaxHealth = math.huge
player.Character.Humanoid.Health = math.huge
-- Temp god mode so that the player is not killed during the cutscene or
-- right as they begin
delay(Time, function()
player.Character.Humanoid.MaxHealth = originalMax
player.Character.Humanoid.Health = originalMax
end)
end
module.OnServerInvoke = function(player, args)
local contract_selected = args.contract
local contract_settings = smuggle_module.JOB_PAY_INCREASE[contract_selected]
if not contract_settings then
return false
end
if not player.Cooldowns:FindFirstChild(contract_selected) then
local new = Instance.new('BoolValue', player.Cooldowns)
new.Name = contract_selected
end
if ( module.CanContinue(player, contract_selected)) and args.functionFire == 'BeginSmuggle' then
delay(0, function()
module.RemoveRemoteDebounce(player)
end)
local leaderstats = player:FindFirstChild('Stats')
--[[
Ensure the player has enough money to buy into the contract
--]]
if (leaderstats.Dollars.Value < contract_settings.buy_in) or not contract_settings then
return false
end
if not player.Cooldowns:FindFirstChild(contract_selected) then
local new = Instance.new('BoolValue', player.Cooldowns)
new.Name = contract_selected
end
module.ActivateGodmode(player, 5)
--[[
Find a random destination from a list of points to send the player to
deliver the package
--]]
local myEvent = player:FindFirstChildOfClass('RemoteEvent')
local smuggleStart = smuggle_module.spawns:FindFirstChildOfClass('Part')
local points = smuggle_module.points:GetChildren()
local destination = Random.new():NextInteger(1, points)
local hrt = player.Character:FindFirstChild('HumanoidRootPart')
if destination then
teleport_player.TeleportPlayer(player, smuggleStart.Position, nil, 1)
player.GlobalChecks.JobActivated.Value = true
leaderstats.Dollars.Value = leaderstats.Dollars.Value - contract_settings.buy_in
local notificationArgs = {
_text = {title = 'SMUGGLE MISSION!', subText = 'Smuggle the package without detection to the drop off zone'},
_type = 'TopMiddle',
_time = 5,
_sound = 'MissionBegin'
}
local maxDeliverTime = smuggle_module.MAX_DELIVERY_TIME
local timeLeft = maxDeliverTime
myEvent:FireClient(player, {action = 'SendNotification', _tbl = notificationArgs})
myEvent:FireClient(player, {action = 'DirectPlayerTo', _tbl = {location = destination, maxDistanceApart = 5, maxDirectionTime = timeLeft}})
myEvent:FireClient(player, {action = 'SmuggleMissionBegin', timer = timeLeft, destination = destination})
local Inside
local INTERVAL = 1
local function Failed()
local notificationArgs = {
_text = {title = 'SMUGGLE MISSION!', subText = 'MISSION FAILED!'},
_type = 'TopMiddle',
_time = 3,
_sound = 'MissionBegin'
}
myEvent:FireClient(player, {action = 'SendNotification', _tbl = notificationArgs})
end
local function Success()
local notificationArgs = {
_text = {title = 'SMUGGLE MISSION!', subText = 'CRATE DELIVERED!'},
_type = 'TopMiddle',
_time = 3,
_sound = 'MissionBegin'
}
myEvent:FireClient(player, {action = 'SendNotification', _tbl = notificationArgs})
local timeTook = maxDeliverTime - timeLeft
local JOB_PAY_INCREASE = smuggle_module.JOB_PAY_INCREASE
local CASH = function(job, _time, _distance)
return JOB_PAY_INCREASE[job].cash --* (_distance / _time)
end
local xpReward = JOB_PAY_INCREASE[contract_selected].xp
local cashReward = CASH(contract_selected, timeTook, (smuggleStart.Position - destination.Position).magnitude)
award_stat.AwardXP(player, {amount = xpReward})
award_stat.AwardCash(player, {amount = cashReward})
end
--[[
Check if the player is inside a certain location by a magnitude radius
--]]
local function inRadius(args, amount, printData)
--[[
The amount value is to prevent local teleports by the client to cheat,
a serverside anti exploit will push them back preventing them from getting
a successful inRadius check.
--]]
local _hrt = args.hrt
local _destination = args.destination
local _maxDistance = args.maxDistance
if not _destination or not _hrt then
return true
end
if printData then
print( ( _hrt.Position - _destination.Position ).magnitude <= _maxDistance )
end
if (_hrt.Position - _destination.Position).magnitude <= _maxDistance then --smuggle_module.POINT_MAX_DISTANCE then
if amount <= 0 then
return true
else
wait(1)
return inRadius(args, amount - 1)
end
end
end
local function collectDogtag(tag, copyHRT, killer, bindableEvent)
local TimeToReachBackpack = 15
local TouchConnection
local Found
TouchConnection = tag.Dogtags.Touched:Connect(function(obj)
local touchPlr = players:GetPlayerFromCharacter(obj.Parent)
if touchPlr and touchPlr == killer then
Found = true
TouchConnection:Disconnect()
end
end)
while true do
wait(1)
TimeToReachBackpack = TimeToReachBackpack -1
if TimeToReachBackpack <= 0 then
print('Didnt reach in time')
copyHRT:Destroy()
tag:Destroy()
break
end
if Found then
print(killer.Name .. ' has collected the killtag')
copyHRT:Destroy()
tag:Destroy()
award_stat.AwardXP(killer, {amount = 20})
award_stat.AwardCash(killer, {amount = 50})
local notificationArgs = {
_text = {title = 'SMUGGLE MISSION!', subText = 'CRATE DESTROYED!'},
_type = 'TopMiddle',
_time = 3,
_sound = 'MissionBegin'
}
myEvent:FireClient(killer, {action = 'SendNotification', _tbl = notificationArgs})
break
end
bindableEvent:Fire(1)
end
end
local charLoaded = player.GlobalChecks.CharacterLoads
local startCharLoaded = charLoaded.Value
local creator_tag
local died = false
player.Character.Humanoid.ChildAdded:Connect(function(obj)
if obj.Name == 'creator' then
creator_tag = obj
end
end)
player.Character.Humanoid.Died:Connect(function()
died = true
end)
while true do
wait(INTERVAL)
--print(timeLeft)
timeLeft = timeLeft - INTERVAL
if not player or not player.Parent then
break
elseif timeLeft <= 0 or not player.Character or charLoaded.Value > startCharLoaded then
print('Failed')
Failed()
break
elseif died or player.Character.Humanoid.Health <=0 then
delay(0, function()
Failed()
end)
print('Dead')
if creator_tag then
print('Found creator')
if creator_tag.Value then
print(creator_tag.Value)
local owner = creator_tag.Value
local function lockModel(model)
for _, v in next, model:GetDescendants() do
if v:IsA('BasePart') then
v.Anchored = true
end
end
end
--[[
Set a "dogtag" model to where the player was eliminated from
and check if the killer collects it to receive his reward
--]]
local character = owner.Character
local copyHRT = player.Character.HumanoidRootPart:Clone()
lockModel(copyHRT)
copyHRT.Parent = workspace
copyHRT.Transparency = 0.5
copyHRT.BrickColor = BrickColor.new('Really red')
local tag = tagModel:Clone()
tag:SetPrimaryPartCFrame(copyHRT.CFrame)
tag.Parent = workspace
print('Created tag..')
local bindableEvent = Instance.new('BindableEvent')
collectDogtag(tag, copyHRT, owner, bindableEvent)
local response = bindableEvent.Event:Wait()
if response == 1 then
bindableEvent:Destroy()
break
end
end
end
break
else
delay(0, function()
local tbl = {hrt = hrt, destination = destination, maxDistance = smuggle_module.POINT_MAX_DISTANCE}
if inRadius(tbl, 1.8) then
Inside = true
end
end)
if Inside and timeLeft > 0 then
Success()
print('Success!')
break
end
end
end
player.Cooldowns[contract_selected].Value = true
print('Time to delete the contract')
myEvent:FireClient(player, {action = 'SmuggleMissionOver'})
player.GlobalChecks.JobActivated.Value = false
module.JobCooldown(player, contract_selected)
else
error('Issue finding destination from module.RandomChild')
end
end
end
return module
Plain text code 1.0:
Summary
local module = {}
local debounces = {}
local replicated = game:GetService('ReplicatedStorage')
local shared_modules = replicated.Shared.Modules
local smuggle_module = require(shared_modules.Activities.Smuggle)
local TagModel = script.TagModel
module.DeleteDebounce = function(player)
delay(3, function()
debounces[player] = nil
end)
end
module.DeleteContractDebounces = function(player, job)
delay(smuggle_module.JOB_PAY_INCREASE[job].cooldown, function()
player.Cooldowns[job].Value = false
end)
end
module.RandomChild = function(Table)
return Table[math.random(#Table)]
end
module.CanContinue = function(player, job)
local CHECK_IF_BY_SPAWN = smuggle_module.SPAWN_CHECK
local CHECK_IF_CORRECT_TEAM = smuggle_module.TEAM_CHECK
if not debounces[player] then
local hrt = player.Character:FindFirstChild('HumanoidRootPart')
if CHECK_IF_BY_SPAWN then
local smuggleStart = smuggle_module.spawns:FindFirstChildOfClass('Part')
if (hrt.Position - smuggleStart.Position).magnitude > smuggle_module.SPAWN_MAX_DISTANCE then
return false
end
end
if CHECK_IF_CORRECT_TEAM then
local VALID_TEAMS = smuggle_module.WHITELISTED_TEAMS
for _, _team in next, VALID_TEAMS do
local whitelisted
if player.Team.Name == _team then
whitelisted = true
end
if not whitelisted then
return false
end
end
end
if player.GlobalChecks.JobActivated.Value == false and player.Cooldowns[job].Value == false then
debounces[player] = true
return true
end
end
end
module.OnServerInvoke = function(player, args)
local contract_selected = args.contract
local contract_settings = smuggle_module.JOB_PAY_INCREASE[contract_selected]
if not contract_settings then
return false
end
if not player.Cooldowns:FindFirstChild(contract_selected) then
local new = Instance.new('BoolValue', player.Cooldowns)
new.Name = contract_selected
end
if ( module.CanContinue(player, contract_selected)) and args.functionFire == 'BeginSmuggle' then
delay(0, function()
module.DeleteDebounce(player)
end)
local leaderstats = player:FindFirstChild('Stats')
local awardStat = require(shared_modules.AwardStat)
--[[
Ensure the player has enough money to buy into the contract
--]]
if leaderstats.Dollars.Value < contract_settings.buy_in then
return false
end
if not contract_settings then
return false
end
if not player.Cooldowns:FindFirstChild(contract_selected) then
local new = Instance.new('BoolValue', player.Cooldowns)
new.Name = contract_selected
end
--[[
Find a random destination from a list of points to send the player to
deliver the package
--]]
local myEvent = player:FindFirstChildOfClass('RemoteEvent')
local smuggleStart = smuggle_module.spawns:FindFirstChildOfClass('Part')
local destination = module.RandomChild(smuggle_module.points:GetChildren())
local hrt = player.Character:FindFirstChild('HumanoidRootPart')
if destination then
local originalMax = player.Character.Humanoid.MaxHealth
player.Character.Humanoid.MaxHealth = math.huge
player.Character.Humanoid.Health = math.huge
-- Temp god mode so that the player is not killed during the cutscene or right as they begin
delay(5, function()
player.Character.Humanoid.MaxHealth = originalMax
player.Character.Humanoid.Health = originalMax
end)
local tp = require(shared_modules.TeleportPlayer)
tp.TeleportPlayer(player, smuggleStart.Position, nil, 1)
player.GlobalChecks.JobActivated.Value = true
leaderstats.Dollars.Value = leaderstats.Dollars.Value - contract_settings.buy_in
local notificationArgs = {
_text = {title = 'SMUGGLE MISSION!', subText = 'Smuggle the package without detection to the drop off zone'},
_type = 'TopMiddle',
_time = 5,
_sound = 'MissionBegin'
}
local maxDeliverTime = smuggle_module.MAX_DELIVERY_TIME
local timeLeft = maxDeliverTime
myEvent:FireClient(player, {action = 'SendNotification', _tbl = notificationArgs})
myEvent:FireClient(player, {action = 'DirectPlayerTo', _tbl = {location = destination, maxDistanceApart = 5, maxDirectionTime = timeLeft}})
myEvent:FireClient(player, {action = 'SmuggleMissionBegin', timer = timeLeft, destination = destination})
local Inside
local INTERVAL = 1
local function Failed()
local notificationArgs = {
_text = {title = 'SMUGGLE MISSION!', subText = 'MISSION FAILED!'},
_type = 'TopMiddle',
_time = 3,
_sound = 'MissionBegin'
}
myEvent:FireClient(player, {action = 'SendNotification', _tbl = notificationArgs})
end
local function Success()
local notificationArgs = {
_text = {title = 'SMUGGLE MISSION!', subText = 'CRATE DELIVERED!'},
_type = 'TopMiddle',
_time = 3,
_sound = 'MissionBegin'
}
myEvent:FireClient(player, {action = 'SendNotification', _tbl = notificationArgs})
local timeTook = maxDeliverTime - timeLeft
local JOB_PAY_INCREASE = smuggle_module.JOB_PAY_INCREASE
local CASH = function(job, _time, _distance)
return JOB_PAY_INCREASE[job].cash --* (_distance / _time)
end
local xpReward = JOB_PAY_INCREASE[contract_selected].xp
local cashReward = CASH(contract_selected, timeTook, (smuggleStart.Position - destination.Position).magnitude)
awardStat.AwardXP(player, {amount = xpReward})
awardStat.AwardCash(player, {amount = cashReward})
end
--[[
Check if the player is inside a certain location by a magnitude radius
--]]
local function inRadius(args, amount, printData)
--[[
The amount value is to prevent local teleports by the client to cheat,
a serverside anti exploit will push them back preventing them from getting
a successful inRadius check.
--]]
local _hrt = args.hrt
local _destination = args.destination
local _maxDistance = args.maxDistance
if not _destination then
return true
end
if not _hrt then
return false
end
if printData then
print( ( _hrt.Position - _destination.Position ).magnitude <= _maxDistance )
end
if (_hrt.Position - _destination.Position).magnitude <= _maxDistance then --smuggle_module.POINT_MAX_DISTANCE then
if amount <= 0 then
return true
else
wait(1)
return inRadius(args, amount - 1)
end
end
end
local charLoaded = player.GlobalChecks.CharacterLoads
local startCharLoaded = charLoaded.Value
local creator_tag
local died = false
player.Character.Humanoid.ChildAdded:Connect(function(obj)
if obj.Name == 'creator' then
creator_tag = obj
end
end)
player.Character.Humanoid.Died:Connect(function()
died = true
end)
while true do
wait(INTERVAL)
--print(timeLeft)
timeLeft = timeLeft - INTERVAL
if timeLeft <= 0 or not player.Character or charLoaded.Value > startCharLoaded then
print('Failed')
Failed()
break
elseif not player then
break
elseif died or player.Character.Humanoid.Health <=0 then
delay(0, function()
Failed()
end)
print('Dead')
if creator_tag then
print('Found creator')
if creator_tag.Value then
print(creator_tag.Value)
local owner = creator_tag.Value
local function lockModel(model)
for _, v in next, model:GetDescendants() do
if v:IsA('BasePart') then
v.Anchored = true
end
end
end
--[[
Set a "dogtag" model to where the player was eliminated from
and check if the killer collects it to receive his reward
--]]
local character = owner.Character
local copyHRT = player.Character.HumanoidRootPart:Clone()
lockModel(copyHRT)
copyHRT.Parent = workspace
copyHRT.Transparency = 0.5
copyHRT.BrickColor = BrickColor.new('Really red')
local tag = TagModel:Clone()
tag:SetPrimaryPartCFrame(copyHRT.CFrame)
tag.Parent = workspace
print('Created tag..')
local Found = false
local TimeToReachBackpack = 15
local Players = game:GetService('Players')
local TouchConnection
TouchConnection = tag.Dogtags.Touched:Connect(function(obj)
local touchPlr = Players:GetPlayerFromCharacter(obj.Parent)
if touchPlr and touchPlr == owner then
Found = true
TouchConnection:Disconnect()
end
end)
--delay(0, function()
while true do
wait(1)
TimeToReachBackpack = TimeToReachBackpack -1
if TimeToReachBackpack <= 0 then
print('Didnt reach in time')
copyHRT:Destroy()
tag:Destroy()
break
end
if Found then
print(owner.Name .. ' has collected the killtag')
copyHRT:Destroy()
tag:Destroy()
awardStat.AwardXP(owner, {amount = 20})
awardStat.AwardCash(owner, {amount = 50})
local notificationArgs = {
_text = {title = 'SMUGGLE MISSION!', subText = 'CRATE DESTROYED!'},
_type = 'TopMiddle',
_time = 3,
_sound = 'MissionBegin'
}
myEvent:FireClient(owner, {action = 'SendNotification', _tbl = notificationArgs})
break
end
end
break
--end)
end
end
break
else
delay(0, function()
local tbl = {hrt = hrt, destination = destination, maxDistance = smuggle_module.POINT_MAX_DISTANCE}
if inRadius(tbl, 1.8) then
Inside = true
end
end)
if Inside and timeLeft > 0 then
Success()
print('Success!')
break
end
end
end
player.Cooldowns[contract_selected].Value = true
print('Time to delete the contract')
myEvent:FireClient(player, {action = 'SmuggleMissionOver'})
player.GlobalChecks.JobActivated.Value = false
module.DeleteContractDebounces(player, contract_selected)
else
error('Issue finding destination from module.RandomChild')
end
end
end
return module
Thank you for reading