Copy salient and essential scripts and models from Plane Building Roblox

This commit is contained in:
2026-06-10 02:53:40 +01:00
commit 891781366d
76 changed files with 10904 additions and 0 deletions
+205
View File
@@ -0,0 +1,205 @@
chat = {}
local rchat=game:GetService("Chat")
function chat.Chat(ignore,object,text)
if not object then return end
rchat:Chat(object,text)
--print("AUTO:",text) --
end
local function advancedTarget(pS,t,o) -- pS = projectileSpeed, t = targetPart, o = originPart
-- So, I understand the maths in this. I also understand that it forms a circle for radius of targetting, also the curve to find it is quadratic and there is sine somewhere too
-- https://devforum.roblox.com/t/making-a-lead-shot-indicator/325666/9 (figure out the maths here when you're older, i understand it but not confidently)
local tV = t.Velocity * 1.1 -- target Velocity, *1.5 because of compensation
local di = t.Position - o.Position -- displacement, origin to target
local a = pS^2 - tV:Dot(tV) -- a,b,c as in quadratic equation so that ax^2 + bx + c = 0
local b = -2 * tV:Dot(di)
local c = -di:Dot(di)
local d = b^2 - 4*a*c -- d as an intermediate value for quadratic formula
if d < 0 then return t.Position end -- failed, let's just hope we hit it anyways by luck
local t0 = (-b + math.sqrt(d)) / (2*a) -- hello mr. hegarty, i exist
local t1 = (-b - math.sqrt(d)) / (2*a)
local ti = 0
if t0 > 0 then ti = t0 end
if t1 > 0 then ti = t1 end
local target = t.CFrame.Position + tV * ti
return target
end
function travelToLocation(a)
a.humanoid:MoveTo(a.target.Position)
end
function findPlayer(a)
local closest
local distance = 100
for _,player in pairs(game.Players:GetPlayers()) do
if player.Character and player.Character:FindFirstChild("Humanoid") then
local currentDistance = (player.Character.PrimaryPart.Position - a.head.Position).Magnitude
if currentDistance < distance then distance = currentDistance end
closest = player.Character.PrimaryPart
end
end
if closest then a.task = travelToLocation a.target = closest end
end
function enterPlane(a)
--[[local pathfinding = game:GetService("PathfindingService")
local path = pathfinding:CreatePath({
AgentCanJump = true,
AgentHeight = 4,
AgentWidth = 4
})
chat:Chat(a.head,"computing")
path:ComputeAsync(a.model.PrimaryPart.Position,a.plane.Position)
if path.Status ~= Enum.PathStatus.Success then
chat:Chat(a.head,"no path")
a.model:SetPrimaryPartCFrame(a.plane.CFrame)
a.task = getTask return end
a.plane.Material = Enum.Material.Neon
a.plane.Transparency = 0.5
chat:Chat(a.head,"walking")
local waypointIndex = 0
local waypoints = path:GetWaypoints()
local function operateWaypoint()
if not a.operate then return end
if a.humanoid.SeatPart then chat:Chat(a.head,"piloting") a.task = flyPlane return end
waypointIndex = waypointIndex + 1
if waypointIndex > #waypoints or not waypoints[waypointIndex] then return end
a.humanoid:MoveTo(waypoints[waypointIndex].Position)
local shouldReturn = false
local event = a.humanoid.MoveToFinished:Connect(function()
if waypoints[waypointIndex] and not a.humanoid.SeatPart and waypoints[waypointIndex].Action == Enum.PathWaypointAction.Jump then
a.humanoid.Jump = true
end
shouldReturn = true
operateWaypoint()
end)
wait(1)
if not a.plane or not a.plane:FindFirstChild("Pilot") then return end
event:Disconnect()
if (a.model.PrimaryPart.Position - a.plane.Position).Magnitude < 6 then
end
if shouldReturn then return end
operateWaypoint()
end
operateWaypoint()]]
a.model:SetPrimaryPartCFrame(a.plane.CFrame)
a.task = flyPlaneStraight
a.v.parent = a.plane.Parent.Parent
a.target = game.Workspace.BotTarget.Position
end
local flight = require(_G.Modules.ObjectInteraction.Main)
function flyPlaneStraight(a)
if not a.flyPlaneStraightTick then a.flyPlaneStraightTick = tick() end
if (tick() - a.flyPlaneStraightTick) > 3 then a.task = flyPlane a.flyPlaneStraightTick = nil end
a.v.bindings.throttle = 0.8
a.v.bindings.pitch = 0.3
a.v.bindings.roll = 0
a.v.bindings.yaw = 0
local tar = a.plane.CFrame.LookVector
tar = Vector3.new(tar.X,0,tar.Z).Unit
local pos = (a.plane.Position + tar * 1000 + Vector3.new(0,150,0))
a.v:aimTowards(pos)
end
function stop(a)
end
local trajectoryPart = Instance.new("Part")
for index,item in pairs({
Color = Color3.new(1,1,1),
Material = Enum.Material.Neon,
Transparency = 0.2,
Size = Vector3.new(6,6,6),
CanCollide = false,
Anchored = true,
Shape = Enum.PartType.Ball,
Parent = game.Workspace
}) do
trajectoryPart[index] = item
end
local targetPart = trajectoryPart:Clone()
targetPart.Parent = game.Workspace
function flyPlane(a)
a.target = a.model.Target.Value.PrimaryPart.Position
local trajectory = a.plane.Velocity*2 + a.plane.Position
trajectoryPart.Position = trajectory
targetPart.Position = a.target
print(trajectory)
if trajectory.Y < -20 then
a.task = flyPlaneStraight
print("recover!")
end
a.v.bindings.pitch = 0.0
a.v.bindings.yaw = 0
a.v:aimTowards(a.target)
local speed = a.plane.Velocity.Magnitude
if speed > 350 or speed < 50 or a.plane.Position.Y < -40 then print("stop!",speed) a.task = stop a.v.bindings.throttle = 0 task.delay(1,function() a.humanoid.Health = 0 end) end
end
function getTask(a)
chat:Chat(a.head,"task")
wait(0.5)
if a.humanoid.SeatPart then chat:Chat(a.head,"piloting") a.task = flyPlaneStraight return end
a.task = locatePlane
chat:Chat(a.head,"pilot")
end
function selfDestruct(a)
chat:Chat(a.head,"destruct")
a.humanoid.Health = 0
end
function locatePlane(a)
chat:Chat(a.head,"find plane")
a.plane = nil
local distance = 100
for _,object in pairs(game.Workspace.Auto:GetChildren()) do
local seat = object:FindFirstChildWhichIsA("VehicleSeat",true)
if seat and not seat.Occupant then
local offset = (seat.Position - a.head.Position).Magnitude
if offset < distance then
distance = offset
a.plane = seat
end
end
end
if a.plane then
chat:Chat(a.head,"found plane")
a.task = enterPlane
return
end
chat:Chat(a.head,"no plane")
a.task = selfDestruct
end
function hibernate(a)
end
function init(auto)
local a = {}
a.model = auto
a.head = auto.Head
if a.head:FindFirstChildWhichIsA("SurfaceGui") then a.head.SurfaceGui:Destroy() end
a.face = a.head.Face
a.humanoid = auto.Humanoid
a.team = auto.Team.Value
a.operate = true
wait()
a.plane = a.humanoid.SeatPart
a.task = flyPlaneStraight
a.v = flight.initialise(a.head)
a.v.parent = a.humanoid.SeatPart.Parent.Parent
a.v:seatEntered(true,a.humanoid.SeatPart)
a.target = (a.plane.CFrame * CFrame.new(0,0,1000)).Position
a.target = Vector3.new(a.target.X,a.plane.CFrame.Position.Y + 100,a.target.Z)
a.humanoid.Died:Connect(function()
wait(2)
a.operate = false
a.v.operate = false
a.v:destroy()
a.model:Destroy()
end)
while wait((1/30)*3) and a.operate do
a.task(a)
end
end
return getfenv()
+63
View File
@@ -0,0 +1,63 @@
local autoModel = _G.Storage.Assets.Autos:WaitForChild("Auto")
local planeModel = _G.Storage.Assets.Vehicles:WaitForChild("BP-10")
local purchaseModule = require(game.ServerScriptService.PurchaseModule)
teams = {}
function init(parent)
wait(1)
local m = parent
local team = game.Teams[parent.Parent.Name]
local autoSpawn = parent:WaitForChild("AutoSpawn")
local planeSpawn = parent:WaitForChild("PlaneSpawn")
local function lockPlane(plane)
plane.Pilot.Anchored = true
plane.Pilot.Changed:Connect(function(name)
if name == "Occupant" then
if plane.Pilot.Occupant then wait(3) plane.Pilot.Anchored = false end
end
end)
end
if not teams[team.Name] then teams[team.Name] = 0 end
local function spawnAuto()
local property = game.Workspace.Property[team.Name]
local newAuto = autoModel:Clone()
newAuto.Parent = property
newAuto.PrimaryPart.CFrame = autoSpawn.CFrame + Vector3.new(0,2,0)
newAuto["Body Colors"].TorsoColor = team.TeamColor
local planeModel = planeModel:Clone()
planeModel.Parent = property
planeModel:SetPrimaryPartCFrame(planeSpawn.CFrame)
--lockPlane(planeModel)
purchaseModule.colorVehicle(planeModel,team)
purchaseModule.collisionCheck(planeModel,0.5,10)
newAuto.Humanoid.Died:Connect(function()
wait(3)
planeModel:Destroy()
newAuto:Destroy()
teams[team.Name]-=1
end)
teams[team.Name] += 1
end
while parent.Parent do
if not (teams[team.Name] < _G.Storage.Variables.AutoNumber.Value) then wait(30) continue end
teams[team.Name] = 0
for _,object in pairs(game.Workspace.Property[team.Name]:GetChildren()) do
if object.Name == "Auto" and object.PrimaryPart and object.PrimaryPart.Velocity.Magnitude > 30 then -- and object.PrimaryPart.Velocity.Magnitude > 50 then
teams[team.Name]+=1
end
end
_G.AutoTeams = teams
--print("Auto: ",team.Name,teams[team.Name])
spawnAuto()
wait(30)
end
end
return getfenv()
+123
View File
@@ -0,0 +1,123 @@
require(game.ReplicatedFirst.ReadyModule)("GenerationForeman")
local rules = require(_G.Modules.RuleModule)
local CHUNK_SIZE = 512 -- wae
local RADIUS = 3
--if _G.IsStudio then RADIUS = 1 end -- stop my computer from dying
local LEEWAY = 20 -- WHY IS THIS SO BIG WTF
local COMBAT_RADIUS = 6
local POOL_SIZE = 4 --
local CHUNK_OFFSET_X = -1150
local CHUNK_OFFSET_Z = 120
local pool = 0
local chunks = {}
local schunks = {}
local _c = {}
_c.__index = _c
_c.delete = function(this)
schunks[this.index.x][this.index.z] = nil
--if #schunks[index.x] == 0 then schunks[index.x] = nil end
if this.generator then this.generator:SendMessage("delete") end
chunks[this.index] = nil
end
local function chunk(x,z)
if not schunks[x] then schunks[x] = {} end
local i = {x=x,z=z}
local first,second
local c
c = {viable = true, permanent = nil, generator = nil, started = false, index = i}
setmetatable(c,_c)
chunks[i]=c
schunks[x][z]=c
spawn(function()
repeat wait() until pool < POOL_SIZE
if not c.viable then return end
pool = pool + 1
c.generator = _G.Modules.Generator:Clone()
c.generator.Parent = game.Workspace
c.generator:SendMessage("generate",x * CHUNK_SIZE,z * CHUNK_SIZE,CHUNK_OFFSET_X,CHUNK_OFFSET_Z)
c.generator.Changed:Wait()
pool = pool - 1
end)
return c
end
local function generateCombatZone()
_G.Remotes.Notification:FireAllClients("Generation","Generating combat zone, please wait.")
--[[rules.setRule("GenerationProcessing",true)
for x = -COMBAT_RADIUS,COMBAT_RADIUS do
for z = -COMBAT_RADIUS*2,COMBAT_RADIUS*2 do
chunk(x,z).permanent = true
end
end
wait()
repeat wait() until pool == 0
rules.setRule("GenerationProcessing",false)]]
_G.Remotes.Notification:FireAllClients("Generation","Generation complete.")
end
local function generateForPlayer()
while wait(0.5) and rules.rules.GenerationFollowPlayer do
for index,chunk in pairs(chunks) do
chunk.viable = false
end
local perPlayer = function(p)
for index,chunk in pairs(chunks) do
if Vector2.new(p.x-index.x*CHUNK_SIZE,p.z-index.z*CHUNK_SIZE).Magnitude < CHUNK_SIZE*(RADIUS+LEEWAY) then
chunk.viable = true
end
end
for x=math.ceil(p.x/CHUNK_SIZE)-RADIUS,math.ceil(p.x/CHUNK_SIZE)+RADIUS do
for z=math.ceil(p.z/CHUNK_SIZE)-RADIUS,math.ceil(p.z/CHUNK_SIZE)+RADIUS do
if not schunks[x] then schunks[x] = {} end
if not schunks[x][z] then
chunk(x,z)
end
end
end
end
for _,player in pairs(game.Players:GetPlayers()) do
if player.Character then
if player.Character.PrimaryPart then
perPlayer(player.Character.PrimaryPart.Position)
end
end
end
perPlayer(game.Workspace.CurrentCamera.CFrame.Position)
for index,chunk in pairs(chunks) do
if not chunk.viable and not chunk.permanent then
chunk:delete()
end
end
end
end
local function reloadGeneration()
for index,chunk in pairs(chunks) do
chunk:delete()
end
end
rules.listenRule("GenerationNoiseOffset",function(x,z)
CHUNK_OFFSET_X = x
CHUNK_OFFSET_Z = z
reloadGeneration()
end)
rules.listenRule("GenerationFollowPlayer",function(yes)
if yes then generateForPlayer() else reloadGeneration() end
end)
local r = Random.new(os.time())
rules.listenRule("GenerationCombatZone",function()
CHUNK_OFFSET_X = r:NextInteger(-10000,10000)
CHUNK_OFFSET_Z = r:NextInteger(-10000,10000)
reloadGeneration()
generateCombatZone()
end)
+2
View File
@@ -0,0 +1,2 @@
require(game.ReplicatedFirst.ReadyModule)("GenerationInsurance")
if not _G.IsStudio then script.Parent.GenerationForeman.Enabled = true end
+793
View File
@@ -0,0 +1,793 @@
require(game.ReplicatedFirst.ReadyModule)("ServerScript")
local objectModule = require(_G.Modules.ObjectModule)
--local objectInteraction = require(_G.Modules.ObjectInteraction.Main)
local rules = require(_G.Modules.RuleModule)
local commands = require(_G.Modules.CommandsModule)
local partStateModule = require(_G.Modules.PartStateModule)
DEFAULT_MAX_SAVES = 20
SAVE_DATA_LIMIT = 5*10^6
PLAYER_INTERACTION_DISTANCE = 100
PLAYER_MAX_FLOOD = 10
PLAYER_FLOOD_TICK = 4
VEHICLE_SAVE_STORE = "VehicleSaveStore"
VEHICLE_SAVE_INFO_STORE = "VehicleSaveInfo"
USER_MOD_STORE = "ModStore"
MAIN_GAME_PLACEID = 11370438752
PLACE_COOLDOWN = 0.75
--[[if game.PlaceId ~= MAIN_GAME_PLACEID then
VEHICLE_SAVE_STORE = "VehicleSaveStoreTest"
VEHICLE_SAVE_INFO_STORE = "VehicleSaveInfoTest"
USER_MOD_STORE = "ModStoreTest"
end]]
for index,value in pairs(_G.Rules[_G.RuleMode]) do
rules.setRule(index,value)
end
local function GetStoreData(store,key,ver)
local success,value = pcall(function() -- Protection call
local data
if ver then -- When a version is provided get it based on that
data = store:GetVersionAsync(key,ver)
else
data = store:GetAsync(key)
end
return data
end)
if ver then print(store,key,ver) end
if not success then warn(value) end
return success,value
end
local function SetStoreData(store,key,val)
local success = pcall(function()
store:SetAsync(key,val)
end)
return success
end
PartExperience = {}
PartCost = {}
local saves = {}
local players = {}
local admins = {
[558665455] = true
}
local _player = {} -- Metatable for player class
_player.__index = _player
_player.Remove = function(this) -- Clear data
players[this.userid] = nil
players[this.instance] = nil
end
_player.IsAdmin = function(this) -- Has commands permissions
if admins[this.instance.UserId] then return true end
if this.admin then return true end
end
_player.DrainFloodGate = function(this,amount)
this.flood = this.flood - amount
if this.flood < 0 then this.flood = 0 end
end
_player.CheckLastPlaced = function(this)
local possible = ((tick() - this.last_placed) > PLACE_COOLDOWN)
if possible then this.last_placed = tick() end
return possible
end
_player.CheckFloodGate = function(this,amount)
this.flood = this.flood + amount
if this.flood > PLAYER_MAX_FLOOD then return false else return true end
end
_player.OwnsPart = function(this,part)
return _G.Methods.playerOwnsPart(this.instance,part)
end
_player.OwnsSave = function(this,group) -- Owns a save DataStore if...
if this:IsAdmin() or group:match("public") or group == this.userid then
return true
else
this:Notify("Permission Error","You do not own this save: "..group)
warn("Permission error: "..group.." "..this.userid)
return false
end
end
_player.InRange = function(this,cframe) -- Is the player close enough to interact
this = this.instance
if
not this or
not cframe or
not this.Character or
not this.Character.PrimaryPart
then
print("Bad parameters",this,cframe,this.Character)
end
return (cframe-this.Character.PrimaryPart.Position).Position.Magnitude < PLAYER_INTERACTION_DISTANCE
end
_player.CanAfford = function(this,part)
end
_player.CanUsePart = function(this,part)
local experience = PartExperience[part]
if experience and experience > this.stats.experience then return false end
local cost = PartCost[part]
if cost and cost > this.stats.money then return false end
return not not part:IsDescendantOf(_G.Storage.Parts)
end
_player.Notify = function(this,title,message)
if this.dummy then return end
_G.Remotes.Notification:FireClient(this.instance,title,message)
end
_player.GetParts = function(this)
return _G.Tags:GetTagged("P_"..this.userid)
end
_player.WaitForStatistics = function(this)
repeat
wait()
until this.stats
end
_player.EvaluateSaves = function(this)
this:WaitForStatistics()
if this.evaluate_save_lock then repeat wait() until not this.evaluate_save_lock end
this.evaluate_save_lock = true
this.max_saves = DEFAULT_MAX_SAVES + (this.stats.additional_saves or 0)
if game:GetService("MarketplaceService"):UserOwnsGamePassAsync(tonumber(this.userid),1014956678) then
this.max_saves = this.max_saves + 20
end
this.evaluate_save_lock = false
end
_player.LoadSave = function(this,group,key)
if not this:CheckFloodGate(1) then return end
--print(string.format("pg:%s,pk:%s",group,key))
local ver
local _group,_key = group:match("(.-):(.+)")
if _group and _key then ver = key key = _key group = _group end
if not players[group] then return end
if not players[group].saves then error(group,key) end
if not this:OwnsSave(group) then return end
--print(string.format("k:%s,g:%s,v:%s",key,group,ver or "nil"))
if players[group].saves[key..(ver or "")] then
return players[group].saves[key]
else
local success,data = GetStoreData(players[group].stores.saves,key,ver)
if success then
if not ver then players[group].saves[key] = data end
return data
end
end
end
players = {
public = setmetatable({
parttag = "P_ublic",
userid = "public",
flood = -math.huge,
saves = {},
stores = {
saves = _G.Data:GetDataStore(VEHICLE_SAVE_STORE,"public"),
save_info = _G.Data:GetDataStore(VEHICLE_SAVE_INFO_STORE,"public")
}
},_player)
}
local function GetPlayer(id) -- Get a player by their id AS A STRING
local player = players[id] or players[tostring(id)]
if not player then error("No player data identified by "..tostring(id),2) end
return player
end
local function AddPlayer(instance)
local data = { -- The player data...
instance = instance, -- Player instance in game.Players
userid = tostring(instance.UserId),
dummy = not instance.Parent,
name = instance.DisplayName,
saves = {}, -- Vehicle{} []
flood = 0, -- If this gets too high, block remotes
stats = nil,
join = tick(),
last_placed = tick(),
max_saves = DEFAULT_MAX_SAVES,
parttag = "P_"..tostring(instance.UserId),
stores = {} -- DataStore
}
setmetatable(data,_player) -- ...made into a class
players[instance] = data -- Register them by id and instance
players[data.userid] = data
data.stores.saves = _G.Data:GetDataStore(VEHICLE_SAVE_STORE,data.userid) -- Vehicles
data.stores.mods = _G.Data:GetDataStore(USER_MOD_STORE,data.userid) -- Properties
data.stores.save_info = _G.Data:GetDataStore(VEHICLE_SAVE_INFO_STORE,data.userid) -- Vehicle Save Info
_,data.stats = GetStoreData(data.stores.mods,"stats")
if data.stats then
data.stats = _G.Http:JSONDecode(data.stats)
else
data.stats = {}
end
_G.Default(data.stats,{
experience = 0,
money = 100,
extra_saves = 0,
playtime = 0,
color = require(_G.Modules.NameColorModule).ComputeNameColor(instance.Name)
})
wait(2)
local playtime = data.stats.playtime
if playtime ~= 0 then
local ending = "seconds"
if playtime > 60 then ending = "minutes" playtime = playtime / 60
if playtime > 60 then ending = "hours" playtime = playtime / 60
if playtime > 24 then ending = "days" playtime = playtime / 24
end
end
end
data:Notify("Welcome",string.format("Welcome back to Plane Building! You've been playing for %d %s!",math.floor(playtime),ending))
if game.PlaceId ~= MAIN_GAME_PLACEID then
data:Notify("Warning",string.format("You are not in the main game place! Irreversible save corruption and gameplay bugs are likely!"))
end
else
data:Notify("Welcome","Hey newbie, have a warm welcome to Plane Building! Thanks so much for playing!")
end
end
game.Players.PlayerAdded:Connect(AddPlayer)
local function RemovePlayer(instance) -- For the event
local player = GetPlayer(instance)
player.stats.playtime = player.stats.playtime + (tick() - player.join)
SetStoreData(player.stores.mods,"stats",_G.Http:JSONEncode(player.stats))
player:Remove()
end
game.Players.PlayerRemoving:Connect(RemovePlayer)
local function Weld(part1,part2,temporary) -- Make a BUILDING weld
local weld = Instance.new("WeldConstraint")
weld.Name = "BuiltWeldConstraint"
weld.Parent = part1
weld.Part0 = part1
weld.Part1 = part2
if temporary then weld.Name = "WeldConstraint" end -- Or not.
return weld
end
local function SetupPart(player,part)
part = part:Clone()
part.Parent = game.Workspace.Objects
_G.Tags:AddTag(part,"P_"..player.userid)
part:SetAttribute("NetworkOwner",player.userid)
return part
end
local function CopyTags(part1,part2)
for _,tag in pairs(_G.Tags:GetTags(part2)) do
if not part1:HasTag(tag) and string.sub(tag,1,2) == "P_" then
part1:AddTag(tag)
end
end
end
local function AttemptWeld(player,part,connection)
local new_weld
if connection and
(player:OwnsPart(connection) or player:OwnsPart(connection.Parent))
then
local attach = part
if part:IsA("Model") then attach = attach.PrimaryPart end
new_weld = Weld(attach,connection)
new_weld.Parent = part
end
CopyTags(part,connection)
return new_weld
end
local function ResizePart(part,size)
if part:IsA("Model") then
part:ScaleTo(size.Magnitude)
else
part.Size = size
end
part:SetAttribute("Size",size)
end
local function _CreatePart(player,part,cframe,connection,scale)
local player = GetPlayer(player)
player:CheckFloodGate(4)
if
not player:CheckLastPlaced() or
not player:CanUsePart(part)
then
return
end
if connection then cframe = connection.CFrame:ToWorldSpace(cframe) end
if not player:InRange(cframe) then return end
part = part:Clone()
part.Parent = game.Workspace.Objects
if scale then ResizePart(part,scale) end
_G.Methods.setItemCFrame(part,cframe)
AttemptWeld(player,part,connection)
--[[if part:IsA("Model") then
_G.Methods.setNetworkOwner(part.PrimaryPart,player.instance)
else
_G.Methods.setNetworkOwner(part,player.instance)
end]]
part:AddTag(player.parttag)
wait()
return part
end
local function ConfigurePart(player,part,own)
part:AddTag(player.parttag)
part.Parent = game.Workspace.Objects
local owner
if own then owner = player.instance end
objectModule.add(part,owner)
part:SetAttribute("Owner",player.instance.UserId)
--local modules = objectInteraction.modulesByName[part.Name]
--if modules then for _,module in pairs(modules) do if module.setup then module.setup(part) end end end
end
local function CreatePart(player,id,...)
local player = GetPlayer(player)
player:CheckFloodGate(4)
local template = partStateModule.get_part_by_id(id)
if not template then error(string.format("No part for id: "..tostring(id))) return end
if
not player:CheckLastPlaced() or
not player:CanUsePart(template)
then
return
end
local state = partStateModule.new()
state.owner = player.instance
state:deserialise(id,...)
local part = state:create()
ConfigurePart(player,part,true)
wait()
return part
end
_G.Remotes.Create.OnServerInvoke = CreatePart
local function _CreatePoly(player,part,nodes,connections)
local player = GetPlayer(player)
if
player:CheckFloodGate(6) and
player:CheckLastPlaced() and
player:CanUsePart(part)
then
for index,node in pairs(nodes) do
if node.connection then node.cframe = node.connection.CFrame:ToWorldSpace(node.cframe) end
end
for index,node in pairs(nodes) do
if (nodes[1].cframe.Position - node.cframe.Position).Magnitude > 80 then return end
if not player:InRange(node.cframe) then return end
end
part = part:Clone()
part.Parent = game.Workspace.Objects
part:AddTag(player.parttag)
if #nodes == 2 then
local a = nodes[1].cframe
local b = nodes[2].cframe
local d = (a-b).Magnitude
part.CFrame = CFrame.lookAt(a.Position,b.Position,a.UpVector) * CFrame.new(d * 0.5,0,0)
elseif #nodes == 3 then
_G.Methods.form_triangle(part.A,part.B,nodes[1].cframe.Position,nodes[2].cframe.Position,nodes[3].cframe.Position)
end
Weld(part.A,part.B)
for _,connection in pairs(connections) do
AttemptWeld(player,part.PrimaryPart,connection)
end
return part
end
end
--_G.Remotes.Poly.OnServerInvoke = CreatePoly
local function TweakEffect(player,effect,rate,enabled)
effect.Enabled = enabled
effect.Rate = rate
end
_G.Remotes.Effects.OnServerEvent:Connect(TweakEffect)
local function ExplodePart(player,part)
local player = GetPlayer(player)
if
not player:CheckFloodGate(1) or
not (player:OwnsPart(part) or
player:OwnsPart(part.Parent))
then
return
end
_G.Methods.explode(part)
end
_G.Remotes.Explode.OnServerEvent:Connect(ExplodePart)
local function DeletePart(player,part,destruct)
local player = GetPlayer(player)
if
part and
player:CheckFloodGate(1) and
player:OwnsPart(part)
then
if destruct then
for _,part in pairs(part:GetChildren()) do
if part:IsA("BasePart") then
for _,joint in pairs(part:GetJoints()) do
if joint.Name == "BuiltWeldConstraint" then joint:Destroy() end
end
end
end
else
part:Destroy()
end
end
end
_G.Remotes.Delete.OnServerInvoke = DeletePart
local function ClearParts(player)
local player = GetPlayer(player)
if not player:CheckFloodGate(1) then return end
for _,part in pairs(player:GetParts()) do
part:Destroy()
end
end
_G.Remotes.Clear.OnServerInvoke = ClearParts
local function ShareParts(player,id,parts)
local player = GetPlayer(player)
if not player:CheckFloodGate(1) then return end
if not parts then parts = player:GetParts() end
for _,part in pairs(parts) do
_G.Storage.TeamBox:Clone().Parent = part
part.TeamBox.Adornee = part
_G.Debris:AddItem(part.TeamBox,0.5)
if not id then
part:AddTag(players.public.parttag)
else
part:AddTag(GetPlayer(id).parttag)
end
end
end
_G.Remotes.Collaborate.OnServerInvoke = ShareParts
local function EnableCombat(player,parts)
local player = GetPlayer(player)
if not player:CheckFloodGate(1) then return end
if not parts then parts = player:GetParts() end
for _,part in pairs(parts) do
_G.Storage.DangerBox:Clone().Parent = part
part.DangerBox.Adornee = part
_G.Debris:AddItem(part.DangerBox,0.5)
part:AddTag("Combat")
end
end
_G.Remotes.Combat.OnServerInvoke = EnableCombat
local function SaveVehicle(player,data,key,group)
player = GetPlayer(player)
player:EvaluateSaves()
if ((key ~= "autosave") and (player.max_saves < tonumber(key))) then
player:Notify("Save Error","You do not have enough space.")
return
end
if not player:OwnsSave(group) then return end
local success,value = SetStoreData(players[group].stores.saves,key,data)
if not success then player:Notify("Vehicle Save Error",value) error(value) return end
local length = #data
local suffix = ""
if length > 5000 then suffix = "K" length = math.floor(length/1000) end
player:Notify("Vehicle Saved","Save success, remember to save regularly! Size: "..length..suffix.."C")
players[group].saves[key] = data
return success
end
_G.Remotes.Save.OnServerInvoke = SaveVehicle
local function GetSaveVersionInfo(group,key)
local store = players[group].stores.saves
local listSuccess, pages = pcall(function()
return store:ListVersionsAsync(key)
end)
local result = {}
if listSuccess then
local items
while true do
items = pages:GetCurrentPage()
for key, info in pairs(items) do
if not info.IsDeleted then
result[info.Version] = os.date("%c",info.CreatedTime/1000)
end
end
if pages.IsFinished then break else pages:AdvanceToNextPageAsync() end
end
else
warn(pages)
end
return result
end
SAVE_INFO_EMPTY = "Empty"
EMPTY_SAVE_INFO = {autosave = SAVE_INFO_EMPTY}
for i=1,DEFAULT_MAX_SAVES do EMPTY_SAVE_INFO[tostring(i)] = SAVE_INFO_EMPTY end
local function GetSaveInfo(player,group)
player = GetPlayer(player)
group = group or player.userid
local key
if group:match("(.-):(.+)") then group,key = group:match("(.-):(.+)") end
if not player:OwnsSave(group) then return end
local max_saves = DEFAULT_MAX_SAVES
if group == player.userid then player:EvaluateSaves() max_saves = player.max_saves end
if key then
return GetSaveVersionInfo(group,key)
else
local success,data = GetStoreData(players[group].stores.save_info,"info")
if not success then
player:Notify("Save Info Error: ","Your save info failed to load, this is a fatal error, try rejoining.")
return
end
local save_info = data or {}
if not save_info.autosave then save_info.autosave = "Unused" end
for index,item in ipairs(save_info) do
local data = save_info[index]
save_info[index] = nil
save_info[tostring(index)] = data
end
for i = 1,max_saves do if not save_info[tostring(i)] then save_info[tostring(i)] = "Empty" end end -- fill any missing slots
return save_info
end
end
_G.Remotes.GetSaveInfo.OnServerInvoke = GetSaveInfo
local function SetSaveInfo(player,data,group)
player = GetPlayer(player)
if not player:OwnsSave(group) then return end
player:EvaluateSaves()
for index,item in pairs(data) do
if not tonumber(index) and index ~= "autosave" then
player:Notify("Malformed save data! Invalid string: "..index)
return
end
end
if #data > player.max_saves then
player:Notify("You do not have enough save slots! "..tostring(#data-1))
return
end
SetStoreData(players[group].stores.save_info,"info",data)
return data
end
_G.Remotes.SetSaveInfo.OnServerInvoke = SetSaveInfo
local function LoadPlayerSave(player,...)
return GetPlayer(player):LoadSave(...)
end
_G.Remotes.Load.OnServerInvoke = LoadPlayerSave
local function ConfigurePlayerVehicle(player,model)
for _,part in pairs(model:GetChildren()) do
ConfigurePart(player,part)
end
end
local function PlaceVehicle(player,cframe,key,group)
local player = GetPlayer(player)
if not player:CheckFloodGate(3) then return end
for _,part in pairs(_G.Tags:GetTagged("P_"..player.userid)) do
part:Destroy()
end
local raw = player:LoadSave(group,key)
if not raw then return end
local model = _G.Methods.saves.dataToModel(raw,true)
if not model then return end
model.Parent = game.Workspace
local primary = model:FindFirstChildWhichIsA("VehicleSeat",true)
if primary then
model.PrimaryPart = primary
end
model:PivotTo(cframe)
--[[task.defer(function()
if primary then _G.Methods.setNetworkOwner(primary,player.instance) end
end)]]
ConfigurePlayerVehicle(player,model)
end
_G.Remotes.Place.OnServerInvoke = PlaceVehicle
-- i hate this...
local function PlaceSubassembly(player,cframe,data,connection)
local player = GetPlayer(player)
if not player:CheckFloodGate(10) then return end
local model = _G.Methods.saves.dataToModel(data,true)
model:PivotTo(cframe)
if player:OwnsPart(connection) then Weld(model.PrimaryPart,connection) end
ConfigurePlayerVehicle(player,model)
end
_G.Remotes.PlaceSubassembly.OnServerInvoke = PlaceSubassembly
local function PlaySoundEffect(player,sound)
if not GetPlayer(player):CheckFloodGate(1) then return end
sound:Play()
end
_G.Remotes.PlaySoundEffect.OnServerEvent:Connect(PlaySoundEffect)
local function ChangeSoundEffect(player,sound,volume,pitch)
if not GetPlayer(player):CheckFloodGate(1) then return end
if sound then
if volume then sound.Volume = volume end
if pitch then sound.Pitch = pitch end
end
end
_G.Remotes.ChangeSoundEffect.OnServerEvent:Connect(ChangeSoundEffect)
local function Paint(player,part,colour) -- Colour is spelt with a 'u' (pun intended)
player = GetPlayer(player)
if not player:CheckFloodGate(1) then return end
if not player:OwnsPart(part) then return end
_G.Methods.colorPart(part,colour)
end
_G.Remotes.Paint.OnServerEvent:Connect(Paint)
local function Admin(player)
player = GetPlayer(player)
if not player:CheckFloodGate(1) then return end
return player:IsAdmin()
end
_G.Remotes.Admin.OnServerInvoke = Admin
local function SnapPart(player,weld)
local player = GetPlayer(player)
if not player:CheckFloodGate(1) then return end
if weld.Parent and (player:OwnsPart(weld.Parent) or player:OwnsPart(weld.Parent.Parent)) and weld.Name == "BuiltWeldConstraint" then
weld:Destroy()
if weld.Part0 and weld.Part0.Parent:FindFirstChild("BombScript") then weld.Part0.Parent.BombScript.Enabled = true end
if weld.Part1 and weld.Part1.Parent:FindFirstChild("BombScript") then weld.Part1.Parent.BombScript.Enabled = true end
else
print("failed",weld:GetFullName())
end
end
_G.Remotes.Snap.OnServerEvent:Connect(SnapPart)
local function EditPart(player,part,edit,value)
if not GetPlayer(player):CheckFloodGate(1) then return end
if GetPlayer(player):OwnsPart(part) then
if edit == "Size" then
ResizePart(part,value)
end
if _G.IsNumber(value) then
local min = edit:GetAttribute("Lower") or -math.huge
local max = edit:GetAttribute("Upper") or math.huge
edit.Value = math.clamp(value,min,max)
else
edit.Value = value
end
objectModule.update(part)
--[[local modules = objectInteraction.modulesByName[part.Name] or {}
for _,module in pairs(modules) do
if module.setup then module.setup(part) end
end]]
end
end
_G.Remotes.Edit.OnServerInvoke = EditPart
--_G.Remotes.Sell
commands.new("get user id (.+)","get user id <name>: Get's a player's userid by name.",function(player,name)
local player = GetPlayer(player)
if name then
player:Notify("Get User Id",game.Players:GetUserIdFromNameAsync(name))
end
end)
commands.new("open player (.+)","open player <userid>: Load a player's data on the server.",function(player,userid)
local player = GetPlayer(player)
if not player:IsAdmin() then player:Kick("Security") return end
if userid then
local name = game.Players:GetNameFromUserIdAsync(tonumber(userid))
AddPlayer({UserId = tonumber(userid),DisplayName = name,Name = name})
player:Notify("Loading Virtual Player",name)
end
end)
commands.new("set save ([^%s]+) (%d+) ([^%s+]) data:(.*)","set store <store> <userid> <key> <value>: Set the save slot data.",function(player,store,userid,key,value)
local player = GetPlayer(player)
if not player:IsAdmin() then player:Kick("Security") return end
print("Modifying store: ",store,userid,key,value)
SetStoreData(players[userid].stores.saves,key,value)
player:Notify("Set Store Value","Success?")
end)
commands.new("read player stats%((.-)%)","",function(player,userid)
local player = GetPlayer(player)
if userid then
local other = GetPlayer(tostring(userid))
player:Notify(other.instance.DisplayName.." Statistics",_G.Http:JSONEncode(other.stats))
end
end)
commands.new("restart server","restart server: Update to latest version.",function(player,userid)
local player = GetPlayer(player)
if not player:IsAdmin() then player:Kick("Security") return end
_G.Remotes.Notification:FireAllClients("Server Restarting","Hold tight!")
game:GetService('TeleportService'):TeleportPartyAsync(137149259787276,game.Players:GetPlayers(),{moveTo = game.PlaceId})
end)
commands.new("rejoin","rejoin: Makes you rejoin.",function(player,userid)
local player = GetPlayer(player)
_G.Remotes.Notification:FireClient(player.instance,"Rejoining","Hold tight!")
game:GetService('TeleportService'):TeleportAsync(game.PlaceId,{player.instance})
end)
--[[local store,userid,key,value = message:match("setstore%((.-),(%d-),(.-),(.-)%)")
if store then
if player then
print("Modifying store: ",store,userid,key,value)
player.stores.saves:SetAsync(key,value)
end
end]]
local function SetMotor(character,motor,C0,C1) -- Allow clients to adjust their character motors
if not character:FindFirstChildWhichIsA("Humanoid") then
character = character.Character
end
if
not character or
not motor or
not motor:IsDescendantOf(character)
then
return
end
motor.C0 = C0 motor.C1 = C1
end
_G.Remotes.MotorMoveClient.OnServerEvent:Connect(SetMotor)
local textService = game:GetService("TextService")
local function Chat(instance,message)
local player = GetPlayer(instance)
if not player:CheckFloodGate(5) then return end
message = textService:FilterStringAsync(message,instance.UserId,Enum.TextFilterContext.PublicChat):GetNonChatStringForBroadcastAsync()
_G.Remotes.Chat:FireAllClients(instance.DisplayName.." | "..instance.Name,message,player.stats.color)
game.Chat:Chat(instance.Character,message)
end
_G.Remotes.Chat.OnServerEvent:Connect(Chat)
local function ApplyState(player,part,...)
local player = GetPlayer(player)
if not player:CheckFloodGate(2) then return end
if not player:OwnsPart(part) then return end
local state = partStateModule.new()
state.owner = player.instance
state.part = part
state:deserialise(...)
state:apply()
end
_G.Remotes.Apply.OnServerEvent:Connect(ApplyState)
spawn(function() -- Drain all flood gates every heartbeat
while wait() do
for id,player in pairs(players) do
if _G.IsString(id) then player:DrainFloodGate(PLAYER_FLOOD_TICK) end
end
end
end)
spawn(function() -- Make the game rain for players every now and then
while true do
_G.Remotes.Rain:FireAllClients(false)
wait(math.random(1,720))
_G.Remotes.Rain:FireAllClients(true)
wait(math.random(1,60))
end
end)
+90
View File
@@ -0,0 +1,90 @@
local CHUNK_SIZE = 256
local RADIUS = 3
local LEEWAY = 20
local POOL_SIZE = 64
local BASE_RADIUS = 1
script:WaitForChild("GenerateChunk").Disabled = true
local pool = 0
local chunks = {}
local schunks = {}
local function chunk(x,z)
if not schunks[x] then schunks[x] = {} end
local i = {x=x,z=z}
local first,second
local c = {delete=function()
if first then
game.Workspace.Terrain:FillRegion(Region3.new(first.Value,second.Value),4,Enum.Material.Air)
end
end,viable = true}
chunks[i]=c
schunks[x][z]=c
task.defer(function()
repeat wait() until pool < POOL_SIZE
if not c.viable and not c.permanent then return end
local actor = Instance.new("Actor")
actor.Parent = game.Workspace
local new_script = script.GenerateChunk:Clone()
local location = new_script.Location
location.Value = Vector3.new(x,CHUNK_SIZE,z)
first = new_script.First
second = new_script.Second
new_script.Parent = actor
new_script.Disabled = false
pool = pool + 1
new_script.Destroying:Connect(function()
pool = pool - 1
end)
end)
return c
end
for x = -BASE_RADIUS,BASE_RADIUS do
for z = -BASE_RADIUS,BASE_RADIUS do
if Vector2.new(x,z).Magnitude < BASE_RADIUS then
chunk(x,z).permanent = true
end
end
end
while wait(0.5) do
for index,chunk in pairs(chunks) do
chunk.viable = false
end
local perPlayer = function(p)
for index,chunk in pairs(chunks) do
if Vector2.new(p.x-index.x*CHUNK_SIZE,p.z-index.z*CHUNK_SIZE).Magnitude < CHUNK_SIZE*(RADIUS+LEEWAY) then
chunk.viable = true
end
end
for x=math.ceil(p.x/CHUNK_SIZE)-RADIUS,math.ceil(p.x/CHUNK_SIZE)+RADIUS do
for z=math.ceil(p.z/CHUNK_SIZE)-RADIUS,math.ceil(p.z/CHUNK_SIZE)+RADIUS do
if not schunks[x] then schunks[x] = {} end
if not schunks[x][z] then
chunk(x,z)
end
end
end
end
for _,player in pairs(game.Players:GetPlayers()) do
if player.Character then
if player.Character.PrimaryPart then
perPlayer(player.Character.PrimaryPart.Position)
end
end
end
perPlayer(game.Workspace.CurrentCamera.CFrame.Position)
for index,chunk in pairs(chunks) do
if not chunk.viable and not chunk.permanent then
schunks[index.x][index.z] = nil
--if #schunks[index.x] == 0 then schunks[index.x] = nil end
chunk.delete()
chunks[index] = nil
end
end
end