This commit is contained in:
parent
f59f568700
commit
6e32233f4b
13 changed files with 437 additions and 11 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
);
|
||||
}
|
|
@ -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)));
|
||||
}
|
|
@ -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());
|
||||
}
|
|
@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue