Ported 1.17.1-2.0.1 to 1.18.1.

This commit is contained in:
2022-01-19 16:23:38 +00:00
parent c15fa527e7
commit f632678810
63 changed files with 2064 additions and 67 deletions

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "totemofreviving:item/diamond_charge"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "totemofreviving:item/diamond_totem"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "totemofreviving:item/iron_charge"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "totemofreviving:item/iron_totem"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "totemofreviving:item/netherite_charge"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "totemofreviving:item/netherite_totem"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "totemofreviving:item/straw_charge"
}
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "totemofreviving:item/straw_totem"
}
}

View File

@ -0,0 +1,34 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"totemofreviving:diamond_charge"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": [
"totemofreviving:diamond_totem"
]
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "totemofreviving:diamond_charge"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View File

@ -0,0 +1,34 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"totemofreviving:diamond_totem"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": [
"minecraft:totem_of_undying"
]
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "totemofreviving:diamond_totem"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View File

@ -0,0 +1,34 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"totemofreviving:iron_charge"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": [
"totemofreviving:iron_totem"
]
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "totemofreviving:iron_charge"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View File

@ -0,0 +1,34 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"totemofreviving:iron_totem"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": [
"minecraft:emerald"
]
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "totemofreviving:iron_totem"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View File

@ -0,0 +1,34 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"totemofreviving:netherite_charge"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": [
"totemofreviving:netherite_totem"
]
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "totemofreviving:netherite_charge"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View File

@ -0,0 +1,34 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"totemofreviving:netherite_totem"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": [
"minecraft:netherite_scrap"
]
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "totemofreviving:netherite_totem"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View File

@ -0,0 +1,34 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"totemofreviving:straw_charge"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": [
"totemofreviving:straw_totem"
]
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "totemofreviving:straw_charge"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View File

@ -0,0 +1,34 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"totemofreviving:straw_totem"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"items": [
"minecraft:wheat"
]
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "totemofreviving:straw_totem"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View File

@ -0,0 +1,25 @@
{
"type": "totemofreviving:totem_recipe",
"pattern": [
"IDI",
"PEP",
"IDI"
],
"key": {
"E": {
"item": "minecraft:emerald"
},
"D": {
"item": "minecraft:diamond"
},
"I": {
"item": "minecraft:iron_ingot"
},
"P": {
"item": "minecraft:ender_pearl"
}
},
"result": {
"item": "totemofreviving:diamond_charge"
}
}

View File

@ -0,0 +1,22 @@
{
"type": "totemofreviving:totem_recipe",
"pattern": [
"EDE",
"DTD",
"EDE"
],
"key": {
"T": {
"item": "minecraft:totem_of_undying"
},
"D": {
"item": "minecraft:diamond"
},
"E": {
"item": "minecraft:ender_pearl"
}
},
"result": {
"item": "totemofreviving:diamond_totem"
}
}

View File

@ -0,0 +1,22 @@
{
"type": "totemofreviving:charge_recipe",
"pattern": [
"NIN",
"IEI",
"NIN"
],
"key": {
"E": {
"item": "minecraft:emerald"
},
"I": {
"item": "minecraft:iron_ingot"
},
"N": {
"item": "minecraft:iron_nugget"
}
},
"result": {
"item": "totemofreviving:iron_charge"
}
}

View File

@ -0,0 +1,22 @@
{
"type": "totemofreviving:totem_recipe",
"pattern": [
" E ",
"IBI",
" I "
],
"key": {
"B": {
"item": "minecraft:iron_block"
},
"E": {
"item": "minecraft:emerald"
},
"I": {
"item": "minecraft:iron_ingot"
}
},
"result": {
"item": "totemofreviving:iron_totem"
}
}

View File

@ -0,0 +1,22 @@
{
"type": "totemofreviving:charge_recipe",
"pattern": [
"GNG",
"NCN",
"GNG"
],
"key": {
"C": {
"item": "totemofreviving:diamond_charge"
},
"N": {
"item": "minecraft:netherite_scrap"
},
"G": {
"item": "minecraft:gold_ingot"
}
},
"result": {
"item": "totemofreviving:netherite_charge"
}
}

View File

@ -0,0 +1,25 @@
{
"type": "totemofreviving:totem_recipe",
"pattern": [
"BNB",
"NTN",
"BGB"
],
"key": {
"T": {
"item": "totemofreviving:diamond_totem"
},
"N": {
"item": "minecraft:netherite_scrap"
},
"G": {
"item": "minecraft:gold_ingot"
},
"B": {
"item": "minecraft:nether_brick"
}
},
"result": {
"item": "totemofreviving:netherite_totem"
}
}

View File

@ -0,0 +1,22 @@
{
"type": "totemofreviving:charge_recipe",
"pattern": [
"NWN",
"WEW",
"NWN"
],
"key": {
"E": {
"item": "minecraft:emerald"
},
"W": {
"item": "minecraft:wheat"
},
"N": {
"item": "minecraft:iron_nugget"
}
},
"result": {
"item": "totemofreviving:straw_charge"
}
}

View File

@ -0,0 +1,25 @@
{
"type": "totemofreviving:totem_recipe",
"pattern": [
"NSN",
"NWN",
"N|N"
],
"key": {
"W": {
"item": "minecraft:wheat"
},
"|": {
"item": "minecraft:stick"
},
"S": {
"item": "minecraft:string"
},
"N": {
"item": "minecraft:iron_nugget"
}
},
"result": {
"item": "totemofreviving:straw_totem"
}
}

View File

@ -0,0 +1,13 @@
package dev.micle.totemofreviving;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
public interface ISideProxy {
MinecraftServer getServer();
Player getClientPlayer();
Level getClientWorld();
}

View File

@ -0,0 +1,104 @@
package dev.micle.totemofreviving;
import dev.micle.totemofreviving.config.Config;
import dev.micle.totemofreviving.data.DataGenerators;
import dev.micle.totemofreviving.network.Network;
import dev.micle.totemofreviving.setup.Registration;
import net.minecraft.client.Minecraft;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.AddReloadListenerEvent;
import net.minecraftforge.event.server.ServerStartedEvent;
import net.minecraftforge.event.server.ServerStoppingEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.event.lifecycle.*;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
class SideProxy implements ISideProxy {
private static MinecraftServer server = null;
// Common setup
SideProxy() {
Registration.register();
Config.init();
Network.init();
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
modEventBus.addListener(DataGenerators::gatherData);
modEventBus.addListener(SideProxy::setup);
modEventBus.addListener(SideProxy::imcEnqueue);
modEventBus.addListener(SideProxy::imcProcess);
MinecraftForge.EVENT_BUS.addListener(SideProxy::onAddReloadListeners);
MinecraftForge.EVENT_BUS.addListener(SideProxy::serverStarted);
MinecraftForge.EVENT_BUS.addListener(SideProxy::serverStopping);
}
private static void setup(FMLCommonSetupEvent event) {}
private static void imcEnqueue(InterModEnqueueEvent event) {}
private static void imcProcess(InterModProcessEvent event) {}
private static void onAddReloadListeners(AddReloadListenerEvent event) {}
private static void serverStarted(ServerStartedEvent event) {
server = event.getServer();
}
private static void serverStopping(ServerStoppingEvent event) {
server = null;
}
@Override
public MinecraftServer getServer() {
return server;
}
@Override
public Player getClientPlayer() {
return null;
}
@Override
public Level getClientWorld() {
return null;
}
// Client setup
static class Client extends SideProxy {
Client() {
FMLJavaModLoadingContext.get().getModEventBus().addListener(Client::setup);
FMLJavaModLoadingContext.get().getModEventBus().addListener(Client::postSetup);
}
private static void setup(FMLClientSetupEvent event) {}
private static void postSetup(FMLLoadCompleteEvent event) {}
@Override
@OnlyIn(Dist.CLIENT)
public Player getClientPlayer() {
return Minecraft.getInstance().player;
}
@Override
@OnlyIn(Dist.CLIENT)
public Level getClientWorld() {
return Minecraft.getInstance().level;
}
}
// Server setup
static class Server extends SideProxy {
Server() {
FMLJavaModLoadingContext.get().getModEventBus().addListener(Server::setup);
}
private static void setup(FMLDedicatedServerSetupEvent event) {}
}
}

View File

