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 af2f878b35
commit 4b9a025e3c
63 changed files with 2088 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.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.