Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ef3466d
initial samod
LilithSilver Dec 16, 2025
5f75e93
More Samod
LilithSilver Dec 16, 2025
fa3a135
add continue
LilithSilver Dec 16, 2025
c6d8898
add back debugs
LilithSilver Dec 16, 2025
fad8dcc
fix peer connection and cleanup
LilithSilver Dec 17, 2025
9af24fc
display connfinishreason again
LilithSilver Dec 17, 2025
9b0a330
fix unwrap bug
LilithSilver Dec 17, 2025
dd82964
adjust samod version and tracing
LilithSilver Dec 18, 2025
493ab0a
hacky project load fix
LilithSilver Dec 19, 2025
917d240
fix crashing when refreshing scenes
nikitalita Dec 20, 2025
664740d
Fix bug in scene parsing
nikitalita Dec 20, 2025
aa87d28
just initial commit
LilithSilver Dec 25, 2025
4b8fedc
Fix plugin ref
LilithSilver Dec 25, 2025
73afa32
fix broken scons
LilithSilver Dec 25, 2025
3265fd5
update paths to use public
LilithSilver Dec 25, 2025
5b62c4a
Enable default vscode config
LilithSilver Dec 25, 2025
7c9bd41
adjust comments
LilithSilver Dec 25, 2025
46c1d61
Merge branch 'samod' of silver:inkandswitch/patchwork-godot-plugin in…
LilithSilver Dec 25, 2025
7b6189d
VScode configs and server url
LilithSilver Dec 26, 2025
6811bbb
Use list as default
LilithSilver Dec 26, 2025
43cfdec
don't use default server
LilithSilver Dec 26, 2025
b7696fb
concurrency
LilithSilver Jan 7, 2026
b7b1f82
Valiant and arduous attempts at fixing the CI, there was much rejoicing
nikitalita Jan 7, 2026
27c37ef
instability fix
LilithSilver Dec 27, 2025
1d3cf48
fix SSH git clone
LilithSilver Jan 7, 2026
4d181fc
paul's mac changes
LilithSilver Jan 7, 2026
43f70a1
ensure `module_text_server_fb_enabled=yes` for godot builds
nikitalita Jan 7, 2026
c8c87ff
Merge branch 'build-system' into samod
LilithSilver Jan 8, 2026
71c4b79
Merge branch 'main' into samod
LilithSilver Jan 8, 2026
c4fa236
change server url
LilithSilver Jan 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
277 changes: 182 additions & 95 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions editor/patchwork_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -546,14 +546,26 @@ void PatchworkEditor::refresh_after_source_change() {
Main::iteration();
}

auto current_scene = EditorInterface::get_singleton()->get_edited_scene_root();

auto open_scenes = EditorInterface::get_singleton()->get_open_scenes();
for (auto &scene : open_scenes) {
if (current_scene != nullptr && scene == current_scene->get_scene_file_path()) {
continue;
}
while (is_changing_scene()) {
OS::get_singleton()->delay_usec(10000);
Main::iteration();
}
EditorInterface::get_singleton()->reload_scene_from_path(scene);
}
if (current_scene != nullptr) {
while (is_changing_scene()) {
OS::get_singleton()->delay_usec(10000);
Main::iteration();
}
EditorInterface::get_singleton()->reload_scene_from_path(current_scene->get_scene_file_path());
}
}

Callable PatchworkEditor::steal_close_current_script_tab_file_callback() {
Expand Down
5 changes: 2 additions & 3 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ automerge_0_6 = []

[dependencies]
automerge = "0.7.2"
automerge_repo = { version = "0.3.0", features = [
"tokio",
] }
autosurgeon = "0.10.1"
futures = "0.3.31"
godot = "0.4.3"
Expand Down Expand Up @@ -56,6 +53,8 @@ rlimit = "0.10.2"
tracing = "0.1.40"
tracing-appender = "0.2.2"
chrono = "0.4.31"
samod = { git="https://github.com/LilithSilver/samod.git", branch="patchwork", features = ["tokio", "threadpool"] }
rayon = "1.11.0"

[build-dependencies]
cbindgen = "^0.27"
Expand Down
5 changes: 4 additions & 1 deletion rust/src/fs/file_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::path::{PathBuf};
use std::str;
use automerge::{Automerge, ChangeHash, ObjType, ReadDoc};
use automerge::ObjId;
use automerge_repo::{DocumentId};
use samod::{DocumentId};
use ya_md5::{Md5Hasher};
use crate::helpers::doc_utils::SimpleDocReader;
use crate::helpers::utils::{ToShortForm, parse_automerge_url};
Expand Down Expand Up @@ -81,7 +81,10 @@ impl FileContent {
let scene = parse_scene(&string);
if scene.is_ok() {
return FileContent::Scene(scene.unwrap());
} else if let Err(e) = scene {
tracing::error!("Error parsing scene: {:?}", e);
}

}
FileContent::String(string)
}
Expand Down
2 changes: 1 addition & 1 deletion rust/src/helpers/branch.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use automerge::ChangeHash;
use automerge_repo::{DocHandle, DocumentId};
use samod::{DocHandle, DocumentId};
use autosurgeon::{Hydrate, Reconcile};
use std::collections::{HashMap, HashSet};

