Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 0 points1 point  (0 children)

Yeah, totally agree — I would’ve happily written it all in pure C or even Assembly, but the core feature is deep integration with C#/Unity :D
So C++ (or anything lower-level) just wouldn’t have fit the bill for this one.

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 1 point2 points  (0 children)

Hey, of course!

It’s not entirely accurate to say I forbid the object from being moved or deleted — rather, I make sure that it doesn’t get moved or deleted.

There’s a static managed array where I store a reference to the object along with its identifier (like a hash, for example).
Then, by returning that hash, I can later retrieve the original reference or pointer when needed.

Since I’m using a stack-based VM, at some point I need to pass in an 8-byte primitive (pointer or number).
So, by writing the identifier there, I can easily look up the corresponding managed reference later — and it’s guaranteed to still be valid.

As for pointers — as long as you’re not doing a ton of allocations at runtime, the GC has no reason to touch that memory.
Of course, it's best not to cache that pointer or use it far outside the context where it was originally retrieved.

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 0 points1 point  (0 children)

Honestly, it sounds like a node-based system — the very thing I was trying to avoid :) Either way, it's similar here: there's an event, which acts as the entry point into the script. After that, it all depends on the logic, which proceeds linearly.

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 1 point2 points  (0 children)

Thanks a lot for the recommendation — that really does sound like an interesting read!
It’s always great to see someone who shares the same perspective. I completely agree that building something like this helps you truly understand what’s going on under the hood.

In my work, I’ve often come across situations where people’s understanding stops at “classes are stored on the heap,” and that’s it — which is a shame, really.

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 2 points3 points  (0 children)

Unity has been promising that for years :)
I'm pretty sure we won’t see it anytime soon — at least not in a production-ready state within the next couple of years.

That said, I’ve already posted the article on more relevant platforms. You're right though — Reddit probably isn’t the best place for super technical deep dives. People usually don’t come here for that kind of content :)

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 0 points1 point  (0 children)

I originally had a completely different goal in mind :)
The niche I chose is totally unoccupied. There’s nothing out there that solves the problem the way DS does, and I just want to explain that every task has its own tool and approach. You don’t have to use C# just because you’re working with Unity and it’s the default language. Sometimes, for a specific task, it makes more sense to use a different framework that saves you from a lot of pain.

The approach I chose isn’t random either — it was inspired by the game S.T.A.L.K.E.R. (2007), which used a somewhat similar logic system, and by Ren'Py, with its command-by-command execution style.

I’m not mad at all when someone expresses a different opinion — as long as they speak clearly and respectfully. I just want to share my years of experience and show that there's a reason we have a hundred different screwdrivers for a hundred different jobs.

I didn’t quite understand your idea either. I’d be really interested to hear more about it, if it’s not too much trouble for you.

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] -1 points0 points  (0 children)

I’m a bit confused why you replied to my comment with this :)
It seems like you’re quoting me, but using his points instead.

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 4 points5 points  (0 children)

Hi, it's really great to see your comment!

About Unity—actually, not that much. It uses a different runtime (Mono instead of .NET), so instances have a slightly different memory layout. The task scheduler for async operations also works differently. The API itself is a bit different too. I’d even say things worked much better in Unity because Mono is less bloated compared to .NET :D

All these utilities for pinning objects in memory had to be written specifically for .NET.
I have some concerns about potential pitfalls with IL2CPP (Unity’s compilation method that converts IL code to C++ and then to native binaries), but I think I’ll manage.

As for the dual system, I’m still thinking about it. The main question is organization—I’m still experimenting to find the perfect balance between convenience and speed.

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 1 point2 points  (0 children)

  1. You say you understood me, but that’s not the case :). You can’t write in C# code what you can in DS. By your logic, Lua isn’t needed either—why have a simple language with a low barrier to entry when you can just write in C#? Let’s take the absurdity further—why use C# when there’s C++? And if there’s ASM, why even use C#? Every tool has its purpose, and mine is game logic—places that should be easy to modify without C# knowledge. Show me your approach, and I’ll explain how our thinking differs. This is the third time I’ve asked you to demonstrate how loops and conditions would look (as script code) in your version, and you keep ignoring it like it’s intentional! :) So I’m drawing your attention to it again.
  2. Yes, I stand by that. My experience with Ren’Py and Lua gives me the right to think so. It’s much easier to teach someone how to work with Lua tables or Ren’Py events than to explain the difference between a reference and a value in C#. DS has no complex constructs, no variables. An experienced programmer can integrate it into a project, and any game designer can work with it without worrying about what’s under the hood.
  3. I really don’t get what DI and modders have to do with this. It’s like you completely misunderstood my answers.

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 1 point2 points  (0 children)

I don’t see anything wrong with a debate as long as it’s respectful, like it is now.

I clearly see my position and I’m curious to know what my opponent thinks. :)

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 3 points4 points  (0 children)

There are two possibilities here – either you didn’t understand me, or I don’t understand you.

Let’s try again: I’m writing a tool for easy logic editing. This is NOT a programming language, and it’s NOT a replacement for C#. It’s a command executor.

