local k=game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")local t=require(k:WaitForChild("\078\101\118\101\114\109\111\114\101",2))local Z=t("\083\116\100")local F=Z.linq local D=Z.uuid local J=game:GetService("\083\101\114\118\101\114\083\116\111\114\097\103\101")local u={}function u.MoveModelToCoordFrame(k,t)print("\068\101\115\116\105\110\097\116\105\111\110 \102\111\114 \115\112\097\119\110\058  "..tostring(t))local Z=k.PrimaryPart or error(k.Name.." \104\097\115 \110\111 \080\114\105\109\097\114\121\080\097\114\116")local F=Z.CFrame local D={}for k,t in next,k:GetDescendants()do if t~=Z and t:IsA("\066\097\115\101\080\097\114\116")then D[t]=F:toObjectSpace(t.CFrame)end end Z.CFrame=t for k,Z in next,D do k.CFrame=t*Z end end function u.CreateFromFolder(k,t,Z,D,J)local m=k:GetChildren()local a=(F(m)):firstOrDefault(function(k)local Z=k:FindFirstChild("\080\114\111\116\111\116\121\112\101\073\100")if Z~=nil then print("\070\111\117\110\100 \105\116\101\109 \112\114\111\116\111\116\121\112\101\058 "..t)return Z.Value==t end return false end)if a==nil then a=(F(m)):firstOrDefault(function(k)return k.Name==t end)end if a==nil then error("\067\111\117\108\100 \110\111\116 \102\105\110\100 \080\114\111\116\111\116\121\112\101\058 "..t)return nil end u.SpawnModelFromPrototype(a,Z,D,J)end function u.CreateFromServerStorage(k,t,Z,F,D)local m=J:FindFirstChild(k)u.CreateFromFolder(m,t,Z,F,D)end function u.SpawnModelFromPrototype(k,t,Z,F)spawn(function()local J=k:Clone()local m=J:FindFirstChild("\069\110\116\105\116\121\073\100")if m==nil then m=Instance.new("\083\116\114\105\110\103\086\097\108\117\101")m.Parent=J end m.Value=D()J.Parent=F or game:GetService("\087\111\114\107\115\112\097\099\101")u.MoveModelToCoordFrame(J,t)if Z~=nil then Z(J)end end)end return u
--- Sugar for creating something out of nothing

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local require = require(ReplicatedStorage:WaitForChild("Nevermore", 2))
local std = require("Std")

local linq = std.linq
local uuid = std.uuid
local serverStorage =  game:GetService("ServerStorage")

local module = {}
--[[
    When working with collections and tags, it’s a good idea to use an object-oriented programming style. 
    In almost all situations, tagged objects have their own identity, state and behavior. 
    The pattern goes like this: 
        when a tag is found (CollectionService:GetTagged and CollectionService:GetInstanceAddedSignal), 
           create a Lua object with the Roblox instance. 
        When it is removed (CollectionService:GetInstanceRemovedSignal), 
            call a cleanup/destroy method within the Lua object. 
    See the code samples for a better idea of how this can be done.

    When tags replicate, all tags on an object replicate at the same time. 
    Therefore, 
        if you set a tag on an object from the client 
        then add/remove a different tag on the same object from the server, 
            the client’s local tags on the object are overwritten.
]]


-- ExampleSetterFunction = exNihilo.MoveModelToCoordFrame(workspace:WaitForChild("Model"), CFrame.new(0,5,0))
function module.MoveModelToCoordFrame( modelWithPrimaryPart, newCoordFrame )
    print("Destination for spawn:  " .. tostring(newCoordFrame))
    local Primary = modelWithPrimaryPart.PrimaryPart or error(modelWithPrimaryPart.Name .. " has no PrimaryPart")
    local PrimaryCF = Primary.CFrame
    local Cache = {}
    
    for _, Desc in next, modelWithPrimaryPart:GetDescendants() do
        if Desc ~= Primary and Desc:IsA("BasePart") then
            Cache[Desc] = PrimaryCF:toObjectSpace(Desc.CFrame)
        end
    end

    Primary.CFrame = newCoordFrame
    for Part, Offset in next, Cache do
        Part.CFrame = newCoordFrame * Offset
        
    end
end

function module.CreateFromFolder(storageFolderInstance, prototypeId, coordsForNewInstance, createdModelCallback, targetParent)
    local modelCandidates = storageFolderInstance:GetChildren()
    local foundPrototype = linq(modelCandidates):firstOrDefault(function( itm )

        local itmPrototypeId = itm:FindFirstChild("PrototypeId")
        
        if (itmPrototypeId ~= nil) then
            print("Found item prototype: " .. prototypeId)
            return itmPrototypeId.Value == prototypeId
        end
        return false
    end)

    if foundPrototype == nil then
        foundPrototype = linq(modelCandidates):firstOrDefault(function( itm )
            return itm.Name == prototypeId
        end)
    end

    if foundPrototype == nil then
        error("Could not find Prototype: " .. prototypeId)
        return nil
    end

    module.SpawnModelFromPrototype(foundPrototype, coordsForNewInstance, createdModelCallback, targetParent)
end

-- createdModelCallback takes the createdModel as its only parameter
function module.CreateFromServerStorage( storageCategory, prototypeId, coordsForNewInstance, createdModelCallback, targetParent )
    local storageCategoryFolder = serverStorage:FindFirstChild(storageCategory)
    module.CreateFromFolder(storageCategoryFolder, prototypeId, coordsForNewInstance, createdModelCallback, targetParent)
end

function module.SpawnModelFromPrototype(prototypeModel, coordsForNewInstance, createdModelCallback, targetParent)
    spawn(function ()
        local createdItem = prototypeModel:Clone()
        local entityIdObj = createdItem:FindFirstChild("EntityId")
        if entityIdObj == nil then
            entityIdObj = Instance.new("StringValue")
            entityIdObj.Parent = createdItem
        end
        entityIdObj.Value = uuid()
        createdItem.Parent = targetParent or game:GetService("Workspace")
        
        module.MoveModelToCoordFrame(createdItem, coordsForNewInstance)
        if createdModelCallback ~= nil then
            createdModelCallback(createdItem)
        end
    end)
end

return module