From b30aa8280dbc3f39b04c8d7a7fbc72dda8b2a7ef Mon Sep 17 00:00:00 2001 From: Joe Date: Sat, 24 Jan 2026 05:24:08 -0600 Subject: [PATCH] Implement sync source-only mode in ServeSession and ChangeBatcher - Added support for a new sync mode in ServeSession that filters property changes to only include the Source property when the server indicates it is in source-only mode. - Updated ChangeBatcher to handle the new syncSourceOnly parameter, ensuring that only relevant property changes are processed based on the server's capabilities. - Enhanced API response to include sync_source_only flag, indicating the server's sync capabilities. - Adjusted related functions to accommodate the new sync logic, improving data synchronization efficiency. --- plugin/src/App/init.lua | 8 ++++++-- plugin/src/ChangeBatcher/createPatchSet.lua | 18 ++++++++++++++--- plugin/src/ChangeBatcher/init.lua | 7 ++++++- plugin/src/ServeSession.lua | 22 +++++++++++++++++++-- src/web/api.rs | 1 + src/web/interface.rs | 4 ++++ 6 files changed, 52 insertions(+), 8 deletions(-) diff --git a/plugin/src/App/init.lua b/plugin/src/App/init.lua index c83d9d1c..fe955603 100644 --- a/plugin/src/App/init.lua +++ b/plugin/src/App/init.lua @@ -106,13 +106,17 @@ function App:init() -- Our notif is now out of date- redoing will not restore the patch -- since we've undone even further. Dismiss the notif. cleanup() - dismissNotif() + if dismissNotif then + dismissNotif() + end end) redoConnection = ChangeHistoryService.OnRedo:Once(function(redoneAction: string) if redoneAction == action then -- The user has restored the patch, so we can dismiss the notif cleanup() - dismissNotif() + if dismissNotif then + dismissNotif() + end end end) end) diff --git a/plugin/src/ChangeBatcher/createPatchSet.lua b/plugin/src/ChangeBatcher/createPatchSet.lua index 5502d0d6..3207722b 100644 --- a/plugin/src/ChangeBatcher/createPatchSet.lua +++ b/plugin/src/ChangeBatcher/createPatchSet.lua @@ -12,7 +12,7 @@ local PatchSet = require(script.Parent.Parent.PatchSet) local encodePatchUpdate = require(script.Parent.encodePatchUpdate) -return function(instanceMap, propertyChanges) +return function(instanceMap, propertyChanges, syncSourceOnly) local patch = PatchSet.newEmpty() for instance, properties in propertyChanges do @@ -30,8 +30,20 @@ return function(instanceMap, propertyChanges) Log.warn("Cannot sync non-nil Parent property changes yet") end else - local update = encodePatchUpdate(instance, instanceId, properties) - table.insert(patch.updated, update) + if syncSourceOnly then + -- Filter to only Source property when server is in source-only mode + if properties.Source then + local update = encodePatchUpdate(instance, instanceId, { Source = true }) + if update then + table.insert(patch.updated, update) + end + end + else + local update = encodePatchUpdate(instance, instanceId, properties) + if update then + table.insert(patch.updated, update) + end + end end propertyChanges[instance] = nil diff --git a/plugin/src/ChangeBatcher/init.lua b/plugin/src/ChangeBatcher/init.lua index 5d320ce2..19af2ed2 100644 --- a/plugin/src/ChangeBatcher/init.lua +++ b/plugin/src/ChangeBatcher/init.lua @@ -27,11 +27,16 @@ function ChangeBatcher.new(instanceMap, onChangesFlushed) __instanceMap = instanceMap, __onChangesFlushed = onChangesFlushed, __pendingPropertyChanges = {}, + __syncSourceOnly = false, }, ChangeBatcher) return self end +function ChangeBatcher:setSyncSourceOnly(enabled) + self.__syncSourceOnly = enabled +end + function ChangeBatcher:stop() self.__renderSteppedConnection:Disconnect() self.__pendingPropertyChanges = {} @@ -69,7 +74,7 @@ function ChangeBatcher:__flush() return nil end - local patch = createPatchSet(self.__instanceMap, self.__pendingPropertyChanges) + local patch = createPatchSet(self.__instanceMap, self.__pendingPropertyChanges, self.__syncSourceOnly) if PatchSet.isEmpty(patch) then return nil diff --git a/plugin/src/ServeSession.lua b/plugin/src/ServeSession.lua index adee9e4d..c9e9d34f 100644 --- a/plugin/src/ServeSession.lua +++ b/plugin/src/ServeSession.lua @@ -100,6 +100,7 @@ function ServeSession.new(options) __status = Status.NotStarted, __apiContext = options.apiContext, __twoWaySync = options.twoWaySync, + __syncSourceOnly = false, __reconciler = reconciler, __instanceMap = instanceMap, __changeBatcher = changeBatcher, @@ -196,6 +197,11 @@ function ServeSession:start() :connect() :andThen(function(serverInfo) self:setLoadingText("Loading initial data from server...") + + -- Configure sync mode based on server capabilities + self.__syncSourceOnly = serverInfo.syncSourceOnly or false + self.__changeBatcher:setSyncSourceOnly(self.__syncSourceOnly) + return self:__initialSync(serverInfo):andThen(function() self:setLoadingText("Starting sync loop...") self:__setStatus(Status.Connected, serverInfo.projectName) @@ -526,8 +532,20 @@ function ServeSession:__initialSync(serverInfo) continue end - local update = encodePatchUpdate(instance, change.id, change.changedProperties) - table.insert(inversePatch.updated, update) + local propertiesToSync = change.changedProperties + if self.__syncSourceOnly then + -- Filter to only Source property when server is in source-only mode + if propertiesToSync.Source then + propertiesToSync = { Source = propertiesToSync.Source } + else + continue + end + end + + local update = encodePatchUpdate(instance, change.id, propertiesToSync) + if update then + table.insert(inversePatch.updated, update) + end end -- Add the removed instances back to Rojo -- selene:allow(empty_if, unused_variable, empty_loop) diff --git a/src/web/api.rs b/src/web/api.rs index 2790106c..efdbf25f 100644 --- a/src/web/api.rs +++ b/src/web/api.rs @@ -95,6 +95,7 @@ impl ApiService { place_id: self.serve_session.place_id(), game_id: self.serve_session.game_id(), root_instance_id, + sync_source_only: true, }) } diff --git a/src/web/interface.rs b/src/web/interface.rs index 430f13ec..d255e1ba 100644 --- a/src/web/interface.rs +++ b/src/web/interface.rs @@ -165,6 +165,10 @@ pub struct ServerInfoResponse { pub game_id: Option, pub place_id: Option, pub root_instance_id: Ref, + /// When true, the server only supports syncing script Source property changes. + /// Other property changes will be ignored. + #[serde(default)] + pub sync_source_only: bool, } /// Response body from /api/read/{id}