Merge branch 'master' into render-type

This commit is contained in:
Martin Robertz authored and GitHub committed 2026-11-04 14:05:11 +01:00
commit 4f5ec82284
11 files changed
+248 -11

No files matched your search

@@ -34,6 +34,7 @@ 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.BlockLightUnderStair;
import com.gtnewhorizon.gtnhlib.test.block.BlockRngTest;
import com.gtnewhorizon.gtnhlib.test.block.BlockTest;
import com.gtnewhorizon.gtnhlib.test.block.BlockTestAo;
@@ -74,6 +75,7 @@ public class CommonProxy {
GTNHLib.info("GTNHLib version " + Tags.VERSION + " loaded.");
if (GTNHLibConfig.enableTestBlocks) {
BlockLightUnderStair.register();
BlockTest.register();
BlockTestAo.register();
BlockTestLectern.register();
@@ -8,21 +8,26 @@ import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import net.minecraft.command.CommandException;
import net.minecraft.command.CommandNotFoundException;
import net.minecraft.command.ICommand;
import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.EnumChatFormatting;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.gtnewhorizon.gtnhlib.util.CommandUtils;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.ParseResults;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.ParsedCommandNode;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.tree.CommandNode;
@@ -32,6 +37,8 @@ import lombok.extern.log4j.Log4j2;
@Log4j2
public class BrigadierApi {
private static final int MAX_REPORTED_USAGES = 5;
@Nullable
private static CommandDispatcher<ICommandSender> dispatcher = new CommandDispatcher<>();
@@ -81,11 +88,71 @@ public class BrigadierApi {
* @return the result
*/
public static int executeCommand(ICommandSender sender, String command) {
CommandDispatcher<ICommandSender> dispatcher = getCommandDispatcher();
ParseResults<ICommandSender> parse = dispatcher.parse(command, sender);
try {
return getCommandDispatcher().execute(command, sender);
return dispatcher.execute(parse);
} catch (CommandSyntaxException e) {
// TODO: make the exception message better
throw new CommandException(e.getMessage());
if (parse.getContext().getNodes().isEmpty()) {
// nothing matched at all, let vanilla report it like any other unknown command
throw new CommandNotFoundException();
}
reportSyntaxError(sender, parse, e);
return 0;
}
}
/**
* Report a parse failure as what went wrong, where it went wrong and how the matched command is meant to be used.
* Brigadier's own message is not a translation key, so it cannot be handed to a {@link CommandException}.
*
* @param sender the executor
* @param parse the parse results the failure came from
* @param e the failure
*/
private static void reportSyntaxError(ICommandSender sender, ParseResults<ICommandSender> parse,
CommandSyntaxException e) {
if (e.getType() == CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand()) {
// brigadier reports a command that parsed but has nothing to run as unknown
CommandUtils.error(sender, "gtnhlib.chat.command.incomplete");
} else {
sender.addChatMessage(
CommandUtils.colorChatComponent(EnumChatFormatting.RED, e.getRawMessage().getString()));
}
String input = e.getInput();
int cursor = e.getCursor();
if (input != null && cursor >= 0 && cursor < input.length()) {
ChatComponentText accepted = CommandUtils
.colorChatComponent(EnumChatFormatting.GRAY, "/" + input.substring(0, cursor));
ChatComponentText rejected = CommandUtils
.colorChatComponent(EnumChatFormatting.RED, input.substring(cursor));
rejected.getChatStyle().setUnderlined(true);
sender.addChatMessage(accepted.appendSibling(rejected));
}
List<ParsedCommandNode<ICommandSender>> nodes = parse.getContext().getNodes();
if (nodes.isEmpty()) return;
StringBuilder path = new StringBuilder("/");
for (ParsedCommandNode<ICommandSender> node : nodes) {
path.append(node.getNode().getUsageText()).append(' ');
}
String[] usages = getCommandDispatcher().getAllUsage(nodes.get(nodes.size() - 1).getNode(), sender, true);
for (int i = 0; i < usages.length && i < MAX_REPORTED_USAGES; i++) {
ChatComponentTranslation usage = new ChatComponentTranslation(
"commands.generic.usage",
(path + usages[i]).trim());
usage.getChatStyle().setColor(EnumChatFormatting.GRAY);
sender.addChatMessage(usage);
}
if (usages.length > MAX_REPORTED_USAGES) {
ChatComponentTranslation more = new ChatComponentTranslation(
"gtnhlib.chat.command.more_usages",
usages.length - MAX_REPORTED_USAGES);
more.getChatStyle().setColor(EnumChatFormatting.GRAY);
sender.addChatMessage(more);
}
}
@@ -0,0 +1,30 @@
package com.gtnewhorizon.gtnhlib.client.model;
import net.minecraft.client.renderer.Tessellator;
import com.gtnewhorizons.angelica.rendering.StateAwareTessellator;
class AngelicaHelper {
/// This method doesn't need to mess with [com.gtnewhorizons.angelica.api.ExtCeleritasRenderBlocks] because that
/// only affects [net.minecraft.client.renderer.RenderBlocks] methods, which we don't use.
static void initAngelicaLighting(Tessellator tesselator) {
if (!(tesselator instanceof StateAwareTessellator saTess)) return;
saTess.angelica$setAppliedAo(true);
}
static void quadAngelicaLighting(Tessellator tesselator, boolean ao, boolean noDirectionalShading) {
if (!(tesselator instanceof StateAwareTessellator saTess)) return;
saTess.angelica$setAppliedAo(ao);
saTess.angelica$setNoDirectionalShading(noDirectionalShading);
}
static void resetAngelicaLighting(Tessellator tesselator) {
if (!(tesselator instanceof StateAwareTessellator saTess)) return;
saTess.angelica$setAppliedAo(false);
saTess.angelica$setNoDirectionalShading(false);
}
}
@@ -5,6 +5,7 @@ import static com.gtnewhorizon.gtnhlib.client.renderer.cel.api.util.NormI8.unpac
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.compat.Mods.ANGELICA;
import static java.lang.Float.intBitsToFloat;
import static java.lang.Math.max;
import static net.minecraftforge.client.IItemRenderer.ItemRenderType.ENTITY;
@@ -86,6 +87,8 @@ public class ModelISBRH implements ISimpleBlockRenderingHandler, IItemRenderer {
worldContext.set(wrappedContext, x, y, z, RAND);
final int meta = wrappedContext.getBlockMetadata(x, y, z);
if (ANGELICA) AngelicaHelper.initAngelicaLighting(tesselator);
final BakedModel model = ModelRegistry.getBakedModel(worldContext);
int color = model.getColor(world, x, y, z, block, meta, RAND);
@@ -126,11 +129,26 @@ public class ModelISBRH implements ISimpleBlockRenderingHandler, IItemRenderer {
final int lm = getLightMap(block, quad, quad.getLightFace(), world, x, y, z, renderer);
tesselator.setBrightness(lm);
final float shade = quad.hasDirectionalShading() ? diffuseLight(quad.getComputedFaceNormal()) : 1;
if (ANGELICA) {
AngelicaHelper.quadAngelicaLighting(
tesselator,
quad.hasAmbientOcclusion(),
!quad.hasDirectionalShading());
}
final float shade;
if (ANGELICA && quad.hasAmbientOcclusion()) {
shade = 1;
} else {
shade = quad.hasDirectionalShading() ? diffuseLight(quad.getComputedFaceNormal()) : 1;
}
tesselator.setColorOpaque_F(r * shade, g * shade, b * shade);
renderQuad(quad, x, y, z, tesselator, renderer.overrideBlockTexture);
}
}
if (ANGELICA) AngelicaHelper.resetAngelicaLighting(tesselator);
worldContext.reset();
return rendered;
}
@@ -67,11 +67,10 @@ public interface ModelQuadView extends ModelPrimitiveView {
*/
boolean isTransparent();
/**
* Not to be confused with ambient occlusion AKA smooth lighting When true, allows this quad to multiply its
* brightness based on the direction it's facing. When this is false, each face derives its brightness directly from
* the light value it's facing without multiplying it.
*/
/// Not to be confused with ambient occlusion AKA smooth lighting. When true, allows this quad to multiply its
/// brightness based on the direction it's facing. When this is false, each face derives its brightness directly
/// from
/// the light value it's facing without multiplying it.
boolean hasDirectionalShading();
/**
@@ -31,11 +31,17 @@ public class MixinCommandHandler {
cancellable = true)
private void gtnhlib$fallbackToBrigadier(ICommandSender sender, String command,
CallbackInfoReturnable<Integer> cir) {
if (gtnhlib$isServerCommandManager()) {
if (!gtnhlib$isServerCommandManager()) return;
// an empty console line or a lone slash is not a command, so do not report it as one
if (command.trim().isEmpty()) {
cir.setReturnValue(0);
return;
}
int value = BrigadierApi.executeCommand(sender, command);
cir.setReturnValue(value);
}
}
@Inject(
method = "getPossibleCommands(Lnet/minecraft/command/ICommandSender;Ljava/lang/String;)Ljava/util/List;",
@@ -0,0 +1,45 @@
package com.gtnewhorizon.gtnhlib.test.block;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import com.gtnewhorizon.gtnhlib.blockstate.properties.DirectionBlockProperty;
import com.gtnewhorizon.gtnhlib.blockstate.properties.DirectionBlockProperty.AbstractDirectionBlockProperty;
import com.gtnewhorizon.gtnhlib.blockstate.registry.BlockPropertyRegistry;
import com.gtnewhorizon.gtnhlib.util.DirectionUtil;
import cpw.mods.fml.common.registry.GameRegistry;
public class BlockLightUnderStair extends Block {
public final AbstractDirectionBlockProperty FACING_PROP = (AbstractDirectionBlockProperty) DirectionBlockProperty
.facing();
public BlockLightUnderStair() {
super(Material.wood);
}
public static void register() {
final var testBlock = new BlockLightUnderStair();
testBlock.setBlockName("light_under_stair");
GameRegistry.registerBlock(testBlock, "light_under_stair");
BlockPropertyRegistry.registerBlockItemProperty(testBlock, testBlock.FACING_PROP, ForgeDirection.EAST);
}
@Override
public boolean isOpaqueCube() {
return false;
}
@Override
public void onBlockPlacedBy(World worldIn, int x, int y, int z, EntityLivingBase placer, ItemStack itemIn) {
var dir = DirectionUtil.yawToDirection(placer.rotationYaw);
worldIn.setBlockMetadataWithNotify(x, y, z, FACING_PROP.getMeta(dir, 0), 2);
}
}
@@ -0,0 +1,8 @@
{
"variants": {
"facing=north": { "model": "gtnhlib:blocks/light_test_stairs", "y": 270, "uvlock": true },
"facing=south": { "model": "gtnhlib:blocks/light_test_stairs", "y": 90, "uvlock": true },
"facing=west": { "model": "gtnhlib:blocks/light_test_stairs", "y": 0, "uvlock": true },
"facing=east": { "model": "gtnhlib:blocks/light_test_stairs", "y": 180, "uvlock": true }
}
}
@@ -1,4 +1,5 @@
# Test block names
tile.light_under_stair.name=Directional Shading Test Block
tile.model_test.name=Test Block
tile.model_test_tint.name=Test Block (Tint)
tile.model_test_tint_mul.name=Test Block (Tint Mul)
@@ -295,3 +296,7 @@ commands.title.show.title.single=Showed title to %s
commands.title.show.subtitle.single=Showed subtitle to %s
commands.title.times.single=Changed title display times for %s
commands.title.icon.single=Changed title icon for %s
# Brigadier command errors
gtnhlib.chat.command.incomplete=Incomplete command
gtnhlib.chat.command.more_usages=... and %s more
@@ -0,0 +1,8 @@
{
"parent": "gtnhlib:blocks/light_under_stair",
"textures": {
"bottom": "minecraft:planks_oak",
"side": "minecraft:planks_oak",
"top": "minecraft:planks_oak"
}
}
@@ -0,0 +1,49 @@
{
"parent": "block/block",
"display": {
"gui": {
"rotation": [ 30, 135, 0 ],
"translation": [ 0, 0, 0],
"scale":[ 0.625, 0.625, 0.625 ]
},
"head": {
"rotation": [ 0, -90, 0 ],
"translation": [ 0, 0, 0 ],
"scale": [ 1, 1, 1 ]
},
"thirdperson_lefthand": {
"rotation": [ 75, -135, 0 ],
"translation": [ 0, 2.5, 0],
"scale": [ 0.375, 0.375, 0.375 ]
}
},
"textures": {
"particle": "#side"
},
"elements": [
{
"from": [ 0, 0, 0 ],
"to": [ 16, 8, 16 ],
"faces": {
"down": { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom", "cullface": "down" },
"up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top" },
"north": { "uv": [ 0, 8, 16, 16 ], "texture": "#side", "cullface": "north" },
"south": { "uv": [ 0, 8, 16, 16 ], "texture": "#side", "cullface": "south" },
"west": { "uv": [ 0, 8, 16, 16 ], "texture": "#side", "cullface": "west" },
"east": { "uv": [ 0, 8, 16, 16 ], "texture": "#side", "cullface": "east" }
},
"shade": false
},
{
"from": [ 8, 8, 0 ],
"to": [ 16, 16, 16 ],
"faces": {
"up": { "uv": [ 8, 0, 16, 16 ], "texture": "#top", "cullface": "up" },
"north": { "uv": [ 0, 0, 8, 8 ], "texture": "#side", "cullface": "north" },
"south": { "uv": [ 8, 0, 16, 8 ], "texture": "#side", "cullface": "south" },
"west": { "uv": [ 0, 0, 16, 8 ], "texture": "#side" },
"east": { "uv": [ 0, 0, 16, 8 ], "texture": "#side", "cullface": "east" }
}
}
]
}