You are browsing as a guest. Sign up (or log in) to start making projects!

BetterClient

@BetterClient

Joined May 31st, 2026

  • 43Devlogs
  • 3Projects
  • 0Ships
  • 0Votes
#1 java glazer in hc
Open comments for this post

4h 17m 55s logged

I added vulkanmod support for all supported versions above 1.21.4, it uses the same backend as the 26.2 vulkan renderer but has some extra handling for vulkanmod

0
0
6
Open comments for this post

4h 0m 52s logged

Added Vulkan support!

This was pretty hard because skiko does not come with vulkan support by default.
However, there is a pull request that adds vulkan support.

So I created git submodules for skia and skiko, made a setup script that automatically applies the vulkan patches, builds and publishes to maven local.

Then I had to fight with a lot of issues(some of them I couldn’t even debug because it was happening in native code), but I got it working :thumbs-up:

0
0
5
Open comments for this post

4h 13m 17s logged

Even more abstractions please

Added generics support, which allows the user to define generic functions/structs that apply with every type, for example:

warp <T> void forEach(T[] a, (T) -> void action) {
    for(T t in a) {
        action(t);
    }
}

Depending on what type you used to call this, a new version of forEach gets generated, if you called it with an integer:

warp void forEach@int(int[] a, (int) -> void action) {
    for(int t in a) {
        action(t);
    }
}

Of course I also allow this on structs:

struct Triangle<Num>(Num x1, Num y1, Num x2, Num y2, Num x3, Num y3);

Also did some small changes:

  • Added an FPS counter to my test code
  • Better optimizations that actually detect not(not(x))
  • Optimized triangle::fill even more (+2 fps)
  • Made DynamicDispatchHandler actually use the apply return properly (it was always returning true)
0
0
8
Open comments for this post

2h 38m 10s logged

More abstractions please!

Added dynamic function dispatch which allows for functions to take in
other functions as arguments, of course, this isn’t possible at all in
normal scratch, so actually FunctionLiteral gets turned into an
integer and a custom dispatch function gets created for every function
literal’s signature which allows for a binary search to call the actual
function

Also made HeapConversion reuse stack slots instead of allocating one
for every variable(mostly by AI)

1
0
13
Open comments for this post

1h 32m 55s logged

Refactored the entire type system to use a sealed interface instead of an unsafe single class

Nothing much to say, this doesn’t affect the input code or the output project, I did just cleanup

0
0
8
Open comments for this post

50m 50s logged

Did more syntax improvements

Added ++ and – support:
index++;

Added type inference support:

auto a = Triangle(5, 15, 60, -120, 240, 67); //type automatically becomes Triangle
auto a = func(); //type automatically becomes the return type of func
0
0
8
Open comments for this post

2h 22m 40s logged

Scratcher is at 100 commits! (Now 104 cause all of these refactors are different commits)
Completely refactored all translation steps to use the ASTVisitor.
Also did type resolving cleanup.

Function Reachability: Went from 117 to 32 lines
Function expression lowering: Went from 439 to 293 lines
Re Parse Local Variables: Went from 34 to 27 lines
Remove Empty Allocations: Went from 97 to 79 lines

ConvertToHeapAccess: Biggest refactor of this whole devlog, went from 500 lines to 418, split into 5 files

0
0
11
Open comments for this post

3h 13m 36s logged

Fixed a lot of bugs with when expressions, also got deepseek to fix some of them

Added If expressions, which allow using if statements inside other expressions, for example, here is some previously invalid code that is now valid:

int max = if (a > b) a else b;
str  message = if (score >= 90) {
    looks::say("something");
    "You win!"
} else {
    looks::say("something");
    "You lose :("
}

 triangles[15] = Triangle(
        utils::random(-240, 240),
        utils::random(-180, 180),
        utils::random(-240, 240),
        utils::random(-180, 180),
        utils::random(-240, 240),
        if(mode == TriangleRenderMode.OFF) {
            5
        } else {
            triangles[14].y3
        }
    );

These still get lowered properly and just look like normal if statements in the final scratch code

0
0
7
Open comments for this post

3h 19m 44s logged

Added more syntax improvements!

Else if: Added support for else if, which replaces big blocks

