diff --git a/CHANGELOG.md b/CHANGELOG.md index 70a7d5a8..efc9405a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased Changes * Added popout diff visualizer for table properties like Attributes and Tags ([#834]) * Updated Theme to use Studio colors ([#838]) +* Added experimental setting for Auto Connect in playtests ([#840]) * Projects may now specify rules for syncing files as if they had a different file extension. ([#813]) This is specified via a new field on project files, `syncRules`: @@ -53,6 +54,7 @@ [#813]: https://github.com/rojo-rbx/rojo/pull/813 [#834]: https://github.com/rojo-rbx/rojo/pull/834 [#838]: https://github.com/rojo-rbx/rojo/pull/838 +[#840]: https://github.com/rojo-rbx/rojo/pull/840 ## [7.4.0] - January 16, 2024 * Improved the visualization for array properties like Tags ([#829]) diff --git a/plugin/src/App/StatusPages/Settings/init.lua b/plugin/src/App/StatusPages/Settings/init.lua index 688be85a..a33eb1b5 100644 --- a/plugin/src/App/StatusPages/Settings/init.lua +++ b/plugin/src/App/StatusPages/Settings/init.lua @@ -75,6 +75,12 @@ function SettingsPage:init() end function SettingsPage:render() + local layoutOrder = 0 + local function layoutIncrement() + layoutOrder += 1 + return layoutOrder + end + return Theme.with(function(theme) theme = theme.Settings @@ -86,7 +92,7 @@ function SettingsPage:render() Navbar = e(Navbar, { onBack = self.props.onBack, transparency = self.props.transparency, - layoutOrder = 0, + layoutOrder = layoutIncrement(), }), ShowNotifications = e(Setting, { @@ -94,7 +100,7 @@ function SettingsPage:render() name = "Show Notifications", description = "Popup notifications in viewport", transparency = self.props.transparency, - layoutOrder = 1, + layoutOrder = layoutIncrement(), }), SyncReminder = e(Setting, { @@ -103,7 +109,7 @@ function SettingsPage:render() description = "Notify to sync when opening a place that has previously been synced", transparency = self.props.transparency, visible = Settings:getBinding("showNotifications"), - layoutOrder = 2, + layoutOrder = layoutIncrement(), }), ConfirmationBehavior = e(Setting, { @@ -111,7 +117,7 @@ function SettingsPage:render() name = "Confirmation Behavior", description = "When to prompt for confirmation before syncing", transparency = self.props.transparency, - layoutOrder = 3, + layoutOrder = layoutIncrement(), options = confirmationBehaviors, }), @@ -121,7 +127,7 @@ function SettingsPage:render() name = "Confirmation Threshold", description = "How many modified instances to be considered a large change", transparency = self.props.transparency, - layoutOrder = 4, + layoutOrder = layoutIncrement(), visible = Settings:getBinding("confirmationBehavior"):map(function(value) return value == "Large Changes" end), @@ -152,7 +158,16 @@ function SettingsPage:render() name = "Play Sounds", description = "Toggle sound effects", transparency = self.props.transparency, - layoutOrder = 5, + layoutOrder = layoutIncrement(), + }), + + AutoConnectPlaytestServer = e(Setting, { + id = "autoConnectPlaytestServer", + name = "Auto Connect Playtest Server", + description = "Automatically connect game server to Rojo when playtesting while connected in Edit", + experimental = true, + transparency = self.props.transparency, + layoutOrder = layoutIncrement(), }), OpenScriptsExternally = e(Setting, { @@ -162,7 +177,7 @@ function SettingsPage:render() locked = self.props.syncActive, experimental = true, transparency = self.props.transparency, - layoutOrder = 6, + layoutOrder = layoutIncrement(), }), TwoWaySync = e(Setting, { @@ -172,7 +187,7 @@ function SettingsPage:render() locked = self.props.syncActive, experimental = true, transparency = self.props.transparency, - layoutOrder = 7, + layoutOrder = layoutIncrement(), }), LogLevel = e(Setting, { @@ -180,7 +195,7 @@ function SettingsPage:render() name = "Log Level", description = "Plugin output verbosity level", transparency = self.props.transparency, - layoutOrder = 100, + layoutOrder = layoutIncrement(), options = invertedLevels, showReset = Settings:getBinding("logLevel"):map(function(value) @@ -196,7 +211,7 @@ function SettingsPage:render() name = "Typechecking", description = "Toggle typechecking on the API surface", transparency = self.props.transparency, - layoutOrder = 101, + layoutOrder = layoutIncrement(), }), Layout = e("UIListLayout", { diff --git a/plugin/src/App/init.lua b/plugin/src/App/init.lua index 22f277f9..ecb807f0 100644 --- a/plugin/src/App/init.lua +++ b/plugin/src/App/init.lua @@ -158,11 +158,29 @@ function App:init() }, }) end + + if self:isAutoConnectPlaytestServerAvailable() then + self:useRunningConnectionInfo() + self:startSession() + end + self.autoConnectPlaytestServerListener = Settings:onChanged("autoConnectPlaytestServer", function(enabled) + if enabled then + if self:isAutoConnectPlaytestServerWriteable() and self.serveSession ~= nil then + -- Write the existing session + local baseUrl = self.serveSession.__apiContext.__baseUrl + self:setRunningConnectionInfo(baseUrl) + end + else + self:clearRunningConnectionInfo() + end + end) end function App:willUnmount() self.waypointConnection:Disconnect() self.confirmationBindable:Destroy() + self.autoConnectPlaytestServerListener() + self:clearRunningConnectionInfo() end function App:addNotification( @@ -278,10 +296,7 @@ function App:getHostAndPort() local host = self.host:getValue() local port = self.port:getValue() - local host = if #host > 0 then host else Config.defaultHost - local port = if #port > 0 then port else Config.defaultPort - - return host, port + return if #host > 0 then host else Config.defaultHost, if #port > 0 then port else Config.defaultPort end function App:isSyncLockAvailable() @@ -349,6 +364,49 @@ function App:releaseSyncLock() Log.trace("Could not relase sync lock because it is owned by {}", lock.Value) end +function App:isAutoConnectPlaytestServerAvailable() + return RunService:IsRunMode() + and RunService:IsServer() + and Settings:get("autoConnectPlaytestServer") + and workspace:GetAttribute("__Rojo_ConnectionUrl") +end + +function App:isAutoConnectPlaytestServerWriteable() + return RunService:IsEdit() and Settings:get("autoConnectPlaytestServer") +end + +function App:setRunningConnectionInfo(baseUrl: string) + if not self:isAutoConnectPlaytestServerWriteable() then + return + end + + Log.trace("Setting connection info for play solo auto-connect") + workspace:SetAttribute("__Rojo_ConnectionUrl", baseUrl) +end + +function App:clearRunningConnectionInfo() + if not RunService:IsEdit() then + -- Only write connection info from edit mode + return + end + + Log.trace("Clearing connection info for play solo auto-connect") + workspace:SetAttribute("__Rojo_ConnectionUrl", nil) +end + +function App:useRunningConnectionInfo() + local connectionInfo = workspace:GetAttribute("__Rojo_ConnectionUrl") + if not connectionInfo then + return + end + + Log.trace("Using connection info for play solo auto-connect") + local host, port = string.match(connectionInfo, "^(.+):(.-)$") + + self.setHost(host) + self.setPort(port) +end + function App:startSession() local claimedLock, priorOwner = self:claimSyncLock() if not claimedLock then @@ -441,6 +499,7 @@ function App:startSession() self:addNotification("Connecting to session...") elseif status == ServeSession.Status.Connected then self.knownProjects[details] = true + self:setRunningConnectionInfo(baseUrl) local address = ("%s:%s"):format(host, port) self:setState({ @@ -453,6 +512,7 @@ function App:startSession() elseif status == ServeSession.Status.Disconnected then self.serveSession = nil self:releaseSyncLock() + self:clearRunningConnectionInfo() self:setState({ patchData = { patch = PatchSet.newEmpty(), @@ -488,6 +548,12 @@ function App:startSession() return "Accept" end + -- Play solo auto-connect does not require confirmation + if self:isAutoConnectPlaytestServerAvailable() then + Log.trace("Accepting patch without confirmation because play solo auto-connect is enabled") + return "Accept" + end + local confirmationBehavior = Settings:get("confirmationBehavior") if confirmationBehavior == "Initial" then -- Only confirm if we haven't synced this project yet this session @@ -603,7 +669,7 @@ function App:render() value = self.props.plugin, }, { e(Theme.StudioProvider, nil, { - e(Tooltip.Provider, nil, { + tooltip = e(Tooltip.Provider, nil, { gui = e(StudioPluginGui, { id = pluginName, title = pluginName, diff --git a/plugin/src/Settings.lua b/plugin/src/Settings.lua index 194dd4c7..b5be22a7 100644 --- a/plugin/src/Settings.lua +++ b/plugin/src/Settings.lua @@ -14,6 +14,7 @@ local defaultSettings = { twoWaySync = false, showNotifications = true, syncReminder = true, + autoConnectPlaytestServer = false, confirmationBehavior = "Initial", largeChangesConfirmationThreshold = 5, playSounds = true,