Skip to content

Commit

Permalink
Begin metabolism compat and fix snow buildup
Browse files Browse the repository at this point in the history
  • Loading branch information
lukebemish committed Jan 4, 2024
1 parent 07f30eb commit 7c117d6
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import dev.lukebemish.tempest.impl.data.NoisyWeatherMap;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
Expand All @@ -22,11 +23,14 @@ public final class Constants {
public static final TagKey<Block> FREEZES_UP = TagKey.create(Registries.BLOCK, id("freezes_up"));
public static final TagKey<Block> BREAKS_WITH_HAIL = TagKey.create(Registries.BLOCK, id("breaks_with_hail"));
public static final TagKey<Block> SAFE_WITH_HAIL = TagKey.create(Registries.BLOCK, id("safe_with_hail"));
public static final TagKey<Block> SNOW_PASSTHROUGH = TagKey.create(Registries.BLOCK, id("snow_passthrough"));
public static final TagKey<EntityType<?>> DAMAGED_BY_HAIL = TagKey.create(Registries.ENTITY_TYPE, id("damaged_by_hail"));
public static final TagKey<EntityType<?>> IMMUNE_TO_HAIL = TagKey.create(Registries.ENTITY_TYPE, id("damaged_by_hail"));

public static final ResourceKey<DamageType> HAIL_DAMAGE_TYPE = ResourceKey.create(Registries.DAMAGE_TYPE, id("hail"));

public static final ResourceLocation TEMPEST_WEATHER_CHECK = id("tempest_weather_check");

public static ResourceLocation id(String path) {
return BASE.withPath(path);
}
Expand All @@ -35,5 +39,7 @@ private Constants() {}

public static void bootstrap() {
NoisyWeatherMap.register();

Services.PLATFORM.register(() -> TempestWeatherCheck.TYPE, TEMPEST_WEATHER_CHECK, BuiltInRegistries.LOOT_CONDITION_TYPE);
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package dev.lukebemish.tempest.impl;

import dev.lukebemish.tempest.impl.data.world.WeatherChunkData;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.chunk.LevelChunk;

import java.util.ServiceLoader;
import java.util.function.Supplier;

public class Services {
public static final Platform PLATFORM = load(Platform.class);
Expand All @@ -16,5 +19,6 @@ public static <T> T load(Class<T> clazz) {

public interface Platform {
WeatherChunkData getChunkData(LevelChunk chunk);
<S, T extends S> Supplier<T> register(Supplier<T> supplier, ResourceLocation location, Registry<S> registry);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package dev.lukebemish.tempest.impl;

import com.google.gson.*;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import dev.lukebemish.tempest.api.WeatherStatus;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.Serializer;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
import net.minecraft.world.level.storage.loot.predicates.LootItemConditionType;
import org.jetbrains.annotations.NotNull;

import java.util.List;
import java.util.Optional;

public record TempestWeatherCheck(Optional<WeatherStatus.Kind> kind, Optional<Range> intensity, Optional<Range> temperature, Optional<Boolean> thunder) implements LootItemCondition {
public static final Codec<TempestWeatherCheck> CODEC = RecordCodecBuilder.create(i -> i.group(
WeatherStatus.Kind.CODEC.optionalFieldOf("kind").forGetter(TempestWeatherCheck::kind),
Range.codecFor(Optional.of(0f), Optional.of(1f)).optionalFieldOf("intensity").forGetter(TempestWeatherCheck::intensity),
Range.codecFor(Optional.of(-1f), Optional.of(1f)).optionalFieldOf("temperature").forGetter(TempestWeatherCheck::temperature),
Codec.BOOL.optionalFieldOf("thunder").forGetter(TempestWeatherCheck::thunder)
).apply(i, TempestWeatherCheck::new));

public static final LootItemConditionType TYPE = new LootItemConditionType(new Serializer<TempestWeatherCheck>() {
@Override
public void serialize(JsonObject json, TempestWeatherCheck value, JsonSerializationContext serializationContext) {
JsonElement out = CODEC.encodeStart(JsonOps.INSTANCE, value).getOrThrow(false, e -> {
throw new JsonSyntaxException(e);
});
if (!out.isJsonObject()) {
throw new JsonSyntaxException("Expected object, got " + out);
}
for (var entry : out.getAsJsonObject().entrySet()) {
json.add(entry.getKey(), entry.getValue());
}
}

@Override
public @NotNull TempestWeatherCheck deserialize(JsonObject json, JsonDeserializationContext serializationContext) {
return CODEC.parse(JsonOps.INSTANCE, json).getOrThrow(false, e -> {
throw new JsonSyntaxException(e);
});
}
});

@Override
public LootItemConditionType getType() {
return TYPE;
}

@Override
public boolean test(LootContext lootContext) {
var level = lootContext.getLevel();
var pos = lootContext.getParamOrNull(LootContextParams.ORIGIN);
if (pos == null) {
return false;
}
var blockPos = new BlockPos((int) Math.round(pos.x()), (int) Math.round(pos.y()), (int) Math.round(pos.z()));
var weather = WeatherStatus.atPosition(level, blockPos);
if (weather == null) {
return false;
}
if (kind.isPresent() && weather.kind() != kind.get()) {
return false;
}
if (intensity.isPresent() && !intensity.get().contains(weather.intensity())) {
return false;
}
if (temperature.isPresent() && !temperature.get().contains(weather.temperature())) {
return false;
}
if (thunder.isPresent() && weather.thunder() != thunder.get()) {
return false;
}
return true;
}

public record Range(float start, float stop) {
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public static Codec<Range> codecFor(Optional<Float> min, Optional<Float> max) {
return Codec.FLOAT.listOf().flatXmap(
list -> {
if (list.size() != 2) {
return DataResult.error(() -> "Expected 2 elements, got " + list.size());
}
if (min.isPresent() && list.get(0) < min.get()) {
return DataResult.error(() -> "Minimum value is " + min.get() + ", got " + list.get(0));
}
if (max.isPresent() && list.get(1) > max.get()) {
return DataResult.error(() -> "Maximum value is " + max.get() + ", got " + list.get(1));
}
return DataResult.success(new Range(list.get(0), list.get(1)));
}, range -> DataResult.success(List.of(range.start, range.stop))
);
}

public boolean contains(float intensity) {
return intensity >= start && intensity <= stop;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,6 @@ private void recalculateWindCheckPositions(Level level) {

private boolean meltAndFreeze(ServerLevel level) {
BlockPos waterySurface = level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, QuasiRandomChunkVisitor.INSTANCE.inChunk(chunk, visitIndex, i -> this.visitIndex = i)).below();
if (!canSeeWindIgnoreLeaves(waterySurface)) {
return false;
}
float temp = temperature(waterySurface);
float precip = precipitation(waterySurface);
float thunder = thunder(waterySurface);
Expand All @@ -346,6 +343,17 @@ private boolean meltAndFreeze(ServerLevel level) {
}

if (temp < 0f) {
BlockPos.MutableBlockPos above = new BlockPos.MutableBlockPos();
above.set(waterySurface);
above.setY(above.getY() + 1);
if (!canSeeWindIgnoreLeavesOrSnow(above)) {
above.setY(above.getY() + 1);
if (level.random.nextBoolean() || !canSeeWindIgnoreLeavesOrSnow(above)) {
if (level.random.nextBoolean() || !canSeeWindIgnoreLeavesOrSnow(above)) {
return false;
}
}
}
// add new black ice or ice
boolean frozen = tryFreezeBlock(level, waterySurface);
repeat = frozen || (repeat && level.random.nextBoolean());
Expand Down Expand Up @@ -443,8 +451,21 @@ public boolean canSeeWindIgnoreLeaves(BlockPos pos) {
mutablePos.setWithOffset(pos, check);
if (chunk.getLevel().isLoaded(mutablePos)) {
BlockState blockState = chunk.getLevel().getBlockState(mutablePos);
//noinspection deprecation
if ((blockState.blocksMotion() || !blockState.getFluidState().isEmpty()) && !(blockState.getBlock() instanceof LeavesBlock)) {
if (isMotionBlocking(blockState) && !(blockState.getBlock() instanceof LeavesBlock)) {
return false;
}
}
}
return true;
}

public boolean canSeeWindIgnoreLeavesOrSnow(BlockPos pos) {
var mutablePos = new BlockPos.MutableBlockPos();
for (BlockPos check : windCheckPositions) {
mutablePos.setWithOffset(pos, check);
if (chunk.getLevel().isLoaded(mutablePos)) {
BlockState blockState = chunk.getLevel().getBlockState(mutablePos);
if (isMotionBlocking(blockState) && !(blockState.getBlock() instanceof LeavesBlock) && !(blockState.is(Constants.SNOW_PASSTHROUGH))) {
return false;
}
}
Expand All @@ -458,15 +479,19 @@ public boolean canSeeWind(BlockPos pos) {
mutablePos.setWithOffset(pos, check);
if (chunk.getLevel().isLoaded(mutablePos)) {
BlockState blockState = chunk.getLevel().getBlockState(mutablePos);
//noinspection deprecation
if (blockState.blocksMotion() || !blockState.getFluidState().isEmpty()) {
if (isMotionBlocking(blockState)) {
return false;
}
}
}
return true;
}

@SuppressWarnings("deprecation")
private static boolean isMotionBlocking(BlockState blockState) {
return (blockState.blocksMotion() || !blockState.getFluidState().isEmpty()) && !(blockState.getBlock() == Blocks.SNOW);
}

private static boolean hasSpaceForSnow(ServerLevel level, BlockPos pos) {
for (int i = 0; i < 4; i++) {
pos = pos.below();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"values": [
"minecraft:powder_snow",
"minecraft:snow_block",
"minecraft:snow"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
import dev.lukebemish.tempest.impl.data.world.WeatherChunkData;
import dev.lukebemish.tempest.impl.data.world.WeatherData;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.core.SectionPos;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.EmptyLevelChunk;
import net.minecraft.world.level.chunk.LevelChunk;

import java.util.List;
import java.util.function.Supplier;

@AutoService(Services.Platform.class)
public final class ModPlatform implements Services.Platform {
Expand All @@ -31,6 +34,12 @@ public WeatherChunkData getChunkData(LevelChunk chunk) {
}
}

@Override
public <S, T extends S> Supplier<T> register(Supplier<T> supplier, ResourceLocation location, Registry<S> registry) {
var entry = Registry.register(registry, location, supplier.get());
return () -> entry;
}

private static final class EmptyData extends WeatherChunkData {
public EmptyData(EmptyLevelChunk chunk) {
super(chunk);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
package dev.lukebemish.tempest.impl.forge;

import com.google.auto.service.AutoService;
import com.mojang.datafixers.util.Pair;
import dev.lukebemish.tempest.impl.Constants;
import dev.lukebemish.tempest.impl.FastChunkLookup;
import dev.lukebemish.tempest.impl.Services;
import dev.lukebemish.tempest.impl.data.world.WeatherChunkData;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.CapabilityToken;
import net.minecraftforge.registries.DeferredRegister;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

@AutoService(Services.Platform.class)
public final class ModPlatform implements Services.Platform {
public static final Capability<WeatherChunkData> WEATHER_CHUNK_DATA = CapabilityManager.get(new CapabilityToken<>(){});
public static final ResourceLocation WEATHER_CHUNK_DATA_LOCATION = Constants.id("weather_status");

private static final Map<Pair<String, ResourceKey<? extends Registry<?>>>, DeferredRegister<?>> REGISTRIES = new HashMap<>();

@Override
public WeatherChunkData getChunkData(LevelChunk chunk) {
var existing = ((FastChunkLookup) chunk).tempest$getChunkData();
Expand All @@ -27,4 +37,11 @@ public WeatherChunkData getChunkData(LevelChunk chunk) {
return data;
}
}

@Override
public <S, T extends S> Supplier<T> register(Supplier<T> supplier, ResourceLocation location, Registry<S> registry) {
//noinspection unchecked
DeferredRegister<S> register = (DeferredRegister<S>) REGISTRIES.computeIfAbsent(Pair.of(location.getNamespace(), registry.key()), k -> DeferredRegister.create(registry.key(), location.getNamespace()));
return register.register(location.getPath(), supplier);
}
}

0 comments on commit 7c117d6

Please sign in to comment.