New minor version with fix for caching on dynamic models #12
@ -9,7 +9,7 @@ loader_version=0.15.6
|
|||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
modrinth_id = jCpoCBpn
|
modrinth_id = jCpoCBpn
|
||||||
mod_version = 1.5.6
|
mod_version = 1.5.7
|
||||||
maven_group = fr.adrien1106
|
maven_group = fr.adrien1106
|
||||||
archives_base_name = ReFramed
|
archives_base_name = ReFramed
|
||||||
mod_id = reframed
|
mod_id = reframed
|
||||||
|
@ -14,6 +14,7 @@ import net.minecraft.util.shape.VoxelShape;
|
|||||||
import net.minecraft.util.shape.VoxelShapes;
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
import net.minecraft.world.BlockView;
|
import net.minecraft.world.BlockView;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.WorldAccess;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -58,6 +59,41 @@ public class ReframedWallBlock extends WaterloggableReFramedBlock {
|
|||||||
super.appendProperties(builder.add(UP, EAST_WALL_SHAPE, NORTH_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE));
|
super.appendProperties(builder.add(UP, EAST_WALL_SHAPE, NORTH_WALL_SHAPE, SOUTH_WALL_SHAPE, WEST_WALL_SHAPE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockState getStateForNeighborUpdate(BlockState state, Direction dir, BlockState other_state, WorldAccess world, BlockPos pos, BlockPos moved) {
|
||||||
|
BlockState new_state = super.getStateForNeighborUpdate(state, dir, other_state, world, pos, moved);
|
||||||
|
if (dir == Direction.DOWN) return new_state;
|
||||||
|
BlockState top_state = dir == Direction.UP? other_state: world.getBlockState(pos.up());
|
||||||
|
boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN);
|
||||||
|
VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN);
|
||||||
|
if (dir == Direction.UP) {
|
||||||
|
for (Direction d : Direction.Type.HORIZONTAL) {
|
||||||
|
Property<WallShape> wall_shape = getWallShape(d);
|
||||||
|
if (state.get(wall_shape) == WallShape.NONE) continue;
|
||||||
|
new_state = new_state.with(
|
||||||
|
wall_shape,
|
||||||
|
fs
|
||||||
|
|| (top_state.contains(wall_shape) && top_state.get(wall_shape) != WallShape.NONE)
|
||||||
|
|| shouldUseTall(WALL_VOXELS[dir.ordinal() + 3], top_shape)
|
||||||
|
? WallShape.TALL
|
||||||
|
: WallShape.LOW
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return new_state.with(UP, shouldHavePost(new_state, top_state, top_shape));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean side_full = other_state.isSideSolidFullSquare(world, moved, dir.getOpposite());
|
||||||
|
if (shouldConnectTo(other_state, side_full, dir.getOpposite())) {
|
||||||
|
new_state = new_state.with(
|
||||||
|
getWallShape(dir),
|
||||||
|
fs || shouldUseTall(WALL_VOXELS[dir.ordinal() + 3], top_shape)
|
||||||
|
? WallShape.TALL
|
||||||
|
: WallShape.LOW
|
||||||
|
);
|
||||||
|
} else new_state = new_state.with(getWallShape(dir), WallShape.NONE);
|
||||||
|
return new_state.with(UP, shouldHavePost(new_state, top_state, top_shape));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
public @Nullable BlockState getPlacementState(ItemPlacementContext ctx) {
|
||||||
BlockState state = super.getPlacementState(ctx);
|
BlockState state = super.getPlacementState(ctx);
|
||||||
@ -67,9 +103,11 @@ public class ReframedWallBlock extends WaterloggableReFramedBlock {
|
|||||||
boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN);
|
boolean fs = top_state.isSideSolidFullSquare(world, pos.up(), Direction.DOWN);
|
||||||
VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN);
|
VoxelShape top_shape = fs ? null : top_state.getCollisionShape(world, pos.up()).getFace(Direction.DOWN);
|
||||||
for (Direction dir : Direction.Type.HORIZONTAL) {
|
for (Direction dir : Direction.Type.HORIZONTAL) {
|
||||||
BlockState neighbor = world.getBlockState(pos.offset(dir));
|
BlockPos offset = pos.offset(dir);
|
||||||
if (shouldConnectTo(neighbor, fs, dir.getOpposite())) {
|
BlockState neighbor = world.getBlockState(offset);
|
||||||
state.with(
|
boolean side_full = neighbor.isSideSolidFullSquare(world, offset, dir.getOpposite());
|
||||||
|
if (shouldConnectTo(neighbor, side_full, dir.getOpposite())) {
|
||||||
|
state = state.with(
|
||||||
getWallShape(dir),
|
getWallShape(dir),
|
||||||
fs || shouldUseTall(WALL_VOXELS[dir.ordinal() + 3], top_shape)
|
fs || shouldUseTall(WALL_VOXELS[dir.ordinal() + 3], top_shape)
|
||||||
? WallShape.TALL
|
? WallShape.TALL
|
||||||
@ -80,15 +118,30 @@ public class ReframedWallBlock extends WaterloggableReFramedBlock {
|
|||||||
return state.with(UP, shouldHavePost(state, top_state, top_shape));
|
return state.with(UP, shouldHavePost(state, top_state, top_shape));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState new_state, boolean moved) {
|
||||||
|
super.onStateReplaced(state, world, pos, new_state, moved);
|
||||||
|
|
||||||
|
if(!state.isOf(new_state.getBlock())) world.removeBlockEntity(pos);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
|
||||||
VoxelShape shape = state.get(UP) ? WALL_VOXELS[0]: VoxelShapes.empty();
|
VoxelShape shape = state.get(UP) ? WALL_VOXELS[0]: VoxelShapes.empty();
|
||||||
for (Direction dir : Direction.Type.HORIZONTAL) {
|
for (Direction dir : Direction.Type.HORIZONTAL) {
|
||||||
WallShape wall_shape = state.get(getWallShape(dir));
|
WallShape wall_shape = state.get(getWallShape(dir));
|
||||||
if (wall_shape != WallShape.NONE) {
|
if (wall_shape != WallShape.NONE)
|
||||||
// System.out.println("wall_shape: " + wall_shape + " wall_shape.ordinal-1: " + (wall_shape.ordinal()-1) + " dir.ordinal() - 2: " + (dir.ordinal() - 2));
|
|
||||||
shape = VoxelShapes.union(shape, WALL_VOXELS[1 + (wall_shape.ordinal()-1) * 4 + (dir.ordinal() - 2)]);
|
shape = VoxelShapes.union(shape, WALL_VOXELS[1 + (wall_shape.ordinal()-1) * 4 + (dir.ordinal() - 2)]);
|
||||||
}
|
}
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VoxelShape getCollisionShape(BlockState state, BlockView view, BlockPos pos, ShapeContext ctx) {
|
||||||
|
VoxelShape shape = state.get(UP) ? WALL_VOXELS[9]: VoxelShapes.empty();
|
||||||
|
for (Direction dir : Direction.Type.HORIZONTAL) {
|
||||||
|
if (state.get(getWallShape(dir)) != WallShape.NONE)
|
||||||
|
shape = VoxelShapes.union(shape, WALL_VOXELS[8 + dir.ordinal()]);
|
||||||
}
|
}
|
||||||
return shape;
|
return shape;
|
||||||
}
|
}
|
||||||
@ -115,10 +168,10 @@ public class ReframedWallBlock extends WaterloggableReFramedBlock {
|
|||||||
return top_state.isIn(BlockTags.WALL_POST_OVERRIDE) || top_shape == null || shouldUseTall(WALL_VOXELS[0], top_shape);
|
return top_state.isIn(BlockTags.WALL_POST_OVERRIDE) || top_shape == null || shouldUseTall(WALL_VOXELS[0], top_shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean shouldConnectTo(BlockState state, boolean faceFullSquare, Direction side) {
|
private static boolean shouldConnectTo(BlockState state, boolean side_full, Direction side) {
|
||||||
Block block = state.getBlock();
|
Block block = state.getBlock();
|
||||||
boolean bl = block instanceof FenceGateBlock && FenceGateBlock.canWallConnect(state, side);
|
boolean bl = block instanceof FenceGateBlock && FenceGateBlock.canWallConnect(state, side);
|
||||||
return state.isIn(BlockTags.WALLS) || !WallBlock.cannotConnect(state) && faceFullSquare || block instanceof PaneBlock || bl;
|
return state.isIn(BlockTags.WALLS) || !WallBlock.cannotConnect(state) && side_full || block instanceof PaneBlock || bl;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean shouldUseTall(VoxelShape self_shape, VoxelShape other_shape) {
|
private static boolean shouldUseTall(VoxelShape self_shape, VoxelShape other_shape) {
|
||||||
@ -141,9 +194,11 @@ public class ReframedWallBlock extends WaterloggableReFramedBlock {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
VoxelShape POST = createCuboidShape(4, 0, 4, 12, 16, 12);
|
VoxelShape POST = createCuboidShape(4, 0, 4, 12, 16, 12);
|
||||||
|
VoxelShape POST_COLLISION = createCuboidShape(4, 0, 4, 12, 24, 12);
|
||||||
VoxelShape LOW = createCuboidShape(5, 0, 0, 11, 14, 8);
|
VoxelShape LOW = createCuboidShape(5, 0, 0, 11, 14, 8);
|
||||||
VoxelShape TALL = createCuboidShape(5, 0, 0, 11, 16, 8);
|
VoxelShape TALL = createCuboidShape(5, 0, 0, 11, 16, 8);
|
||||||
WALL_VOXELS = VoxelHelper.VoxelListBuilder.create(POST, 9)
|
VoxelShape SIDE_COLLISION = createCuboidShape(5, 0, 0, 11, 24, 8);
|
||||||
|
WALL_VOXELS = VoxelHelper.VoxelListBuilder.create(POST, 14)
|
||||||
.add(LOW)
|
.add(LOW)
|
||||||
.add(VoxelHelper::mirrorZ)
|
.add(VoxelHelper::mirrorZ)
|
||||||
.add(VoxelHelper::rotateY)
|
.add(VoxelHelper::rotateY)
|
||||||
@ -152,6 +207,11 @@ public class ReframedWallBlock extends WaterloggableReFramedBlock {
|
|||||||
.add(VoxelHelper::mirrorZ)
|
.add(VoxelHelper::mirrorZ)
|
||||||
.add(VoxelHelper::rotateY)
|
.add(VoxelHelper::rotateY)
|
||||||
.add(VoxelHelper::mirrorX)
|
.add(VoxelHelper::mirrorX)
|
||||||
|
.add(POST_COLLISION)
|
||||||
|
.add(SIDE_COLLISION)
|
||||||
|
.add(VoxelHelper::mirrorZ)
|
||||||
|
.add(VoxelHelper::rotateY)
|
||||||
|
.add(VoxelHelper::mirrorX)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,9 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
|||||||
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 = getRetexturedMesh(new MeshCacheKey(frame_block.getModelCacheKey(state), camo, model_id), state);
|
MeshCacheKey key = new MeshCacheKey(frame_block.getModelCacheKey(state), camo, model_id);
|
||||||
|
// do not clutter the cache with single-use meshes
|
||||||
|
Mesh untintedMesh = camo.hashCode() == -1 ? transformMesh(key, state) : getRetexturedMesh(key, state);
|
||||||
|
|
||||||
//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.
|
||||||
|
@ -95,7 +95,7 @@ public class CamoAppearanceManager {
|
|||||||
model = dynamic_model.computeQuads(world, state, pos, theme_index);
|
model = dynamic_model.computeQuads(world, state, pos, theme_index);
|
||||||
// if model isn't rebaked its just wrapped (i.e. not dynamic and may be cached)
|
// if model isn't rebaked its just wrapped (i.e. not dynamic and may be cached)
|
||||||
if (model instanceof RebakedModel) {
|
if (model instanceof RebakedModel) {
|
||||||
CamoAppearance appearance = computeAppearance(model, state);
|
CamoAppearance appearance = computeAppearance(model, state, !item);
|
||||||
if (item) APPEARANCE_CACHE.put(state, appearance);
|
if (item) APPEARANCE_CACHE.put(state, appearance);
|
||||||
return appearance;
|
return appearance;
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ public class CamoAppearanceManager {
|
|||||||
// refresh cache
|
// refresh cache
|
||||||
if (APPEARANCE_CACHE.asMap().containsKey(state)) return APPEARANCE_CACHE.getIfPresent(state);
|
if (APPEARANCE_CACHE.asMap().containsKey(state)) return APPEARANCE_CACHE.getIfPresent(state);
|
||||||
|
|
||||||
CamoAppearance appearance = computeAppearance(model, state);
|
CamoAppearance appearance = computeAppearance(model, state, false);
|
||||||
APPEARANCE_CACHE.put(state, appearance);
|
APPEARANCE_CACHE.put(state, appearance);
|
||||||
return appearance;
|
return appearance;
|
||||||
}
|
}
|
||||||
@ -118,7 +118,7 @@ public class CamoAppearanceManager {
|
|||||||
// The computeIfAbsent map update will work without corrupting the map, but there will be some "wasted effort" computing the value twice.
|
// The computeIfAbsent map update will work without corrupting the map, but there will be some "wasted effort" computing the value twice.
|
||||||
// The results are going to be the same, apart from their serialNumbers differing (= their equals & hashCode differing).
|
// The results are going to be the same, apart from their serialNumbers differing (= their equals & hashCode differing).
|
||||||
// Tiny amount of wasted space in some caches if CamoAppearances are used as a map key, then. IMO it's not a critical issue.
|
// Tiny amount of wasted space in some caches if CamoAppearances are used as a map key, then. IMO it's not a critical issue.
|
||||||
private CamoAppearance computeAppearance(BakedModel model, BlockState state) {
|
private CamoAppearance computeAppearance(BakedModel model, BlockState state, boolean is_dynamic) {
|
||||||
if(state.getBlock() == Blocks.BARRIER) return barrierItemAppearance;
|
if(state.getBlock() == Blocks.BARRIER) return barrierItemAppearance;
|
||||||
|
|
||||||
if (!(model instanceof WeightedBakedModelAccessor weighted_model)) {
|
if (!(model instanceof WeightedBakedModelAccessor weighted_model)) {
|
||||||
@ -126,7 +126,7 @@ public class CamoAppearanceManager {
|
|||||||
getAppearance(model),
|
getAppearance(model),
|
||||||
getCachedMaterial(state, true),
|
getCachedMaterial(state, true),
|
||||||
getCachedMaterial(state, false),
|
getCachedMaterial(state, false),
|
||||||
serial_number.getAndIncrement()
|
is_dynamic ? -1 : serial_number.getAndIncrement()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
List<Weighted.Present<Appearance>> appearances = weighted_model.getModels().stream()
|
List<Weighted.Present<Appearance>> appearances = weighted_model.getModels().stream()
|
||||||
@ -137,7 +137,7 @@ public class CamoAppearanceManager {
|
|||||||
appearances,
|
appearances,
|
||||||
getCachedMaterial(state, true),
|
getCachedMaterial(state, true),
|
||||||
getCachedMaterial(state, false),
|
getCachedMaterial(state, false),
|
||||||
serial_number.getAndIncrement()
|
is_dynamic ? -1 : serial_number.getAndIncrement()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user