Flags prototype
All checks were successful
Build / build (push) Successful in 2m18s

This commit is contained in:
kalle 2025-07-03 15:16:53 +02:00
parent f59f568700
commit 6e32233f4b
13 changed files with 437 additions and 11 deletions

View file

@ -4,6 +4,10 @@ import com.mojang.logging.LogUtils;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.common.Mod;
import nl.kallestruik.riseofblocks.registry.BlockEntityRegistry;
import nl.kallestruik.riseofblocks.registry.BlockRegistry;
import nl.kallestruik.riseofblocks.registry.CreativeTabRegistry;
import nl.kallestruik.riseofblocks.registry.ItemRegistry;
import org.slf4j.Logger;
// The value here should match an entry in the META-INF/neoforge.mods.toml file
@ -17,5 +21,10 @@ public class RiseOfBlocks {
public RiseOfBlocks(IEventBus modEventBus, ModContainer modContainer) {
// Load blast resistance override config
BlastResistanceOverrideConfig.load();
BlockRegistry.BLOCKS.register(modEventBus);
ItemRegistry.ITEMS.register(modEventBus);
CreativeTabRegistry.CREATIVE_MODE_TABS.register(modEventBus);
BlockEntityRegistry.BLOCK_ENTITY_TYPES.register(modEventBus);
}
}

View file

@ -0,0 +1,41 @@
package nl.kallestruik.riseofblocks.blockentities;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import nl.kallestruik.riseofblocks.registry.BlockEntityRegistry;
import org.jetbrains.annotations.NotNull;
public class FlagBlockEntity extends BlockEntity {
private String teamName;
public FlagBlockEntity(BlockPos pos, BlockState blockState) {
super(BlockEntityRegistry.FLAG.get(), pos, blockState);
}
public void setTeamName(String teamName) {
this.teamName = teamName;
setChanged();
}
public String getTeamName() {
return teamName;
}
// Read values from the passed CompoundTag here.
@Override
public void loadAdditional(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
super.loadAdditional(tag, registries);
this.teamName = tag.getString("team");
}
// Save values into the passed CompoundTag here.
@Override
public void saveAdditional(@NotNull CompoundTag tag, HolderLookup.@NotNull Provider registries) {
super.saveAdditional(tag, registries);
if (this.teamName == null) return;
tag.putString("team", this.teamName);
}
}

View file

@ -0,0 +1,58 @@
package nl.kallestruik.riseofblocks.blockentities;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.world.scores.Team;
import javax.annotation.ParametersAreNonnullByDefault;
public class FlagBlockRenderer implements BlockEntityRenderer<FlagBlockEntity> {
@Override
@ParametersAreNonnullByDefault
public void render(FlagBlockEntity be, float v, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay) {
if (be.getLevel() == null) return;
Team team = be.getLevel().getScoreboard().getPlayersTeam(be.getTeamName());
int color = 0xFFFFFF; // default white
if (team != null) {
ChatFormatting textColor = team.getColor();
color = textColor.getColor();
}
float r = ((color >> 16) & 0xFF) / 255f;
float g = ((color >> 8) & 0xFF) / 255f;
float b = (color & 0xFF) / 255f;
poseStack.pushPose();
// Translate to the block position center (optional)
poseStack.translate(0.5, 0.5, 0.5);
// Get model and vertex consumer
BlockRenderDispatcher dispatcher = Minecraft.getInstance().getBlockRenderer();
BakedModel model = dispatcher.getBlockModel(be.getBlockState());
VertexConsumer vertexConsumer = multiBufferSource.getBuffer(RenderType.cutout());
// Render model with tint
dispatcher.getModelRenderer().renderModel(
poseStack.last(),
vertexConsumer,
be.getBlockState(),
model,
r, g, b,
packedLight,
packedOverlay
);
poseStack.popPose();
}
}

View file

