Make Biome-Tinted Grass Not Suck

This commit is contained in:
TheBrokenRail 2024-12-17 09:22:48 -05:00
parent aea31dd4c8
commit 5d8aa28113
9 changed files with 93 additions and 30 deletions

View File

@ -7,4 +7,5 @@
| [Ghidra](https://ghidra-sre.org) | Used For Decompiling Minecraft: Pi Edition | | [Ghidra](https://ghidra-sre.org) | Used For Decompiling Minecraft: Pi Edition |
| [RetDec](https://retdec.com) | Used For Decompiling Minecraft: Pi Edition | | [RetDec](https://retdec.com) | Used For Decompiling Minecraft: Pi Edition |
| [minecraft-linux/mcpelauncher-core](https://github.com/minecraft-linux/mcpelauncher-core/blob/6b5e17b5685a612143297ae4595bdd12327284f3/src/patch_utils.cpp#L42) | Original Function Overwrite Code | | [minecraft-linux/mcpelauncher-core](https://github.com/minecraft-linux/mcpelauncher-core/blob/6b5e17b5685a612143297ae4595bdd12327284f3/src/patch_utils.cpp#L42) | Original Function Overwrite Code |
| [Hooking C Functions at Runtime - Thomas Finch](http://thomasfinch.me/blog/2015/07/24/Hooking-C-Functions-At-Runtime.html) | Original Patching Code | | [Hooking C Functions at Runtime - Thomas Finch](http://thomasfinch.me/blog/2015/07/24/Hooking-C-Functions-At-Runtime.html) | Original Patching Code |
| [ReMinecraftPE](https://github.com/ReMinecraftPE/mcpe) | A Lot Of Decompiled Code |

View File

@ -19,7 +19,7 @@ install(
DESTINATION "${MCPI_INSTALL_DIR}/data/images/item" DESTINATION "${MCPI_INSTALL_DIR}/data/images/item"
) )
install( install(
FILES "mojang/shadow.png" "mojang/vignette.png" FILES "mojang/shadow.png" "mojang/vignette.png" "mojang/grasscolor.png"
DESTINATION "${MCPI_INSTALL_DIR}/data/images/misc" DESTINATION "${MCPI_INSTALL_DIR}/data/images/misc"
) )

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -1,42 +1,54 @@
#include <libreborn/patch.h> #include <cstdint>
#include <libreborn/patch.h>
#include <symbols/minecraft.h> #include <symbols/minecraft.h>
#include <mods/feature/feature.h> #include <mods/feature/feature.h>
#include <mods/extend/extend.h>
#include "misc-internal.h" #include "misc-internal.h"
// Change Grass Color // Change Grass Color
static int32_t get_color(LevelSource *level_source, int32_t x, int32_t z) { static bool grass_colors_loaded = false;
// Get Biome #define GRASS_COLORS_SIZE 256
const Biome *biome = level_source->getBiome(x, z); static uint32_t grass_colors[GRASS_COLORS_SIZE][GRASS_COLORS_SIZE];
if (biome == nullptr) { static void Minecraft_init_injection(Minecraft_init_t original, Minecraft *self) {
return 0; // Call Original Method
original(self);
// Load
const uint32_t id = self->textures->loadTexture("misc/grasscolor.png", true);
const Texture *data = self->textures->getTemporaryTextureData(id);
if (data == nullptr || data->width != GRASS_COLORS_SIZE || data->height != GRASS_COLORS_SIZE) {
return;
} }
// Return const uint32_t *texture = (uint32_t *) data->data;
return biome->color; // Copy
} for (int y = 0; y < GRASS_COLORS_SIZE; y++) {
#define BIOME_BLEND_SIZE 7 for (int x = 0; x < GRASS_COLORS_SIZE; x++) {
static int32_t GrassTile_getColor_injection(__attribute__((unused)) GrassTile_getColor_t original, __attribute__((unused)) GrassTile *tile, LevelSource *level_source, const int32_t x, __attribute__((unused)) int32_t y, const int32_t z) { grass_colors[y][x] = texture[(y * GRASS_COLORS_SIZE) + x];
int r_sum = 0;
int g_sum = 0;
int b_sum = 0;
int color_sum = 0;
const int x_start = x - (BIOME_BLEND_SIZE / 2);
const int z_start = z - (BIOME_BLEND_SIZE / 2);
for (int x_offset = 0; x_offset < BIOME_BLEND_SIZE; x_offset++) {
for (int z_offset = 0; z_offset < BIOME_BLEND_SIZE; z_offset++) {
const int32_t color = get_color(level_source, x_start + x_offset, z_start + z_offset);
r_sum += (color >> 16) & 0xff;
g_sum += (color >> 8) & 0xff;
b_sum += color & 0xff;
color_sum++;
} }
} }
const int r_avg = r_sum / color_sum; grass_colors_loaded = true;
const int g_avg = g_sum / color_sum; }
const int b_avg = b_sum / color_sum; static int32_t GrassTile_getColor_injection(__attribute__((unused)) GrassTile_getColor_t original, __attribute__((unused)) GrassTile *tile, LevelSource *level_source, const int32_t x, __attribute__((unused)) int32_t y, const int32_t z) {
return (r_avg << 16) | (g_avg << 8) | b_avg; // Get Level
Level *level = ((Region *) level_source)->level;
// Find Biome Temperature
BiomeSource *biome_source = level->getBiomeSource();
biome_source->getBiomeBlock(x, z, 1, 1);
const float temperature = biome_source->temperature[0];
float downfall = biome_source->downfall[0];
// Get Grass Color
downfall *= temperature;
const int xx = (int) ((1 - temperature) * (GRASS_COLORS_SIZE - 1));
const int yy = (int) ((1 - downfall) * (GRASS_COLORS_SIZE - 1));
uint32_t color = grass_colors[yy][xx];
// Convert From ABGR To ARGB
const uint8_t b = (color >> 16) & 0xff;
const uint8_t g = (color >> 8) & 0xff;
const uint8_t r = color & 0xff;
color = (r << 16) | (g << 8) | b;
return (int32_t) color;
} }
static int32_t TallGrass_getColor_injection(TallGrass_getColor_t original, TallGrass *tile, LevelSource *level_source, const int32_t x, const int32_t y, const int32_t z) { static int32_t TallGrass_getColor_injection(TallGrass_getColor_t original, TallGrass *tile, LevelSource *level_source, const int32_t x, const int32_t y, const int32_t z) {
const int32_t original_color = original(tile, level_source, x, y, z); const int32_t original_color = original(tile, level_source, x, y, z);
@ -47,6 +59,32 @@ static int32_t TallGrass_getColor_injection(TallGrass_getColor_t original, TallG
} }
} }
// Grass Side Tinting
CUSTOM_VTABLE(grass_side, Tile) {
vtable->shouldRenderFace = [](Tile *self, LevelSource *level_source, const int x, const int y, const int z, const int face) {
return face != 0 && face != 1 && Tile_vtable::base->shouldRenderFace(self, level_source, x, y, z, face);
};
vtable->getColor = [](Tile *self, LevelSource *level_source, const int32_t x, const int32_t y, const int32_t z) {
return GrassTile_getColor_injection(nullptr, (GrassTile *) self, level_source, x, y, z);
};
}
static Tile *get_fake_grass_side_tile() {
static Tile *out = nullptr;
if (out == nullptr) {
out = Tile::allocate();
out->constructor(0, 38, Material::dirt);
out->vtable = get_grass_side_vtable();
}
return out;
}
static bool TileRenderer_tesselateBlockInWorld_injection(TileRenderer_tesselateBlockInWorld_t original, TileRenderer *self, Tile *tile, const int x, const int y, const int z) {
const bool ret = original(self, tile, x, y, z);
if (tile == Tile::grass && tile->getTexture3((LevelSource *) self->level, x, y, z, 2) == 3) {
original(self, get_fake_grass_side_tile(), x, y, z);
}
return ret;
}
// No Block Tinting // No Block Tinting
template <typename T> template <typename T>
static int32_t Tile_getColor_injection(__attribute__((unused)) const std::function<int(T *, LevelSource *, int, int, int)> &original, __attribute__((unused)) T *self, __attribute__((unused)) LevelSource *level_source, __attribute__((unused)) int x, __attribute__((unused)) int y, __attribute__((unused)) int z) { static int32_t Tile_getColor_injection(__attribute__((unused)) const std::function<int(T *, LevelSource *, int, int, int)> &original, __attribute__((unused)) T *self, __attribute__((unused)) LevelSource *level_source, __attribute__((unused)) int x, __attribute__((unused)) int y, __attribute__((unused)) int z) {
@ -57,8 +95,14 @@ static int32_t Tile_getColor_injection(__attribute__((unused)) const std::functi
void _init_misc_tinting() { void _init_misc_tinting() {
// Change Grass Color // Change Grass Color
if (feature_has("Add Biome Colors To Grass", server_disabled)) { if (feature_has("Add Biome Colors To Grass", server_disabled)) {
overwrite_calls(Minecraft_init, Minecraft_init_injection);
overwrite_calls(GrassTile_getColor, GrassTile_getColor_injection); overwrite_calls(GrassTile_getColor, GrassTile_getColor_injection);
overwrite_calls(TallGrass_getColor, TallGrass_getColor_injection); overwrite_calls(TallGrass_getColor, TallGrass_getColor_injection);
// Fancy Grass Side
// This Requires Alpha Testing On The Opaque Render-Layer, Which Could Hurt Performance
overwrite_calls(TileRenderer_tesselateBlockInWorld, TileRenderer_tesselateBlockInWorld_injection);
unsigned char nop_patch[4] = {0x00, 0xf0, 0x20, 0xe3}; // "nop"
patch((void *) 0x4a038, nop_patch);
} }
// Disable Block Tinting // Disable Block Tinting

View File

@ -97,6 +97,8 @@ set(SRC
src/level/DistanceChunkSorter.def src/level/DistanceChunkSorter.def
src/level/renderer/Chunk.def src/level/renderer/Chunk.def
src/level/LevelStorage.def src/level/LevelStorage.def
src/level/BiomeSource.def
src/level/Region.def
src/item/ItemRenderer.def src/item/ItemRenderer.def
src/item/ItemInHandRenderer.def src/item/ItemInHandRenderer.def
src/item/AuxDataTileItem.def src/item/AuxDataTileItem.def

View File

@ -0,0 +1,9 @@
static-property float tempScale = 0x110254;
static-property float downfallScale = 0x110250;
vtable 0x110218;
virtual-method Biome **getBiomeBlock(int x, int z, int param_1, int param_2) = 0x14;
property float *temperature = 0x4;
property float *downfall = 0x8;

View File

@ -50,6 +50,7 @@ method bool getDirectSignal(int x, int y, int z, int direction) = 0xa5d2c;
method bool canSeeSky(int x, int y, int z) = 0xa39b8; method bool canSeeSky(int x, int y, int z) = 0xa39b8;
method bool isDay() = 0xa3d9c; method bool isDay() = 0xa3d9c;
method int getTopTile(int x, int z) = 0xa2cc8; method int getTopTile(int x, int z) = 0xa2cc8;
method BiomeSource *getBiomeSource() = 0xa3c64;
virtual-method void tick() = 0x28; virtual-method void tick() = 0x28;
virtual-method void updateSleepingPlayerList() = 0x2c; virtual-method void updateSleepingPlayerList() = 0x2c;

View File

@ -0,0 +1,5 @@
extends LevelSource;
vtable 0x10ff58;
property Level *level = 0x10;

View File

@ -57,6 +57,7 @@ virtual-method Tile *setExplodeable(float explodeable) = 0xf4;
virtual-method Tile *setDestroyTime(float destroy_time) = 0xf8; virtual-method Tile *setDestroyTime(float destroy_time) = 0xf8;
virtual-method void spawnResources(Level *level, int x, int y, int z, int data, float chance) = 0x80; virtual-method void spawnResources(Level *level, int x, int y, int z, int data, float chance) = 0x80;
virtual-method Tile *setLightBlock(int strength) = 0xec; virtual-method Tile *setLightBlock(int strength) = 0xec;
virtual-method bool shouldRenderFace(LevelSource *level_source, int x, int y, int z, int face) = 0x24;
property int texture = 0x4; property int texture = 0x4;
property int id = 0x8; property int id = 0x8;