Expand Down
6 changes: 4 additions & 2 deletions rust/src/helpers/tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@ pub fn initialize_tracing() {
.with_writer(CustomStdoutWriter::custom_stdout)
.with_filter(EnvFilter::new("info")
.add_directive("patchwork_rust_core=debug".parse().unwrap())
.add_directive("automerge_repo=info".parse().unwrap()));
.add_directive("samod=info".parse().unwrap())
.add_directive("samod_core=info".parse().unwrap()));
let file_layer = tracing_subscriber::fmt::layer()
.with_line_number(true)
.with_ansi(false)
.with_writer(non_blocking_file_writer.clone())
.with_filter(EnvFilter::new("info")
.add_directive("patchwork_rust_core=trace".parse().unwrap())
.add_directive("automerge_repo=debug".parse().unwrap()));
.add_directive("samod=info".parse().unwrap())
.add_directive("samod_core=info".parse().unwrap()));
if let Err(e) = tracing_subscriber::registry()
// stdout writer
.with(stdout_layer)
Expand Down
5 changes: 3 additions & 2 deletions rust/src/helpers/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{diff::differ::ProjectDiff, helpers::{branch::BranchState, doc_utils:
use automerge::{
Automerge, Change, ChangeHash, Patch, PatchLog, ROOT, ReadDoc, transaction::{CommitOptions, Transaction}
};
use automerge_repo::{DocHandle, DocumentId};
use samod::{DocHandle, DocumentId};
use chrono::{DateTime, Local};
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -73,7 +73,7 @@ pub(crate) fn get_linked_docs_of_branch(
branch_doc_handle: &DocHandle,
) -> HashMap<String, DocumentId> {
// Collect all linked doc IDs from this branch
branch_doc_handle.with_doc(|d| {
branch_doc_handle.with_document(|d| {
let files = match d.get_obj_id(ROOT, "files") {
Some(files) => files,
None => {
Expand Down Expand Up @@ -215,6 +215,7 @@ impl From<&Change> for CommitInfo {
}
}


#[derive(Debug)]
pub struct BranchWrapper {
pub state: BranchState,
Expand Down
2 changes: 1 addition & 1 deletion rust/src/interop/godot_helpers.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::path::PathBuf;
use std::{fmt::Display};
use automerge::{ChangeHash};
use automerge_repo::{DocumentId};
use samod::{DocumentId};
use godot::meta::{ArgPassing, ByValue, GodotType, ToArg};
use godot::{prelude::*, meta::ToGodot, meta::GodotConvert};
use crate::fs::file_utils::FileContent;
Expand Down
2 changes: 1 addition & 1 deletion rust/src/interop/godot_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::project::project::{Project, GodotProjectSignal};
use automerge::ChangeHash;
use godot::classes::editor_plugin::DockSlot;
use ::safer_ffi::prelude::*;
use automerge_repo::{DocumentId};
use samod::{DocumentId};
use godot::classes::resource_loader::CacheMode;
use godot::classes::{ConfirmationDialog, Control};
use godot::classes::EditorInterface;
Expand Down
2 changes: 1 addition & 1 deletion rust/src/parser/godot_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,7 @@ pub fn parse_scene(source: &String) -> Result<GodotScene, String> {
// Check if node has a patchwork_id in metadata
let node_id_num = match heading.get("unique_id") {
Some(unique_id) => unique_id.parse::<i32>().unwrap_or(UNIQUE_SCENE_ID_UNASSIGNED),
None => return Err("Missing required 'unique_id' attribute in node section".to_string())
None => -1
};
parsed_node_ids.insert(node_id_num);

Expand Down
47 changes: 26 additions & 21 deletions rust/src/project/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use ::safer_ffi::prelude::*;
use automerge::{
ChangeHash, ObjId, ObjType, ROOT, ReadDoc
};
use automerge_repo::{DocHandle, DocumentId, PeerConnectionInfo};
use samod::{DocHandle, DocumentId, ConnectionInfo};
use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
use tracing::instrument;
use std::{cell::RefCell, collections::HashSet};
Expand Down Expand Up @@ -45,7 +45,7 @@ pub struct Project {
driver: Option<ProjectDriver>,
pub(super) driver_input_tx: UnboundedSender<InputEvent>,
driver_output_rx: UnboundedReceiver<OutputEvent>,
pub(super) sync_server_connection_info: Option<PeerConnectionInfo>,
pub(super) sync_server_connection_info: Option<ConnectionInfo>,
file_system_driver: Option<FileSystemDriver>,
project_dir: String,
is_started: bool,
Expand Down Expand Up @@ -90,7 +90,7 @@ impl Default for Project {
}

/// The default server URL used for syncing Patchwork projects. Can be overridden by user or project configuration.
const DEFAULT_SERVER_URL: &str = "24.199.97.236:8080";
const DEFAULT_SERVER_URL: &str = "24.199.97.236:8085";

/// Notifications that can be emitted via process and consumed by GodotProject, in order to trigger signals to GDScript.
pub enum GodotProjectSignal {
Expand Down Expand Up @@ -147,7 +147,7 @@ impl Project {
.and_then(|i| i.docs.get(&branch_state.doc_handle.document_id()))
.and_then(|p| p.last_acked_heads.as_ref());

let changes = branch_state.doc_handle.with_doc(|d|
let changes = branch_state.doc_handle.with_document(|d|
d.get_changes(&[])
.to_vec()
.iter()
Expand Down Expand Up @@ -258,7 +258,7 @@ impl Project {
);
println!("");
let branch_state = self.get_checked_out_branch_state().unwrap();
let heads = branch_state.doc_handle.with_doc(|d| {
let heads = branch_state.doc_handle.with_document(|d| {
d.get_heads()
});
let content = self.get_changed_file_content_between(Some(branch_state.doc_handle.document_id().clone()), branch_state.doc_handle.document_id().clone(), heads.clone(), revert_to.clone(), true);
Expand Down Expand Up @@ -306,7 +306,7 @@ impl Project {
panic!("_get_descendent_document: previous_heads is empty");
}

if branch_state.doc_handle.with_doc(|d| {
if branch_state.doc_handle.with_document(|d| {
d.get_obj_id_at(ROOT, "files", &previous_heads).is_some() &&
d.get_obj_id_at(ROOT, "files", &current_heads).is_some()
}) {
Expand All @@ -320,7 +320,7 @@ impl Project {
return None;
}
};
if other_branch_state.doc_handle.with_doc(|d| {
if other_branch_state.doc_handle.with_document(|d| {
d.get_obj_id_at(ROOT, "files", &previous_heads).is_some() &&
d.get_obj_id_at(ROOT, "files", &current_heads).is_some()
}) {
Expand All @@ -338,7 +338,7 @@ impl Project {

pub fn revert_to_heads(&mut self, to_revert_to: Vec<ChangeHash>) {
let branch_state = self.get_checked_out_branch_state().unwrap();
let heads = branch_state.doc_handle.with_doc(|d| {
let heads = branch_state.doc_handle.with_document(|d| {
d.get_heads()
});
let content = self.get_changed_file_content_between(Some(branch_state.doc_handle.document_id().clone()), branch_state.doc_handle.document_id().clone(), heads.clone(), to_revert_to.clone(), true);
Expand Down Expand Up @@ -455,7 +455,7 @@ impl Project {
curr_heads.to_short_form()
);
let (patches, old_file_set, curr_file_set) =
branch_state.doc_handle.with_doc(|d| {
branch_state.doc_handle.with_document(|d| {
let old_files_id: Option<ObjId> = d.get_obj_id_at(ROOT, "files", &previous_heads);
let curr_files_id = d.get_obj_id_at(ROOT, "files", &curr_heads);
let old_file_set = if old_files_id.is_none(){
Expand Down Expand Up @@ -521,7 +521,7 @@ impl Project {
changed_file_events.push(FileSystemEvent::FileDeleted(PathBuf::from(path)));
}

branch_state.doc_handle.with_doc(|doc|{
branch_state.doc_handle.with_document(|doc|{
let files_obj_id: ObjId = doc.get_at(ROOT, "files", &curr_heads).unwrap().unwrap().1;

for path in doc.keys_at(&files_obj_id, &curr_heads) {
Expand Down Expand Up @@ -585,7 +585,7 @@ impl Project {
fn get_linked_file(&self, doc_id: &DocumentId) -> Option<FileContent> {
self.doc_handles.get(&doc_id)
.map(|doc_handle| {
doc_handle.with_doc(|d| match d.get(ROOT, "content") {
doc_handle.with_document(|d| match d.get(ROOT, "content") {
Ok(Some((value, _))) if value.is_bytes() => {
Some(FileContent::Binary(value.into_bytes().unwrap()))
}
Expand Down Expand Up @@ -616,7 +616,7 @@ impl Project {
&HashSet::new()
};

branch_state.doc_handle.with_doc(|doc|{
branch_state.doc_handle.with_document(|doc|{
let files_obj_id: ObjId = doc.get_at(ROOT, "files", &heads).unwrap().unwrap().1;
for path in doc.keys_at(&files_obj_id, &heads) {
if filtered_paths.len() > 0 && !filtered_paths.contains(&path) {
Expand Down Expand Up @@ -757,7 +757,7 @@ impl Project {
differ.get_diff()
}

fn start_driver(&mut self) {
async fn start_driver(&mut self) {
if self.driver.is_some() {
return;
}
Expand All @@ -780,7 +780,7 @@ impl Project {
tracing::info!("Using project override for server url: {:?}", server_url);
}

let mut driver: ProjectDriver = ProjectDriver::create(storage_folder_path, server_url);
let mut driver: ProjectDriver = ProjectDriver::create(storage_folder_path, server_url).await;
let maybe_user_name: String = PatchworkConfigAccessor::get_user_value("user_name", "");
driver.spawn(
driver_input_rx,
Expand Down Expand Up @@ -875,7 +875,8 @@ impl Project {
self.checked_out_branch_state
);

self.start_driver();
// Bad practice; figure out a way to propogate this await to the UI instead
futures::executor::block_on(self.start_driver());
self.start_file_system_driver();
self.is_started = true;
// get the project path
Expand Down Expand Up @@ -956,12 +957,12 @@ impl Project {
}
}
};
if &current_doc_id == from_branch_id.as_ref().unwrap_or(&current_doc_id) && current_heads == previous_heads {
if current_doc_id == from_branch_id.as_ref().unwrap_or(&current_doc_id) && current_heads == previous_heads {
tracing::debug!("heads are the same, no changes to sync");
return Vec::new();
}
tracing::debug!("syncing branch {:?} from {}{} to {}", current_branch_state.name,
if from_branch_id.as_ref().unwrap_or(&current_doc_id) != &current_doc_id {
if from_branch_id.as_ref().unwrap_or(&current_doc_id) != current_doc_id {
format!("{} @ ", self.get_branch_name(from_branch_id.as_ref().unwrap()))
} else {
"".to_string()
Expand Down Expand Up @@ -1130,12 +1131,12 @@ impl Project {
tracing::trace!(
"NewBinaryDocHandle !!!! {} {} changes",
doc_handle.document_id(),
doc_handle.with_doc(|d| d.get_heads().len())
doc_handle.with_document(|d| d.get_heads().len())
);
}

self.doc_handles
.insert(doc_handle.document_id(), doc_handle.clone());
.insert(doc_handle.document_id().clone(), doc_handle.clone());
}
OutputEvent::BranchStateChanged {
branch_state: new_branch_state,
Expand All @@ -1158,7 +1159,7 @@ impl Project {
checking_out_new_branch = true;

self.checked_out_branch_state = CheckedOutBranchState::CheckingOut(
branch_state.doc_handle.document_id(),
branch_state.doc_handle.document_id().clone(),
prev_branch_id.clone(),
);
(Some(branch_state), cloned_prev_branch_id)
Expand Down Expand Up @@ -1186,7 +1187,7 @@ impl Project {
);

self.checked_out_branch_state = CheckedOutBranchState::CheckedOut(
active_branch_state.doc_handle.document_id(),
active_branch_state.doc_handle.document_id().clone(),
prev_branch_info,
);

Expand Down Expand Up @@ -1215,6 +1216,10 @@ impl Project {
OutputEvent::PeerConnectionInfoChanged {
peer_connection_info,
} => {
// TODO(Samod): Remove this hack
let Some(peer_connection_info) = peer_connection_info else {
continue;
};
let _info = match self
.sync_server_connection_info
.as_mut()
Expand Down
2 changes: 1 addition & 1 deletion rust/src/project/project_api.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use automerge::ChangeHash;
use automerge_repo::DocumentId;
use samod::DocumentId;

use crate::{diff::differ::ProjectDiff};

Expand Down
Loading