@ -0,0 +1,43 @@
package nl.kallestruik.riseofblocks.blocks;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import nl.kallestruik.riseofblocks.blockentities.FlagBlockEntity;
import nl.kallestruik.riseofblocks.registry.FlagRegistry;
import org.jetbrains.annotations.NotNull;
import javax.annotation.ParametersAreNonnullByDefault;
public class FlagBlock extends Block implements EntityBlock {
public FlagBlock(Properties properties) {
super(properties);
}
@Override
@ParametersAreNonnullByDefault
public BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new FlagBlockEntity(pos, state);
}
@Override
@ParametersAreNonnullByDefault
public @NotNull BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state, Player player) {
if (!level.isClientSide && level instanceof ServerLevel serverLevel) {
BlockEntity be = serverLevel.getBlockEntity(pos);
if (be instanceof FlagBlockEntity blockEntity) {
String teamName = blockEntity.getTeamName();
if (teamName != null) {
FlagRegistry.get(serverLevel).remove(teamName);
}
}
}
return super.playerWillDestroy(level, pos, state, player);
}
}

View file

@ -0,0 +1,21 @@
package nl.kallestruik.riseofblocks.handlers;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
import nl.kallestruik.riseofblocks.RiseOfBlocks;
import nl.kallestruik.riseofblocks.blockentities.FlagBlockRenderer;
import nl.kallestruik.riseofblocks.registry.BlockEntityRegistry;
@EventBusSubscriber(value = Dist.CLIENT, modid = RiseOfBlocks.MODID)
public class BlockEntityRendererRegister {
@SubscribeEvent
public static void registerEntityRenderers(EntityRenderersEvent.RegisterRenderers event) {
event.registerBlockEntityRenderer(BlockEntityRegistry.FLAG.get(),
// Pass the context to an empty (default) constructor call
context -> new FlagBlockRenderer()
);
}
}

View file

@ -0,0 +1,78 @@
package nl.kallestruik.riseofblocks.handlers;
import net.minecraft.core.BlockPos;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.TickTask;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.scores.Team;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import net.neoforged.neoforge.event.level.BlockEvent;
import nl.kallestruik.riseofblocks.RiseOfBlocks;
import nl.kallestruik.riseofblocks.blockentities.FlagBlockEntity;
import nl.kallestruik.riseofblocks.registry.FlagRegistry;
@EventBusSubscriber(modid = RiseOfBlocks.MODID)
public class FlagEventHandler {
@SubscribeEvent
public static void onPlayerRespawn(PlayerEvent.Clone event) {
System.out.println("onPlayerRespawn: " + event.getEntity().getScoreboardName() + " is " + (event.isWasDeath() ? "dead" : "alive") + " and is respawning.");
if (!event.isWasDeath()) return; // Only handle actual death-respawns
ServerPlayer player = (ServerPlayer) event.getEntity();
ServerLevel world = player.serverLevel();
MinecraftServer server = world.getServer();
// Get player's team
Team team = player.getScoreboard().getPlayersTeam(player.getScoreboardName());
System.out.println("Team: " + (team == null ? "null" : team.getName()));
if (team == null) return;
// Get position from registry
FlagRegistry.FlagPosition flagPos = FlagRegistry.get(world).get(team.getName());
System.out.println("FlagPos: " + flagPos);
if (flagPos == null || flagPos.getPos() == null) return;
BlockPos pos = flagPos.getPos();
ResourceKey<Level> dimensionKey = ResourceKey.create(Registries.DIMENSION, flagPos.getDimension());
ServerLevel dimension = server.getLevel(dimensionKey);
if (dimension == null) return;
// Teleport after short delay (avoid spawn conflict)
server.execute(() -> {
player.teleportTo(dimension, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, player.getYRot(), player.getXRot());
});
}
@SubscribeEvent
public static void onBlockPlace(BlockEvent.EntityPlaceEvent event) {
if (!(event.getLevel() instanceof ServerLevel world)) return;
if (event.getEntity() instanceof Player player) {
BlockPos pos = event.getPos();
world.getServer().tell(new TickTask(1, () -> {
BlockEntity be = world.getBlockEntity(pos);
if (be instanceof FlagBlockEntity flagBe) {
Team team = player.getScoreboard().getPlayersTeam(player.getScoreboardName());
if (team != null) {
FlagRegistry flagRegistry = FlagRegistry.get(world);
FlagRegistry.FlagPosition oldFlagPos = flagRegistry.get(team.getName());
if (oldFlagPos != null) {
// Break the old flag if it exists
world.destroyBlock(oldFlagPos.getPos(), false, player);
}
flagBe.setTeamName(team.getName());
FlagRegistry.FlagPosition flagPos = new FlagRegistry.FlagPosition(pos, world.dimension().location());
flagRegistry.put(team.getName(), flagPos);
}
}
}));
}
}
}