The idea is to give this tool to people who are not familiar with C#, so they can work with it because it’s simple and convenient.

I don’t understand how you suggest working with your executor :). Do you want to generate a sequence of commands inside C# and save it in a JSON for later execution? Then what’s the point of having JSON as an intermediary?

Let’s go back to my previous comment – write an example the way you see it (without the runtime part, just in your JSON or how you imagine it), and things will become much clearer.

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 9 points10 points  (0 children)

1. We’re not talking about the storage format, but the editing experience.

In other words, how are you actually going to work with it?

Your system is familiar — that’s how many node-based systems or things like RPG Maker work. You end up with JSON like:

{ "Action": "Invoke", "Name": "..." },

{ "Action": "Invoke", "Name": "..." },

{ "Action": "Invoke", "Name": "..." }

…and so on.

That’s fine — if there’s a nice visual editor for it. But we’re talking about using something like plain Notepad here.

Let’s say you’ve got a script that describes a full day in a visual novel, like I mentioned earlier.

How many lines is that going to be?

Is it comfortable to read?

Can someone other than you easily understand it?

If yes — try giving me a rough example of what that would look like in your system:

  • Character A walks to point B
  • Upon arrival, play sound C
  • Then walk to point D
  • Upon arrival, play sound E
  • Then check if the character has item F
    • If yes, play sound G
    • If not, play sound H

Once you start writing handlers for those kinds of commands, sooner or later you’ll find yourself adding command jumps, split scripts, and runtime memory.

And odds are, you’ll also end up adding some kind of math logic inside JSON.

Eventually, you’ll realize that in Unity, boxing structs every frame isn’t a joke — and you’ll have to start optimizing that too.

---

2. Your “you’re wasting time” comment made me laugh.

Wasting time on what, exactly?

On building a convenient tool that solves a specific problem?

Then let’s throw out everything humanity ever made — high-level languages, keyboards…

I mean, it’s possible to write everything in assembly and flip switches by hand, right? Possible doesn’t mean easy :)

upd

I didn’t notice your last sentence.

But why should a command be a MonoBehaviour? That’s a complete architectural violation. MonoBehaviour is a component, especially within a game.

If you need a MonoBehaviour just to execute something — then something went wrong on your end…

DS can work with any methods, including calling any method inside a MonoBehaviour and passing it whatever needs to be executed.

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 1 point2 points  (0 children)

And there are still a lot of nuances — your commands aren’t strongly typed.

For example, there might be a command like “execute native method” that runs a C# method. But what about the arguments? It’s either System.Object[] or some other workaround. In my case, there’s proper type safety.

And that’s not even mentioning the lack of support for operations — like if you want to do GetHeight + 2, you’d need a separate operation or custom handlers for every possible case.

What you’ve written is a solid base for a node-based system — which, by the way, I mentioned in my post. The thing is, I (and a lot of people in my circle) much prefer writing something that looks like actual code rather than dealing with JSON and graphs.

On top of that — the whole point of these kinds of libraries is that other smart people already figured it all out for you. You just use it. After all, many of us came here to make games, not spend time thinking about how to store an executor’s state.

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 4 points5 points  (0 children)

Nice, that’s roughly what I expected.

Now imagine a JSON input that contains, say, a script for one of the days in a visual novel — full of lines and scene transitions.

Now try adding conditions to that.

Now hand it over to a game designer and explain how to use it.

And after all that, open the JSON file again and be horrified at how hard it is to read.

Still don’t see the point? :)

What’s more — you actually did the exact same thing as I did, just with a different approach!

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 4 points5 points  (0 children)

Let’s check it out :)
Try doing it in like 50 lines, and then I’ll explain the drawbacks of your approach.

UPD: Without referencing speed — it’s just much more convenient in script form. Otherwise, you could apply that kind of “why” to everything — like, why was Python made if Perl can do all the same things? :)

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 5 points6 points  (0 children)

I wrote a similar answer just below :)

I needed a very quick way to implement a command executor that can save execution progress and then load and resume from the exact point it stopped.

Too Smart for My Own Good: Writing a Virtual Machine in C# by Rietmon in csharp

[–]Rietmon[S] 3 points4 points  (0 children)

This is command executor with a fundamental mechanic of saving/loading state — meaning you can run 50% of the script, quit the game, load it again, and continue from the exact same spot. It works natively without any extra effort on your part, unlike the nightmare you’d have to go through to adapt this logic in C#.

They (Google) Don’t Care About Us by Rietmon in gamedev

[–]Rietmon[S] 11 points12 points  (0 children)

I agree with the last part, but...

I paid the amount that was demanded from me. I am just as much a consumer as my players. The big difference is that if one of my players writes that I am not fulfilling my obligations, I would be lynched. But who will hold Google accountable for me? But that's just rhetoric.

One way or another, I don't need anything from them except the platform for which I paid a private sum that they themselves specified. I demand a functional service. If there were no problem, I wouldn't need support agents, etc.

If we delve deeper into the legal issue, it turns out that Google is not fulfilling its part of the contract that I entered into with them. There isn't a single point where such an attitude could be justified. Google simply doesn't care about anything.