//Before:
if(triangles[14].y1 >= 15) {
        looks::say(">=15");
    } else {
    if(triangles[14].y2 >= 155) {
        looks::say("<=15");
    } else {
        looks::say("Both false!");
    }
}
//After:
if(triangles[14].y1 >= 15) {
        looks::say(">=15");
    } else if(triangles[14].y2 >= 155) {
        looks::say("<=15");
    } else {
        looks::say("Both false!");
    }

Compound assignment: Added support for compound assignment

//Before:
triangles[15].y3 = triangles[15].y3 + 5;
//After:
triangles[15].y3 += 5;

Enums: Added support for enums, which are just fancy integer wrappers

enum TriangleRenderMode(OFF, RENDER, ITHINK);

TriangleRenderMode mode = TriangleRenderMode.OFF;

When: Added support for when expressions/statements that allow for matching a subject:

//Before:
if(answer == "off") {
    mode = TriangleRenderMode.OFF;
} else if(answer == "render") {
    mode = TriangleRenderMode.RENDER;
} else {
    mode = TriangleRenderMode.ITHINK;
    looks::say("If thinking is your power, what are you without it?");
    return;
}
//After:
TriangleRenderMode mode = when(answer) {
    "off" -> TriangleRenderMode.OFF
    "render" -> TriangleRenderMode.RENDER
    else -> {
        looks::say("If thinking is your power, what are you without it?");

        TriangleRenderMode.ITHINK;
    }
};
0
0
7
Open comments for this post

2h 39m 17s logged

Tried to do turbowarp only return optimization, wasn’t able to make it very good… reverted it

Improved the structure of CompilationConstants
Added string::split and string::substring
Made some of the list functions inlined (itemAt, clear, length)

1
0
12
Open comments for this post

1h 16m 3s logged

Made the garbage collector treat top level variables as roots, this prevents top level variables from getting freed

I added 2 modes to this

  • Reflect: This uses a hacked block to read the variables by name and reduce script size if theres a lot of variables(this doesn’t render properly inside the editor but it works)
  • NoReflect: Get all the top level variables at compile time and mark them one by one
0
0
12
Open comments for this post

7h 40m 41s logged

Garbage collection

Added a mark and sweep garbage collector to my language, it walks the roots, marks every used object, then frees all unused objects!

Most impressive part of this(in my opinion) is that most of the garbage collector is actually written in my language

Misc

  • The garbage collector gets called automatically every 1 second, but you can turn it off (CompilationConstants.AUTOMATIC_GC)
  • If you want to manage memory manually, you can turn off the garbage collector entirely (CompilationConstants.MANUAL_MEMORY)
1
0
21
Open comments for this post

40m 6s logged

Added more compiler sugar for lists:
list[index] replaces list::itemAt(list, index)

list[index] = ...; replaces list::replace(list, item, index)

for(type name in list) {} replaces

int len = list::length(list);
int i = 0;
while (i < len) {
    type name = list::itemAt(list, i);

    i = i + 1;
}

(i am not proud of the shitcode that was used to get for(type name in list) working)

0
0
8
Open comments for this post

1h 16m 56s logged

Made “PromoteToGlobals” which is a more powerful version of OptimizeToGlobals which allows for recursive functions to have their locals turned into globals aswell

This is something called liveness analysis, the compiler looks at the code paths and decides at which points a variable is “live”, which means it can’t get overwritten by a recursive call
Example:

warp int fib(int n) {
    return 0 if n <= 0;
    return 1 if n == 1;
    if (n == 2) {
        int b = n * 2;
        return otherFunc(b);
    }
    return fib(n - 1) + fib(n - 2);
}

In this function the “b” variable can be turned into a global because it cannot get overwritten by a recursive call, its used too early for that to happen

0
0
3
Open comments for this post

1h 34m logged

Did some compiler testing
Fixed function inlining bugs
Fixed a single use assignment bug
Created a triangle library that allows for triangle rendering using the pen

0
0
6
Open comments for this post

1h 42m 51s logged

Borrowed the “return expr if(cond)” syntax from ruby
Implemented Tail call optimization which optimizes away recursion on tail calls

Example:
Before:

str count(int amount) {
    return "Done!" if amount == 1;
    return count(amount - 1);
}

After:

str count(int amount) {
    int tco@argument@amount = amount;
    while (true) {
        if (tco@argument@amount == 1) return "Done !";
        tco@argument@amount = tco@argument@amount - 1;
    }
}
0
0
6
Loading more…

Followers

Loading…