CSCraft banner

CSCraft

6 devlogs
46h 6m 27s

Minecraft modding in Java is painful. The API is verbose, the syntax is clunky, and you spend more time fighting boilerplate than actually building your mod. Craft# lets you write mods in C# instead - same Fabric API under the hood, but exposed th…

Minecraft modding in Java is painful. The API is verbose, the syntax is clunky, and you spend more time fighting boilerplate than actually building your mod. Craft# lets you write mods in C# instead - same Fabric API under the hood, but exposed through a clean, modern interface. Build your project and you get a .jar file ready to drop into any Minecraft instance. No Java required.

This project uses AI

I’ve used AI to help me map the functions and to fix some bugs with the compiler. Also it helped me fix some of the README - I gave it the information it needed and basically reformatted it.

Demo Repository

Loading README...

borkoaxtyt

Today I wanted to do something different so I added more version support via adding attributes and now versions from 1.20 up to the newest are supported. I also added Nbt back for some versions. I had some problems regarding the nullability as it’s a bit different and Java and you could get errors during build for things that just aren’t supported in Java. It took me some time but I tried building on every version and it worked perfectly so now I’m kind of unsure what to add in the API. I thought of making an online interpreter which I will probably vibe code as I don’t want to waste time in just making a compiler. But the main things that it will have is like built-in intellisense for the API and like restricting the usage of C# functions and implementations. The main job of the interpreter will be to make it even easier to make mods - don’t need to add attributes and you won’t see any of the files such as fabric template and others. I also updated the documentation of the API so it looks a bit cleaner now.

Attachment
0
borkoaxtyt

Finally after going through all the bugs, I fixed the detranspiler and everything works perfectly. I’m going to ship after this devlog. I started on making it so you can write mods on more versions - as of now only versions from 1,20 to 1.21 are supported. These include: 1.20, 1.20.1, 1.20.2, 1.20.3, 1.20.4, 1.20.5, 1.20.6, 1.21 and 1.21.1. It might be a bit tricky as the first time I used it, I had to find the perfect loom version and fabric version + Java version to build the project. I think I might just make it so you can do it for versions above 1.18. The versions though will take a lot of time as I will have to make attributes for every different command but I might find an easier way to do that automatically. I also started making my own reflection API and for now it’s not turning out so well. I have problems related to getting information from classes. I’m going to look at the official source code of the C# reflection API and see what I can improve. I think I’ve made really good progress in the past week and I’m going to continue doing it.. I might get my friend to make a simple mod and see what will happen as I haven’t really tested a lot of the new versions in-game. I also published the Detranspiler in nuget though I haven’t added a README - I will do that tomorrow.

Attachment
0
borkoaxtyt

Today was a really productive session for CSCraft. I spent a good chunk of time fixing bugs in the detranspiler - mostly edge cases that only show up when you throw real code at it rather than the small test mod I was using before. Things like command bodies getting eaten because the preamble stripper was too aggressive, trailing ) signs showing up as orphaned statements, and private method calls not getting PascalCase-converted.

To actually stress test it I ran it against a 3000-line Java Fabric mod, which is a lot closer to what someone would actually be trying to convert in the real world. The output was genuinely pretty good - class structure came out correct, field declarations translated cleanly, event handlers had the right parameters and populated bodies, command registrations came out with the right variants
There’s still more that could be done on the detranspiler - more pattern coverage in the method mapper for common Java patterns, better handling of helper classes, and smarter handling of for/while loops in translated bodies. But it’s at a point where it produces useful first-draft output on a real mod without requiring massive manual cleanup.

Attachment
0
borkoaxtyt

