Add rojo open command (AI-assisted)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
nezuo 2026-09-28 13:28:00 -07:00
parent a30a8ecd0f
commit dfa6dd7003
7 changed files with 224 additions and 17 deletions

View file

@ -2,6 +2,7 @@ local ChangeHistoryService = game:GetService("ChangeHistoryService")
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local RunService = game:GetService("RunService")
local StudioService = game:GetService("StudioService")
local Rojo = script:FindFirstAncestor("Rojo")
local Plugin = Rojo.Plugin
@ -139,7 +140,7 @@ function App:init()
if RunService:IsEdit() then
self:checkForUpdates()
self:checkForRojoOpen()
self:startSyncReminderPolling()
self.disconnectSyncReminderPollingChanged = Settings:onChanged("syncReminderPolling", function(enabled)
if enabled then
@ -173,12 +174,59 @@ function App:init()
end)
end
function App:checkForRojoOpen()
local rojoOpenName = `ROJO_OPEN_{StudioService:GetUserId()}`
local function tryRojoOpen(instance: Instance)
if instance.Name ~= rojoOpenName then
return
end
local host = instance:GetAttribute("Host")
local port = instance:GetAttribute("Port")
local sessionId = instance:GetAttribute("SessionId")
instance:Destroy()
if instance.Archivable then
-- Protect against malicious ROJO_OPEN saved to the place.
return
elseif typeof(sessionId) ~= "string" then
return
end
if self.rojoOpenConnection then
self.rojoOpenConnection:Disconnect()
self.rojoOpenConnection = nil
end
if self.serveSession == nil or self.serveSession:getStatus() == ServeSession.Status.NotStarted then
self.setHost(if host ~= Config.defaultHost then host else "")
self.setPort(if port ~= Config.defaultPort then port else "")
self:startSession(sessionId)
end
end
self.rojoOpenConnection = game.ChildAdded:Connect(tryRojoOpen)
local existing = game:FindFirstChild(rojoOpenName)
if existing then
tryRojoOpen(existing)
end
end
function App:willUnmount()
self:endSession()
self.waypointConnection:Disconnect()
self.confirmationBindable:Destroy()
if self.rojoOpenConnection then
self.rojoOpenConnection:Disconnect()
self.rojoOpenConnection = nil
end
self.disconnectUpdatesCheckChanged()
self.disconnectPrereleasesCheckChanged()
if self.disconnectSyncReminderPollingChanged then
@ -600,7 +648,7 @@ function App:useRunningConnectionInfo()
self.setPort(port)
end
function App:startSession()
function App:startSession(expectedSessionId: string?)
local claimedLock, priorOwner = self:claimSyncLock()
if not claimedLock then
local msg = string.format("Could not sync because user '%s' is already syncing", tostring(priorOwner))
@ -629,6 +677,7 @@ function App:startSession()
local serveSession = ServeSession.new({
apiContext = apiContext,
twoWaySync = Settings:get("twoWaySync"),
expectedSessionId = expectedSessionId,
})
serveSession:setUpdateLoadingTextCallback(function(text: string)

View file

@ -63,6 +63,7 @@ ServeSession.Status = Status
local validateServeOptions = t.strictInterface({
apiContext = t.table,
twoWaySync = t.boolean,
expectedSessionId = t.optional(t.string),
})
function ServeSession.new(options)
@ -101,6 +102,7 @@ function ServeSession.new(options)
__status = Status.NotStarted,
__apiContext = options.apiContext,
__twoWaySync = options.twoWaySync,
__expectedSessionId = options.expectedSessionId,
__reconciler = reconciler,
__instanceMap = instanceMap,
__changeBatcher = changeBatcher,
@ -196,6 +198,10 @@ function ServeSession:start()
self.__apiContext
:connect()
:andThen(function(serverInfo)
if self.__expectedSessionId ~= nil and serverInfo.sessionId ~= self.__expectedSessionId then
return Promise.reject("Connected to a different Rojo server than the one that opened this place")
end
self:setLoadingText("Loading initial data from server...")
return self:__initialSync(serverInfo):andThen(function()
self:setLoadingText("Starting sync loop...")