Ad
Log in to vote
0

how to make placement system saving??? it dont save if i leave, it only works with click button:/

Asked by 5 days ago
Edited 1 day ago

saving here in local script:

local canvas = game.Workspace.Bases.Base1.Building
local furniture = game.ReplicatedStorage.PlacementObjects
local Placement = require(game:GetService("ReplicatedStorage"):WaitForChild("Placement"))

local placement = Placement.new(canvas)

local mouse = game.Players.LocalPlayer:GetMouse()
mouse.TargetFilter = placement.CanvasObjects

local tableModel = furniture.Table:Clone()
tableModel.Parent = mouse.TargetFilter

local rotation = 0

local function onRotate(actionName, userInputState, input)
    if (userInputState == Enum.UserInputState.Begin) then
        rotation = rotation + math.pi/2
    end
end

game:GetService("ContextActionService"):BindAction("rotate", onRotate, false, Enum.KeyCode.R)

game:GetService("RunService").RenderStepped:Connect(function(dt)
    local cf = placement:CalcPlacementCFrame(tableModel, mouse.Hit.p, rotation)
    local xd = placement:isColliding(tableModel)

    tableModel:SetPrimaryPartCFrame(cf)
end)

placement.GridUnit = 1

local function onPlace(actionName, userInputState, input)
    if (userInputState == Enum.UserInputState.Begin) then
        local cf = placement:CalcPlacementCFrame(tableModel, mouse.Hit.p, rotation)

        placement:Place(furniture[tableModel.Name], cf, placement:isColliding(tableModel))
    end
end

local function change(actionName, userInputState, input)
    local VALUE = canvas.BuildV
    if (userInputState == Enum.UserInputState.Begin) then
        if actionName == "up" then
            if VALUE.Value <= 49 then
                game.ReplicatedStorage.PlacementRemotes.Up:FireServer(game.Players.LocalPlayer)
            end
        elseif actionName == "down" then
            if VALUE.Value >= 1 then
                game.ReplicatedStorage.PlacementRemotes.Down:FireServer(game.Players.LocalPlayer)
            end
        end
    end
end

