A mod for 1.12.2+ by Cadiboo that creates smooth terrain in Minecraft.
Website
CurseForge Page
Note: NoCubes is not feature complete and is still very much in development.
How (technical)
See also the project's TODO list, Trello board and TV Show
Visuals
This feature works regardless of if the server has the mod installed or not.
Here's how Minecraft's rendering system works:
- Minecraft renders 16x16x16 block sized ‘render chunks’ of your world
- Building the visual data for the entire chunk each frame would be inefficient so the visual data is built once when the chunk is loaded and only rebuilt when it changes (i.e. a block in the chunk changes). The render data for each visible chunk is drawn to the screen every frame (but not recalculated each frame)
- To build this render data Minecraft’s engine allocates some memory for this render data and then goes through (iterates) every block in the 16x16x16 area, gets the model for the block (which contains all the faces and textures to render), calculates light for the block, calculates colouring for the block and then puts this data for each face into the chunk render data it is building
Here's where NoCubes comes in:
Collisions
This feature only works when both the client and server have NoCubes installed.
NoCubes changes Minecraft's terrain collisions to be smooth too (i.e. you can walk on the smooth terrain, rather than on the original cubes).
Here's how Minecraft's rendering system works:
- Whenever you walk on terrain, Minecraft looks at the nearby blocks
- For each block the engine gets its collision shape
- If the player is inside the shape, it pushes the player out
NoCubes changes the shape that the collision system sees for each block:
- For each nearby block, NoCubes redirects Minecraft's collision system's request for the block's collision shape to NoCubes' collision code
- NoCubes' collision code then runs the mesh generator (Surface Nets by default) on that block and the surrounding blocks to get a list of mesh faces
- It then turns each one of these mesh faces into shapes and gives them back to Minecraft's collision engine
This approach is wasteful because the mesh generator is being called for the same area multiple times rather than once for the whole nearby area. Work is being done to fix this.
Meshing
Reading the above you might've started wondering "What is a mesh generator?".
Mesh generators (aka isosurface extractors) are the underlying technology that makes NoCubes work.
A mesh generator is an algorithm (NoCubes supports multiple different ones) that takes a field (aka area) of voxels (aka cubes/blocks) and turns them into faces (quads/squares or triangles).
Here are some links:
Isosurface extraction isn't the only way of procedurally generating a mesh though, Wave Function Collapse is another very interesting approach that gives artists much more control over the final product:
Setting up a development environment (using IntelliJ)
- Clone/download this repo
- Open NoCubes/build.gradle in IntelliJ and select 'Open as Gradle Project'
- Go to the gradle sidebar on the right and click the 🔄 "Reload All Gradle Projects" icon
- Go to the gradle sidebar on the right and select "🐘 NoCubes > Tasks > forgegradle runs > genIntellijRuns" and double click it to run it (may have to rerun it multiple times, it often fails to download assets)
- Go to the run configurations dropdown in the right of the top 'sidebar' and select 'runClient'
- Clicking the 🕷 "Debug 'runClient'" button will start Minecraft with NoCubes running
OptiFine compatibility
OptiFine is a bit hard to work with
To get it running in your development environment:
- Download the OptiFine version that you want from optifine.net
- Download OptiFine dev tweaker from GitHub
- Put both jar files into
NoCubes/run/mods/
- Run the game and OptiFine & Shaders will load
To be able to also compile against OptiFine (do the above steps first):
- You must have set up NoCubes and had gradle install and deobfuscate Minecraft first
- Make sure that you have Minecraft for the version you're running NoCubes on
If you don't, just open the minecraft launcher, select the right version and hit 'Play'.
The launcher will download everything and you can just quit the game when it starts.
To find the version of Minecraft that NoCubes is being built against look in gradle.properties
.
- Download OptiFineDeobf from GitHub
- Run the OptiFine jar in
NoCubes/run/mods/
and select 'Extract', put the resulting extracted jar somewhere outside the mods
folder
- Run OptiFineDeobf, select the extracted OptiFine jar that you just created and select the
NoCubes
folder for the project folder
- Select a mappings file that maps from SRG to MCP/official (don't use obf -> MCP mappings)
- Select 'Make Public' and 'Forge Dev jar' then click 'Deobf'
- Put the deobfuscated OptiFine jar into
NoCubes/libs/
- Refresh gradle in your IDE and you should be able to compile against OptiFine's classes (and running OptiFine still works as it did before)
Note: You can replace the normal OptiFine jar with the extracted (non-deobfuscated) one in NoCubes/run/mods/
(this may speed up OptiFine's loading time)
NoCubes' OptiFine compatibility should not be shipped to production compiled directly against OptiFine's classes because
it can crash if OptiFine isn't present. Instead, the code should be converted to Reflection.
Using Reflection has the added benefit of allowing the same NoCubes jar to support multiple versions of OptiFine.
Other OptiFine info (just putting this here so I don't forget and can come back to it at some point)
It's possible to get Forge to do most of the work by adding the following code to `build.gradle`.
```groovy
repositories {
flatDir {
dirs 'run/mods'
}
}
dependencies {
// OptiFine is the first dependency because so that we can compile against its version of vanilla's classes, not Forge's
// Needs a group classifier even though it's not used, this can be anything, I used 'undefined'
compileOnly fg.deobf('undefined:OptiFine_1.16.5_HD_U_G8_pre12_MOD.jar:')
//... other dependencies like Forge
}
```
However, this doesn't fully work because Forge doesn't apply my ATs to OptiFine's classes :(
It's probably possible to run [AccessTransformers](https://github.com/MinecraftForge/ForgeGradle/blob/6639464b29b0923187eee0a609e546ba9f1b998b/src/userdev/java/net/minecraftforge/gradle/userdev/tasks/AccessTransformJar.java#L45) ourselves against the deobfed OptiFine dependency, but I can't figure out how