mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 05:51:39 +00:00
Refactor and rebrand Rojo to Atlas
- Renamed the project from Rojo to Atlas, updating all relevant files, scripts, and documentation to reflect the new branding. - Bumped version to 7.7.0-rc.2 and updated protocol version from 5 to 6. - Modified installation scripts and CI workflows to use the new binary name and paths. - Adjusted plugin settings and internal identifiers to prevent conflicts with the original Rojo. - Enhanced session management and API response handling to support the new server fork identifier. - Updated project templates and README files to guide users on using Atlas.
This commit is contained in:
parent
0e263789b0
commit
50b9e18514
54 changed files with 496 additions and 218 deletions
|
|
@ -1 +1 @@
|
|||
7.7.0-rc.1
|
||||
7.7.0-rc.2
|
||||
|
|
|
|||
|
|
@ -27,11 +27,10 @@ end
|
|||
local function rejectWrongProtocolVersion(infoResponseBody)
|
||||
if infoResponseBody.protocolVersion ~= Config.protocolVersion then
|
||||
local message = (
|
||||
"Found a Rojo dev server, but it's using a different protocol version, and is incompatible."
|
||||
.. "\nMake sure you have matching versions of both the Rojo plugin and server!"
|
||||
"Found a server, but it's using a different protocol version, and is incompatible."
|
||||
.. "\nMake sure you have matching versions of both the Atlas plugin and server!"
|
||||
.. "\n\nYour client is version %s, with protocol version %s. It expects server version %s."
|
||||
.. "\nYour server is version %s, with protocol version %s."
|
||||
.. "\n\nGo to https://github.com/rojo-rbx/rojo for more details."
|
||||
):format(
|
||||
Version.display(Config.version),
|
||||
Config.protocolVersion,
|
||||
|
|
@ -46,6 +45,20 @@ local function rejectWrongProtocolVersion(infoResponseBody)
|
|||
return Promise.resolve(infoResponseBody)
|
||||
end
|
||||
|
||||
local function rejectWrongFork(infoResponseBody)
|
||||
if infoResponseBody.serverFork ~= "atlas" then
|
||||
local message = (
|
||||
"Found a Rojo server, but this plugin requires an Atlas server."
|
||||
.. "\nThe stock Rojo server is not compatible with the Atlas plugin."
|
||||
.. "\nMake sure you are running 'atlas serve' instead of 'rojo serve'."
|
||||
)
|
||||
|
||||
return Promise.reject(message)
|
||||
end
|
||||
|
||||
return Promise.resolve(infoResponseBody)
|
||||
end
|
||||
|
||||
local function rejectWrongPlaceId(infoResponseBody)
|
||||
if infoResponseBody.expectedPlaceIds ~= nil then
|
||||
local foundId = table.find(infoResponseBody.expectedPlaceIds, game.PlaceId)
|
||||
|
|
@ -147,6 +160,7 @@ function ApiContext:connect()
|
|||
:andThen(rejectFailedRequests)
|
||||
:andThen(Http.Response.msgpack)
|
||||
:andThen(rejectWrongProtocolVersion)
|
||||
:andThen(rejectWrongFork)
|
||||
:andThen(function(body)
|
||||
assert(validateApiInfo(body))
|
||||
|
||||
|
|
|
|||
|
|
@ -81,25 +81,65 @@ function SelectionOption:render()
|
|||
local buttonWidth = if props.text == "Studio" then 44 else 36
|
||||
|
||||
-- Transparency logic with hover effect
|
||||
-- Combines real hover state with subtree highlight binding so the matching
|
||||
-- button on child nodes looks hovered when a parent's button is hovered.
|
||||
local bgTransparency, txtTransparency
|
||||
if isParentOnly then
|
||||
-- Parent-only: partially transparent, less so when hovering the button
|
||||
bgTransparency = props.transparency:map(function(t)
|
||||
return if isHovered then 0.2 + (0.8 * t) else 0.5 + (0.5 * t)
|
||||
end)
|
||||
txtTransparency = props.transparency:map(function(t)
|
||||
return if isHovered then 0 + t else 0.3 + (0.7 * t)
|
||||
end)
|
||||
else
|
||||
-- Normal buttons: show hover effect by reducing transparency
|
||||
bgTransparency = props.transparency:map(function(t)
|
||||
if isSelected then
|
||||
return if isHovered then 0 + (1 * t) else 0.1 + (0.9 * t)
|
||||
local subtreeBinding = props.subtreeHighlightBinding
|
||||
local ancestorIds = props.ancestorIds
|
||||
|
||||
if subtreeBinding and ancestorIds then
|
||||
local optionType = props.optionType
|
||||
local joined = Roact.joinBindings({
|
||||
transparency = props.transparency,
|
||||
highlight = subtreeBinding,
|
||||
})
|
||||
|
||||
bgTransparency = joined:map(function(values)
|
||||
local t = values.transparency
|
||||
local info = values.highlight
|
||||
local subtreeHov = info ~= nil and ancestorIds[info.nodeId] == true and info.optionType == optionType
|
||||
local hov = isHovered or subtreeHov
|
||||
|
||||
if isParentOnly then
|
||||
return if hov then 0.2 + (0.8 * t) else 0.5 + (0.5 * t)
|
||||
elseif isSelected then
|
||||
return if hov then 0 + (1 * t) else 0.1 + (0.9 * t)
|
||||
else
|
||||
return if isHovered then 0.5 + (0.5 * t) else 0.7 + (0.3 * t)
|
||||
return if hov then 0.5 + (0.5 * t) else 0.7 + (0.3 * t)
|
||||
end
|
||||
end)
|
||||
txtTransparency = props.transparency
|
||||
|
||||
txtTransparency = joined:map(function(values)
|
||||
local t = values.transparency
|
||||
local info = values.highlight
|
||||
local subtreeHov = info ~= nil and ancestorIds[info.nodeId] == true and info.optionType == optionType
|
||||
local hov = isHovered or subtreeHov
|
||||
|
||||
if isParentOnly then
|
||||
return if hov then 0 + t else 0.3 + (0.7 * t)
|
||||
else
|
||||
return t
|
||||
end
|
||||
end)
|
||||
else
|
||||
-- Fallback: no subtree highlight available
|
||||
if isParentOnly then
|
||||
bgTransparency = props.transparency:map(function(t)
|
||||
return if isHovered then 0.2 + (0.8 * t) else 0.5 + (0.5 * t)
|
||||
end)
|
||||
txtTransparency = props.transparency:map(function(t)
|
||||
return if isHovered then 0 + t else 0.3 + (0.7 * t)
|
||||
end)
|
||||
else
|
||||
bgTransparency = props.transparency:map(function(t)
|
||||
if isSelected then
|
||||
return if isHovered then 0 + (1 * t) else 0.1 + (0.9 * t)
|
||||
else
|
||||
return if isHovered then 0.5 + (0.5 * t) else 0.7 + (0.3 * t)
|
||||
end
|
||||
end)
|
||||
txtTransparency = props.transparency
|
||||
end
|
||||
end
|
||||
|
||||
return e("TextButton", {
|
||||
|
|
@ -118,7 +158,7 @@ function SelectionOption:render()
|
|||
self:setState({ isHovered = true })
|
||||
-- Trigger subtree highlight when this button would apply to children
|
||||
if (isParentOnly or (isSelected and hasChildren)) and props.onSubtreeHoverStart then
|
||||
props.onSubtreeHoverStart()
|
||||
props.onSubtreeHoverStart(props.optionType)
|
||||
end
|
||||
end,
|
||||
[Roact.Event.MouseLeave] = function()
|
||||
|
|
@ -180,6 +220,8 @@ local function SelectionRadio(props)
|
|||
layoutOrder = 1,
|
||||
hasChildren = hasChildren,
|
||||
isParentOnly = isParentOnly,
|
||||
subtreeHighlightBinding = props.subtreeHighlightBinding,
|
||||
ancestorIds = props.ancestorIds,
|
||||
onSubtreeHoverStart = props.onSubtreeHoverStart,
|
||||
onSubtreeHoverEnd = props.onSubtreeHoverEnd,
|
||||
onClick = function()
|
||||
|
|
@ -201,6 +243,8 @@ local function SelectionRadio(props)
|
|||
layoutOrder = 2,
|
||||
hasChildren = hasChildren,
|
||||
isParentOnly = isParentOnly,
|
||||
subtreeHighlightBinding = props.subtreeHighlightBinding,
|
||||
ancestorIds = props.ancestorIds,
|
||||
onSubtreeHoverStart = props.onSubtreeHoverStart,
|
||||
onSubtreeHoverEnd = props.onSubtreeHoverEnd,
|
||||
onClick = function()
|
||||
|
|
@ -222,6 +266,8 @@ local function SelectionRadio(props)
|
|||
layoutOrder = 3,
|
||||
hasChildren = hasChildren,
|
||||
isParentOnly = isParentOnly,
|
||||
subtreeHighlightBinding = props.subtreeHighlightBinding,
|
||||
ancestorIds = props.ancestorIds,
|
||||
onSubtreeHoverStart = props.onSubtreeHoverStart,
|
||||
onSubtreeHoverEnd = props.onSubtreeHoverEnd,
|
||||
onClick = function()
|
||||
|
|
@ -337,17 +383,6 @@ function DomLabel:render()
|
|||
local props = self.props
|
||||
local depth = props.depth or 1
|
||||
|
||||
-- Derive subtree highlight state from binding (no re-renders needed)
|
||||
local ancestorIds = props.ancestorIds
|
||||
local isSubtreeHighlighted = if props.subtreeHighlightNodeId
|
||||
then props.subtreeHighlightNodeId:map(function(highlightId)
|
||||
if highlightId == nil then
|
||||
return false
|
||||
end
|
||||
return ancestorIds[highlightId] == true
|
||||
end)
|
||||
else nil
|
||||
|
||||
return Theme.with(function(theme)
|
||||
local color = if props.isWarning
|
||||
then theme.Diff.Warning
|
||||
|
|
@ -544,17 +579,6 @@ function DomLabel:render()
|
|||
})
|
||||
else nil,
|
||||
}),
|
||||
SubtreeHighlight = if isSubtreeHighlighted
|
||||
then e("Frame", {
|
||||
Size = UDim2.fromScale(1, 1),
|
||||
BackgroundColor3 = theme.Diff.SubtreeHighlight,
|
||||
BackgroundTransparency = isSubtreeHighlighted:map(function(highlighted)
|
||||
return if highlighted then 0.92 else 1
|
||||
end),
|
||||
BorderSizePixel = 0,
|
||||
ZIndex = 0,
|
||||
})
|
||||
else nil,
|
||||
SelectionRadio = e(SelectionRadio, {
|
||||
-- Visible for nodes with patchType, or for parent-only nodes on hover
|
||||
visible = (props.patchType ~= nil and props.onSelectionChange ~= nil)
|
||||
|
|
@ -572,9 +596,12 @@ function DomLabel:render()
|
|||
isParentOnly = props.patchType == nil,
|
||||
onSelectionChange = props.onSelectionChange,
|
||||
onSubtreeSelectionChange = props.onSubtreeSelectionChange,
|
||||
onSubtreeHoverStart = function()
|
||||
-- Subtree hover highlight: pass binding and ancestors to child buttons
|
||||
subtreeHighlightBinding = props.subtreeHighlightNodeId,
|
||||
ancestorIds = props.ancestorIds,
|
||||
onSubtreeHoverStart = function(optionType)
|
||||
if props.setSubtreeHighlightNodeId then
|
||||
props.setSubtreeHighlightNodeId(props.nodeId)
|
||||
props.setSubtreeHighlightNodeId({ nodeId = props.nodeId, optionType = optionType })
|
||||
end
|
||||
end,
|
||||
onSubtreeHoverEnd = function()
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ function ConfirmingPage:render()
|
|||
}),
|
||||
|
||||
StringDiff = e(StudioPluginGui, {
|
||||
id = "Rojo_ConfirmingStringDiff",
|
||||
id = "Atlas_ConfirmingStringDiff",
|
||||
title = "String diff",
|
||||
active = self.state.showingStringDiff,
|
||||
isEphemeral = true,
|
||||
|
|
@ -283,7 +283,7 @@ function ConfirmingPage:render()
|
|||
}),
|
||||
|
||||
TableDiff = e(StudioPluginGui, {
|
||||
id = "Rojo_ConfirmingTableDiff",
|
||||
id = "Atlas_ConfirmingTableDiff",
|
||||
title = "Table diff",
|
||||
active = self.state.showingTableDiff,
|
||||
isEphemeral = true,
|
||||
|
|
@ -322,7 +322,7 @@ function ConfirmingPage:render()
|
|||
|
||||
-- Accept confirmation popup for unselected items
|
||||
AcceptConfirm = e(StudioPluginGui, {
|
||||
id = "Rojo_AcceptConfirm",
|
||||
id = "Atlas_AcceptConfirm",
|
||||
title = "Unreviewed Items",
|
||||
active = self.state.showingAcceptConfirm,
|
||||
isEphemeral = true,
|
||||
|
|
@ -400,7 +400,7 @@ function ConfirmingPage:render()
|
|||
|
||||
if self.props.createPopup then
|
||||
return e(StudioPluginGui, {
|
||||
id = "Rojo_DiffSync",
|
||||
id = "Atlas_DiffSync",
|
||||
title = string.format(
|
||||
"Confirm sync for project '%s':",
|
||||
self.props.confirmData.serverInfo.projectName or "UNKNOWN"
|
||||
|
|
|
|||
|
|
@ -481,7 +481,7 @@ function ConnectedPage:render()
|
|||
}),
|
||||
|
||||
ChangesViewer = e(StudioPluginGui, {
|
||||
id = "Rojo_ChangesViewer",
|
||||
id = "Atlas_ChangesViewer",
|
||||
title = "View changes",
|
||||
active = self.state.renderChanges,
|
||||
isEphemeral = true,
|
||||
|
|
@ -536,7 +536,7 @@ function ConnectedPage:render()
|
|||
}),
|
||||
|
||||
StringDiff = e(StudioPluginGui, {
|
||||
id = "Rojo_ConnectedStringDiff",
|
||||
id = "Atlas_ConnectedStringDiff",
|
||||
title = "String diff",
|
||||
active = self.state.showingStringDiff,
|
||||
isEphemeral = true,
|
||||
|
|
@ -574,7 +574,7 @@ function ConnectedPage:render()
|
|||
}),
|
||||
|
||||
TableDiff = e(StudioPluginGui, {
|
||||
id = "Rojo_ConnectedTableDiff",
|
||||
id = "Atlas_ConnectedTableDiff",
|
||||
title = "Table diff",
|
||||
active = self.state.showingTableDiff,
|
||||
isEphemeral = true,
|
||||
|
|
|
|||
|
|
@ -237,7 +237,6 @@ function StudioProvider:updateTheme()
|
|||
Edit = Color3.fromRGB(255, 0, 255),
|
||||
|
||||
Row = studioTheme:GetColor(Enum.StudioStyleGuideColor.BrightText),
|
||||
SubtreeHighlight = if isDark then Color3.fromRGB(255, 255, 255) else Color3.fromRGB(0, 0, 0),
|
||||
Warning = studioTheme:GetColor(Enum.StudioStyleGuideColor.WarningText),
|
||||
WhitespaceOnly = if isDark then Color3.fromRGB(140, 140, 140) else Color3.fromRGB(110, 110, 110),
|
||||
Changes = if isDark then Color3.fromRGB(100, 140, 220) else Color3.fromRGB(40, 100, 180),
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ function App:init()
|
|||
self.notifId = 0
|
||||
|
||||
self.waypointConnection = ChangeHistoryService.OnUndo:Connect(function(action: string)
|
||||
if not string.find(action, "^Rojo: Patch") then
|
||||
if not string.find(action, "^Atlas: Patch") then
|
||||
return
|
||||
end
|
||||
|
||||
|
|
@ -318,7 +318,7 @@ function App:isSyncLockAvailable()
|
|||
return true
|
||||
end
|
||||
|
||||
local lock = ServerStorage:FindFirstChild("__Rojo_SessionLock")
|
||||
local lock = ServerStorage:FindFirstChild("__Atlas_SessionLock")
|
||||
if not lock then
|
||||
-- No lock is made yet, so it is available
|
||||
return true
|
||||
|
|
@ -345,10 +345,10 @@ function App:claimSyncLock()
|
|||
return false, priorOwner
|
||||
end
|
||||
|
||||
local lock = ServerStorage:FindFirstChild("__Rojo_SessionLock")
|
||||
local lock = ServerStorage:FindFirstChild("__Atlas_SessionLock")
|
||||
if not lock then
|
||||
lock = Instance.new("ObjectValue")
|
||||
lock.Name = "__Rojo_SessionLock"
|
||||
lock.Name = "__Atlas_SessionLock"
|
||||
lock.Archivable = false
|
||||
lock.Value = Players.LocalPlayer
|
||||
lock.Parent = ServerStorage
|
||||
|
|
@ -362,7 +362,7 @@ function App:claimSyncLock()
|
|||
end
|
||||
|
||||
function App:releaseSyncLock()
|
||||
local lock = ServerStorage:FindFirstChild("__Rojo_SessionLock")
|
||||
local lock = ServerStorage:FindFirstChild("__Atlas_SessionLock")
|
||||
if not lock then
|
||||
Log.trace("No sync lock found, assumed released")
|
||||
return
|
||||
|
|
@ -450,7 +450,7 @@ function App:checkSyncReminder()
|
|||
|
||||
local timeSinceSync = timeUtil.elapsedToText(os.time() - priorSyncInfo.timestamp)
|
||||
self:sendSyncReminder(
|
||||
`You synced project '{priorSyncInfo.projectName}' to this place {timeSinceSync}.\nDid you mean to run 'rojo serve' and then connect?`
|
||||
`You synced project '{priorSyncInfo.projectName}' to this place {timeSinceSync}.\nDid you mean to run 'atlas serve' and then connect?`
|
||||
)
|
||||
end
|
||||
end)
|
||||
|
|
@ -531,7 +531,7 @@ function App:isAutoConnectPlaytestServerAvailable()
|
|||
and RunService:IsStudio()
|
||||
and RunService:IsServer()
|
||||
and Settings:get("autoConnectPlaytestServer")
|
||||
and workspace:GetAttribute("__Rojo_ConnectionUrl")
|
||||
and workspace:GetAttribute("__Atlas_ConnectionUrl")
|
||||
end
|
||||
|
||||
function App:isAutoConnectPlaytestServerWriteable()
|
||||
|
|
@ -544,7 +544,7 @@ function App:setRunningConnectionInfo(baseUrl: string)
|
|||
end
|
||||
|
||||
Log.trace("Setting connection info for play solo auto-connect")
|
||||
workspace:SetAttribute("__Rojo_ConnectionUrl", baseUrl)
|
||||
workspace:SetAttribute("__Atlas_ConnectionUrl", baseUrl)
|
||||
end
|
||||
|
||||
function App:clearRunningConnectionInfo()
|
||||
|
|
@ -554,11 +554,11 @@ function App:clearRunningConnectionInfo()
|
|||
end
|
||||
|
||||
Log.trace("Clearing connection info for play solo auto-connect")
|
||||
workspace:SetAttribute("__Rojo_ConnectionUrl", nil)
|
||||
workspace:SetAttribute("__Atlas_ConnectionUrl", nil)
|
||||
end
|
||||
|
||||
function App:useRunningConnectionInfo()
|
||||
local connectionInfo = workspace:GetAttribute("__Rojo_ConnectionUrl")
|
||||
local connectionInfo = workspace:GetAttribute("__Atlas_ConnectionUrl")
|
||||
if not connectionInfo then
|
||||
return
|
||||
end
|
||||
|
|
@ -890,7 +890,8 @@ function App:endSession()
|
|||
-- but the UI is still stuck on Connected/Connecting, force reset to NotConnected.
|
||||
-- This handles race conditions where onStatusChanged(Connected) fires after
|
||||
-- onStatusChanged(Disconnected) due to a coroutine resuming on a dead session.
|
||||
if self.state.appStatus ~= AppStatus.NotConnected
|
||||
if
|
||||
self.state.appStatus ~= AppStatus.NotConnected
|
||||
and self.state.appStatus ~= AppStatus.Error
|
||||
and self.state.appStatus ~= AppStatus.Settings
|
||||
then
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ return strict("Config", {
|
|||
codename = "Epiphany",
|
||||
version = realVersion,
|
||||
expectedServerVersionString = ("%d.%d or newer"):format(realVersion[1], realVersion[2]),
|
||||
protocolVersion = 5,
|
||||
protocolVersion = 6,
|
||||
defaultHost = "localhost",
|
||||
defaultPort = "34872",
|
||||
defaultPort = "34873",
|
||||
ignoredClassNames = IgnoredClassNames,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -38,11 +38,11 @@ Settings._bindings = {}
|
|||
|
||||
if plugin then
|
||||
for name, defaultValue in pairs(Settings._values) do
|
||||
local savedValue = plugin:GetSetting("Rojo_" .. name)
|
||||
local savedValue = plugin:GetSetting("Atlas_" .. name)
|
||||
|
||||
if savedValue == nil then
|
||||
-- plugin:SetSetting hits disc instead of memory, so it can be slow. Spawn so we don't hang.
|
||||
task.spawn(plugin.SetSetting, plugin, "Rojo_" .. name, defaultValue)
|
||||
task.spawn(plugin.SetSetting, plugin, "Atlas_" .. name, defaultValue)
|
||||
Settings._values[name] = defaultValue
|
||||
else
|
||||
Settings._values[name] = savedValue
|
||||
|
|
@ -67,7 +67,7 @@ function Settings:set(name, value)
|
|||
|
||||
if plugin then
|
||||
-- plugin:SetSetting hits disc instead of memory, so it can be slow. Spawn so we don't hang.
|
||||
task.spawn(plugin.SetSetting, plugin, "Rojo_" .. name, value)
|
||||
task.spawn(plugin.SetSetting, plugin, "Atlas_" .. name, value)
|
||||
end
|
||||
|
||||
if self._updateListeners[name] then
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ local ApiInfoResponse = t.interface({
|
|||
sessionId = t.string,
|
||||
serverVersion = t.string,
|
||||
protocolVersion = t.number,
|
||||
serverFork = t.string,
|
||||
expectedPlaceIds = t.optional(t.array(t.number)),
|
||||
rootInstanceId = RbxId,
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue