package com.thebrokenrail.sorcerycraft; import com.thebrokenrail.sorcerycraft.advancement.CreateSpellCriterion; import com.thebrokenrail.sorcerycraft.advancement.DiscoverAllSpellsCriterion; import com.thebrokenrail.sorcerycraft.block.CastingTableBlock; import com.thebrokenrail.sorcerycraft.command.SpellCommand; import com.thebrokenrail.sorcerycraft.entity.SpellEntity; import com.thebrokenrail.sorcerycraft.item.SpellItem; import com.thebrokenrail.sorcerycraft.mixin.CriterionRegistryHook; import com.thebrokenrail.sorcerycraft.packet.SelectSpellC2SPacket; import com.thebrokenrail.sorcerycraft.spell.util.RandomSpellLootTableFunction; import com.thebrokenrail.sorcerycraft.spell.api.registry.Spells; import me.sargunvohra.mcmods.autoconfig1u.AutoConfig; import me.sargunvohra.mcmods.autoconfig1u.serializer.GsonConfigSerializer; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder; import net.fabricmc.fabric.api.container.ContainerProviderRegistry; import net.fabricmc.fabric.api.entity.FabricEntityTypeBuilder; import net.fabricmc.fabric.api.loot.v1.FabricLootPoolBuilder; import net.fabricmc.fabric.api.loot.v1.event.LootTableLoadingCallback; import net.fabricmc.fabric.api.registry.CommandRegistry; import net.fabricmc.fabric.impl.networking.ServerSidePacketRegistryImpl; import net.minecraft.block.DispenserBlock; import net.minecraft.block.dispenser.ProjectileDispenserBehavior; import net.minecraft.entity.EntityCategory; import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.EntityType; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.ProjectileEntity; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; import net.minecraft.loot.BinomialLootTableRange; import net.minecraft.loot.LootTables; import net.minecraft.loot.entry.ItemEntry; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvent; import net.minecraft.sound.SoundEvents; import net.minecraft.stat.StatFormatter; import net.minecraft.stat.Stats; import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPointer; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Position; import net.minecraft.util.registry.Registry; import net.minecraft.world.World; import java.util.Objects; public class SorceryCraft implements ModInitializer { public static final String NAMESPACE = "sorcerycraft"; public static SpellItem SPELL_ITEM; public static CastingTableBlock CASTING_TABLE_BLOCK; public static BlockItem CASTING_TABLE_BLOCK_ITEM; public static ItemGroup ITEM_GROUP; public static EntityType SPELL_ENTITY; public static final Identifier[] LOOT_TABLES = new Identifier[]{ LootTables.SIMPLE_DUNGEON_CHEST, LootTables.END_CITY_TREASURE_CHEST, LootTables.NETHER_BRIDGE_CHEST, LootTables.ABANDONED_MINESHAFT_CHEST, LootTables.SHIPWRECK_TREASURE_CHEST, LootTables.DESERT_PYRAMID_CHEST, LootTables.JUNGLE_TEMPLE_CHEST, LootTables.STRONGHOLD_LIBRARY_CHEST, LootTables.PILLAGER_OUTPOST_CHEST, LootTables.WOODLAND_MANSION_CHEST, LootTables.BURIED_TREASURE_CHEST, LootTables.FISHING_TREASURE_GAMEPLAY }; public static Identifier INTERACT_WITH_CASTING_TABLE_STAT; public static Identifier CAST_SPELL_STAT; public static DiscoverAllSpellsCriterion DISCOVER_ALL_SPELLS_CRITERION; public static CreateSpellCriterion CREATE_SPELL_CRITERION; public static ModConfig getConfig() { return AutoConfig.getConfigHolder(ModConfig.class).getConfig(); } private boolean isSelectedLootTable(Identifier lootTable) { for (Identifier id : LOOT_TABLES) { if (id.equals(lootTable)) { return true; } } return false; } @Override public void onInitialize() { new Spells(); AutoConfig.register(ModConfig.class, GsonConfigSerializer::new); ITEM_GROUP = FabricItemGroupBuilder.create( new Identifier(NAMESPACE, "spells")) .icon(() -> new ItemStack(SPELL_ITEM)) .build(); CASTING_TABLE_BLOCK = new CastingTableBlock(); CASTING_TABLE_BLOCK_ITEM = new BlockItem(CASTING_TABLE_BLOCK, new Item.Settings().group(ITEM_GROUP)); SPELL_ITEM = new SpellItem(); SPELL_ENTITY = FabricEntityTypeBuilder.create(EntityCategory.MISC, (EntityType.EntityFactory) SpellEntity::new).size(EntityDimensions.fixed(0.25f, 0.25f)).build(); Registry.register(Registry.ITEM, new Identifier(NAMESPACE, "spell"), SPELL_ITEM); Registry.register(Registry.BLOCK, new Identifier(NAMESPACE, "casting_table"), CASTING_TABLE_BLOCK); Registry.register(Registry.ITEM, new Identifier(NAMESPACE, "casting_table"), CASTING_TABLE_BLOCK_ITEM); Registry.register(Registry.ENTITY_TYPE, new Identifier(NAMESPACE, "spell"), SPELL_ENTITY); ContainerProviderRegistry.INSTANCE.registerFactory(new Identifier(NAMESPACE, "casting_table"), (syncId, identifier, player, buf) -> { final World world = player.world; final BlockPos pos = buf.readBlockPos(); return Objects.requireNonNull(world.getBlockState(pos).createScreenHandlerFactory(player.world, pos)).createMenu(syncId, player.inventory, player); }); CommandRegistry.INSTANCE.register(false, SpellCommand::register); ServerSidePacketRegistryImpl.INSTANCE.register(new Identifier(NAMESPACE, "select_spell"), SelectSpellC2SPacket::handle); LootTableLoadingCallback.EVENT.register((resourceManager, lootManager, id, supplier, setter) -> { if (isSelectedLootTable(id)) { FabricLootPoolBuilder poolBuilder = FabricLootPoolBuilder.builder() .withRolls(new BinomialLootTableRange(2, 0.5f)) .withEntry(ItemEntry.builder(SPELL_ITEM)) .withFunction(new RandomSpellLootTableFunction.Builder()); supplier.withPool(poolBuilder); } }); DispenserBlock.registerBehavior(SorceryCraft.SPELL_ITEM, new ProjectileDispenserBehavior() { @Override protected ProjectileEntity createProjectile(World position, Position stack, ItemStack itemStack) { SpellEntity entity = new SpellEntity(position, stack.getX(), stack.getY(), stack.getZ()); entity.setItem(itemStack); return entity; } @Override protected void playSound(BlockPointer pointer) { playSpellSound(pointer); } }); INTERACT_WITH_CASTING_TABLE_STAT = registerStat("interact_with_casting_table"); CAST_SPELL_STAT = registerStat("cast_spell"); DISCOVER_ALL_SPELLS_CRITERION = CriterionRegistryHook.callRegister(new DiscoverAllSpellsCriterion()); CREATE_SPELL_CRITERION = CriterionRegistryHook.callRegister(new CreateSpellCriterion()); } private Identifier registerStat(String name) { Identifier statID = new Identifier(NAMESPACE, name); Registry.register(Registry.CUSTOM_STAT, name, statID); Stats.CUSTOM.getOrCreateStat(statID, StatFormatter.DEFAULT); return statID; } private static final SoundEvent SPELL_SOUND_EFFECT = SoundEvents.BLOCK_ENCHANTMENT_TABLE_USE; public static void playSpellSound(World world, BlockPos pos) { world.playSound(null, pos, SPELL_SOUND_EFFECT, SoundCategory.BLOCKS, 1.0f, 1.0f); } public static void playSpellSound(BlockPointer block) { playSpellSound(block.getWorld(), block.getBlockPos()); } public static void playSpellSound(PlayerEntity player) { player.playSound(SPELL_SOUND_EFFECT, SoundCategory.PLAYERS, 1.0f, 1.0f); } }