mirror of
https://github.com/GTNewHorizons/GTNHLib.git
synced 2026-11-08 12:34:52 +00:00
Add more model patches (#373)
This commit is contained in:
1 parent
d9d69087a5
commit
cab49dc8de
24 files changed
+237
-169
No files matched your search
@@ -29,10 +29,12 @@ import com.gtnewhorizon.gtnhlib.network.PacketMessageAboveHotbar;
|
||||
import com.gtnewhorizon.gtnhlib.network.PacketViewDistance;
|
||||
import com.gtnewhorizon.gtnhlib.teams.TeamAdminCommand;
|
||||
import com.gtnewhorizon.gtnhlib.teams.TeamCommand;
|
||||
import com.gtnewhorizon.gtnhlib.test.block.BlockRngTest;
|
||||
import com.gtnewhorizon.gtnhlib.test.block.BlockTest;
|
||||
import com.gtnewhorizon.gtnhlib.test.block.BlockTestLectern;
|
||||
import com.gtnewhorizon.gtnhlib.test.block.BlockTestTint;
|
||||
import com.gtnewhorizon.gtnhlib.test.block.BlockTestTintMul;
|
||||
import com.gtnewhorizon.gtnhlib.test.block.BlockWeightedRngTest;
|
||||
import com.gtnewhorizon.gtnhlib.test.item.TestItem;
|
||||
import com.gtnewhorizon.gtnhlib.util.numberformatting.NumberFormatConfig;
|
||||
import com.gtnewhorizon.gtnhlib.util.numberformatting.NumberFormatUtil;
|
||||
@@ -66,6 +68,8 @@ public class CommonProxy {
|
||||
BlockTestLectern.register();
|
||||
BlockTestTint.register();
|
||||
BlockTestTintMul.register();
|
||||
BlockRngTest.register();
|
||||
BlockWeightedRngTest.register();
|
||||
}
|
||||
|
||||
if (GTNHLibConfig.enableTestItems) {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package com.gtnewhorizon.gtnhlib.client.model;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.api.util.NormI8.*;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing.*;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.api.util.NormI8.unpackX;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.api.util.NormI8.unpackY;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.api.util.NormI8.unpackZ;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing.DIRECTIONS;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing.VALUES;
|
||||
import static com.gtnewhorizon.gtnhlib.util.CoordinatePacker.pack;
|
||||
import static java.lang.Float.intBitsToFloat;
|
||||
import static java.lang.Math.max;
|
||||
import static net.minecraftforge.client.IItemRenderer.ItemRenderType.ENTITY;
|
||||
@@ -18,7 +22,6 @@ import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.ForgeHooksClient;
|
||||
import net.minecraftforge.client.IItemRenderer;
|
||||
|
||||
@@ -38,6 +41,7 @@ import com.gtnewhorizon.gtnhlib.client.renderer.cel.api.util.NormI8;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.ModelQuadView;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing;
|
||||
import com.gtnewhorizon.gtnhlib.core.fml.transformers.BlockIconTransformer;
|
||||
import com.gtnewhorizon.gtnhlib.util.StdLCG;
|
||||
import com.gtnewhorizons.angelica.api.ThreadSafeISBRH;
|
||||
|
||||
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
|
||||
@@ -53,7 +57,7 @@ public class ModelISBRH implements ISimpleBlockRenderingHandler, IItemRenderer {
|
||||
/// implement {@link BlockModelInfo} instead, and simply always return true.
|
||||
public static final int JSON_ISBRH_ID = RenderingRegistry.getNextAvailableRenderId();
|
||||
|
||||
private final Random RAND = new Random();
|
||||
private final Random RAND = new StdLCG();
|
||||
|
||||
private final WorldContext worldContext = new WorldContext();
|
||||
private final ItemContext itemContext = new ItemContext();
|
||||
@@ -66,26 +70,21 @@ public class ModelISBRH implements ISimpleBlockRenderingHandler, IItemRenderer {
|
||||
@Override
|
||||
public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId,
|
||||
RenderBlocks renderer) {
|
||||
final Random random = world instanceof World worldIn ? worldIn.rand : RAND;
|
||||
final Tessellator tesselator = TessellatorManager.get();
|
||||
|
||||
// Get the model!
|
||||
final int meta = world.getBlockMetadata(x, y, z);
|
||||
|
||||
worldContext.world = world;
|
||||
worldContext.x = x;
|
||||
worldContext.y = y;
|
||||
worldContext.z = z;
|
||||
worldContext.blockState = BlockPropertyRegistry.getBlockState(world, x, y, z);
|
||||
worldContext.random = random;
|
||||
|
||||
worldContext.set(world, x, y, z, RAND);
|
||||
final BakedModel model = ModelRegistry.getBakedModel(worldContext);
|
||||
|
||||
int color = model.getColor(world, x, y, z, block, meta, random);
|
||||
int color = model.getColor(world, x, y, z, block, meta, RAND);
|
||||
|
||||
var rendered = false;
|
||||
for (var dir : VALUES) {
|
||||
worldContext.quadFacing = dir;
|
||||
worldContext.random.setSeed(pack(x, y, z));
|
||||
|
||||
final var quads = model.getQuads(worldContext);
|
||||
if (quads.isEmpty()) continue;
|
||||
if (dir.isDirection() && !renderer.renderAllFaces
|
||||
@@ -230,7 +229,7 @@ public class ModelISBRH implements ISimpleBlockRenderingHandler, IItemRenderer {
|
||||
}
|
||||
|
||||
// The face is inset to some degree, pick self light (if transparent)
|
||||
if (block.getLightOpacity(world, x, y, z) != 0) {
|
||||
if (block.getLightOpacity(world, x, y, z) < 255) {
|
||||
return getBrightness(block, quad, world, x, y, z);
|
||||
}
|
||||
|
||||
@@ -306,6 +305,8 @@ public class ModelISBRH implements ISimpleBlockRenderingHandler, IItemRenderer {
|
||||
itemContext.stack = stack;
|
||||
itemContext.blockState = BlockPropertyRegistry.getBlockState(stack);
|
||||
itemContext.random = RAND;
|
||||
// I mean, I *could* pack 0, 0, 0. But that seems like a waste when I know the answer...
|
||||
itemContext.random.setSeed(0);
|
||||
|
||||
final BakedModel model = ModelRegistry.getBakedModel(itemContext);
|
||||
|
||||
@@ -318,6 +319,9 @@ public class ModelISBRH implements ISimpleBlockRenderingHandler, IItemRenderer {
|
||||
int color = model.getColor(null, 0, 0, 0, block, meta, RAND);
|
||||
|
||||
for (ModelQuadFacing dir : VALUES) {
|
||||
// I don't *like* reseeding the RNG before each quad get, but it seems like the only way to ensure a
|
||||
// consistent RNG state for each side.
|
||||
itemContext.random.setSeed(0);
|
||||
itemContext.quadFacing = dir;
|
||||
|
||||
final var quads = model.getQuads(itemContext);
|
||||
|
||||
@@ -16,16 +16,16 @@ public final class Weighted<T> {
|
||||
}
|
||||
|
||||
public static <T> T selectOne(ObjectList<Weighted<T>> heavyThings, Random rand) {
|
||||
var maxWeight = 0;
|
||||
for (var v : heavyThings) {
|
||||
maxWeight += v.weight();
|
||||
}
|
||||
|
||||
final var selector = rand.nextInt(maxWeight) + 1;
|
||||
var weight = 0;
|
||||
for (var v : heavyThings) {
|
||||
weight += v.weight();
|
||||
}
|
||||
|
||||
final var selector = rand.nextInt(weight);
|
||||
weight = 0;
|
||||
for (var v : heavyThings) {
|
||||
if (selector <= weight) return v.thing();
|
||||
weight += v.weight();
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Randomly selected beyond the list!");
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.gtnewhorizon.gtnhlib.client.model;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.util.CoordinatePacker.pack;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -8,6 +10,7 @@ import net.minecraft.world.IBlockAccess;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.blockstate.core.BlockState;
|
||||
import com.gtnewhorizon.gtnhlib.blockstate.registry.BlockPropertyRegistry;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.ModelQuadViewMutable;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing;
|
||||
|
||||
@@ -29,6 +32,16 @@ public class WorldContext implements BakedModelQuadContext.World {
|
||||
this.quadPool = null;
|
||||
}
|
||||
|
||||
public void set(IBlockAccess world, int x, int y, int z, Random random) {
|
||||
this.world = world;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.blockState = BlockPropertyRegistry.getBlockState(world, x, y, z);
|
||||
this.random = random;
|
||||
random.setSeed(pack(x, y, z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockAccess getWorld() {
|
||||
return world;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.gtnewhorizon.gtnhlib.client.model.baked;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.client.model.loading.ModelDeserializer.Position.ModelDisplay.DEFAULT;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing.NEG_X;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing.NEG_Y;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing.NEG_Z;
|
||||
@@ -18,6 +19,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.model.BakedModelQuadContext;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.loading.ModelDeserializer.Position;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.loading.ModelDeserializer.Position.ModelDisplay;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.ModelQuadView;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing;
|
||||
|
||||
@@ -26,17 +28,17 @@ import it.unimi.dsi.fastutil.objects.ObjectImmutableList;
|
||||
public final class PileOfQuads implements BakedModel {
|
||||
|
||||
private final SidedQuadStore sidedQuadStore;
|
||||
private final Map<Position, Position.ModelDisplay> display;
|
||||
private final Map<Position, ModelDisplay> display;
|
||||
private final IIcon particle;
|
||||
|
||||
public PileOfQuads(SidedQuadStore sidedQuadStore, Map<Position, Position.ModelDisplay> display, IIcon particle) {
|
||||
public PileOfQuads(SidedQuadStore sidedQuadStore, Map<Position, ModelDisplay> display, IIcon particle) {
|
||||
this.sidedQuadStore = sidedQuadStore;
|
||||
this.display = display;
|
||||
this.particle = particle;
|
||||
}
|
||||
|
||||
public PileOfQuads(Map<ModelQuadFacing, ArrayList<ModelQuadView>> sidedQuadStore,
|
||||
Map<Position, Position.ModelDisplay> display, IIcon particle) {
|
||||
Map<Position, ModelDisplay> display, IIcon particle) {
|
||||
this(new SidedQuadStore(sidedQuadStore), display, particle);
|
||||
}
|
||||
|
||||
@@ -46,8 +48,9 @@ public final class PileOfQuads implements BakedModel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position.ModelDisplay getDisplay(Position pos, BakedModelQuadContext context) {
|
||||
return display.getOrDefault(pos, Position.ModelDisplay.DEFAULT);
|
||||
public ModelDisplay getDisplay(Position pos, BakedModelQuadContext context) {
|
||||
if (display == null) return DEFAULT;
|
||||
return display.getOrDefault(pos, DEFAULT);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,8 +71,8 @@ public final class PileOfQuads implements BakedModel {
|
||||
private final ObjectImmutableList<ModelQuadView> unknown;
|
||||
|
||||
public SidedQuadStore(Map<ModelQuadFacing, ArrayList<ModelQuadView>> sidedQuadStore) {
|
||||
up = lockList(sidedQuadStore.get(POS_Y));
|
||||
down = lockList(sidedQuadStore.get(NEG_Y));
|
||||
up = lockList(sidedQuadStore.get(POS_Y));
|
||||
north = lockList(sidedQuadStore.get(NEG_Z));
|
||||
south = lockList(sidedQuadStore.get(POS_Z));
|
||||
west = lockList(sidedQuadStore.get(NEG_X));
|
||||
@@ -79,8 +82,8 @@ public final class PileOfQuads implements BakedModel {
|
||||
|
||||
public List<ModelQuadView> getQuads(ModelQuadFacing dir) {
|
||||
return switch (dir) {
|
||||
case POS_Y -> up;
|
||||
case NEG_Y -> down;
|
||||
case POS_Y -> up;
|
||||
case NEG_Z -> north;
|
||||
case POS_Z -> south;
|
||||
case NEG_X -> west;
|
||||
|
||||
@@ -103,10 +103,7 @@ public class ModelRegistry {
|
||||
// Caching this would be a little pointless, since an UnbakedModel here would map directly to the BakedModel
|
||||
// missing from the cache... that's why we're loading one from scratch. The JSONModel *used* by the UnbakedModel
|
||||
// will be cached, however.
|
||||
final var dough = smm.selectModel(state);
|
||||
if (dough == null) return MISSING_MODEL.bake();
|
||||
|
||||
return dough.bake();
|
||||
return smm.selectModel(state).bake();
|
||||
}
|
||||
|
||||
private static StateModelMap getStateModelMap(Block block) {
|
||||
@@ -116,9 +113,7 @@ public class ModelRegistry {
|
||||
}
|
||||
|
||||
private static JSONModel loadAndResolveJSONModel(ResourceLoc.ModelLoc loc) {
|
||||
final var m = loc.load(() -> MISSING_MODEL, GSON);
|
||||
m.resolveParents(JSON_MODEL_CACHE::get);
|
||||
return m;
|
||||
return loc.load(() -> MISSING_MODEL, GSON).resolveParents(JSON_MODEL_CACHE::get);
|
||||
}
|
||||
|
||||
private static final class BlockName {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package com.gtnewhorizon.gtnhlib.client.model.state;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.client.model.unbaked.MissingModel.MISSING_MODEL;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.blockstate.core.BlockState;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.unbaked.UnbakedModel;
|
||||
|
||||
@@ -8,7 +12,7 @@ public class MissingState implements StateModelMap {
|
||||
public static final MissingState MISSING_STATE_MAP = new MissingState();
|
||||
|
||||
@Override
|
||||
public UnbakedModel selectModel(BlockState state) {
|
||||
return null;
|
||||
public @NotNull UnbakedModel selectModel(BlockState state) {
|
||||
return MISSING_MODEL;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.gtnewhorizon.gtnhlib.client.model.state;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.client.model.unbaked.MissingModel.MISSING_MODEL;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.blockstate.core.BlockState;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.JSONVariant;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.Weighted;
|
||||
@@ -24,7 +28,7 @@ public class MonopartState implements StateModelMap {
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbakedModel selectModel(BlockState state) {
|
||||
public @NotNull UnbakedModel selectModel(BlockState state) {
|
||||
Map<String, String> properties = state.toMap();
|
||||
|
||||
final var iter = Object2ObjectMaps.fastIterator(variants);
|
||||
@@ -34,7 +38,7 @@ public class MonopartState implements StateModelMap {
|
||||
if (match.matches(properties)) return new MonopartDough(e.getValue());
|
||||
}
|
||||
|
||||
return null;
|
||||
return MISSING_MODEL;
|
||||
}
|
||||
|
||||
static class StateMatch {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.gtnewhorizon.gtnhlib.client.model.state;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.blockstate.core.BlockState;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.BakeData;
|
||||
@@ -26,7 +27,7 @@ public class MultipartState implements StateModelMap, UnbakedModel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnbakedModel selectModel(BlockState state) {
|
||||
public @NotNull UnbakedModel selectModel(BlockState state) {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
package com.gtnewhorizon.gtnhlib.client.model.state;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.blockstate.core.BlockState;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.unbaked.UnbakedModel;
|
||||
|
||||
public interface StateModelMap {
|
||||
|
||||
/**
|
||||
* @param state The blockstate properties as strings
|
||||
* @return The appropriate model, or null if none match
|
||||
*/
|
||||
@Nullable
|
||||
/// @param state The blockstate properties as strings
|
||||
/// @return The appropriate model, or [MissingModel#MISSING_MODEL] if none match
|
||||
@NotNull
|
||||
UnbakedModel selectModel(BlockState state);
|
||||
}
|
||||
@@ -3,7 +3,10 @@ package com.gtnewhorizon.gtnhlib.client.model.unbaked;
|
||||
import static com.gtnewhorizon.gtnhlib.client.model.loading.ModelDeserializer.ModelElement.Rotation.NOOP;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing.NEG_Y;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing.POS_Y;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing.UNASSIGNED;
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing.fromForgeDir;
|
||||
import static com.gtnewhorizon.gtnhlib.core.GTNHLibCore.MODEL_LOGGER;
|
||||
import static com.gtnewhorizon.gtnhlib.util.DirectionUtil.rotateFacing;
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
import static org.joml.Math.fma;
|
||||
@@ -39,7 +42,6 @@ import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.ModelQuad;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.ModelQuadView;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.ModelQuadViewMutable;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.util.MathUtil;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
|
||||
@@ -55,12 +57,14 @@ public class JSONModel implements UnbakedModel {
|
||||
protected final Map<Position, ModelDisplay> display;
|
||||
@NotNull
|
||||
protected final Object2ObjectMap<String, String> textures;
|
||||
@NotNull
|
||||
protected List<ModelDeserializer.ModelElement> elements;
|
||||
|
||||
protected static final Vector4f DEFAULT_UV = new Vector4f(0, 0, 16, 16);
|
||||
|
||||
public JSONModel(@Nullable ModelLoc parentId, boolean useAO, Map<Position, ModelDisplay> display,
|
||||
@NotNull Object2ObjectMap<String, String> textures, List<ModelDeserializer.ModelElement> elements) {
|
||||
@NotNull Object2ObjectMap<String, String> textures,
|
||||
@NotNull List<ModelDeserializer.ModelElement> elements) {
|
||||
this.parentId = parentId;
|
||||
this.useAO = useAO;
|
||||
this.display = display;
|
||||
@@ -178,11 +182,10 @@ public class JSONModel implements UnbakedModel {
|
||||
Z = max(Z, vert.z);
|
||||
}
|
||||
|
||||
// Set shading and lighting
|
||||
// Set shading properties
|
||||
quad.setEmissiveness(e.lightEmission());
|
||||
quad.setDirectionalShading(e.shade());
|
||||
quad.setHasAmbientOcclusion(this.useAO);
|
||||
quad.setLightFace(ModelQuadFacing.fromForgeDir(f.name()));
|
||||
|
||||
// Set UV
|
||||
Vector4f uv = Objects.firstNonNull(f.uv(), DEFAULT_UV);
|
||||
@@ -214,6 +217,11 @@ public class JSONModel implements UnbakedModel {
|
||||
// Set the sprite
|
||||
var texKey = f.texture();
|
||||
var texName = textures.get(texKey);
|
||||
if (texName == null) {
|
||||
MODEL_LOGGER.warn("Model {} has no texture for variable {}!", this, texKey);
|
||||
texName = "minecraft:missing";
|
||||
}
|
||||
|
||||
if (texName.startsWith("#")) {
|
||||
MODEL_LOGGER.warn("Model {} has unflattened texture variable {} when baking!", this, texName);
|
||||
textures.put(texKey, "minecraft:missing");
|
||||
@@ -224,35 +232,13 @@ public class JSONModel implements UnbakedModel {
|
||||
// Set the tint index
|
||||
quad.setColorIndex(f.tintIndex());
|
||||
|
||||
// Bake and add it
|
||||
// Rotate the cull face and lighting face
|
||||
final var cullFace = rotateFacing(fromForgeDir(f.cullFace()), vRot);
|
||||
final var lightFace = rotateFacing(fromForgeDir(f.name()), vRot);
|
||||
// Light face may not be unassigned
|
||||
quad.setLightFace(lightFace == UNASSIGNED ? POS_Y : lightFace);
|
||||
|
||||
ModelQuadFacing cullFace = ModelQuadFacing.fromForgeDir(f.cullFace());
|
||||
if (cullFace.isDirection()) {
|
||||
// If cullface is not unassigned, we rotate it by the affine matrix, so that way the direction we
|
||||
// check for culling also is rotated.
|
||||
Vector3f facing = new Vector3f(cullFace.getStepX(), cullFace.getStepY(), cullFace.getStepZ())
|
||||
.mulDirection(vRot);
|
||||
// Only one of these three vector coordinates should be a value other than 0. Error handling should
|
||||
// be done where the vRot's data is serialized.
|
||||
if (MathUtil.roughlyEqual(facing.x, 1)) {
|
||||
cullFace = ModelQuadFacing.POS_X;
|
||||
}
|
||||
if (MathUtil.roughlyEqual(facing.x, -1)) {
|
||||
cullFace = ModelQuadFacing.NEG_X;
|
||||
}
|
||||
if (MathUtil.roughlyEqual(facing.y, 1)) {
|
||||
cullFace = ModelQuadFacing.POS_Y;
|
||||
}
|
||||
if (MathUtil.roughlyEqual(facing.y, -1)) {
|
||||
cullFace = ModelQuadFacing.NEG_Y;
|
||||
}
|
||||
if (MathUtil.roughlyEqual(facing.z, 1)) {
|
||||
cullFace = ModelQuadFacing.POS_Z;
|
||||
}
|
||||
if (MathUtil.roughlyEqual(facing.z, -1)) {
|
||||
cullFace = ModelQuadFacing.NEG_Z;
|
||||
}
|
||||
}
|
||||
// Add the quad to the sided store
|
||||
sidedQuadStore.computeIfAbsent(cullFace, d -> new ArrayList<>()).add(quad);
|
||||
}
|
||||
}
|
||||
@@ -277,23 +263,23 @@ public class JSONModel implements UnbakedModel {
|
||||
}
|
||||
}
|
||||
|
||||
public void resolveParents(Function<ModelLoc, JSONModel> modelLoader) {
|
||||
/// @return A JSON model which is the result of model resolution. Note that while this is *usually* the caller, it's
|
||||
/// not always - missing parents, for example, will propogate a missing model down.
|
||||
public JSONModel resolveParents(Function<ModelLoc, JSONModel> modelLoader) {
|
||||
|
||||
if (this.parentId == null || this.parent != null) {
|
||||
return;
|
||||
return this;
|
||||
}
|
||||
|
||||
final JSONModel p = modelLoader.apply(this.parentId);
|
||||
p.resolveParents(modelLoader);
|
||||
|
||||
// Inherit properties
|
||||
this.parent = p;
|
||||
this.parent = modelLoader.apply(this.parentId).resolveParents(modelLoader);
|
||||
if (parent instanceof MissingModel) return parent;
|
||||
|
||||
if (this.elements.isEmpty()) this.elements = this.parent.elements;
|
||||
|
||||
// Resolve texture variables
|
||||
// Add parent texture mappings, but prioritize ours.
|
||||
for (Map.Entry<String, String> e : this.parent.textures.entrySet()) {
|
||||
|
||||
this.textures.putIfAbsent(e.getKey(), e.getValue());
|
||||
}
|
||||
|
||||
@@ -320,11 +306,12 @@ public class JSONModel implements UnbakedModel {
|
||||
}
|
||||
|
||||
if (this.parent != null && this.parent.display != null) {
|
||||
|
||||
for (Map.Entry<Position, ModelDisplay> e : this.parent.display.entrySet()) {
|
||||
this.display.putIfAbsent(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
protected IIcon getParticle() {
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
package com.gtnewhorizon.gtnhlib.client.model.unbaked;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.client.model.loading.ModelDeserializer.ModelElement.Rotation.NOOP;
|
||||
import static net.minecraftforge.common.util.ForgeDirection.DOWN;
|
||||
import static net.minecraftforge.common.util.ForgeDirection.EAST;
|
||||
import static net.minecraftforge.common.util.ForgeDirection.NORTH;
|
||||
import static net.minecraftforge.common.util.ForgeDirection.SOUTH;
|
||||
import static net.minecraftforge.common.util.ForgeDirection.UP;
|
||||
import static net.minecraftforge.common.util.ForgeDirection.WEST;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.util.IIcon;
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.model.BakeData;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.baked.BakedModel;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.baked.PileOfQuads;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.ModelQuad;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.ModelQuadView;
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.loading.ModelDeserializer.ModelElement;
|
||||
import com.gtnewhorizon.gtnhlib.client.model.loading.ModelDeserializer.ModelElement.Face;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
|
||||
|
||||
@@ -28,78 +23,17 @@ public class MissingModel extends JSONModel {
|
||||
public static final MissingModel MISSING_MODEL = new MissingModel();
|
||||
|
||||
public MissingModel() {
|
||||
super(null, false, null, Object2ObjectMaps.emptyMap(), null);
|
||||
}
|
||||
super(null, true, null, Object2ObjectMaps.emptyMap(), new ArrayList<>());
|
||||
|
||||
@Override
|
||||
public BakedModel bake() {
|
||||
return super.bake();
|
||||
}
|
||||
final var uv = new Vector4f(0, 0, 16, 16);
|
||||
final var faces = new ArrayList<Face>();
|
||||
faces.add(new Face(DOWN, uv, "missingno", DOWN, 0, 0));
|
||||
faces.add(new Face(UP, uv, "missingno", UP, 0, 0));
|
||||
faces.add(new Face(WEST, uv, "missingno", WEST, 0, 0));
|
||||
faces.add(new Face(EAST, uv, "missingno", EAST, 0, 0));
|
||||
faces.add(new Face(NORTH, uv, "missingno", NORTH, 0, 0));
|
||||
faces.add(new Face(SOUTH, uv, "missingno", SOUTH, 0, 0));
|
||||
|
||||
/**
|
||||
* Overrides the default baking logic to bake a hardcoded cube. Used when a state not specified in the blockstate
|
||||
* file is chosen to render. Also appears when the model provided is missing.
|
||||
* <p>
|
||||
* TODO: Possible memory leak since a new one is baked for every missing state. Perhaps we could store a singleton
|
||||
* that's cached on first bake, that is reset on resource reload. Would that need a threadlocal?
|
||||
*/
|
||||
@Override
|
||||
public BakedModel bake(BakeData data) {
|
||||
final var vRot = data.getAffineMatrix();
|
||||
final var sidedQuadStore = new HashMap<ModelQuadFacing, ArrayList<ModelQuadView>>(7);
|
||||
for (ForgeDirection facing : ForgeDirection.VALID_DIRECTIONS) {
|
||||
ModelQuadFacing quadFacing = ModelQuadFacing.fromForgeDir(facing);
|
||||
final Matrix4f rot = NOOP.getAffineMatrix();
|
||||
|
||||
// The from vector is the minimum corner of the face's element
|
||||
final Vector3f from = switch (quadFacing) {
|
||||
case POS_X -> new Vector3f(1, 0, 0);
|
||||
case POS_Y -> new Vector3f(0, 1, 0);
|
||||
case POS_Z -> new Vector3f(0, 0, 1);
|
||||
case NEG_X, NEG_Y, NEG_Z -> new Vector3f(0, 0, 0);
|
||||
case UNASSIGNED -> null;
|
||||
};
|
||||
|
||||
// The to vector is the maximum corner of the face's element
|
||||
final Vector3f to = switch (quadFacing) {
|
||||
// POS_X (Fixed X=1, Y/Z span 0->1)
|
||||
case POS_X, POS_Y, POS_Z -> new Vector3f(1, 1, 1);
|
||||
case NEG_X -> new Vector3f(0, 1, 1);
|
||||
case NEG_Y -> new Vector3f(1, 0, 1);
|
||||
case NEG_Z -> new Vector3f(1, 1, 0);
|
||||
case UNASSIGNED -> null;
|
||||
};
|
||||
|
||||
// Assign vertexes
|
||||
final var quad = new ModelQuad();
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
final Vector3f vert = mapSideToVertex(from, to, i, facing).mulPosition(rot).mulPosition(vRot);
|
||||
quad.setX(i, vert.x);
|
||||
quad.setY(i, vert.y);
|
||||
quad.setZ(i, vert.z);
|
||||
}
|
||||
|
||||
// Set culling and nominal faces
|
||||
quad.setLightFace(quadFacing);
|
||||
quad.setColorIndex(-1);
|
||||
quad.setDirectionalShading(true);
|
||||
quad.setEmissiveness(0);
|
||||
|
||||
// Set UV
|
||||
final Vector4f uv = DEFAULT_UV;
|
||||
setUV(quad, 0, uv.x, uv.y);
|
||||
setUV(quad, 1, uv.x, uv.w);
|
||||
setUV(quad, 2, uv.z, uv.w);
|
||||
setUV(quad, 3, uv.z, uv.y);
|
||||
|
||||
bakeSprite(quad, "missingno");
|
||||
|
||||
// Bake and add it
|
||||
sidedQuadStore.computeIfAbsent(quadFacing, d -> new ArrayList<>()).add(quad);
|
||||
}
|
||||
|
||||
final IIcon missing = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite("missingno");
|
||||
// Add them to the model
|
||||
return new PileOfQuads(sidedQuadStore, Collections.emptyMap(), missing);
|
||||
elements.add(new ModelElement("cube", new Vector3f(), new Vector3f(1, 1, 1), NOOP, true, 0, faces));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.gtnewhorizon.gtnhlib.test.block;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
|
||||
public class BlockRngTest extends Block {
|
||||
|
||||
public BlockRngTest() {
|
||||
super(Material.wood);
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
final var testBlock = new BlockRngTest();
|
||||
testBlock.setBlockName("rng_test");
|
||||
GameRegistry.registerBlock(testBlock, "rng_test");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.gtnewhorizon.gtnhlib.test.block;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.material.Material;
|
||||
|
||||
import cpw.mods.fml.common.registry.GameRegistry;
|
||||
|
||||
public class BlockWeightedRngTest extends Block {
|
||||
|
||||
public BlockWeightedRngTest() {
|
||||
super(Material.wood);
|
||||
}
|
||||
|
||||
public static void register() {
|
||||
final var testBlock = new BlockWeightedRngTest();
|
||||
testBlock.setBlockName("weighted_rng_test");
|
||||
GameRegistry.registerBlock(testBlock, "weighted_rng_test");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,14 @@
|
||||
package com.gtnewhorizon.gtnhlib.util;
|
||||
|
||||
import static com.gtnewhorizon.gtnhlib.client.renderer.cel.util.MathUtil.roughlyEqual;
|
||||
|
||||
import net.minecraftforge.common.util.ForgeDirection;
|
||||
|
||||
import org.joml.Matrix4fc;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import com.gtnewhorizon.gtnhlib.client.renderer.cel.model.quad.properties.ModelQuadFacing;
|
||||
|
||||
public class DirectionUtil {
|
||||
|
||||
public static ForgeDirection yawToDirection(float yaw) {
|
||||
@@ -12,4 +19,29 @@ public class DirectionUtil {
|
||||
default -> ForgeDirection.NORTH;
|
||||
};
|
||||
}
|
||||
|
||||
public static ModelQuadFacing rotateFacing(ModelQuadFacing facing, Matrix4fc rotation) {
|
||||
// We can't meaningfully rotate an unknown vector
|
||||
if (!facing.isDirection()) return ModelQuadFacing.UNASSIGNED;
|
||||
|
||||
final var vecFacing = new Vector3f(facing.getStepX(), facing.getStepY(), facing.getStepZ())
|
||||
.mulDirection(rotation);
|
||||
// Only one of these three vector coordinates should be a value other than near-zero.
|
||||
if (roughlyEqual(vecFacing.x, 1)) {
|
||||
return ModelQuadFacing.POS_X;
|
||||
} else if (roughlyEqual(vecFacing.x, -1)) {
|
||||
return ModelQuadFacing.NEG_X;
|
||||
} else if (roughlyEqual(vecFacing.y, 1)) {
|
||||
return ModelQuadFacing.POS_Y;
|
||||
} else if (roughlyEqual(vecFacing.y, -1)) {
|
||||
return ModelQuadFacing.NEG_Y;
|
||||
} else if (roughlyEqual(vecFacing.z, 1)) {
|
||||
return ModelQuadFacing.POS_Z;
|
||||
} else if (roughlyEqual(vecFacing.z, -1)) {
|
||||
return ModelQuadFacing.NEG_Z;
|
||||
}
|
||||
|
||||
// We rotated it and didn't get something axis-aligned!
|
||||
return ModelQuadFacing.UNASSIGNED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"variants": {
|
||||
"": [
|
||||
{
|
||||
"model": "gtnhlib:blocks/test_one"
|
||||
},
|
||||
{
|
||||
"model": "gtnhlib:blocks/test_two"
|
||||
},
|
||||
{
|
||||
"model": "gtnhlib:blocks/test_three"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"variants": {
|
||||
"": [
|
||||
{
|
||||
"model": "gtnhlib:blocks/test_one",
|
||||
"weight": 8
|
||||
},
|
||||
{
|
||||
"model": "gtnhlib:blocks/test_two"
|
||||
},
|
||||
{
|
||||
"model": "gtnhlib:blocks/test_three"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ tile.model_test.name=Test Block
|
||||
tile.model_test_tint.name=Test Block (Tint)
|
||||
tile.model_test_tint_mul.name=Test Block (Tint Mul)
|
||||
tile.model_test_lectern.name=Lectern Test Block
|
||||
tile.rng_test.name=RNG Test Block
|
||||
tile.weighted_rng_test.name=Weighted RNG Test Block
|
||||
|
||||
# Configuration
|
||||
fml.configgui.tooltip.default=[default: %s]
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "block/cube_all",
|
||||
"textures": {
|
||||
"all": "gtnhlib:test_one"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "block/cube_all",
|
||||
"textures": {
|
||||
"all": "gtnhlib:test_three"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "block/cube_all",
|
||||
"textures": {
|
||||
"all": "gtnhlib:test_two"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 177 B |
Binary file not shown.
|
After Width: | Height: | Size: 176 B |
Binary file not shown.
|
After Width: | Height: | Size: 178 B |
Reference in new issue
Block a user