null
nil
-
true
false
StellarX Studio Builder
0 and parts==#job.actions and parts<=90
pending.Text=(safeAuto and "Auto Build (parts only):\n" or "Waiting for your approval:\n")..
tostring(job.title or "Build").."\n"..parts.." parts and "..scripts.." disabled scripts."
setButtonState(true)
if safeAuto and os.clock()-lastAutoBuild>=30 then
lastAutoBuild=os.clock()
task.defer(function()
if handle and currentJob and currentJob.id==job.id and not busy and autoBuild then
handle(true)
end
end)
end
else
currentJob=nil
setButtonState(false)
pending.Text="No build waiting. Describe something on the StellarX website."
end
end
local function number(v,limit)
return type(v)=="number" and v==v and v>=-limit and v<=limit
end
local function coordinates(v,limit,positive)
if type(v)~="table" or #v~=3 then return nil end
for i=1,3 do
if not number(v[i],limit) or (positive and v[i]<.05) then return nil end
end
return Vector3.new(v[1],v[2],v[3])
end
local permittedMaterials={
SmoothPlastic=true,Plastic=true,Asphalt=true,Concrete=true,Wood=true,
Grass=true,Ground=true,Metal=true,Glass=true,Neon=true,Brick=true,
Fabric=true,Cobblestone=true,Granite=true,Sand=true,Slate=true
}
local function verify(actions)
if type(actions)~="table" or #actions<1 or #actions>90 then
error("The requested build has too many changes.")
end
for _,a in ipairs(actions) do
if type(a)~="table" or type(a.name)~="string" or #a.name<1 or #a.name>75 then
error("A build object has an invalid name.")
end
if a.type=="part" then
if not coordinates(a.size,500,true) or not coordinates(a.position,15000,false) then
error("A part has unsafe dimensions or position.")
end
if a.color and (type(a.color)~="string" or not a.color:match("^#%x%x%x%x%x%x$")) then
error("A part has an invalid colour.")
end
if a.material and not permittedMaterials[a.material] then
error("A part has an unsupported material.")
end
if a.shape and a.shape~="Block" and a.shape~="Ball" and a.shape~="Cylinder" then
error("Unsupported part shape.")
end
elseif a.type=="script" then
if type(a.source)~="string" or #a.source>14000 then
error("A generated script is invalid.")
end
else error("Unsupported action. No changes were made.") end
end
end
local function folder(parent,name)
local f=parent:FindFirstChild(name)
if f and not f:IsA("Folder") then error(name.." is not a folder") end
if not f then f=Instance.new("Folder");f.Name=name;f.Parent=parent end
return f
end
local function safeFolderName(value)
return (tostring(value):gsub("[^%w_%- ]",""):sub(1,38))
end
local function apply(actions,id,title)
verify(actions)
local selected=Selection:Get()
local offset=Vector3.zero
local first=selected[1]
if first then
if first:IsA("BasePart") then offset=first.Position
elseif first:IsA("Model") then offset=first:GetPivot().Position end
end
local parent=folder(workspace,"StellarGenerated")
local run=Instance.new("Folder")
run.Name=safeFolderName(title).."_"..id:sub(1,8)
local scriptRoot=nil
local scriptGroup=nil
local ok,err=pcall(function()
for _,a in ipairs(actions) do
if a.type=="part" then
local part=Instance.new("Part")
part.Name=a.name
part.Anchored=true
part.Size=coordinates(a.size,500,true)
part.Position=offset+coordinates(a.position,15000,false)
if a.color then part.Color=Color3.fromHex(a.color) end
if a.material then part.Material=Enum.Material[a.material] end
if a.shape then part.Shape=Enum.PartType[a.shape] end
part.Parent=run
elseif a.type=="script" then
if not scriptRoot then scriptRoot=folder(ServerScriptService,"StellarGeneratedScripts") end
if not scriptGroup then
scriptGroup=Instance.new("Folder")
scriptGroup.Name=run.Name
end
local scriptObject=Instance.new("Script")
scriptObject.Name=a.name
scriptObject.Disabled=true
scriptObject.Source=a.source
scriptObject.Parent=scriptGroup
end
end
if #run:GetChildren()>0 then run.Parent=parent else run:Destroy() end
if scriptGroup then scriptGroup.Parent=scriptRoot end
end)
if not ok then
pcall(function()run:Destroy()end)
if scriptGroup then pcall(function()scriptGroup:Destroy()end) end
error(err)
end
pcall(function() ChangeHistoryService:SetWaypoint("StellarX builder: "..safeFolderName(title)) end)
end
local function finish(id,result,note)
local ok,reply=pcall(request,"stellar_studio_finish",{
p_code=code,p_job=id,p_status=result,p_note=tostring(note or ""):sub(1,260)
})
return ok and reply==true
end
handle=function(accepted)
if busy or not currentJob then return end
busy=true
local job=currentJob
setButtonState(false)
pending.Text=accepted and "Building inside Studio. Please wait..." or "Rejecting build..."
task.spawn(function()
local statusValue="rejected"
local reason="Rejected in Roblox Studio"
if accepted then
local ok,err=pcall(apply,job.actions,job.id,job.title)
statusValue=ok and "applied" or "failed"
reason=ok and "Added into StellarGenerated. Scripts disabled." or tostring(err)
if ok then completed[job.id]=true end
else completed[job.id]=true end
local acknowledged=finish(job.id,statusValue,reason)
if acknowledged then
pending.Text=accepted and (statusValue=="applied" and
"Build added to your game. Review your map and save it." or
"Build failed: "..reason) or "Build rejected. No changes made."
else
pending.Text="Local action finished, but the website did not confirm it. Do not run this job again. Check connection."
end
currentJob=nil
busy=false
task.wait(1)
poll()
end)
end
autoToggle.MouseButton1Click:Connect(function()
autoBuild=not autoBuild
autoToggle.Text=autoBuild and "Auto Build: ON (parts only)" or "Auto Build: OFF (safe parts only)"
pending.Text=autoBuild and "Auto Build ON for parts only. Scripts still need approval." or "Auto Build OFF. All builds require manual approval."
if autoBuild then task.defer(poll) end
end)
approve.MouseButton1Click:Connect(function()if currentJob and not busy then handle(true)end end)
reject.MouseButton1Click:Connect(function()if currentJob and not busy then handle(false)end end)
refresh.MouseButton1Click:Connect(function()task.spawn(poll)end)
openWeb.MouseButton1Click:Connect(function()
status.Text="Open "..BUILDER_URL.." in your browser, sign in, then enter the code shown above."
-- The website address is shown above. This button never runs commands.
end)
toggle.Click:Connect(function()widget.Enabled=not widget.Enabled;if widget.Enabled then task.spawn(poll) end end)
task.spawn(function()
while true do
if not busy then poll() end
task.wait(7)
end
end)
]]>