Developer Update - 25 November 2024

Hi folks! Thank you for your questions. We couldn’t immediately respond to questions about Soba’s technical details, so we appreciate your patience. Our team put together a small FAQ that may give you a better idea of how Soba works and why it’s different from what we previously announced:


Q: Why did you decide not to use WebAssembly (WASM)?
A: WASM was very promising initially, but as development continued, our engineers encountered several downsides that would have made it difficult for us to release Udon 2 as initially announced.

The biggest reason is that WASM would have massively increased VRChat’s memory usage. WASM’s heap and the Mono runtime increased memory usage by one gigabyte in some worlds. This would affect all players, especially in ambitious worlds or on low-end devices. We concluded that a huge memory regression is unacceptable - but there are even more reasons:

  1. Apple forbids Just-in-time compilation (JIT) on iOS. JIT is the main reason for WASM’s performance improvements, so we would have needed to invest additional development time into making WASM work on iOS - and its performance would be lower than on other platforms.
  2. The WASM runtime added enormous complexity to our code. It added edge cases that hadn’t been fixed yet, made our development process slower, and would have distracted us from adding feature requests that the community had been asking for.
  3. WASM’s memory usage problems could get worse if we add additional features in the future.

Combined, these issues made it very difficult for us to proceed with WASM. Development took much longer than initially expected, and delivering everything we announced in time was impossible. We decided to spend a small amount of time to look for alternative solutions, which quickly led us to Soba.

Compared to using WASM, Soba’s development has been very fast. We’ve carefully limited the number of initial features and reused existing code whenever possible, making Soba small and easy to work on.


Q: Will Soba’s performance be higher than Udon?
A: Yes, but not in the first release.

Our preliminary benchmarks show the potential for over a 7x speedup on math-heavy code. And we may be able to achieve even greater performance in future updates.

However, we don’t think our benchmarks are ready to share yet because Soba is still in active development. We don’t want to overpromise anything, so we’ll share benchmarks once Soba is closer to a Closed Beta.


Q: Is Soba a replacement for Udon?
A: No, it’s not a direct replacement. But it contains many improvements compared to Udon.

While developing Udon 2, we realized how many worlds depend on unspecified behavior, which would be difficult to recreate in Soba. We want to maintain backward compatibility with Udon.

However, we also use Soba as an opportunity to fix bugs and design problems in Udon that we can’t fix without breaking backward compatibility. For example, for methods callable over the network, Soba is private-by-default, and uses a new [NetworkCallable] attribute instead of adding an _ to the start of a method name to block it.


Q: Will I be able to convert my Udon scripts to Soba?
A: Yep! We’re working on it.


Q: Will Soba have generics?
A: Yes, but not in the first release. It’s on our roadmap!


Q: Will Soba have everything that was announced for Udon 2?
No, not everything. (In fact, the initial announcement contained many promises we shouldn’t have made at the time!)

However, Soba will still accomplish many of Udon 2’s overarching goals. Our goal is to be as transparent as possible, but we also want to avoid creating problems by sharing inaccurate information. We hope that Soba’s release will speak for itself, and that you’ll enjoy using it once it’s released! We’ll share more information about Soba in the coming months.

14 Likes

Glad you like it! What’s something you’d like to improve about our networking? Persistence has made some networking tasks much easier, such as having a single script for every player.

Yes! Soba will be faster than Udon, though the initial release might be slower. We can share benchmarks one Soba is closer to completion.

The experience will be similar, though we’re making small improvements or fixing inconsistencies in VRChat’s API along the way.

Absolutely! Most notably, Soba has a much lower RAM requirement than what we announced in Udon 2. And our development process has been pretty fast, too!

We appreciate your patience! It’s taken us longer than usual to answer questions this week, but we’re glad we finally get to share more details about Soba and its development history. Thank you for your feedback!

Generics would be awesome! We’d like to work on this feature after Soba’s initial release, instead of delaying the release further.

That’s already possible! World creators can make their own custom stores inside their worlds, even without our “world stores” feature.

I think it would be cool for us to work on better store prefabs for creators. Creating an in-game store takes time, and the CE is still quite new.

