Skip to content

Commit

Permalink
Registration groups + decorative blocks
Browse files Browse the repository at this point in the history
Registration groups are a mini version of the registration class, designed to let you group similar blocks/items into smaller groups to keep code cleaner

Decorative blocks started, with a system to pass in a model with "texture sets" - a key/value pair to match textures to the definition in the model file without child mods depending on the datagen system to find them.

Rotation dec stuff isn't finished yet!
  • Loading branch information
Fureniku committed Nov 26, 2023
1 parent 075d454 commit 5c098a4
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 0 deletions.
51 changes: 51 additions & 0 deletions src/main/java/com/fureniku/metropolis/RegistrationBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import net.minecraft.world.level.block.Block;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
import net.neoforged.neoforge.registries.DeferredRegister;
import net.neoforged.neoforge.registries.ForgeRegistries;
Expand Down Expand Up @@ -39,6 +41,8 @@ public RegistrationBase(String modid, IEventBus modEventBus) {
blockRegistry = DeferredRegister.create(ForgeRegistries.BLOCKS, modid);
itemRegistry = DeferredRegister.create(ForgeRegistries.ITEMS, modid);
creativeTabs = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, modid);
modEventBus.addListener(this::common);
modEventBus.addListener(this::client);
modEventBus.addListener(this::buildCreativeTabs);
blockRegistry.register(modEventBus);
itemRegistry.register(modEventBus);
Expand Down Expand Up @@ -163,4 +167,51 @@ public void buildCreativeTabs(BuildCreativeModeTabContentsEvent event) {
}
}
}

@SubscribeEvent
private void common(final FMLCommonSetupEvent event) {
generateCreativeTabs();
commonSetup(event);
}

@SubscribeEvent
private void client(final FMLClientSetupEvent event) {
clientSetup(event);
}

/**
* Common setup event. Handle setup stuff for client and server here.
* @param event Common setup event
*/
protected abstract void commonSetup(final FMLCommonSetupEvent event);

/**
* Client setup event. Handle client-only setup here (e.g. rendering)
* @param event Client setup event
*/
protected abstract void clientSetup(final FMLClientSetupEvent event);

/**
* Getter for the block deferred register
* @return
*/
public DeferredRegister<Block> getBlockDeferredRegister() {
return blockRegistry;
}

/**
* Getter for the item deferred register
* @return
*/
public DeferredRegister<Item> getItemDeferredRegister() {
return itemRegistry;
}

/**
* Getter for the creative tab deferred register
* @return
*/
public DeferredRegister<CreativeModeTab> getCreativeTabDeferredRegister() {
return creativeTabs;
}
}
88 changes: 88 additions & 0 deletions src/main/java/com/fureniku/metropolis/RegistrationGroup.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.fureniku.metropolis;

import com.fureniku.metropolis.utils.CreativeTabSet;
import com.fureniku.metropolis.utils.Debug;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
import net.neoforged.neoforge.registries.DeferredRegister;
import net.neoforged.neoforge.registries.ForgeRegistries;
import net.neoforged.neoforge.registries.RegistryObject;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.function.Supplier;

