Merge pull request 'Athena support + stair improvements + coloration' (#5) from dev into master
All checks were successful
deploy / deploy (push) Successful in 5m13s
All checks were successful
deploy / deploy (push) Successful in 5m13s
Reviewed-on: #5
This commit is contained in:
commit
6dc0cf7fdf
15
build.gradle
15
build.gradle
@ -66,6 +66,12 @@ repositories {
|
||||
name 'altarik-releases'
|
||||
url 'https://repo.altarik.fr/releases/'
|
||||
}
|
||||
maven {
|
||||
url "https://maven.teamresourceful.com/repository/maven-public/"
|
||||
}
|
||||
maven {
|
||||
url "https://maven.resourcefulbees.com/repository/maven-public/"
|
||||
}
|
||||
mavenCentral()
|
||||
|
||||
// Add repositories to retrieve artifacts from in here.
|
||||
@ -82,6 +88,14 @@ dependencies {
|
||||
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
|
||||
// Athena for connected texture
|
||||
modCompileOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}"
|
||||
modRuntimeOnly "earth.terrarium.athena:athena-fabric-${project.minecraft_version}:${project.athena_version}"
|
||||
|
||||
// Chipped to test athena implementation
|
||||
modRuntimeOnly "com.teamresourceful.resourcefullib:resourcefullib-fabric-${project.minecraft_version}:2.4.7"
|
||||
// modRuntimeOnly "earth.terrarium.chipped:chipped-fabric-${project.minecraft_version}:3.1.2" TODO not working for some reasons
|
||||
|
||||
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||
}
|
||||
@ -91,6 +105,7 @@ processResources {
|
||||
inputs.property "minecraft_version", project.minecraft_version
|
||||
inputs.property "loader_version", project.loader_version
|
||||
inputs.property "mod_id", project.mod_id
|
||||
inputs.property "athena_version", project.athena_version
|
||||
filteringCharset "UTF-8"
|
||||
|
||||
filesMatching("fabric.mod.json") {
|
||||
|
@ -8,7 +8,7 @@ yarn_mappings=1.20.4+build.3
|
||||
loader_version=0.15.6
|
||||
|
||||
# Mod Properties
|
||||
mod_version = 1.0-SNAPSHOT
|
||||
mod_version = 1.2
|
||||
maven_group = fr.adrien1106
|
||||
archives_base_name = ReFramed
|
||||
mod_id = reframed
|
||||
@ -19,3 +19,5 @@ fabric_version=0.95.4+1.20.4
|
||||
|
||||
git_owner=Altarik
|
||||
git_repo=ReFramed
|
||||
|
||||
athena_version=3.3.0
|
||||
|
@ -25,7 +25,7 @@ import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* TODO handle grass side, multiple camos
|
||||
* TODO multiple camos
|
||||
*/
|
||||
public class ReFramed implements ModInitializer {
|
||||
public static final String MODID = "reframed";
|
||||
|
@ -459,7 +459,7 @@ public class ReFramedStairsBlock extends WaterloggableReFramedBlock implements M
|
||||
GBlockstate.when(FACING, DOWN_EAST, SHAPE, OUTER_LEFT),
|
||||
GBlockstate.when(FACING, NORTH_EAST, SHAPE, OUTER_RIGHT)),
|
||||
GBlockstate.variant(double_outer_id, true, R0, R270))
|
||||
/* OUTER BOTTOM */
|
||||
/* OUTER TOP */
|
||||
.with(When.anyOf(
|
||||
GBlockstate.when(FACING, UP_NORTH, SHAPE, OUTER_RIGHT),
|
||||
GBlockstate.when(FACING, EAST_UP, SHAPE, OUTER_LEFT),
|
||||
@ -474,12 +474,12 @@ public class ReFramedStairsBlock extends WaterloggableReFramedBlock implements M
|
||||
GBlockstate.when(FACING, SOUTH_UP, SHAPE, OUTER_LEFT),
|
||||
GBlockstate.when(FACING, UP_WEST, SHAPE, OUTER_RIGHT),
|
||||
GBlockstate.when(FACING, SOUTH_WEST, SHAPE, OUTER_LEFT)),
|
||||
GBlockstate.variant(double_outer_id, true, R180, R90))
|
||||
GBlockstate.variant(double_outer_id, true, R180, R180))
|
||||
.with(When.anyOf(
|
||||
GBlockstate.when(FACING, UP_NORTH, SHAPE, OUTER_LEFT),
|
||||
GBlockstate.when(FACING, UP_WEST, SHAPE, OUTER_LEFT),
|
||||
GBlockstate.when(FACING, WEST_NORTH, SHAPE, OUTER_LEFT)),
|
||||
GBlockstate.variant(double_outer_id, true, R270, R90));
|
||||
GBlockstate.variant(double_outer_id, true, R180, R270));
|
||||
}
|
||||
|
||||
static {
|
||||
|
@ -53,10 +53,10 @@ public class ReFramedClient implements ClientModInitializer {
|
||||
HELPER.addReFramedModel(ReFramed.id("pressure_plate_up_special") , HELPER.auto(new Identifier("block/pressure_plate_up")));
|
||||
HELPER.addReFramedModel(ReFramed.id("pressure_plate_down_special") , HELPER.auto(new Identifier("block/pressure_plate_down")));
|
||||
HELPER.addReFramedModel(ReFramed.id("slab_special") , HELPER.auto(new Identifier("block/slab")));
|
||||
HELPER.addReFramedModel(ReFramed.id("stairs_special") , HELPER.auto(new Identifier("block/stairs")));
|
||||
HELPER.addReFramedModel(ReFramed.id("stairs_special") , HELPER.auto(ReFramed.id("block/stairs")));
|
||||
HELPER.addReFramedModel(ReFramed.id("double_outer_stairs_special") , HELPER.auto(ReFramed.id("block/double_outer_stairs")));
|
||||
HELPER.addReFramedModel(ReFramed.id("inner_stairs_special") , HELPER.auto(new Identifier("block/inner_stairs")));
|
||||
HELPER.addReFramedModel(ReFramed.id("outer_stairs_special") , HELPER.auto(new Identifier("block/outer_stairs")));
|
||||
HELPER.addReFramedModel(ReFramed.id("inner_stairs_special") , HELPER.auto(ReFramed.id("block/inner_stairs")));
|
||||
HELPER.addReFramedModel(ReFramed.id("outer_stairs_special") , HELPER.auto(ReFramed.id("block/outer_stairs")));
|
||||
HELPER.addReFramedModel(ReFramed.id("outer_side_stairs_special") , HELPER.auto(ReFramed.id("block/outer_side_stairs")));
|
||||
HELPER.addReFramedModel(ReFramed.id("trapdoor_bottom_special") , HELPER.auto(new Identifier("block/template_trapdoor_bottom")));
|
||||
HELPER.addReFramedModel(ReFramed.id("trapdoor_top_special") , HELPER.auto(new Identifier("block/template_trapdoor_top")));
|
||||
|
@ -0,0 +1,10 @@
|
||||
package fr.adrien1106.reframed.client.model;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
public interface DynamicBakedModel {
|
||||
BakedModel computeQuads(BlockRenderView level, BlockState state, BlockPos pos);
|
||||
}
|
@ -15,13 +15,16 @@ import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class MeshTransformUtil {
|
||||
public static Mesh pretransformMesh(Mesh mesh, RenderContext.QuadTransform transform) {
|
||||
public static Mesh pretransformMesh(Mesh mesh, RetexturingBakedModel.RetexturingTransformer transform) {
|
||||
MeshBuilder builder = ReFramedClient.HELPER.getFabricRenderer().meshBuilder();
|
||||
QuadEmitter emitter = builder.getEmitter();
|
||||
|
||||
mesh.forEach(quad -> {
|
||||
emitter.copyFrom(quad);
|
||||
if(transform.transform(emitter)) emitter.emit();
|
||||
int i = -1;
|
||||
do {
|
||||
emitter.copyFrom(quad);
|
||||
i = transform.transform(emitter, i);
|
||||
} while (i > 0);
|
||||
});
|
||||
|
||||
return builder.build();
|
||||
|
@ -0,0 +1,79 @@
|
||||
package fr.adrien1106.reframed.client.model;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView;
|
||||
import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
public record QuadPosBounds(float min_x, float max_x, float min_y, float max_y, float min_z, float max_z) {
|
||||
|
||||
public static QuadPosBounds read(QuadView quad) {
|
||||
return read(quad, true);
|
||||
}
|
||||
|
||||
public static QuadPosBounds read(QuadView quad, boolean check_full) {
|
||||
float x0 = quad.x(0), x1 = quad.x(1), x2 = quad.x(2), x3 = quad.x(3);
|
||||
float y0 = quad.y(0), y1 = quad.y(1), y2 = quad.y(2), y3 = quad.y(3);
|
||||
float z0 = quad.z(0), z1 = quad.z(1), z2 = quad.z(2), z3 = quad.z(3);
|
||||
|
||||
// Checks if the Dimensions are either 0 or 1 except for the Axis dimension
|
||||
Direction.Axis axis = quad.nominalFace().getAxis();
|
||||
if (check_full && (axis == Direction.Axis.X || (
|
||||
(MathHelper.approximatelyEquals(x0, 0) || MathHelper.approximatelyEquals(x0, 1))
|
||||
&& (MathHelper.approximatelyEquals(x1, 0) || MathHelper.approximatelyEquals(x1, 1))
|
||||
&& (MathHelper.approximatelyEquals(x2, 0) || MathHelper.approximatelyEquals(x2, 1))
|
||||
&& (MathHelper.approximatelyEquals(x3, 0) || MathHelper.approximatelyEquals(x3, 1))
|
||||
)) && (axis == Direction.Axis.Y || (
|
||||
(MathHelper.approximatelyEquals(y0, 0) || MathHelper.approximatelyEquals(y0, 1))
|
||||
&& (MathHelper.approximatelyEquals(y1, 0) || MathHelper.approximatelyEquals(y1, 1))
|
||||
&& (MathHelper.approximatelyEquals(y2, 0) || MathHelper.approximatelyEquals(y2, 1))
|
||||
&& (MathHelper.approximatelyEquals(y3, 0) || MathHelper.approximatelyEquals(y3, 1))
|
||||
)) & (axis == Direction.Axis.Z || (
|
||||
(MathHelper.approximatelyEquals(z0, 0) || MathHelper.approximatelyEquals(z0, 1))
|
||||
&& (MathHelper.approximatelyEquals(z1, 0) || MathHelper.approximatelyEquals(z1, 1))
|
||||
&& (MathHelper.approximatelyEquals(z2, 0) || MathHelper.approximatelyEquals(z2, 1))
|
||||
&& (MathHelper.approximatelyEquals(z3, 0) || MathHelper.approximatelyEquals(z3, 1))
|
||||
))
|
||||
) return null;
|
||||
|
||||
return new QuadPosBounds(
|
||||
Math.min(Math.min(x0, x1), Math.min(x2, x3)),
|
||||
Math.max(Math.max(x0, x1), Math.max(x2, x3)),
|
||||
Math.min(Math.min(y0, y1), Math.min(y2, y3)),
|
||||
Math.max(Math.max(y0, y1), Math.max(y2, y3)),
|
||||
Math.min(Math.min(z0, z1), Math.min(z2, z3)),
|
||||
Math.max(Math.max(z0, z1), Math.max(z2, z3))
|
||||
);
|
||||
}
|
||||
|
||||
public boolean matches(QuadPosBounds other_bounds) {
|
||||
return !(
|
||||
(min_x != max_x && (min_x >= other_bounds.max_x || max_x <= other_bounds.min_x))
|
||||
|| (min_y != max_y && (min_y >= other_bounds.max_y || max_y <= other_bounds.min_y))
|
||||
|| (min_z != max_z && (min_z >= other_bounds.max_z || max_z <= other_bounds.min_z))
|
||||
);
|
||||
}
|
||||
|
||||
public QuadPosBounds intersection(QuadPosBounds other_bounds, Direction.Axis axis) {
|
||||
return new QuadPosBounds(
|
||||
axis.equals(Direction.Axis.X) ? other_bounds.min_x: Math.max(min_x, other_bounds.min_x),
|
||||
axis.equals(Direction.Axis.X) ? other_bounds.max_x: Math.min(max_x, other_bounds.max_x),
|
||||
axis.equals(Direction.Axis.Y) ? other_bounds.min_y: Math.max(min_y, other_bounds.min_y),
|
||||
axis.equals(Direction.Axis.Y) ? other_bounds.max_y: Math.min(max_y, other_bounds.max_y),
|
||||
axis.equals(Direction.Axis.Z) ? other_bounds.min_z: Math.max(min_z, other_bounds.min_z),
|
||||
axis.equals(Direction.Axis.Z) ? other_bounds.max_z: Math.min(max_z, other_bounds.max_z)
|
||||
);
|
||||
}
|
||||
|
||||
public void apply(MutableQuadView quad, QuadPosBounds origin_bounds) {
|
||||
Vector3f pos = new Vector3f();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
quad.copyPos(i, pos);
|
||||
pos.x = MathHelper.approximatelyEquals(pos.x, origin_bounds.min_x)? min_x: max_x;
|
||||
pos.y = MathHelper.approximatelyEquals(pos.y, origin_bounds.min_y)? min_y: max_y;
|
||||
pos.z = MathHelper.approximatelyEquals(pos.z, origin_bounds.min_z)? min_z: max_z;
|
||||
quad.pos(i, pos);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,10 +5,10 @@ import net.fabricmc.fabric.api.renderer.v1.mesh.QuadView;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
record QuadUvBounds(float minU, float maxU, float minV, float maxV) {
|
||||
static QuadUvBounds read(QuadView quad) {
|
||||
float u0 = quad.u(0); float u1 = quad.u(1); float u2 = quad.u(2); float u3 = quad.u(3);
|
||||
float v0 = quad.v(0); float v1 = quad.v(1); float v2 = quad.v(2); float v3 = quad.v(3);
|
||||
public record QuadUvBounds(float minU, float maxU, float minV, float maxV) {
|
||||
public static QuadUvBounds read(QuadView quad) {
|
||||
float u0 = quad.u(0), u1 = quad.u(1), u2 = quad.u(2), u3 = quad.u(3);
|
||||
float v0 = quad.v(0), v1 = quad.v(1), v2 = quad.v(2), v3 = quad.v(3);
|
||||
return new QuadUvBounds(
|
||||
Math.min(Math.min(u0, u1), Math.min(u2, u3)),
|
||||
Math.max(Math.max(u0, u1), Math.max(u2, u3)),
|
||||
@ -37,8 +37,4 @@ record QuadUvBounds(float minU, float maxU, float minV, float maxV) {
|
||||
return (value2 - low) / (high - low);
|
||||
}
|
||||
|
||||
//static float rangeRemap(float value, float low1, float high1, float low2, float high2) {
|
||||
// float value2 = MathHelper.clamp(value, low1, high1);
|
||||
// return low2 + (value2 - low1) * (high2 - low2) / (high1 - low1);
|
||||
//}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package fr.adrien1106.reframed.client.model;
|
||||
|
||||
import fr.adrien1106.reframed.block.ReFramedEntity;
|
||||
import fr.adrien1106.reframed.client.model.apperance.SpriteProperties;
|
||||
import fr.adrien1106.reframed.mixin.MinecraftAccessor;
|
||||
import fr.adrien1106.reframed.client.model.apperance.CamoAppearance;
|
||||
import fr.adrien1106.reframed.client.model.apperance.CamoAppearanceManager;
|
||||
@ -22,6 +23,7 @@ import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Supplier;
|
||||
@ -59,12 +61,12 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
||||
|
||||
@Override
|
||||
public Sprite getParticleSprite() {
|
||||
return tam.getDefaultAppearance().getSprite(Direction.UP, 0);
|
||||
return tam.getDefaultAppearance().getSprites(Direction.UP, 0).get(0).sprite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitBlockQuads(BlockRenderView blockView, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
BlockState theme = (blockView.getBlockEntityRenderData(pos) instanceof BlockState s) ? s : null;
|
||||
public void emitBlockQuads(BlockRenderView world, BlockState state, BlockPos pos, Supplier<Random> randomSupplier, RenderContext context) {
|
||||
BlockState theme = (world.getBlockEntityRenderData(pos) instanceof BlockState s) ? s : null;
|
||||
QuadEmitter quad_emitter = context.getEmitter();
|
||||
if(theme == null || theme.isAir()) {
|
||||
getUntintedRetexturedMesh(new MeshCacheKey(state, new TransformCacheKey(tam.getDefaultAppearance(), 0)), 0).outputTo(quad_emitter);
|
||||
@ -72,12 +74,12 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
||||
}
|
||||
if(theme.getBlock() == Blocks.BARRIER) return;
|
||||
|
||||
CamoAppearance camo = tam.getCamoAppearance(theme);
|
||||
CamoAppearance camo = tam.getCamoAppearance(world, theme, pos);
|
||||
long seed = theme.getRenderingSeed(pos);
|
||||
int model_id = 0;
|
||||
if (camo instanceof WeightedComputedAppearance wca) model_id = wca.getAppearanceIndex(seed);
|
||||
|
||||
int tint = 0xFF000000 | MinecraftClient.getInstance().getBlockColors().getColor(theme, blockView, pos, 0);
|
||||
int tint = 0xFF000000 | MinecraftClient.getInstance().getBlockColors().getColor(theme, world, pos, 0);
|
||||
Mesh untintedMesh = getUntintedRetexturedMesh(
|
||||
new MeshCacheKey(
|
||||
state,
|
||||
@ -105,7 +107,7 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
||||
int tint;
|
||||
BlockState theme = ReFramedEntity.readStateFromItem(stack);
|
||||
if(!theme.isAir()) {
|
||||
nbtAppearance = tam.getCamoAppearance(theme);
|
||||
nbtAppearance = tam.getCamoAppearance(null, theme, null);
|
||||
tint = 0xFF000000 | ((MinecraftAccessor) MinecraftClient.getInstance()).getItemColors().getColor(new ItemStack(theme.getBlock()), 0);
|
||||
} else {
|
||||
nbtAppearance = tam.getDefaultAppearance();
|
||||
@ -133,7 +135,7 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
||||
return MeshTransformUtil.pretransformMesh(getBaseMesh(key.state), transformer);
|
||||
}
|
||||
|
||||
protected class RetexturingTransformer implements RenderContext.QuadTransform {
|
||||
public class RetexturingTransformer {
|
||||
private final long seed;
|
||||
protected RetexturingTransformer(CamoAppearance ta, long seed) {
|
||||
this.ta = ta;
|
||||
@ -142,21 +144,49 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
||||
|
||||
protected final CamoAppearance ta;
|
||||
|
||||
@Override
|
||||
public boolean transform(MutableQuadView quad) {
|
||||
quad.material(ta.getRenderMaterial(ao));
|
||||
public int transform(QuadEmitter quad, int i) {
|
||||
if(quad.tag() == 0) return 0; //Pass the quad through unmodified.
|
||||
|
||||
int tag = quad.tag();
|
||||
if(tag == 0) return true; //Pass the quad through unmodified.
|
||||
|
||||
//The quad tag numbers were selected so this magic trick works:
|
||||
Direction direction = quad.nominalFace();
|
||||
quad.spriteBake(ta.getSprite(direction, seed), MutableQuadView.BAKE_NORMALIZED | ta.getBakeFlags(direction, seed) | (uvlock ? MutableQuadView.BAKE_LOCK_UV : 0));
|
||||
return true;
|
||||
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()
|
||||
| (uvlock ? 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( // TODO check if the flags are usefull because it seems to be braking the functioning of it
|
||||
properties.sprite(),
|
||||
MutableQuadView.BAKE_NORMALIZED
|
||||
| MutableQuadView.BAKE_LOCK_UV
|
||||
);
|
||||
quad.tag(i+1);
|
||||
quad.emit();
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
protected class TintingTransformer implements RenderContext.QuadTransform {
|
||||
protected static class TintingTransformer implements RenderContext.QuadTransform {
|
||||
private final long seed;
|
||||
protected TintingTransformer(CamoAppearance ta, int tint, long seed) {
|
||||
this.ta = ta;
|
||||
@ -169,10 +199,9 @@ public abstract class RetexturingBakedModel extends ForwardingBakedModel {
|
||||
|
||||
@Override
|
||||
public boolean transform(MutableQuadView quad) {
|
||||
int tag = quad.tag();
|
||||
if(tag == 0) return true;
|
||||
if(quad.tag() == 0) return true;
|
||||
|
||||
if(ta.hasColor(quad.nominalFace(), seed)) quad.color(tint, tint, tint, tint);
|
||||
if(ta.hasColor(quad.nominalFace(), seed, quad.tag())) quad.color(tint, tint, tint, tint);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
package fr.adrien1106.reframed.client.model.apperance;
|
||||
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.Direction;
|
||||
|
||||
public record Appearance(Sprite[] sprites, int[] flags, byte color_mask) {}
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public record Appearance(Map<Direction, List<SpriteProperties>> sprites) {}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package fr.adrien1106.reframed.client.model.apperance;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CamoAppearance {
|
||||
@NotNull RenderMaterial getRenderMaterial(boolean ao);
|
||||
@NotNull Sprite getSprite(Direction dir, long seed);
|
||||
int getBakeFlags(Direction dir, long seed);
|
||||
boolean hasColor(Direction dir, long seed);
|
||||
@NotNull List<SpriteProperties> getSprites(Direction dir, long seed);
|
||||
boolean hasColor(Direction dir, long seed, int index);
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package fr.adrien1106.reframed.client.model.apperance;
|
||||
|
||||
import fr.adrien1106.reframed.ReFramed;
|
||||
import fr.adrien1106.reframed.client.ReFramedClient;
|
||||
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
|
||||
import fr.adrien1106.reframed.client.model.QuadPosBounds;
|
||||
import fr.adrien1106.reframed.mixin.model.WeightedBakedModelAccessor;
|
||||
import net.fabricmc.fabric.api.renderer.v1.Renderer;
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.BlendMode;
|
||||
@ -21,13 +23,12 @@ import net.minecraft.client.util.SpriteIdentifier;
|
||||
import net.minecraft.screen.PlayerScreenHandler;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.collection.Weighted;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
@ -68,8 +69,14 @@ public class CamoAppearanceManager {
|
||||
return defaultAppearance;
|
||||
}
|
||||
|
||||
public CamoAppearance getCamoAppearance(BlockState state) {
|
||||
return appearanceCache.computeIfAbsent(state, this::computeAppearance);
|
||||
public CamoAppearance getCamoAppearance(BlockRenderView world, BlockState state, BlockPos pos) {
|
||||
BakedModel model = MinecraftClient.getInstance().getBlockRenderManager().getModel(state);
|
||||
|
||||
// add support for connected textures and more generally any compatible models injected so that they return baked quads
|
||||
if (model instanceof DynamicBakedModel dynamic_model) {
|
||||
return computeAppearance(dynamic_model.computeQuads(world, state, pos), state);
|
||||
}
|
||||
return appearanceCache.computeIfAbsent(state, block_state -> computeAppearance(model, block_state));
|
||||
}
|
||||
|
||||
public RenderMaterial getCachedMaterial(BlockState state, boolean ao) {
|
||||
@ -81,10 +88,9 @@ 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 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.
|
||||
private CamoAppearance computeAppearance(BlockState state) {
|
||||
private CamoAppearance computeAppearance(BakedModel model, BlockState state) {
|
||||
if(state.getBlock() == Blocks.BARRIER) return barrierItemAppearance;
|
||||
|
||||
BakedModel model = MinecraftClient.getInstance().getBlockRenderManager().getModel(state);
|
||||
if (!(model instanceof WeightedBakedModelAccessor weighted_model)) {
|
||||
return new ComputedAppearance(
|
||||
getAppearance(model),
|
||||
@ -112,42 +118,34 @@ public class CamoAppearanceManager {
|
||||
RenderMaterial material = r.materialFinder().clear().find();
|
||||
Random random = Random.create();
|
||||
|
||||
Sprite[] sprites = new Sprite[6];
|
||||
int[] flags = new int[6];
|
||||
byte[] color_mask = {0b000000};
|
||||
Map<Direction, List<SpriteProperties>> sprites = new EnumMap<>(Direction.class);
|
||||
|
||||
//Read quads off the model by their `cullface`
|
||||
Arrays.stream(Direction.values()).forEach(direction -> {
|
||||
List<BakedQuad> quads = model.getQuads(null, direction, random);
|
||||
if(quads.isEmpty() || quads.get(0) == null) {
|
||||
sprites[direction.ordinal()] = defaultAppearance.getSprite(direction, 0); // make sure direction has a sprite
|
||||
if(quads.isEmpty()) { // add default appearance if none present
|
||||
sprites.put(direction, defaultAppearance.getSprites(direction, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
BakedQuad quad = quads.get(0);
|
||||
if(quad.hasColor()) color_mask[0] |= (byte) (1 << direction.ordinal());
|
||||
|
||||
Sprite sprite = quad.getSprite();
|
||||
if(sprite == null) return;
|
||||
sprites[direction.ordinal()] = sprite;
|
||||
|
||||
//Problem: Some models (eg. pistons, stone, glazed terracotta) have their UV coordinates permuted in
|
||||
//non-standard ways. The actual png image appears sideways, but the original model's UVs rotate it right way up again.
|
||||
//If I simply display the texture on my model, it will appear sideways, like it does in the png.
|
||||
//If I can discover the pattern of rotations and flips on the original model, I can "un-rotate" the texture back
|
||||
//into a standard orientation.
|
||||
//
|
||||
//Solution: Look at the first and second vertices of the orignial quad, and decide whether their UV coordinates
|
||||
//are "low" or "high" compared to the middle of the sprite. The first two vertices uniquely determine the pattern
|
||||
//of the other two (since UV coordinates are unique and shouldn't cross). There are 16 possibilities so this information
|
||||
//is easily summarized in a bitfield, and the correct fabric rendering API "bake flags" to un-transform the sprite
|
||||
//are looked up with a simple table.
|
||||
quad_emitter.fromVanilla(quad, material, direction);
|
||||
|
||||
flags[direction.ordinal()] = getBakeFlags(quad_emitter, sprite);
|
||||
sprites.put(direction, new ArrayList<>());
|
||||
quads.forEach(quad -> {
|
||||
Sprite sprite = quad.getSprite();
|
||||
if(sprite == null) return;
|
||||
sprites.computeIfPresent(direction, (dir, pairs) -> {
|
||||
quad_emitter.fromVanilla(quad, material, direction);
|
||||
pairs.add(new SpriteProperties(
|
||||
sprite,
|
||||
getBakeFlags(quad_emitter, sprite),
|
||||
QuadPosBounds.read(quad_emitter),
|
||||
quad.hasColor())
|
||||
);
|
||||
return pairs;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return new Appearance(sprites, flags, color_mask[0]);
|
||||
return new Appearance(sprites);
|
||||
}
|
||||
|
||||
private static int getBakeFlags(QuadEmitter emitter, Sprite sprite) {
|
||||
|
@ -1,11 +1,10 @@
|
||||
package fr.adrien1106.reframed.client.model.apperance;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class ComputedAppearance implements CamoAppearance {
|
||||
private final Appearance appearance;
|
||||
@ -27,18 +26,15 @@ public class ComputedAppearance implements CamoAppearance {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Sprite getSprite(Direction dir, long seed) {
|
||||
return appearance.sprites()[dir.ordinal()];
|
||||
public @NotNull List<SpriteProperties> getSprites(Direction dir, long seed) {
|
||||
return appearance.sprites().get(dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBakeFlags(Direction dir, long seed) {
|
||||
return appearance.flags()[dir.ordinal()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasColor(Direction dir, long seed) {
|
||||
return (appearance.color_mask() & (1 << dir.ordinal())) != 0;
|
||||
public boolean hasColor(Direction dir, long seed, int index) {
|
||||
List<SpriteProperties> properties = getSprites(dir, seed);
|
||||
if (index != 0) index = properties.size() - index;
|
||||
return properties.get(index).has_colors();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -53,10 +49,4 @@ public class ComputedAppearance implements CamoAppearance {
|
||||
public int hashCode() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ComputedApperance{sprites=%s, bakeFlags=%s, hasColorMask=%s, matWithoutAo=%s, matWithAo=%s, id=%d}"
|
||||
.formatted(Arrays.toString(appearance.sprites()), Arrays.toString(appearance.flags()), appearance.color_mask(), matWithoutAo, matWithAo, id);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SingleSpriteAppearance implements CamoAppearance {
|
||||
private final @NotNull Sprite defaultSprite;
|
||||
private final RenderMaterial mat;
|
||||
@ -22,17 +24,12 @@ public class SingleSpriteAppearance implements CamoAppearance {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Sprite getSprite(Direction dir, long seed) {
|
||||
return defaultSprite;
|
||||
public @NotNull List<SpriteProperties> getSprites(Direction dir, long seed) {
|
||||
return List.of(new SpriteProperties(defaultSprite, 0, null, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBakeFlags(Direction dir, long seed) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasColor(Direction dir, long seed) {
|
||||
public boolean hasColor(Direction dir, long seed, int index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,7 @@
|
||||
package fr.adrien1106.reframed.client.model.apperance;
|
||||
|
||||
import fr.adrien1106.reframed.client.model.QuadPosBounds;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
|
||||
public record SpriteProperties(Sprite sprite, int flags, QuadPosBounds bounds, boolean has_colors) {
|
||||
}
|
@ -1,14 +1,12 @@
|
||||
package fr.adrien1106.reframed.client.model.apperance;
|
||||
|
||||
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.collection.Weighted;
|
||||
import net.minecraft.util.collection.Weighting;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class WeightedComputedAppearance implements CamoAppearance {
|
||||
@ -46,18 +44,16 @@ public class WeightedComputedAppearance implements CamoAppearance {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Sprite getSprite(Direction dir, long seed) {
|
||||
return getAppearance(seed).sprites()[dir.ordinal()];
|
||||
public @NotNull List<SpriteProperties> getSprites(Direction dir, long seed) {
|
||||
return getAppearance(seed).sprites().get(dir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBakeFlags(Direction dir, long seed) {
|
||||
return getAppearance(seed).flags()[dir.ordinal()];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasColor(Direction dir, long seed) {
|
||||
return (getAppearance(seed).color_mask() & (1 << dir.ordinal())) != 0;
|
||||
public boolean hasColor(Direction dir, long seed, int index) {
|
||||
List<SpriteProperties> properties = getSprites(dir, seed);
|
||||
if (index != 0) index = properties.size() - index;
|
||||
return properties.get(index).has_colors();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -72,11 +68,4 @@ public class WeightedComputedAppearance implements CamoAppearance {
|
||||
public int hashCode() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
Appearance appearance = appearances.get(0).getData();
|
||||
return "ComputedApperance{sprites=%s, bakeFlags=%s, hasColorMask=%s, matWithoutAo=%s, matWithAo=%s, id=%d}"
|
||||
.formatted(Arrays.toString(appearance.sprites()), Arrays.toString(appearance.flags()), appearance.color_mask(), matWithoutAo, matWithAo, id);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
package fr.adrien1106.reframed.compat;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.render.model.json.ModelOverrideList;
|
||||
import net.minecraft.client.render.model.json.ModelTransformation;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class RebakedAthenaModel implements BakedModel {
|
||||
protected final Map<Direction, List<BakedQuad>> face_quads;
|
||||
|
||||
public RebakedAthenaModel(Map<Direction, List<BakedQuad>> face_quads) {
|
||||
this.face_quads = face_quads;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(BlockState state, Direction direction, Random random) {
|
||||
return face_quads.getOrDefault(direction, List.of());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAmbientOcclusion() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDepth() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSideLit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getParticleSprite() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelTransformation getTransformation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelOverrideList getOverrides() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package fr.adrien1106.reframed.mixin;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class CompatMixinPlugin implements IMixinConfigPlugin {
|
||||
|
||||
private static final Map<String, Supplier<Boolean>> CONDITIONS = Map.of(
|
||||
"fr.adrien1106.reframed.mixin.compat.AthenaBakedModelMixin", () -> FabricLoader.getInstance().isModLoaded("athena"),
|
||||
"fr.adrien1106.reframed.mixin.compat.AthenaWrappedGetterMixin", () -> FabricLoader.getInstance().isModLoaded("athena")
|
||||
);
|
||||
|
||||
|
||||
@Override
|
||||
public void onLoad(String mixin_package) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRefMapperConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyMixin(String target_class, String mixin_class) {
|
||||
return CONDITIONS.getOrDefault(mixin_class, () -> true).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptTargets(Set<String> mine, Set<String> others) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMixins() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package fr.adrien1106.reframed.mixin.compat;
|
||||
|
||||
import earth.terrarium.athena.api.client.fabric.AthenaBakedModel;
|
||||
import earth.terrarium.athena.api.client.fabric.WrappedGetter;
|
||||
import earth.terrarium.athena.api.client.models.AthenaBlockModel;
|
||||
import fr.adrien1106.reframed.client.ReFramedClient;
|
||||
import fr.adrien1106.reframed.client.model.DynamicBakedModel;
|
||||
import fr.adrien1106.reframed.compat.RebakedAthenaModel;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
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.QuadEmitter;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Mixin(AthenaBakedModel.class)
|
||||
public abstract class AthenaBakedModelMixin implements DynamicBakedModel, BakedModel {
|
||||
|
||||
@Shadow @Final private AthenaBlockModel model;
|
||||
|
||||
@Shadow @Final private Int2ObjectMap<Sprite> textures;
|
||||
|
||||
/**
|
||||
* Reuses the emitQuad method to compute the quads to be used by the frame
|
||||
*
|
||||
* @param level - the world
|
||||
* @param state - the current block camo
|
||||
* @param pos - the block position
|
||||
* @return - the rebakedmodel containing the computed quads
|
||||
*/
|
||||
@Override
|
||||
public BakedModel computeQuads(BlockRenderView level, BlockState state, BlockPos pos) {
|
||||
if (level == null || pos == null) return this;
|
||||
|
||||
Map<Direction, List<BakedQuad>> face_quads = new HashMap<>();
|
||||
|
||||
Renderer r = ReFramedClient.HELPER.getFabricRenderer();
|
||||
QuadEmitter emitter = r.meshBuilder().getEmitter();
|
||||
|
||||
WrappedGetter getter = new WrappedGetter(level);
|
||||
Arrays.stream(Direction.values()).forEach(direction -> {
|
||||
face_quads.put(direction, new ArrayList<>());
|
||||
model.getQuads(getter, state, pos, direction).forEach(sprite -> face_quads.computeIfPresent(direction, (d, quads) -> {
|
||||
Sprite texture = textures.get(sprite.sprite());
|
||||
if (texture == null) return quads;
|
||||
emitter.square(direction, sprite.left(), sprite.bottom(), sprite.right(), sprite.top(), sprite.depth());
|
||||
|
||||
int flag = MutableQuadView.BAKE_LOCK_UV;
|
||||
|
||||
switch (sprite.rotation()) {
|
||||
case CLOCKWISE_90 -> flag |= MutableQuadView.BAKE_ROTATE_90;
|
||||
case CLOCKWISE_180 -> flag |= MutableQuadView.BAKE_ROTATE_180;
|
||||
case COUNTERCLOCKWISE_90 -> flag |= MutableQuadView.BAKE_ROTATE_270;
|
||||
}
|
||||
|
||||
emitter.spriteBake(texture, flag);
|
||||
emitter.color(-1, -1, -1, -1);
|
||||
quads.add(emitter.toBakedQuad(texture));
|
||||
return quads;
|
||||
}));
|
||||
});
|
||||
|
||||
return new RebakedAthenaModel(face_quads);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package fr.adrien1106.reframed.mixin.compat;
|
||||
|
||||
import earth.terrarium.athena.api.client.utils.AppearanceAndTintGetter;
|
||||
import earth.terrarium.athena.api.client.utils.CtmUtils;
|
||||
import earth.terrarium.athena.impl.client.models.ConnectedBlockModel;
|
||||
import fr.adrien1106.reframed.block.ReFramedEntity;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(ConnectedBlockModel.class)
|
||||
public class AthenaConnectedBlockModelMixin {
|
||||
|
||||
@Redirect(method = "getQuads",
|
||||
at = @At(value = "INVOKE", target = "Learth/terrarium/athena/api/client/utils/CtmUtils;" +
|
||||
"checkRelative(Learth/terrarium/athena/api/client/utils/AppearanceAndTintGetter;" +
|
||||
"Lnet/minecraft/block/BlockState;" +
|
||||
"Lnet/minecraft/util/math/BlockPos;" +
|
||||
"Lnet/minecraft/util/math/Direction;)Z"))
|
||||
private boolean checkForCull(AppearanceAndTintGetter level, BlockState state, BlockPos pos, Direction direction) {
|
||||
// Always get all the textures unless its another block then use default behaviour
|
||||
if (level.getBlockEntity(pos) instanceof ReFramedEntity
|
||||
|| level.getBlockEntity(pos.offset(direction)) instanceof ReFramedEntity)
|
||||
return false;
|
||||
return CtmUtils.checkRelative(level, state, pos, direction);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package fr.adrien1106.reframed.mixin.compat;
|
||||
|
||||
import earth.terrarium.athena.api.client.fabric.WrappedGetter;
|
||||
import fr.adrien1106.reframed.block.ReFramedEntity;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.BlockRenderView;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(WrappedGetter.class)
|
||||
public class AthenaWrappedGetterMixin {
|
||||
|
||||
@Shadow @Final private BlockRenderView getter;
|
||||
|
||||
@Inject(method = "getBlockState", at = @At(value = "HEAD"), cancellable = true)
|
||||
private void getCamoState(BlockPos pos, CallbackInfoReturnable<BlockState> cir) {
|
||||
if (!(getter.getBlockEntity(pos) instanceof ReFramedEntity framed_entity)) return;
|
||||
cir.setReturnValue(framed_entity.getThemeState());
|
||||
}
|
||||
|
||||
@Redirect(method = "getAppearance(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;)" +
|
||||
"Lnet/minecraft/block/BlockState;",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/BlockRenderView;" +
|
||||
"getBlockState(Lnet/minecraft/util/math/BlockPos;)" +
|
||||
"Lnet/minecraft/block/BlockState;"))
|
||||
private BlockState appearanceCamoState(BlockRenderView world, BlockPos pos) {
|
||||
if (world.getBlockEntity(pos) instanceof ReFramedEntity framed_entity) return framed_entity.getThemeState();
|
||||
return world.getBlockState(pos);
|
||||
}
|
||||
|
||||
@Redirect(method = "query",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/BlockRenderView;" +
|
||||
"getBlockState(Lnet/minecraft/util/math/BlockPos;)" +
|
||||
"Lnet/minecraft/block/BlockState;"))
|
||||
private BlockState queryCamoState(BlockRenderView world, BlockPos pos) {
|
||||
if (world.getBlockEntity(pos) instanceof ReFramedEntity framed_entity) return framed_entity.getThemeState();
|
||||
return world.getBlockState(pos);
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"parent": "minecraft:block/block",
|
||||
"textures": {
|
||||
"particle": "#side"
|
||||
@ -7,14 +6,22 @@
|
||||
"elements": [
|
||||
{
|
||||
"from": [8, 0, 0],
|
||||
"to": [16, 8, 16],
|
||||
"to": [16, 8, 8],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "north"},
|
||||
"east": {"uv": [0, 8, 16, 16], "texture": "#side", "cullface": "east"},
|
||||
"east": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "east"},
|
||||
"west": {"uv": [0, 8, 8, 16], "texture": "#side"},
|
||||
"up": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
||||
"down": {"uv": [8, 8, 16, 16], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 0, 8],
|
||||
"to": [16, 8, 16],
|
||||
"faces": {
|
||||
"east": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "east"},
|
||||
"south": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "south"},
|
||||
"west": {"uv": [0, 8, 16, 16], "texture": "#side"},
|
||||
"up": {"uv": [8, 0, 16, 16], "texture": "#top", "cullface": "up"},
|
||||
"down": {"uv": [8, 0, 16, 16], "texture": "#bottom"}
|
||||
"down": {"uv": [8, 0, 16, 8], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -22,9 +29,9 @@
|
||||
"to": [16, 16, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 8, 8], "texture": "#side"},
|
||||
"east": {"uv": [0, 0, 8, 8], "texture": "#side"},
|
||||
"east": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "east"},
|
||||
"south": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "south"},
|
||||
"west": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "west"},
|
||||
"west": {"uv": [8, 0, 16, 8], "texture": "#side"},
|
||||
"up": {"uv": [8, 8, 16, 16], "texture": "#top", "cullface": "up"}
|
||||
}
|
||||
},
|
||||
@ -35,8 +42,8 @@
|
||||
"north": {"uv": [8, 8, 16, 16], "texture": "#side"},
|
||||
"south": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "south"},
|
||||
"west": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "west"},
|
||||
"up": {"uv": [0, 8, 8, 16], "texture": "#top", "cullface": "up"},
|
||||
"down": {"uv": [0, 0, 8, 8], "texture": "#bottom"}
|
||||
"up": {"uv": [0, 8, 8, 16], "texture": "#top"},
|
||||
"down": {"uv": [0, 0, 8, 8], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -0,0 +1,65 @@
|
||||
{
|
||||
"textures": {
|
||||
"particle": "#side"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 8],
|
||||
"to": [16, 8, 16],
|
||||
"faces": {
|
||||
"east": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "east"},
|
||||
"south": {"uv": [0, 8, 16, 16], "texture": "#side", "cullface": "south"},
|
||||
"west": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "west"},
|
||||
"down": {"uv": [0, 0, 16, 8], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [8, 8, 8],
|
||||
"faces": {
|
||||
"north": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "north"},
|
||||
"west": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "west"},
|
||||
"up": {"uv": [0, 0, 8, 8], "texture": "#top"},
|
||||
"down": {"uv": [0, 8, 8, 16], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 0, 0],
|
||||
"to": [16, 8, 8],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "north"},
|
||||
"east": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "east"},
|
||||
"down": {"uv": [8, 8, 16, 16], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 8, 8],
|
||||
"to": [16, 16, 16],
|
||||
"faces": {
|
||||
"east": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "east"},
|
||||
"south": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "south"},
|
||||
"up": {"uv": [8, 8, 16, 16], "texture": "#top", "cullface": "up"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 8, 0],
|
||||
"to": [16, 16, 8],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "north"},
|
||||
"east": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "east"},
|
||||
"west": {"uv": [0, 0, 8, 8], "texture": "#side"},
|
||||
"up": {"uv": [8, 0, 16, 8], "texture": "#top", "cullface": "up"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [0, 8, 8],
|
||||
"to": [8, 16, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [8, 0, 16, 8], "texture": "#side"},
|
||||
"south": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "south"},
|
||||
"west": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "west"},
|
||||
"up": {"uv": [0, 8, 8, 16], "texture": "#top", "cullface": "up"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -1,19 +1,36 @@
|
||||
{
|
||||
"credit": "Made with Blockbench",
|
||||
"textures": {
|
||||
"particle": "#side"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [8, 0, 0],
|
||||
"to": [16, 16, 16],
|
||||
"to": [16, 16, 8],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 8, 16], "texture": "#side", "cullface": "north"},
|
||||
"east": {"uv": [0, 0, 16, 16], "texture": "#side", "cullface": "east"},
|
||||
"south": {"uv": [8, 0, 16, 16], "texture": "#side", "cullface": "south"},
|
||||
"west": {"uv": [0, 0, 16, 16], "texture": "#side"},
|
||||
"up": {"uv": [8, 0, 16, 16], "texture": "#top", "cullface": "up"},
|
||||
"down": {"uv": [8, 0, 16, 16], "texture": "#bottom", "cullface": "down"}
|
||||
"east": {"uv": [8, 0, 16, 16], "texture": "#side", "cullface": "east"},
|
||||
"west": {"uv": [0, 0, 8, 16], "texture": "#side"},
|
||||
"up": {"uv": [8, 0, 16, 8], "texture": "#top", "cullface": "up"},
|
||||
"down": {"uv": [8, 8, 16, 16], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 8, 8],
|
||||
"to": [16, 16, 16],
|
||||
"faces": {
|
||||
"east": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "east"},
|
||||
"south": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "south"},
|
||||
"west": {"uv": [8, 0, 16, 8], "texture": "#side"},
|
||||
"up": {"uv": [8, 8, 16, 16], "texture": "#top", "cullface": "up"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 0, 8],
|
||||
"to": [16, 8, 16],
|
||||
"faces": {
|
||||
"east": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "east"},
|
||||
"south": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "south"},
|
||||
"down": {"uv": [8, 0, 16, 8], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -33,7 +50,7 @@
|
||||
"name": "outer_stairs",
|
||||
"origin": [8, 8, 8],
|
||||
"color": 0,
|
||||
"children": [0, 1]
|
||||
"children": [0, 1, 2, 3]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
{
|
||||
"textures": {
|
||||
"particle": "#side"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [8, 8, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "north"},
|
||||
"south": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "south"},
|
||||
"west": {"uv": [0, 8, 16, 16], "texture": "#side", "cullface": "west"},
|
||||
"up": {"uv": [0, 0, 8, 16], "texture": "#top"},
|
||||
"down": {"uv": [0, 0, 8, 16], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 0, 0],
|
||||
"to": [16, 8, 8],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "north"},
|
||||
"east": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "east"},
|
||||
"up": {"uv": [8, 0, 16, 8], "texture": "#top"},
|
||||
"down": {"uv": [8, 8, 16, 16], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 0, 8],
|
||||
"to": [16, 8, 16],
|
||||
"faces": {
|
||||
"east": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "east"},
|
||||
"south": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "south"},
|
||||
"down": {"uv": [8, 0, 16, 8], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 8, 8],
|
||||
"to": [16, 16, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 8, 8], "texture": "#side"},
|
||||
"east": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "east"},
|
||||
"south": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "south"},
|
||||
"west": {"uv": [8, 0, 16, 8], "texture": "#side"},
|
||||
"up": {"uv": [8, 8, 16, 16], "texture": "#top", "cullface": "up"}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
54
src/main/resources/assets/reframed/models/block/stairs.json
Normal file
54
src/main/resources/assets/reframed/models/block/stairs.json
Normal file
@ -0,0 +1,54 @@
|
||||
{
|
||||
"parent": "block/block",
|
||||
"textures": {
|
||||
"particle": "#side"
|
||||
},
|
||||
"elements": [
|
||||
{
|
||||
"from": [0, 0, 0],
|
||||
"to": [8, 8, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "north"},
|
||||
"south": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "south"},
|
||||
"west": {"uv": [0, 8, 16, 16], "texture": "#side", "cullface": "west"},
|
||||
"up": {"uv": [0, 0, 8, 16], "texture": "#top"},
|
||||
"down": {"uv": [0, 0, 8, 16], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 0, 0],
|
||||
"to": [16, 8, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 8, 8, 16], "texture": "#side", "cullface": "north"},
|
||||
"east": {"uv": [0, 8, 16, 16], "texture": "#side", "cullface": "east"},
|
||||
"south": {"uv": [8, 8, 16, 16], "texture": "#side", "cullface": "south"},
|
||||
"down": {"uv": [8, 0, 16, 16], "texture": "#bottom", "cullface": "down"}
|
||||
}
|
||||
},
|
||||
{
|
||||
"from": [8, 8, 0],
|
||||
"to": [16, 16, 16],
|
||||
"faces": {
|
||||
"north": {"uv": [0, 0, 8, 8], "texture": "#side", "cullface": "north"},
|
||||
"east": {"uv": [0, 0, 16, 8], "texture": "#side", "cullface": "east"},
|
||||
"south": {"uv": [8, 0, 16, 8], "texture": "#side", "cullface": "south"},
|
||||
"west": {"uv": [0, 0, 16, 8], "texture": "#side"},
|
||||
"up": {"uv": [8, 0, 16, 16], "texture": "#top", "cullface": "up"}
|
||||
}
|
||||
}
|
||||
],
|
||||
"display": {
|
||||
"thirdperson_lefthand": {
|
||||
"rotation": [75, -135, 0],
|
||||
"translation": [0, 2.5, 0],
|
||||
"scale": [0.375, 0.375, 0.375]
|
||||
},
|
||||
"gui": {
|
||||
"rotation": [30, 135, 0],
|
||||
"scale": [0.625, 0.625, 0.625]
|
||||
},
|
||||
"head": {
|
||||
"rotation": [0, -90, 0]
|
||||
}
|
||||
}
|
||||
}
|
@ -29,5 +29,8 @@
|
||||
"minecraft": "${minecraft_version}",
|
||||
"fabricloader": "^${loader_version}",
|
||||
"fabric-api": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"athena": "^${athena_version}"
|
||||
}
|
||||
}
|
@ -1,23 +1,26 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "fr.adrien1106.reframed.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
"WallBlockAccessor",
|
||||
"particles.MixinEntity",
|
||||
"particles.MixinLivingEntity"
|
||||
],
|
||||
"client": [
|
||||
"MinecraftAccessor",
|
||||
"BlockRenderInfoMixin",
|
||||
"BlockMixin",
|
||||
"particles.AccessorParticle",
|
||||
"particles.AccessorSpriteBillboardParticle",
|
||||
"particles.MixinBlockDustParticle",
|
||||
"particles.MixinBlockDustParticle",
|
||||
"model.WeightedBakedModelAccessor"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
"required": true,
|
||||
"package": "fr.adrien1106.reframed.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"plugin": "fr.adrien1106.reframed.mixin.CompatMixinPlugin",
|
||||
"mixins": [
|
||||
"WallBlockAccessor",
|
||||
"particles.MixinEntity",
|
||||
"particles.MixinLivingEntity"
|
||||
],
|
||||
"client": [
|
||||
"BlockMixin",
|
||||
"BlockRenderInfoMixin",
|
||||
"MinecraftAccessor",
|
||||
"compat.AthenaBakedModelMixin",
|
||||
"compat.AthenaWrappedGetterMixin",
|
||||
"compat.AthenaConnectedBlockModelMixin",
|
||||
"model.WeightedBakedModelAccessor",
|
||||
"particles.AccessorParticle",
|
||||
"particles.AccessorSpriteBillboardParticle",
|
||||
"particles.MixinBlockDustParticle"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user