How do you feel about our roadmap? We put more effort this year into sharing our plans, and we released a lot of highly requested features for world creators (Unity 2022, exposing APIs, world stores, Persistence, etc.)

6 Likes

On the topic of one-time purchases launching, are there plans to get credits purchases working on mobile soon?
I have leftover cash sitting in my google play balance waiting to be spent on credits but this isn’t possible yet haha

Ooo, that would be lovely, I’m in the same situation, haha.

Please feel free to suggest it here: Creator Economy | VRChat

Will Soba support coroutines or some form of task delaying that gives us more control compared to SendCustomEventDelayed (eg. UniTask)?

1 Like

Already got one up a long time ago!

1 Like

WASM’s heap and the Mono runtime increased memory usage by one gigabyte in some worlds.

Like existing worlds? Is this using the backwards compatibility? Did you make any attempt to understand how memory usage went up by 1GB? This doesn’t sound right at all. Are you sure there wasn’t some memory leak here? This should be something you look at and can debug in a day or few, not something you pivot off of the whole project for. There is a heap snapshot tool in Mono that should work for debugging this FWIW, not that it’s very helpful now HeapShot | Mono

so we would have needed to invest additional development time into making WASM work on iOS - and its performance would be lower than on other platforms.

This is wrong, it’s a straightforward set of API calls in the Rust APIs that your engineer is supposedly skilled with to precompile it to avoid the JIT. Engine in wasmtime - Rust Most popular Wasm VMs have some form of precompiled wasm modules
It does not have degraded performance

edit: To elaborate, wasmtime of course doesn’t have iOS support – at least not yet and it just seems to be some build target changes as Cranelift already supports aarch64-apple-darwin. Wasmer is what you’d probably want to use for that. I could see confusion arising since Wasmer recently announced iOS support by way of an interpreter. This is a more ‘complete’ support where you can dynamically load new Wasm. However this is not needed for Blazor to function so you can use the precompiled modules and cross-compilation, which have been in Wasmer since 2.1. Here are some relevant posts about this feature.

Wasmer has since updated their APIs a bit, the dylib engine mentioned in their iOS headless sample has been removed and merged into their “universal engine”, as a result the iOS sample does not work out of the box since it hasn’t been updated. A basic working example of getting a precompiled module of an iOS build can be found here. This was thrown together combining the cross compilation example with the target triple from the iOS example, along with the serialization of the module from their headless example.

This was a well-known thing, I made sure of it because it was the #1 concern of VRC before I even pitched Udon 2.

While developing Udon 2, we realized how many worlds depend on unspecified behavior, which would be difficult to recreate in Soba. We want to maintain backward compatibility with Udon.

Soba was not needed for this, you could’ve just left old Udon compatibility as you are already if your engineers didn’t understand the implicit behavior.

The WASM runtime added enormous complexity to our code. It added edge cases that hadn’t been fixed yet, made our development process slower, and would have distracted us from adding feature requests that the community had been asking for.

Instead you decided to spend years of working on slowly approaching C# with a bunch of inherent jank and bugs. Of course all the while building up a VM that you depend on 1 person to maintain as opposed to being able to benifit from the Mono team’s work over 20 years.

So basically what I’m reading is you ran some profiles in worlds, didn’t make effort to understand why the heap size was so large, and pivoted to another project entirely because you didn’t know how to fix issues.

Compared to using WASM, Soba’s development has been very fast. We’ve carefully limited the number of initial features and reused existing code whenever possible, making Soba small and easy to work on.

Of course it’s fast to develop, it’s reimplementing Udon but slightly different with a few new features. You’d likely get most of the way to what Soba is with a few features and changes to Udon.

But hey, credit where credit’s due you posted the issues even if some aren’t valid and others are dubious at best, only took most of the creator community asking why you are making a big decision that directly impacts them without any actual info.

(In fact, the initial announcement contained many promises we shouldn’t have made at the time!)

edit: going to add here, VRC likes to say “oh no we shouldn’t have communicated this thing now people’s hopes are up.” This is not the problem. The problem is that VRC always manages to cancel and delay major projects for years. It’s pretty much never a communication problem when VRC deflects it as “we shouldn’t have shared this” it’s a delivery problem.

