More WIP porting messing around with Codex pt. 2
This commit is contained in:
parent
ff6776a660
commit
2fc91263ee
|
|
@ -19,7 +19,6 @@
|
|||
package thedarkcolour.exdeorum;
|
||||
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.fml.ModList;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
|
|
@ -60,7 +59,7 @@ public class ExDeorum {
|
|||
// Game Events
|
||||
EventHandler.register(modBus);
|
||||
// Client init
|
||||
if (FMLEnvironment.dist == Dist.CLIENT) {
|
||||
if (FMLEnvironment.getDist().isClient()) {
|
||||
ClientHandler.register(modBus);
|
||||
}
|
||||
// Config init
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import net.minecraft.util.Mth;
|
|||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||
|
|
@ -64,33 +65,23 @@ public class BarrelBlock extends ETankBlock {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean isMoving) {
|
||||
if (!level.isClientSide()) {
|
||||
if (!state.is(newState.getBlock())) {
|
||||
if (level.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) {
|
||||
var item = barrel.getItem();
|
||||
public void affectNeighborsAfterRemoval(BlockState state, ServerLevel level, BlockPos pos, boolean movedByPiston) {
|
||||
if (level.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) {
|
||||
var item = barrel.getItem();
|
||||
|
||||
if (!item.isEmpty()) {
|
||||
EBlock.dropItem(level, pos, item);
|
||||
}
|
||||
}
|
||||
if (!item.isEmpty()) {
|
||||
EBlock.dropItem(level, pos, item);
|
||||
}
|
||||
}
|
||||
|
||||
super.onRemove(state, level, pos, newState, isMoving);
|
||||
super.affectNeighborsAfterRemoval(state, level, pos, movedByPiston);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void neighborChanged(BlockState pState, Level level, BlockPos pos, Block pBlock, BlockPos fromPos, boolean pIsMoving) {
|
||||
// Only check when the above block is updated, or when the below block is updated
|
||||
if (fromPos.getY() - pos.getY() == 1) {
|
||||
if (level.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) {
|
||||
barrel.tryInWorldFluidMixing();
|
||||
}
|
||||
} else if (fromPos.getY() - pos.getY() == -1) {
|
||||
if (level.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) {
|
||||
barrel.updateFluidTransform();
|
||||
}
|
||||
public void neighborChanged(BlockState pState, Level level, BlockPos pos, Block pBlock, @org.jetbrains.annotations.Nullable net.minecraft.world.level.redstone.Orientation orientation, boolean pIsMoving) {
|
||||
if (level.getBlockEntity(pos) instanceof BarrelBlockEntity barrel) {
|
||||
barrel.tryInWorldFluidMixing();
|
||||
barrel.updateFluidTransform();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package thedarkcolour.exdeorum.block;
|
|||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.InsideBlockEffectApplier;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
|
|
@ -40,7 +41,7 @@ public abstract class ETankBlock extends EBlock {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
|
||||
public void entityInside(BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier applier, boolean shouldApplyEffects) {
|
||||
if (!level.isClientSide() && level.getBlockEntity(pos) instanceof ETankBlockEntity blockEntity) {
|
||||
var tank = blockEntity.getTank();
|
||||
var fluid = tank.getFluid();
|
||||
|
|
|
|||
|
|
@ -28,8 +28,9 @@ import net.minecraft.world.item.ItemStack;
|
|||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.CakeBlock;
|
||||
import net.minecraft.world.level.block.EndPortalBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.portal.TeleportTransition;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import thedarkcolour.exdeorum.tag.EItemTags;
|
||||
|
|
@ -94,10 +95,9 @@ public class EndCakeBlock extends CakeBlock {
|
|||
var endLevel = level.getServer().getLevel(Level.END);
|
||||
|
||||
if (endLevel != null) {
|
||||
if (player.canChangeDimensions(level, endLevel)) {
|
||||
player.changeDimension(((EndPortalBlock) Blocks.END_PORTAL).getPortalDestination(level, player, player.getOnPos()));
|
||||
return true;
|
||||
}
|
||||
var spawn = ServerLevel.END_SPAWN_POINT.getBottomCenter();
|
||||
player.teleportTo(endLevel, spawn.x, spawn.y, spawn.z, java.util.Set.of(), player.getYRot(), player.getXRot(), false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,10 +37,8 @@ import net.minecraft.world.level.block.entity.BlockEntityType;
|
|||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.StateDefinition;
|
||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.fml.loading.FMLEnvironment;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import thedarkcolour.exdeorum.blockentity.InfestedLeavesBlockEntity;
|
||||
import thedarkcolour.exdeorum.client.RenderUtil;
|
||||
import thedarkcolour.exdeorum.config.EConfig;
|
||||
|
|
@ -49,12 +47,18 @@ import thedarkcolour.exdeorum.registry.EBlocks;
|
|||
|
||||
public class InfestedLeavesBlock extends LeavesBlock implements EntityBlock {
|
||||
public static final BooleanProperty FULLY_INFESTED = BooleanProperty.create("fully_infested");
|
||||
public static final MapCodec<InfestedLeavesBlock> CODEC = simpleCodec(InfestedLeavesBlock::new);
|
||||
|
||||
public InfestedLeavesBlock(Properties properties) {
|
||||
super(properties);
|
||||
super(0.005f, properties);
|
||||
registerDefaultState(defaultBlockState().setValue(FULLY_INFESTED, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends LeavesBlock> codec() {
|
||||
return CODEC;
|
||||
}
|
||||
|
||||
public static void setBlock(Level level, BlockPos pos, BlockState fromState) {
|
||||
level.setBlock(pos, EBlocks.INFESTED_LEAVES.get().defaultBlockState()
|
||||
.setValue(LeavesBlock.DISTANCE, fromState.hasProperty(LeavesBlock.DISTANCE) ? fromState.getValue(LeavesBlock.DISTANCE) : 0)
|
||||
|
|
@ -98,11 +102,15 @@ public class InfestedLeavesBlock extends LeavesBlock implements EntityBlock {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getCloneItemStack(BlockState state, HitResult target, LevelReader level, BlockPos pos, Player player) {
|
||||
public ItemStack getCloneItemStack(LevelReader level, BlockPos pos, BlockState state, boolean includeData) {
|
||||
if (level.getBlockEntity(pos) instanceof InfestedLeavesBlockEntity leaves) {
|
||||
return leaves.getMimic().getCloneItemStack(target, level, pos, player);
|
||||
return leaves.getMimic().getCloneItemStack(pos, level, includeData, null);
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
return state.getCloneItemStack(pos, level, includeData, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void spawnFallingLeavesParticle(Level level, BlockPos pos, RandomSource random) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -115,7 +123,9 @@ public class InfestedLeavesBlock extends LeavesBlock implements EntityBlock {
|
|||
|
||||
@Override
|
||||
public RenderShape getRenderShape(BlockState pState) {
|
||||
if (FMLEnvironment.dist == Dist.DEDICATED_SERVER) return RenderShape.MODEL;
|
||||
return (EConfig.CLIENT_SPEC.isLoaded() && EConfig.CLIENT.useFastInfestedLeaves.get()) || RenderUtil.IRIS_ACCESS.areShadersEnabled() ? RenderShape.MODEL : RenderShape.INVISIBLE;
|
||||
if (!EConfig.CLIENT_SPEC.isLoaded()) {
|
||||
return RenderShape.MODEL;
|
||||
}
|
||||
return (EConfig.CLIENT.useFastInfestedLeaves.get() || RenderUtil.IRIS_ACCESS.areShadersEnabled()) ? RenderShape.MODEL : RenderShape.INVISIBLE;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,21 +21,25 @@ package thedarkcolour.exdeorum.block;
|
|||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.util.ProblemReporter;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.level.gamerules.GameRules;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityTicker;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.redstone.Orientation;
|
||||
import net.minecraft.world.level.storage.TagValueInput;
|
||||
import net.minecraft.world.level.storage.TagValueOutput;
|
||||
import net.neoforged.neoforge.items.ItemStackHandler;
|
||||
import thedarkcolour.exdeorum.blockentity.AbstractMachineBlockEntity;
|
||||
import thedarkcolour.exdeorum.config.EConfig;
|
||||
|
|
@ -60,7 +64,6 @@ public abstract class MachineBlock extends EBlock {
|
|||
// Label for the item tooltip where the mesh/hammer is listed
|
||||
protected abstract MutableComponent getHighlightItemLabel();
|
||||
|
||||
@Override
|
||||
public void appendHoverText(ItemStack stack, Item.TooltipContext level, List<Component> tooltip, TooltipFlag flag) {
|
||||
var lookup = level.registries();
|
||||
if (lookup != null) {
|
||||
|
|
@ -73,14 +76,14 @@ public abstract class MachineBlock extends EBlock {
|
|||
|
||||
if (nbt.contains("inventory")) {
|
||||
var inventory = new ItemStackHandler();
|
||||
inventory.deserializeNBT(lookup, nbt.getCompound("inventory"));
|
||||
inventory.deserialize(TagValueInput.create(ProblemReporter.DISCARDING, lookup, nbt.getCompound("inventory").orElseGet(CompoundTag::new)));
|
||||
|
||||
// Hammer or sieve mesh
|
||||
var highlightItem = inventory.getStackInSlot(getHighlightItemSlot());
|
||||
|
||||
if (!highlightItem.isEmpty()) {
|
||||
// display the mesh/hammer inside the machine
|
||||
tooltip.add(getHighlightItemLabel().withStyle(ChatFormatting.GRAY).append(Component.translatable(highlightItem.getDescriptionId())));
|
||||
tooltip.add(getHighlightItemLabel().withStyle(ChatFormatting.GRAY).append(Component.translatable(highlightItem.getItem().getDescriptionId())));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,12 +99,14 @@ public abstract class MachineBlock extends EBlock {
|
|||
// Drops the item for creative mode players
|
||||
@Override
|
||||
public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState pState, Player player) {
|
||||
if (!level.isClientSide() && player.isCreative() && level.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) {
|
||||
if (!level.isClientSide() && player.isCreative()) {
|
||||
if (level.getBlockEntity(pos) instanceof AbstractMachineBlockEntity<?> machine) {
|
||||
if (!machine.inventory.getStackInSlot(getHighlightItemSlot()).isEmpty()) {
|
||||
var stack = new ItemStack(this);
|
||||
// save machine properties to the item if mesh/hammer slot is not empty
|
||||
BlockItem.setBlockEntityData(stack, this.blockEntityType.get(), machine.saveWithoutMetadata(level.registryAccess()));
|
||||
var data = TagValueOutput.createWithContext(ProblemReporter.DISCARDING, level.registryAccess());
|
||||
machine.saveCustomOnly(data);
|
||||
BlockItem.setBlockEntityData(stack, this.blockEntityType.get(), data);
|
||||
var itemEntity = new ItemEntity(level, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, stack);
|
||||
itemEntity.setDefaultPickUpDelay();
|
||||
level.addFreshEntity(itemEntity);
|
||||
|
|
@ -124,7 +129,7 @@ public abstract class MachineBlock extends EBlock {
|
|||
|
||||
// Redstone state
|
||||
@Override
|
||||
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, BlockPos fromPos, boolean isMoving) {
|
||||
public void neighborChanged(BlockState state, Level level, BlockPos pos, Block block, @org.jetbrains.annotations.Nullable Orientation orientation, boolean isMoving) {
|
||||
if (level.getBlockEntity(pos) instanceof AbstractMachineBlockEntity<?> machine) {
|
||||
machine.checkPoweredState(level, pos);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public class MechanicalHammerBlock extends MachineBlock {
|
|||
@SuppressWarnings("deprecation")
|
||||
var nbt = customData.getUnsafe();
|
||||
|
||||
if (nbt.contains("progress") && nbt.getInt("progress") != MechanicalHammerBlockEntity.NOT_RUNNING) {
|
||||
if (nbt.contains("progress") && nbt.getIntOr("progress", MechanicalHammerBlockEntity.NOT_RUNNING) != MechanicalHammerBlockEntity.NOT_RUNNING) {
|
||||
state = state.setValue(RUNNING, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package thedarkcolour.exdeorum.block;
|
|||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||
|
|
@ -55,19 +56,15 @@ public class SieveBlock extends EBlock {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean pIsMoving) {
|
||||
if (!level.isClientSide()) {
|
||||
if (!state.is(newState.getBlock())) {
|
||||
if (level.getBlockEntity(pos) instanceof AbstractSieveBlockEntity sieve) {
|
||||
var mesh = sieve.getLogic().getMesh();
|
||||
public void affectNeighborsAfterRemoval(BlockState state, ServerLevel level, BlockPos pos, boolean movedByPiston) {
|
||||
if (level.getBlockEntity(pos) instanceof AbstractSieveBlockEntity sieve) {
|
||||
var mesh = sieve.getLogic().getMesh();
|
||||
|
||||
if (!mesh.isEmpty()) {
|
||||
dropItem(level, pos, mesh);
|
||||
}
|
||||
}
|
||||
if (!mesh.isEmpty()) {
|
||||
dropItem(level, pos, mesh);
|
||||
}
|
||||
}
|
||||
|
||||
super.onRemove(state, level, pos, newState, pIsMoving);
|
||||
super.affectNeighborsAfterRemoval(state, level, pos, movedByPiston);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,27 +19,26 @@
|
|||
package thedarkcolour.exdeorum.block;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
import net.minecraft.world.Difficulty;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.*;
|
||||
import net.minecraft.world.entity.InsideBlockEffectApplier;
|
||||
import net.minecraft.world.entity.animal.cow.MushroomCow;
|
||||
import net.minecraft.world.entity.animal.rabbit.Rabbit;
|
||||
import net.minecraft.world.entity.animal.axolotl.Axolotl;
|
||||
import net.minecraft.world.entity.monster.Creeper;
|
||||
import net.minecraft.world.entity.monster.zombie.Zombie;
|
||||
import net.minecraft.world.entity.monster.zombie.ZombieVillager;
|
||||
import net.minecraft.world.entity.npc.villager.Villager;
|
||||
import net.minecraft.world.entity.npc.villager.VillagerProfession;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.ServerLevelAccessor;
|
||||
import net.minecraft.world.level.block.LiquidBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.material.FlowingFluid;
|
||||
import net.neoforged.neoforge.event.EventHooks;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import thedarkcolour.exdeorum.config.EConfig;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class WitchWaterBlock extends LiquidBlock {
|
||||
|
|
@ -48,7 +47,7 @@ public class WitchWaterBlock extends LiquidBlock {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void entityInside(BlockState pState, Level level, BlockPos pPos, Entity entity) {
|
||||
protected void entityInside(BlockState pState, Level level, BlockPos pPos, Entity entity, InsideBlockEffectApplier pEffectApplier, boolean pCanTriggerEffects) {
|
||||
if (!level.isClientSide()) {
|
||||
witchWaterEntityEffects(level, entity);
|
||||
}
|
||||
|
|
@ -64,23 +63,15 @@ public class WitchWaterBlock extends LiquidBlock {
|
|||
var villager = (Villager) entity;
|
||||
|
||||
if (level.getDifficulty() != Difficulty.PEACEFUL) {
|
||||
if (!villager.isBaby() && villager.getVillagerData().getProfession() == VillagerProfession.CLERIC) {
|
||||
if (attemptToConvertEntity(level, villager, EntityType.WITCH) != null) {
|
||||
villager.releaseAllPois();
|
||||
}
|
||||
if (!villager.isBaby() && villager.getVillagerData().profession().is(VillagerProfession.CLERIC)) {
|
||||
attemptToConvertEntity(level, villager, EntityType.WITCH);
|
||||
} else {
|
||||
var zombieVillager = villager.convertTo(EntityType.ZOMBIE_VILLAGER, false);
|
||||
if (zombieVillager != null) {
|
||||
EventHooks.finalizeMobSpawn(zombieVillager, (ServerLevelAccessor) level, level.getCurrentDifficultyAt(zombieVillager.blockPosition()), MobSpawnType.CONVERSION, new Zombie.ZombieGroupData(false, true));
|
||||
villager.convertTo(EntityType.ZOMBIE_VILLAGER, ConversionParams.single(villager, false, false), EntitySpawnReason.CONVERSION, (ZombieVillager zombieVillager) -> {
|
||||
zombieVillager.setVillagerData(villager.getVillagerData());
|
||||
zombieVillager.setGossips(villager.getGossips().store(NbtOps.INSTANCE));
|
||||
zombieVillager.setGossips(villager.getGossips().copy());
|
||||
zombieVillager.setTradeOffers(villager.getOffers().copy());
|
||||
zombieVillager.setVillagerXp(villager.getVillagerXp());
|
||||
|
||||
EventHooks.onLivingConvert(villager, zombieVillager);
|
||||
|
||||
villager.discard();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (entityType == EntityType.SKELETON) {
|
||||
|
|
@ -96,11 +87,11 @@ public class WitchWaterBlock extends LiquidBlock {
|
|||
} else if (entityType == EntityType.HOGLIN) {
|
||||
attemptToConvertEntity(level, entity, EntityType.ZOGLIN);
|
||||
} else if (entityType == EntityType.MOOSHROOM) {
|
||||
((MushroomCow) entity).setVariant(MushroomCow.MushroomType.BROWN);
|
||||
setVariant((MushroomCow) entity, "setVariant", MushroomCow.Variant.class, MushroomCow.Variant.BROWN);
|
||||
} else if (entityType == EntityType.AXOLOTL) {
|
||||
((Axolotl) entity).setVariant(Axolotl.Variant.BLUE);
|
||||
setVariant((Axolotl) entity, "setVariant", Axolotl.Variant.class, Axolotl.Variant.BLUE);
|
||||
} else if (entityType == EntityType.RABBIT) {
|
||||
((Rabbit) entity).setVariant(Rabbit.Variant.EVIL);
|
||||
setVariant((Rabbit) entity, "setVariant", Rabbit.Variant.class, Rabbit.Variant.EVIL);
|
||||
} else if (entityType == EntityType.PUFFERFISH) {
|
||||
attemptToConvertEntity(level, entity, EntityType.GUARDIAN);
|
||||
} else if (entityType == EntityType.HORSE) {
|
||||
|
|
@ -117,36 +108,34 @@ public class WitchWaterBlock extends LiquidBlock {
|
|||
living.addEffect(new MobEffectInstance(MobEffects.BLINDNESS, 210));
|
||||
living.addEffect(new MobEffectInstance(MobEffects.WEAKNESS, 210, 2));
|
||||
living.addEffect(new MobEffectInstance(MobEffects.WITHER, 210));
|
||||
living.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 210));
|
||||
living.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, 210));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static <T extends Mob> T attemptToConvertEntity(Level level, Entity entity, EntityType<T> newType) {
|
||||
if (level.getDifficulty() != Difficulty.PEACEFUL && entity instanceof LivingEntity) {
|
||||
var newEntity = newType.create(level);
|
||||
|
||||
if (newEntity != null) {
|
||||
var serverLevel = (ServerLevelAccessor) level;
|
||||
newEntity.copyPosition(entity);
|
||||
EventHooks.finalizeMobSpawn(newEntity, serverLevel, level.getCurrentDifficultyAt(entity.blockPosition()), MobSpawnType.CONVERSION, null);
|
||||
newEntity.setNoAi(newEntity.isNoAi());
|
||||
|
||||
if (level.getDifficulty() != Difficulty.PEACEFUL && entity instanceof Mob mob) {
|
||||
return mob.convertTo(newType, ConversionParams.single(mob, false, false), EntitySpawnReason.CONVERSION, converted -> {
|
||||
if (entity.hasCustomName()) {
|
||||
newEntity.setCustomName(entity.getCustomName());
|
||||
newEntity.setCustomNameVisible(entity.isCustomNameVisible());
|
||||
converted.setCustomName(entity.getCustomName());
|
||||
converted.setCustomNameVisible(entity.isCustomNameVisible());
|
||||
}
|
||||
|
||||
newEntity.setPersistenceRequired();
|
||||
EventHooks.onLivingConvert((LivingEntity) entity, newEntity);
|
||||
serverLevel.addFreshEntityWithPassengers(newEntity);
|
||||
entity.discard();
|
||||
}
|
||||
|
||||
return newEntity;
|
||||
converted.setPersistenceRequired();
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static <T extends LivingEntity, V> void setVariant(T entity, String methodName, Class<V> variantType, V variant) {
|
||||
try {
|
||||
Method method = entity.getClass().getDeclaredMethod(methodName, variantType);
|
||||
method.setAccessible(true);
|
||||
method.invoke(entity, variant);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new IllegalStateException("Failed to set entity variant for " + entity.getClass().getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,7 @@
|
|||
package thedarkcolour.exdeorum.blockentity;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
|
|
@ -32,6 +30,8 @@ import net.minecraft.world.item.Item;
|
|||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.storage.ValueInput;
|
||||
import net.minecraft.world.level.storage.ValueOutput;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
|
|
@ -48,6 +48,7 @@ import net.neoforged.neoforge.fluids.capability.IFluidHandler;
|
|||
import net.neoforged.neoforge.fluids.capability.templates.FluidTank;
|
||||
import net.neoforged.neoforge.items.IItemHandler;
|
||||
import net.neoforged.neoforge.items.ItemStackHandler;
|
||||
import net.neoforged.neoforge.transfer.access.ItemAccess;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import thedarkcolour.exdeorum.blockentity.helper.FluidHelper;
|
||||
|
|
@ -85,27 +86,33 @@ public abstract class AbstractCrucibleBlockEntity extends ETankBlockEntity {
|
|||
|
||||
// NBT
|
||||
@Override
|
||||
public void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
super.saveAdditional(nbt, registries);
|
||||
protected void saveAdditional(ValueOutput output) {
|
||||
super.saveAdditional(output);
|
||||
|
||||
nbt.put("Tank", this.tank.writeToNBT(registries, new CompoundTag()));
|
||||
this.tank.serialize(output.child("tank"));
|
||||
if (this.lastMelted != null) {
|
||||
nbt.putString("LastMelted", BuiltInRegistries.BLOCK.getKey(this.lastMelted).toString());
|
||||
output.putString("lastMelted", BuiltInRegistries.BLOCK.getKey(this.lastMelted).toString());
|
||||
}
|
||||
if (this.fluid != null) {
|
||||
nbt.putString("Fluid", BuiltInRegistries.FLUID.getKey(this.fluid).toString());
|
||||
output.putString("fluid", BuiltInRegistries.FLUID.getKey(this.fluid).toString());
|
||||
}
|
||||
nbt.putShort("Solids", this.solids);
|
||||
output.putShort("solids", this.solids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
|
||||
super.loadAdditional(nbt, registries);
|
||||
public void loadAdditional(ValueInput input) {
|
||||
super.loadAdditional(input);
|
||||
|
||||
this.tank.readFromNBT(registries, nbt.getCompound("Tank"));
|
||||
this.lastMelted = BuiltInRegistries.BLOCK.get(Identifier.parse(nbt.getString("LastMelted")));
|
||||
this.fluid = BuiltInRegistries.FLUID.get(Identifier.parse(nbt.getString("Fluid")));
|
||||
this.solids = nbt.getShort("Solids");
|
||||
this.tank.deserialize(input.childOrEmpty("tank"));
|
||||
this.lastMelted = input.getString("lastMelted")
|
||||
.map(Identifier::parse)
|
||||
.flatMap(id -> BuiltInRegistries.BLOCK.get(id).map(reference -> reference.value()))
|
||||
.orElse(null);
|
||||
this.fluid = input.getString("fluid")
|
||||
.map(Identifier::parse)
|
||||
.flatMap(id -> BuiltInRegistries.FLUID.get(id).map(reference -> reference.value()))
|
||||
.orElse(null);
|
||||
this.solids = (short) input.getShortOr("solids", (short) 0);
|
||||
|
||||
updateLight(this.level, this.worldPosition, this.fluid);
|
||||
}
|
||||
|
|
@ -155,7 +162,7 @@ public abstract class AbstractCrucibleBlockEntity extends ETankBlockEntity {
|
|||
public InteractionResult useItemOn(Level level, Player player, ItemStack stack, InteractionHand hand) {
|
||||
var playerItem = player.getItemInHand(hand);
|
||||
|
||||
if (playerItem.getCapability(Capabilities.Fluid.ITEM) != null) {
|
||||
if (getFluidHandler(playerItem) != null) {
|
||||
return FluidUtil.interactWithFluidHandler(player, hand, this.tank) ? InteractionResult.SUCCESS : InteractionResult.TRY_WITH_EMPTY_HAND;
|
||||
}
|
||||
|
||||
|
|
@ -261,10 +268,19 @@ public abstract class AbstractCrucibleBlockEntity extends ETankBlockEntity {
|
|||
return this.tank;
|
||||
}
|
||||
|
||||
public IItemHandler getItem() {
|
||||
public ItemStackHandler getItem() {
|
||||
return this.item;
|
||||
}
|
||||
|
||||
private static IFluidHandler getFluidHandler(ItemStack stack) {
|
||||
if (stack.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var handler = stack.getCapability(Capabilities.Fluid.ITEM, ItemAccess.forStack(stack));
|
||||
return handler == null ? null : IFluidHandler.of(handler);
|
||||
}
|
||||
|
||||
public abstract Block getDefaultMeltBlock();
|
||||
|
||||
@Nullable
|
||||
|
|
@ -296,7 +312,12 @@ public abstract class AbstractCrucibleBlockEntity extends ETankBlockEntity {
|
|||
|
||||
if (key.getPath().endsWith("sapling")) {
|
||||
try {
|
||||
overrides.put(item, BuiltInRegistries.BLOCK.get(Identifier.fromNamespaceAndPath(key.getNamespace(), key.getPath().replace("sapling", "leaves"))));
|
||||
var leaves = BuiltInRegistries.BLOCK.get(Identifier.fromNamespaceAndPath(key.getNamespace(), key.getPath().replace("sapling", "leaves")))
|
||||
.map(reference -> reference.value())
|
||||
.orElse(Blocks.AIR);
|
||||
if (leaves != Blocks.AIR) {
|
||||
overrides.put(item, leaves);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,10 +19,8 @@
|
|||
package thedarkcolour.exdeorum.blockentity;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
|
|
@ -36,6 +34,8 @@ import net.minecraft.world.item.ItemStack;
|
|||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.alchemy.PotionContents;
|
||||
import net.minecraft.world.item.alchemy.Potions;
|
||||
import net.minecraft.world.level.storage.ValueInput;
|
||||
import net.minecraft.world.level.storage.ValueOutput;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.BucketPickup;
|
||||
|
|
@ -54,6 +54,7 @@ import net.neoforged.neoforge.fluids.capability.IFluidHandler;
|
|||
import net.neoforged.neoforge.fluids.capability.templates.FluidTank;
|
||||
import net.neoforged.neoforge.items.IItemHandler;
|
||||
import net.neoforged.neoforge.items.ItemStackHandler;
|
||||
import net.neoforged.neoforge.transfer.access.ItemAccess;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import thedarkcolour.exdeorum.block.BarrelBlock;
|
||||
import thedarkcolour.exdeorum.blockentity.helper.FluidHelper;
|
||||
|
|
@ -66,8 +67,6 @@ import thedarkcolour.exdeorum.recipe.barrel.FluidTransformationRecipe;
|
|||
import thedarkcolour.exdeorum.registry.EBlockEntities;
|
||||
import thedarkcolour.exdeorum.registry.ESounds;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class BarrelBlockEntity extends ETankBlockEntity {
|
||||
private static final int MOSS_SPREAD_RANGE = 2;
|
||||
private static final int MAX_CAPACITY = 1000;
|
||||
|
|
@ -93,29 +92,29 @@ public class BarrelBlockEntity extends ETankBlockEntity {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void saveAdditional(CompoundTag nbt, HolderLookup.Provider lookup) {
|
||||
super.saveAdditional(nbt, lookup);
|
||||
protected void saveAdditional(ValueOutput output) {
|
||||
super.saveAdditional(output);
|
||||
|
||||
nbt.put("item", this.item.serializeNBT(lookup));
|
||||
nbt.put("tank", this.tank.writeToNBT(lookup, new CompoundTag()));
|
||||
nbt.putShort("compost", this.compost);
|
||||
nbt.putFloat("progress", this.progress);
|
||||
nbt.putShort("r", this.r);
|
||||
nbt.putShort("g", this.g);
|
||||
nbt.putShort("b", this.b);
|
||||
this.item.serialize(output.child("item"));
|
||||
this.tank.serialize(output.child("tank"));
|
||||
output.putShort("compost", this.compost);
|
||||
output.putFloat("progress", this.progress);
|
||||
output.putShort("r", this.r);
|
||||
output.putShort("g", this.g);
|
||||
output.putShort("b", this.b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAdditional(CompoundTag nbt, HolderLookup.Provider lookup) {
|
||||
super.loadAdditional(nbt, lookup);
|
||||
public void loadAdditional(ValueInput input) {
|
||||
super.loadAdditional(input);
|
||||
|
||||
this.item.deserializeNBT(lookup, nbt.getCompound("item"));
|
||||
this.tank.readFromNBT(lookup, nbt.getCompound("tank"));
|
||||
this.compost = nbt.getShort("compost");
|
||||
this.progress = nbt.getFloat("progress");
|
||||
this.r = nbt.getShort("r");
|
||||
this.g = nbt.getShort("g");
|
||||
this.b = nbt.getShort("b");
|
||||
this.item.deserialize(input.childOrEmpty("item"));
|
||||
this.tank.deserialize(input.childOrEmpty("tank"));
|
||||
this.compost = (short) input.getShortOr("compost", (short) 0);
|
||||
this.progress = input.getFloatOr("progress", 0f);
|
||||
this.r = (short) input.getShortOr("r", (short) 0);
|
||||
this.g = (short) input.getShortOr("g", (short) 0);
|
||||
this.b = (short) input.getShortOr("b", (short) 0);
|
||||
|
||||
AbstractCrucibleBlockEntity.updateLight(this.level, this.worldPosition, this.tank.getFluid().getFluid());
|
||||
}
|
||||
|
|
@ -263,7 +262,8 @@ public class BarrelBlockEntity extends ETankBlockEntity {
|
|||
}
|
||||
|
||||
// Otherwise, mix the item's fluid into the barrel's fluid
|
||||
var itemFluidCap = playerItem.getCapability(Capabilities.Fluid.ITEM);
|
||||
var itemAccess = ItemAccess.forPlayerInteraction(player, hand);
|
||||
var itemFluidCap = getFluidHandler(itemAccess);
|
||||
if (itemFluidCap != null) {
|
||||
var itemFluid = itemFluidCap.drain(1000, IFluidHandler.FluidAction.SIMULATE);
|
||||
BarrelFluidMixingRecipe recipe = RecipeUtil.getFluidMixingRecipe(this.tank.getFluid(), itemFluid.getFluid());
|
||||
|
|
@ -276,7 +276,6 @@ public class BarrelBlockEntity extends ETankBlockEntity {
|
|||
|
||||
if (recipe.consumesAdditive()) {
|
||||
itemFluidCap.drain(1000, IFluidHandler.FluidAction.EXECUTE);
|
||||
player.setItemInHand(hand, itemFluidCap.getContainer());
|
||||
}
|
||||
}
|
||||
// If a mix was successful, skip rest of logic
|
||||
|
|
@ -478,10 +477,15 @@ public class BarrelBlockEntity extends ETankBlockEntity {
|
|||
}
|
||||
}
|
||||
|
||||
public IItemHandler getItemHandler() {
|
||||
public ItemStackHandler getItemHandler() {
|
||||
return this.item;
|
||||
}
|
||||
|
||||
private static IFluidHandler getFluidHandler(ItemAccess itemAccess) {
|
||||
var handler = itemAccess.getCapability(Capabilities.Fluid.ITEM);
|
||||
return handler == null ? null : IFluidHandler.of(handler);
|
||||
}
|
||||
|
||||
public static class Ticker implements BlockEntityTicker<BarrelBlockEntity> {
|
||||
@Override
|
||||
public void tick(Level level, BlockPos pos, BlockState state, BarrelBlockEntity barrel) {
|
||||
|
|
@ -595,9 +599,13 @@ public class BarrelBlockEntity extends ETankBlockEntity {
|
|||
}
|
||||
|
||||
private static ItemStack getRemainderItem(ItemStack stack) {
|
||||
var food = stack.get(DataComponents.FOOD);
|
||||
Optional<ItemStack> foodRemainder = food == null ? Optional.empty() : food.usingConvertsTo();
|
||||
return foodRemainder.map(ItemStack::copy).orElseGet(stack::getCraftingRemainingItem);
|
||||
var useRemainder = stack.get(DataComponents.USE_REMAINDER);
|
||||
if (useRemainder != null) {
|
||||
return useRemainder.convertInto().create();
|
||||
}
|
||||
|
||||
var craftingRemainder = stack.getItem().getCraftingRemainder();
|
||||
return craftingRemainder != null ? craftingRemainder.create() : ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ package thedarkcolour.exdeorum.blockentity;
|
|||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
|
@ -33,6 +32,7 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||
import net.neoforged.neoforge.model.data.ModelData;
|
||||
import net.neoforged.neoforge.model.data.ModelProperty;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import thedarkcolour.exdeorum.block.InfestedLeavesBlock;
|
||||
import thedarkcolour.exdeorum.registry.EBlockEntities;
|
||||
import thedarkcolour.exdeorum.registry.EBlocks;
|
||||
|
|
@ -105,10 +105,8 @@ public class InfestedLeavesBlockEntity extends EBlockEntity {
|
|||
public void loadAdditional(ValueInput input) {
|
||||
super.loadAdditional(input);
|
||||
|
||||
var holderLookup = input.lookup().lookupOrThrow(Registries.BLOCK);
|
||||
this.mimic = input.child("mimic")
|
||||
.map(child -> NbtUtils.readBlockState(holderLookup, child.asTag()))
|
||||
.orElse(Blocks.OAK_LEAVES.defaultBlockState());
|
||||
input.lookup().lookupOrThrow(Registries.BLOCK);
|
||||
this.mimic = input.read("mimic", BlockState.CODEC).orElse(Blocks.OAK_LEAVES.defaultBlockState());
|
||||
this.progress = (short) input.getShortOr("progress", (short) 0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import net.minecraft.client.gui.screens.worldselection.CreateWorldScreen;
|
|||
import net.minecraft.client.gui.screens.worldselection.WorldCreationUiState;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.util.Unit;
|
||||
import net.minecraft.world.level.levelgen.presets.WorldPreset;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.fml.ModList;
|
||||
|
|
@ -31,6 +30,7 @@ import net.neoforged.fml.event.config.ModConfigEvent;
|
|||
import net.neoforged.neoforge.client.event.*;
|
||||
import net.neoforged.neoforge.client.extensions.common.RegisterClientExtensionsEvent;
|
||||
import net.neoforged.neoforge.common.NeoForge;
|
||||
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.asm.ASMHooks;
|
||||
import thedarkcolour.exdeorum.client.screen.MechanicalHammerScreen;
|
||||
|
|
@ -68,9 +68,7 @@ public class ClientHandler {
|
|||
}
|
||||
|
||||
private static void addClientReloadListeners(AddClientReloadListenersEvent event) {
|
||||
event.addListener(ExDeorum.loc("render_util"), (prepBarrier, resourceManager, prepProfiler, reloadProfiler, backgroundExecutor, gameExecutor) -> {
|
||||
return prepBarrier.wait(Unit.INSTANCE).thenRunAsync(RenderUtil::reload, gameExecutor);
|
||||
});
|
||||
event.addListener(ExDeorum.loc("render_util"), (ResourceManagerReloadListener) resourceManager -> RenderUtil.reload());
|
||||
}
|
||||
|
||||
private static void registerMenuScreens(RegisterMenuScreensEvent event) {
|
||||
|
|
@ -96,7 +94,7 @@ public class ClientHandler {
|
|||
|
||||
private static void registerRenderers(EntityRenderersEvent.RegisterRenderers event) {
|
||||
event.registerBlockEntityRenderer(EBlockEntities.INFESTED_LEAVES.get(), ctx -> new InfestedLeavesRenderer());
|
||||
event.registerBlockEntityRenderer(EBlockEntities.BARREL.get(), ctx -> new BarrelRenderer());
|
||||
event.registerBlockEntityRenderer(EBlockEntities.BARREL.get(), BarrelRenderer::new);
|
||||
event.registerBlockEntityRenderer(EBlockEntities.LAVA_CRUCIBLE.get(), ctx -> new CrucibleRenderer());
|
||||
event.registerBlockEntityRenderer(EBlockEntities.WATER_CRUCIBLE.get(), ctx -> new CrucibleRenderer());
|
||||
event.registerBlockEntityRenderer(EBlockEntities.SIEVE.get(), ctx -> new SieveRenderer<>(0.75f, 15f));
|
||||
|
|
|
|||
|
|
@ -18,46 +18,32 @@
|
|||
|
||||
package thedarkcolour.exdeorum.client;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.util.GsonHelper;
|
||||
import net.minecraft.world.inventory.InventoryMenu;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.fml.ModList;
|
||||
import net.neoforged.fml.loading.FMLEnvironment;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.joml.Vector3i;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.compat.ModIds;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.Color;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
// ExDeorum comes with a precomputed list of vanilla colors, since textures don't exist on the server.
|
||||
// However, modded textures usually DO exist on the server, so their colors can be computed by the server once
|
||||
// and stored in a file which can be configured by the user after the fact.
|
||||
// Server-safe compost color loader. Vanilla colors come from the bundled text file,
|
||||
// while modded overrides are read from config/exdeorum/compost_colors.
|
||||
public class CompostColors {
|
||||
public static final String VANILLA_COMPOST_COLORS_FILE = "vanilla_compost_colors.txt";
|
||||
public static final Path COMPOST_COLORS_CONFIGS = Paths.get("config/exdeorum/compost_colors");
|
||||
|
|
@ -67,7 +53,6 @@ public class CompostColors {
|
|||
|
||||
public static void loadColors() {
|
||||
COLORS.clear();
|
||||
|
||||
loadVanilla();
|
||||
loadModded();
|
||||
}
|
||||
|
|
@ -77,280 +62,118 @@ public class CompostColors {
|
|||
}
|
||||
|
||||
private static void loadVanilla() {
|
||||
var vanillaColors = ModList.get().getModFileById(ExDeorum.ID).getFile().findResource(CompostColors.VANILLA_COMPOST_COLORS_FILE);
|
||||
try (var stream = CompostColors.class.getClassLoader().getResourceAsStream(VANILLA_COMPOST_COLORS_FILE)) {
|
||||
if (stream == null) {
|
||||
ExDeorum.LOGGER.error("Failed to load bundled vanilla compost colors");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Files.exists(vanillaColors)) {
|
||||
ExDeorum.LOGGER.error("Failed to load vanilla colors!");
|
||||
} else {
|
||||
readColorFile(ModIds.MINECRAFT, vanillaColors);
|
||||
try (var reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
|
||||
readColorEntries("minecraft", reader, VANILLA_COMPOST_COLORS_FILE);
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
ExDeorum.LOGGER.error("Failed to read bundled vanilla compost colors", exception);
|
||||
}
|
||||
}
|
||||
|
||||
// Used to generate the list of vanilla colors shipped with the Ex Deorum jar
|
||||
// TODO: port debugCompute to MC 26.x (ItemRenderer/getItemModelShaper/BakedModel.getParticleIcon removed)
|
||||
public static void debugCompute() {
|
||||
throw new UnsupportedOperationException("debugCompute not yet ported to MC 26.x");
|
||||
}
|
||||
|
||||
private static void loadModded() {
|
||||
var readMods = readModdedColorFiles();
|
||||
|
||||
for (var entry : BuiltInRegistries.ITEM.entrySet()) {
|
||||
var key = entry.getKey().identifier();
|
||||
var modid = key.getNamespace();
|
||||
|
||||
if (!readMods.contains(modid)) {
|
||||
var id = key.getPath();
|
||||
var modFile = ModList.get().getModFileById(modid);
|
||||
if (modFile == null)
|
||||
continue;
|
||||
var jarFile = modFile.getFile();
|
||||
var modelPath = jarFile.findResource("assets/" + modid + "/models/item/" + id + ".json");
|
||||
|
||||
if (Files.exists(modelPath)) {
|
||||
JsonObject modelJson = parseModelJson(modelPath, modid, id);
|
||||
|
||||
if (modelJson != null) {
|
||||
var textures = modelJson.get("textures");
|
||||
|
||||
if (textures instanceof JsonObject textureMap) {
|
||||
String texture = findFirstTexture(textureMap);
|
||||
|
||||
if (texture != null) {
|
||||
// Best case scenario, we are in a plain old 2D item.
|
||||
var texturePath = jarFile.findResource("assets/" + modid + "/textures/" + texture + ".png");
|
||||
|
||||
if (Files.exists(texturePath)) {
|
||||
try (var stream = Files.newInputStream(texturePath)) {
|
||||
var img = ImageIO.read(stream);
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
int pixels = 0;
|
||||
int totalR = 0;
|
||||
int totalG = 0;
|
||||
int totalB = 0;
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
int pixel = img.getRGB(x, y);
|
||||
if (pixel != 0) {
|
||||
totalR += (pixel >> 16) & 0xff;
|
||||
totalG += (pixel >> 8) & 0xff;
|
||||
totalB += (pixel) & 0xff;
|
||||
pixels++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
putColor(pixels, totalR, totalG, totalB, entry.getValue());
|
||||
|
||||
if (ExDeorum.DEBUG) {
|
||||
ExDeorum.LOGGER.debug("Item {}:{} has color {}", modid, id, COLORS.get(entry.getValue()));
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
ExDeorum.LOGGER.error("Failed to read texture file for item {}:{}", modid, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo should i sort the registry before iterating it, or should I keep the sort here?
|
||||
Map<String, List<Item>> entries = COLORS.keySet().stream()
|
||||
.sorted(Comparator.comparing(BuiltInRegistries.ITEM::getKey))
|
||||
.collect(Collectors.groupingBy(item -> BuiltInRegistries.ITEM.getKey(item).getNamespace()));
|
||||
|
||||
for (var entry : entries.entrySet()) {
|
||||
if (!readMods.contains(entry.getKey())) {
|
||||
export(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String findFirstTexture(JsonObject textureMap) {
|
||||
if (textureMap.get("layer0") instanceof JsonPrimitive primitive) {
|
||||
return Identifier.parse(primitive.getAsString()).getPath();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Returns a set of the mod ids that were read
|
||||
private static ObjectSet<String> readModdedColorFiles() {
|
||||
var colorsFolder = COMPOST_COLORS_CONFIGS.toFile();
|
||||
if (!colorsFolder.exists() || !colorsFolder.isDirectory()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Minecraft is hardcoded in the Ex Deorum jar file
|
||||
var readMods = new ObjectOpenHashSet<String>();
|
||||
readMods.add("minecraft");
|
||||
var children = colorsFolder.list();
|
||||
if (children == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (colorsFolder.exists() && colorsFolder.isDirectory()) {
|
||||
var children = colorsFolder.list();
|
||||
for (var child : children) {
|
||||
if (!child.endsWith(".txt")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (children != null) {
|
||||
// child should be "modid.txt"
|
||||
for (var child : children) {
|
||||
if (child.endsWith(".txt")) {
|
||||
var modid = child.replace(".txt", "");
|
||||
var modid = child.substring(0, child.length() - 4);
|
||||
var path = COMPOST_COLORS_CONFIGS.resolve(child);
|
||||
try (var reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
|
||||
readColorEntries(modid, reader, path.toString());
|
||||
} catch (IOException exception) {
|
||||
ExDeorum.LOGGER.error("Error reading compost colors file {}", path, exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ModList.get().isLoaded(modid) && !modid.equals("minecraft")) {
|
||||
if (readColorFile(modid, COMPOST_COLORS_CONFIGS.resolve(child))) {
|
||||
readMods.add(modid);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void readColorEntries(String modid, BufferedReader reader, String source) throws IOException {
|
||||
int lineNumber = 0;
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lineNumber++;
|
||||
if (line.isBlank() || line.startsWith("//")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var tokenizer = new StringTokenizer(line, ", #");
|
||||
try {
|
||||
var id = Identifier.fromNamespaceAndPath(modid, tokenizer.nextToken());
|
||||
var item = BuiltInRegistries.ITEM.get(id).map(reference -> reference.value()).orElse(Items.AIR);
|
||||
int color = Integer.parseInt(tokenizer.nextToken(), 16);
|
||||
|
||||
if (item == Items.AIR) {
|
||||
ExDeorum.LOGGER.error("Unknown item {} in compost colors source {} line {}", id, source, lineNumber);
|
||||
continue;
|
||||
}
|
||||
|
||||
COLORS.put(item, new Vector3i((color >> 16) & 255, (color >> 8) & 255, color & 255));
|
||||
} catch (IllegalArgumentException | NoSuchElementException exception) {
|
||||
ExDeorum.LOGGER.error("Invalid compost color entry in {} line {}", source, lineNumber, exception);
|
||||
}
|
||||
}
|
||||
|
||||
return readMods;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static JsonObject parseModelJson(Path modelPath, String modid, String id) {
|
||||
try (var stream = Files.newInputStream(modelPath)) {
|
||||
try (var streamReader = new InputStreamReader(stream)) {
|
||||
try {
|
||||
return GsonHelper.parse(IOUtils.toString(streamReader));
|
||||
} catch (JsonParseException exception) {
|
||||
ExDeorum.LOGGER.error("Failed to parse model file for item {}:{}", modid, id);
|
||||
}
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
ExDeorum.LOGGER.error("Failed to read model file for item {}:{}", modid, id);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void putColor(int pixels, int totalR, int totalG, int totalB, Item item) {
|
||||
if (pixels > 0 && (totalR | totalG | totalB) != 0) {
|
||||
var tint = getTint(item);
|
||||
Color c;
|
||||
if (tint == 0) {
|
||||
c = new Color(totalR / pixels, totalG / pixels, totalB / pixels).brighter();
|
||||
} else {
|
||||
c = new Color(
|
||||
((float) totalR / pixels / 255f) * ((tint >> 16 & 0xff) / 255f),
|
||||
((float) totalG / pixels / 255f) * ((tint >> 8 & 0xff) / 255f),
|
||||
((float) totalB / pixels / 255f) * ((tint & 0xff) / 255f)
|
||||
);
|
||||
}
|
||||
|
||||
Vector3i color = new Vector3i(c.getRed(), c.getGreen(), c.getBlue());
|
||||
CompostColors.COLORS.put(item, color);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getTint(Item item) {
|
||||
if (ExDeorum.DEBUG && FMLEnvironment.dist == Dist.CLIENT) {
|
||||
return Minecraft.getInstance().getItemColors().getColor(new ItemStack(item), 0);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean readColorFile(String modid, Path path) {
|
||||
try (var stream = Files.newInputStream(path)) {
|
||||
try (var streamReader = new InputStreamReader(stream)) {
|
||||
try (var reader = new BufferedReader(streamReader)) {
|
||||
int readColors = 0;
|
||||
int lineNumber = 0;
|
||||
String line;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lineNumber++;
|
||||
if (line.startsWith("//")) continue;
|
||||
|
||||
var tokenizer = new StringTokenizer(line, ", #");
|
||||
try {
|
||||
var id = Identifier.fromNamespaceAndPath(modid, tokenizer.nextToken());
|
||||
var item = BuiltInRegistries.ITEM.get(id);
|
||||
String token = tokenizer.nextToken();
|
||||
var color = Integer.parseInt(token, 16);
|
||||
|
||||
if (item != Items.AIR) {
|
||||
readColors++;
|
||||
|
||||
COLORS.put(item, new Vector3i(
|
||||
(color >> 16) & 255,
|
||||
(color >> 8) & 255,
|
||||
(color) & 255
|
||||
));
|
||||
} else {
|
||||
ExDeorum.LOGGER.error("Failed to read line {} of compost colors file {} - Unknown item {}", lineNumber, path, id);
|
||||
}
|
||||
} catch (NumberFormatException | NoSuchElementException e) {
|
||||
ExDeorum.LOGGER.error("Failed to read line {} of compost colors file {} - Invalid format: {}", lineNumber, path, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (readColors > 0) {
|
||||
ExDeorum.LOGGER.debug("Read {} compost colors from compost colors file {}", readColors, path);
|
||||
return true;
|
||||
} else {
|
||||
ExDeorum.LOGGER.debug("Ignoring empty compost colors file {}", path);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
ExDeorum.LOGGER.error("Error reading colors file {} : {}", path, e);
|
||||
}
|
||||
|
||||
return false;
|
||||
public static void debugCompute() {
|
||||
throw new UnsupportedOperationException("debugCompute is not ported to MC 26.x");
|
||||
}
|
||||
|
||||
public static void export(String modid) {
|
||||
export(modid, COLORS.keySet().stream().filter(key -> BuiltInRegistries.ITEM.getKey(key).getNamespace().equals(modid)).sorted(Comparator.comparing(BuiltInRegistries.ITEM::getKey)).toList());
|
||||
export(modid, COLORS.keySet().stream()
|
||||
.filter(item -> BuiltInRegistries.ITEM.getKey(item).getNamespace().equals(modid))
|
||||
.sorted(Comparator.comparing(BuiltInRegistries.ITEM::getKey))
|
||||
.toList());
|
||||
}
|
||||
|
||||
// The given list should be sorted
|
||||
private static void export(String modid, List<Item> sortedToExport) {
|
||||
try {
|
||||
if (createConfigFolder(COMPOST_COLORS_CONFIGS)) {
|
||||
var path = COMPOST_COLORS_CONFIGS.resolve(modid + ".txt");
|
||||
var file = path.toFile();
|
||||
|
||||
if ((file.exists() && file.delete()) || file.createNewFile()) {
|
||||
try (var fileWriter = new FileWriter(file)) {
|
||||
try (var writer = new BufferedWriter(fileWriter)) {
|
||||
// sort file entries alphabetically
|
||||
var alphabeticalItems = new ArrayList<>(sortedToExport);
|
||||
alphabeticalItems.sort(Comparator.comparing(item -> BuiltInRegistries.ITEM.getKey(item).getPath()));
|
||||
|
||||
writer.write("// Compost colors for " + modid + ". You may add your own colors, change existing ones, or remove colors that aren't needed.\n");
|
||||
|
||||
for (var item : alphabeticalItems) {
|
||||
if (COLORS.containsKey(item)) {
|
||||
writer.write(BuiltInRegistries.ITEM.getKey(item).getPath());
|
||||
writer.write(", #");
|
||||
var colorVec = COLORS.get(item);
|
||||
writer.write(Integer.toHexString(new Color(colorVec.x, colorVec.y, colorVec.z).getRGB() & 0xffffff));
|
||||
writer.write('\n');
|
||||
}
|
||||
}
|
||||
|
||||
// Skips the error message
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!createConfigFolder(COMPOST_COLORS_CONFIGS)) {
|
||||
ExDeorum.LOGGER.error("Unable to create compost color config folder for {}", modid);
|
||||
return;
|
||||
}
|
||||
|
||||
ExDeorum.LOGGER.error("Unable to save compost colors for mod \"{}\"", modid);
|
||||
} catch (IOException e) {
|
||||
ExDeorum.LOGGER.error("Encountered exception while trying to save compost colors for mod \"{}\"", modid, e);
|
||||
var path = COMPOST_COLORS_CONFIGS.resolve(modid + ".txt");
|
||||
try (var writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
|
||||
writer.write("// Compost colors for " + modid + ".\n");
|
||||
|
||||
var alphabeticalItems = new ArrayList<>(sortedToExport);
|
||||
alphabeticalItems.sort(Comparator.comparing(item -> BuiltInRegistries.ITEM.getKey(item).getPath()));
|
||||
|
||||
for (var item : alphabeticalItems) {
|
||||
var color = COLORS.get(item);
|
||||
if (color == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
writer.write(BuiltInRegistries.ITEM.getKey(item).getPath());
|
||||
writer.write(", #");
|
||||
writer.write(String.format("%02x%02x%02x", color.x, color.y, color.z));
|
||||
writer.write('\n');
|
||||
}
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
throw new UncheckedIOException("Failed to export compost colors for " + modid, exception);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean createConfigFolder(Path configPath) {
|
||||
var colorsFolder = configPath.toFile();
|
||||
var configFolder = configPath.getParent().toFile();
|
||||
|
||||
return (configFolder.exists() || configFolder.mkdir()) && (colorsFolder.exists() || colorsFolder.mkdir());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,12 +23,19 @@ import com.mojang.blaze3d.vertex.VertexConsumer;
|
|||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.Sheets;
|
||||
import net.minecraft.client.renderer.block.BlockAndTintGetter;
|
||||
import net.minecraft.client.renderer.block.FluidModel;
|
||||
import net.minecraft.client.renderer.block.dispatch.BlockStateModelPart;
|
||||
import net.minecraft.client.renderer.rendertype.RenderType;
|
||||
import net.minecraft.client.renderer.texture.MissingTextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlas;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.inventory.InventoryMenu;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
|
|
@ -37,14 +44,15 @@ import thedarkcolour.exdeorum.ExDeorum;
|
|||
import thedarkcolour.exdeorum.client.ter.SieveRenderer;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class RenderUtil {
|
||||
private static final Map<Block, RenderFace> TOP_FACES = new HashMap<>();
|
||||
// TODO: port TINTED_CUTOUT_MIPPED to MC 26.x RenderSetup API (RenderStateShard/CompositeState removed)
|
||||
public static final Object TINTED_CUTOUT_MIPPED = null;
|
||||
public static TextureAtlas blockAtlas;
|
||||
public static final RenderType TINTED_CUTOUT_MIPPED = Sheets.cutoutBlockItemSheet();
|
||||
public static final IrisAccess IRIS_ACCESS;
|
||||
|
||||
static {
|
||||
|
|
@ -53,49 +61,40 @@ public class RenderUtil {
|
|||
|
||||
public static void reload() {
|
||||
invalidateCaches();
|
||||
blockAtlas = Minecraft.getInstance().getModelManager().getAtlas(InventoryMenu.BLOCK_ATLAS);
|
||||
}
|
||||
|
||||
public static void invalidateCaches() {
|
||||
SieveRenderer.MESH_TEXTURES.clear();
|
||||
TOP_FACES.clear();
|
||||
blockAtlas = null;
|
||||
}
|
||||
|
||||
// TODO: port getTopFace to MC 26.x (BakedModel/BlockRenderDispatcher removed; use FluidStateModelSet/BlockStateModelSet)
|
||||
public static RenderFace getTopFaceOrDefault(Block block, Block defaultBlock) {
|
||||
return getTopFace(block);
|
||||
var face = getTopFace(block);
|
||||
return face.isMissingTexture() ? getTopFace(defaultBlock) : face;
|
||||
}
|
||||
|
||||
public static RenderFace getTopFace(Block block) {
|
||||
return TOP_FACES.computeIfAbsent(block, b -> {
|
||||
// TODO: implement using 26.x block model API
|
||||
// Placeholder: use missing texture sprite
|
||||
var sprite = blockAtlas != null ? blockAtlas.getSprite(MissingTextureAtlasSprite.getLocation()) : null;
|
||||
return new RenderFace.Single(null, sprite);
|
||||
});
|
||||
return TOP_FACES.computeIfAbsent(block, RenderUtil::loadTopFace);
|
||||
}
|
||||
|
||||
public static boolean isMissingTexture(TextureAtlasSprite sprite) {
|
||||
return sprite.contents().name() == MissingTextureAtlasSprite.getLocation();
|
||||
}
|
||||
|
||||
// TODO: port renderFlatFluidSprite to 26.x (IClientFluidTypeExtensions no longer has getStillTexture/getTintColor)
|
||||
public static void renderFlatFluidSprite(MultiBufferSource buffers, PoseStack stack, Level level, BlockPos pos, float y, float edge, int light, int r, int g, int b, Fluid fluid) {
|
||||
if (blockAtlas == null) return;
|
||||
var builder = buffers.getBuffer(Sheets.translucentBlockSheet());
|
||||
// Use a placeholder sprite until fluid model system is ported
|
||||
var sprite = blockAtlas.getSprite(MissingTextureAtlasSprite.getLocation());
|
||||
var builder = buffers.getBuffer(getFluidRenderType(fluid));
|
||||
var sprite = getFluidSprite(fluid);
|
||||
RenderUtil.renderFlatSprite(builder, stack, y, r, g, b, sprite, light, edge);
|
||||
}
|
||||
|
||||
// TODO: port renderFluidCube to 26.x (IClientFluidTypeExtensions no longer has getStillTexture/getTintColor)
|
||||
public static void renderFlatFluidSprite(VertexConsumer builder, PoseStack.Pose pose, float y, float edge, int light, int r, int g, int b, Fluid fluid) {
|
||||
RenderUtil.renderFlatSprite(builder, pose, y, r, g, b, getFluidSprite(fluid), light, edge);
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public static void renderFluidCube(MultiBufferSource buffers, PoseStack stack, Level level, BlockPos pos, float minY, float maxY, float edge, int light, int r, int g, int b, Fluid fluid) {
|
||||
if (blockAtlas == null) return;
|
||||
var builder = buffers.getBuffer(Sheets.translucentBlockSheet());
|
||||
// Use a placeholder sprite until fluid model system is ported
|
||||
var sprite = blockAtlas.getSprite(MissingTextureAtlasSprite.getLocation());
|
||||
var builder = buffers.getBuffer(getFluidRenderType(fluid));
|
||||
var sprite = getFluidSprite(fluid);
|
||||
|
||||
var pose = stack.last().pose();
|
||||
var poseNormal = stack.last().normal();
|
||||
|
|
@ -148,12 +147,21 @@ public class RenderUtil {
|
|||
builder.addVertex(pose, edgeMin, minY, edgeMax).setColor(r, g, b, 255).setUv(uMax, vMax).setUv1(0, 10).setLight(light).setNormal(normal.x, normal.y, normal.z);
|
||||
}
|
||||
|
||||
public static void renderFluidCube(VertexConsumer builder, PoseStack.Pose pose, float minY, float maxY, float edge, int light, int r, int g, int b, Fluid fluid) {
|
||||
RenderUtil.renderCuboid(builder, pose, minY, maxY, r, g, b, getFluidSprite(fluid), light, edge);
|
||||
}
|
||||
|
||||
// Renders a sprite inside the barrel with the height determined by how full the barrel is.
|
||||
public static void renderFlatSpriteLerp(VertexConsumer builder, PoseStack stack, float percentage, int r, int g, int b, TextureAtlasSprite sprite, int light, float edge, float yMin, float yMax) {
|
||||
float y = Mth.lerp(percentage, yMin, yMax) / 16f;
|
||||
renderFlatSprite(builder, stack, y, r, g, b, sprite, light, edge);
|
||||
}
|
||||
|
||||
public static void renderFlatSpriteLerp(VertexConsumer builder, PoseStack.Pose pose, float percentage, int r, int g, int b, TextureAtlasSprite sprite, int light, float edge, float yMin, float yMax) {
|
||||
float y = Mth.lerp(percentage, yMin, yMax) / 16f;
|
||||
renderFlatSprite(builder, pose, y, r, g, b, sprite, light, edge);
|
||||
}
|
||||
|
||||
// Renders a sprite (y should be between 0 and 1)
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public static void renderFlatSprite(VertexConsumer builder, PoseStack stack, float y, int r, int g, int b, TextureAtlasSprite sprite, int light, float edge) {
|
||||
|
|
@ -178,13 +186,95 @@ public class RenderUtil {
|
|||
builder.addVertex(pose, edgeMax, y, edgeMin).setColor(r, g, b, 255).setUv(uMax, vMin).setUv1(0, 10).setLight(light).setNormal(normal.x, normal.y, normal.z);
|
||||
}
|
||||
|
||||
public static void renderFlatSprite(VertexConsumer builder, PoseStack.Pose pose, float y, int r, int g, int b, TextureAtlasSprite sprite, int light, float edge) {
|
||||
if (sprite == null) return;
|
||||
var normal = pose.normal().transform(new Vector3f(0, 1, 0));
|
||||
float edgeMin = edge / 16.0f;
|
||||
float edgeMax = (16.0f - edge) / 16.0f;
|
||||
float uMin = sprite.getU0();
|
||||
float uMax = sprite.getU1();
|
||||
float vMin = sprite.getV0();
|
||||
float vMax = sprite.getV1();
|
||||
|
||||
builder.addVertex(pose.pose(), edgeMin, y, edgeMin).setColor(r, g, b, 255).setUv(uMin, vMin).setUv1(0, 10).setLight(light).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMin, y, edgeMax).setColor(r, g, b, 255).setUv(uMin, vMax).setUv1(0, 10).setLight(light).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMax, y, edgeMax).setColor(r, g, b, 255).setUv(uMax, vMax).setUv1(0, 10).setLight(light).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMax, y, edgeMin).setColor(r, g, b, 255).setUv(uMax, vMin).setUv1(0, 10).setLight(light).setNormal(normal.x, normal.y, normal.z);
|
||||
}
|
||||
|
||||
public static Color getRainbowColor(long time, float partialTicks) {
|
||||
return Color.getHSBColor((180 * Mth.sin((time + partialTicks) / 30.0f) - 180) / 360.0f, 0.5f, 0.8f);
|
||||
}
|
||||
|
||||
// TODO: port getFluidColor to 26.x (IClientFluidTypeExtensions no longer has getTintColor)
|
||||
public static TextureAtlasSprite getBlockSprite(Identifier location) {
|
||||
return ((TextureAtlas) Minecraft.getInstance().getTextureManager().getTexture(TextureAtlas.LOCATION_BLOCKS)).getSprite(location);
|
||||
}
|
||||
|
||||
public static int getFluidColor(Fluid fluid, Level level, BlockPos pos) {
|
||||
return -1; // white/no tint; use FluidModel.fluidTintSource() in 26.x
|
||||
var tintSource = getFluidModel(fluid).fluidTintSource();
|
||||
if (tintSource == null) {
|
||||
return -1;
|
||||
}
|
||||
if (level instanceof BlockAndTintGetter getter) {
|
||||
return tintSource.colorInWorld(fluid.defaultFluidState(), level.getBlockState(pos), getter, pos);
|
||||
}
|
||||
return tintSource.color(fluid.defaultFluidState());
|
||||
}
|
||||
|
||||
private static RenderFace loadTopFace(Block block) {
|
||||
var state = block.defaultBlockState();
|
||||
var model = Minecraft.getInstance().getModelManager().getBlockStateModelSet().get(state);
|
||||
var random = RandomSource.create(block.hashCode());
|
||||
List<BlockStateModelPart> parts = new ArrayList<>();
|
||||
model.collectParts(BlockAndTintGetter.EMPTY, BlockPos.ZERO, state, random, parts);
|
||||
|
||||
var layers = new LinkedHashMap<String, RenderFace.CompositeLayer>();
|
||||
for (var part : parts) {
|
||||
for (var quad : part.getQuads(Direction.UP)) {
|
||||
var materialInfo = quad.materialInfo();
|
||||
var key = materialInfo.itemRenderType() + "::" + materialInfo.sprite().contents().name();
|
||||
layers.putIfAbsent(key, new RenderFace.CompositeLayer(materialInfo.itemRenderType(), materialInfo.sprite()));
|
||||
}
|
||||
}
|
||||
|
||||
if (layers.isEmpty()) {
|
||||
var particle = getTopTexture(block, state);
|
||||
return new RenderFace.Single(inferMaterialRenderType(particle), particle);
|
||||
}
|
||||
|
||||
if (layers.size() == 1) {
|
||||
return new RenderFace.Single(layers.values().iterator().next().renderType(), layers.values().iterator().next().sprite());
|
||||
}
|
||||
|
||||
return new RenderFace.Composite(layers.values().toArray(RenderFace.CompositeLayer[]::new));
|
||||
}
|
||||
|
||||
private static TextureAtlasSprite getTopTexture(Block block, net.minecraft.world.level.block.state.BlockState state) {
|
||||
var registryName = BuiltInRegistries.BLOCK.getKey(block);
|
||||
var sprite = getBlockSprite(registryName.withPrefix("block/"));
|
||||
if (isMissingTexture(sprite)) {
|
||||
sprite = getBlockSprite(Identifier.fromNamespaceAndPath(registryName.getNamespace(), "block/" + registryName.getPath() + "_top"));
|
||||
}
|
||||
if (isMissingTexture(sprite)) {
|
||||
sprite = Minecraft.getInstance().getModelManager().getBlockStateModelSet().getParticleMaterial(state).sprite();
|
||||
}
|
||||
return sprite;
|
||||
}
|
||||
|
||||
private static RenderType inferMaterialRenderType(TextureAtlasSprite sprite) {
|
||||
return sprite.transparency().hasTranslucent() ? Sheets.translucentBlockItemSheet() : Sheets.cutoutBlockItemSheet();
|
||||
}
|
||||
|
||||
private static FluidModel getFluidModel(Fluid fluid) {
|
||||
return Minecraft.getInstance().getModelManager().getFluidStateModelSet().get(fluid.defaultFluidState());
|
||||
}
|
||||
|
||||
public static TextureAtlasSprite getFluidSprite(Fluid fluid) {
|
||||
return getFluidModel(fluid).stillMaterial().sprite();
|
||||
}
|
||||
|
||||
public static RenderType getFluidRenderType(Fluid fluid) {
|
||||
return getFluidModel(fluid).layer().translucent() ? Sheets.translucentBlockItemSheet() : Sheets.cutoutBlockItemSheet();
|
||||
}
|
||||
|
||||
// todo use ambient occlusion
|
||||
|
|
@ -249,6 +339,62 @@ public class RenderUtil {
|
|||
builder.addVertex(pose, edgeMin, minY, edgeMax).setColor(r, g, b, 255).setUv(uMax, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
}
|
||||
|
||||
public static void renderCuboid(VertexConsumer builder, PoseStack.Pose pose, float minY, float maxY, int r, int g, int b, TextureAtlasSprite sprite, int light, float edge) {
|
||||
if (sprite == null) return;
|
||||
var poseNormal = pose.normal();
|
||||
|
||||
Vector3f normal;
|
||||
float uMin = sprite.getU0();
|
||||
float uMax = sprite.getU1();
|
||||
float vMin = sprite.getV0();
|
||||
float vMax = sprite.getV1();
|
||||
|
||||
float edgeMin = edge / 16f;
|
||||
float edgeMax = 1f - edge / 16f;
|
||||
|
||||
int lightU = light & '\uffff';
|
||||
int lightV = light >> 16 & '\uffff';
|
||||
|
||||
normal = poseNormal.transform(new Vector3f(0, 1, 0));
|
||||
builder.addVertex(pose.pose(), edgeMin, maxY, edgeMin).setColor(r, g, b, 255).setUv(uMin, vMin).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMin, maxY, edgeMax).setColor(r, g, b, 255).setUv(uMin, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMax, maxY, edgeMax).setColor(r, g, b, 255).setUv(uMax, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMax, maxY, edgeMin).setColor(r, g, b, 255).setUv(uMax, vMin).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
|
||||
normal = poseNormal.transform(new Vector3f(0, -1, 0));
|
||||
builder.addVertex(pose.pose(), edgeMin, minY, edgeMin).setColor(r, g, b, 255).setUv(uMin, vMin).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMax, minY, edgeMin).setColor(r, g, b, 255).setUv(uMax, vMin).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMax, minY, edgeMax).setColor(r, g, b, 255).setUv(uMax, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMin, minY, edgeMax).setColor(r, g, b, 255).setUv(uMin, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
|
||||
float f = sprite.getV1() - sprite.getV0();
|
||||
vMax = sprite.getV0() + f * (maxY - minY);
|
||||
|
||||
normal = poseNormal.transform(new Vector3f(0, 0, -1));
|
||||
builder.addVertex(pose.pose(), edgeMax, maxY, edgeMax).setColor(r, g, b, 255).setUv(uMax, vMin).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMin, maxY, edgeMax).setColor(r, g, b, 255).setUv(uMin, vMin).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMin, minY, edgeMax).setColor(r, g, b, 255).setUv(uMin, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMax, minY, edgeMax).setColor(r, g, b, 255).setUv(uMax, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
|
||||
normal = poseNormal.transform(new Vector3f(0, 0, -1));
|
||||
builder.addVertex(pose.pose(), edgeMin, maxY, edgeMin).setColor(r, g, b, 255).setUv(uMin, vMin).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMax, maxY, edgeMin).setColor(r, g, b, 255).setUv(uMax, vMin).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMax, minY, edgeMin).setColor(r, g, b, 255).setUv(uMax, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMin, minY, edgeMin).setColor(r, g, b, 255).setUv(uMin, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
|
||||
normal = poseNormal.transform(new Vector3f(1, 0, 0));
|
||||
builder.addVertex(pose.pose(), edgeMax, maxY, edgeMin).setColor(r, g, b, 255).setUv(uMin, vMin).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMax, maxY, edgeMax).setColor(r, g, b, 255).setUv(uMax, vMin).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMax, minY, edgeMax).setColor(r, g, b, 255).setUv(uMax, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMax, minY, edgeMin).setColor(r, g, b, 255).setUv(uMin, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
|
||||
normal = poseNormal.transform(new Vector3f(-1, 0, 0));
|
||||
builder.addVertex(pose.pose(), edgeMin, maxY, edgeMax).setColor(r, g, b, 255).setUv(uMax, vMin).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMin, maxY, edgeMin).setColor(r, g, b, 255).setUv(uMin, vMin).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMin, minY, edgeMin).setColor(r, g, b, 255).setUv(uMin, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
builder.addVertex(pose.pose(), edgeMin, minY, edgeMax).setColor(r, g, b, 255).setUv(uMax, vMax).setUv1(0, 10).setUv2(lightU, lightV).setNormal(normal.x, normal.y, normal.z);
|
||||
}
|
||||
|
||||
public interface IrisAccess {
|
||||
boolean areShadersEnabled();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,10 +43,7 @@ public class MechanicalHammerScreen extends AbstractContainerScreen<MechanicalHa
|
|||
private RedstoneControlWidget redstoneControlWidget;
|
||||
|
||||
public MechanicalHammerScreen(MechanicalHammerMenu menu, Inventory playerInventory, Component title) {
|
||||
super(menu, playerInventory, title);
|
||||
|
||||
this.imageWidth = 176;
|
||||
this.imageHeight = 166;
|
||||
super(menu, playerInventory, title, 176, 166);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -44,10 +44,8 @@ public class MechanicalSieveScreen extends AbstractContainerScreen<MechanicalSie
|
|||
private RedstoneControlWidget redstoneControlWidget;
|
||||
|
||||
public MechanicalSieveScreen(MechanicalSieveMenu menu, Inventory playerInventory, Component title) {
|
||||
super(menu, playerInventory, title);
|
||||
super(menu, playerInventory, title, 176, 173);
|
||||
|
||||
this.imageWidth = 176;
|
||||
this.imageHeight = 173;
|
||||
this.inventoryLabelY += 7;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package thedarkcolour.exdeorum.client.screen;
|
|||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.input.MouseButtonEvent;
|
||||
import net.minecraft.client.gui.GuiGraphicsExtractor;
|
||||
import net.minecraft.client.gui.components.Renderable;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
|
|
@ -128,7 +129,11 @@ public class RedstoneControlWidget implements GuiEventListener, NarratableEntry,
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||
public boolean mouseClicked(MouseButtonEvent event, boolean focused) {
|
||||
return handleMouseClicked(event.x(), event.y(), event.button());
|
||||
}
|
||||
|
||||
private boolean handleMouseClicked(double mouseX, double mouseY, int button) {
|
||||
// relative xy
|
||||
int mx = (int) mouseX;
|
||||
int my = (int) mouseY;
|
||||
|
|
|
|||
|
|
@ -19,26 +19,174 @@
|
|||
package thedarkcolour.exdeorum.client.ter;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.renderer.state.level.CameraRenderState;
|
||||
import com.mojang.math.Axis;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.block.BlockModelRenderState;
|
||||
import net.minecraft.client.renderer.block.model.BlockDisplayContext;
|
||||
import net.minecraft.client.renderer.state.level.CameraRenderState;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||
import net.minecraft.client.renderer.rendertype.RenderTypes;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.block.BarrelBlock;
|
||||
import thedarkcolour.exdeorum.blockentity.BarrelBlockEntity;
|
||||
import thedarkcolour.exdeorum.client.RenderUtil;
|
||||
import thedarkcolour.exdeorum.config.EConfig;
|
||||
|
||||
// TODO: port BarrelRenderer to MC 26.x rendering API (BlockEntityRenderer changed to extract/submit pattern,
|
||||
// BlockRenderDispatcher/ItemRenderer removed, fluid color/texture APIs changed)
|
||||
public class BarrelRenderer implements BlockEntityRenderer<BarrelBlockEntity, BlockEntityRenderState> {
|
||||
public class BarrelRenderer implements BlockEntityRenderer<BarrelBlockEntity, BarrelRenderer.BarrelRenderState> {
|
||||
public static final Identifier COMPOST_DIRT_TEXTURE = ExDeorum.loc("block/compost_dirt");
|
||||
private static final BlockDisplayContext BLOCK_DISPLAY_CONTEXT = BlockDisplayContext.create();
|
||||
private final net.minecraft.client.renderer.block.BlockModelResolver blockModelResolver;
|
||||
private final ItemModelResolver itemModelResolver;
|
||||
|
||||
@Override
|
||||
public BlockEntityRenderState createRenderState() {
|
||||
return new BlockEntityRenderState();
|
||||
public BarrelRenderer(BlockEntityRendererProvider.Context ctx) {
|
||||
this.blockModelResolver = ctx.blockModelResolver();
|
||||
this.itemModelResolver = ctx.itemModelResolver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submit(BlockEntityRenderState state, PoseStack stack, SubmitNodeCollector collector, CameraRenderState cameraState) {
|
||||
// TODO: implement barrel fluid/compost/item rendering using new 26.x rendering API
|
||||
public BarrelRenderState createRenderState() {
|
||||
return new BarrelRenderState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extractRenderState(BarrelBlockEntity barrel, BarrelRenderState state, float partialTicks, net.minecraft.world.phys.Vec3 cameraPosition, net.minecraft.client.renderer.feature.ModelFeatureRenderer.CrumblingOverlay breakProgress) {
|
||||
BlockEntityRenderer.super.extractRenderState(barrel, state, partialTicks, cameraPosition, breakProgress);
|
||||
|
||||
state.blockItemModel.clear();
|
||||
state.outputItem.clear();
|
||||
state.renderBlockItem = false;
|
||||
state.fluid = null;
|
||||
state.hasFluid = false;
|
||||
state.hasCompost = false;
|
||||
state.transparent = barrel.transparent;
|
||||
|
||||
var item = barrel.getItem();
|
||||
if (!item.isEmpty()) {
|
||||
if (item.getItem() instanceof BlockItem blockItem) {
|
||||
this.blockModelResolver.update(state.blockItemModel, blockItem.getBlock().defaultBlockState(), BLOCK_DISPLAY_CONTEXT);
|
||||
state.renderBlockItem = true;
|
||||
} else {
|
||||
this.itemModelResolver.updateForTopItem(state.outputItem, item, ItemDisplayContext.FIXED, barrel.getLevel(), null, 0);
|
||||
}
|
||||
}
|
||||
|
||||
var fluidStack = barrel.getTank().getFluidInTank(0);
|
||||
if (!fluidStack.isEmpty() && barrel.getLevel() != null) {
|
||||
var fluid = fluidStack.getFluid();
|
||||
var percentage = fluidStack.getAmount() / 1000.0f;
|
||||
var y = Mth.lerp(percentage, BarrelBlock.BARREL_FLUID_BOTTOM, BarrelBlock.BARREL_FLUID_TOP);
|
||||
var inputFluidColor = RenderUtil.getFluidColor(fluid, barrel.getLevel(), barrel.getBlockPos());
|
||||
int r = (inputFluidColor >> 16) & 0xff;
|
||||
int g = (inputFluidColor >> 8) & 0xff;
|
||||
int b = inputFluidColor & 0xff;
|
||||
|
||||
if (barrel.isBrewing()) {
|
||||
float progress = barrel.progress;
|
||||
r = (int) Mth.lerp(progress, r, barrel.r);
|
||||
g = (int) Mth.lerp(progress, g, barrel.g);
|
||||
b = (int) Mth.lerp(progress, b, barrel.b);
|
||||
}
|
||||
|
||||
state.fluid = fluid;
|
||||
state.hasFluid = true;
|
||||
state.fluidY = y;
|
||||
state.fluidColor = packRgb(r, g, b);
|
||||
}
|
||||
|
||||
if (barrel.compost > 0) {
|
||||
float compostProgress = barrel.progress;
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
|
||||
if (ExDeorum.IS_JUNE && EConfig.CLIENT.rainbowCompostDuringJune.get() && barrel.getLevel() != null) {
|
||||
var rainbow = RenderUtil.getRainbowColor(barrel.getLevel().getGameTime(), partialTicks);
|
||||
r = rainbow.getRed();
|
||||
g = rainbow.getGreen();
|
||||
b = rainbow.getBlue();
|
||||
} else {
|
||||
r = barrel.r;
|
||||
g = barrel.g;
|
||||
b = barrel.b;
|
||||
}
|
||||
|
||||
r = (int) Mth.lerp(compostProgress, r, 238);
|
||||
g = (int) Mth.lerp(compostProgress, g, 169);
|
||||
b = (int) Mth.lerp(compostProgress, b, 109);
|
||||
|
||||
state.hasCompost = true;
|
||||
state.compostPercentage = barrel.compost / 1000.0f;
|
||||
state.compostColor = packRgb(r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submit(BarrelRenderState state, PoseStack stack, SubmitNodeCollector collector, CameraRenderState cameraState) {
|
||||
if (state.renderBlockItem && !state.blockItemModel.isEmpty()) {
|
||||
stack.pushPose();
|
||||
stack.translate(2 / 16f, 2 / 16f, 2 / 16f);
|
||||
stack.scale(12 / 16f, 12 / 16f, 12 / 16f);
|
||||
state.blockItemModel.submitMultiLayer(stack, collector, state.lightCoords, OverlayTexture.NO_OVERLAY, 0);
|
||||
stack.popPose();
|
||||
} else if (!state.outputItem.isEmpty()) {
|
||||
stack.pushPose();
|
||||
stack.translate(0.5, 1.5 / 16f + (state.hasFluid ? state.fluidY : 0.0f), 0.5);
|
||||
stack.mulPose(Axis.XP.rotation(Mth.HALF_PI));
|
||||
state.outputItem.submit(stack, collector, state.lightCoords, OverlayTexture.NO_OVERLAY, 0);
|
||||
stack.popPose();
|
||||
}
|
||||
|
||||
if (state.hasFluid && state.fluid != null) {
|
||||
int r = (state.fluidColor >> 16) & 0xff;
|
||||
int g = (state.fluidColor >> 8) & 0xff;
|
||||
int b = state.fluidColor & 0xff;
|
||||
if (state.transparent) {
|
||||
collector.submitCustomGeometry(stack, RenderUtil.getFluidRenderType(state.fluid), (pose, buffer) ->
|
||||
RenderUtil.renderFluidCube(buffer, pose, BarrelBlock.BARREL_FLUID_BOTTOM, state.fluidY, 2.0f, state.lightCoords, r, g, b, state.fluid)
|
||||
);
|
||||
} else {
|
||||
collector.submitCustomGeometry(stack, RenderUtil.getFluidRenderType(state.fluid), (pose, buffer) ->
|
||||
RenderUtil.renderFlatFluidSprite(buffer, pose, state.fluidY, 2.0f, state.lightCoords, r, g, b, state.fluid)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.hasCompost) {
|
||||
var sprite = RenderUtil.getBlockSprite(COMPOST_DIRT_TEXTURE);
|
||||
int r = (state.compostColor >> 16) & 0xff;
|
||||
int g = (state.compostColor >> 8) & 0xff;
|
||||
int b = state.compostColor & 0xff;
|
||||
collector.submitCustomGeometry(stack, RenderUtil.TINTED_CUTOUT_MIPPED, (pose, buffer) ->
|
||||
RenderUtil.renderFlatSpriteLerp(buffer, pose, state.compostPercentage, r, g, b, sprite, state.lightCoords, 2.0f, BarrelBlock.BARREL_FLUID_BOTTOM * 16f, BarrelBlock.BARREL_FLUID_TOP * 16f)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static int packRgb(int r, int g, int b) {
|
||||
return (r & 0xff) << 16 | (g & 0xff) << 8 | (b & 0xff);
|
||||
}
|
||||
|
||||
public static class BarrelRenderState extends BlockEntityRenderState {
|
||||
public final BlockModelRenderState blockItemModel = new BlockModelRenderState();
|
||||
public final ItemStackRenderState outputItem = new ItemStackRenderState();
|
||||
public boolean renderBlockItem;
|
||||
public boolean hasFluid;
|
||||
public boolean transparent;
|
||||
public float fluidY;
|
||||
public Fluid fluid;
|
||||
public int fluidColor;
|
||||
public boolean hasCompost;
|
||||
public float compostPercentage;
|
||||
public int compostColor;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,21 +19,104 @@
|
|||
package thedarkcolour.exdeorum.client.ter;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.renderer.state.level.CameraRenderState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
|
||||
import net.minecraft.client.renderer.state.level.CameraRenderState;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import thedarkcolour.exdeorum.block.AbstractCrucibleBlock;
|
||||
import thedarkcolour.exdeorum.blockentity.AbstractCrucibleBlockEntity;
|
||||
import thedarkcolour.exdeorum.client.RenderFace;
|
||||
import thedarkcolour.exdeorum.client.RenderUtil;
|
||||
|
||||
// TODO: port CrucibleRenderer to MC 26.x rendering API (BlockEntityRenderer changed to extract/submit pattern)
|
||||
public class CrucibleRenderer implements BlockEntityRenderer<AbstractCrucibleBlockEntity, BlockEntityRenderState> {
|
||||
public class CrucibleRenderer implements BlockEntityRenderer<AbstractCrucibleBlockEntity, CrucibleRenderer.CrucibleRenderState> {
|
||||
@Override
|
||||
public BlockEntityRenderState createRenderState() {
|
||||
return new BlockEntityRenderState();
|
||||
public CrucibleRenderState createRenderState() {
|
||||
return new CrucibleRenderState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submit(BlockEntityRenderState state, PoseStack stack, SubmitNodeCollector collector, CameraRenderState cameraState) {
|
||||
// TODO: implement crucible fluid/solid rendering using new 26.x rendering API
|
||||
public void extractRenderState(AbstractCrucibleBlockEntity crucible, CrucibleRenderState state, float partialTicks, net.minecraft.world.phys.Vec3 cameraPosition, net.minecraft.client.renderer.feature.ModelFeatureRenderer.CrumblingOverlay breakProgress) {
|
||||
BlockEntityRenderer.super.extractRenderState(crucible, state, partialTicks, cameraPosition, breakProgress);
|
||||
|
||||
state.hasFluid = false;
|
||||
state.fluid = null;
|
||||
state.solidsFace = null;
|
||||
|
||||
var tank = crucible.getTank();
|
||||
var level = crucible.getLevel();
|
||||
if (level == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var fluidStack = tank.getFluidInTank(0);
|
||||
var solids = (float) crucible.getSolids() / (float) AbstractCrucibleBlockEntity.MAX_SOLIDS;
|
||||
var liquid = (float) fluidStack.getAmount() / (float) tank.getTankCapacity(0);
|
||||
|
||||
if (!fluidStack.isEmpty() && liquid != 0) {
|
||||
var fluid = fluidStack.getFluid();
|
||||
var color = RenderUtil.getFluidColor(fluid, level, crucible.getBlockPos());
|
||||
state.hasFluid = true;
|
||||
state.fluid = fluid;
|
||||
state.fluidY = Mth.lerp(liquid, AbstractCrucibleBlock.CRUCIBLE_FLUID_BOTTOM, AbstractCrucibleBlock.CRUCIBLE_FLUID_TOP);
|
||||
state.fluidColor = color == -1 ? 0xffffff : color;
|
||||
}
|
||||
|
||||
if (solids != 0) {
|
||||
var lastMelted = crucible.getLastMelted();
|
||||
if (lastMelted == null) {
|
||||
lastMelted = crucible.getDefaultMeltBlock();
|
||||
}
|
||||
|
||||
state.solidsFace = RenderUtil.getTopFaceOrDefault(lastMelted, crucible.getDefaultMeltBlock());
|
||||
state.solidsPercentage = solids;
|
||||
|
||||
var tintSource = Minecraft.getInstance().getBlockColors().getTintSource(lastMelted.defaultBlockState(), 0);
|
||||
var color = tintSource != null && level instanceof net.minecraft.client.renderer.block.BlockAndTintGetter getter
|
||||
? tintSource.colorInWorld(lastMelted.defaultBlockState(), getter, crucible.getBlockPos())
|
||||
: -1;
|
||||
state.solidsColor = color == -1 ? 0xffffff : color;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submit(CrucibleRenderState state, PoseStack stack, SubmitNodeCollector collector, CameraRenderState cameraState) {
|
||||
if (state.hasFluid && state.fluid != null) {
|
||||
int r = (state.fluidColor >> 16) & 0xff;
|
||||
int g = (state.fluidColor >> 8) & 0xff;
|
||||
int b = state.fluidColor & 0xff;
|
||||
collector.submitCustomGeometry(stack, RenderUtil.getFluidRenderType(state.fluid), (pose, buffer) ->
|
||||
RenderUtil.renderFlatFluidSprite(buffer, pose, state.fluidY, 2.0f, state.lightCoords, r, g, b, state.fluid)
|
||||
);
|
||||
}
|
||||
|
||||
if (state.solidsFace instanceof RenderFace.Single single) {
|
||||
submitSolidLayer(collector, stack, state, single.renderType(), single.sprite());
|
||||
} else if (state.solidsFace instanceof RenderFace.Composite composite) {
|
||||
for (var layer : composite.layers()) {
|
||||
submitSolidLayer(collector, stack, state, layer.renderType(), layer.sprite());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void submitSolidLayer(SubmitNodeCollector collector, PoseStack stack, CrucibleRenderState state, net.minecraft.client.renderer.rendertype.RenderType renderType, net.minecraft.client.renderer.texture.TextureAtlasSprite sprite) {
|
||||
int r = (state.solidsColor >> 16) & 0xff;
|
||||
int g = (state.solidsColor >> 8) & 0xff;
|
||||
int b = state.solidsColor & 0xff;
|
||||
collector.submitCustomGeometry(stack, renderType, (pose, buffer) ->
|
||||
RenderUtil.renderFlatSpriteLerp(buffer, pose, state.solidsPercentage, r, g, b, sprite, state.lightCoords, 2.0f, AbstractCrucibleBlock.CRUCIBLE_FLUID_BOTTOM * 16f, AbstractCrucibleBlock.CRUCIBLE_FLUID_TOP * 16f)
|
||||
);
|
||||
}
|
||||
|
||||
public static class CrucibleRenderState extends BlockEntityRenderState {
|
||||
public boolean hasFluid;
|
||||
public Fluid fluid;
|
||||
public float fluidY;
|
||||
public int fluidColor;
|
||||
public RenderFace solidsFace;
|
||||
public float solidsPercentage;
|
||||
public int solidsColor;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,20 +19,28 @@
|
|||
package thedarkcolour.exdeorum.client.ter;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.renderer.state.level.CameraRenderState;
|
||||
import net.minecraft.client.renderer.SubmitNodeCollector;
|
||||
import net.minecraft.client.renderer.Sheets;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
|
||||
import net.minecraft.client.renderer.rendertype.RenderTypes;
|
||||
import net.minecraft.client.renderer.state.level.CameraRenderState;
|
||||
import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import thedarkcolour.exdeorum.blockentity.EBlockEntity;
|
||||
import thedarkcolour.exdeorum.blockentity.logic.SieveLogic;
|
||||
import thedarkcolour.exdeorum.client.RenderFace;
|
||||
import thedarkcolour.exdeorum.client.RenderUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
// TODO: port SieveRenderer to MC 26.x rendering API (BlockEntityRenderer changed to extract/submit pattern)
|
||||
public class SieveRenderer<T extends EBlockEntity & SieveLogic.Owner> implements BlockEntityRenderer<T, BlockEntityRenderState> {
|
||||
public class SieveRenderer<T extends EBlockEntity & SieveLogic.Owner> implements BlockEntityRenderer<T, SieveRenderer.SieveRenderState> {
|
||||
public static final Map<Item, TextureAtlasSprite> MESH_TEXTURES = new HashMap<>();
|
||||
|
||||
private final float meshHeight;
|
||||
|
|
@ -46,16 +54,84 @@ public class SieveRenderer<T extends EBlockEntity & SieveLogic.Owner> implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public BlockEntityRenderState createRenderState() {
|
||||
return new BlockEntityRenderState();
|
||||
public SieveRenderState createRenderState() {
|
||||
return new SieveRenderState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submit(BlockEntityRenderState state, PoseStack stack, SubmitNodeCollector collector, CameraRenderState cameraState) {
|
||||
// TODO: implement sieve mesh/contents rendering using new 26.x rendering API
|
||||
public void extractRenderState(T sieve, SieveRenderState state, float partialTicks, net.minecraft.world.phys.Vec3 cameraPosition, net.minecraft.client.renderer.feature.ModelFeatureRenderer.CrumblingOverlay breakProgress) {
|
||||
BlockEntityRenderer.super.extractRenderState(sieve, state, partialTicks, cameraPosition, breakProgress);
|
||||
|
||||
var logic = sieve.getLogic();
|
||||
var contents = logic.getContents();
|
||||
state.contentsFace = null;
|
||||
state.contentsPercentage = logic.getProgress();
|
||||
state.renderContents3d = shouldContentsRender3d(sieve);
|
||||
|
||||
if (!contents.isEmpty() && contents.getItem() instanceof BlockItem blockItem) {
|
||||
state.contentsFace = RenderUtil.getTopFace(blockItem.getBlock());
|
||||
}
|
||||
|
||||
var mesh = logic.getMesh();
|
||||
state.meshSprite = null;
|
||||
state.meshHasFoil = false;
|
||||
if (!mesh.isEmpty()) {
|
||||
var meshItem = mesh.getItem();
|
||||
if (MESH_TEXTURES.containsKey(meshItem)) {
|
||||
state.meshSprite = MESH_TEXTURES.get(meshItem);
|
||||
} else {
|
||||
Identifier textureLoc = BuiltInRegistries.ITEM.getKey(meshItem).withPrefix("item/mesh/");
|
||||
var sprite = RenderUtil.getBlockSprite(textureLoc);
|
||||
MESH_TEXTURES.put(meshItem, sprite);
|
||||
state.meshSprite = sprite;
|
||||
}
|
||||
state.meshHasFoil = mesh.hasFoil();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void submit(SieveRenderState state, PoseStack stack, SubmitNodeCollector collector, CameraRenderState cameraState) {
|
||||
if (state.contentsFace != null) {
|
||||
if (state.contentsFace instanceof RenderFace.Single single) {
|
||||
submitContentsLayer(collector, stack, state, single.renderType(), single.sprite());
|
||||
} else if (state.contentsFace instanceof RenderFace.Composite composite) {
|
||||
for (var layer : composite.layers()) {
|
||||
submitContentsLayer(collector, stack, state, layer.renderType(), layer.sprite());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.meshSprite != null) {
|
||||
collector.submitCustomGeometry(stack, Sheets.cutoutBlockSheet(), (pose, buffer) ->
|
||||
RenderUtil.renderFlatSprite(buffer, pose, this.meshHeight, 0xff, 0xff, 0xff, state.meshSprite, state.lightCoords, 1f)
|
||||
);
|
||||
if (state.meshHasFoil) {
|
||||
collector.submitCustomGeometry(stack, RenderTypes.glint(), (pose, buffer) ->
|
||||
RenderUtil.renderFlatSprite(buffer, pose, this.meshHeight, 0xff, 0xff, 0xff, state.meshSprite, state.lightCoords, 1f)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void submitContentsLayer(SubmitNodeCollector collector, PoseStack stack, SieveRenderState state, net.minecraft.client.renderer.rendertype.RenderType renderType, TextureAtlasSprite sprite) {
|
||||
collector.submitCustomGeometry(stack, renderType, (pose, buffer) -> {
|
||||
if (state.renderContents3d) {
|
||||
RenderUtil.renderCuboid(buffer, pose, this.contentsMinY / 16f, Mth.lerp(state.contentsPercentage, this.contentsMaxY, this.contentsMinY) / 16f, 0xff, 0xff, 0xff, sprite, state.lightCoords, 1.0f);
|
||||
} else {
|
||||
RenderUtil.renderFlatSpriteLerp(buffer, pose, state.contentsPercentage, 0xff, 0xff, 0xff, sprite, state.lightCoords, 1.0f, this.contentsMaxY, this.contentsMinY);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected boolean shouldContentsRender3d(T sieve) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class SieveRenderState extends BlockEntityRenderState {
|
||||
public RenderFace contentsFace;
|
||||
public float contentsPercentage;
|
||||
public boolean renderContents3d;
|
||||
public TextureAtlasSprite meshSprite;
|
||||
public boolean meshHasFoil;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ public class CompatUtil {
|
|||
public static void addEnchantmentsTooltip(ItemStack mesh, Level level, Consumer<Component> aggregator) {
|
||||
var enchantments = mesh.getOrDefault(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY);
|
||||
if (!enchantments.isEmpty()) {
|
||||
enchantments.addToTooltip(Item.TooltipContext.of(level), aggregator, TooltipFlag.NORMAL);
|
||||
enchantments.addToTooltip(Item.TooltipContext.of(level), aggregator, TooltipFlag.NORMAL, mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,13 +66,13 @@ public class PreferredOres {
|
|||
* @param defaultOre The default ore choice, picked by Ex Deorum based on which mod is the "best" choice according to thedarkcolour.
|
||||
*/
|
||||
private static void putPreferredOre(TagKey<Item> tag, ModConfigSpec.ConfigValue<String> config, Item defaultOre) {
|
||||
var item = BuiltInRegistries.ITEM.get(Identifier.parse(config.get()));
|
||||
var item = BuiltInRegistries.ITEM.get(Identifier.parse(config.get())).map(reference -> reference.value()).orElse(Items.AIR);
|
||||
|
||||
if (item == Items.AIR) {
|
||||
item = defaultOre;
|
||||
ExDeorum.LOGGER.debug("No preferred ore was set for tag {}. Using default choice {}", tag.location(), BuiltInRegistries.ITEM.getKey(item));
|
||||
}
|
||||
PREFERRED_ORE_ITEMS.put(tag, defaultOre);
|
||||
PREFERRED_ORE_ITEMS.put(tag, item);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -171,11 +171,11 @@ public class PreferredOres {
|
|||
|
||||
if (modId != null) {
|
||||
if (modId.equals(ModIds.FACTORIUM)) {
|
||||
return BuiltInRegistries.ITEM.get(Identifier.fromNamespaceAndPath(modId, "mat_" + path));
|
||||
return BuiltInRegistries.ITEM.get(Identifier.fromNamespaceAndPath(modId, "mat_" + path)).map(reference -> reference.value()).orElse(Items.AIR);
|
||||
} else if (modId.equals(ModIds.IMMERSIVE_ENGINEERING)) {
|
||||
return BuiltInRegistries.ITEM.get(Identifier.fromNamespaceAndPath(modId, "ore_" + path.substring(0, path.length() - 4)));
|
||||
return BuiltInRegistries.ITEM.get(Identifier.fromNamespaceAndPath(modId, "ore_" + path.substring(0, path.length() - 4))).map(reference -> reference.value()).orElse(Items.AIR);
|
||||
} else {
|
||||
return BuiltInRegistries.ITEM.get(Identifier.fromNamespaceAndPath(modId, path));
|
||||
return BuiltInRegistries.ITEM.get(Identifier.fromNamespaceAndPath(modId, path)).map(reference -> reference.value()).orElse(Items.AIR);
|
||||
}
|
||||
} else {
|
||||
return Items.AIR;
|
||||
|
|
|
|||
|
|
@ -79,8 +79,8 @@ public record XeiSieveRecipe(Ingredient ingredient, ItemStack mesh, List<Result>
|
|||
|
||||
// these lists are grouped into sub lists based on their meshes (ex. dirt with string mesh)
|
||||
for (var recipe : values) {
|
||||
for (var stack : recipe.mesh.getItems()) {
|
||||
meshGrouper.put(stack.getItem(), recipe);
|
||||
for (var holder : recipe.mesh.items().toList()) {
|
||||
meshGrouper.put(holder.value(), recipe);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,11 @@ import net.neoforged.neoforge.event.server.ServerStoppingEvent;
|
|||
import net.neoforged.neoforge.event.tick.ServerTickEvent;
|
||||
import net.neoforged.neoforge.fluids.FluidInteractionRegistry;
|
||||
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
|
||||
import thedarkcolour.exdeorum.ExDeorum;
|
||||
import thedarkcolour.exdeorum.blockentity.AbstractCrucibleBlockEntity;
|
||||
import thedarkcolour.exdeorum.blockentity.AbstractMachineBlockEntity;
|
||||
import thedarkcolour.exdeorum.blockentity.BarrelBlockEntity;
|
||||
import thedarkcolour.exdeorum.blockentity.helper.ItemHelper;
|
||||
import thedarkcolour.exdeorum.client.CompostColors;
|
||||
import thedarkcolour.exdeorum.compat.ModIds;
|
||||
|
|
@ -72,6 +76,10 @@ import thedarkcolour.exdeorum.registry.EBlockEntities;
|
|||
import thedarkcolour.exdeorum.registry.EFluids;
|
||||
import thedarkcolour.exdeorum.registry.EItems;
|
||||
import thedarkcolour.exdeorum.tag.EBiomeTags;
|
||||
import thedarkcolour.exdeorum.transfer.LegacyEnergyStorageTransfer;
|
||||
import thedarkcolour.exdeorum.transfer.LegacyFluidItemAccessTransfer;
|
||||
import thedarkcolour.exdeorum.transfer.LegacyFluidTankTransfer;
|
||||
import thedarkcolour.exdeorum.transfer.LegacyItemHandlerTransfer;
|
||||
import thedarkcolour.exdeorum.voidworld.VoidChunkGenerator;
|
||||
|
||||
import java.util.Locale;
|
||||
|
|
@ -160,7 +168,7 @@ public final class EventHandler {
|
|||
|
||||
event.setCanceled(true);
|
||||
event.getSettings().setSpawn(LevelData.RespawnData.of(level.dimension(), level.getHeightmapPos(Heightmap.Types.WORLD_SURFACE_WG, pos), 90.0F, 0.0F));
|
||||
level.getGameRules().getRule(GameRules.RESPAWN_RADIUS).set(0, level.getServer());
|
||||
level.getGameRules().set(GameRules.RESPAWN_RADIUS, 0, level.getServer());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +202,7 @@ public final class EventHandler {
|
|||
// tries to account for other SkyBlock generator mods like SkyBlockBuilder
|
||||
if (generator instanceof VoidChunkGenerator || generator.getClass().getName().toLowerCase(Locale.ROOT).contains("skyblock")) {
|
||||
NetworkHandler.sendVoidWorld(player);
|
||||
var advancement = player.getServer().getAdvancements().get(Identifier.fromNamespaceAndPath(ExDeorum.ID, "core/root"));
|
||||
var advancement = player.level().getServer().getAdvancements().get(Identifier.fromNamespaceAndPath(ExDeorum.ID, "core/root"));
|
||||
|
||||
if (advancement != null) {
|
||||
if (!player.getAdvancements().getOrStartProgress(advancement).isDone()) {
|
||||
|
|
@ -226,11 +234,7 @@ public final class EventHandler {
|
|||
|
||||
private static void addReloadListeners(AddServerReloadListenersEvent event) {
|
||||
var recipeMap = event.getServerResources().getRecipeManager().recipeMap();
|
||||
event.addListener(ExDeorum.loc("recipes"), (prepBarrier, resourceManager, prepProfiler, reloadProfiler, backgroundExecutor, gameExecutor) -> {
|
||||
return prepBarrier.wait(Unit.INSTANCE).thenRunAsync(() -> {
|
||||
RecipeUtil.reload(recipeMap);
|
||||
}, gameExecutor);
|
||||
});
|
||||
event.addListener(ExDeorum.loc("recipes"), (ResourceManagerReloadListener) resourceManager -> RecipeUtil.reload(recipeMap));
|
||||
}
|
||||
|
||||
private static void serverTick(ServerTickEvent.Post event) {
|
||||
|
|
@ -238,28 +242,28 @@ public final class EventHandler {
|
|||
}
|
||||
|
||||
private static void registerCapabilities(RegisterCapabilitiesEvent event) {
|
||||
event.registerBlockEntity(Capabilities.Item.BLOCK, EBlockEntities.BARREL.get(), (barrel, direction) -> barrel.getItemHandler());
|
||||
event.registerBlockEntity(Capabilities.Fluid.BLOCK, EBlockEntities.BARREL.get(), (barrel, direction) -> barrel.getTank());
|
||||
event.registerBlockEntity(Capabilities.Item.BLOCK, EBlockEntities.BARREL.get(), (barrel, direction) -> new LegacyItemHandlerTransfer(barrel.getItemHandler()));
|
||||
event.registerBlockEntity(Capabilities.Fluid.BLOCK, EBlockEntities.BARREL.get(), (barrel, direction) -> new LegacyFluidTankTransfer(barrel.getTank()));
|
||||
|
||||
event.registerBlockEntity(Capabilities.Item.BLOCK, EBlockEntities.MECHANICAL_SIEVE.get(), (sieve, direction) -> sieve.getItemHandler());
|
||||
event.registerBlockEntity(Capabilities.Energy.BLOCK, EBlockEntities.MECHANICAL_SIEVE.get(), (sieve, direction) -> sieve.getEnergyStorage());
|
||||
event.registerBlockEntity(Capabilities.Item.BLOCK, EBlockEntities.MECHANICAL_SIEVE.get(), (sieve, direction) -> new LegacyItemHandlerTransfer(sieve.inventory));
|
||||
event.registerBlockEntity(Capabilities.Energy.BLOCK, EBlockEntities.MECHANICAL_SIEVE.get(), (sieve, direction) -> new LegacyEnergyStorageTransfer(sieve.getEnergyStorage(), sieve.energy::setStoredEnergy));
|
||||
|
||||
event.registerBlockEntity(Capabilities.Item.BLOCK, EBlockEntities.MECHANICAL_HAMMER.get(), (hammer, direction) -> hammer.getItemHandler());
|
||||
event.registerBlockEntity(Capabilities.Energy.BLOCK, EBlockEntities.MECHANICAL_HAMMER.get(), (hammer, direction) -> hammer.getEnergyStorage());
|
||||
event.registerBlockEntity(Capabilities.Item.BLOCK, EBlockEntities.MECHANICAL_HAMMER.get(), (hammer, direction) -> new LegacyItemHandlerTransfer(hammer.inventory));
|
||||
event.registerBlockEntity(Capabilities.Energy.BLOCK, EBlockEntities.MECHANICAL_HAMMER.get(), (hammer, direction) -> new LegacyEnergyStorageTransfer(hammer.getEnergyStorage(), hammer.energy::setStoredEnergy));
|
||||
|
||||
event.registerBlockEntity(Capabilities.Item.BLOCK, EBlockEntities.LAVA_CRUCIBLE.get(), (hammer, direction) -> hammer.getItem());
|
||||
event.registerBlockEntity(Capabilities.Fluid.BLOCK, EBlockEntities.LAVA_CRUCIBLE.get(), (hammer, direction) -> hammer.getTank());
|
||||
event.registerBlockEntity(Capabilities.Item.BLOCK, EBlockEntities.LAVA_CRUCIBLE.get(), (crucible, direction) -> new LegacyItemHandlerTransfer(crucible.getItem()));
|
||||
event.registerBlockEntity(Capabilities.Fluid.BLOCK, EBlockEntities.LAVA_CRUCIBLE.get(), (crucible, direction) -> new LegacyFluidTankTransfer(crucible.getTank()));
|
||||
|
||||
event.registerBlockEntity(Capabilities.Item.BLOCK, EBlockEntities.WATER_CRUCIBLE.get(), (hammer, direction) -> hammer.getItem());
|
||||
event.registerBlockEntity(Capabilities.Fluid.BLOCK, EBlockEntities.WATER_CRUCIBLE.get(), (hammer, direction) -> hammer.getTank());
|
||||
event.registerBlockEntity(Capabilities.Item.BLOCK, EBlockEntities.WATER_CRUCIBLE.get(), (crucible, direction) -> new LegacyItemHandlerTransfer(crucible.getItem()));
|
||||
event.registerBlockEntity(Capabilities.Fluid.BLOCK, EBlockEntities.WATER_CRUCIBLE.get(), (crucible, direction) -> new LegacyFluidTankTransfer(crucible.getTank()));
|
||||
|
||||
event.registerItem(Capabilities.Fluid.ITEM, (stack, ctx) -> new PorcelainBucket.ItemHandler(stack),
|
||||
event.registerItem(Capabilities.Fluid.ITEM, (stack, ctx) -> ctx == null ? null : new LegacyFluidItemAccessTransfer(ctx, PorcelainBucket.ItemHandler::new),
|
||||
EItems.PORCELAIN_BUCKET,
|
||||
EItems.PORCELAIN_WATER_BUCKET,
|
||||
EItems.PORCELAIN_LAVA_BUCKET,
|
||||
EItems.PORCELAIN_MILK_BUCKET,
|
||||
EItems.PORCELAIN_WITCH_WATER_BUCKET);
|
||||
event.registerItem(Capabilities.Fluid.ITEM, (stack, ctx) -> new WateringCanItem.FluidHandler(stack),
|
||||
event.registerItem(Capabilities.Fluid.ITEM, (stack, ctx) -> ctx == null ? null : new LegacyFluidItemAccessTransfer(ctx, WateringCanItem.FluidHandler::new),
|
||||
EItems.WOODEN_WATERING_CAN,
|
||||
EItems.STONE_WATERING_CAN,
|
||||
EItems.IRON_WATERING_CAN,
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import net.neoforged.neoforge.common.util.FakePlayer;
|
|||
import net.neoforged.neoforge.fluids.FluidStack;
|
||||
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
|
||||
import net.neoforged.neoforge.fluids.capability.templates.FluidHandlerItemStack;
|
||||
import net.neoforged.neoforge.transfer.access.ItemAccess;
|
||||
import thedarkcolour.exdeorum.blockentity.BarrelBlockEntity;
|
||||
import thedarkcolour.exdeorum.data.TranslationKeys;
|
||||
import thedarkcolour.exdeorum.registry.EDataComponents;
|
||||
|
|
@ -94,7 +95,7 @@ public class WateringCanItem extends Item {
|
|||
|
||||
public static ItemStack getFull(Supplier<? extends Item> wateringCan) {
|
||||
var stack = new ItemStack(wateringCan.get());
|
||||
var fluidHandler = stack.getCapability(Capabilities.Fluid.ITEM);
|
||||
var fluidHandler = getFluidHandler(stack);
|
||||
if (fluidHandler != null) {
|
||||
fluidHandler.fill(new FluidStack(Fluids.WATER, Integer.MAX_VALUE), IFluidHandler.FluidAction.EXECUTE);
|
||||
}
|
||||
|
|
@ -104,7 +105,7 @@ public class WateringCanItem extends Item {
|
|||
@Override
|
||||
public boolean isBarVisible(ItemStack stack) {
|
||||
if (this.renewing) {
|
||||
var fluidHandler = stack.getCapability(Capabilities.Fluid.ITEM);
|
||||
var fluidHandler = getFluidHandler(stack);
|
||||
return fluidHandler == null || fluidHandler.getFluidInTank(0).getAmount() < this.capacity;
|
||||
} else {
|
||||
return true;
|
||||
|
|
@ -118,7 +119,7 @@ public class WateringCanItem extends Item {
|
|||
|
||||
@Override
|
||||
public int getBarWidth(ItemStack stack) {
|
||||
var fluidHandler = stack.getCapability(Capabilities.Fluid.ITEM);
|
||||
var fluidHandler = getFluidHandler(stack);
|
||||
if (fluidHandler != null) {
|
||||
return Math.round((float) fluidHandler.getFluidInTank(0).getAmount() * 13f / (float) this.capacity);
|
||||
} else {
|
||||
|
|
@ -137,7 +138,7 @@ public class WateringCanItem extends Item {
|
|||
}
|
||||
|
||||
public void appendHoverText(ItemStack stack, TooltipContext context, List<Component> tooltip, TooltipFlag pIsAdvanced) {
|
||||
var fluidHandler = stack.getCapability(Capabilities.Fluid.ITEM);
|
||||
var fluidHandler = getFluidHandler(stack);
|
||||
if (fluidHandler != null) {
|
||||
// use the block name which is guaranteed to have a vanilla translation
|
||||
tooltip.add(Component.translatable("block.minecraft.water").append(Component.translatable(TranslationKeys.FRACTION_DISPLAY, fluidHandler.getFluidInTank(0).getAmount(), this.capacity)).withStyle(ChatFormatting.GRAY));
|
||||
|
|
@ -147,7 +148,8 @@ public class WateringCanItem extends Item {
|
|||
@Override
|
||||
public InteractionResult use(Level level, Player player, InteractionHand hand) {
|
||||
var itemInHand = player.getItemInHand(hand);
|
||||
var fluidHandler = itemInHand.getCapability(Capabilities.Fluid.ITEM);
|
||||
var itemAccess = ItemAccess.forPlayerInteraction(player, hand);
|
||||
var fluidHandler = getFluidHandler(itemAccess);
|
||||
if (fluidHandler != null) {
|
||||
if (fluidHandler.getFluidInTank(0).getAmount() < this.capacity) {
|
||||
var hitResult = getPlayerPOVHitResult(level, player, ClipContext.Fluid.SOURCE_ONLY);
|
||||
|
|
@ -188,7 +190,7 @@ public class WateringCanItem extends Item {
|
|||
var useTicks = 72000 - remainingTicks;
|
||||
|
||||
if (useTicks >= STARTUP_TIME || living instanceof FakePlayer) {
|
||||
var fluidHandler = stack.getCapability(Capabilities.Fluid.ITEM);
|
||||
var fluidHandler = getFluidHandler(stack);
|
||||
if (fluidHandler != null) {
|
||||
if (!fluidHandler.getFluidInTank(0).isEmpty()) {
|
||||
// do watering can
|
||||
|
|
@ -205,7 +207,7 @@ public class WateringCanItem extends Item {
|
|||
|
||||
if (!this.renewing || fluidHandler.getFluidInTank(0).getAmount() != this.capacity) {
|
||||
if (!(living instanceof Player player && player.getAbilities().instabuild)) {
|
||||
((FluidHandler) fluidHandler).drain();
|
||||
new FluidHandler(stack).drain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -386,4 +388,18 @@ public class WateringCanItem extends Item {
|
|||
return 1 - opposite * opposite * opposite;
|
||||
}
|
||||
}
|
||||
|
||||
private static IFluidHandler getFluidHandler(ItemAccess itemAccess) {
|
||||
var handler = itemAccess.getCapability(Capabilities.Fluid.ITEM);
|
||||
return handler == null ? null : IFluidHandler.of(handler);
|
||||
}
|
||||
|
||||
private static IFluidHandler getFluidHandler(ItemStack stack) {
|
||||
if (stack.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var itemAccess = ItemAccess.forStack(stack);
|
||||
return getFluidHandler(itemAccess);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,9 +50,9 @@ public class CrookLootModifier extends LootModifier {
|
|||
@Override
|
||||
protected @NotNull ObjectArrayList<ItemStack> doApply(ObjectArrayList<ItemStack> generatedLoot, LootContext context) {
|
||||
var state = context.getOptionalParameter(LootContextParams.BLOCK_STATE);
|
||||
var stack = context.getOptionalParameter(LootContextParams.TOOL);
|
||||
var tool = context.getOptionalParameter(LootContextParams.TOOL);
|
||||
|
||||
if (state != null && stack != null) {
|
||||
if (state != null && tool instanceof ItemStack stack) {
|
||||
var rand = context.getRandom();
|
||||
|
||||
if (stack.getEnchantmentLevel(context.getLevel().holderLookup(Registries.ENCHANTMENT).getOrThrow(Enchantments.SILK_TOUCH)) == 0) {
|
||||
|
|
@ -71,7 +71,8 @@ public class CrookLootModifier extends LootModifier {
|
|||
if (state.is(BlockTags.LEAVES)) {
|
||||
// this must not be a crook in order to avoid recursively triggering CrookLootModifier from the re roll method
|
||||
// copying the tag is required so that enchantments like fortune are preserved
|
||||
var nonCrook = stack.transmuteCopy(Items.BARRIER, 1);
|
||||
var nonCrook = new ItemStack(Items.BARRIER, 1);
|
||||
nonCrook.applyComponents(stack.getComponentsPatch());
|
||||
|
||||
for (int i = 0; i < rolls; i++) {
|
||||
generatedLoot.addAll(reRollDrops(context, nonCrook, state));
|
||||
|
|
|
|||
|
|
@ -78,9 +78,11 @@ public class HammerLootModifier extends LootModifier {
|
|||
var resultAmount = recipe.resultAmount.getInt(context);
|
||||
|
||||
if (!itemForm.builtInRegistryHolder().is(this.fortuneBlacklistTag) && context.hasParameter(LootContextParams.TOOL)) {
|
||||
var hammer = context.getParameter(LootContextParams.TOOL);
|
||||
// fortune handling; more likely to boost drops if there are none to begin with
|
||||
resultAmount += calculateFortuneBonus(context.getLevel().registryAccess(), hammer, context.getRandom(), resultAmount == 0);
|
||||
var tool = context.getParameter(LootContextParams.TOOL);
|
||||
if (tool instanceof ItemStack hammer) {
|
||||
// fortune handling; more likely to boost drops if there are none to begin with
|
||||
resultAmount += calculateFortuneBonus(context.getLevel().registryAccess(), hammer, context.getRandom(), resultAmount == 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (resultAmount > 0) {
|
||||
|
|
|
|||
|
|
@ -29,12 +29,12 @@ import thedarkcolour.exdeorum.material.DefaultMaterials;
|
|||
public class EBlockEntities {
|
||||
public static final DeferredRegister<BlockEntityType<?>> BLOCK_ENTITIES = DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE, ExDeorum.ID);
|
||||
|
||||
public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<InfestedLeavesBlockEntity>> INFESTED_LEAVES = BLOCK_ENTITIES.register("infested_leaves", () -> BlockEntityType.Builder.of(InfestedLeavesBlockEntity::new, EBlocks.INFESTED_LEAVES.get()).build(null));
|
||||
public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<InfestedLeavesBlockEntity>> INFESTED_LEAVES = BLOCK_ENTITIES.register("infested_leaves", () -> new BlockEntityType<>(InfestedLeavesBlockEntity::new, java.util.Set.of(EBlocks.INFESTED_LEAVES.get())));
|
||||
public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<LavaCrucibleBlockEntity>> LAVA_CRUCIBLE = BLOCK_ENTITIES.register("lava_crucible", () -> DefaultMaterials.LAVA_CRUCIBLES.createBlockEntityType(LavaCrucibleBlockEntity::new));
|
||||
public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<WaterCrucibleBlockEntity>> WATER_CRUCIBLE = BLOCK_ENTITIES.register("water_crucible", () -> DefaultMaterials.WATER_CRUCIBLES.createBlockEntityType(WaterCrucibleBlockEntity::new));
|
||||
public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<BarrelBlockEntity>> BARREL = BLOCK_ENTITIES.register("barrel", () -> DefaultMaterials.BARRELS.createBlockEntityType(BarrelBlockEntity::new));
|
||||
public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<SieveBlockEntity>> SIEVE = BLOCK_ENTITIES.register("sieve", () -> DefaultMaterials.SIEVES.createBlockEntityType(SieveBlockEntity::new));
|
||||
public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<CompressedSieveBlockEntity>> COMPRESSED_SIEVE = BLOCK_ENTITIES.register("compressed_sieve", () -> DefaultMaterials.COMPRESSED_SIEVES.createBlockEntityType(CompressedSieveBlockEntity::new));
|
||||
public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<MechanicalSieveBlockEntity>> MECHANICAL_SIEVE = BLOCK_ENTITIES.register("mechanical_sieve", () -> BlockEntityType.Builder.of(MechanicalSieveBlockEntity::new, EBlocks.MECHANICAL_SIEVE.get()).build(null));
|
||||
public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<MechanicalHammerBlockEntity>> MECHANICAL_HAMMER = BLOCK_ENTITIES.register("mechanical_hammer", () -> BlockEntityType.Builder.of(MechanicalHammerBlockEntity::new, EBlocks.MECHANICAL_HAMMER.get()).build(null));
|
||||
public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<MechanicalSieveBlockEntity>> MECHANICAL_SIEVE = BLOCK_ENTITIES.register("mechanical_sieve", () -> new BlockEntityType<>(MechanicalSieveBlockEntity::new, java.util.Set.of(EBlocks.MECHANICAL_SIEVE.get())));
|
||||
public static final DeferredHolder<BlockEntityType<?>, BlockEntityType<MechanicalHammerBlockEntity>> MECHANICAL_HAMMER = BLOCK_ENTITIES.register("mechanical_hammer", () -> new BlockEntityType<>(MechanicalHammerBlockEntity::new, java.util.Set.of(EBlocks.MECHANICAL_HAMMER.get())));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
package thedarkcolour.exdeorum.transfer;
|
||||
|
||||
import net.neoforged.neoforge.energy.IEnergyStorage;
|
||||
import net.neoforged.neoforge.transfer.energy.EnergyHandler;
|
||||
import net.neoforged.neoforge.transfer.transaction.SnapshotJournal;
|
||||
import net.neoforged.neoforge.transfer.transaction.TransactionContext;
|
||||
|
||||
import java.util.function.IntConsumer;
|
||||
|
||||
public class LegacyEnergyStorageTransfer extends SnapshotJournal<Integer> implements EnergyHandler {
|
||||
private final IEnergyStorage storage;
|
||||
private final IntConsumer restore;
|
||||
|
||||
public LegacyEnergyStorageTransfer(IEnergyStorage storage, IntConsumer restore) {
|
||||
this.storage = storage;
|
||||
this.restore = restore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAmountAsLong() {
|
||||
return this.storage.getEnergyStored();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCapacityAsLong() {
|
||||
return this.storage.getMaxEnergyStored();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insert(int amount, TransactionContext transaction) {
|
||||
if (amount <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
updateSnapshots(transaction);
|
||||
return this.storage.receiveEnergy(amount, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int extract(int amount, TransactionContext transaction) {
|
||||
if (amount <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
updateSnapshots(transaction);
|
||||
return this.storage.extractEnergy(amount, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer createSnapshot() {
|
||||
return this.storage.getEnergyStored();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void revertToSnapshot(Integer snapshot) {
|
||||
this.restore.accept(snapshot);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package thedarkcolour.exdeorum.transfer;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.neoforged.neoforge.fluids.FluidStack;
|
||||
import net.neoforged.neoforge.fluids.capability.IFluidHandler;
|
||||
import net.neoforged.neoforge.fluids.capability.IFluidHandlerItem;
|
||||
import net.neoforged.neoforge.transfer.ItemAccessResourceHandler;
|
||||
import net.neoforged.neoforge.transfer.access.ItemAccess;
|
||||
import net.neoforged.neoforge.transfer.fluid.FluidResource;
|
||||
import net.neoforged.neoforge.transfer.item.ItemResource;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class LegacyFluidItemAccessTransfer extends ItemAccessResourceHandler<FluidResource> {
|
||||
private final Function<ItemStack, IFluidHandlerItem> factory;
|
||||
|
||||
public LegacyFluidItemAccessTransfer(ItemAccess itemAccess, Function<ItemStack, IFluidHandlerItem> factory) {
|
||||
super(itemAccess, 1);
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FluidResource getResourceFrom(ItemResource itemResource, int amount) {
|
||||
return FluidResource.of(getHandler(itemResource, amount).getFluidInTank(0));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getAmountFrom(ItemResource itemResource, int amount) {
|
||||
return getHandler(itemResource, amount).getFluidInTank(0).getAmount();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemResource update(ItemResource itemResource, int amount, FluidResource resource, int resourceAmount) {
|
||||
var handler = getHandler(itemResource, amount);
|
||||
var current = handler.getFluidInTank(0);
|
||||
|
||||
if (!current.isEmpty()) {
|
||||
handler.drain(current, IFluidHandler.FluidAction.EXECUTE);
|
||||
}
|
||||
if (!resource.isEmpty() && resourceAmount > 0) {
|
||||
handler.fill(resource.toStack(resourceAmount), IFluidHandler.FluidAction.EXECUTE);
|
||||
}
|
||||
|
||||
return ItemResource.of(handler.getContainer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(int index, FluidResource resource) {
|
||||
return !resource.isEmpty() && getHandler(this.itemAccess.getResource(), this.itemAccess.getAmount()).isFluidValid(0, resource.toStack(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getCapacity(int index, FluidResource resource) {
|
||||
return getHandler(this.itemAccess.getResource(), this.itemAccess.getAmount()).getTankCapacity(0);
|
||||
}
|
||||
|
||||
private IFluidHandlerItem getHandler(ItemResource itemResource, int amount) {
|
||||
return this.factory.apply(itemResource.toStack(Math.max(amount, 1)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package thedarkcolour.exdeorum.transfer;
|
||||
|
||||
import net.neoforged.neoforge.fluids.FluidStack;
|
||||
import net.neoforged.neoforge.fluids.capability.templates.FluidTank;
|
||||
import net.neoforged.neoforge.transfer.ResourceHandler;
|
||||
import net.neoforged.neoforge.transfer.fluid.FluidResource;
|
||||
import net.neoforged.neoforge.transfer.transaction.SnapshotJournal;
|
||||
import net.neoforged.neoforge.transfer.transaction.TransactionContext;
|
||||
|
||||
public class LegacyFluidTankTransfer extends SnapshotJournal<FluidStack> implements ResourceHandler<FluidResource> {
|
||||
private final FluidTank tank;
|
||||
|
||||
public LegacyFluidTankTransfer(FluidTank tank) {
|
||||
this.tank = tank;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidResource getResource(int index) {
|
||||
return FluidResource.of(this.tank.getFluid());
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAmountAsLong(int index) {
|
||||
return this.tank.getFluidAmount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCapacityAsLong(int index, FluidResource resource) {
|
||||
return this.tank.getCapacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(int index, FluidResource resource) {
|
||||
return !resource.isEmpty() && this.tank.isFluidValid(resource.toStack(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insert(int index, FluidResource resource, int amount, TransactionContext transaction) {
|
||||
if (resource.isEmpty() || amount <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
updateSnapshots(transaction);
|
||||
return this.tank.fill(resource.toStack(amount), FluidTank.FluidAction.EXECUTE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int extract(int index, FluidResource resource, int amount, TransactionContext transaction) {
|
||||
if (resource.isEmpty() || amount <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
updateSnapshots(transaction);
|
||||
return this.tank.drain(resource.toStack(amount), FluidTank.FluidAction.EXECUTE).getAmount();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FluidStack createSnapshot() {
|
||||
return this.tank.getFluid().copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void revertToSnapshot(FluidStack snapshot) {
|
||||
this.tank.setFluid(snapshot.copy());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
package thedarkcolour.exdeorum.transfer;
|
||||
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.neoforged.neoforge.items.ItemStackHandler;
|
||||
import net.neoforged.neoforge.transfer.ResourceHandler;
|
||||
import net.neoforged.neoforge.transfer.item.ItemResource;
|
||||
import net.neoforged.neoforge.transfer.transaction.SnapshotJournal;
|
||||
import net.neoforged.neoforge.transfer.transaction.TransactionContext;
|
||||
|
||||
public class LegacyItemHandlerTransfer extends SnapshotJournal<NonNullList<ItemStack>> implements ResourceHandler<ItemResource> {
|
||||
private final ItemStackHandler handler;
|
||||
|
||||
public LegacyItemHandlerTransfer(ItemStackHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return this.handler.getSlots();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemResource getResource(int index) {
|
||||
return ItemResource.of(this.handler.getStackInSlot(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getAmountAsLong(int index) {
|
||||
return this.handler.getStackInSlot(index).getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCapacityAsLong(int index, ItemResource resource) {
|
||||
return Math.min(this.handler.getSlotLimit(index), resource.getMaxStackSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(int index, ItemResource resource) {
|
||||
return !resource.isEmpty() && this.handler.isItemValid(index, resource.toStack());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insert(int index, ItemResource resource, int amount, TransactionContext transaction) {
|
||||
if (resource.isEmpty() || amount <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
updateSnapshots(transaction);
|
||||
var remainder = this.handler.insertItem(index, resource.toStack(amount), false);
|
||||
return amount - remainder.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int extract(int index, ItemResource resource, int amount, TransactionContext transaction) {
|
||||
if (resource.isEmpty() || amount <= 0 || index < 0 || index >= this.handler.getSlots()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var current = this.handler.getStackInSlot(index);
|
||||
if (current.isEmpty() || !resource.matches(current)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
updateSnapshots(transaction);
|
||||
return this.handler.extractItem(index, amount, false).getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected NonNullList<ItemStack> createSnapshot() {
|
||||
var snapshot = NonNullList.withSize(this.handler.getSlots(), ItemStack.EMPTY);
|
||||
for (int i = 0; i < this.handler.getSlots(); i++) {
|
||||
snapshot.set(i, this.handler.getStackInSlot(i).copy());
|
||||
}
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void revertToSnapshot(NonNullList<ItemStack> snapshot) {
|
||||
for (int i = 0; i < snapshot.size(); i++) {
|
||||
this.handler.setStackInSlot(i, snapshot.get(i).copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user