A “party” system module for a game, that teleported players to places within the game.
-- Lugical
local PlayerService = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TelerportService = game:GetService("TeleportService")
local updatePartyEvent = ReplicatedStorage.UpdatePartyStatus
local mainPlaceID = {["Urban Falls"] = 5041125493, ["East Bay Port"] = 5119882137}
local Party = {}
local PartyGroups = {}
Party.__index = Party
--CONFIGURATIONS COMPONENT ORDER
--map
--public status
--rank requirement
--difficulty
--leader
--people
--Party Module
--Create the system where party groups are formed, and can be dealt with accordingly
function Party.new(configurations, play) -- Create a new party group
local newPartyFormed = {} -- Metatable Work
setmetatable(newPartyFormed, Party)
table.insert(PartyGroups, newPartyFormed)
newPartyFormed.Map = configurations.Map -- Attach the party settings to the party group
newPartyFormed.PublicStatus = configurations.PublicStatus
newPartyFormed.RankRequirement = configurations.RankRequirement
newPartyFormed.Difficulty = configurations.Difficulty
newPartyFormed.PartyLeader = play
newPartyFormed.People = configurations.People
return newPartyFormed, PartyGroups -- Send the new party group to the server
end
function Party:Remove(yieldForPlayerExit, forceShutdown) -- Get rid of a party group. Optional argument to wait for all players to leave and to shutdown regardless.
if self.People then -- Checks if people values are there.
if not forceShutdown then
local canRemove = true -- Sees if players are out/party is ready to be removed
for index, player in pairs(self.People) do
if player then
if yieldForPlayerExit then
local found = false
PlayerService.PlayerRemoving:Connect(function(plr)
if plr == player then
found = true
end
end)
while not found do
PlayerService.PlayerRemoving:Wait()
game:GetService("RunService").Heartbeat:Wait()
end
if index >= #self.People then
canRemove= true
end
else
canRemove = false
end
end
end
if canRemove then -- Sends back whether party can be removed
ReplicatedStorage.PartyChange:FireAllClients(false, tostring(self), self)
if workspace:FindFirstChild("PARTY: "..tostring(self)) then
wait(1)
workspace:FindFirstChild("PARTY: "..tostring(self)):Destroy()
end
table.remove(PartyGroups, table.find(PartyGroups, self))
self = {}
return true, PartyGroups
else
return false, PartyGroups
end
else
for _, v in pairs(self.People) do
if v and v ~= self.PartyLeader then
ReplicatedStorage.PartySignal:FireClient(v, nil, "Shutdown")
end
end
ReplicatedStorage.PartyChange:FireAllClients(false, tostring(self), self)
if workspace:FindFirstChild("PARTY: "..tostring(self)) then
workspace:FindFirstChild("PARTY: "..tostring(self)):Destroy()
end
table.remove(PartyGroups, table.find(PartyGroups, self))
self = {}
return true, PartyGroups
end
else
ReplicatedStorage.PartyChange:FireAllClients(false, tostring(self), self)
table.remove(PartyGroups, table.find(PartyGroups, self))
self = {}
return true, PartyGroups
end
end
function Party:JoinRequest(requestingPlayer) -- Handles player requests
if self.PublicStatus then -- If public server, automatically handle the joining process
if not table.find(self.People, requestingPlayer) then
print()
if #self.People < 6 then
table.insert(self.People, requestingPlayer)
ReplicatedStorage.UpdatePartyStatus:FireAllClients(self, tostring(self))
ReplicatedStorage.EventSignal:FireAllClients(requestingPlayer)
return true, PartyGroups
else
return false, PartyGroups, "FullParty"
end
else
return false, PartyGroups, "NoIssue"
end
else -- If private, handle it with owner approval first
local grantedStatus = ReplicatedStorage.PlayerRequest:InvokeClient(self.PartyLeader, requestingPlayer)
print("GSIUF", grantedStatus)
if grantedStatus and grantedStatus == requestingPlayer and #self.People < 6 then
local inAnotherParty = false
for pos, party in pairs(PartyGroups) do
for _, player in pairs(party) do
if player then
if player == requestingPlayer then
inAnotherParty = true
end
else
table.remove(party, pos)
end
end
end
if not inAnotherParty then
table.insert(self.People, #self.People +1, requestingPlayer)
updatePartyEvent:FireAllClients(self, tostring(self))
ReplicatedStorage.EventSignal:FireAllClients(requestingPlayer)
return true, PartyGroups
end
else
return false, PartyGroups, "NoIssue"
end
end
end
function Party:RemovePlayer(player)
if player == self.PartyLeader then
self:Remove(false, true)
else
for position, person in pairs(self.People) do
if person == player then
table.remove(self.People, position)
updatePartyEvent:FireAllClients(self)
end
end
end
return PartyGroups
end
function Party:Teleport()
if self.People then
local people = {}
for i, v in pairs(self.People) do
if v then
table.insert(people, v)
else
table.remove(self.People, i)
end
end
pcall(function()
local reservedServerKey = TelerportService:ReserveServer(mainPlaceID[self.Map])
TelerportService:TeleportToPrivateServer(mainPlaceID[self.Map], reservedServerKey, people)
end)
end
end
return Party
A quick patch I posted on the DevForums about a “chat exploit”. It checks for the remote being spammed, and whether the contents being sent to the server are out of the ordinary. If so, it’ll kick the player and place them on a temporary ban from that server.
local characterLimit = 16384 --> Based on console
local counter = {} --> Counts issues from input
local counter2 = {} --> Counts issues from remote firing
local serverBanList = {} --> List of players banned from the server due to the exploit
local defaultMessage = "Abnormal activity was detected."
game.Players.PlayerAdded:Connect(function(player)
if table.find(serverBanList, player.UserId) then
player:Kick(defaultMessage)
else
counter[player.UserId] = 0 --> Number of times input would've caused an error
counter2[player.UserId] = {false, 0, 0} --> isTrackingCount, # of remotes sent by player in a second, # of "strikes"
end
end)
local ChatService = require(game.ServerScriptService:WaitForChild("ChatServiceRunner"):WaitForChild("ChatService"))
local eventListener = game:GetService('ReplicatedStorage').DefaultChatSystemChatEvents:WaitForChild('SayMessageRequest')
--> Detects if the message or channel inputs are abnormal
eventListener.OnServerEvent:Connect(function(plr, message, channel)
if counter2[plr.UserId] and not counter2[plr.UserId][1] then
coroutine.wrap(function() --> Start new thread so it doesn't wait for other "checkers"
counter2[plr.UserId][1] = true
wait(.5)
counter2[plr.UserId][1] = false
if counter2[plr.UserId][2] >= 7 then --> Arbitrary, feel free to change the 7.
counter2[plr.UserId][3] = 1 + counter2[plr.UserId][3]
if counter2[plr.UserId][3] > 1 then
plr:Kick(defaultMessage)
table.insert(serverBanList, plr.UserId)
end
end
end)
elseif counter2[plr.UserId] then
counter2[plr.UserId][2] = counter2[plr.UserId][2] + 1
end
if not ChatService:GetChannel(channel) then
counter[plr.UserId] = counter[plr.UserId] + 1
end
if string.len(message) > characterLimit then
counter[plr.UserId] = counter[plr.UserId] + 2
end
if counter[plr.UserId] > 1 then
plr:Kick(defaultMessage)
table.insert(serverBanList, plr.UserId)
end
end)
For UI, I made a falling block animation, with a map spawner.
The falling block script:
math.randomseed(tick())
local timeToFall = .625
local camera = workspace.CurrentCamera
local tweenService = game:GetService("TweenService")
local runService = game:GetService("RunService")
local info = TweenInfo.new(timeToFall+.1, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0)
local info2 = TweenInfo.new(timeToFall * 2, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0)
local information = TweenInfo.new(7, Enum.EasingStyle.Sine, Enum.EasingDirection.Out, 0)
local dupedFrame = script.Parent.Frame
local fullFrame = script.Parent.FullFrame
local jumpIn = .25
local messages = {"The Next Map", "Created by willcq", "Get Ready!"}
local farmCoordinates = {
{Vector3.new(-1546.14636, -1.72039771, 50.696106), Vector3.new(-1544.39026, -1.70912862, 51.6531601), Vector3.new(-1529.35156, -2.05191469, 58.8550339), Vector3.new(-1527.58887, -2.01970029, 59.7995262)}, --> C1, F1, C2, F2
{Vector3.new(-1443.21265, 4.05529308, 119.708214), Vector3.new(-1444.39966, 3.43780231, 118.221703), Vector3.new(-1447.6311, -1.53761768, 111.159401), Vector3.new(-1448.729, -1.82998323, 109.513451)},
{Vector3.new(-1435.4248, 8.99509907, 170.079758), Vector3.new(-1436.63721, 9.06910992, 168.490829), Vector3.new(-1425.79675, 6.19084644, 189.666412), Vector3.new(-1426.76404, 6.51472759, 187.946106)},
}
local factoryCoordinates = {
{Vector3.new(-1521.82068, 21.7119064, 144.432327), Vector3.new(-1520.71887, 20.9670372, 142.938599), Vector3.new(-1516.05908, 17.8692665, 136.540497), Vector3.new(-1514.91846, 17.114645, 135.081207)},
{Vector3.new(-1458.85706, 17.5081272, 128.109406), Vector3.new(-1460.1438, 16.63867, 126.848846), Vector3.new(-1452.32837, 21.6742897, 134.032379), Vector3.new(-1453.64624, 20.7954922, 132.81134)},
{Vector3.new(-1522.63782, -9.35536289, 122.778023), Vector3.new(-1521.6283, -8.99966526, 121.088554), Vector3.new(-1517.20093, 0.0427943468, 113.493813), Vector3.new(-1516.21704, 0.263785481, 111.76664)},
}
local subwayCoordinates = {
{Vector3.new(-1524.39746, 7.47533417, 147.319275), Vector3.new(-1523.0741, 6.84747219, 145.957199), Vector3.new(-1515.19788, 3.58258319, 138.255798), Vector3.new(-1513.60022, 3.18745136, 137.119293)},
{Vector3.new(-1446.60913, 5.23921156, 72.6108093), Vector3.new(-1444.96667, 5.37550163, 71.4777832), Vector3.new(-1459.45667, 3.89753532, 86.0056305), Vector3.new(-1457.93201, 4.0233736, 84.7172394)},
{Vector3.new(-1459.61987, -2.1936028, 68.2351074), Vector3.new(-1460.67261, -2.2778933, 69.9334946), Vector3.new(-1467.23853, -2.6162374, 80.2618713), Vector3.new(-1468.31396, -2.50164557, 81.9442215)},
}
local convert = {
["FarmFrame"] = farmCoordinates,
["FactoryFrame"] = factoryCoordinates,
["SubwayFrame"] = subwayCoordinates,
}
local map = {
["FarmFrame"] = "Farmlands",
["FactoryFrame"] = "The Factory",
["SubwayFrame"] = "The Subway",
}
local function scramble(min, max)
local fullSet = {min, max}
local current = max
while current - 1 > min do
table.insert(fullSet, current - 1)
current = current - 1
end
local randomNumbers = {}
local randomizedSet = {}
for i = 1, #fullSet do
local random = math.random(1, #fullSet)
if not table.find(randomNumbers, random) then
table.insert(randomNumbers, random)
table.insert(randomizedSet, fullSet[random])
else
while table.find(randomNumbers, random) do
runService.RenderStepped:Wait()
random = math.random(1, #fullSet)
end
table.insert(randomNumbers, random)
table.insert(randomizedSet, fullSet[random])
end
end
return randomizedSet
end
local UIs = {}
local function pile(visibleText)
local tween = tweenService:Create(game.Lighting.Blur, info2, {Size = 30})
tween:Play()
for i = .85, -.2, -.125 do
spawn(function()
local randomSet = scramble(0, 10)
for _, pos in pairs(randomSet) do
local newFrame = dupedFrame:Clone()
newFrame.Parent = fullFrame
newFrame.Position = UDim2.new((pos/10)-.05, 0, -.2, 0)
newFrame.Rotation = math.random(-20, 20)
newFrame.Visible = true
newFrame:TweenPosition(UDim2.new(newFrame.Position.X.Scale, 0, i, 0), "Out", "Bounce", timeToFall, true)
local tween = tweenService:Create(newFrame, info, {Rotation = math.random(-5,5)})
tween:Play()
wait(.05)
end
end)
wait(jumpIn)
end
wait(2.5)
for _, v in pairs(game.Players.LocalPlayer:WaitForChild("PlayerGui"):GetChildren()) do
if v.Name ~= "Cutscenes" and v.Name ~= "Chat" and v:IsA("ScreenGui") and v.Enabled then
v.Enabled = false
table.insert(UIs, v)
end
end
fullFrame.BackgroundTransparency = 0
for _, v in pairs(fullFrame:GetChildren()) do
v:Destroy()
end
if visibleText then
script.Parent.MapName.Visible = true
script.Parent.BottomFrame.Visible = true
script.Parent.BottomFrame.BottomText.Text = "The Next Map"
else
for _, v in pairs(UIs) do
v.Enabled = true
end
UIs = {}
script.Parent.MapName.Visible = false
script.Parent.BottomFrame.Visible = false
end
camera.CameraType = Enum.CameraType.Custom
local tween = tweenService:Create(fullFrame, info2, {BackgroundTransparency = 1})
tween:Play()
local tween1 = tweenService:Create(game.Lighting.Blur, info2, {Size = 2})
tween1:Play()
end