Re-implemented the crafting interface for spellbooks

This commit is contained in:
Sollace 2019-01-10 19:46:40 +02:00
parent b3e689d220
commit 1f433bf497
23 changed files with 1197 additions and 6 deletions

View file

@ -33,11 +33,13 @@ import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.item.crafting.ShapedRecipes;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.registries.IForgeRegistry;
import static com.minelittlepony.unicopia.Predicates.*;
import com.minelittlepony.unicopia.forgebullshit.BuildInTexturesBakery;
import com.minelittlepony.unicopia.forgebullshit.RegistryLockSpinner;
public class UItems {
@ -153,6 +155,8 @@ public class UItems {
registerAllVariants(tomato, "tomato", "rotten_tomato");
registerAllVariants(cloudsdale_tomato, "cloudsdale_tomato", "rotten_cloudsdale_tomato");
registerAllVariants(tomato_seeds, "tomato_seeds");
BuildInTexturesBakery.getBuiltInTextures().add(new ResourceLocation("unicopia", "items/empty_slot_gem"));
}
registerFuels();

View file

@ -29,16 +29,23 @@ import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.eventhandler.Event.Result;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
import net.minecraftforge.fml.common.network.IGuiHandler;
import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.registry.EntityEntry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import java.util.Map;
import java.util.function.Function;
import com.google.gson.JsonObject;
import com.minelittlepony.jumpingcastle.api.IChannel;
import com.minelittlepony.jumpingcastle.api.JumpingCastle;
import com.minelittlepony.jumpingcastle.api.Target;
@ -48,15 +55,19 @@ import com.minelittlepony.unicopia.client.particle.EntityMagicFX;
import com.minelittlepony.unicopia.client.particle.EntityRaindropFX;
import com.minelittlepony.unicopia.client.particle.Particles;
import com.minelittlepony.unicopia.command.Commands;
import com.minelittlepony.unicopia.enchanting.SpellRecipe;
import com.minelittlepony.unicopia.forgebullshit.FBS;
import com.minelittlepony.unicopia.hud.UHud;
import com.minelittlepony.unicopia.input.Keyboard;
import com.minelittlepony.unicopia.inventory.gui.ContainerSpellBook;
import com.minelittlepony.unicopia.inventory.gui.GuiSpellBook;
import com.minelittlepony.unicopia.network.MsgPlayerAbility;
import com.minelittlepony.unicopia.network.MsgPlayerCapabilities;
import com.minelittlepony.unicopia.network.MsgRequestCapabilities;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import com.minelittlepony.unicopia.power.PowersRegistry;
import com.minelittlepony.unicopia.util.crafting.CraftingManager;
import com.minelittlepony.pony.data.IPony;
@Mod(
@ -66,7 +77,7 @@ import com.minelittlepony.pony.data.IPony;
dependencies = "required-after:jumpingcastle"
)
@EventBusSubscriber
public class Unicopia {
public class Unicopia implements IGuiHandler {
public static final String MODID = "unicopia";
public static final String NAME = "@NAME@";
public static final String VERSION = "@VERSION@";
@ -86,6 +97,8 @@ public class Unicopia {
*/
private static Race clientPlayerRace = getclientPlayerRace();
private static CraftingManager craftingManager;
@EventHandler
public void preInit(FMLPreInitializationEvent event) {
if (UClient.isClientSide()) {
@ -117,6 +130,24 @@ public class Unicopia {
UAdvancements.init();
FBS.init();
NetworkRegistry.INSTANCE.registerGuiHandler(this, this);
}
@EventHandler
public void posInit(FMLPostInitializationEvent event) {
craftingManager = new CraftingManager(MODID, "enchanting") {
@Override
protected void registerRecipeTypes(Map<String, Function<JsonObject, IRecipe>> types) {
super.registerRecipeTypes(types);
types.put("unicopia:crafting_spell", SpellRecipe::deserialize);
}
};
}
public static CraftingManager getCraftingManager() {
return craftingManager;
}
@SubscribeEvent
@ -295,4 +326,20 @@ public class Unicopia {
event.setNewfov(fov);
}
@Override
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
switch (ID) {
case 0: return new ContainerSpellBook(player.inventory, world, new BlockPos(x, y, z));
default: return null;
}
}
@Override
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
switch (ID) {
case 0: return new GuiSpellBook(player);
default: return null;
}
}
}

View file

@ -0,0 +1,32 @@
package com.minelittlepony.unicopia.enchanting;
import com.minelittlepony.unicopia.UItems;
import com.minelittlepony.unicopia.enchanting.PagesList.IPageEvent;
import com.minelittlepony.unicopia.spell.SpellRegistry;
import net.minecraft.item.ItemStack;
/**
* A basic event for unlocking a page when a gem is crafted for the given spell
*/
public class BasicCraftingEvent implements IPageEvent {
private final String matched;
private final int pageIndex;
public BasicCraftingEvent(int page, String effectName) {
matched = effectName;
pageIndex = page;
}
@Override
public boolean matches(IPageOwner prop, ItemStack stack) {
return stack.getItem() == UItems.spell && SpellRegistry.getKeyFromStack(stack).equals(matched);
}
@Override
public int getPage(int stackSize) {
return pageIndex;
}
}

View file

@ -0,0 +1,32 @@
package com.minelittlepony.unicopia.enchanting;
import java.util.List;
import javax.annotation.Nonnull;
import com.minelittlepony.unicopia.network.ITransmittable;
public interface IPageOwner extends ITransmittable {
@Nonnull
List<Integer> getUnlockedPages();
default boolean hasPageUnlock(int pageIndex) {
return getUnlockedPages().contains(pageIndex);
}
default boolean unlockPage(int pageIndex) {
if (!hasPageUnlock(pageIndex)) {
if (getUnlockedPages().add(pageIndex)) {
sendCapabilities(true);
return true;
}
}
return false;
}
default boolean hasUnlockedPages() {
return getUnlockedPages().size() > 0;
}
}

View file

@ -0,0 +1,5 @@
package com.minelittlepony.unicopia.enchanting;
public interface IPageUnlockListener {
public void onPageUnlocked();
}

View file

@ -0,0 +1,41 @@
package com.minelittlepony.unicopia.enchanting;
import com.minelittlepony.unicopia.enchanting.PagesList.IPageEvent;
import net.minecraft.item.ItemStack;
/**
* An unlock event that requires other pages to be unlocked before it too can be unlocked.
*
*/
public class MultiPageUnlockEvent implements IPageEvent {
private final int pageIndex;
private final int[][] otherPageIndeces;
public MultiPageUnlockEvent(int page, int[]... otherPages) {
pageIndex = page;
otherPageIndeces = otherPages;
}
@Override
public boolean matches(IPageOwner prop, ItemStack stack) {
for (int i = 0; i < otherPageIndeces.length; i++) {
if (!checkPageUnlockSet(prop, otherPageIndeces[i])) return false;
}
return true;
}
private boolean checkPageUnlockSet(IPageOwner prop, int[] pages) {
for (int i = 0; i < pages.length; i++) {
if (prop.hasPageUnlock(pages[i])) return true;
}
return false;
}
@Override
public int getPage(int stackSize) {
return pageIndex;
}
}

View file

@ -0,0 +1,117 @@
package com.minelittlepony.unicopia.enchanting;
import java.util.ArrayList;
import java.util.List;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
public class PagesList {
private static final List<Integer> unreadPages = new ArrayList<Integer>();
private static final List<IPageEvent> pageEvents = new ArrayList<IPageEvent>();
private static int totalPages = 0;
/**
* Sets the maximum number of pages displayed in the spellbook.
* Only allows widening. Total pages cannot be reduced.
*/
public static void setTotalPages(int pages) {
if (pages > totalPages) {
totalPages = pages;
}
}
public static int getTotalPages() {
return totalPages;
}
/**
* Registers an event for unlocking a page.
*/
public static void registerPageEvent(IPageEvent event) {
pageEvents.add(event);
}
/**
* Marks a page as read
*/
public static void readPage(int pageIndex) {
unreadPages.remove(Integer.valueOf(pageIndex));
}
/**
* Checks if there are any pages after the given index that are unread
* Only useful on the client
*/
public static boolean hasUnreadPagesAfter(int pageIndex) {
for (Integer i : unreadPages) {
if (i > pageIndex) return true;
}
return false;
}
/**
* Checks if there are any pages before the given index that are unread
* Only useful on the client
*/
public static boolean hasUnreadPagesBefore(int pageIndex) {
for (Integer i : unreadPages) {
if (i < pageIndex) return true;
}
return false;
}
/**
* Checks if the given page has been read yet.
* Only of use on the client
*/
public static boolean isPageUnread(int pageIndex) {
return unreadPages.contains(pageIndex);
}
private static boolean unlockPages(IPageOwner prop, ItemStack stack) {
boolean result = false;
if (stack != null && stack.getCount() > 0) {
for (IPageEvent i : pageEvents) {
if (i.matches(prop, stack)) {
int page = i.getPage(stack.getCount());
if (page >= 0 && prop.unlockPage(page)) {
result |= unreadPages.add(page);
}
}
}
}
return result;
}
/**
* Checks for, and unlocks any pages that can be unlocked by the given item for the given player
* @return True if a page was unlocked, false otherwise
*/
public static boolean unlockPage(EntityPlayer player, ItemStack stack) {
return unlockPages(PlayerSpeciesList.instance().getPlayer(player), stack);
}
/**
* A PageEvent for determining when certain pages must be unlocked.
*
*/
public static interface IPageEvent {
/**
* Checks if this event's conditions are met.
* @param prop PlayerExtension for the player doing the crafting
* @param stack ItemStack crafted
*/
public boolean matches(IPageOwner prop, ItemStack stack);
/**
* Gets the page number corresponding to the given stack for this event
*/
public int getPage(int stackSize);
}
}

View file

@ -0,0 +1,142 @@
package com.minelittlepony.unicopia.enchanting;
import java.util.ArrayList;
import com.google.common.collect.Lists;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.minelittlepony.unicopia.UItems;
import com.minelittlepony.unicopia.inventory.InventorySpellBook;
import com.minelittlepony.unicopia.spell.SpellRegistry;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.util.NonNullList;
import net.minecraft.world.World;
import net.minecraftforge.registries.IForgeRegistryEntry.Impl;
public class SpellRecipe extends Impl<IRecipe> implements IRecipe {
private String spellId;
private final NonNullList<RecipeItem> ingredients;
public static IRecipe deserialize(JsonObject json) {
NonNullList<RecipeItem> ingredients = NonNullList.create();
for (JsonElement i : json.get("ingredients").getAsJsonArray()) {
JsonObject o = i.getAsJsonObject();
Item item = Item.getByNameOrId(o.get("item").getAsString());
if (item != null) {
int metadata = Math.max(0, o.has("data") ? o.get("data").getAsInt() : 0);
int size = Math.max(1, o.has("count") ? o.get("count").getAsInt() : 1);
ingredients.add(new RecipeItem(new ItemStack(item, size, metadata), !o.has("data")));
}
}
json = json.get("result").getAsJsonObject();
String spellId = json.get("spell").getAsString();
return new SpellRecipe(spellId, ingredients);
}
public SpellRecipe(String spellName, NonNullList<RecipeItem> ingredients) {
spellId = spellName;
this.ingredients = ingredients;
}
@Override
public boolean matches(InventoryCrafting inv, World worldIn) {
ItemStack enchantedStack = ((InventorySpellBook)inv).getCraftResultMatrix().getStackInSlot(0);
if (enchantedStack.isEmpty()) {
return false;
}
int materialMult = enchantedStack.getCount();
ArrayList<RecipeItem> toMatch = Lists.newArrayList(ingredients);
for (int i = 0; i < inv.getSizeInventory(); i++) {
ItemStack stack = inv.getStackInSlot(i);
if (!stack.isEmpty()) {
if (toMatch.isEmpty() && !stack.isEmpty()) {
return false;
}
if (!toMatch.isEmpty() && !toMatch.removeIf(s -> s.matches(stack, materialMult))) {
return false;
}
}
}
return toMatch.isEmpty();
}
@Override
public ItemStack getCraftingResult(InventoryCrafting inv) {
return getRecipeOutput();
}
@Override
public boolean canFit(int width, int height) {
return width * height < ingredients.size();
}
@Override
public ItemStack getRecipeOutput() {
return SpellRegistry.instance().enchantStack(new ItemStack(UItems.spell, 1), spellId);
}
@Override
public NonNullList<ItemStack> getRemainingItems(InventoryCrafting inv) {
NonNullList<ItemStack> remainers = NonNullList.<ItemStack>withSize(inv.getSizeInventory(), ItemStack.EMPTY);
for (int i = 0; i < remainers.size(); i++) {
ItemStack stack = inv.getStackInSlot(i);
if (stack != null && stack.getItem().hasContainerItem(stack)) {
remainers.set(i, new ItemStack(stack.getItem().getContainerItem()));
}
}
return remainers;
}
private static class RecipeItem {
private final ItemStack contained;
private final boolean ignoreMeta;
RecipeItem(ItemStack stack, boolean meta) {
contained = stack;
ignoreMeta = meta;
}
boolean matches(ItemStack other, int materialMult) {
if (other.isEmpty() != contained.isEmpty()) {
return false;
} else if (other.isEmpty()) {
return true;
}
if (other.isEmpty()) {
return false;
}
if (contained.getItem() == other.getItem()
&& (ignoreMeta || other.getMetadata() == contained.getMetadata())) {
return other.getCount() >= (materialMult * contained.getCount());
}
return false;
}
}
}

View file

@ -2,10 +2,12 @@ package com.minelittlepony.unicopia.entity;
import com.minelittlepony.unicopia.Predicates;
import com.minelittlepony.unicopia.UItems;
import com.minelittlepony.unicopia.Unicopia;
import net.minecraft.block.SoundType;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.datasync.DataParameter;
@ -130,7 +132,10 @@ public class EntitySpellbook extends EntityLiving implements IMagicals {
}
if (Predicates.MAGI.test(player)) {
//ApiGui.openContainer((EntityPlayerMP)player, new InterfaceBook());
player.playSound(SoundEvents.BLOCK_FURNACE_FIRE_CRACKLE, 2, 1);
player.openGui(Unicopia.MODID, 0, world, (int)posX, (int)posY, (int)posZ);
return EnumActionResult.SUCCESS;
}

View file

@ -0,0 +1,17 @@
package com.minelittlepony.unicopia.forgebullshit;
import java.util.Set;
import net.minecraft.client.renderer.block.model.ModelBakery;
import net.minecraft.util.ResourceLocation;
public final class BuildInTexturesBakery extends ModelBakery {
private BuildInTexturesBakery() {
super(null, null, null);
}
public static Set<ResourceLocation> getBuiltInTextures() {
return LOCATIONS_BUILTIN_TEXTURES;
}
}

View file

@ -0,0 +1,19 @@
package com.minelittlepony.unicopia.inventory;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryCrafting;
public class InventorySpellBook extends InventoryCrafting {
private final IInventory craftResult;
public InventorySpellBook(IInventory resultMatrix, Container eventHandler, int width, int height) {
super(eventHandler, width, height);
craftResult = resultMatrix;
}
public IInventory getCraftResultMatrix() {
return craftResult;
}
}

View file

@ -0,0 +1,149 @@
package com.minelittlepony.unicopia.inventory.gui;
import javax.annotation.Nonnull;
import com.minelittlepony.unicopia.Predicates;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.enchanting.IPageUnlockListener;
import com.minelittlepony.unicopia.inventory.InventorySpellBook;
import com.minelittlepony.unicopia.inventory.slot.SlotEnchanting;
import com.minelittlepony.unicopia.inventory.slot.SlotEnchantingResult;
import com.minelittlepony.unicopia.item.ItemSpell;
import com.minelittlepony.unicopia.spell.SpellRegistry;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryBasic;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class ContainerSpellBook extends Container {
private final World worldObj;
private IInventory craftResult = new InventoryBasic("Spell Result", false, 1);
private InventorySpellBook craftMatrix = new InventorySpellBook(craftResult, this, 5, 1);
private IPageUnlockListener listener;
private SlotEnchantingResult resultSlot = null;
private final EntityPlayer player;
public ContainerSpellBook(InventoryPlayer inventory, World world, BlockPos pos) {
super();
worldObj = world;
player = inventory.player;
initCraftingSlots();
for (int i = 0; i < 9; ++i) {
addSlotToContainer(new Slot(inventory, i, 121 + i * 18, 195));
}
onCraftMatrixChanged(craftMatrix);
}
public void setListener(IPageUnlockListener listener) {
this.listener = listener;
if (resultSlot != null) {
resultSlot.setListener(listener);
}
}
public void initCraftingSlots() {
addSlotToContainer(new SlotEnchanting(craftMatrix, 0, 180, 50));
addSlotToContainer(new SlotEnchanting(craftMatrix, 1, 154, 94));
addSlotToContainer(new SlotEnchanting(craftMatrix, 2, 180, 134));
addSlotToContainer(new SlotEnchanting(craftMatrix, 3, 231, 120));
addSlotToContainer(new SlotEnchanting(craftMatrix, 4, 232, 65));
addSlotToContainer(resultSlot = new SlotEnchantingResult(listener, player, craftMatrix, craftResult, 0, 196, 92));
}
@Override
public void onCraftMatrixChanged(IInventory inventoryIn) {
ItemStack current = craftResult.getStackInSlot(0);
if (!current.isEmpty()) {
ItemStack crafted = Unicopia.getCraftingManager().findMatchingResult(craftMatrix, worldObj);
if (!crafted.isEmpty()) {
current = SpellRegistry.instance().enchantStack(current, crafted);
player.playSound(SoundEvents.BLOCK_NOTE_CHIME, 1, 1);
} else {
current = SpellRegistry.instance().disenchantStack(current);
player.playSound(SoundEvents.BLOCK_NOTE_BASS, 1, 1);
}
craftResult.setInventorySlotContents(0, current);
}
}
@Nonnull
@Override
public ItemStack transferStackInSlot(EntityPlayer playerIn, int index) {
ItemStack stack = ItemStack.EMPTY;
Slot slot = inventorySlots.get(index);
if (slot != null && slot.getHasStack()) {
ItemStack slotStack = slot.getStack();
stack = slotStack.copy();
if (index > 5) {
if (stack.getItem() instanceof ItemSpell) {
if (!mergeItemStack(slotStack, 5, 6, false)) {
return ItemStack.EMPTY;
}
} else if (!mergeItemStack(slotStack, 0, 5, false)) {
return ItemStack.EMPTY;
}
} else {
if (!mergeItemStack(slotStack, 6, 15, false)) {
return ItemStack.EMPTY;
}
slot.onSlotChange(slotStack, stack);
onCraftMatrixChanged(craftMatrix);
}
if (slotStack.getCount() == stack.getCount()) {
return ItemStack.EMPTY;
}
slot.onTake(playerIn, slotStack);
}
return stack;
}
@Override
public void onContainerClosed(EntityPlayer player) {
super.onContainerClosed(player);
for (int i = 0; i < craftMatrix.getSizeInventory(); i++) {
if (craftMatrix.getStackInSlot(i) != null) {
player.dropItem(craftMatrix.getStackInSlot(i), false);
craftMatrix.setInventorySlotContents(i, ItemStack.EMPTY);
}
}
if (craftResult.getStackInSlot(0) != null) {
player.dropItem(craftResult.getStackInSlot(0), false);
craftResult.setInventorySlotContents(0, ItemStack.EMPTY);
}
}
@Override
public boolean canInteractWith(EntityPlayer player) {
return Predicates.MAGI.test(player);
}
}

View file

@ -0,0 +1,209 @@
package com.minelittlepony.unicopia.inventory.gui;
import java.io.IOException;
import org.lwjgl.opengl.GL11;
import com.minelittlepony.unicopia.enchanting.IPageUnlockListener;
import com.minelittlepony.unicopia.enchanting.PagesList;
import com.minelittlepony.unicopia.inventory.slot.SlotEnchanting;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.ResourceLocation;
public class GuiSpellBook extends GuiContainer implements IPageUnlockListener {
private static int currentPage = 0;
private static ResourceLocation spellBookPageTextures = new ResourceLocation("unicopia", "textures/gui/container/pages/page-" + currentPage + ".png");
private static final ResourceLocation spellBookGuiTextures = new ResourceLocation("unicopia", "textures/gui/container/book.png");
private IPlayer playerExtension;
private PageButton nextPage;
private PageButton prevPage;
public GuiSpellBook(EntityPlayer player) {
super(new ContainerSpellBook(player.inventory, player.world, new BlockPos(player)));
player.openContainer = inventorySlots;
((ContainerSpellBook)inventorySlots).setListener(this);
xSize = 405;
ySize = 219;
allowUserInput = true;
playerExtension = PlayerSpeciesList.instance().getPlayer(player);
}
@Override
public void initGui() {
super.initGui();
buttonList.clear();
int x = (width - xSize) / 2;
int y = (height - ySize) / 2;
buttonList.add(nextPage = new PageButton(1, x + 360, y + 160, true));
buttonList.add(prevPage = new PageButton(2, x + 20, y + 160, false));
}
@Override
protected void actionPerformed(GuiButton button) throws IOException {
initGui();
if (button.id == 1) {
nextPage();
} else {
prevPage();
}
}
public void nextPage() {
if (currentPage == 0) {
playerExtension.unlockPage(1);
}
if (currentPage < PagesList.getTotalPages() - 1) {
currentPage++;
spellBookPageTextures = new ResourceLocation("unicopia", "textures/gui/container/pages/page-" + currentPage + ".png");
onPageUnlocked();
PagesList.readPage(currentPage);
}
}
@Override
public void onPageUnlocked() {
if (PagesList.hasUnreadPagesAfter(currentPage)) {
nextPage.triggerShake();
}
if (PagesList.hasUnreadPagesBefore(currentPage)) {
prevPage.triggerShake();
}
}
public void prevPage() {
if (currentPage > 0) {
currentPage--;
spellBookPageTextures = new ResourceLocation("unicopia", "textures/gui/container/pages/page-" + currentPage + ".png");
onPageUnlocked();
PagesList.readPage(currentPage);
}
}
@Override
protected void drawGradientRect(int left, int top, int width, int height, int startColor, int endColor) {
Slot slot = getSlotUnderMouse();
if (slot == null || left != slot.xPos || top != slot.yPos || !drawSlotOverlay(slot)) {
super.drawGradientRect(left, top, width, height, startColor, endColor);
}
}
protected boolean drawSlotOverlay(Slot slot) {
if (slot instanceof SlotEnchanting) {
GlStateManager.enableBlend();
GL11.glDisable(GL11.GL_ALPHA_TEST);
mc.getTextureManager().bindTexture(spellBookGuiTextures);
drawModalRectWithCustomSizedTexture(slot.xPos - 1, slot.yPos - 1, 51, 223, 18, 18, 512, 256);
GL11.glEnable(GL11.GL_ALPHA_TEST);
GlStateManager.disableBlend();
return true;
}
return false;
}
@Override
public void drawScreen(int mouseX, int mouseY, float partialTicks) {
super.drawScreen(mouseX, mouseY, partialTicks);
renderHoveredToolTip(mouseX, mouseY);
}
@Override
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
if (PagesList.getTotalPages() > 0) {
String text = (currentPage + 1) + "/" + PagesList.getTotalPages();
fontRenderer.drawString(text, 203 - fontRenderer.getStringWidth(text)/2, 165, 0x0);
}
}
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
GlStateManager.color(1, 1, 1, 1);
int left = (width - xSize) / 2;
int top = (height - ySize) / 2;
mc.getTextureManager().bindTexture(spellBookGuiTextures);
drawModalRectWithCustomSizedTexture(left, top, 0, 0, xSize, ySize, 512, 256);
GlStateManager.enableBlend();
GL11.glDisable(GL11.GL_ALPHA_TEST);
if (playerExtension.hasPageUnlock(currentPage)) {
if (mc.getTextureManager().getTexture(spellBookPageTextures) != TextureUtil.MISSING_TEXTURE) {
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
mc.getTextureManager().bindTexture(spellBookPageTextures);
drawModalRectWithCustomSizedTexture(left, top, 0, 0, xSize, ySize, 512, 256);
}
}
mc.getTextureManager().bindTexture(spellBookGuiTextures);
drawModalRectWithCustomSizedTexture(left + 152, top + 49, 407, 2, 100, 101, 512, 256);
GL11.glEnable(GL11.GL_ALPHA_TEST);
GlStateManager.disableBlend();
}
static class PageButton extends GuiButton {
private final boolean direction;
private int shakesLeft = 0;
private float shakeCount = 0;
public PageButton(int id, int x, int y, boolean direction) {
super(id, x, y, 23, 13, "");
this.direction = direction;
}
@Override
public void drawButton(Minecraft mc, int mouseX, int mouseY, float partialTicks) {
if (visible) {
int x = this.x;
int y = this.y;
if (shakesLeft > 0) {
shakeCount += (float)Math.PI/2;
if (shakeCount >= Math.PI * 2) {
shakeCount %= Math.PI*2;
shakesLeft--;
}
x += (int)(Math.sin(shakeCount)*3);
y -= (int)(Math.sin(shakeCount)*3);
}
boolean hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + width && mouseY < this.y + height;
GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
mc.getTextureManager().bindTexture(spellBookGuiTextures);
int u = 0;
int v = 220;
if (hovered) u += 23;
if (!direction) v += 13;
drawModalRectWithCustomSizedTexture(x, y, u, v, 23, 13, 512, 256);
}
}
public void triggerShake() {
if (shakesLeft <= 0) {
shakesLeft = 5;
}
}
}
}

View file

@ -0,0 +1,15 @@
package com.minelittlepony.unicopia.inventory.slot;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.Slot;
public class SlotEnchanting extends Slot {
public SlotEnchanting(IInventory inventoryIn, int index, int xPosition, int yPosition) {
super(inventoryIn, index, xPosition, yPosition);
}
public boolean canBeHovered() {
return true;
}
}

View file

@ -0,0 +1,96 @@
package com.minelittlepony.unicopia.inventory.slot;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.enchanting.IPageUnlockListener;
import com.minelittlepony.unicopia.enchanting.PagesList;
import com.minelittlepony.unicopia.inventory.InventorySpellBook;
import com.minelittlepony.unicopia.item.ItemSpell;
import com.minelittlepony.unicopia.spell.SpellRegistry;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.util.NonNullList;
public class SlotEnchantingResult extends SlotEnchanting {
private final EntityPlayer thePlayer;
private final InventorySpellBook craftMatrix;
private IPageUnlockListener listener;
public SlotEnchantingResult(IPageUnlockListener listener, EntityPlayer player, InventorySpellBook craftMatric, IInventory inventory, int index, int xPosition, int yPosition) {
super(inventory, index, xPosition, yPosition);
thePlayer = player;
this.listener = listener;
craftMatrix = craftMatric;
}
public void setListener(IPageUnlockListener listener) {
this.listener = listener;
}
@Override
public ItemStack onTake(EntityPlayer player, ItemStack stack) {
onCrafting(stack);
ItemStack current = craftMatrix.getCraftResultMatrix().getStackInSlot(0);
craftMatrix.getCraftResultMatrix().setInventorySlotContents(0, stack);
NonNullList<ItemStack> remaining = Unicopia.getCraftingManager().getRemainingItems(craftMatrix, player.world);
craftMatrix.getCraftResultMatrix().setInventorySlotContents(0, current);
for (int i = 0; i < remaining.size(); ++i) {
current = craftMatrix.getStackInSlot(i);
ItemStack remainder = remaining.get(i);
if (!current.isEmpty()) {
if (current.getCount() < stack.getCount()) {
craftMatrix.setInventorySlotContents(i, ItemStack.EMPTY);
} else {
craftMatrix.decrStackSize(i, stack.getCount());
}
if (!remainder.isEmpty()) {
if (craftMatrix.getStackInSlot(i).isEmpty()) {
craftMatrix.setInventorySlotContents(i, remainder);
} else {
remainder.setCount(stack.getCount());
if (!player.inventory.addItemStackToInventory(remainder)) {
player.dropItem(remainder, true);
}
}
}
}
}
return super.onTake(player, stack);
}
@Override
protected void onCrafting(ItemStack stack, int amount) {
onCrafting(stack);
}
@Override
protected void onCrafting(ItemStack stack) {
if (PagesList.unlockPage(thePlayer, stack) && listener != null) {
listener.onPageUnlocked();
}
if (listener != null) {
listener.onPageUnlocked();
}
}
@Override
public boolean isItemValid(ItemStack stack) {
return stack.getItem() instanceof ItemSpell && !SpellRegistry.stackHasEnchantment(stack);
}
@Override
public String getSlotTexture() {
return "unicopia:items/empty_slot_gem";
}
}

View file

@ -0,0 +1,5 @@
package com.minelittlepony.unicopia.network;
public interface ITransmittable {
void sendCapabilities(boolean full);
}

View file

@ -3,6 +3,8 @@ package com.minelittlepony.unicopia.player;
import java.util.UUID;
import com.minelittlepony.model.anim.IInterpolator;
import com.minelittlepony.unicopia.enchanting.IPageOwner;
import com.minelittlepony.unicopia.network.ITransmittable;
import com.minelittlepony.unicopia.spell.ICaster;
import net.minecraft.client.Minecraft;
@ -10,9 +12,7 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.common.FMLCommonHandler;
public interface IPlayer extends ICaster<EntityPlayer>, IRaceContainer<EntityPlayer> {
void sendCapabilities(boolean full);
public interface IPlayer extends ICaster<EntityPlayer>, IRaceContainer<EntityPlayer>, ITransmittable, IPageOwner {
IAbilityReceiver getAbilities();

View file

@ -1,5 +1,10 @@
package com.minelittlepony.unicopia.player;
import java.util.List;
import javax.annotation.Nonnull;
import com.google.common.collect.Lists;
import com.minelittlepony.model.anim.BasicEasingInterpolator;
import com.minelittlepony.model.anim.IInterpolator;
import com.minelittlepony.unicopia.Race;
@ -17,6 +22,7 @@ import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.MobEffects;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagIntArray;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
@ -29,12 +35,17 @@ class PlayerCapabilities implements IPlayer, ICaster<EntityPlayer> {
private static final DataParameter<Integer> PLAYER_RACE = EntityDataManager
.createKey(EntityPlayer.class, DataSerializers.VARINT);
private static final DataParameter<Integer> ENERGY = EntityDataManager
.createKey(EntityPlayer.class, DataSerializers.VARINT);
private static final DataParameter<Float> EXERTION = EntityDataManager
.createKey(EntityPlayer.class, DataSerializers.FLOAT);
private static final DataParameter<NBTTagCompound> EFFECT = EntityDataManager
.createKey(EntityPlayer.class, DataSerializers.COMPOUND_TAG);
private final List<Integer> pages = Lists.newArrayList();
private final PlayerAbilityDelegate powers = new PlayerAbilityDelegate(this);
private final PlayerGravityDelegate gravity = new PlayerGravityDelegate(this);
@ -57,6 +68,7 @@ class PlayerCapabilities implements IPlayer, ICaster<EntityPlayer> {
player.getDataManager().register(PLAYER_RACE, Race.HUMAN.ordinal());
player.getDataManager().register(EXERTION, 0F);
player.getDataManager().register(EFFECT, new NBTTagCompound());
player.getDataManager().register(ENERGY, 0);
}
@Override
@ -159,7 +171,7 @@ class PlayerCapabilities implements IPlayer, ICaster<EntityPlayer> {
if (!getPlayerSpecies().canCast()) {
setEffect(null);
} else {
if (entity.getEntityWorld().isRemote) { // && entity.getEntityWorld().getWorldTime() % 10 == 0
if (entity.getEntityWorld().isRemote) {
getEffect().renderOnPerson(this);
}
@ -219,6 +231,10 @@ class PlayerCapabilities implements IPlayer, ICaster<EntityPlayer> {
compound.setTag("powers", powers.toNBT());
compound.setTag("gravity", gravity.toNBT());
if (hasUnlockedPages()) {
compound.setTag("pages", new NBTTagIntArray(pages));
}
IMagicEffect effect = getEffect();
if (effect != null) {
@ -236,6 +252,13 @@ class PlayerCapabilities implements IPlayer, ICaster<EntityPlayer> {
if (compound.hasKey("effect")) {
setEffect(SpellRegistry.instance().createEffectFromNBT(compound.getCompoundTag("effect")));
}
if (compound.hasKey("pages")) {
pages.clear();
for (int i : compound.getIntArray("pages")) {
pages.add(i);
}
}
}
@Override
@ -274,4 +297,10 @@ class PlayerCapabilities implements IPlayer, ICaster<EntityPlayer> {
@Override
public void setCurrentLevel(int level) {
}
@Nonnull
public List<Integer> getUnlockedPages() {
return pages;
}
}

View file

@ -5,6 +5,8 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import javax.annotation.Nonnull;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
@ -82,6 +84,21 @@ public class SpellRegistry {
}
}
public ItemStack disenchantStack(ItemStack stack) {
if (stackHasEnchantment(stack)) {
stack.getTagCompound().removeTag("spell");
}
return stack;
}
public ItemStack enchantStack(ItemStack stack, ItemStack from) {
stack.setTagCompound(new NBTTagCompound());
stack.getTagCompound().setString("spell", getKeyFromStack(from));
return stack;
}
public ItemStack enchantStack(ItemStack stack, String name) {
stack.setTagCompound(new NBTTagCompound());
stack.getTagCompound().setString("spell", name);
@ -89,6 +106,7 @@ public class SpellRegistry {
return stack;
}
@Nonnull
public static String getKeyFromStack(ItemStack stack) {
if (stack.isEmpty() || !stack.hasTagCompound() || !stack.getTagCompound().hasKey("spell")) {
return "";

View file

@ -0,0 +1,197 @@
package com.minelittlepony.unicopia.util.crafting;
import java.io.BufferedReader;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSyntaxException;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.inventory.InventoryCrafting;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.ShapedRecipes;
import net.minecraft.item.crafting.ShapelessRecipes;
import net.minecraft.util.JsonUtils;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
public class CraftingManager implements IResourceManagerReloadListener {
private static final Logger LOGGER = LogManager.getLogger();
private final Map<ResourceLocation, IRecipe> REGISTRY = Maps.newHashMap();
private final Map<String, Function<JsonObject, IRecipe>> JSON_PARSERS = Maps.newHashMap();
private static final Gson gson = new GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.create();
@Nonnull
private final ResourceLocation crafting_id;
public CraftingManager(String modid, String resourcename) {
this(new ResourceLocation(modid, resourcename + "/recipes"));
}
public CraftingManager(@Nonnull ResourceLocation id) {
crafting_id = id;
load();
}
protected void registerRecipeTypes(Map<String, Function<JsonObject, IRecipe>> types) {
types.put("crafting_shaped", ShapedRecipes::deserialize);
types.put("crafting_shapeless", ShapelessRecipes::deserialize);
}
@Override
public void onResourceManagerReload(IResourceManager resourceManager) {
load();
}
public void load() {
JSON_PARSERS.clear();
REGISTRY.clear();
registerRecipeTypes(JSON_PARSERS);
try {
String loadLocation = "/assets/" + crafting_id.getNamespace() + "/" + crafting_id.getPath();
URL url = CraftingManager.class.getResource(loadLocation);
if (url == null) {
LOGGER.error("Couldn't find .mcassetsroot");
return;
}
URI uri = url.toURI();
if ("file".equals(uri.getScheme())) {
loadRecipesFrom(Paths.get(CraftingManager.class.getResource(loadLocation).toURI()));
} else {
if (!"jar".equals(uri.getScheme())) {
LOGGER.error("Unsupported scheme " + uri + " trying to list all recipes");
return;
}
try (FileSystem filesystem = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
loadRecipesFrom(filesystem.getPath(loadLocation));
}
}
} catch (IOException | URISyntaxException e) {
LOGGER.error("Couldn't get a list of all recipe files", e);
}
}
private void loadRecipesFrom(@Nullable Path path) throws IOException {
if (path == null) {
return;
}
Iterator<Path> iterator = Files.walk(path).iterator();
while (iterator.hasNext()) {
Path i = iterator.next();
if ("json".equals(FilenameUtils.getExtension(i.toString()))) {
ResourceLocation id = new ResourceLocation(FilenameUtils.removeExtension(path.relativize(i).toString()).replaceAll("\\\\", "/"));
try(BufferedReader bufferedreader = Files.newBufferedReader(i)) {
REGISTRY.put(id, parseRecipeJson(JsonUtils.fromJson(gson, bufferedreader, JsonObject.class)));
} catch (JsonParseException e) {
LOGGER.error("Parsing error loading recipe " + id, e);
return;
} catch (IOException e) {
LOGGER.error("Couldn't read recipe " + id + " from " + i, e);
return;
}
}
}
}
protected IRecipe parseRecipeJson(JsonObject json) {
String s = JsonUtils.getString(json, "type");
if (!JSON_PARSERS.containsKey(s)) {
throw new JsonSyntaxException("Invalid or unsupported recipe type '" + s + "'");
}
return JSON_PARSERS.get(s).apply(json);
}
@Nonnull
public ItemStack findMatchingResult(InventoryCrafting craftMatrix, World worldIn) {
IRecipe recipe = findMatchingRecipe(craftMatrix, worldIn);
if (recipe != null) {
return recipe.getCraftingResult(craftMatrix);
}
return ItemStack.EMPTY;
}
@Nullable
public IRecipe findMatchingRecipe(InventoryCrafting craftMatrix, World worldIn) {
load();
for (IRecipe irecipe : REGISTRY.values()) {
if (irecipe.matches(craftMatrix, worldIn)) {
return irecipe;
}
}
return null;
}
public NonNullList<ItemStack> getRemainingItems(InventoryCrafting craftMatrix, World worldIn) {
IRecipe recipe = findMatchingRecipe(craftMatrix, worldIn);
if (recipe != null) {
return recipe.getRemainingItems(craftMatrix);
}
return cloneInventoryContents(craftMatrix);
}
public static NonNullList<ItemStack> cloneInventoryContents(InventoryCrafting craftMatrix) {
NonNullList<ItemStack> result = NonNullList.withSize(craftMatrix.getSizeInventory(), ItemStack.EMPTY);
for (int i = 0; i < result.size(); ++i) {
result.set(i, craftMatrix.getStackInSlot(i));
}
return result;
}
}

View file

@ -0,0 +1,12 @@
{
"type": "unicopia:crafting_spell",
"ingredients": [
{
"item": "minecraft:apple",
"data": 0
}
],
"result": {
"spell": "shield"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B