edit: Noting here as I said below, I understand this overall to some degree of “better the devil you know.” If you are not confident in shipping Udon 2, that sucks but makes some sense. However, I’d really rather you didn’t represent it as “we found fundamental show-stopping problems in these software packages that have been widely used for many years-to-decades.” Udon 2 was ultimately just glue between these packages with some handling for fast Unity-specialized marshaling.

24 Likes

Yeah of course. But I meant something that is unified and by VRChat. So it always looks the same but the products are different, we have VR so it’s a unique opportunity. Maybe the colors could change based on the product/thumbnail. Just something very simple. But would love that compared to menu, not that I’m gonna be one to spend haha.

Yes, a unified in-game store would be awesome!

Currently, it’s somewhat difficult to have an in-game store that automatically updates, so it requires creators to set up things manually…

Here are some of the prefabs we’ve already made: Example Prefabs | VRChat Creation

For networking I’m still early enough in my world creation journey that I’ve yet to run into networking problems I’m convinced there are no answers to, but I would like to ask one thing I’ve never seen a response on:

Is the ~8-11kb/s upload data limit something that can be improved? Is it an artificial limitation put in place for the sake of your server infrastructure? Or is that already a reasonable amount of bandwidth and asking for more is unreasonable?

Also for a bonus big ask that would probably be impossible anytime soon: I think it’d be cool to have server-side game code in worlds.

1 Like

like WASM? generics? more performance to allow complex worlds?
or you mean more vrc+ features to pollute visual space of everyone else

I think most of advanced creators would love a more low level access to networking with being able to just manually send data to selected players/all. Currently everyone needs to deal with weird workarounds of listening for deserialization or setting data fields separately to then call an event making the whole process 10x more complex than needed. Where half of development time goes to fight against udon and not using it.
Where often people give up on doing stuff correctly and just sync stuff using strings, jsons and huge arrays as making actual data packets is too annoying.
You made a system that works great for tracking random data like toggles and points with no effort required, but no good system to actually talk between clients for game development.
Not having the unreasonably high delay between players would be amazing too, as not sure if anyone ever seen other game where 200 ping causes 2 second delays between what people see. As that just makes a lot games not physically possible
And ofc the extreme rate limiting for anything network related, also making many games just physically impossible - but you usually hit the udon performance limits first I guess.

But who cares? It can still work without JIT, and still faster than udon. Is there any benchmark showing it somehow being even slower than other solutions? As I don’t even understand why is this an argument, because one platform will not benefit as much as other then all platforms must suck? From previous posts it was also clear that JIT was not even planned for the initial release, and was just planned to be added later, so I’m really lost what this has to do with anything.

I hope that this x7 figure is at least true, for actual real calculations… but i for sure have near 0 trust in that after everything that vrchat failed to deliver. Probably its 7x faster if the only thing you do is try to sum numbers from array or some other extremely simplified and unrealistic case.

well, i don’t think that will surprise anyone, simple and bad solution with limited scalability was quick and easy to do, shocking.

I guess now its official written down stance of vrchat team, to always choose the simplest&fastest to develop solution over anything else.

11 Likes

Classic Apple L

I bet you guys just going to add value-typed primitives and operations with them, to avoid boxing, but it’s still will be slow. Udon is still dozens…hundreds times slower than native code, and x7 better than nothing, but not promising, tbh.

I would say few things without thinking deep:

  • vrc object sync on physical objects are vulnerable (why edge spellcheck ties to change this to Vernabelle?) to hacks and crashes, it has no sanity checks and limits, for years, so it’s useless for large/popular worlds. As I know, hackers can simply tp owning object to large coords, and then instantly move to opposite large coords, causing unity’s physics engine to go insane, idk how true is it. So, we have to use or invent custom syncing scripts, increasing udon overhead.
  • continues sync just sucks rn, interpolation very rough and imprecise, it jitters, cannot always rely on and have to use manual with custom interpolation
  • a way to check how much is network loaded. you may check if it IsClogged, but it often too late when it already is. need a way to see load to avoid unnecessary serializations.
  • ability to set priorities (dynamically) to the objects/scripts so if network clogged, it’s ok for some scripts to be laggy, to yield resources to more important scripts.
  • ability to call RPCs with arguments. Currently we have to make syncable variables for arguments and call the newtwork event. And most annoying we can’t just do it because only owner can alter variables, so only owner can make “seudo-rpc” calls. Also, at least year ago when I tested one thing, if networking is clogged or network connection is simply unstable, variables can desync from network call: network event might come earlier than variables. so, we need to bring on deserialization here, which increases complexity.

