Copy salient and essential scripts and models from Plane Building Roblox
This commit is contained in:
@@ -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()
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
@@ -0,0 +1,2 @@
|
||||
require(game.ReplicatedFirst.ReadyModule)("GenerationInsurance")
|
||||
if not _G.IsStudio then script.Parent.GenerationForeman.Enabled = true end
|
||||
@@ -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)
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user