/**
* Class to keep RegistrationBase derivitive classes a bit cleaner. Group your blocks into these classes, if you want to.
*/
public abstract class RegistrationGroup {

protected final RegistrationBase registration;

/**
* Constructor.
* @param registrationBase the core registration class of your mod
*/
public RegistrationGroup(RegistrationBase registrationBase) {
registration = registrationBase;
}

/**
* Initialize the registration, and register all your stuff. Cannot be called from the constructor!
* Handle the creation of blocks in here - either creating blocksets, or call registerBlockSet(name, BlockClass::new)
* Handle the creation of items
* Handle the creation of creative tabs (new creativetabset, pass creativeTabs as first arg)
* Do anything else you want at this stage.
* @param modEventBus
*/
public abstract void init(IEventBus modEventBus);

/**
* Add all your blocks to the created creative tabs in here!
* <p>It may be neater to create a function for each tab, and call those functions from here.</p>
* <p>Tab registry is done using <code>yourTab.addItem(ItemStack)</code></p>
* <p>A good example of achieving that here could be <code>yourTab.addItem(getItem("item_name").get().getDefaultInstance())</code></p>
* <p>If you're using <code>BlockSet</code>s, you can instead call <code>blockSet.registerToCreativeTab(yourTab)</code> to add all blocks in the set to the tab.</p>
*/
public abstract void generateCreativeTabs();

/**
* Create an ArrayList of all your creative tabs here.
* @return an <code>ArrayList{@literal <CreativeTabSet>}</code> with all your creative tabs in
*/
public abstract ArrayList<CreativeTabSet> getCreativeTabs();

/**
* Passthrough to register a blockset
* @param name blockset name
* @param blockClass block's class
*/
protected void registerBlockSet(String name, Supplier<Block> blockClass) {
registration.registerBlockSet(name, blockClass);
}

/**
* Passthrough to get a block
* @param key block name
* @return registry object of the block
*/
protected RegistryObject<Block> getBlock(String key) {
return registration.getBlock(key);
}

/**
* Passthrough to get a item
* @param key item name
* @return registry object of the item
*/
protected RegistryObject<Item> getItem(String key) {
return registration.getItem(key);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ protected void onRightClickRemote(BlockState state, BlockPos pos, Player player)

/**
* Create the blockstate file for this block! Used by datagen. Override if the block is anything other than a normal, boring, full size block.
* For blocks that you don't want to datagen, override this with no function body to skip.
* @param blockRegistryObject the block's registryobject
* @param blockStateProvider the blockstate provider class, for some helper functions.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.fureniku.metropolis.blocks;

import com.fureniku.metropolis.datagen.MetroBlockStateProvider;
import com.fureniku.metropolis.datagen.TextureSet;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.neoforged.neoforge.client.model.generators.BlockModelBuilder;
import net.neoforged.neoforge.registries.RegistryObject;

public class MetroBlockDecorative extends MetroBlockBase {

private final VoxelShape BLOCK_SHAPE;
private TextureSet[] _resources;
private String _modelName;

public MetroBlockDecorative(Properties props, String modelName, ResourceLocation resource) {
this(props, 16, 16, modelName, new TextureSet("texture", resource));
}

public MetroBlockDecorative(Properties props, float height, String modelName, ResourceLocation resource) {
this(props, height, 16, modelName, new TextureSet("texture", resource));
}

public MetroBlockDecorative(Properties props, float height, float width, String modelName, ResourceLocation resource) {
this(props, height, width, modelName, new TextureSet("texture", resource));
}

public MetroBlockDecorative(Properties props, VoxelShape shape, String modelName, ResourceLocation resource) {
this(props, shape, modelName, new TextureSet("texture", resource));
}

public MetroBlockDecorative(Properties props, String modelName, TextureSet... textures) {
this(props, 16, 16, modelName, textures);
}

public MetroBlockDecorative(Properties props, float height, String modelName, TextureSet... textures) {
this(props, height, 16, modelName, textures);
}

public MetroBlockDecorative(Properties props, float height, float width, String modelName, TextureSet... textures) {
super(props);
float inset = (16-width)/2;
BLOCK_SHAPE = Block.box(inset, 0, inset, 16-inset, height, 16-inset);
_resources = textures;
_modelName = modelName;
}

public MetroBlockDecorative(Properties props, VoxelShape shape, String modelName, TextureSet... textures) {
super(props);
BLOCK_SHAPE = shape;
_resources = textures;
_modelName = modelName;
}

@Override
protected VoxelShape getShapeFromBlockState(BlockState pState) {
return BLOCK_SHAPE;
}

@Override
public void generateBlockState(RegistryObject<Block> blockRegistryObject, MetroBlockStateProvider blockStateProvider) {
Block block = blockRegistryObject.get();
BlockModelBuilder bmb = blockStateProvider.getModelFilesWithTexture(block, "", "blocks/decorative/" + _modelName, _resources[0].getTexture());
if (_resources.length > 1) {
for (int i = 1; i < _resources.length; i++) {
bmb = bmb.texture(_resources[i].getKey(), _resources[i].getTexture());
}
}

blockStateProvider.simpleBlockWithItem(block, bmb);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.fureniku.metropolis.blocks;

import com.fureniku.metropolis.datagen.MetroBlockStateProvider;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.neoforged.neoforge.registries.RegistryObject;

public class MetroBlockDecorativeRotatable extends MetroBlockBase {

protected static final DirectionProperty DIRECTION = DirectionProperty.create("rotation", Direction.Plane.HORIZONTAL);
private final VoxelShape BLOCK_SHAPE;

public MetroBlockDecorativeRotatable(Properties props) {
this(props, 16, 16);
}

public MetroBlockDecorativeRotatable(Properties props, float height) {
this(props, height, 16);
}

public MetroBlockDecorativeRotatable(Properties props, float height, float width) {
this(props, width, height, width);
}

public MetroBlockDecorativeRotatable(Properties props, VoxelShape shape) {
super(props);
BLOCK_SHAPE = shape;
this.registerDefaultState(this.defaultBlockState().setValue(DIRECTION, Direction.NORTH));
}

public MetroBlockDecorativeRotatable(Properties props, float sizeX, float sizeY, float sizeZ) {
super(props);
float insetX = (16-sizeX)/2;
float insetZ = (16-sizeZ)/2;
BLOCK_SHAPE = Block.box(insetX, 0, insetZ, 16-insetX, 16-sizeY, 16-insetZ);
this.registerDefaultState(this.defaultBlockState().setValue(DIRECTION, Direction.NORTH));
}

@Override
public void generateBlockState(RegistryObject<Block> blockRegistryObject, MetroBlockStateProvider blockStateProvider) {
blockStateProvider.simpleBlockWithItem(blockRegistryObject.get());
}

@Override
protected BlockState getPlacementState(BlockPlaceContext context) {
BlockState blockstate = this.defaultBlockState().setValue(DIRECTION, context.getHorizontalDirection());
return blockstate;
}

@Override
protected void createBlockState(StateDefinition.Builder builder) {
builder.add(DIRECTION);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ public void simpleBlockWithItem(Block block) {
simpleBlockWithItem(block, cubeAll(block));
}

/**
* Get a modelled block, with a matching itemblock. Uses your blocks name to get the matching texture.
* @param block Your block
*/
public void blockWithItem(Block block, ResourceLocation loc) {
simpleBlockWithItem(block, models().withExistingParent(name(block), loc));
}

/**
* Get a model for a block with a single texture.
* @param block your block
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/com/fureniku/metropolis/datagen/TextureSet.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.fureniku.metropolis.datagen;

import net.minecraft.resources.ResourceLocation;

public class TextureSet {

private String _name;
private ResourceLocation _location;

public TextureSet(String key, ResourceLocation value) {
_name = key;
_location = value;
}

public String getKey() {
return _name;
}

public ResourceLocation getTexture() {
return _location;
}
}

0 comments on commit 5c098a4

Please sign in to comment.