For some reason after I published the latest version of the API yesterday, I decided that today I would make a detranspiler (from Java project to C# project). Idk why but I thought that it would be a good idea to make one as it would let people just migrate their project over to the C# API. I started working on it and for now I have decent progress - It works on half the stuff and I haven’t added mappings for the things that don’t work yet. I will try to finish the things and see what will come out of it. I had many problems regarding the JSON files and just keeping the file structure bu I’ve managed to make something that is kind of okay. The detranspiler will be a different nuget package but in the same pack so people won’t have problems finding it. After I finish with the detranspiler, I think I’m gonna start to try and make my own Reflection API so I can sync it with Java’s and hopefully it will allow modders to actually make significant mods, but before that I will try to get my hands on some big minecraft mods and see whether the detranspiler works as it should. I will also add a picture of the current result of the detranspiler.

Attachment
0
borkoaxtyt

Today I tried fixing a lot of the methods and mappings in the API. It took way longer than I expected, and for some reason every time I fixed something, something else would break. Because of that I ended up rewriting parts of the transpiler just to get a clearer view of where the issues were coming from.

I managed to fix quite a few things. The scheduler was completely broken before — RunRepeating was basically just a comment and RunLater was using Thread.sleep which would’ve frozen the server. I reworked both of them properly using Fabric tick events. I also fixed enchantments since Mojang changed how registries work in 1.21.1, so now it uses the dynamic registry system instead of just outputting useless comments.

There were also issues with type resolution, especially with things like armor slot chains (like player.Helmet.GetItem()), so I added a lookup system to help the transpiler understand return types better. Particle constants were also wrong before, so I mapped them properly to strings like “minecraft:flame”. I also added proper handling for array creation since that was just throwing warnings before, and improved how McGameRule generics are handled so they don’t silently break anymore.

There are still some issues, but most of the major ones are fixed for now.

One thing that really fought back was the scoreboard API. I thought I was using a bad workaround and tried switching to the proper method, but it turns out Mojang removed it in 1.21.1. So I had to go back to the workaround anyway.

Also I took a screenshot of a java file before being built. I don’t think I need to say anything - it just looks ugly.

This is how much cleaner it looks when making it using this API:

// /kit — give starter kit to yourself
McCommand.Register(“kit”, (src) =>
{
McPlayer p = src.Player;
if (p == null) { src.SendError(“Players only!”); return; }
p.GiveItem(“examplemod:ruby_sword”, 1);
p.GiveItem(“examplemod:ruby_pickaxe”, 1);
p.GiveItem(“examplemod:ruby_helmet”, 1);
p.GiveItem(“minecraft:bread”, 32);
p.GiveEffect(“minecraft:speed”, 600, 1);
p.GiveEffect(“minecraft:haste”, 600, 1);
src.SendMessage(“Ruby kit granted!”);
});

    // /heal <target> — op only, heals a named player
    McCommand.RegisterOpWithPlayer("heal", "target", (src, target) =>
    {
        target.Heal(target.MaxHealth);
        target.ClearEffects();
        target.GiveEffect("minecraft:regeneration", 100, 1);
        target.SendMessage("You were healed by an admin.");
        src.SendMessage("Healed " + target.Name + "!");
    });

    // /spawn — teleport to world spawn
    McCommand.Register("spawn", (src) =>
    {
        McPlayer p = src.Player;
        if (p == null) return;
        McWorld w = p.World;
        McBlockPos sp = w.SpawnPos;
        p.Teleport(sp.X, sp.Y, sp.Z);
        p.PlaySound("minecraft:entity.enderman.teleport");
        src.SendMessage("Teleported to spawn!");
    });
Attachment
0
borkoaxtyt

Today I tried fixing a lot of the methods and mappers for the API. It took me a long time and I don’t know why but the more I tried fixing something, the more it broke. I rewrote some of the code for the transpiler to get a better perspective of where the errors where. I am still running into some issues but most are fixed (for now). So for today I’d say that I have done a lot of stuff but before making a new Nuget patch, I will try to have all the issues fixed and have an example mod with every function to test it out. I’m still not sure whether the automatic JSON creation will work for making recipes so I will also try to do that and see what will happen. Also I switched over to my linux laptop for now so I might also encounter some problems with the building. For tomorrow I will try to have everything ready and fixed and will hopefully start working on making the build experience better. I plan on making a page entirely for bug testing and fixing so the developing process becomes a lot smoother. I will also put a picture of a java file to show a bit of my progress. Also please don’t try out the latest versions of the API as none of them work for some reason.

Attachment
0