function Placement.fromSerialization(canvasPart, data)
    local self = Placement.new(canvasPart)
    local canvasCF = canvasPart.CFrame

    data = data or {}

    for cf, name in pairs(data) do
        local model = furniture:FindFirstChild(name)
        if (model) then
            local components = {}
            for num in string.gmatch(cf, "[^%s,]+") do
                components[#components+1] = tonumber(num)
            end

            self:Place(model, canvasCF * CFrame.new(unpack(components)), false)
        end
    end

    return self
end

local remotes = game:GetService("ReplicatedStorage"):WaitForChild("PlacementRemotes")

game:GetService("ContextActionService"):BindAction("place", onPlace, false, Enum.KeyCode.E)

game:GetService("ContextActionService"):BindAction("up", change, false, Enum.KeyCode.U)
game:GetService("ContextActionService"):BindAction("down", change, false, Enum.KeyCode.J)

game.Players.LocalPlayer.PlayerGui.Bases.LoadData.MouseButton1Click:Connect(function()
    local myData = remotes.DSPlacement:InvokeServer()
    placement = Placement.fromSerialization(canvas, myData)
end)

game.Players.LocalPlayer.PlayerGui.Bases.SaveData.MouseButton1Click:Connect(function()
    remotes.DSPlacement:InvokeServer(game.Players.LocalPlayer,1,canvas)
end) -- works only with this button but i want it when i leave too

while wait(10) do
    remotes.DSPlacement:InvokeServer(game.Players.LocalPlayer,1,canvas)
end -- i tryed make this but dont work and game.Players.PlayerRemoving dont work too

this is server script

local placementClass = require(game:GetService("ReplicatedStorage"):WaitForChild("Placement"))
local placementObjects = {}

local remotes = game:GetService("ReplicatedStorage"):WaitForChild("PlacementRemotes")

function remotes.InitPlacement.OnServerInvoke(player, canvasPart)
    placementObjects[player] = placementClass.new(canvasPart)
    return placementObjects[player].CanvasObjects
end

remotes.InvokePlacement.OnServerEvent:Connect(function(player, func, ...)
    if (placementObjects[player]) then
        placementClass[func](placementObjects[player], ...)
    end
end)

local datastore = game:GetService("DataStoreService"):GetDataStore("PlacementSystem")

function remotes.DSPlacement.OnServerInvoke(player, saving, useData)
    local key = "player_"..player.UserId

    local success, result = pcall(function()
        if (saving and placementObjects[player]) then
            if (useData) then
                datastore:SetAsync(key, placementObjects[player]:Serialize())
            else
                datastore:SetAsync(key, {})
            end
        elseif (not saving) then
            return datastore:GetAsync(key)
        end
    end)

    if (success) then
        return saving or result
    else
        warn(result)
    end
end

this is module script

local isServer = game:GetService("RunService"):IsServer()
local remotes = game:GetService("ReplicatedStorage"):WaitForChild("PlacementRemotes")
local initPlacement = remotes.InitPlacement
local invokePlacement = remotes.InvokePlacement

local Placement = {}
Placement.__index = Placement

function Placement.new(canvasPart)
    local self = setmetatable({}, Placement)
    self.CanvasPart = canvasPart

    if (isServer) then
        self.CanvasObjects = Instance.new("Folder")
        self.CanvasObjects.Name = "CanvasObjects"
        self.CanvasObjects.Parent = canvasPart
    else
        self.CanvasObjects = initPlacement:InvokeServer(canvasPart)
    end

    self.Surface = Enum.NormalId.Top
    self.GridUnit = 1

    return self
end

function Placement:CalcCanvas()
    local canvasSize = self.CanvasPart.Size

    local back = Vector3.new(0, -1, 0)
    local top = Vector3.new(0, 0, -1)
    local right = Vector3.new(-1, 0, 0)

    local cf = self.CanvasPart.CFrame * CFrame.fromMatrix(-back*canvasSize/2, right, top, back)
    local size = Vector2.new((canvasSize * right).magnitude, (canvasSize * top).magnitude)

    return cf, size
end

function Placement:CalcPlacementCFrame(model, position, rotation)
    local cf, size = self:CalcCanvas()

    local modelSize = CFrame.fromEulerAnglesYXZ(0, rotation, 0) * model.PrimaryPart.Size
    modelSize = Vector3.new(math.abs(modelSize.x), math.abs(modelSize.y), math.abs(modelSize.z))

    local lpos = cf:pointToObjectSpace(position);
    local size2 = (size - Vector2.new(modelSize.x, modelSize.z))/2

    local x = math.clamp(lpos.x, -size2.x, size2.x);
    local y = math.clamp(lpos.y, -size2.y, size2.y);

    local g = self.GridUnit
    if (g > 0) then
        x = math.sign(x)*((math.abs(x) - math.abs(x) % g) + (size2.x % g))
        y = math.sign(y)*((math.abs(y) - math.abs(y) % g) + (size2.y % g))
    end

    return cf * CFrame.new(x, y, -modelSize.y/2) * CFrame.Angles(-math.pi/2, rotation, 0)
end

function Placement:Place(model, cf)
    if (isServer) then
        local clone = model:Clone()
        clone:SetPrimaryPartCFrame(cf)
        clone.Parent = self.CanvasObjects
    end

    if (not isServer) then
        invokePlacement:FireServer("Place", model, cf, isColliding)
    end
end

function Placement:isColliding(model)
    local isColliding = false

    local touch = model.PrimaryPart.Touched:Connect(function() end)
    local touching = model.PrimaryPart:GetTouchingParts()

    for i = 1, #touching do
        if (not touching[i]:IsDescendantOf(model) and touching[i] ~= model.Parent.Parent) then
            isColliding = true
            break
        end
    end

    touch:Disconnect()
    if isColliding == false then
        model.PrimaryPart.BrickColor = BrickColor.new(0,1,0)
        model.PrimaryPart.Transparency = 0.75
    else
        model.PrimaryPart.BrickColor = BrickColor.new(1,0,0)
        model.PrimaryPart.Transparency = 0.75
    end
    return isColliding
end

function Placement:Place(model, cf, isColliding)
    if (not isColliding and isServer) then
        local clone = model:Clone()
        clone:SetPrimaryPartCFrame(cf)
        clone.Parent = self.CanvasObjects
        clone.PrimaryPart.Transparency = 1
    end

    if (not isServer) then
        invokePlacement:FireServer("Place", model, cf, isColliding)
    end
end

function Placement:Serialize()
    local serial = {}

    local cfi = self.CanvasPart.CFrame:inverse()
    local children = self.CanvasObjects:GetChildren()

    for i = 1, #children do
        local objectSpaceCF = cfi * children[i].PrimaryPart.CFrame
        serial[tostring(objectSpaceCF)] = children[i].Name 
    end

    return serial
end

return Placement

Answer this question