@ -1,77 +1,58 @@
package dev.micle.totemofreviving;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.InterModComms;
import dev.micle.totemofreviving.setup.ModItems;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent;
import net.minecraftforge.event.server.ServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.util.stream.Collectors;
import java.util.Optional;
import java.util.Random;
// The value here should match an entry in the META-INF/mods.toml file
@Mod("totemofreviving")
public class TotemOfReviving {
// Directly reference a log4j logger.
private static final Logger LOGGER = LogManager.getLogger();
public TotemOfReviving() {
// Register the setup method for modloading
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
// Register the enqueueIMC method for modloading
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::enqueueIMC);
// Register the processIMC method for modloading
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::processIMC);
// Register ourselves for server and other game events we are interested in
MinecraftForge.EVENT_BUS.register(this);
}
private void setup(final FMLCommonSetupEvent event) {
// some preinit code
LOGGER.info("HELLO FROM PREINIT");
LOGGER.info("DIRT BLOCK >> {}", Blocks.DIRT.getRegistryName());
}
private void enqueueIMC(final InterModEnqueueEvent event) {
// some example code to dispatch IMC to another mod
InterModComms.sendTo("totemofreviving", "helloworld", () -> {
LOGGER.info("Hello world from the MDK");
return "Hello world";
});
}
private void processIMC(final InterModProcessEvent event) {
// some example code to receive and process InterModComms from other mods
LOGGER.info("Got IMC {}", event.getIMCStream().
map(m -> m.messageSupplier().get()).
collect(Collectors.toList()));
}
// You can use SubscribeEvent and let the Event Bus discover methods to call
@SubscribeEvent
public void onServerStarting(ServerStartingEvent event) {
// do something when the server starts
LOGGER.info("HELLO from server starting");
}
// You can use EventBusSubscriber to automatically subscribe events on the contained class (this is subscribing to the MOD
// Event bus for receiving Registry Events)
@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public static class RegistryEvents {
@SubscribeEvent
public static void onBlocksRegistry(final RegistryEvent.Register<Block> blockRegistryEvent) {
// register a new block here
LOGGER.info("HELLO from Register Block");
@Mod(TotemOfReviving.MOD_ID)
public final class TotemOfReviving {
public static final String MOD_ID = "totemofreviving";
public static final String MOD_NAME = "Micle's Totem of Reviving";
public static final CreativeModeTab ITEM_GROUP = new CreativeModeTab(MOD_ID) {
@Override
public ItemStack makeIcon() {
return new ItemStack(ModItems.STRAW_TOTEM.get());
}
};
public static final String RESOURCE_PREFIX = MOD_ID + ':';
public static final Random RANDOM = new Random();
public static final Logger LOGGER = LogManager.getLogger(MOD_NAME);
public static TotemOfReviving INSTANCE;
public static ISideProxy PROXY;
public TotemOfReviving() {
INSTANCE = this;
PROXY = DistExecutor.safeRunForDist(
() -> SideProxy.Client::new,
() -> SideProxy.Server::new
);
}
public static String getVersion() {
Optional<? extends ModContainer> optional = ModList.get().getModContainerById(MOD_ID);
if (optional.isPresent()) {
return optional.get().getModInfo().getVersion().toString();
}
return "0.0.0";
}
public static ResourceLocation createResourceLocation(String name) {
if (name.contains(":")) {
throw new IllegalArgumentException("name containes namespace");
}
return new ResourceLocation(MOD_ID, name);
}
}

View File

@ -0,0 +1,95 @@
package dev.micle.totemofreviving.config;
import dev.micle.totemofreviving.item.totem.DiamondTotemItem;
import dev.micle.totemofreviving.item.totem.IronTotemItem;
import dev.micle.totemofreviving.item.totem.NetheriteTotemItem;
import dev.micle.totemofreviving.item.totem.StrawTotemItem;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.config.ModConfig;
public final class Config {
public static void init() {
ModLoadingContext.get().registerConfig(ModConfig.Type.SERVER, Server.SPEC);
}
public static class Server {
private static final ForgeConfigSpec SPEC;
private static final TotemConfig STRAW_TOTEM_CONFIG;
private static final TotemConfig IRON_TOTEM_CONFIG;
private static final TotemConfig DIAMOND_TOTEM_CONFIG;
private static final TotemConfig NETHERITE_TOTEM_CONFIG;
static {
ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder();
builder.comment("WHEN MAKING CHANGES IT IS RECOMMENDED TO NOT BE IN A WORLD.\n" +
"CHANGES WILL MOST LIKELY REQUIRE A RESTART FOR EVERYTHING TO WORK PROPERLY.");
STRAW_TOTEM_CONFIG = new TotemConfig(builder, StrawTotemItem.getName(), true, -1, 3,
1, false, false, 1);
IRON_TOTEM_CONFIG = new TotemConfig(builder, IronTotemItem.getName(), true, -1, 5,
0.75, false, false, 4);
DIAMOND_TOTEM_CONFIG = new TotemConfig(builder, DiamondTotemItem.getName(), true, -1, 10,
0.5, false, false, 10);
NETHERITE_TOTEM_CONFIG = new TotemConfig(builder, NetheriteTotemItem.getName(), true, 1, 1,
1, true, true, 0);
SPEC = builder.build();
}
public static TotemConfig getStrawTotemConfig() { return STRAW_TOTEM_CONFIG; }
public static TotemConfig getIronTotemConfig() { return IRON_TOTEM_CONFIG; }
public static TotemConfig getDiamondTotemConfig() { return DIAMOND_TOTEM_CONFIG; }
public static TotemConfig getNetheriteTotemConfig() { return NETHERITE_TOTEM_CONFIG; }
}
public static class TotemConfig {
private final ForgeConfigSpec.BooleanValue IS_ENABLED;
private final ForgeConfigSpec.IntValue CHARGE_COST;
private final ForgeConfigSpec.IntValue CHARGE_COST_LIMIT;
private final ForgeConfigSpec.DoubleValue CHARGE_COST_MULTIPLIER;
private final ForgeConfigSpec.BooleanValue CAN_REVIVE_MORE_EXPENSIVE_TARGETS;
private final ForgeConfigSpec.BooleanValue CAN_REVIVE_ACROSS_DIMENSIONS;
private final ForgeConfigSpec.IntValue DURABILITY;
TotemConfig(ForgeConfigSpec.Builder builder, String name, boolean isEnabled, int chargeCost,
int chargeCostLimit, double chargeCostMultiplier, boolean canReviveMoreExpensiveTargets,
boolean canReviveAcrossDimensions, int durability) {
builder.push(name);
IS_ENABLED = builder
.comment("Is the " + name + " enabled?")
.define("isEnabled", isEnabled);
CHARGE_COST = builder
.comment("The charge cost to revive a player.\n" +
"-1 means the cost is dynamic (follows the amount of deaths the target has)\n" +
"Higher values set the charge cost to static, meaning that this will be the amount of charges needed to revive someone.")
.defineInRange("chargeCost", chargeCost, -1, Integer.MAX_VALUE);
CHARGE_COST_LIMIT = builder
.comment("The max amount of charge this totem can hold at once. Only works with dynamic cost.")
.defineInRange("chargeCostLimit", chargeCostLimit, 1, Integer.MAX_VALUE);
CHARGE_COST_MULTIPLIER = builder
.comment("Charge cost multiplier. 0.5 means the charge cost will be 50% of the original cost. Only works with dynamic cost.")
.defineInRange("chargeCostMultiplier", chargeCostMultiplier, 0.01, 100);
CAN_REVIVE_MORE_EXPENSIVE_TARGETS = builder
.comment("Is the totem able to revive targets that cost more than the totems max charge?\n" +
"This only applies if the totem is fully charged. (dynamic wont work if limit is 0)")
.define("canReviveMoreExpensiveTargets", canReviveMoreExpensiveTargets);
CAN_REVIVE_ACROSS_DIMENSIONS = builder
.comment("Is the totem able to revive targets across dimensions?")
.define("canReviveAcrossDimensions", canReviveAcrossDimensions);
DURABILITY = builder
.comment("The durability of the totem. 0 means unbreakable.")
.defineInRange("durability", durability, 0, Integer.MAX_VALUE);
builder.pop();
}
public boolean getIsEnabled() { return IS_ENABLED.get(); }
public int getChargeCost() { return CHARGE_COST.get(); }
public int getChargeCostLimit() { return CHARGE_COST_LIMIT.get(); }
public double getChargeCostMultiplier() { return CHARGE_COST_MULTIPLIER.get(); }
public boolean getCanReviveMoreExpensiveTargets() { return CAN_REVIVE_MORE_EXPENSIVE_TARGETS.get(); }
public boolean getCanReviveAcrossDimensions() { return CAN_REVIVE_ACROSS_DIMENSIONS.get(); }
public int getDurability() { return DURABILITY.get(); }
}
}

View File

@ -0,0 +1,22 @@
package dev.micle.totemofreviving.data;
import dev.micle.totemofreviving.TotemOfReviving;
import dev.micle.totemofreviving.data.client.ModItemModelProvider;
import net.minecraft.data.DataGenerator;
import net.minecraftforge.common.data.ExistingFileHelper;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.forge.event.lifecycle.GatherDataEvent;
@Mod.EventBusSubscriber(modid = TotemOfReviving.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
public class DataGenerators {
@SubscribeEvent
public static void gatherData(GatherDataEvent event) {
DataGenerator generator = event.getGenerator();
ExistingFileHelper existingFileHelper = event.getExistingFileHelper();
generator.addProvider(new ModItemModelProvider(generator, existingFileHelper));
generator.addProvider(new ModRecipeProvider(generator));
}
}

View File

@ -0,0 +1,99 @@
package dev.micle.totemofreviving.data;
import dev.micle.totemofreviving.item.crafting.ExtendedShapedRecipeBuilder;
import dev.micle.totemofreviving.setup.ModItems;
import dev.micle.totemofreviving.setup.ModRecipes;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.data.recipes.RecipeProvider;
import net.minecraft.world.item.Items;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.function.Consumer;
public class ModRecipeProvider extends RecipeProvider {
public ModRecipeProvider(DataGenerator generator) {
super(generator);
}
@Override
@ParametersAreNonnullByDefault
protected void buildCraftingRecipes(Consumer<FinishedRecipe> consumer) {
ExtendedShapedRecipeBuilder.shaped(ModRecipes.TOTEM_RECIPE.get(), ModItems.STRAW_TOTEM.get())
.define('W', Items.WHEAT)
.define('|', Items.STICK)
.define('S', Items.STRING)
.define('N', Items.IRON_NUGGET)
.pattern("NSN")
.pattern("NWN")
.pattern("N|N")
.unlockedBy("has_item", has(Items.WHEAT))
.save(consumer);
ExtendedShapedRecipeBuilder.shaped(ModRecipes.TOTEM_RECIPE.get(), ModItems.IRON_TOTEM.get())
.define('B', Items.IRON_BLOCK)
.define('E', Items.EMERALD)
.define('I', Items.IRON_INGOT)
.pattern(" E ")
.pattern("IBI")
.pattern(" I ")
.unlockedBy("has_item", has(Items.EMERALD))
.save(consumer);
ExtendedShapedRecipeBuilder.shaped(ModRecipes.TOTEM_RECIPE.get(), ModItems.DIAMOND_TOTEM.get())
.define('T', Items.TOTEM_OF_UNDYING)
.define('D', Items.DIAMOND)
.define('E', Items.ENDER_PEARL)
.pattern("EDE")
.pattern("DTD")
.pattern("EDE")
.unlockedBy("has_item", has(Items.TOTEM_OF_UNDYING))
.save(consumer);
ExtendedShapedRecipeBuilder.shaped(ModRecipes.TOTEM_RECIPE.get(), ModItems.NETHERITE_TOTEM.get())
.define('T', ModItems.DIAMOND_TOTEM.get())
.define('N', Items.NETHERITE_SCRAP)
.define('G', Items.GOLD_INGOT)
.define('B', Items.NETHER_BRICK)
.pattern("BNB")
.pattern("NTN")
.pattern("BGB")
.unlockedBy("has_item", has(Items.NETHERITE_SCRAP))
.save(consumer);
ExtendedShapedRecipeBuilder.shaped(ModRecipes.CHARGE_RECIPE.get(), ModItems.STRAW_CHARGE.get())
.define('E', Items.EMERALD)
.define('W', Items.WHEAT)
.define('N', Items.IRON_NUGGET)
.pattern("NWN")
.pattern("WEW")
.pattern("NWN")
.unlockedBy("has_item", has(ModItems.STRAW_TOTEM.get()))
.save(consumer);
ExtendedShapedRecipeBuilder.shaped(ModRecipes.CHARGE_RECIPE.get(), ModItems.IRON_CHARGE.get())
.define('E', Items.EMERALD)
.define('I', Items.IRON_INGOT)
.define('N', Items.IRON_NUGGET)
.pattern("NIN")
.pattern("IEI")
.pattern("NIN")
.unlockedBy("has_item", has(ModItems.IRON_TOTEM.get()))
.save(consumer);
ExtendedShapedRecipeBuilder.shaped(ModRecipes.TOTEM_RECIPE.get(), ModItems.DIAMOND_CHARGE.get())
.define('E', Items.EMERALD)
.define('D', Items.DIAMOND)
.define('I', Items.IRON_INGOT)
.define('P', Items.ENDER_PEARL)
.pattern("IDI")
.pattern("PEP")
.pattern("IDI")
.unlockedBy("has_item", has(ModItems.DIAMOND_TOTEM.get()))
.save(consumer);
ExtendedShapedRecipeBuilder.shaped(ModRecipes.CHARGE_RECIPE.get(), ModItems.NETHERITE_CHARGE.get())
.define('C', ModItems.DIAMOND_CHARGE.get())
.define('N', Items.NETHERITE_SCRAP)
.define('G', Items.GOLD_INGOT)
.pattern("GNG")
.pattern("NCN")
.pattern("GNG")
.unlockedBy("has_item", has(ModItems.NETHERITE_TOTEM.get()))
.save(consumer);
}
}

View File

@ -0,0 +1,41 @@
package dev.micle.totemofreviving.data.client;
import dev.micle.totemofreviving.TotemOfReviving;
import dev.micle.totemofreviving.item.charge.DiamondChargeItem;
import dev.micle.totemofreviving.item.charge.IronChargeItem;
import dev.micle.totemofreviving.item.charge.NetheriteChargeItem;
import dev.micle.totemofreviving.item.charge.StrawChargeItem;
import dev.micle.totemofreviving.item.totem.DiamondTotemItem;
import dev.micle.totemofreviving.item.totem.IronTotemItem;
import dev.micle.totemofreviving.item.totem.NetheriteTotemItem;
import dev.micle.totemofreviving.item.totem.StrawTotemItem;
import net.minecraft.data.DataGenerator;
import net.minecraftforge.client.model.generators.ItemModelBuilder;
import net.minecraftforge.client.model.generators.ItemModelProvider;
import net.minecraftforge.client.model.generators.ModelFile;
import net.minecraftforge.common.data.ExistingFileHelper;
public class ModItemModelProvider extends ItemModelProvider {
public ModItemModelProvider(DataGenerator generator, ExistingFileHelper existingFileHelper) {
super(generator, TotemOfReviving.MOD_ID, existingFileHelper);
}
@Override
protected void registerModels() {
ModelFile itemGenerated = getExistingFile(mcLoc("item/generated"));
builder(itemGenerated, StrawTotemItem.getName());
builder(itemGenerated, IronTotemItem.getName());
builder(itemGenerated, DiamondTotemItem.getName());
builder(itemGenerated, NetheriteTotemItem.getName());
builder(itemGenerated, StrawChargeItem.getName());
builder(itemGenerated, IronChargeItem.getName());
builder(itemGenerated, DiamondChargeItem.getName());
builder(itemGenerated, NetheriteChargeItem.getName());
}
private ItemModelBuilder builder(ModelFile itemGenerated, String name) {
return getBuilder(name).parent(itemGenerated).texture("layer0", "item/" + name);
}
}

View File

@ -0,0 +1,49 @@
package dev.micle.totemofreviving.item.charge;
import dev.micle.totemofreviving.TotemOfReviving;
import dev.micle.totemofreviving.config.Config;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Rarity;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.List;
public class ChargeItem extends Item {
public ChargeItem() {
this(Rarity.COMMON);
}
public ChargeItem(Rarity rarity) {
super(new Properties().tab(TotemOfReviving.ITEM_GROUP).stacksTo(64).rarity(rarity));
}
@Override
@OnlyIn(Dist.CLIENT)
@ParametersAreNonnullByDefault
public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> tooltip, TooltipFlag tooltipFlag) {
if (isEnabled(stack)) {
tooltip.add(new TextComponent(ChatFormatting.WHITE + "Used for charging its corresponding totem."));
} else {
tooltip.add(new TextComponent(ChatFormatting.RED + "Totem is disabled!"));
}
super.appendHoverText(stack, world, tooltip, tooltipFlag);
}
public static boolean isEnabled(ItemStack stack) {
Item item = stack.getItem();
if (item instanceof StrawChargeItem) { return Config.Server.getStrawTotemConfig().getIsEnabled(); }
if (item instanceof IronChargeItem) { return Config.Server.getIronTotemConfig().getIsEnabled(); }
if (item instanceof DiamondChargeItem) { return Config.Server.getDiamondTotemConfig().getIsEnabled(); }
if (item instanceof NetheriteChargeItem) { return Config.Server.getNetheriteTotemConfig().getIsEnabled(); }
return false;
}
}

View File

@ -0,0 +1,13 @@
package dev.micle.totemofreviving.item.charge;
import net.minecraft.world.item.Rarity;
public class DiamondChargeItem extends ChargeItem {
public DiamondChargeItem() {
super(Rarity.RARE);
}
public static String getName() {
return "diamond_charge";
}
}

View File

@ -0,0 +1,9 @@
package dev.micle.totemofreviving.item.charge;
public class IronChargeItem extends ChargeItem {
public IronChargeItem() {}
public static String getName() {
return "iron_charge";
}
}

View File

@ -0,0 +1,13 @@
package dev.micle.totemofreviving.item.charge;
import net.minecraft.world.item.Rarity;
public class NetheriteChargeItem extends ChargeItem {
public NetheriteChargeItem() {
super(Rarity.EPIC);
}
public static String getName() {
return "netherite_charge";
}
}

View File

@ -0,0 +1,13 @@
package dev.micle.totemofreviving.item.charge;
import net.minecraft.world.item.Rarity;
public class StrawChargeItem extends ChargeItem {
public StrawChargeItem() {
super(Rarity.UNCOMMON);
}
public static String getName() {
return "straw_charge";
}
}

View File

@ -0,0 +1,33 @@
package dev.micle.totemofreviving.item.crafting;
import dev.micle.totemofreviving.item.charge.ChargeItem;
import dev.micle.totemofreviving.setup.ModRecipes;
import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.ShapedRecipe;
import net.minecraft.world.level.Level;
public class ChargeRecipe extends ExtendedShapedRecipe {
public ChargeRecipe(ShapedRecipe recipe) {
super(recipe);
}
@Override
public RecipeSerializer<?> getSerializer() {
return ModRecipes.CHARGE_RECIPE.get();
}
@Override
public boolean matches(CraftingContainer inventory, Level world) {
if (!ChargeItem.isEnabled(getResultItem())) {
return false;
}
return getBaseRecipe().matches(inventory, world);
}
@Override
public ItemStack assemble(CraftingContainer inventory) {
return getBaseRecipe().getResultItem();
}
}

View File

@ -0,0 +1,88 @@
package dev.micle.totemofreviving.item.crafting;
import com.google.gson.JsonObject;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.ShapedRecipe;
import net.minecraft.world.level.Level;
import net.minecraftforge.registries.ForgeRegistryEntry;
import javax.annotation.Nullable;
import java.util.function.BiConsumer;
import java.util.function.Function;
public abstract class ExtendedShapedRecipe extends ShapedRecipe {
private static final RecipeSerializer<ShapedRecipe> BASE_SERIALIZER = RecipeSerializer.SHAPED_RECIPE;
private final ShapedRecipe recipe;
public ExtendedShapedRecipe(ShapedRecipe recipe) {
super(recipe.getId(), recipe.getGroup(), recipe.getRecipeWidth(), recipe.getRecipeHeight(), recipe.getIngredients(), recipe.getResultItem());
this.recipe = recipe;
}
public ShapedRecipe getBaseRecipe() {
return this.recipe;
}
@Override
public abstract RecipeSerializer<?> getSerializer();
@Override
public abstract boolean matches(CraftingContainer inventory, Level world);
@Override
public abstract ItemStack assemble(CraftingContainer inventory);
public static class Serializer<T extends ExtendedShapedRecipe> extends ForgeRegistryEntry<RecipeSerializer<?>> implements RecipeSerializer<T> {
private final Function<ShapedRecipe, T> recipeFactory;
@Nullable private final BiConsumer<JsonObject, T> readJson;
@Nullable private final BiConsumer<FriendlyByteBuf, T> readBuffer;
@Nullable private final BiConsumer<FriendlyByteBuf, T> writeBuffer;
public Serializer(Function<ShapedRecipe, T> recipeFactory,
@Nullable BiConsumer<JsonObject, T> readJson,
@Nullable BiConsumer<FriendlyByteBuf, T> readBuffer,
@Nullable BiConsumer<FriendlyByteBuf, T> writeBuffer) {
this.recipeFactory = recipeFactory;
this.readJson = readJson;
this.readBuffer = readBuffer;
this.writeBuffer = writeBuffer;
}
public static <S extends ExtendedShapedRecipe> Serializer<S> basic(Function<ShapedRecipe, S> recipeFactory) {
return new Serializer<>(recipeFactory, null, null, null);
}
@Override
public T fromJson(ResourceLocation recipeId, JsonObject json) {
ShapedRecipe recipe = BASE_SERIALIZER.fromJson(recipeId, json);
T result = this.recipeFactory.apply(recipe);
if (this.readJson != null) {
this.readJson.accept(json, result);
}
return result;
}
@Override
public T fromNetwork(ResourceLocation recipeId, FriendlyByteBuf buffer) {
ShapedRecipe recipe = BASE_SERIALIZER.fromNetwork(recipeId, buffer);
T result = this.recipeFactory.apply(recipe);
if (this.readBuffer != null) {
this.readBuffer.accept(buffer, result);
}
return result;
}
@Override
public void toNetwork(FriendlyByteBuf buffer, T recipe) {
BASE_SERIALIZER.toNetwork(buffer, recipe.getBaseRecipe());
if (this.writeBuffer != null) {
this.writeBuffer.accept(buffer, recipe);
}
}
}
}

View File

@ -0,0 +1,184 @@
package dev.micle.totemofreviving.item.crafting;
import com.google.common.collect.Sets;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import net.minecraft.advancements.Advancement;
import net.minecraft.advancements.AdvancementRewards;
import net.minecraft.advancements.CriterionTriggerInstance;
import net.minecraft.advancements.RequirementsStrategy;
import net.minecraft.advancements.critereon.EntityPredicate;
import net.minecraft.advancements.critereon.RecipeUnlockedTrigger;
import net.minecraft.data.recipes.FinishedRecipe;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.Tag;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.level.ItemLike;
import javax.annotation.Nullable;
import java.util.*;
import java.util.function.Consumer;
public class ExtendedShapedRecipeBuilder {
private final RecipeSerializer<?> serializer;
private final Item result;
private final int count;
private final List<String> pattern = new ArrayList<>();
private final Map<Character, Ingredient> key = new LinkedHashMap<>();
private final Advancement.Builder advancementBuilder = Advancement.Builder.advancement();
private boolean hasAdvancementCriterion = false;
private String group = "";
private ExtendedShapedRecipeBuilder(RecipeSerializer<?> serializer, ItemLike result, int count) {
this.serializer = serializer;
this.result = result.asItem();
this.count = count;
}
public static ExtendedShapedRecipeBuilder shaped(RecipeSerializer<?> serializer, ItemLike result) {
return shaped(serializer, result, 1);
}
public static ExtendedShapedRecipeBuilder shaped(RecipeSerializer<?> serializer, ItemLike result, int count) {
return new ExtendedShapedRecipeBuilder(serializer, result, count);
}
public ExtendedShapedRecipeBuilder define(Character symbol, Tag<Item> tagIn) {
return this.define(symbol, Ingredient.of(tagIn));
}
public ExtendedShapedRecipeBuilder define(Character symbol, ItemLike itemIn) {
return this.define(symbol, Ingredient.of(itemIn));
}
public ExtendedShapedRecipeBuilder define(Character symbol, Ingredient ingredientIn) {
if (this.key.containsKey(symbol)) {
throw new IllegalArgumentException("Symbol '" + symbol + "' is already defined!");
} else if (symbol == ' ') {
throw new IllegalArgumentException("Symbol ' ' (whitespace) is reserved and cannot be defined");
} else {
this.key.put(symbol, ingredientIn);
return this;
}
}
public ExtendedShapedRecipeBuilder pattern(String patternIn) {
if (!this.pattern.isEmpty() && patternIn.length() != this.pattern.get(0).length()) {
throw new IllegalArgumentException("Pattern must be the same width on every line!");
} else {
this.pattern.add(patternIn);
return this;
}
}
public ExtendedShapedRecipeBuilder unlockedBy(String name, CriterionTriggerInstance criterionIn) {
this.advancementBuilder.addCriterion(name, criterionIn);
this.hasAdvancementCriterion = true;
return this;
}
public ExtendedShapedRecipeBuilder group(String groupIn) {
this.group = groupIn;
return this;
}
public void save(Consumer<FinishedRecipe> consumer) {
save(consumer, this.result.getRegistryName());
}
public void save(Consumer<FinishedRecipe> consumer, ResourceLocation id) {
this.validate(id);
if (this.hasAdvancementCriterion && !this.advancementBuilder.getCriteria().isEmpty()) {
this.advancementBuilder.parent(new ResourceLocation("recipes/root"))
.addCriterion("has_the_recipe", new RecipeUnlockedTrigger.TriggerInstance(EntityPredicate.Composite.ANY, id))
.rewards(AdvancementRewards.Builder.recipe(id))
.requirements(RequirementsStrategy.OR);
}
ResourceLocation advancementId = new ResourceLocation(id.getNamespace(), "recipes/" + this.result.getItemCategory().getRecipeFolderName() + "/" + id.getPath());
consumer.accept(new Result(id, this, advancementId));
}
private void validate(ResourceLocation id) {
if (this.pattern.isEmpty()) {
throw new IllegalStateException("No pattern is defined for shaped recipe " + id + "!");
} else {
Set<Character> set = Sets.newHashSet(this.key.keySet());
set.remove(' ');
for (String s : this.pattern) {
for (int i = 0; i < s.length(); ++i) {
char c0 = s.charAt(i);
if (!this.key.containsKey(c0) && c0 != ' ') {
throw new IllegalStateException("Pattern in recipe " + id + " uses undefined symbol '" + c0 + "'");
}
set.remove(c0);
}
}
if (!set.isEmpty()) {
throw new IllegalStateException("Ingredients are defined but not used in pattern for recipe " + id);
} else if (this.pattern.size() == 1 && this.pattern.get(0).length() == 1) {
throw new IllegalStateException("Shaped recipe " + id + " only takes in a single item - should it be a shapeless recipe instead?");
}
}
}
public static class Result implements FinishedRecipe {
private final ResourceLocation id;
private final ExtendedShapedRecipeBuilder builder;
private final ResourceLocation advancementId;
public Result(ResourceLocation id, ExtendedShapedRecipeBuilder builder, ResourceLocation advancementId) {
this.id = id;
this.builder = builder;
this.advancementId = advancementId;
}
@Override
public void serializeRecipeData(JsonObject json) {
if (!builder.group.isEmpty()) {
json.addProperty("group", builder.group);
}
JsonArray pattern = new JsonArray();
builder.pattern.forEach(pattern::add);
json.add("pattern", pattern);
JsonObject key = new JsonObject();
builder.key.forEach((c, ingredient) -> key.add(String.valueOf(c), ingredient.toJson()));
json.add("key", key);
JsonObject result = new JsonObject();
result.addProperty("item", builder.result.getRegistryName().toString());
if (builder.count > 1) {
result.addProperty("count", builder.count);
}
json.add("result", result);
}
@Override
public RecipeSerializer<?> getType() {
return builder.serializer;
}
@Override
public ResourceLocation getId() {
return id;
}
@Nullable
@Override
public JsonObject serializeAdvancement() {
return builder.hasAdvancementCriterion ? builder.advancementBuilder.serializeToJson() : null;
}
@Nullable
@Override
public ResourceLocation getAdvancementId() {
return builder.hasAdvancementCriterion ? advancementId : null;
}
}
}

View File

@ -0,0 +1,33 @@
package dev.micle.totemofreviving.item.crafting;
import dev.micle.totemofreviving.item.totem.TotemItem;
import dev.micle.totemofreviving.setup.ModRecipes;
import net.minecraft.world.inventory.CraftingContainer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraft.world.item.crafting.ShapedRecipe;
import net.minecraft.world.level.Level;
public class TotemRecipe extends ExtendedShapedRecipe {
public TotemRecipe(ShapedRecipe recipe) {
super(recipe);
}
@Override
public RecipeSerializer<?> getSerializer() {
return ModRecipes.TOTEM_RECIPE.get();
}
@Override
public boolean matches(CraftingContainer inventory, Level world) {
if (!TotemItem.isEnabled(getResultItem())) {
return false;
}
return getBaseRecipe().matches(inventory, world);
}
@Override
public ItemStack assemble(CraftingContainer inventory) {
return getBaseRecipe().getResultItem();
}
}

View File

@ -0,0 +1,21 @@
package dev.micle.totemofreviving.item.totem;
import dev.micle.totemofreviving.config.Config;
import dev.micle.totemofreviving.item.charge.DiamondChargeItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Rarity;
public class DiamondTotemItem extends TotemItem {
public DiamondTotemItem() {
super(Rarity.RARE, Config.Server.getDiamondTotemConfig().getDurability());
}
public static String getName() {
return "diamond_totem";
}
@Override
public boolean isCharge(ItemStack stack) {
return (stack.getItem() instanceof DiamondChargeItem);
}
}

View File

@ -0,0 +1,20 @@
package dev.micle.totemofreviving.item.totem;
import dev.micle.totemofreviving.config.Config;
import dev.micle.totemofreviving.item.charge.IronChargeItem;
import net.minecraft.world.item.ItemStack;
public class IronTotemItem extends TotemItem {
public IronTotemItem() {
super(Config.Server.getIronTotemConfig().getDurability());
}
public static String getName() {
return "iron_totem";
}
@Override
public boolean isCharge(ItemStack stack) {
return (stack.getItem() instanceof IronChargeItem);
}
}

View File

@ -0,0 +1,26 @@
package dev.micle.totemofreviving.item.totem;
import dev.micle.totemofreviving.config.Config;
import dev.micle.totemofreviving.item.charge.NetheriteChargeItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Rarity;
public class NetheriteTotemItem extends TotemItem {
public NetheriteTotemItem() {
super(Rarity.EPIC, Config.Server.getNetheriteTotemConfig().getDurability());
}
public static String getName() {
return "netherite_totem";
}
@Override
public boolean isCharge(ItemStack stack) {
return (stack.getItem() instanceof NetheriteChargeItem);
}
@Override
public boolean isFireResistant() {
return true;
}
}

View File

@ -0,0 +1,21 @@
package dev.micle.totemofreviving.item.totem;
import dev.micle.totemofreviving.config.Config;
import dev.micle.totemofreviving.item.charge.StrawChargeItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Rarity;
public class StrawTotemItem extends TotemItem {
public StrawTotemItem() {
super(Rarity.UNCOMMON, Config.Server.getStrawTotemConfig().getDurability());
}
public static String getName() {
return "straw_totem";
}
@Override
public boolean isCharge(ItemStack stack) {
return (stack.getItem() instanceof StrawChargeItem);
}
}

View File

@ -0,0 +1,259 @@
package dev.micle.totemofreviving.item.totem;
import dev.micle.totemofreviving.TotemOfReviving;
import dev.micle.totemofreviving.config.Config;
import dev.micle.totemofreviving.network.ChangeTargetPacket;
import dev.micle.totemofreviving.network.ChargeTotemPacket;
import dev.micle.totemofreviving.network.Network;
import dev.micle.totemofreviving.network.ReviveTargetPacket;
import dev.micle.totemofreviving.setup.ModKeyMappings;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stats;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Rarity;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.List;
import java.util.UUID;
public abstract class TotemItem extends Item {
private static final String TAG_TARGET_INDEX = "target_index";
private static final String TAG_TARGET_UUID = "target_uuid";
private static final String TAG_TARGET_NAME = "target_name";
private static final String TAG_TARGET_DEATHS = "target_deaths";
private static final String TAG_CHARGE = "charge";
public TotemItem(int durability) {
this(Rarity.COMMON, durability);
}
public TotemItem(Rarity rarity, int durability) {
super(new Properties().tab(TotemOfReviving.ITEM_GROUP).stacksTo(1).rarity(rarity).defaultDurability(durability));
}
public abstract boolean isCharge(ItemStack stack);
public static int getTargetIndex(ItemStack stack) {
if (!isTotem(stack)) { return -1; }
return stack.getOrCreateTag().getInt(TAG_TARGET_INDEX);
}
public static void setTargetIndex(ItemStack stack, int targetIndex) {
if (!isTotem(stack)) { return; }
stack.getOrCreateTag().putInt(TAG_TARGET_INDEX, targetIndex);
}
public static UUID getTargetUUID(ItemStack stack) {
if (!isTotem(stack)) { return null; }
try {
return UUID.fromString(stack.getOrCreateTag().getString(TAG_TARGET_UUID));
} catch (IllegalArgumentException exception) {
return null;
}
}
public static void setTargetUUID(ItemStack stack, UUID targetUUID) {
if (!isTotem(stack)) { return; }
stack.getOrCreateTag().putString(TAG_TARGET_UUID, targetUUID.toString());
}
public static String getTargetName(ItemStack stack) {
if (!isTotem(stack)) { return null; }
return stack.getOrCreateTag().getString(TAG_TARGET_NAME);
}
public static void setTargetName(ItemStack stack, String targetName) {
if (!isTotem(stack)) { return; }
stack.getOrCreateTag().putString(TAG_TARGET_NAME, targetName);
}
public static int getTargetCost(ItemStack stack) {
if (!isTotem(stack)) { return -1; }
return !isCostDynamic(stack) ? getConfig(stack).getChargeCost() :
(int)(getTargetDeaths(stack) * getConfig(stack).getChargeCostMultiplier());
}
public static int getTargetDeaths(ItemStack stack) {
if (!isTotem(stack)) { return -1; }
return stack.getOrCreateTag().getInt(TAG_TARGET_DEATHS);
}
public static void setTargetDeaths(ItemStack stack, ServerPlayer target) {
if (!isTotem(stack)) { return; }
stack.getOrCreateTag().putInt(TAG_TARGET_DEATHS, target.getStats().getValue(Stats.CUSTOM.get(Stats.DEATHS)));
}
public static boolean isTotemFull(ItemStack stack) {
if (!isTotem(stack)) { return false; }
return getCharge(stack) == getMaxCharge(stack);
}
public static boolean canTotemAffordTarget(ItemStack stack) {
if (!isTotem(stack)) { return false; }
if (getCharge(stack) < getTargetCost(stack)) {
if (!isTotemFull(stack)) {
return false;
}
return isTotemFull(stack) && canReviveMoreExpensiveTargets(stack);
}
return true;
}
public static int getCharge(ItemStack stack) {
if (!isTotem(stack)) { return -1; }
int charge = stack.getOrCreateTag().getInt(TAG_CHARGE);
int maxCharge = getMaxCharge(stack);
if (charge > maxCharge) {
charge = maxCharge;
setCharge(stack, charge);
}
return charge;
}
public static void setCharge(ItemStack stack, int charge) {
if (!isTotem(stack)) { return; }
stack.getOrCreateTag().putInt(TAG_CHARGE, charge);
}
public static int getMaxCharge(ItemStack stack) {
Config.TotemConfig config = getConfig(stack);
if (config == null) { return -1; }
if (config.getChargeCost() == -1) {
return config.getChargeCostLimit();
}
return config.getChargeCost();
}
public static boolean isCostDynamic(ItemStack stack) {
if (!isTotem(stack)) { return false; }
return getConfig(stack).getChargeCost() == -1;
}
public static boolean canReviveAcrossDimensions(ItemStack stack) {
if (!isTotem(stack)) { return false; }
return getConfig(stack).getCanReviveAcrossDimensions();
}
public static boolean canReviveMoreExpensiveTargets(ItemStack stack) {
if (!isTotem(stack)) { return false; }
return getConfig(stack).getCanReviveMoreExpensiveTargets();
}
public static boolean isEnabled(ItemStack stack) {
if (!isTotem(stack)) { return false; }
return getConfig(stack).getIsEnabled();
}
@Override
@OnlyIn(Dist.CLIENT)
@ParametersAreNonnullByDefault
public void appendHoverText(ItemStack stack, @Nullable Level world, List<Component> tooltip, TooltipFlag tooltipFlag) {
if (world == null) { return; }
UUID targetUUID = getTargetUUID(stack);
String targetName = getTargetName(stack);
int targetCost = getTargetCost(stack);
int charge = getCharge(stack);
int maxCharge = getMaxCharge(stack);
double multiplier = getConfig(stack).getChargeCostMultiplier();
if (getConfig(stack).getIsEnabled()) {
if (targetUUID == null) {
tooltip.add(new TextComponent(ChatFormatting.RED + "Target: " + ChatFormatting.DARK_RED + "NONE"));
} else {
tooltip.add(new TextComponent(ChatFormatting.WHITE + "Target: " + ChatFormatting.GRAY + targetName));
}
tooltip.add(new TextComponent(""));
if (!canTotemAffordTarget(stack)) {
tooltip.add(new TextComponent(ChatFormatting.RED + "Charges: " + ChatFormatting.DARK_RED + "(" + charge + "/" + targetCost + ") " +
ChatFormatting.RED + "[Max: " + ChatFormatting.DARK_RED + maxCharge + ChatFormatting.RED + "] [Multi: " + ChatFormatting.DARK_RED + multiplier + ChatFormatting.RED + "]"));
} else {
tooltip.add(new TextComponent(ChatFormatting.WHITE + "Charges: " + ChatFormatting.GRAY + "(" + charge + "/" + targetCost + ") " +
ChatFormatting.WHITE + "[Max: " + ChatFormatting.GRAY + maxCharge + ChatFormatting.WHITE + "] [Multi: " + ChatFormatting.GRAY + multiplier + ChatFormatting.WHITE + "]"));
}
if (canReviveMoreExpensiveTargets(stack)) {
tooltip.add(new TextComponent(ChatFormatting.WHITE + "Can revive more expensive targets."));
}
if (canReviveAcrossDimensions(stack)) {
tooltip.add(new TextComponent(ChatFormatting.WHITE + "Can revive targets across dimensions."));
}
tooltip.add(new TextComponent(""));
if (ModKeyMappings.ADVANCED_TOOLTIP.isDown()) {
tooltip.add(new TextComponent(ChatFormatting.GRAY + "Showing advanced tooltip."));
tooltip.add(new TextComponent(ChatFormatting.WHITE + "[" + ChatFormatting.GRAY + "R-CLICK" + ChatFormatting.WHITE + "]"));
tooltip.add(new TextComponent(ChatFormatting.WHITE + "When second hand is empty: revive target."));
tooltip.add(new TextComponent(ChatFormatting.WHITE + "When second hand is holding a reviving charge: charge totem."));
tooltip.add(new TextComponent(""));
tooltip.add(new TextComponent(ChatFormatting.WHITE + "[" + ChatFormatting.GRAY + "L-SHIFT + R-CLICK" + ChatFormatting.WHITE + "]"));
tooltip.add(new TextComponent(ChatFormatting.WHITE + "Change target."));
} else {
tooltip.add(new TextComponent(ChatFormatting.GRAY + "Hold [" + ChatFormatting.DARK_GRAY + "L-SHIFT" + ChatFormatting.GRAY + "] for advanced tooltip."));
}
} else {
tooltip.add(new TextComponent(ChatFormatting.RED + "Totem is disabled!"));
}
super.appendHoverText(stack, world, tooltip, tooltipFlag);
}
@Override
@OnlyIn(Dist.CLIENT)
@ParametersAreNonnullByDefault
public InteractionResultHolder<ItemStack> use(Level world, Player player, InteractionHand hand) {
if (!getConfig(player.getItemInHand(hand)).getIsEnabled() || !world.isClientSide) {
return super.use(world, player, hand);
}
ItemStack chargeItem = (hand.equals(InteractionHand.MAIN_HAND)) ? player.getOffhandItem() : player.getMainHandItem();
if (player.isCrouching()) {
Network.channel.sendToServer(new ChangeTargetPacket(hand));
} else {
if (isCharge(chargeItem)) {
Network.channel.sendToServer(new ChargeTotemPacket(hand));
} else {
Network.channel.sendToServer(new ReviveTargetPacket(hand));
}
}
return super.use(world, player, hand);
}
@Override
public int getMaxDamage(ItemStack stack) {
return getConfig(stack).getDurability();
}
@Override
public boolean isDamageable(ItemStack stack) {
return (getConfig(stack).getDurability() != 0);
}
@Override
public int getDamage(ItemStack stack) {
if (isDamageable(stack) && super.getDamage(stack) >= getMaxDamage(stack)) {
stack.setCount(0);
return getMaxDamage(stack);
}
return (isDamageable(stack)) ? super.getDamage(stack) : 0;
}
private static boolean isTotem(ItemStack stack) {
return (stack.getItem() instanceof TotemItem);
}
private static Config.TotemConfig getConfig(ItemStack stack) {
Item item = stack.getItem();
if (item instanceof StrawTotemItem) { return Config.Server.getStrawTotemConfig(); }
if (item instanceof IronTotemItem) { return Config.Server.getIronTotemConfig(); }
if (item instanceof DiamondTotemItem) { return Config.Server.getDiamondTotemConfig(); }
if (item instanceof NetheriteTotemItem) { return Config.Server.getNetheriteTotemConfig(); }
return null;
}
}

View File

@ -0,0 +1,55 @@
package dev.micle.totemofreviving.network;
import dev.micle.totemofreviving.TotemOfReviving;
import dev.micle.totemofreviving.item.totem.TotemItem;
import net.minecraft.ChatFormatting;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.players.PlayerList;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class ChangeTargetPacket {
private final InteractionHand hand;
public ChangeTargetPacket(final InteractionHand hand) {
this.hand = hand;
}
public static void encode(final ChangeTargetPacket packet, final FriendlyByteBuf buffer) {
Network.writeVersionInfo(buffer, false);
buffer.writeEnum(packet.hand);
}
public static ChangeTargetPacket decode(final FriendlyByteBuf buffer) {
Network.checkVersion(buffer);
return new ChangeTargetPacket(buffer.readEnum(InteractionHand.class));
}
public static void handle(final ChangeTargetPacket packet, final Supplier<NetworkEvent.Context> contextSupplier) {
final NetworkEvent.Context context = contextSupplier.get();
context.enqueueWork(() -> {
ServerPlayer sender = context.getSender();
if (sender == null) { return; }
ItemStack totemStack = sender.getItemInHand(packet.hand);
PlayerList playerList = TotemOfReviving.PROXY.getServer().getPlayerList();
int targetIndex = TotemItem.getTargetIndex(totemStack) + 1;
if (targetIndex > playerList.getPlayerCount()-1) { targetIndex = 0; }
ServerPlayer target = playerList.getPlayers().get(targetIndex);
TotemItem.setTargetIndex(totemStack, targetIndex);
TotemItem.setTargetUUID(totemStack, target.getUUID());
TotemItem.setTargetName(totemStack, target.getDisplayName().getString());
TotemItem.setTargetDeaths(totemStack, target);
sender.sendMessage(new TextComponent(ChatFormatting.WHITE + "Now targetting " + ChatFormatting.GRAY + target.getDisplayName().getString() + "."), sender.getUUID());
});
context.setPacketHandled(true);
}
}

View File

@ -0,0 +1,45 @@
package dev.micle.totemofreviving.network;
import dev.micle.totemofreviving.item.totem.TotemItem;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class ChargeTotemPacket {
private final InteractionHand hand;
public ChargeTotemPacket(final InteractionHand hand) {
this.hand = hand;
}
public static void encode(final ChargeTotemPacket packet, final FriendlyByteBuf buffer) {
Network.writeVersionInfo(buffer, false);
buffer.writeEnum(packet.hand);
}
public static ChargeTotemPacket decode(final FriendlyByteBuf buffer) {
Network.checkVersion(buffer);
return new ChargeTotemPacket(buffer.readEnum(InteractionHand.class));
}
public static void handle(final ChargeTotemPacket packet, final Supplier<NetworkEvent.Context> contextSupplier) {
final NetworkEvent.Context context = contextSupplier.get();
context.enqueueWork(() -> {
ServerPlayer sender = context.getSender();
if (sender == null) { return; }
ItemStack totemStack = (packet.hand.equals(InteractionHand.MAIN_HAND)) ? sender.getMainHandItem() : sender.getOffhandItem();
ItemStack chargeStack = (packet.hand.equals(InteractionHand.MAIN_HAND)) ? sender.getOffhandItem() : sender.getMainHandItem();
if (TotemItem.isTotemFull(totemStack)) { return; }
TotemItem.setCharge(totemStack, TotemItem.getCharge(totemStack) + 1);
chargeStack.setCount(chargeStack.getCount() - 1);
});
context.setPacketHandled(true);
}
}

View File

@ -0,0 +1,83 @@
package dev.micle.totemofreviving.network;
import dev.micle.totemofreviving.TotemOfReviving;
import dev.micle.totemofreviving.util.MismatchedVersionException;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.network.NetworkRegistry;
import net.minecraftforge.network.simple.SimpleChannel;
import java.util.Objects;
import java.util.regex.Pattern;
public class Network {
public static final String VERSION = TotemOfReviving.MOD_ID + "-net-1";
private static final Pattern NET_VERSION_PATTERN = Pattern.compile(TotemOfReviving.MOD_ID + "-net-\\d+$");
private static final Pattern MOD_VERSION_PATTERN = Pattern.compile("Forge-\\d+\\.\\d+\\.\\d+-\\d+\\.\\d+\\.\\d+$");
public static SimpleChannel channel;
public static void init() {
channel = NetworkRegistry.ChannelBuilder.named(TotemOfReviving.createResourceLocation("network"))
.clientAcceptedVersions(s -> Objects.equals(s, VERSION))
.serverAcceptedVersions(s -> Objects.equals(s, VERSION))
.networkProtocolVersion(() -> VERSION)
.simpleChannel();
int id = 0;
channel.messageBuilder(ChangeTargetPacket.class, id++)
.encoder(ChangeTargetPacket::encode)
.decoder(ChangeTargetPacket::decode)
.consumer(ChangeTargetPacket::handle)
.add();
channel.messageBuilder(ChargeTotemPacket.class, id++)
.encoder(ChargeTotemPacket::encode)
.decoder(ChargeTotemPacket::decode)
.consumer(ChargeTotemPacket::handle)
.add();
channel.messageBuilder(ReviveTargetPacket.class, id++)
.encoder(ReviveTargetPacket::encode)
.decoder(ReviveTargetPacket::decode)
.consumer(ReviveTargetPacket::handle)
.add();
}
public static void writeVersionInfo(FriendlyByteBuf buffer, boolean senderIsServer) {
buffer.writeBoolean(senderIsServer);
buffer.writeUtf(VERSION);
buffer.writeUtf(TotemOfReviving.getVersion());
}
public static void checkVersion(FriendlyByteBuf buffer) {
boolean senderIsServer = buffer.readBoolean();
String serverNetVersion = (senderIsServer) ? readNetVersion(buffer) : VERSION;
String serverModVersion = (senderIsServer) ? readModVersion(buffer) : TotemOfReviving.getVersion();
String clientNetVersion = (senderIsServer) ? VERSION : readNetVersion(buffer);
String clientModVersion = (senderIsServer) ? TotemOfReviving.getVersion() : readModVersion(buffer);
if (!serverNetVersion.equals(clientNetVersion)) {
throw new MismatchedVersionException(
String.format("The server and client are running different versions of [Micle's Totem of Reviving]. " +
"Try updating this mod on either the client and or the server. " +
"Client version is %s (%s). Server version is %s (%s)",
clientModVersion, clientNetVersion,
serverModVersion, serverNetVersion)
);
}
}
public static String readNetVersion(FriendlyByteBuf buffer) {
String netVersion = buffer.readUtf();
if (!NET_VERSION_PATTERN.matcher(netVersion).matches()) {
return "UNKNOWN (" + netVersion + ")";
}
return netVersion;
}
public static String readModVersion(FriendlyByteBuf buffer) {
String modVersion = buffer.readUtf();
if (!modVersion.equals("NONE") && !MOD_VERSION_PATTERN.matcher(modVersion).matches()) {
return "UNKNOWN (" + modVersion + ")";
}
return modVersion;
}
}

View File

@ -0,0 +1,73 @@
package dev.micle.totemofreviving.network;
import dev.micle.totemofreviving.TotemOfReviving;
import dev.micle.totemofreviving.item.totem.TotemItem;
import net.minecraft.ChatFormatting;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent;
import java.util.function.Supplier;
public class ReviveTargetPacket {
private final InteractionHand hand;
public ReviveTargetPacket(final InteractionHand hand) {
this.hand = hand;
}
public static void encode(final ReviveTargetPacket packet, final FriendlyByteBuf buffer) {
Network.writeVersionInfo(buffer, false);
buffer.writeEnum(packet.hand);
}
public static ReviveTargetPacket decode(final FriendlyByteBuf buffer) {
Network.checkVersion(buffer);
return new ReviveTargetPacket(buffer.readEnum(InteractionHand.class));
}
public static void handle(final ReviveTargetPacket packet, final Supplier<NetworkEvent.Context> contextSupplier) {
final NetworkEvent.Context context = contextSupplier.get();
context.enqueueWork(() -> {
ServerPlayer sender = context.getSender();
if (sender == null) { return; }
ItemStack totemStack = sender.getItemInHand(packet.hand);
ServerPlayer target;
try {
target = TotemOfReviving.PROXY.getServer().getPlayerList().getPlayer(TotemItem.getTargetUUID(totemStack));
if (target == null) { throw new NullPointerException("Target is null!"); }
} catch (NullPointerException exception) {
sender.sendMessage(new TextComponent(ChatFormatting.WHITE + "Unable to find player!"), sender.getUUID());
return;
}
if (!target.isSpectator()) {
sender.sendMessage(new TextComponent(ChatFormatting.GRAY + target.getDisplayName().getString() + ChatFormatting.WHITE + " is not dead!"), sender.getUUID());
return;
}
if (!target.getLevel().equals(sender.getLevel()) && !TotemItem.canReviveAcrossDimensions(totemStack)) {
sender.sendMessage(new TextComponent(ChatFormatting.GRAY + target.getDisplayName().getString() + ChatFormatting.WHITE + " is in a different dimension!"), sender.getUUID());
return;
}
TotemItem.setTargetDeaths(totemStack, target);
if (!TotemItem.canTotemAffordTarget(totemStack)) {
sender.sendMessage(new TextComponent(ChatFormatting.WHITE + "Not enough charge!"), sender.getUUID());
return;
}
target.teleportTo(sender.getLevel(), sender.position().x, sender.position().y, sender.position().z, sender.getYRot(), sender.getXRot());
target.setGameMode(sender.getLevel().getServer().getDefaultGameType());
TotemItem.setCharge(totemStack, TotemItem.getCharge(totemStack) - TotemItem.getTargetCost(totemStack));
totemStack.hurtAndBreak(1, sender, e -> e.broadcastBreakEvent(packet.hand));
sender.sendMessage(new TextComponent(ChatFormatting.WHITE + "Successfully revived " + ChatFormatting.GRAY + target.getDisplayName().getString() + "!"), sender.getUUID());
});
context.setPacketHandled(true);
}
}

View File

@ -0,0 +1,26 @@
package dev.micle.totemofreviving.setup;
import dev.micle.totemofreviving.item.charge.DiamondChargeItem;
import dev.micle.totemofreviving.item.charge.IronChargeItem;
import dev.micle.totemofreviving.item.charge.NetheriteChargeItem;
import dev.micle.totemofreviving.item.charge.StrawChargeItem;
import dev.micle.totemofreviving.item.totem.DiamondTotemItem;
import dev.micle.totemofreviving.item.totem.IronTotemItem;
import dev.micle.totemofreviving.item.totem.NetheriteTotemItem;
import dev.micle.totemofreviving.item.totem.StrawTotemItem;
import net.minecraft.world.item.Item;
import net.minecraftforge.registries.RegistryObject;
public class ModItems {
public static RegistryObject<Item> STRAW_TOTEM = Registration.ITEMS.register(StrawTotemItem.getName(), StrawTotemItem::new);
public static RegistryObject<Item> IRON_TOTEM = Registration.ITEMS.register(IronTotemItem.getName(), IronTotemItem::new);
public static RegistryObject<Item> DIAMOND_TOTEM = Registration.ITEMS.register(DiamondTotemItem.getName(), DiamondTotemItem::new);
public static RegistryObject<Item> NETHERITE_TOTEM = Registration.ITEMS.register(NetheriteTotemItem.getName(), NetheriteTotemItem::new);
public static RegistryObject<Item> STRAW_CHARGE = Registration.ITEMS.register(StrawChargeItem.getName(), StrawChargeItem::new);
public static RegistryObject<Item> IRON_CHARGE = Registration.ITEMS.register(IronChargeItem.getName(), IronChargeItem::new);
public static RegistryObject<Item> DIAMOND_CHARGE = Registration.ITEMS.register(DiamondChargeItem.getName(), DiamondChargeItem::new);
public static RegistryObject<Item> NETHERITE_CHARGE = Registration.ITEMS.register(NetheriteChargeItem.getName(), NetheriteChargeItem::new);
public static void register() {}
}

View File

@ -0,0 +1,9 @@
package dev.micle.totemofreviving.setup;
import com.mojang.blaze3d.platform.InputConstants;
import net.minecraft.client.KeyMapping;
public class ModKeyMappings {
public static final KeyMapping ADVANCED_TOOLTIP =
new KeyMapping("advanced_tooltip", InputConstants.KEY_LSHIFT, KeyMapping.CATEGORY_INVENTORY);
}

View File

@ -0,0 +1,16 @@
package dev.micle.totemofreviving.setup;
import dev.micle.totemofreviving.item.crafting.ChargeRecipe;
import dev.micle.totemofreviving.item.crafting.ExtendedShapedRecipe;
import dev.micle.totemofreviving.item.crafting.TotemRecipe;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraftforge.registries.RegistryObject;
public class ModRecipes {
public static final RegistryObject<RecipeSerializer<?>> TOTEM_RECIPE =
Registration.RECIPE_SERIALIZERS.register("totem_recipe", () -> ExtendedShapedRecipe.Serializer.basic(TotemRecipe::new));
public static final RegistryObject<RecipeSerializer<?>> CHARGE_RECIPE =
Registration.RECIPE_SERIALIZERS.register("charge_recipe", () -> ExtendedShapedRecipe.Serializer.basic(ChargeRecipe::new));
public static void register() {}
}

View File

@ -0,0 +1,30 @@
package dev.micle.totemofreviving.setup;
import dev.micle.totemofreviving.TotemOfReviving;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.crafting.RecipeSerializer;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.IForgeRegistryEntry;
public class Registration {
public static final DeferredRegister<Item> ITEMS = create(ForgeRegistries.ITEMS);
public static final DeferredRegister<RecipeSerializer<?>> RECIPE_SERIALIZERS = create(ForgeRegistries.RECIPE_SERIALIZERS);
public static void register() {
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
ITEMS.register(modEventBus);
ModItems.register();
RECIPE_SERIALIZERS.register(modEventBus);
ModRecipes.register();
}
private static <T extends IForgeRegistryEntry<T>> DeferredRegister<T> create(IForgeRegistry<T> registry) {
return DeferredRegister.create(registry, TotemOfReviving.MOD_ID);
}
}

View File

@ -0,0 +1,7 @@
package dev.micle.totemofreviving.util;
public class MismatchedVersionException extends RuntimeException {
public MismatchedVersionException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,11 @@
{
"itemGroup.totemofreviving": "Micle's Totem of Reviving",
"item.totemofreviving.straw_totem": "Straw totem of reviving",
"item.totemofreviving.iron_totem": "Iron totem of reviving",
"item.totemofreviving.diamond_totem": "Diamond totem of reviving",
"item.totemofreviving.netherite_totem": "Netherite totem of reviving",
"item.totemofreviving.straw_charge": "Straw reviving charge",
"item.totemofreviving.iron_charge": "Iron reviving charge",
"item.totemofreviving.diamond_charge": "Diamond reviving charge",
"item.totemofreviving.netherite_charge": "Netherite reviving charge"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 287 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 826 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 741 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 836 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB