Skip to content

Commit

Permalink
New tag/mech pair foliage_color (#2458)
Browse files Browse the repository at this point in the history
* Add new tag/mech pair `foliage_color`

Tested on 1.17.1, 1.18.2, and 1.19.4

* Change wording of comment.

* Different way of setting and getting foliage color

Now, the foliage color is directly set instead of using a builder class.

Also, the foliage color is now approximated for all biomes without an already set foliage color.

* Meta and code cleanup
  • Loading branch information
BreadcrumbIsTaken committed May 16, 2023
1 parent 2f22d09 commit f223574
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 2 deletions.
@@ -1,5 +1,6 @@
package com.denizenscript.denizen.nms.abstracts;

import com.denizenscript.denizencore.objects.core.ColorTag;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import org.bukkit.World;
import org.bukkit.block.Block;
Expand Down Expand Up @@ -46,6 +47,8 @@ public List<EntityType> getAllEntities() {

public abstract List<EntityType> getWaterEntities();

public abstract int getFoliageColor();

public abstract void setHumidity(float humidity);

public abstract void setTemperature(float temperature);
Expand All @@ -58,5 +61,41 @@ public enum DownfallType {
RAIN, SNOW, NONE
}

public abstract void setFoliageColor(int color);

public abstract void setTo(Block block);

public ColorTag getColor(int x, int y) {
ColorTag topLeft = new ColorTag(26, 191, 0);
ColorTag topRight = new ColorTag(28, 164, 73);
ColorTag bottomLeft = new ColorTag(174, 164, 42);
ColorTag bottomRight = new ColorTag(96, 161, 123);
float normalizedX = x / 255.0f;
float normalizedY = y / 255.0f;
ColorTag lu = scaleColor(topLeft, (1 - normalizedX) * (1 - normalizedY));
ColorTag ru = scaleColor(topRight, normalizedX * (1 - normalizedY));
ColorTag ld = scaleColor(bottomLeft, (1 - normalizedX) * normalizedY);
ColorTag rd = scaleColor(bottomRight, normalizedX * normalizedY);
int r = lu.red + ld.red + rd.red + ru.red;
int g = lu.green + ld.green + rd.green + ru.green;
int b = lu.blue + ld.blue + rd.blue + ru.blue;
return new ColorTag(r, g, b);
}

public float clampColor(float n) {
if (n < 0.0f) {
return 0.0f;
}
else if (n > 1.0f) {
return 1.0f;
}
return n;
}

private ColorTag scaleColor(ColorTag color, float scale) {
float r = color.red * scale;
float g = color.green * scale;
float b = color.blue * scale;
return new ColorTag((int) r, (int) g, (int) b);
}
}
Expand Up @@ -7,6 +7,7 @@
import com.denizenscript.denizencore.objects.*;
import com.denizenscript.denizen.nms.NMSHandler;
import com.denizenscript.denizen.nms.abstracts.BiomeNMS;
import com.denizenscript.denizencore.objects.core.ColorTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.objects.core.ListTag;
import com.denizenscript.denizencore.tags.Attribute;
Expand Down Expand Up @@ -282,6 +283,38 @@ else if (attribute.startsWith("water", 2)) {
}
return list;
});

// <--[tag]
// @attribute <BiomeTag.foliage_color>
// @returns ColorTag
// @mechanism BiomeTag.foliage_color
// @description
// Returns the approximate foliage color of this biome. Foliage includes leaves and vines.
// The "swamp", "mangrove_swamp", "badlands", "wooded_badlands", and "eroded_badlands" biomes are the only biomes with hard-coded foliage colors.
// Biomes with no set foliage color already will have their foliage colors based on temperature and humidity of the biome.
// -->
tagProcessor.registerTag(ColorTag.class, "foliage_color", (attribute, object) -> {
return new ColorTag(ColorTag.fromRGB(object.biome.getFoliageColor()));
});

// <--[mechanism]
// @object BiomeTag
// @name foliage_color
// @input ColorTag
// @description
// Sets the foliage color of this biome. Foliage includes leaves and vines.
// Colors reset on server restart. For the change to take effect on the players' clients, they must quit and rejoin the server.
// @tags
// <BiomeTag.foliage_color>
// @example
// # Adjusts the foliage color of the plains biome permanently, using a server start event to keep it applied.
// # Now the leaves and vines will be a nice salmon-pink!
// on server start:
// - adjust <biome[plains]> foliage_color:#F48D8D
// -->
tagProcessor.registerMechanism("foliage_color", false, ColorTag.class, (object, mechanism, color) -> {
object.biome.setFoliageColor(color.asRGB());
});
}

public static ObjectTagProcessor<BiomeTag> tagProcessor = new ObjectTagProcessor<>();
Expand Down
Expand Up @@ -39,6 +39,7 @@ public class ReflectionMappingsInfo {
public static String Biome_ClimateSettings_temperature = "c";
public static String Biome_ClimateSettings_downfall = "e";
public static String Biome_ClimateSettings_precipitation = "b";
public static String BiomeSpecialEffects_foliageColorOverride = "f";

public static String ThreadedLevelLightEngine_Update_PRE_UPDATE = "a";

Expand Down
Expand Up @@ -4,22 +4,26 @@
import com.denizenscript.denizen.nms.abstracts.BiomeNMS;
import com.denizenscript.denizen.nms.v1_17.ReflectionMappingsInfo;
import com.denizenscript.denizencore.utilities.ReflectionHelper;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.random.WeightedRandomList;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import net.minecraft.world.level.biome.MobSpawnSettings;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_17_R1.CraftWorld;
import org.bukkit.entity.EntityType;

import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

public class BiomeNMSImpl extends BiomeNMS {

Expand Down Expand Up @@ -78,6 +82,23 @@ public List<EntityType> getWaterEntities() {
return getSpawnableEntities(MobCategory.WATER_CREATURE);
}

@Override
public int getFoliageColor() {
// Check if the biome already has a default color
if (biomeBase.getFoliageColor() != 0) {
return biomeBase.getFoliageColor();
}
// Based on net.minecraft.world.level.biome.Biome#getFoliageColorFromTexture()
float temperature = clampColor(getTemperature());
float humidity = clampColor(getHumidity());
// Based on net.minecraft.world.level.FoliageColor#get()
humidity *= temperature;
int humidityValue = (int)((1.0f - humidity) * 255.0f);
int temperatureValue = (int)((1.0f - temperature) * 255.0f);
int index = temperatureValue << 8 | humidityValue;
return index >= 65536 ? 4764952 : getColor(index / 256, index % 256).asRGB();
}

public Object getClimate() {
return ReflectionHelper.getFieldValue(net.minecraft.world.level.biome.Biome.class, ReflectionMappingsInfo.Biome_climateSettings, biomeBase);
}
Expand Down Expand Up @@ -114,6 +135,16 @@ public void setPrecipitation(DownfallType type) {
ReflectionHelper.setFieldValue(climate.getClass(), ReflectionMappingsInfo.Biome_ClimateSettings_precipitation, climate, nmsType);
}

@Override
public void setFoliageColor(int color) {
try {
ReflectionHelper.setFieldValue(BiomeSpecialEffects.class, ReflectionMappingsInfo.BiomeSpecialEffects_foliageColorOverride, biomeBase.getSpecialEffects(), Optional.of(color));
}
catch (Throwable ex) {
Debug.echoError(ex);
}
}

private List<EntityType> getSpawnableEntities(MobCategory creatureType) {
MobSpawnSettings mobs = biomeBase.getMobSettings();
WeightedRandomList<MobSpawnSettings.SpawnerData> typeSettingList = mobs.getMobs(creatureType);
Expand Down
Expand Up @@ -60,11 +60,15 @@ public class ReflectionMappingsInfo {

// net.minecraft.world.level.biome.Biome
public static String Biome_climateSettings = "i";

// net.minecraft.world.level.biome.Biome$ClimateSettings
public static String Biome_ClimateSettings_temperature = "c";
public static String Biome_ClimateSettings_downfall = "e";
public static String Biome_ClimateSettings_precipitation = "b";

// net.minecraft.world.level.biome.BiomeSpecialEffects
public static String BiomeSpecialEffects_foliageColorOverride = "f";

// net.minecraft.network.Connection
public static String Connection_receiving = "k";

Expand Down
Expand Up @@ -4,6 +4,7 @@
import com.denizenscript.denizen.nms.abstracts.BiomeNMS;
import com.denizenscript.denizen.nms.v1_18.ReflectionMappingsInfo;
import com.denizenscript.denizencore.utilities.ReflectionHelper;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
Expand All @@ -13,15 +14,18 @@
import net.minecraft.util.random.WeightedRandomList;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import net.minecraft.world.level.biome.MobSpawnSettings;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
import org.bukkit.entity.EntityType;

import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

public class BiomeNMSImpl extends BiomeNMS {

Expand Down Expand Up @@ -76,6 +80,23 @@ public List<EntityType> getWaterEntities() {
return getSpawnableEntities(MobCategory.WATER_CREATURE);
}

@Override
public int getFoliageColor() {
// Check if the biome already has a default color
if (biomeBase.value().getFoliageColor() != 0) {
return biomeBase.value().getFoliageColor();
}
// Based on net.minecraft.world.level.biome.Biome#getFoliageColorFromTexture()
float temperature = clampColor(getTemperature());
float humidity = clampColor(getHumidity());
// Based on net.minecraft.world.level.FoliageColor#get()
humidity *= temperature;
int humidityValue = (int)((1.0f - humidity) * 255.0f);
int temperatureValue = (int)((1.0f - temperature) * 255.0f);
int index = temperatureValue << 8 | humidityValue;
return index >= 65536 ? 4764952 : getColor(index / 256, index % 256).asRGB();
}

public Object getClimate() {
return ReflectionHelper.getFieldValue(net.minecraft.world.level.biome.Biome.class, ReflectionMappingsInfo.Biome_climateSettings, biomeBase.value());
}
Expand Down Expand Up @@ -104,6 +125,16 @@ public void setPrecipitation(DownfallType type) {
ReflectionHelper.setFieldValue(climate.getClass(), ReflectionMappingsInfo.Biome_ClimateSettings_precipitation, climate, nmsType);
}

@Override
public void setFoliageColor(int color) {
try {
ReflectionHelper.setFieldValue(BiomeSpecialEffects.class, ReflectionMappingsInfo.BiomeSpecialEffects_foliageColorOverride, biomeBase.value().getSpecialEffects(), Optional.of(color));
}
catch (Throwable ex) {
Debug.echoError(ex);
}
}

private List<EntityType> getSpawnableEntities(MobCategory creatureType) {
MobSpawnSettings mobs = biomeBase.value().getMobSettings();
WeightedRandomList<MobSpawnSettings.SpawnerData> typeSettingList = mobs.getMobs(creatureType);
Expand Down
Expand Up @@ -62,6 +62,9 @@ public class ReflectionMappingsInfo {
// net.minecraft.world.level.biome.Biome$ClimateSettings
public static String BiomeClimateSettings_temperatureModifier = "d";

// net.minecraft.world.level.biome.BiomeSpecialEffects
public static String BiomeSpecialEffects_foliageColorOverride = "f";

// net.minecraft.network.Connection
public static String Connection_receiving = "k";

Expand Down
Expand Up @@ -13,8 +13,7 @@
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.random.WeightedRandomList;
import net.minecraft.world.entity.MobCategory;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.MobSpawnSettings;
import net.minecraft.world.level.biome.*;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
Expand All @@ -24,6 +23,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

public class BiomeNMSImpl extends BiomeNMS {

Expand Down Expand Up @@ -85,6 +85,23 @@ public List<EntityType> getWaterEntities() {
return getSpawnableEntities(MobCategory.WATER_CREATURE);
}

@Override
public int getFoliageColor() {
// Check if the biome already has a default color
if (biomeHolder.value().getFoliageColor() != 0) {
return biomeHolder.value().getFoliageColor();
}
// Based on net.minecraft.world.level.biome.Biome#getFoliageColorFromTexture()
float temperature = clampColor(getTemperature());
float humidity = clampColor(getHumidity());
// Based on net.minecraft.world.level.FoliageColor#get()
humidity *= temperature;
int humidityValue = (int)((1.0f - humidity) * 255.0f);
int temperatureValue = (int)((1.0f - temperature) * 255.0f);
int index = temperatureValue << 8 | humidityValue;
return index >= 65536 ? 4764952 : getColor(index / 256, index % 256).asRGB();
}

public Object getClimate() {
return ReflectionHelper.getFieldValue(Biome.class, ReflectionMappingsInfo.Biome_climateSettings, biomeHolder.value());
}
Expand Down Expand Up @@ -130,6 +147,16 @@ public void setPrecipitation(DownfallType type) { // TODO: 1.19.4: This is no lo
setClimate(nmsType, getTemperature(), getTemperatureModifier(), getHumidity());*/
}

@Override
public void setFoliageColor(int color) {
try {
ReflectionHelper.setFieldValue(BiomeSpecialEffects.class, ReflectionMappingsInfo.BiomeSpecialEffects_foliageColorOverride, biomeHolder.value().getSpecialEffects(), Optional.of(color));
}
catch (Throwable ex) {
Debug.echoError(ex);
}
}

private List<EntityType> getSpawnableEntities(MobCategory creatureType) {
MobSpawnSettings mobs = biomeHolder.value().getMobSettings();
WeightedRandomList<MobSpawnSettings.SpawnerData> typeSettingList = mobs.getMobs(creatureType);
Expand Down

0 comments on commit f223574

Please sign in to comment.