View file

@ -0,0 +1,28 @@
package nl.kallestruik.riseofblocks.registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.neoforged.neoforge.registries.DeferredRegister;
import nl.kallestruik.riseofblocks.RiseOfBlocks;
import nl.kallestruik.riseofblocks.blockentities.FlagBlockEntity;
import java.util.function.Supplier;
public class BlockEntityRegistry {
public static final DeferredRegister<BlockEntityType<?>> BLOCK_ENTITY_TYPES =
DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE, RiseOfBlocks.MODID);
public static final Supplier<BlockEntityType<FlagBlockEntity>> FLAG = BLOCK_ENTITY_TYPES.register(
"flag",
// The block entity type, created using a builder.
() -> BlockEntityType.Builder.of(
// The supplier to use for constructing the block entity instances.
FlagBlockEntity::new,
// A vararg of blocks that can have this block entity.
// This assumes the existence of the referenced blocks as DeferredBlock<Block>s.
BlockRegistry.FLAG.get()
)
// Build using null; vanilla does some datafixer shenanigans with the parameter that we don't need.
.build(null)
);
}

View file

@ -0,0 +1,15 @@
package nl.kallestruik.riseofblocks.registry;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.material.MapColor;
import net.neoforged.neoforge.registries.DeferredBlock;
import net.neoforged.neoforge.registries.DeferredRegister;
import nl.kallestruik.riseofblocks.RiseOfBlocks;
import nl.kallestruik.riseofblocks.blocks.FlagBlock;
public class BlockRegistry {
public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(RiseOfBlocks.MODID);
public static DeferredBlock<Block> FLAG = BLOCKS.register("flag", () -> new FlagBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOL)));
}

View file

@ -0,0 +1,21 @@
package nl.kallestruik.riseofblocks.registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredRegister;
import nl.kallestruik.riseofblocks.RiseOfBlocks;
public class CreativeTabRegistry {
public static final DeferredRegister<CreativeModeTab> CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, RiseOfBlocks.MODID);
public static final DeferredHolder<CreativeModeTab, CreativeModeTab> RISE_OF_BLOCKS_TAB = CREATIVE_MODE_TABS.register("rise_of_blocks", () -> CreativeModeTab.builder()
.title(Component.translatable("itemGroup.riseofblocks")) //The language key for the title of your CreativeModeTab
.withTabsBefore(CreativeModeTabs.COMBAT)
.icon(() -> ItemRegistry.FLAG.get().getDefaultInstance())
.displayItems((parameters, output) -> {
output.accept(ItemRegistry.FLAG.get()); // Add the example item to the tab. For your own tabs, this method is preferred over the event
}).build());
}

View file

@ -0,0 +1,109 @@
package nl.kallestruik.riseofblocks.registry;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.saveddata.SavedData;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
public class FlagRegistry extends SavedData {
private static final String DATA_NAME = "flag_registry";
private final HashMap<String, FlagPosition> flagPositions = new HashMap<>();
private static final Factory<FlagRegistry> FACTORY = new Factory<FlagRegistry>(FlagRegistry::new, FlagRegistry::load);
public static FlagRegistry get(ServerLevel world) {
return world.getDataStorage().computeIfAbsent(
FACTORY,
DATA_NAME
);
}
public FlagPosition get(String teamName) {
return flagPositions.get(teamName);
}
public void put(String teamName, FlagPosition pos) {
flagPositions.put(teamName, pos);
setDirty();
}
public void remove(String teamName) {
flagPositions.remove(teamName);
setDirty();
}
@Override
public @NotNull CompoundTag save(@NotNull CompoundTag compoundTag, HolderLookup.@NotNull Provider provider) {
ListTag list = new ListTag();
for (String teamName : flagPositions.keySet()) {
CompoundTag entry = new CompoundTag();
entry.putString("team", teamName);
FlagPosition flagPos = flagPositions.get(teamName);
entry.putInt("x", flagPos.pos.getX());
entry.putInt("y", flagPos.pos.getY());
entry.putInt("z", flagPos.pos.getZ());
entry.putString("dimension", flagPos.dimension.toString());
list.add(entry);
}
compoundTag.put("entries", list);
return compoundTag;
}
public static FlagRegistry load(CompoundTag tag, HolderLookup.Provider provider) {
FlagRegistry registry = new FlagRegistry();
ListTag list = tag.getList("entries", ListTag.TAG_COMPOUND);
for (Tag t : list) {
CompoundTag entry = (CompoundTag) t;
String teamName = entry.getString("team");
int x = entry.getInt("x");
int y = entry.getInt("y");
int z = entry.getInt("z");
ResourceLocation dimension = ResourceLocation.parse(entry.getString("dimension"));
FlagPosition flagPos = new FlagPosition(new BlockPos(x, y, z), dimension);
registry.flagPositions.put(teamName, flagPos);
}
return registry;
}
public static class FlagPosition {
private BlockPos pos;
private ResourceLocation dimension;
public FlagPosition(BlockPos pos, ResourceLocation dimension) {
this.pos = pos;
this.dimension = dimension;
}
public BlockPos getPos() {
return pos;
}
public void setPos(BlockPos pos) {
this.pos = pos;
}
public ResourceLocation getDimension() {
return dimension;
}
public void setDimension(ResourceLocation dimension) {
this.dimension = dimension;
}
@Override
public String toString() {
return "FlagPosition{" +
"pos=" + pos +
", dimension=" + dimension +
'}';
}
}
}

View file

@ -0,0 +1,12 @@
package nl.kallestruik.riseofblocks.registry;
import net.minecraft.world.item.BlockItem;
import net.neoforged.neoforge.registries.DeferredItem;
import net.neoforged.neoforge.registries.DeferredRegister;
import nl.kallestruik.riseofblocks.RiseOfBlocks;
public class ItemRegistry {
public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(RiseOfBlocks.MODID);
public static final DeferredItem<BlockItem> FLAG = ITEMS.registerSimpleBlockItem("flag", BlockRegistry.FLAG);
}

View file

@ -1,13 +1,4 @@
{
"itemGroup.riseofblocks": "Example Mod Tab",
"block.riseofblocks.example_block": "Example Block",
"item.riseofblocks.example_item": "Example Item",
"riseofblocks.configuration.title": "Rise of Blocks Configs",
"riseofblocks.configuration.section.riseofblocks.common.toml": "Rise of Blocks Configs",
"riseofblocks.configuration.section.riseofblocks.common.toml.title": "Rise of Blocks Configs",
"riseofblocks.configuration.items": "Item List",
"riseofblocks.configuration.logDirtBlock": "Log Dirt Block",
"riseofblocks.configuration.magicNumberIntroduction": "Magic Number Text",
"riseofblocks.configuration.magicNumber": "Magic Number"
"block.riseofblocks.example_block": "Example Block"
}

View file

@ -83,7 +83,7 @@ config="${mod_id}.mixins.json"
type="required"
# This version range declares a minimum of the current minecraft version up to but not including the next major version
versionRange="${minecraft_version_range}"
ordering="NONE",
ordering="NONE"
side="BOTH"
# Features are specific properties of the game environment, that you may want to declare you require. This example declares