v1.5 new shapes + self culling + caching + coding tools/cleanup #10
@ -1,7 +1,7 @@
|
|||||||
package fr.adrien1106.reframed;
|
package fr.adrien1106.reframed;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.block.*;
|
import fr.adrien1106.reframed.block.*;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import net.fabricmc.api.ModInitializer;
|
import net.fabricmc.api.ModInitializer;
|
||||||
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
|
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
|
||||||
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
|
||||||
@ -26,7 +26,9 @@ import java.util.function.BiConsumer;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO self culling, fix other models, better connected textures, preload items, better cache
|
* TODO self culling
|
||||||
|
* TODO fix other models
|
||||||
|
* TODO better connected textures
|
||||||
*/
|
*/
|
||||||
public class ReFramed implements ModInitializer {
|
public class ReFramed implements ModInitializer {
|
||||||
public static final String MODID = "reframed";
|
public static final String MODID = "reframed";
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.block;
|
|||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.generator.RecipeSetter;
|
import fr.adrien1106.reframed.generator.RecipeSetter;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
import net.minecraft.block.*;
|
import net.minecraft.block.*;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
@ -33,7 +33,7 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.LIGHT;
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT;
|
||||||
|
|
||||||
public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeSetter {
|
public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeSetter {
|
||||||
|
|
||||||
@ -41,6 +41,23 @@ public class ReFramedBlock extends Block implements BlockEntityProvider, RecipeS
|
|||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState().with(LIGHT, false));
|
setDefaultState(getDefaultState().with(LIGHT, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a record for the key so that it replaces the blockstate
|
||||||
|
* which may have states that returns same models
|
||||||
|
* @param state - the state_key to generate the key from
|
||||||
|
* @return a cache key with only relevant properties
|
||||||
|
*/
|
||||||
|
public Object getModelCacheKey(BlockState state) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the amount of models the block can have prevents allocating too much space for a model
|
||||||
|
*/
|
||||||
|
public int getModelStateCount() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
//For addon devs: override this so your blocks don't end up trying to place my block entity, my BlockEntityType only handles blocks internal to the mod
|
//For addon devs: override this so your blocks don't end up trying to place my block entity, my BlockEntityType only handles blocks internal to the mod
|
||||||
//Just make your own BlockEntityType, it's fine, you can even use the same ReFramedEntity class
|
//Just make your own BlockEntityType, it's fine, you can even use the same ReFramedEntity class
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.ShapeContext;
|
import net.minecraft.block.ShapeContext;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
@ -44,7 +44,7 @@ public class ReFramedDoubleEntity extends ReFramedEntity {
|
|||||||
public void readNbt(NbtCompound nbt) {
|
public void readNbt(NbtCompound nbt) {
|
||||||
super.readNbt(nbt);
|
super.readNbt(nbt);
|
||||||
|
|
||||||
BlockState rendered_state = second_state;// keep previous state to check if rerender is needed
|
BlockState rendered_state = second_state;// keep previous state_key to check if rerender is needed
|
||||||
second_state = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), nbt.getCompound(BLOCKSTATE_KEY + 2));
|
second_state = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), nbt.getCompound(BLOCKSTATE_KEY + 2));
|
||||||
|
|
||||||
// Force a chunk remesh on the client if the displayed blockstate has changed
|
// Force a chunk remesh on the client if the displayed blockstate has changed
|
||||||
|
@ -25,25 +25,36 @@ import static net.minecraft.data.client.VariantSettings.Rotation.R90;
|
|||||||
import static net.minecraft.state.property.Properties.AXIS;
|
import static net.minecraft.state.property.Properties.AXIS;
|
||||||
|
|
||||||
public class ReFramedDoubleSlabBlock extends ReFramedDoubleBlock implements BlockStateProvider {
|
public class ReFramedDoubleSlabBlock extends ReFramedDoubleBlock implements BlockStateProvider {
|
||||||
|
|
||||||
public ReFramedDoubleSlabBlock(Settings settings) {
|
public ReFramedDoubleSlabBlock(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState().with(Properties.AXIS, Direction.Axis.Y));
|
setDefaultState(getDefaultState().with(AXIS, Direction.Axis.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getModelCacheKey(BlockState state) {
|
||||||
|
return state.get(AXIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getModelStateCount() {
|
||||||
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
super.appendProperties(builder.add(Properties.AXIS));
|
super.appendProperties(builder.add(AXIS));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
public BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
return super.getPlacementState(ctx).with(Properties.AXIS, ctx.getSide().getAxis());
|
return super.getPlacementState(ctx).with(AXIS, ctx.getSide().getAxis());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VoxelShape getShape(BlockState state, int i) {
|
public VoxelShape getShape(BlockState state, int i) {
|
||||||
return switch (state.get(Properties.AXIS)) {
|
return switch (state.get(AXIS)) {
|
||||||
case Y -> i == 2 ? UP : DOWN;
|
case Y -> i == 2 ? UP : DOWN;
|
||||||
case Z -> i == 2 ? NORTH : SOUTH;
|
case Z -> i == 2 ? NORTH : SOUTH;
|
||||||
case X -> i == 2 ? EAST : WEST;
|
case X -> i == 2 ? EAST : WEST;
|
||||||
|
@ -2,9 +2,9 @@ package fr.adrien1106.reframed.block;
|
|||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.property.Corner;
|
import fr.adrien1106.reframed.util.blocks.Corner;
|
||||||
import fr.adrien1106.reframed.util.property.StairShape;
|
import fr.adrien1106.reframed.util.blocks.StairShape;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@ -28,17 +28,27 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.block.ReFramedStairsBlock.*;
|
import static fr.adrien1106.reframed.block.ReFramedStairsBlock.*;
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.CORNER;
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER;
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.STAIR_SHAPE;
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.STAIR_SHAPE;
|
||||||
import static fr.adrien1106.reframed.util.property.StairShape.STRAIGHT;
|
|
||||||
|
|
||||||
public class ReFramedDoubleStairsBlock extends ReFramedDoubleBlock implements BlockStateProvider {
|
public class ReFramedDoubleStairsBlock extends ReFramedDoubleBlock implements BlockStateProvider {
|
||||||
|
|
||||||
private static final List<VoxelShape> COMPLEMENT_LIST = new ArrayList<>(52);
|
private static final List<VoxelShape> COMPLEMENT_LIST = new ArrayList<>(52);
|
||||||
|
private record ModelCacheKey(Corner corner, StairShape shape) {}
|
||||||
|
|
||||||
public ReFramedDoubleStairsBlock(Settings settings) {
|
public ReFramedDoubleStairsBlock(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState().with(CORNER, Corner.NORTH_DOWN).with(STAIR_SHAPE, STRAIGHT));
|
setDefaultState(getDefaultState().with(CORNER, Corner.NORTH_DOWN).with(STAIR_SHAPE, StairShape.STRAIGHT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getModelCacheKey(BlockState state) {
|
||||||
|
return new ModelCacheKey(state.get(CORNER), state.get(STAIR_SHAPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getModelStateCount() {
|
||||||
|
return 108; // Has 12 * 9 state combination and 52 models still reduces cache size
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -3,7 +3,9 @@ package fr.adrien1106.reframed.block;
|
|||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.generator.GBlockstate;
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.Corner;
|
||||||
|
import fr.adrien1106.reframed.util.blocks.StairShape;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@ -32,11 +34,23 @@ import static net.minecraft.state.property.Properties.AXIS;
|
|||||||
import static net.minecraft.util.shape.VoxelShapes.empty;
|
import static net.minecraft.util.shape.VoxelShapes.empty;
|
||||||
|
|
||||||
public class ReFramedDoubleStepBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider {
|
public class ReFramedDoubleStepBlock extends WaterloggableReFramedDoubleBlock implements BlockStateProvider {
|
||||||
|
private record ModelCacheKey(Direction facing, Axis axis) {}
|
||||||
|
|
||||||
public ReFramedDoubleStepBlock(Settings settings) {
|
public ReFramedDoubleStepBlock(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState().with(FACING, Direction.DOWN).with(AXIS, Axis.X));
|
setDefaultState(getDefaultState().with(FACING, Direction.DOWN).with(AXIS, Axis.X));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getModelCacheKey(BlockState state) {
|
||||||
|
return new ModelCacheKey(state.get(FACING), state.get(AXIS));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getModelStateCount() {
|
||||||
|
return 18;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
super.appendProperties(builder.add(FACING, AXIS));
|
super.appendProperties(builder.add(FACING, AXIS));
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.block;
|
package fr.adrien1106.reframed.block;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.util.BlockProperties;
|
import fr.adrien1106.reframed.util.blocks.BlockProperties;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
@ -27,7 +27,7 @@ import java.util.Objects;
|
|||||||
|
|
||||||
//Keeping the weight of this block entity down, both in terms of memory consumption and NBT sync traffic,
|
//Keeping the weight of this block entity down, both in terms of memory consumption and NBT sync traffic,
|
||||||
//is pretty important since players might place a lot of them. There were tons and tons of these at Blanketcon.
|
//is pretty important since players might place a lot of them. There were tons and tons of these at Blanketcon.
|
||||||
//To that end, most of the state has been crammed into a bitfield.
|
//To that end, most of the state_key has been crammed into a bitfield.
|
||||||
public class ReFramedEntity extends BlockEntity implements ThemeableBlockEntity {
|
public class ReFramedEntity extends BlockEntity implements ThemeableBlockEntity {
|
||||||
protected BlockState first_state = Blocks.AIR.getDefaultState();
|
protected BlockState first_state = Blocks.AIR.getDefaultState();
|
||||||
protected byte bit_field = SOLIDITY_MASK;
|
protected byte bit_field = SOLIDITY_MASK;
|
||||||
@ -47,7 +47,7 @@ public class ReFramedEntity extends BlockEntity implements ThemeableBlockEntity
|
|||||||
public void readNbt(NbtCompound nbt) {
|
public void readNbt(NbtCompound nbt) {
|
||||||
super.readNbt(nbt);
|
super.readNbt(nbt);
|
||||||
|
|
||||||
BlockState rendered_state = first_state; // keep previous state to check if rerender is needed
|
BlockState rendered_state = first_state; // keep previous state_key to check if rerender is needed
|
||||||
first_state = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), nbt.getCompound(BLOCKSTATE_KEY + 1));
|
first_state = NbtHelper.toBlockState(Registries.BLOCK.getReadOnlyWrapper(), nbt.getCompound(BLOCKSTATE_KEY + 1));
|
||||||
if (nbt.contains(BITFIELD_KEY)) bit_field = nbt.getByte(BITFIELD_KEY);
|
if (nbt.contains(BITFIELD_KEY)) bit_field = nbt.getByte(BITFIELD_KEY);
|
||||||
|
|
||||||
|
@ -38,6 +38,16 @@ public class ReFramedSlabBlock extends WaterloggableReFramedBlock implements Blo
|
|||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState().with(FACING, Direction.DOWN));
|
setDefaultState(getDefaultState().with(FACING, Direction.DOWN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getModelCacheKey(BlockState state) {
|
||||||
|
return state.get(FACING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getModelStateCount() {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
@ -3,10 +3,10 @@ package fr.adrien1106.reframed.block;
|
|||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.generator.GBlockstate;
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.VoxelHelper;
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
import fr.adrien1106.reframed.util.property.Corner;
|
import fr.adrien1106.reframed.util.blocks.Corner;
|
||||||
import fr.adrien1106.reframed.util.property.StairShape;
|
import fr.adrien1106.reframed.util.blocks.StairShape;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@ -34,19 +34,30 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.*;
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.*;
|
||||||
import static fr.adrien1106.reframed.util.property.StairShape.*;
|
import static fr.adrien1106.reframed.util.blocks.StairShape.*;
|
||||||
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
import static fr.adrien1106.reframed.util.property.Corner.*;
|
import static fr.adrien1106.reframed.util.blocks.Corner.*;
|
||||||
|
|
||||||
public class ReFramedStairsBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
|
public class ReFramedStairsBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
|
||||||
|
|
||||||
public static final List<VoxelShape> VOXEL_LIST = new ArrayList<>(52);
|
public static final List<VoxelShape> VOXEL_LIST = new ArrayList<>(52);
|
||||||
|
private record ModelCacheKey(Corner corner, StairShape shape) {}
|
||||||
|
|
||||||
public ReFramedStairsBlock(Settings settings) {
|
public ReFramedStairsBlock(Settings settings) {
|
||||||
super(settings);
|
super(settings);
|
||||||
setDefaultState(getDefaultState().with(CORNER, Corner.NORTH_DOWN).with(STAIR_SHAPE, STRAIGHT));
|
setDefaultState(getDefaultState().with(CORNER, Corner.NORTH_DOWN).with(STAIR_SHAPE, STRAIGHT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getModelCacheKey(BlockState state) {
|
||||||
|
return new ModelCacheKey(state.get(CORNER), state.get(STAIR_SHAPE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getModelStateCount() {
|
||||||
|
return 108; // Has 12 * 9 state combination and 52 models still reduces cache size
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
|
@ -3,9 +3,9 @@ package fr.adrien1106.reframed.block;
|
|||||||
import fr.adrien1106.reframed.ReFramed;
|
import fr.adrien1106.reframed.ReFramed;
|
||||||
import fr.adrien1106.reframed.generator.GBlockstate;
|
import fr.adrien1106.reframed.generator.GBlockstate;
|
||||||
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
import fr.adrien1106.reframed.generator.BlockStateProvider;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.VoxelHelper;
|
import fr.adrien1106.reframed.util.VoxelHelper;
|
||||||
import fr.adrien1106.reframed.util.property.Corner;
|
import fr.adrien1106.reframed.util.blocks.Corner;
|
||||||
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@ -28,8 +28,8 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.CORNER;
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER;
|
||||||
import static fr.adrien1106.reframed.util.property.Corner.*;
|
import static fr.adrien1106.reframed.util.blocks.Corner.*;
|
||||||
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
import static net.minecraft.data.client.VariantSettings.Rotation.*;
|
||||||
|
|
||||||
public class ReFramedStepBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
|
public class ReFramedStepBlock extends WaterloggableReFramedBlock implements BlockStateProvider {
|
||||||
@ -41,6 +41,16 @@ public class ReFramedStepBlock extends WaterloggableReFramedBlock implements Blo
|
|||||||
setDefaultState(getDefaultState().with(CORNER, Corner.NORTH_DOWN));
|
setDefaultState(getDefaultState().with(CORNER, Corner.NORTH_DOWN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getModelCacheKey(BlockState state) {
|
||||||
|
return state.get(CORNER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getModelStateCount() {
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
protected void appendProperties(StateManager.Builder<Block, BlockState> builder) {
|
||||||
super.appendProperties(builder.add(CORNER));
|
super.appendProperties(builder.add(CORNER));
|
||||||
|
@ -45,7 +45,7 @@ public class DoubleRetexturingBakedModel extends ForwardingBakedModel implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<BakedModel> models() {
|
public List<ForwardingBakedModel> models() {
|
||||||
return List.of(model_1, model_2);
|
return List.of(model_1, model_2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
package fr.adrien1106.reframed.client.model;
|
package fr.adrien1106.reframed.client.model;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface MultiRetexturableModel {
|
public interface MultiRetexturableModel {
|
||||||
|
|
||||||
List<BakedModel> models();
|
List<ForwardingBakedModel> models();
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package fr.adrien1106.reframed.client.model;
|
package fr.adrien1106.reframed.client.model;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.block.ReFramedBlock;
|
||||||
import fr.adrien1106.reframed.block.ReFramedEntity;
|
import fr.adrien1106.reframed.block.ReFramedEntity;
|
||||||
import fr.adrien1106.reframed.client.ReFramedClient;
|
import fr.adrien1106.reframed.client.ReFramedClient;
|
||||||
import fr.adrien1106.reframed.client.model.apperance.SpriteProperties;
|
|
||||||
import fr.adrien1106.reframed.mixin.MinecraftAccessor;
|
import fr.adrien1106.reframed.mixin.MinecraftAccessor;
|
||||||
import fr.adrien1106.reframed.client.model.apperance.CamoAppearance;
|
import fr.adrien1106.reframed.client.model.apperance.CamoAppearance;
|
||||||
import fr.adrien1106.reframed.client.model.apperance.CamoAppearanceManager;
|
import fr.adrien1106.reframed.client.model.apperance.CamoAppearanceManager;
|
||||||
import fr.adrien1106.reframed.client.model.apperance.WeightedComputedAppearance;
|
import fr.adrien1106.reframed.client.model.apperance.WeightedComputedAppearance;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||||
@ -26,34 +27,42 @@ import net.minecraft.util.math.Direction;
|
|||||||
import net.minecraft.util.math.random.Random;
|
import net.minecraft.util.math.random.Random;
|
||||||
import net.minecraft.world.BlockRenderView;
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
||||||
public RetexturingBakedModel(BakedModel base_model, CamoAppearanceManager tam, int theme_index, ModelBakeSettings settings, BlockState item_state, boolean ao) {
|
public RetexturingBakedModel(BakedModel base_model, CamoAppearanceManager tam, int theme_index, ModelBakeSettings settings, BlockState item_state, boolean ao) {
|
||||||
this.wrapped = base_model; //field from the superclass; vanilla getQuads etc. will delegate through to this
|
this.wrapped = base_model; //field from the superclass; vanilla getQuads etc. will delegate through to this
|
||||||
|
|
||||||
this.tam = tam;
|
this.appearance_manager = tam;
|
||||||
this.theme_index = theme_index;
|
this.theme_index = theme_index;
|
||||||
this.uv_lock = settings.isUvLocked();
|
this.uv_lock = settings.isUvLocked();
|
||||||
this.item_state = item_state;
|
this.item_state = item_state;
|
||||||
this.ao = ao;
|
this.ao = ao;
|
||||||
|
|
||||||
|
int cache_size = 64; // default is 64 why don't ask me and it should get overwritten
|
||||||
|
if (item_state.getBlock() instanceof ReFramedBlock frame_block) cache_size = frame_block.getModelStateCount() + 1;
|
||||||
|
BASE_MESH_CACHE = new Object2ObjectLinkedOpenHashMap<>(cache_size, 0.25f) {
|
||||||
|
@Override
|
||||||
|
protected void rehash(int v) {}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final CamoAppearanceManager tam;
|
protected final CamoAppearanceManager appearance_manager;
|
||||||
protected final int theme_index;
|
protected final int theme_index;
|
||||||
protected final boolean uv_lock;
|
protected final boolean uv_lock;
|
||||||
protected final BlockState item_state;
|
|
||||||
protected final boolean ao;
|
protected final boolean ao;
|
||||||
|
protected final BlockState item_state;
|
||||||
|
|
||||||
/* ----------------------------------------------- CACHE ELEMENT ------------------------------------------------ */
|
protected record MeshCacheKey(Object state_key, CamoAppearance appearance, int model_id) {}
|
||||||
// TODO make static ? for connected textures ?
|
/** cache that store retextured models */
|
||||||
protected record MeshCacheKey(BlockState state, TransformCacheKey transform) {}
|
protected final Object2ObjectLinkedOpenHashMap<MeshCacheKey, Mesh> RETEXTURED_MESH_CACHE =
|
||||||
protected record TransformCacheKey(CamoAppearance appearance, int model_id) {}
|
new Object2ObjectLinkedOpenHashMap<>(128, 0.25f) {
|
||||||
protected final ConcurrentMap<TransformCacheKey, RetexturingTransformer> retextured_transforms = new ConcurrentHashMap<>();
|
@Override
|
||||||
protected final ConcurrentMap<MeshCacheKey, Mesh> retextured_meshes = new ConcurrentHashMap<>(); //mutable, append-only cache
|
protected void rehash(int v) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** cache that stores the base meshes which has the size of the amount of models */
|
||||||
|
protected final Object2ObjectLinkedOpenHashMap<Object, Mesh> BASE_MESH_CACHE;
|
||||||
|
|
||||||
protected static final Direction[] DIRECTIONS_AND_NULL;
|
protected static final Direction[] DIRECTIONS_AND_NULL;
|
||||||
static {
|
static {
|
||||||
@ -62,11 +71,12 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
System.arraycopy(values, 0, DIRECTIONS_AND_NULL, 0, values.length);
|
System.arraycopy(values, 0, DIRECTIONS_AND_NULL, 0, values.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final ConcurrentMap<BlockState, Mesh> jsonToMesh = new ConcurrentHashMap<>();
|
protected Mesh getBaseMesh(Object key, BlockState state) {
|
||||||
|
|
||||||
protected Mesh getBaseMesh(BlockState state) {
|
|
||||||
//Convert models to re-texturable Meshes lazily, the first time we encounter each blockstate
|
//Convert models to re-texturable Meshes lazily, the first time we encounter each blockstate
|
||||||
return jsonToMesh.computeIfAbsent(state, this::convertModel);
|
if (BASE_MESH_CACHE.containsKey(key)) return BASE_MESH_CACHE.getAndMoveToFirst(key);
|
||||||
|
Mesh mesh = convertModel(state);
|
||||||
|
BASE_MESH_CACHE.putAndMoveToFirst(key, mesh);
|
||||||
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Mesh convertModel(BlockState state);
|
protected abstract Mesh convertModel(BlockState state);
|
||||||
@ -78,39 +88,42 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Sprite getParticleSprite() {
|
public Sprite getParticleSprite() {
|
||||||
return tam.getDefaultAppearance(theme_index).getSprites(Direction.UP, 0).get(0).sprite();
|
return appearance_manager.getDefaultAppearance(theme_index).getSprites(Direction.UP, 0).get(0).sprite();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||||
|
// skip render if block not a frame (which should always be the case
|
||||||
|
if (!(state.getBlock() instanceof ReFramedBlock frame_block)) return;
|
||||||
BlockState theme = (world.getBlockEntity(pos) instanceof ThemeableBlockEntity s) ? s.getTheme(theme_index) : null;
|
BlockState theme = (world.getBlockEntity(pos) instanceof ThemeableBlockEntity s) ? s.getTheme(theme_index) : null;
|
||||||
QuadEmitter quad_emitter = context.getEmitter();
|
QuadEmitter quad_emitter = context.getEmitter();
|
||||||
if(theme == null || theme.isAir()) {
|
if(theme == null || theme.isAir()) {
|
||||||
getUntintedRetexturedMesh(new MeshCacheKey(state, new TransformCacheKey(tam.getDefaultAppearance(theme_index), 0)), 0).outputTo(quad_emitter);
|
getRetexturedMesh(
|
||||||
|
new MeshCacheKey(
|
||||||
|
frame_block.getModelCacheKey(state),
|
||||||
|
appearance_manager.getDefaultAppearance(theme_index),
|
||||||
|
0
|
||||||
|
),
|
||||||
|
state
|
||||||
|
).outputTo(quad_emitter);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(theme.getBlock() == Blocks.BARRIER) return;
|
if(theme.getBlock() == Blocks.BARRIER) return;
|
||||||
|
|
||||||
CamoAppearance camo = tam.getCamoAppearance(world, theme, pos, theme_index);
|
CamoAppearance camo = appearance_manager.getCamoAppearance(world, theme, pos, theme_index);
|
||||||
long seed = theme.getRenderingSeed(pos);
|
long seed = theme.getRenderingSeed(pos);
|
||||||
int model_id = 0;
|
int model_id = 0;
|
||||||
if (camo instanceof WeightedComputedAppearance wca) model_id = wca.getAppearanceIndex(seed);
|
if (camo instanceof WeightedComputedAppearance wca) model_id = wca.getAppearanceIndex(seed);
|
||||||
|
|
||||||
int tint = 0xFF000000 | MinecraftClient.getInstance().getBlockColors().getColor(theme, world, pos, 0);
|
int tint = 0xFF000000 | MinecraftClient.getInstance().getBlockColors().getColor(theme, world, pos, 0);
|
||||||
Mesh untintedMesh = getUntintedRetexturedMesh(
|
Mesh untintedMesh = getRetexturedMesh(new MeshCacheKey(frame_block.getModelCacheKey(state), camo, model_id), state);
|
||||||
new MeshCacheKey(
|
|
||||||
state,
|
|
||||||
new TransformCacheKey(camo, model_id)
|
|
||||||
),
|
|
||||||
seed
|
|
||||||
);
|
|
||||||
|
|
||||||
//The specific tint might vary a lot; imagine grass color smoothly changing. Trying to bake the tint into
|
//The specific tint might vary a lot; imagine grass color smoothly changing. Trying to bake the tint into
|
||||||
//the cached mesh will pollute it with a ton of single-use meshes with only slightly different colors.
|
//the cached mesh will pollute it with a ton of single-use meshes with only slightly different colors.
|
||||||
if(tint == 0xFFFFFFFF) {
|
if(tint == 0xFFFFFFFF) {
|
||||||
untintedMesh.outputTo(quad_emitter);
|
untintedMesh.outputTo(quad_emitter);
|
||||||
} else {
|
} else {
|
||||||
context.pushTransform(new TintingTransformer(camo, tint, seed));
|
context.pushTransform(new TintingTransformer(camo, model_id, tint));
|
||||||
untintedMesh.outputTo(quad_emitter);
|
untintedMesh.outputTo(quad_emitter);
|
||||||
context.popTransform();
|
context.popTransform();
|
||||||
}
|
}
|
||||||
@ -120,121 +133,68 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
public void emitItemQuads(ItemStack stack, Supplier<Random> randomSupplier, RenderContext context) {
|
||||||
//cheeky: if the item has NBT data, pluck out the blockstate from it & look up the item color provider
|
//cheeky: if the item has NBT data, pluck out the blockstate from it & look up the item color provider
|
||||||
//none of this is accessible unless you're in creative mode doing ctrl-pick btw
|
//none of this is accessible unless you're in creative mode doing ctrl-pick btw
|
||||||
CamoAppearance nbtAppearance;
|
CamoAppearance appearance;
|
||||||
int tint;
|
int tint;
|
||||||
BlockState theme = ReFramedEntity.readStateFromItem(stack, theme_index);
|
BlockState theme = ReFramedEntity.readStateFromItem(stack, theme_index);
|
||||||
if(!theme.isAir()) {
|
if(!theme.isAir()) {
|
||||||
nbtAppearance = tam.getCamoAppearance(null, theme, null, theme_index);
|
appearance = appearance_manager.getCamoAppearance(null, theme, null, theme_index);
|
||||||
tint = 0xFF000000 | ((MinecraftAccessor) MinecraftClient.getInstance()).getItemColors().getColor(new ItemStack(theme.getBlock()), 0);
|
tint = 0xFF000000 | ((MinecraftAccessor) MinecraftClient.getInstance()).getItemColors().getColor(new ItemStack(theme.getBlock()), 0);
|
||||||
} else {
|
} else {
|
||||||
nbtAppearance = tam.getDefaultAppearance(theme_index);
|
appearance = appearance_manager.getDefaultAppearance(theme_index);
|
||||||
tint = 0xFFFFFFFF;
|
tint = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh untintedMesh = getUntintedRetexturedMesh(new MeshCacheKey(item_state, new TransformCacheKey(nbtAppearance, 0)), 0);
|
Mesh untintedMesh = getRetexturedMesh(new MeshCacheKey("I", appearance, 0), item_state);
|
||||||
|
|
||||||
QuadEmitter quad_emitter = context.getEmitter();
|
QuadEmitter quad_emitter = context.getEmitter();
|
||||||
if(tint == 0xFFFFFFFF) {
|
if(tint == 0xFFFFFFFF) {
|
||||||
untintedMesh.outputTo(quad_emitter);
|
untintedMesh.outputTo(quad_emitter);
|
||||||
} else {
|
} else {
|
||||||
context.pushTransform(new TintingTransformer(nbtAppearance, tint, 0));
|
context.pushTransform(new TintingTransformer(appearance, 0, tint));
|
||||||
untintedMesh.outputTo(quad_emitter);
|
untintedMesh.outputTo(quad_emitter);
|
||||||
context.popTransform();
|
context.popTransform();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Mesh getUntintedRetexturedMesh(MeshCacheKey key, long seed) {
|
protected Mesh getRetexturedMesh(MeshCacheKey key, BlockState state) {
|
||||||
return retextured_meshes.computeIfAbsent(key, (k) -> createUntintedRetexturedMesh(k, seed));
|
if (RETEXTURED_MESH_CACHE.containsKey(key)) return RETEXTURED_MESH_CACHE.getAndMoveToFirst(key);
|
||||||
|
Mesh mesh = transformMesh(key, state);
|
||||||
|
RETEXTURED_MESH_CACHE.putAndMoveToFirst(key, mesh);
|
||||||
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Mesh createUntintedRetexturedMesh(MeshCacheKey key, long seed) {
|
protected Mesh transformMesh(MeshCacheKey key, BlockState state) {
|
||||||
RetexturingTransformer transformer = retextured_transforms.computeIfAbsent(key.transform, (k) -> new RetexturingTransformer(k.appearance, seed));
|
|
||||||
return pretransformMesh(getBaseMesh(key.state), transformer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Mesh pretransformMesh(Mesh mesh, RetexturingTransformer transform) {
|
|
||||||
MeshBuilder builder = ReFramedClient.HELPER.getFabricRenderer().meshBuilder();
|
MeshBuilder builder = ReFramedClient.HELPER.getFabricRenderer().meshBuilder();
|
||||||
QuadEmitter emitter = builder.getEmitter();
|
QuadEmitter emitter = builder.getEmitter();
|
||||||
|
|
||||||
mesh.forEach(quad -> {
|
getBaseMesh(key.state_key, state).forEach(quad -> {
|
||||||
int i = -1;
|
int i = -1;
|
||||||
do {
|
do {
|
||||||
emitter.copyFrom(quad);
|
emitter.copyFrom(quad);
|
||||||
i = transform.transform(emitter, i);
|
i = key.appearance.transformQuad(emitter, i, key.model_id, ao, uv_lock);
|
||||||
} while (i > 0);
|
} while (i > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RetexturingTransformer {
|
|
||||||
private final long seed;
|
|
||||||
protected RetexturingTransformer(CamoAppearance ta, long seed) {
|
|
||||||
this.ta = ta;
|
|
||||||
this.seed = seed;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final CamoAppearance ta;
|
|
||||||
|
|
||||||
public int transform(QuadEmitter quad, int i) {
|
|
||||||
if(quad.tag() == 0) return 0; //Pass the quad through unmodified.
|
|
||||||
|
|
||||||
Direction direction = quad.nominalFace();
|
|
||||||
List<SpriteProperties> sprites = ta.getSprites(direction, seed);
|
|
||||||
if (i == -1) i = sprites.size();
|
|
||||||
|
|
||||||
SpriteProperties properties = sprites.get(sprites.size() - i);
|
|
||||||
i--;
|
|
||||||
QuadPosBounds bounds = properties.bounds();
|
|
||||||
|
|
||||||
if (bounds == null) { // sprite applies anywhere e.g. default behaviour
|
|
||||||
quad.material(ta.getRenderMaterial(ao));
|
|
||||||
quad.spriteBake(
|
|
||||||
properties.sprite(),
|
|
||||||
MutableQuadView.BAKE_NORMALIZED
|
|
||||||
| properties.flags()
|
|
||||||
| (uv_lock ? MutableQuadView.BAKE_LOCK_UV : 0)
|
|
||||||
);
|
|
||||||
quad.tag(i+1);
|
|
||||||
quad.emit();
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify if sprite covers the current quad and apply the new size
|
|
||||||
QuadPosBounds origin_bounds = QuadPosBounds.read(quad, false);
|
|
||||||
if (!bounds.matches(origin_bounds)) return i;
|
|
||||||
|
|
||||||
// apply new quad shape
|
|
||||||
quad.material(ta.getRenderMaterial(ao));
|
|
||||||
bounds.intersection(origin_bounds, direction.getAxis()).apply(quad, origin_bounds);
|
|
||||||
quad.spriteBake( // seems to work without the flags and break with it
|
|
||||||
properties.sprite(),
|
|
||||||
MutableQuadView.BAKE_NORMALIZED
|
|
||||||
| MutableQuadView.BAKE_LOCK_UV
|
|
||||||
);
|
|
||||||
quad.tag(i+1);
|
|
||||||
quad.emit();
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class TintingTransformer implements RenderContext.QuadTransform {
|
protected static class TintingTransformer implements RenderContext.QuadTransform {
|
||||||
private final long seed;
|
private final CamoAppearance appearance;
|
||||||
protected TintingTransformer(CamoAppearance ta, int tint, long seed) {
|
private final int model_id;
|
||||||
this.ta = ta;
|
private final int tint;
|
||||||
|
|
||||||
|
protected TintingTransformer(CamoAppearance appearance, int model_id, int tint) {
|
||||||
|
this.appearance = appearance;
|
||||||
|
this.model_id = model_id;
|
||||||
this.tint = tint;
|
this.tint = tint;
|
||||||
this.seed = seed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final CamoAppearance ta;
|
|
||||||
protected final int tint;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean transform(MutableQuadView quad) {
|
public boolean transform(MutableQuadView quad) {
|
||||||
if(quad.tag() == 0) return true;
|
if(quad.tag() == 0) return true;
|
||||||
|
|
||||||
if(ta.hasColor(quad.nominalFace(), seed, quad.tag())) quad.color(tint, tint, tint, tint);
|
if(appearance.hasColor(quad.nominalFace(), model_id, quad.tag())) quad.color(tint, tint, tint, tint);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ public class UnbakedAutoRetexturedModel extends UnbakedRetexturedModel {
|
|||||||
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
||||||
MeshBuilder builder = r.meshBuilder();
|
MeshBuilder builder = r.meshBuilder();
|
||||||
QuadEmitter emitter = builder.getEmitter();
|
QuadEmitter emitter = builder.getEmitter();
|
||||||
RenderMaterial mat = tam.getCachedMaterial(state, false);
|
RenderMaterial mat = appearance_manager.getCachedMaterial(state, false);
|
||||||
|
|
||||||
Random rand = Random.create(42);
|
Random rand = Random.create(42);
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ public class UnbakedJsonRetexturedModel extends UnbakedRetexturedModel {
|
|||||||
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
||||||
MeshBuilder builder = r.meshBuilder();
|
MeshBuilder builder = r.meshBuilder();
|
||||||
QuadEmitter emitter = builder.getEmitter();
|
QuadEmitter emitter = builder.getEmitter();
|
||||||
RenderMaterial mat = tam.getCachedMaterial(state, false);
|
RenderMaterial mat = appearance_manager.getCachedMaterial(state, false);
|
||||||
|
|
||||||
Random rand = Random.create(42);
|
Random rand = Random.create(42);
|
||||||
|
|
||||||
|
@ -1,13 +1,76 @@
|
|||||||
package fr.adrien1106.reframed.client.model.apperance;
|
package fr.adrien1106.reframed.client.model.apperance;
|
||||||
|
|
||||||
|
import fr.adrien1106.reframed.client.model.QuadPosBounds;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface CamoAppearance {
|
public abstract class CamoAppearance {
|
||||||
@NotNull RenderMaterial getRenderMaterial(boolean ao);
|
protected final int id;
|
||||||
@NotNull List<SpriteProperties> getSprites(Direction dir, long seed);
|
protected final RenderMaterial ao_material;
|
||||||
boolean hasColor(Direction dir, long seed, int index);
|
protected final RenderMaterial material;
|
||||||
|
|
||||||
|
protected CamoAppearance(RenderMaterial ao_material, RenderMaterial material, int id) {
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
this.ao_material = ao_material;
|
||||||
|
this.material = material;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract @NotNull List<SpriteProperties> getSprites(Direction dir, int model_id);
|
||||||
|
public abstract boolean hasColor(Direction dir, int model_id, int index);
|
||||||
|
|
||||||
|
public @NotNull RenderMaterial getRenderMaterial(boolean ao) {
|
||||||
|
return ao && ao_material != null? ao_material : material;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int transformQuad(QuadEmitter quad, int i, int model_id, boolean ao, boolean uv_lock) {
|
||||||
|
if(quad.tag() == 0) return 0; // Pass the quad through unmodified.
|
||||||
|
|
||||||
|
Direction direction = quad.nominalFace();
|
||||||
|
List<SpriteProperties> sprites = getSprites(direction, model_id);
|
||||||
|
if (i == -1) i = sprites.size();
|
||||||
|
|
||||||
|
SpriteProperties properties = sprites.get(sprites.size() - i);
|
||||||
|
i--;
|
||||||
|
QuadPosBounds bounds = properties.bounds();
|
||||||
|
|
||||||
|
if (bounds == null) { // sprite applies anywhere e.g. default behaviour
|
||||||
|
quad.material(getRenderMaterial(ao));
|
||||||
|
quad.spriteBake(
|
||||||
|
properties.sprite(),
|
||||||
|
MutableQuadView.BAKE_NORMALIZED
|
||||||
|
| properties.flags()
|
||||||
|
| (uv_lock ? MutableQuadView.BAKE_LOCK_UV : 0)
|
||||||
|
);
|
||||||
|
quad.tag(i+1);
|
||||||
|
quad.emit();
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify if sprite covers the current quad and apply the new size
|
||||||
|
QuadPosBounds origin_bounds = QuadPosBounds.read(quad, false);
|
||||||
|
if (!bounds.matches(origin_bounds)) return i;
|
||||||
|
|
||||||
|
// apply new quad shape
|
||||||
|
quad.material(getRenderMaterial(ao));
|
||||||
|
bounds.intersection(origin_bounds, direction.getAxis()).apply(quad, origin_bounds);
|
||||||
|
quad.spriteBake( // seems to work without the flags and break with it
|
||||||
|
properties.sprite(),
|
||||||
|
MutableQuadView.BAKE_NORMALIZED
|
||||||
|
| MutableQuadView.BAKE_LOCK_UV
|
||||||
|
);
|
||||||
|
quad.tag(i+1);
|
||||||
|
quad.emit();
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import fr.adrien1106.reframed.client.ReFramedClient;
|
|||||||
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
|
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
|
||||||
import fr.adrien1106.reframed.client.model.QuadPosBounds;
|
import fr.adrien1106.reframed.client.model.QuadPosBounds;
|
||||||
import fr.adrien1106.reframed.mixin.model.WeightedBakedModelAccessor;
|
import fr.adrien1106.reframed.mixin.model.WeightedBakedModelAccessor;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
|
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
|
import net.fabricmc.fabric.api.renderer.v1.material.MaterialFinder;
|
||||||
@ -29,7 +30,6 @@ import net.minecraft.util.math.random.Random;
|
|||||||
import net.minecraft.world.BlockRenderView;
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@ -40,20 +40,20 @@ public class CamoAppearanceManager {
|
|||||||
for(BlendMode blend : BlendMode.values()) {
|
for(BlendMode blend : BlendMode.values()) {
|
||||||
finder.clear().disableDiffuse(false).blendMode(blend);
|
finder.clear().disableDiffuse(false).blendMode(blend);
|
||||||
|
|
||||||
materialsWithoutAo.put(blend, finder.ambientOcclusion(TriState.FALSE).find());
|
materials.put(blend, finder.ambientOcclusion(TriState.FALSE).find());
|
||||||
materialsWithAo.put(blend, finder.ambientOcclusion(TriState.DEFAULT).find()); //not "true" since that *forces* AO, i just want to *allow* AO
|
ao_materials.put(blend, finder.ambientOcclusion(TriState.DEFAULT).find()); //not "true" since that *forces* AO, i just want to *allow* AO
|
||||||
}
|
}
|
||||||
|
|
||||||
Sprite sprite = spriteLookup.apply(DEFAULT_SPRITE_MAIN);
|
Sprite sprite = spriteLookup.apply(DEFAULT_SPRITE_MAIN);
|
||||||
if(sprite == null) throw new IllegalStateException("Couldn't locate " + DEFAULT_SPRITE_MAIN + " !");
|
if(sprite == null) throw new IllegalStateException("Couldn't locate " + DEFAULT_SPRITE_MAIN + " !");
|
||||||
this.default_appearance = new SingleSpriteAppearance(sprite, materialsWithoutAo.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
|
this.default_appearance = new SingleSpriteAppearance(sprite, materials.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
|
||||||
|
|
||||||
sprite = spriteLookup.apply(DEFAULT_SPRITE_SECONDARY);
|
sprite = spriteLookup.apply(DEFAULT_SPRITE_SECONDARY);
|
||||||
if(sprite == null) throw new IllegalStateException("Couldn't locate " + DEFAULT_SPRITE_MAIN + " !");
|
if(sprite == null) throw new IllegalStateException("Couldn't locate " + DEFAULT_SPRITE_MAIN + " !");
|
||||||
this.accent_appearance = new SingleSpriteAppearance(sprite, materialsWithoutAo.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
|
this.accent_appearance = new SingleSpriteAppearance(sprite, materials.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
|
||||||
|
|
||||||
sprite = spriteLookup.apply(BARRIER_SPRITE_ID);
|
sprite = spriteLookup.apply(BARRIER_SPRITE_ID);
|
||||||
this.barrierItemAppearance = new SingleSpriteAppearance(sprite, materialsWithoutAo.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
|
this.barrierItemAppearance = new SingleSpriteAppearance(sprite, materials.get(BlendMode.CUTOUT), serial_number.getAndIncrement());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final SpriteIdentifier DEFAULT_SPRITE_MAIN = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier(ReFramed.MODID, "block/framed_block"));
|
protected static final SpriteIdentifier DEFAULT_SPRITE_MAIN = new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, new Identifier(ReFramed.MODID, "block/framed_block"));
|
||||||
@ -63,12 +63,16 @@ public class CamoAppearanceManager {
|
|||||||
private final CamoAppearance default_appearance;
|
private final CamoAppearance default_appearance;
|
||||||
private final CamoAppearance accent_appearance;
|
private final CamoAppearance accent_appearance;
|
||||||
private final CamoAppearance barrierItemAppearance;
|
private final CamoAppearance barrierItemAppearance;
|
||||||
|
|
||||||
private final ConcurrentHashMap<BlockState, CamoAppearance> appearanceCache = new ConcurrentHashMap<>(); //Mutable, append-only cache
|
private static final Object2ObjectLinkedOpenHashMap<BlockState, CamoAppearance> APPEARANCE_CACHE =
|
||||||
|
new Object2ObjectLinkedOpenHashMap<>(2048, 0.25f) {
|
||||||
|
@Override
|
||||||
|
protected void rehash(int n) {}
|
||||||
|
};
|
||||||
private final AtomicInteger serial_number = new AtomicInteger(0); //Mutable
|
private final AtomicInteger serial_number = new AtomicInteger(0); //Mutable
|
||||||
|
|
||||||
private final EnumMap<BlendMode, RenderMaterial> materialsWithAo = new EnumMap<>(BlendMode.class);
|
private final EnumMap<BlendMode, RenderMaterial> ao_materials = new EnumMap<>(BlendMode.class);
|
||||||
private final EnumMap<BlendMode, RenderMaterial> materialsWithoutAo = new EnumMap<>(BlendMode.class); //Immutable contents
|
private final EnumMap<BlendMode, RenderMaterial> materials = new EnumMap<>(BlendMode.class); //Immutable contents
|
||||||
|
|
||||||
public CamoAppearance getDefaultAppearance(int appearance) {
|
public CamoAppearance getDefaultAppearance(int appearance) {
|
||||||
return appearance == 2 ? accent_appearance: default_appearance;
|
return appearance == 2 ? accent_appearance: default_appearance;
|
||||||
@ -81,11 +85,17 @@ public class CamoAppearanceManager {
|
|||||||
if (model instanceof DynamicBakedModel dynamic_model) {
|
if (model instanceof DynamicBakedModel dynamic_model) {
|
||||||
return computeAppearance(dynamic_model.computeQuads(world, state, pos, theme_index), state);
|
return computeAppearance(dynamic_model.computeQuads(world, state, pos, theme_index), state);
|
||||||
}
|
}
|
||||||
return appearanceCache.computeIfAbsent(state, block_state -> computeAppearance(model, block_state));
|
|
||||||
|
// refresh cache
|
||||||
|
if (APPEARANCE_CACHE.containsKey(state)) return APPEARANCE_CACHE.getAndMoveToFirst(state);
|
||||||
|
|
||||||
|
CamoAppearance appearance = computeAppearance(model, state);
|
||||||
|
APPEARANCE_CACHE.putAndMoveToFirst(state, appearance);
|
||||||
|
return appearance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RenderMaterial getCachedMaterial(BlockState state, boolean ao) {
|
public RenderMaterial getCachedMaterial(BlockState state, boolean ao) {
|
||||||
Map<BlendMode, RenderMaterial> m = ao ? materialsWithAo : materialsWithoutAo;
|
Map<BlendMode, RenderMaterial> m = ao ? ao_materials : materials;
|
||||||
return m.get(BlendMode.fromRenderLayer(RenderLayers.getBlockLayer(state)));
|
return m.get(BlendMode.fromRenderLayer(RenderLayers.getBlockLayer(state)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,33 +6,22 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class ComputedAppearance implements CamoAppearance {
|
public class ComputedAppearance extends CamoAppearance {
|
||||||
private final Appearance appearance;
|
private final Appearance appearance;
|
||||||
private final int id;
|
|
||||||
private final RenderMaterial matWithAo;
|
|
||||||
private final RenderMaterial matWithoutAo;
|
|
||||||
|
|
||||||
public ComputedAppearance(@NotNull Appearance appearance, RenderMaterial withAo, RenderMaterial withoutAo, int id) {
|
public ComputedAppearance(@NotNull Appearance appearance, RenderMaterial ao_material, RenderMaterial material, int id) {
|
||||||
|
super(ao_material, material, id);
|
||||||
this.appearance = appearance;
|
this.appearance = appearance;
|
||||||
this.id = id;
|
|
||||||
|
|
||||||
this.matWithAo = withAo;
|
|
||||||
this.matWithoutAo = withoutAo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull RenderMaterial getRenderMaterial(boolean ao) {
|
public @NotNull List<SpriteProperties> getSprites(Direction dir, int model_id) {
|
||||||
return ao ? matWithAo : matWithoutAo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull List<SpriteProperties> getSprites(Direction dir, long seed) {
|
|
||||||
return appearance.sprites().get(dir);
|
return appearance.sprites().get(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasColor(Direction dir, long seed, int index) {
|
public boolean hasColor(Direction dir, int model_id, int index) {
|
||||||
List<SpriteProperties> properties = getSprites(dir, seed);
|
List<SpriteProperties> properties = getSprites(dir, model_id);
|
||||||
if (index != 0) index = properties.size() - index;
|
if (index != 0) index = properties.size() - index;
|
||||||
return properties.get(index).has_colors();
|
return properties.get(index).has_colors();
|
||||||
}
|
}
|
||||||
@ -40,13 +29,7 @@ public class ComputedAppearance implements CamoAppearance {
|
|||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(this == o) return true;
|
if(this == o) return true;
|
||||||
if(o == null || getClass() != o.getClass()) return false;
|
if(!(o instanceof ComputedAppearance that)) return false;
|
||||||
ComputedAppearance that = (ComputedAppearance) o;
|
|
||||||
return id == that.id;
|
return id == that.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,47 +7,33 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SingleSpriteAppearance implements CamoAppearance {
|
public class SingleSpriteAppearance extends CamoAppearance {
|
||||||
private final @NotNull Sprite defaultSprite;
|
private final @NotNull Sprite defaultSprite;
|
||||||
private final RenderMaterial mat;
|
|
||||||
private final int id;
|
|
||||||
|
|
||||||
public SingleSpriteAppearance(@NotNull Sprite defaultSprite, RenderMaterial mat, int id) {
|
public SingleSpriteAppearance(@NotNull Sprite defaultSprite, RenderMaterial mat, int id) {
|
||||||
|
super(null, mat, id);
|
||||||
this.defaultSprite = defaultSprite;
|
this.defaultSprite = defaultSprite;
|
||||||
this.mat = mat;
|
|
||||||
this.id = id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull RenderMaterial getRenderMaterial(boolean ao) {
|
public @NotNull List<SpriteProperties> getSprites(Direction dir, int model_id) {
|
||||||
return mat;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull List<SpriteProperties> getSprites(Direction dir, long seed) {
|
|
||||||
return List.of(new SpriteProperties(defaultSprite, 0, null, false));
|
return List.of(new SpriteProperties(defaultSprite, 0, null, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasColor(Direction dir, long seed, int index) {
|
public boolean hasColor(Direction dir, int model_id, int index) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(this == o) return true;
|
if(this == o) return true;
|
||||||
if(o == null || getClass() != o.getClass()) return false;
|
if(!(o instanceof SingleSpriteAppearance that)) return false;
|
||||||
SingleSpriteAppearance that = (SingleSpriteAppearance) o;
|
|
||||||
return id == that.id;
|
return id == that.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "SingleSpriteAppearance[defaultSprite=%s, mat=%s, id=%d]".formatted(defaultSprite, mat, id);
|
return "SingleSpriteAppearance[defaultSprite=%s, mat=%s, id=%d]".formatted(defaultSprite, material, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,25 +9,14 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class WeightedComputedAppearance implements CamoAppearance {
|
public class WeightedComputedAppearance extends CamoAppearance {
|
||||||
private final List<Weighted.Present<Appearance>> appearances;
|
private final List<Weighted.Present<Appearance>> appearances;
|
||||||
private final int total_weight;
|
private final int total_weight;
|
||||||
private final int id;
|
|
||||||
private final RenderMaterial matWithAo;
|
|
||||||
private final RenderMaterial matWithoutAo;
|
|
||||||
|
|
||||||
public WeightedComputedAppearance(@NotNull List<Weighted.Present<Appearance>> appearances, RenderMaterial withAo, RenderMaterial withoutAo, int id) {
|
public WeightedComputedAppearance(@NotNull List<Weighted.Present<Appearance>> appearances, RenderMaterial ao_material, RenderMaterial material, int id) {
|
||||||
|
super(ao_material, material, id);
|
||||||
this.appearances = appearances;
|
this.appearances = appearances;
|
||||||
this.total_weight = Weighting.getWeightSum(appearances);
|
this.total_weight = Weighting.getWeightSum(appearances);
|
||||||
this.id = id;
|
|
||||||
|
|
||||||
this.matWithAo = withAo;
|
|
||||||
this.matWithoutAo = withoutAo;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull RenderMaterial getRenderMaterial(boolean ao) {
|
|
||||||
return ao ? matWithAo : matWithoutAo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -37,21 +26,19 @@ public class WeightedComputedAppearance implements CamoAppearance {
|
|||||||
.map(appearances::indexOf).orElse(0);
|
.map(appearances::indexOf).orElse(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Appearance getAppearance(long seed) {
|
private Appearance getAppearance(int model_id) {
|
||||||
Random random = Random.create(seed);
|
return appearances.get(model_id).getData();
|
||||||
return Weighting.getAt(appearances, Math.abs((int)random.nextLong()) % total_weight)
|
|
||||||
.map(Weighted.Present::getData).get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull List<SpriteProperties> getSprites(Direction dir, long seed) {
|
public @NotNull List<SpriteProperties> getSprites(Direction dir, int model_id) {
|
||||||
return getAppearance(seed).sprites().get(dir);
|
return getAppearance(model_id).sprites().get(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasColor(Direction dir, long seed, int index) {
|
public boolean hasColor(Direction dir, int model_id, int index) {
|
||||||
List<SpriteProperties> properties = getSprites(dir, seed);
|
List<SpriteProperties> properties = getSprites(dir, model_id);
|
||||||
if (index != 0) index = properties.size() - index;
|
if (index != 0) index = properties.size() - index;
|
||||||
return properties.get(index).has_colors();
|
return properties.get(index).has_colors();
|
||||||
}
|
}
|
||||||
@ -59,13 +46,7 @@ public class WeightedComputedAppearance implements CamoAppearance {
|
|||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if(this == o) return true;
|
if(this == o) return true;
|
||||||
if(o == null || getClass() != o.getClass()) return false;
|
if(!(o instanceof WeightedComputedAppearance that)) return false;
|
||||||
WeightedComputedAppearance that = (WeightedComputedAppearance) o;
|
|
||||||
return id == that.id;
|
return id == that.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ public class BlockItemMixin {
|
|||||||
|| !Block.isShapeFullCube(block.getBlock().getDefaultState().getCollisionShape(world, pos))
|
|| !Block.isShapeFullCube(block.getBlock().getDefaultState().getCollisionShape(world, pos))
|
||||||
) return;
|
) return;
|
||||||
NbtCompound new_comp = new NbtCompound();
|
NbtCompound new_comp = new NbtCompound();
|
||||||
|
player.getOffHandStack().decrement(1);
|
||||||
new_comp.put(BLOCKSTATE_KEY + 1, NbtHelper.fromBlockState(block.getBlock().getDefaultState()));
|
new_comp.put(BLOCKSTATE_KEY + 1, NbtHelper.fromBlockState(block.getBlock().getDefaultState()));
|
||||||
compound.set(new_comp);
|
compound.set(new_comp);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import earth.terrarium.athena.api.client.models.AthenaBlockModel;
|
|||||||
import fr.adrien1106.reframed.client.ReFramedClient;
|
import fr.adrien1106.reframed.client.ReFramedClient;
|
||||||
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
|
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
|
||||||
import fr.adrien1106.reframed.compat.RebakedAthenaModel;
|
import fr.adrien1106.reframed.compat.RebakedAthenaModel;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||||
|
@ -3,7 +3,7 @@ package fr.adrien1106.reframed.mixin.compat;
|
|||||||
import earth.terrarium.athena.api.client.utils.AppearanceAndTintGetter;
|
import earth.terrarium.athena.api.client.utils.AppearanceAndTintGetter;
|
||||||
import earth.terrarium.athena.api.client.utils.CtmUtils;
|
import earth.terrarium.athena.api.client.utils.CtmUtils;
|
||||||
import earth.terrarium.athena.impl.client.models.ConnectedBlockModel;
|
import earth.terrarium.athena.impl.client.models.ConnectedBlockModel;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.compat;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import earth.terrarium.athena.api.client.fabric.WrappedGetter;
|
import earth.terrarium.athena.api.client.fabric.WrappedGetter;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.BlockRenderView;
|
import net.minecraft.world.BlockRenderView;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.mixin.compat;
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.IBlockRenderInfoMixin;
|
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import link.infra.indium.renderer.render.BlockRenderInfo;
|
import link.infra.indium.renderer.render.BlockRenderInfo;
|
||||||
import link.infra.indium.renderer.render.TerrainBlockRenderInfo;
|
import link.infra.indium.renderer.render.TerrainBlockRenderInfo;
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
|
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package fr.adrien1106.reframed.mixin.compat;
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
|
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
|
||||||
import fr.adrien1106.reframed.util.IBlockRenderInfoMixin;
|
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
|
||||||
import fr.adrien1106.reframed.util.IMultipartBakedModelMixin;
|
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
|
||||||
import link.infra.indium.renderer.render.AbstractBlockRenderContext;
|
import link.infra.indium.renderer.render.AbstractBlockRenderContext;
|
||||||
import link.infra.indium.renderer.render.TerrainRenderContext;
|
import link.infra.indium.renderer.render.TerrainRenderContext;
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext;
|
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockRenderContext;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
@ -29,13 +30,13 @@ public abstract class IndiumTerrainRenderContextMixin extends AbstractBlockRende
|
|||||||
if (!(ctx.model() instanceof IMultipartBakedModelMixin wrapped)
|
if (!(ctx.model() instanceof IMultipartBakedModelMixin wrapped)
|
||||||
|| !(wrapped.getModel(ctx.state()) instanceof MultiRetexturableModel retexturing_model)) return;
|
|| !(wrapped.getModel(ctx.state()) instanceof MultiRetexturableModel retexturing_model)) return;
|
||||||
|
|
||||||
List<BakedModel> models = retexturing_model.models();
|
List<ForwardingBakedModel> models = retexturing_model.models();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (BakedModel bakedModel : models) {
|
for (BakedModel model : models) {
|
||||||
i++;
|
i++;
|
||||||
aoCalc.clear();
|
aoCalc.clear();
|
||||||
((IBlockRenderInfoMixin) blockInfo).prepareForBlock(ctx.state(), ctx.pos(), ctx.seed(), bakedModel.useAmbientOcclusion(), i);
|
((IBlockRenderInfoMixin) blockInfo).prepareForBlock(ctx.state(), ctx.pos(), ctx.seed(), model.useAmbientOcclusion(), i);
|
||||||
bakedModel.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
|
model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
|
||||||
}
|
}
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.mixin.compat;
|
package fr.adrien1106.reframed.mixin.compat;
|
||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
|
import me.jellysquid.mods.sodium.client.render.chunk.compile.pipeline.BlockOcclusionCache;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package fr.adrien1106.reframed.mixin.particles;
|
package fr.adrien1106.reframed.mixin.particles;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
import fr.adrien1106.reframed.block.ReFramedBlock;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
import net.minecraft.client.particle.BlockDustParticle;
|
import net.minecraft.client.particle.BlockDustParticle;
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.particles;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
import fr.adrien1106.reframed.block.ReFramedBlock;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.particles;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
import fr.adrien1106.reframed.block.ReFramedBlock;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package fr.adrien1106.reframed.mixin.render;
|
package fr.adrien1106.reframed.mixin.render;
|
||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.util.BlockHelper;
|
import fr.adrien1106.reframed.util.blocks.BlockHelper;
|
||||||
import fr.adrien1106.reframed.util.IBlockRenderInfoMixin;
|
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo;
|
import net.fabricmc.fabric.impl.client.indigo.renderer.render.BlockRenderInfo;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package fr.adrien1106.reframed.mixin.render;
|
package fr.adrien1106.reframed.mixin.render;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.util.IMultipartBakedModelMixin;
|
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
import net.minecraft.client.render.model.BakedModel;
|
||||||
import net.minecraft.client.render.model.MultipartBakedModel;
|
import net.minecraft.client.render.model.MultipartBakedModel;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package fr.adrien1106.reframed.mixin.render;
|
package fr.adrien1106.reframed.mixin.render;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
|
import fr.adrien1106.reframed.client.model.MultiRetexturableModel;
|
||||||
import fr.adrien1106.reframed.util.IBlockRenderInfoMixin;
|
import fr.adrien1106.reframed.util.mixin.IBlockRenderInfoMixin;
|
||||||
import fr.adrien1106.reframed.util.IMultipartBakedModelMixin;
|
import fr.adrien1106.reframed.util.mixin.IMultipartBakedModelMixin;
|
||||||
|
import net.fabricmc.fabric.api.renderer.v1.model.ForwardingBakedModel;
|
||||||
import net.fabricmc.fabric.impl.client.indigo.renderer.render.AbstractBlockRenderContext;
|
import net.fabricmc.fabric.impl.client.indigo.renderer.render.AbstractBlockRenderContext;
|
||||||
import net.fabricmc.fabric.impl.client.indigo.renderer.render.TerrainRenderContext;
|
import net.fabricmc.fabric.impl.client.indigo.renderer.render.TerrainRenderContext;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@ -28,13 +29,18 @@ public abstract class TerrainRenderContextMixin extends AbstractBlockRenderConte
|
|||||||
if (!(wrapper instanceof IMultipartBakedModelMixin wrapped)
|
if (!(wrapper instanceof IMultipartBakedModelMixin wrapped)
|
||||||
|| !(wrapped.getModel(state) instanceof MultiRetexturableModel retexturing_model)) return;
|
|| !(wrapped.getModel(state) instanceof MultiRetexturableModel retexturing_model)) return;
|
||||||
|
|
||||||
List<BakedModel> models = retexturing_model.models();
|
List<ForwardingBakedModel> models = retexturing_model.models();
|
||||||
|
// models.forEach(model -> // TODO self culling here
|
||||||
|
// model.getWrappedModel().getQuads(state_key, null, blockInfo.randomSupplier.get())
|
||||||
|
// .forEach(quad -> QuadPosBounds.read(getEmitter().fromVanilla(quad.getVertexData(), 0)).min_x())
|
||||||
|
// );
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (BakedModel bakedModel : models) {
|
for (BakedModel model : models) {
|
||||||
i++;
|
i++;
|
||||||
aoCalc.clear();
|
aoCalc.clear();
|
||||||
((IBlockRenderInfoMixin) blockInfo).prepareForBlock(state, pos, bakedModel.useAmbientOcclusion(), i);
|
// TODO if (state_key.getBlock() instanceof ReFramedDoubleBlock frame_block) frame_block.getRenderOutline(i);
|
||||||
bakedModel.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
|
((IBlockRenderInfoMixin) blockInfo).prepareForBlock(state, pos, model.useAmbientOcclusion(), i);
|
||||||
|
model.emitBlockQuads(blockInfo.blockView, blockInfo.blockState, blockInfo.blockPos, blockInfo.randomSupplier, this);
|
||||||
}
|
}
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.sound;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
import fr.adrien1106.reframed.block.ReFramedBlock;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.item.BlockItem;
|
import net.minecraft.item.BlockItem;
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.sound;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
import fr.adrien1106.reframed.block.ReFramedBlock;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package fr.adrien1106.reframed.mixin.sound;
|
package fr.adrien1106.reframed.mixin.sound;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
import fr.adrien1106.reframed.block.ReFramedBlock;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.entity.LivingEntity;
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
@ -2,7 +2,7 @@ package fr.adrien1106.reframed.mixin.sound;
|
|||||||
|
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
import fr.adrien1106.reframed.block.ReFramedBlock;
|
||||||
import fr.adrien1106.reframed.util.ThemeableBlockEntity;
|
import fr.adrien1106.reframed.util.blocks.ThemeableBlockEntity;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.Blocks;
|
import net.minecraft.block.Blocks;
|
||||||
import net.minecraft.client.render.WorldRenderer;
|
import net.minecraft.client.render.WorldRenderer;
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
package fr.adrien1106.reframed.util;
|
package fr.adrien1106.reframed.util.blocks;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.block.ReFramedBlock;
|
import fr.adrien1106.reframed.block.ReFramedBlock;
|
||||||
import fr.adrien1106.reframed.block.ReFramedEntity;
|
import fr.adrien1106.reframed.block.ReFramedEntity;
|
||||||
import fr.adrien1106.reframed.util.property.Corner;
|
import it.unimi.dsi.fastutil.objects.Object2ByteLinkedOpenHashMap;
|
||||||
import fr.adrien1106.reframed.util.property.StairShape;
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockEntityProvider;
|
import net.minecraft.block.BlockEntityProvider;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
@ -30,13 +29,25 @@ import java.util.Map;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.CORNER;
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.CORNER;
|
||||||
import static fr.adrien1106.reframed.util.BlockProperties.LIGHT;
|
import static fr.adrien1106.reframed.util.blocks.BlockProperties.LIGHT;
|
||||||
import static fr.adrien1106.reframed.util.property.StairShape.*;
|
import static fr.adrien1106.reframed.util.blocks.StairShape.*;
|
||||||
import static net.minecraft.util.shape.VoxelShapes.combine;
|
import static net.minecraft.util.shape.VoxelShapes.combine;
|
||||||
|
|
||||||
public class BlockHelper {
|
public class BlockHelper {
|
||||||
|
|
||||||
|
// self culling cache TODO move
|
||||||
|
private static final ThreadLocal<Object2ByteLinkedOpenHashMap<CullElement>> INNER_FACE_CULL_MAP = ThreadLocal.withInitial(() -> {
|
||||||
|
Object2ByteLinkedOpenHashMap<CullElement> object2ByteLinkedOpenHashMap = new Object2ByteLinkedOpenHashMap<>(2048, 0.25F) {
|
||||||
|
protected void rehash(int newN) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
object2ByteLinkedOpenHashMap.defaultReturnValue((byte)0);
|
||||||
|
return object2ByteLinkedOpenHashMap;
|
||||||
|
});
|
||||||
|
|
||||||
|
private record CullElement(BlockState state, int model, Direction side) {}
|
||||||
|
|
||||||
public static Corner getPlacementCorner(ItemPlacementContext ctx) {
|
public static Corner getPlacementCorner(ItemPlacementContext ctx) {
|
||||||
Direction side = ctx.getSide().getOpposite();
|
Direction side = ctx.getSide().getOpposite();
|
||||||
Vec3d pos = getHitPos(ctx.getHitPos(), ctx.getBlockPos());
|
Vec3d pos = getHitPos(ctx.getHitPos(), ctx.getBlockPos());
|
@ -1,7 +1,5 @@
|
|||||||
package fr.adrien1106.reframed.util;
|
package fr.adrien1106.reframed.util.blocks;
|
||||||
|
|
||||||
import fr.adrien1106.reframed.util.property.Corner;
|
|
||||||
import fr.adrien1106.reframed.util.property.StairShape;
|
|
||||||
import net.minecraft.state.property.BooleanProperty;
|
import net.minecraft.state.property.BooleanProperty;
|
||||||
import net.minecraft.state.property.EnumProperty;
|
import net.minecraft.state.property.EnumProperty;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package fr.adrien1106.reframed.util.property;
|
package fr.adrien1106.reframed.util.blocks;
|
||||||
|
|
||||||
import net.minecraft.util.StringIdentifiable;
|
import net.minecraft.util.StringIdentifiable;
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
@ -1,4 +1,4 @@
|
|||||||
package fr.adrien1106.reframed.util;
|
package fr.adrien1106.reframed.util.blocks;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
@ -1,4 +1,4 @@
|
|||||||
package fr.adrien1106.reframed.util.property;
|
package fr.adrien1106.reframed.util.blocks;
|
||||||
|
|
||||||
import net.minecraft.util.StringIdentifiable;
|
import net.minecraft.util.StringIdentifiable;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package fr.adrien1106.reframed.util;
|
package fr.adrien1106.reframed.util.blocks;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
package fr.adrien1106.reframed.util;
|
package fr.adrien1106.reframed.util.mixin;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
@ -1,4 +1,4 @@
|
|||||||
package fr.adrien1106.reframed.util;
|
package fr.adrien1106.reframed.util.mixin;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.client.render.model.BakedModel;
|
import net.minecraft.client.render.model.BakedModel;
|
Loading…
Reference in New Issue
Block a user