GRAYBOXING TOOL
Jan 16, 2026 - Solo School Project - Unity C#
Jan 16, 2026 - Solo School Project - Unity C#
The World class holds a Dictionary of Chunks whereby the key is a Vector3Int, each chunk holds a HashSet of 8x8x8 blocks
The World keeps track of which chunks to visually update and which blocks have been placed / removed
That information is passed onto WorldHistory, which allows for the user to undo / redo their work
The most inefficient way of meshing is having each cube always have 6 faces ( 12 triangles )
To improve this, we "cull" the faces that are not facing air, that is why it is called culled meshing
To further increase the performance of a mesh, greedy meshing attempts to generalize large flat areas of the mesh
Greedy meshing is statically faster but dynamically slower, meaning more overall fps but if you edit the world you might get a lag spike
The best of both worlds is to have a culled mesh for fast editing and a greedy ( optimized ) mesh for when the user decides to export
This, however, takes more computational power and that is why I off-load that work to a background thread so the tool remains smooth
☆ Externally, when the user is done with all the changes to the World class, Flush() should be called to update all the affected chunks visually.
Not only does it update the visual, but it also stores the changes via the OnNewChanges Action.Â
☆ This is how blocks are added and removed. Notice how a lot of checks are made to make sure the task is carried out successfully.Â
☆ This is how the async export is handled. Notice here how there are two methods that the main Export() chooses between. This is because the user can either export the world in pieces ( but under one mesh ) or export it as a whole.Â
I decided to implement the strategy pattern here so I could easily swap what meshing I wanted to use for the export ( culled, greedy, improving on older code ).
☆ Very similar to the culled meshing code in my Minecraft Clone, here we have the meshing utils code that is used by the aforementioned meshing strategies.
public void Setup()
{
    message = ServiceLocator<IMessageService>.Locate();
    settingsScreen.Setup();
    pauseAction = InputSystem.actions.FindAction(pauseName);
    screens = GetComponentsInChildren<Screen>(true);
    fsm.AddState(fileScreen);
    fsm.AddState(settingsScreen);
    fsm.AddState(wikiScreen);
    fsm.AddTransition(new Transition(fileScreen, settingsScreen));
    fsm.AddTransition(new Transition(fileScreen, wikiScreen));
    fsm.AddTransition(new Transition(settingsScreen, fileScreen));
    fsm.AddTransition(new Transition(settingsScreen, wikiScreen));
    fsm.AddTransition(new Transition(wikiScreen, fileScreen));
    fsm.AddTransition(new Transition(wikiScreen, settingsScreen));
}
☆ The menu works using a finite state machine ( FSM ). This is because when one screen is active, the code for others doesn't need to be run.
<--
The assignment was to create a tool that aids in the production step of a game. I thought it would be interesting to create a level editor that played like Minecraft in order to set the level of entry of level design as low as I could make it.
The project involved quite a lot of research into the world of "meshing," as its called. This went in tandem with development of my Minecraft Clone. What I'm really proud of is that when you export your world as an OBJ file, the tool off-loads this work onto another thread ( with the C# async keyword ). This means that the tool remains smooth while work is done in the background.Â