so, when to expect open beta?

Isn’t CE available not for everyone and gatekept? I mean sellers.

tbh you guys should think about it, why there is so many “unspecified behavior” and why creators have to rely on it.

Still waiting for custom world controls in QM and MM wings… :smiling_face_with_tear: its been… 4 years?

4 Likes

No udon 2 is honestly such horrible regression for no legitimate reason. The few reasons given have been easily disproven, no sane dev would ever think anything taking 1 gigabyte of heap, is working as intended. Clearly no effort was put into understanding Merlin’s codebase.

The worst thing is that this isnt the first time VRChat has done a major regression hurting the community at large, for no legitimate reason; Opting to make up excuses after the fact.

The loss of UDon 2 will likely be the 2nd biggest loss for the community, after open source modding was killed by EAC.

In both cases VRChat had the oppertunity to reach out to involved community members asking for assistance, and decided instead to nuke everything.

7 Likes

Also, Im not WASM expert,
but isn’t it is possible to compile WASM to native binaries w/o JIT?
So, JIT can be dropped to save resources and ready per-platform binaries loaded in-world?
Binaries might be complied server side by vrc, for security reasons?

I believe JIT can cause large ram usage, but I also believe JIT can be avoided. We would like to see fast-as-fuck jit-optimized native code, but just without jit is also good, we are not making stock trading computers or air defence systems here :person_shrugging: so, some performance might be sacrificed to save ram?

Now that you are adding SOBA, can you just remove Udonsharp from the SDK so it can be open source again and @Merlin can continue to improve it? I am sure everyone would like it to be external along side ClientSim

Edit: oops I didn’t mean to reply to you^

3 Likes

Yes precompiling modules is something used for performance and removing the JIT overhead on platforms even without iOS restrictions. Udon 2 was using Mono’s interpreter to interpret CIL so it was just 1 wasm blob that VRC could precompile and use for all worlds. If they wanted to look at using Mono’s AOT then they’d need to have different wasm for each world, but that’s also something that can fall back gracefully on iOS to just the Mono interpreter.

3 Likes

Yea, I remember back in 2020 (?) when Udon was just about to be born, somewhere on Canny I was thinking about it:
Creator’s C# code can be almost normally compiled into CIL assemblies, checked for valid calls (method references, type references, etc) ahead of time, and then simply loaded and executed at run time. VRC was run by Mono, and I wasn’t aware about upcoming IL2CPP at that moment, so user-code assumed to be like equal to vrc’s in terms of performance.

This approach feels simply, maybe there is a rocks somewhere underwater, but it’s amazingly sad that this idea still actual and we are still there.

Loading C# directly in Unity doesn’t work with IL2CPP and has its own set of concerns with sandboxing, this is actually what VRC used for several official worlds for several years ~pre-2019 before they switched to IL2CPP.

2 Likes

And yea.
Everyone talking about Generics, but why no one talking about Exceptions?
There are still some methods that can throw Exceptions
and there are still problems like this exits :point_down:


Exceptions are important part of C# syntax and it’s tough to avoid them completely, there is also a lot of caveats.

At least it can be implemented in some wacky way in theory, like lua-styled (result, error) pairs and then emulated at UdonSharp/SobaSharp compiler-level, but still… doesn’t feels good w/o native support.

1 Like

Is it possible to rehire merlin or at least reach out to them? They seem very knowledgeable and such a great asset to the team. You should take their and everyone’s feedback to heart. You may want to be more amicable and learn from their work.

11 Likes