3DStreet / 3dstreet

🚲🚢🚌 Web-based 3D visualization of streets using A-Frame
https://3dstreet.app
Other
264 stars 33 forks source link

Implement autosave #801

Closed vincentfretin closed 1 month ago

vincentfretin commented 2 months ago

Autosave changes a few seconds later after the user made changes. With #704 done, all the user changes are now undoable. To know if there is any change to save, we can listen to the events entitycreate, entityclone, entityremoved, entityupdate, componentadd, componentremove.

rahulkgupta commented 1 month ago

from a product perspective, there are a couple things to consider...

  1. How often should we autosave? At what interval?
  2. What happens if theres a network failure or if the user closes the tab prior to saving?
  3. What happens if a change occurs while saving?
  4. What happens if the user is not logged in?
  5. What happens if the scene hasn't been "saved for the first time"?
  6. What about mutliplayer?

Some thoughts to the above:

  1. Offline first. The state of the scene is saved locally on the user's device (think indexedb).
  2. Syncing mechanism. Changes saved locally will be synced to the db. We can play around with delaying the sync. This is where we can handle things like multiplayer
  3. Saving can be tied to a user. We could locally save a scene but not store it on the cloud as an alt. That might be too complex. Ultimately, we should incentivize auth and sign up.
  4. If a user is authed, we can create and save a scene. Import from streetmix -> create a scene ID. new scene -> create a scene ID.
  5. Multiplayer will require exploration of things like CRDT. I will do some exploration here prior to implementation to see if it helps or if it's too complicated.
rahulkgupta commented 1 month ago

More questions:

  1. what if the user is looking at a scene with geospatial and they dont have pro? Maybe if they try to "save as" a scene with geospatial, the scene loses its geospatial.

Looking deeper in the code...A really naive and simple approach is whenever historychanged is emitted, we can do something similar as the cloudSaveHandler and put that on a debounce. This would get us a decent solution. it runs the risk of if the user closes the tab prior to the save / during function firing.

CRDTs and doing multiplayer will require a pretty major rewrite. I dont think it's necessary to pursue this at the moment.

From a phasing perspective, we could do the following:

  1. naive autosave: can fail if the user closes the browser prior to save function
  2. Local storage: save scene / maybe even history locally so that the application is offline first
  3. Multiplayer
rahulkgupta commented 1 month ago

https://github.com/3DStreet/3dstreet/pull/865

vincentfretin commented 1 month ago

Oh yes I forgot we had the historychanged event, good call.

Saving the serialized json in localStorage should be enough for now, the maximum size limit for localStorage is about 5 MB per origin in all browsers.

Multi-users edit is indeed a bit more complex to implement. There are indeed some CRDT libraries like https://github.com/yjs/yjs that we could use for this, you would also need a server with WebSocket. To avoid conflicts we should also save at the entity level, each entity required to have an id. IndexedDB and a syncing engine would be good to have offline data, I used kinto a few years ago on a project to edit collaboratively a scene each user on different parts of the scene, and when I saved, it synced again both way, and I got the changes from the other user.

kfarr commented 1 month ago

closed by https://github.com/3DStreet/3dstreet/pull/865