Compare commits

...
18 changed files with 640 additions and 106 deletions

No files matched your search

+1
View File
@@ -18,4 +18,5 @@ dependencies {
compileOnly('curse.maven:automagy-222153:2285272')
compileOnly('com.github.GTNewHorizons:EnderIO:2.10.25:dev')
runtimeOnly("com.github.GTNewHorizons:NotEnoughItems:2.8.118-GTNH:dev")
}
@@ -26,7 +26,9 @@ import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper;
version = References.VERSION,
canBeDeactivated = false,
guiFactory = References.GUIFACTORY,
dependencies = "after:NotEnoughItems;" + "after:ThermalExpansion;" + "after:ThermalFoundation;")
dependencies = "after:NotEnoughItems;" + "after:ThermalExpansion;"
+ "after:ThermalFoundation;"
+ "required-after:gtnhlib@[0.9.47,);")
public class DraconicEvolution {
@Mod.Instance(References.MODID)
@@ -28,6 +28,7 @@ import com.brandon3055.draconicevolution.client.utils.guicomponents.GUIBase;
import com.brandon3055.draconicevolution.common.container.ContainerAdvTool;
import com.brandon3055.draconicevolution.common.handler.ContributorHandler;
import com.brandon3055.draconicevolution.common.items.weapons.BowHandler;
import com.brandon3055.draconicevolution.common.items.weapons.IEnergyContainerBowItem;
import com.brandon3055.draconicevolution.common.lib.References;
import com.brandon3055.draconicevolution.common.network.ContributorPacket;
import com.brandon3055.draconicevolution.common.network.ItemConfigPacket;
@@ -310,11 +311,11 @@ public class GUIToolConfig extends GUIBase {
super.drawGuiContainerForegroundLayer(mouseX, mouseY);
if (slot > -1) editingItem = player.inventory.getStackInSlot(slot);
if (slot > -1 && editingItem != null && editingItem.getUnlocalizedName().toLowerCase().contains("bow")) {
if (slot > -1 && editingItem != null && editingItem.getItem() instanceof IEnergyContainerBowItem) {
BowHandler.BowProperties properties = new BowHandler.BowProperties(editingItem, player);
if (!properties.canFire() && properties.cantFireMessage != null
&& !properties.cantFireMessage.equals("msg.de.outOfArrows.name")) {
&& !properties.cantFireMessage.equals("msg.de.outOfArrows.txt")) {
fontRendererObj.drawSplitString(
StatCollector.translateToLocal(properties.cantFireMessage),
0,
@@ -139,6 +139,17 @@ public final class HudHandler {
showShieldHud = false;
return;
}
if (!shouldDisplayArmorHud(summary)) {
showShieldHud = false;
armorStatsFadeOut = 0F;
maxShieldPoints = 0F;
shieldPoints = 0F;
shieldPercentCharge = 0;
shieldEntropy = 0F;
rfCharge = 0;
rfTotal = 0;
return;
}
showShieldHud = armorStatsFadeOut > 0F;
if (maxShieldPoints != summary.maxProtectionPoints || shieldPoints != summary.protectionPoints
@@ -155,6 +166,10 @@ public final class HudHandler {
rfTotal = summary.totalEnergyStored;
}
private boolean shouldDisplayArmorHud(ArmorSummary summary) {
return summary.maxProtectionPoints > 0F || summary.maxTotalEnergyStorage > 0;
}
private void drawArmorHUD(int x, int y, boolean rotated, double scale) {
GL11.glPushMatrix();
GL11.glEnable(GL11.GL_ALPHA_TEST);
@@ -15,6 +15,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.imageio.ImageIO;
@@ -48,7 +49,7 @@ public class ResourceHandler {
private static ResourceLocation particles = new ResourceLocation(
References.RESOURCESPREFIX + "textures/particle/particles.png");
private static Map<String, ResourceLocation> cachedResources = new HashMap<String, ResourceLocation>();
public static Map<String, CustomResourceLocation> downloadedImages = new HashMap<String, CustomResourceLocation>();
public static Map<String, CustomResourceLocation> downloadedImages = new ConcurrentHashMap<>();
private static String savePath;
private static File saveFolder;
@@ -64,7 +65,6 @@ public class ResourceHandler {
if (downloadThread.isReloadRequired()) LogHelper.info("Image Download Finished");
downloadStatus = downloadThread.wasSuccessful ? 1 : 2;
FMLCommonHandler.instance().bus().unregister(this);
addRSPack(event != null);
downloadThread = null;
}
}
@@ -74,6 +74,10 @@ public class ResourceHandler {
if (event != null) savePath = event.getModConfigurationDirectory().getParentFile().getAbsolutePath()
+ "/config/draconicevolution";
// Register the namespace before FML's final reload; folder-pack files are resolved on demand.
getImagesFolder();
addRSPack();
GUIManual.loadPages();
downloadThread = new DownloadThread(GUIManual.imageURLs);
@@ -83,7 +87,7 @@ public class ResourceHandler {
public static class DownloadThread extends Thread {
private List<String> imageURLs;
private boolean isFinished = false;
private volatile boolean isFinished = false;
private boolean wasSuccessful = true;
private boolean reloadRequired = false;
@@ -171,7 +175,7 @@ public class ResourceHandler {
}
}
private static void addRSPack(boolean refreash) {
private static void addRSPack() {
File rspack = new File(getConfigFolder(), "/resources");
if (!rspack.exists()) return;
@@ -200,7 +204,6 @@ public class ResourceHandler {
f.set(Minecraft.getMinecraft(), defaultResourcePacks);
LogHelper.info("RS Added");
if (refreash) Minecraft.getMinecraft().refreshResources();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
@@ -35,6 +35,7 @@ public class ModelRenderOBJ extends ModelRenderer {
this.compileDisplayList(scale);
}
ResourceHandler.bindTexture(texture);
GL11.glTranslatef(this.offsetX, this.offsetY, this.offsetZ);
if (this.rotateAngleX == 0.0F && this.rotateAngleY == 0.0F && this.rotateAngleZ == 0.0F) {
@@ -84,7 +85,6 @@ public class ModelRenderOBJ extends ModelRenderer {
GL11.glNewList(this.displayList, GL11.GL_COMPILE);
GL11.glPushMatrix();
ResourceHandler.bindTexture(texture);
// scale = 1F/15F;
GL11.glScalef(scale, scale, scale);
GL11.glRotatef(180, -1, 0, 1);
@@ -102,6 +102,7 @@ public class ModelRenderOBJ extends ModelRenderer {
this.compileDisplayList(scale);
}
ResourceHandler.bindTexture(texture);
GL11.glPushMatrix();
GL11.glTranslatef(this.rotationPointX * scale, this.rotationPointY * scale, this.rotationPointZ * scale);
if (this.rotateAngleY != 0.0F) {
@@ -15,6 +15,12 @@ import com.brandon3055.draconicevolution.common.utils.LogHelper;
public class RenderMobSoul implements IItemRenderer {
public static volatile boolean applyTimeRotation = true;
public static float getRotationAngle() {
return (float) (Minecraft.getSystemTime() / -10);
}
private final Minecraft mc;
private final String[] randomEntities = new String[] { "Pig", "Sheep", "Enderman", "Zombie", "Creeper", "Cow",
"Chicken", "Ozelot", "Witch", "Wolf", "MushroomCow", "Squid", "EntityHorse", "Spider", "Skeleton", "Blaze",
@@ -58,7 +64,7 @@ public class RenderMobSoul implements IItemRenderer {
GL11.glScalef(13F, 13F, 13F);
GL11.glTranslated(1.2, 2.2, 0);
GL11.glRotatef(180F, 1F, 0F, 0F);
GL11.glRotatef(mc.getSystemTime() / -10, 0F, 1F, 0F);
if (applyTimeRotation) GL11.glRotatef(getRotationAngle(), 0F, 1F, 0F);
GL11.glRotatef(-20F, 1F, 0F, 0F);
RenderManager.instance.renderEntityWithPosYaw(mob, 0, 0, 0, 0F, 1F);
GL11.glPopMatrix();
@@ -67,7 +73,7 @@ public class RenderMobSoul implements IItemRenderer {
GL11.glScalef(0.8F, 0.8F, 0.8F);
GL11.glTranslated(2, 0.5, 0);
GL11.glRotatef(20F, 0F, 0F, 1F);
GL11.glRotatef(mc.getSystemTime() / -10, 0F, 1F, 0F);
if (applyTimeRotation) GL11.glRotatef(getRotationAngle(), 0F, 1F, 0F);
GL11.glRotatef(-20F, 1F, 0F, 0F);
RenderManager.instance.renderEntityWithPosYaw(mob, 0, 0, 0, 0F, 1F);
GL11.glPopMatrix();
@@ -76,14 +82,14 @@ public class RenderMobSoul implements IItemRenderer {
GL11.glScalef(0.8F, 0.8F, 0.8F);
GL11.glTranslated(1, 0.5, 0);
GL11.glRotatef(20F, 0F, 0F, 1F);
GL11.glRotatef(mc.getSystemTime() / -10, 0F, 1F, 0F);
if (applyTimeRotation) GL11.glRotatef(getRotationAngle(), 0F, 1F, 0F);
GL11.glRotatef(-20F, 1F, 0F, 0F);
RenderManager.instance.renderEntityWithPosYaw(mob, 0, 0, 0, 0F, 1F);
GL11.glPopMatrix();
} else {
GL11.glPushMatrix();
GL11.glScalef(1.5F, 1.5F, 1.5F);
GL11.glRotatef(mc.getSystemTime() / -10, 0F, 1F, 0F);
if (applyTimeRotation) GL11.glRotatef(getRotationAngle(), 0F, 1F, 0F);
GL11.glRotatef(-20F, 1F, 0F, 0F);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
@@ -0,0 +1,213 @@
package com.brandon3055.draconicevolution.client.render.tile;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.entity.RenderItem;
import net.minecraft.client.renderer.texture.ITickable;
import net.minecraft.item.ItemStack;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.client.event.RenderWorldLastEvent;
import net.minecraftforge.client.event.TextureStitchEvent;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.ChunkEvent;
import net.minecraftforge.event.world.WorldEvent;
import org.lwjgl.opengl.GL11;
import com.brandon3055.draconicevolution.client.render.item.RenderMobSoul;
import com.brandon3055.draconicevolution.common.items.MobSoul;
import com.brandon3055.draconicevolution.common.tileentities.TilePlacedItem;
import com.brandon3055.draconicevolution.common.utils.ItemNBTHelper;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
public class PlacedItemDisplayListCache {
private static final long GLINT_TTL_MS = 33L;
private static final long ANIMATED_TTL_MS = 50L;
private static final long MOBSOUL_TTL_MS = 1000L;
private static final long PRUNE_INTERVAL_MS = 1000L;
private final Map<TilePlacedItem, CacheEntry> displayListCache = new HashMap<>();
private int atlasVersion;
private long nextPruneMs;
public PlacedItemDisplayListCache() {
MinecraftForge.EVENT_BUS.register(this);
}
public CacheEntry getOrCompile(TilePlacedItem tile, int meta, Runnable renderBody) {
List<ItemStack> stacks = tile.getStacks();
CacheEntry entry = displayListCache.get(tile);
if (entry == null || !entry.isValid(stacks, meta, tile.rotation, atlasVersion) || entry.needsRefresh()) {
dispose(tile);
entry = compile(tile, stacks, meta, renderBody);
}
return entry;
}
private CacheEntry compile(TilePlacedItem tile, List<ItemStack> stacks, int meta, Runnable renderBody) {
int listId = GL11.glGenLists(1);
// A lone mob soul sits at the block centre, so its spin can be applied outside the list each frame. Souls in
// a grid are baked with their current angle instead and the list is refreshed on a short TTL.
boolean mobSoul = stacks.size() == 1 && stacks.get(0).getItem() instanceof MobSoul;
boolean previousRotationFlag = RenderMobSoul.applyTimeRotation;
GL11.glNewList(listId, GL11.GL_COMPILE);
try {
if (mobSoul) RenderMobSoul.applyTimeRotation = false;
renderBody.run();
GL11.glEndList();
} catch (RuntimeException | Error t) {
GL11.glEndList();
GL11.glDeleteLists(listId, 1);
RenderItem.renderInFrame = false;
throw t;
} finally {
RenderMobSoul.applyTimeRotation = previousRotationFlag;
}
CacheEntry entry = new CacheEntry(
listId,
stacks,
meta,
tile.rotation,
getTTL(stacks, mobSoul),
mobSoul,
atlasVersion);
displayListCache.put(tile, entry);
return entry;
}
private long getTTL(List<ItemStack> stacks, boolean mobSoulOutsideList) {
long ttl = Long.MAX_VALUE; // static (event-invalidated)
for (ItemStack stack : stacks) {
ttl = Math.min(ttl, getTTL(stack, mobSoulOutsideList));
}
return ttl;
}
private long getTTL(ItemStack stack, boolean mobSoulOutsideList) {
if (stack.getItem() instanceof MobSoul) {
// "Any" soul swaps mob every second while named souls only need per-frame rotation outside the list
if (isAnyMobSoul(stack)) return MOBSOUL_TTL_MS;
return mobSoulOutsideList ? Long.MAX_VALUE : ANIMATED_TTL_MS;
}
if (stack.hasEffect()) return GLINT_TTL_MS; // Glint scroll (~30 fps)
if (stack.getItem().getIconIndex(stack) instanceof ITickable) return ANIMATED_TTL_MS; // 20 Hz sprite ticks
return Long.MAX_VALUE;
}
private boolean isAnyMobSoul(ItemStack stack) {
return "Any".equals(ItemNBTHelper.getString(stack, "Name", "Pig"));
}
public void dispose(TilePlacedItem tile) {
CacheEntry entry = displayListCache.remove(tile);
if (entry != null) GL11.glDeleteLists(entry.listId, 1);
}
private void pruneInvalidEntries() {
if (displayListCache.isEmpty()) return;
long now = Minecraft.getSystemTime();
if (now < nextPruneMs) return;
nextPruneMs = now + PRUNE_INTERVAL_MS;
Iterator<Map.Entry<TilePlacedItem, CacheEntry>> it = displayListCache.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<TilePlacedItem, CacheEntry> entry = it.next();
TilePlacedItem tile = entry.getKey();
if (tile.isInvalid() || tile.getWorldObj() == null || tile.getDisplayCount() == 0) {
GL11.glDeleteLists(entry.getValue().listId, 1);
it.remove();
}
}
}
private void clearAll() {
for (CacheEntry entry : displayListCache.values()) {
GL11.glDeleteLists(entry.listId, 1);
}
displayListCache.clear();
}
@SubscribeEvent
public void onRenderWorldLast(RenderWorldLastEvent event) {
pruneInvalidEntries();
}
@SubscribeEvent
public void onTextureStitch(TextureStitchEvent.Post event) {
atlasVersion++;
clearAll();
}
@SubscribeEvent
public void onChunkUnload(ChunkEvent.Unload event) {
if (!event.world.isRemote) return;
Chunk chunk = event.getChunk();
Iterator<Map.Entry<TilePlacedItem, CacheEntry>> it = displayListCache.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<TilePlacedItem, CacheEntry> e = it.next();
TilePlacedItem tile = e.getKey();
if ((tile.xCoord >> 4) == chunk.xPosition && (tile.zCoord >> 4) == chunk.zPosition) {
GL11.glDeleteLists(e.getValue().listId, 1);
it.remove();
}
}
}
@SubscribeEvent
public void onWorldUnload(WorldEvent.Unload event) {
if (!event.world.isRemote) return;
clearAll();
}
public static class CacheEntry {
public final int listId;
private final ItemStack[] stacks;
private final int[] stackSizes;
public final int meta;
public final float rotation;
public final long ttlMs;
/** True when the list holds a single mob soul whose spin is applied by the caller each frame. */
public final boolean mobSoul;
public final int atlasVersion;
private long lastCompileMs;
private CacheEntry(int listId, List<ItemStack> stacks, int meta, float rotation, long ttlMs, boolean mobSoul,
int atlasVersion) {
this.listId = listId;
this.stacks = stacks.toArray(new ItemStack[0]);
this.stackSizes = new int[this.stacks.length];
for (int i = 0; i < this.stacks.length; i++) {
this.stackSizes[i] = this.stacks[i].stackSize;
}
this.meta = meta;
this.rotation = rotation;
this.ttlMs = ttlMs;
this.mobSoul = mobSoul;
this.atlasVersion = atlasVersion;
this.lastCompileMs = System.currentTimeMillis();
}
private boolean isValid(List<ItemStack> stacks, int meta, float rotation, int atlasVersion) {
if (this.meta != meta || this.rotation != rotation || this.atlasVersion != atlasVersion) return false;
if (this.stacks.length != stacks.size()) return false;
for (int i = 0; i < this.stacks.length; i++) {
// checking the pointer of the stack is enough
ItemStack stack = stacks.get(i);
if (this.stacks[i] != stack || this.stackSizes[i] != stack.stackSize) return false;
}
return true;
}
private boolean needsRefresh() {
return ttlMs != Long.MAX_VALUE && System.currentTimeMillis() - lastCompileMs >= ttlMs;
}
}
}
@@ -14,6 +14,8 @@ import net.minecraft.tileentity.TileEntity;
import org.lwjgl.opengl.GL11;
import com.brandon3055.draconicevolution.client.render.item.RenderMobSoul;
import com.brandon3055.draconicevolution.client.render.tile.PlacedItemDisplayListCache.CacheEntry;
import com.brandon3055.draconicevolution.common.items.MobSoul;
import com.brandon3055.draconicevolution.common.tileentities.TilePlacedItem;
@@ -22,24 +24,75 @@ import com.brandon3055.draconicevolution.common.tileentities.TilePlacedItem;
*/
public class RenderTilePlacedItem extends TileEntitySpecialRenderer {
private static final float MOBSOUL_CENTER_X = 0.5F;
private static final float MOBSOUL_CENTER_Y = 0.3F;
private static final float MOBSOUL_CENTER_Z = 0.5F;
private final EntityItem cachedEntity = new EntityItem(null, 0, 0, 0, new ItemStack(Items.apple));
private final PlacedItemDisplayListCache displayListCache = new PlacedItemDisplayListCache();
@Override
public void renderTileEntityAt(TileEntity te, double x, double y, double z, float timeSinceLastTick) {
if (!(te instanceof TilePlacedItem tile)) return;
if (tile.getStack() == null) return;
int count = tile.getDisplayCount();
if (count == 0) {
displayListCache.dispose(tile);
return;
}
if (tile.getWorldObj() == null) return;
int meta = tile.getWorldObj().getBlockMetadata(tile.xCoord, tile.yCoord, tile.zCoord);
if (meta < 0 || meta > 5) meta = 1;
final int gridMeta = meta;
CacheEntry entry = displayListCache.getOrCompile(tile, meta, () -> renderGrid(tile, gridMeta));
GL11.glPushMatrix();
GL11.glPushAttrib(GL11.GL_ENABLE_BIT);
GL11.glTranslated(x, y, z);
renderItem(tile);
if (entry.mobSoul) {
GL11.glTranslated(MOBSOUL_CENTER_X, MOBSOUL_CENTER_Y, MOBSOUL_CENTER_Z);
GL11.glRotatef(RenderMobSoul.getRotationAngle(), 0F, 1F, 0F);
GL11.glTranslated(-MOBSOUL_CENTER_X, -MOBSOUL_CENTER_Y, -MOBSOUL_CENTER_Z);
}
GL11.glCallList(entry.listId);
GL11.glPopAttrib();
GL11.glPopMatrix();
}
public void renderItem(TilePlacedItem tile) {
ItemStack stack = tile.getStack();
int meta = tile.getWorldObj().getBlockMetadata(tile.xCoord, tile.yCoord, tile.zCoord);
// itemEntity.getEntityItem().stackSize = 1;
/**
* Renders every item on the display laid out in a grid on the mounting face. This is the body that gets compiled
* into the cached display list.
*/
private void renderGrid(TilePlacedItem tile, int meta) {
int count = tile.getDisplayCount();
int gridSize = TilePlacedItem.getGridSize(count);
float cell = 1F / gridSize;
float[] pivot = TilePlacedItem.FACE_PIVOT[meta];
float[] axisU = TilePlacedItem.FACE_AXIS_U[meta];
float[] axisV = TilePlacedItem.FACE_AXIS_V[meta];
for (int i = 0; i < count; i++) {
ItemStack stack = tile.getStack(i);
if (stack == null) continue;
GL11.glPushMatrix();
if (gridSize > 1) {
float[] offset = TilePlacedItem.getCellOffset(i, count);
float u = offset[0];
float v = offset[1];
GL11.glTranslatef(
pivot[0] + axisU[0] * u + axisV[0] * v,
pivot[1] + axisU[1] * u + axisV[1] * v,
pivot[2] + axisU[2] * u + axisV[2] * v);
GL11.glScalef(cell, cell, cell);
GL11.glTranslatef(-pivot[0], -pivot[1], -pivot[2]);
}
renderItem(tile, stack, meta);
GL11.glPopMatrix();
}
}
public void renderItem(TilePlacedItem tile, ItemStack stack, int meta) {
final Item item = stack.getItem();
boolean is3D = item.isFull3D();
boolean isBlock = item instanceof ItemBlock;
@@ -58,7 +111,7 @@ public class RenderTilePlacedItem extends TileEntitySpecialRenderer {
GL11.glRotatef(tile.rotation, 0F, 0F, 1F);
GL11.glTranslatef(0.0F, -0.21F, 0.0F);
} else if (item instanceof MobSoul) {
GL11.glTranslatef(0.5F, 0.3F, 0.5F);
GL11.glTranslatef(MOBSOUL_CENTER_X, MOBSOUL_CENTER_Y, MOBSOUL_CENTER_Z);
} else {
GL11.glRotatef(90F, -1F, 0F, 0F);
GL11.glTranslatef(0.5F, -0.65F, 0.02F);
@@ -147,47 +147,61 @@ public class PlacedItem extends BlockDE {
@Override
public void breakBlock(World world, int x, int y, int z, Block block, int meta) {
TileEntity te = world.getTileEntity(x, y, z);
if (te != null && te instanceof TilePlacedItem && ((TilePlacedItem) te).getStack() != null) {
TilePlacedItem tile = (TilePlacedItem) te;
float spawnX = x + world.rand.nextFloat();
float spawnY = y + world.rand.nextFloat();
float spawnZ = z + world.rand.nextFloat();
EntityItem droppedItem = new EntityItem(world, spawnX, spawnY, spawnZ, tile.getStack());
tile.setStack(null);
float multiplier = 0.05F;
droppedItem.motionX = (-0.5F + world.rand.nextFloat()) * multiplier;
droppedItem.motionY = (4 + world.rand.nextFloat()) * multiplier;
droppedItem.motionZ = (-0.5F + world.rand.nextFloat()) * multiplier;
world.spawnEntityInWorld(droppedItem);
if (te instanceof TilePlacedItem tile) {
ItemStack stack;
while ((stack = tile.removeLastItem()) != null) {
dropStack(world, x, y, z, stack);
}
}
super.breakBlock(world, x, y, z, block, meta);
}
private static void dropStack(World world, int x, int y, int z, ItemStack stack) {
float spawnX = x + world.rand.nextFloat();
float spawnY = y + world.rand.nextFloat();
float spawnZ = z + world.rand.nextFloat();
EntityItem droppedItem = new EntityItem(world, spawnX, spawnY, spawnZ, stack);
float multiplier = 0.05F;
droppedItem.motionX = (-0.5F + world.rand.nextFloat()) * multiplier;
droppedItem.motionY = (4 + world.rand.nextFloat()) * multiplier;
droppedItem.motionZ = (-0.5F + world.rand.nextFloat()) * multiplier;
world.spawnEntityInWorld(droppedItem);
}
@Override
public Item getItemDropped(int p_149650_1_, Random p_149650_2_, int p_149650_3_) {
return null;
}
@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int p_149727_6_,
float p_149727_7_, float p_149727_8_, float p_149727_9_) {
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float hitX,
float hitY, float hitZ) {
TilePlacedItem tile = (world.getTileEntity(x, y, z) != null
&& world.getTileEntity(x, y, z) instanceof TilePlacedItem)
? (TilePlacedItem) world.getTileEntity(x, y, z)
: null;
if (tile == null) {
world.setBlockToAir(x, y, z);
return true;
}
if (player.isSneaking()) {
TilePlacedItem tile = (world.getTileEntity(x, y, z) != null
&& world.getTileEntity(x, y, z) instanceof TilePlacedItem)
? (TilePlacedItem) world.getTileEntity(x, y, z)
: null;
if (tile == null) {
world.setBlockToAir(x, y, z);
}
tile.rotation += 5.625F;
} else {
if (!world.isRemote) breakBlock(world, x, y, z, this, world.getBlockMetadata(x, y, z));
world.setBlockToAir(x, y, z);
// Remove the item the player clicked on; the block is removed once the last one is taken.
if (!world.isRemote) {
int index = tile.getStackIndexAt(world.getBlockMetadata(x, y, z), hitX, hitY, hitZ);
ItemStack stack = tile.removeItem(index);
if (stack != null) {
dropStack(world, x, y, z, stack);
}
if (tile.getDisplayCount() == 0) {
world.setBlockToAir(x, y, z);
}
}
}
world.markBlockForUpdate(x, y, z);
return true;
@@ -195,45 +209,42 @@ public class PlacedItem extends BlockDE {
@Override
public void onBlockClicked(World world, int x, int y, int z, EntityPlayer player) {
if (player.isSneaking()) {
TilePlacedItem tile = (world.getTileEntity(x, y, z) != null
&& world.getTileEntity(x, y, z) instanceof TilePlacedItem)
? (TilePlacedItem) world.getTileEntity(x, y, z)
: null;
if (tile == null) {
world.setBlockToAir(x, y, z);
}
tile.rotation += 22.5F;
} else {
TilePlacedItem tile = (world.getTileEntity(x, y, z) != null
&& world.getTileEntity(x, y, z) instanceof TilePlacedItem)
? (TilePlacedItem) world.getTileEntity(x, y, z)
: null;
if (tile == null) {
world.setBlockToAir(x, y, z);
}
tile.rotation -= 22.5F;
TilePlacedItem tile = (world.getTileEntity(x, y, z) != null
&& world.getTileEntity(x, y, z) instanceof TilePlacedItem)
? (TilePlacedItem) world.getTileEntity(x, y, z)
: null;
if (tile == null) {
world.setBlockToAir(x, y, z);
return;
}
tile.rotation += player.isSneaking() ? 22.5F : -22.5F;
world.markBlockForUpdate(x, y, z);
}
@Override
public int getLightValue(IBlockAccess world, int x, int y, int z) {
TileEntity te = world.getTileEntity(x, y, z);
if (te != null && te instanceof TilePlacedItem && ((TilePlacedItem) te).getStack() != null) {
TilePlacedItem tile = (TilePlacedItem) te;
if (tile.getStack() != null && tile.getStack().getItem() instanceof ItemBlock)
return Block.getBlockFromItem(tile.getStack().getItem()).getLightValue();
int light = 0;
if (te instanceof TilePlacedItem tile) {
for (ItemStack stack : tile.getStacks()) {
if (stack != null && stack.getItem() instanceof ItemBlock) {
light = Math.max(light, Block.getBlockFromItem(stack.getItem()).getLightValue());
}
}
}
return 0;
return light;
}
@Override
public ItemStack getPickBlock(MovingObjectPosition target, World world, int x, int y, int z) {
TileEntity te = world.getTileEntity(x, y, z);
if (te != null && te instanceof TilePlacedItem && ((TilePlacedItem) te).getStack() != null) {
TilePlacedItem tile = (TilePlacedItem) te;
return tile.getStack();
if (te instanceof TilePlacedItem tile && target != null && target.hitVec != null) {
int index = tile.getStackIndexAt(
world.getBlockMetadata(x, y, z),
(float) (target.hitVec.xCoord - x),
(float) (target.hitVec.yCoord - y),
(float) (target.hitVec.zCoord - z));
return tile.getStack(index);
}
return null;
}
@@ -17,6 +17,7 @@ public class ConfigHandler {
// GENERAL
public static boolean disableEarthBlock;
public static int teleporterUsesPerPearl;
public static int placedItemStackLimit;
public static int soulDropChance;
public static int passiveSoulDropChance;
public static int cometRarity;
@@ -113,6 +114,14 @@ public class ConfigHandler {
"Teleporter Uses PerPearl",
1,
"Charm of Dislocation uses per Ender pearl").getInt(1);
placedItemStackLimit = snapToAllowedStackLimit(
config.get(
Configuration.CATEGORY_GENERAL,
"Placed Item Stack Limit",
4,
"Maximum number of items that can be placed in the same block with the Place Item key. Valid values: 1, 2, 4, 8, 16",
1,
16).getInt(4));
bowBlockDamage = config.get(
Configuration.CATEGORY_GENERAL,
"Bow Block Damage",
@@ -478,6 +487,16 @@ public class ConfigHandler {
if (config.hasChanged()) config.save();
}
}
private static int snapToAllowedStackLimit(int value) {
int snapped = 1;
for (int allowed : new int[] { 1, 2, 4, 8, 16 }) {
if (value >= allowed) {
snapped = allowed;
}
}
return snapped;
}
}
/*
* { //config.load(); disableSunDial = config.getInt("Disable Sun Dial", Configuration.CATEGORY_GENERAL, disableSunDial,
@@ -61,8 +61,10 @@ public class Magnet extends ItemDE implements IBauble, IConfigurableItem {
DELAY,
NEVER;
public static final SelfPickUpMode[] VALUES = values();
public SelfPickUpMode next() {
final SelfPickUpMode[] values = SelfPickUpMode.values();
final SelfPickUpMode[] values = SelfPickUpMode.VALUES;
return values[(this.ordinal() + 1) % values.length];
}
}
@@ -265,7 +267,7 @@ public class Magnet extends ItemDE implements IBauble, IConfigurableItem {
private static SelfPickUpMode getSelfPickupStatus(ItemStack itemStack) {
final short mode = getSelfPickupStatusShort(itemStack);
return SelfPickUpMode.values()[mode];
return SelfPickUpMode.VALUES[mode];
}
public static void toggleSelfPickupStatus(ItemStack itemStack) {
@@ -158,8 +158,8 @@ public class BowHandler {
public int calculateEnergyCost() {
updateValues();
double rfCost = (bow.getItem() instanceof IEnergyContainerWeaponItem)
? ((IEnergyContainerWeaponItem) bow.getItem()).getEnergyPerAttack()
double rfCost = (bow.getItem() instanceof IEnergyContainerBowItem)
? ((IEnergyContainerBowItem) bow.getItem()).getEnergyPerAttack()
: 80;
rfCost *= 1 + arrowDamage;
@@ -175,7 +175,7 @@ public class BowHandler {
updateValues();
if (player == null) return false;
if (!(bow.getItem() instanceof IEnergyContainerWeaponItem)) {
if (!(bow.getItem() instanceof IEnergyContainerBowItem)) {
cantFireMessage = "[Error] This bow is not a valid energy container (This is a bug, Please report on the Draconic Evolution github)";
return false;
} else if (!energyBolt && shockWavePower > 0) {
@@ -184,7 +184,7 @@ public class BowHandler {
} else if (energyBolt && explosionPower > 0) {
cantFireMessage = "msg.de.explosiveNotForEnergyBolts.txt";
return false;
} else if (calculateEnergyCost() > ((IEnergyContainerWeaponItem) bow.getItem()).getEnergyStored(bow)
} else if (calculateEnergyCost() > ((IEnergyContainerBowItem) bow.getItem()).getEnergyStored(bow)
&& !player.capabilities.isCreativeMode) {
cantFireMessage = "msg.de.insufficientPowerToFire.txt";
return false;
@@ -223,7 +223,7 @@ public class BowHandler {
public boolean consumeArrowAndEnergy() {
if (!player.capabilities.isCreativeMode)
((IEnergyContainerWeaponItem) bow.getItem()).extractEnergy(bow, calculateEnergyCost(), false);
((IEnergyContainerBowItem) bow.getItem()).extractEnergy(bow, calculateEnergyCost(), false);
if (!energyBolt && EnchantmentHelper.getEnchantmentLevel(Enchantment.infinity.effectId, bow) == 0
&& !player.capabilities.isCreativeMode) {
@@ -39,7 +39,7 @@ import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class DraconicBow extends ItemBow
implements IInventoryTool, IUpgradableItem, IEnergyContainerWeaponItem, IHudDisplayItem {
implements IInventoryTool, IUpgradableItem, IEnergyContainerBowItem, IHudDisplayItem {
public static final String[] bowPullIconNameArray = new String[] { "pulling_0", "pulling_1", "pulling_2" };
@@ -0,0 +1,4 @@
package com.brandon3055.draconicevolution.common.items.weapons;
public interface IEnergyContainerBowItem extends IEnergyContainerWeaponItem {
}
@@ -39,7 +39,7 @@ import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class WyvernBow extends ItemBow
implements IInventoryTool, IUpgradableItem, IEnergyContainerWeaponItem, IHudDisplayItem {
implements IInventoryTool, IUpgradableItem, IEnergyContainerBowItem, IHudDisplayItem {
public static final String[] bowPullIconNameArray = new String[] { "pulling_0", "pulling_1", "pulling_2" };
@@ -62,9 +62,19 @@ public class PlacedItemPacket implements IMessage {
World world = ctx.getServerHandler().playerEntity.worldObj;
EntityPlayer player = ctx.getServerHandler().playerEntity;
if (!world.isAirBlock(x, y, z) || player.getHeldItem() == null
|| !ModBlocks.isEnabled(ModBlocks.placedItem))
if (player.getHeldItem() == null || !ModBlocks.isEnabled(ModBlocks.placedItem)) {
return null;
}
// Aiming directly at an existing placed item display adds the held item to it.
if (addToExistingDisplay(world, message.blockX, message.blockY, message.blockZ, player)
|| addToExistingDisplay(world, x, y, z, player)) {
return null;
}
if (!world.isAirBlock(x, y, z)) {
return null;
}
BlockEvent.PlaceEvent event = new BlockEvent.PlaceEvent(
new BlockSnapshot(world, x, y, z, ModBlocks.placedItem, 0),
@@ -93,5 +103,26 @@ public class PlacedItemPacket implements IMessage {
player.destroyCurrentEquippedItem();
return null;
}
private static boolean addToExistingDisplay(World world, int x, int y, int z, EntityPlayer player) {
if (!(world.getTileEntity(x, y, z) instanceof TilePlacedItem tile)) {
return false;
}
BlockEvent.PlaceEvent event = new BlockEvent.PlaceEvent(
new BlockSnapshot(world, x, y, z, ModBlocks.placedItem, world.getBlockMetadata(x, y, z)),
world.getBlock(x, y, z),
player);
MinecraftForge.EVENT_BUS.post(event);
if (event.isCanceled()) {
return false;
}
if (!tile.addItem(player.getHeldItem().copy())) {
return false;
}
player.destroyCurrentEquippedItem();
return true;
}
}
}
@@ -1,15 +1,19 @@
package com.brandon3055.draconicevolution.common.tileentities;
import net.minecraft.init.Blocks;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.Vec3;
import com.brandon3055.draconicevolution.common.ModBlocks;
import com.brandon3055.draconicevolution.common.handler.ConfigHandler;
import com.brandon3055.draconicevolution.common.utils.LogHelper;
/**
@@ -17,13 +21,37 @@ import com.brandon3055.draconicevolution.common.utils.LogHelper;
*/
public class TilePlacedItem extends TileEntity {
public ItemStack stack;
public static final int ABSOLUTE_MAX_STACKS = 16;
/**
* Pivot point on the mounting face and the two in-plane axes used to lay out the item grid, indexed by block
* metadata (the side the display is attached to). Shared by the renderer and the hit test so that the stack a
* player clicks on is the one they see.
*/
public static final float[][] FACE_PIVOT = { { 0.5F, 1F, 0.5F }, { 0.5F, 0F, 0.5F }, { 0.5F, 0.5F, 1F },
{ 0.5F, 0.5F, 0F }, { 1F, 0.5F, 0.5F }, { 0F, 0.5F, 0.5F } };
public static final float[][] FACE_AXIS_U = { { 1F, 0F, 0F }, { 1F, 0F, 0F }, { 1F, 0F, 0F }, { 1F, 0F, 0F },
{ 0F, 0F, 1F }, { 0F, 0F, 1F } };
public static final float[][] FACE_AXIS_V = { { 0F, 0F, 1F }, { 0F, 0F, 1F }, { 0F, 1F, 0F }, { 0F, 1F, 0F },
{ 0F, 1F, 0F }, { 0F, 1F, 0F } };
private final List<ItemStack> stacks = new ArrayList<>(ABSOLUTE_MAX_STACKS);
public float rotation = 0F;
private boolean hasUpdated = false;
private AxisAlignedBB renderBoundingBox;
@Override
public AxisAlignedBB getRenderBoundingBox() {
if (renderBoundingBox == null) {
renderBoundingBox = AxisAlignedBB
.getBoundingBox(xCoord - 2, yCoord - 2, zCoord - 2, xCoord + 2, yCoord + 2, zCoord + 2);
}
return renderBoundingBox;
}
@Override
public void updateEntity() {
if (!hasUpdated && stack != null) {
if (!hasUpdated && !stacks.isEmpty()) {
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
hasUpdated = true;
}
@@ -39,44 +67,188 @@ public class TilePlacedItem extends TileEntity {
@Override
public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) {
readFromNBT(pkt.func_148857_g());
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
public void setStack(ItemStack stack) {
this.stack = stack;
stacks.clear();
if (stack != null) {
stacks.add(stack);
}
worldObj.scheduleBlockUpdate(xCoord, yCoord, zCoord, ModBlocks.placedItem, 20);
}
public ItemStack getStack() {
/**
* Adds an item to this display if there is room for it. The limit is the lower of the configured stack limit and
* {@link #ABSOLUTE_MAX_STACKS}.
*
* @return true if the item was added.
*/
public boolean addItem(ItemStack stack) {
if (stack == null || stacks.size() >= getStackLimit()) {
return false;
}
stacks.add(stack);
markDirtyAndSync();
return true;
}
/**
* Removes and returns the most recently added item, or null if empty.
*/
public ItemStack removeLastItem() {
if (stacks.isEmpty()) {
return null;
}
ItemStack stack = stacks.remove(stacks.size() - 1);
markDirtyAndSync();
return stack;
}
/**
* Removes and returns the item at {@code index}, or null if the index is out of range.
*/
public ItemStack removeItem(int index) {
if (index < 0 || index >= stacks.size()) {
return null;
}
ItemStack stack = stacks.remove(index);
markDirtyAndSync();
return stack;
}
/**
* @return the number of columns (and maximum rows) in the grid used to display {@code count} items.
*/
public static int getGridSize(int count) {
return (int) Math.ceil(Math.sqrt(count));
}
/**
* Computes where the centre of grid cell {@code index} sits relative to the face pivot, in block units along
* {@link #FACE_AXIS_U} and {@link #FACE_AXIS_V}. Rows are centred so a partially filled last row does not hang to
* one side.
*
* @return {u, v}
*/
public static float[] getCellOffset(int index, int count) {
int gridSize = getGridSize(count);
if (gridSize <= 1) {
return new float[] { 0F, 0F };
}
int rows = (count + gridSize - 1) / gridSize;
float cell = 1F / gridSize;
int row = index / gridSize;
int col = index % gridSize;
int rowLength = Math.min(gridSize, count - row * gridSize);
return new float[] { (col - (rowLength - 1) / 2F) * cell, ((rows - 1) / 2F - row) * cell };
}
/**
* Finds the stack whose grid cell is closest to a point on this block.
*
* @param meta the block metadata (mounting side)
* @param hitX x of the hit, relative to the block (0..1)
* @param hitY y of the hit, relative to the block (0..1)
* @param hitZ z of the hit, relative to the block (0..1)
* @return the index of the closest stack, or -1 if the display is empty
*/
public int getStackIndexAt(int meta, float hitX, float hitY, float hitZ) {
int count = stacks.size();
if (count == 0) {
return -1;
}
if (meta < 0 || meta > 5) {
meta = 1;
}
float[] pivot = FACE_PIVOT[meta];
float[] axisU = FACE_AXIS_U[meta];
float[] axisV = FACE_AXIS_V[meta];
float dx = hitX - pivot[0];
float dy = hitY - pivot[1];
float dz = hitZ - pivot[2];
float u = dx * axisU[0] + dy * axisU[1] + dz * axisU[2];
float v = dx * axisV[0] + dy * axisV[1] + dz * axisV[2];
int closest = 0;
float closestDistSq = Float.MAX_VALUE;
for (int i = 0; i < count; i++) {
float[] offset = getCellOffset(i, count);
float du = u - offset[0];
float dv = v - offset[1];
float distSq = du * du + dv * dv;
if (distSq < closestDistSq) {
closestDistSq = distSq;
closest = i;
}
}
return closest;
}
public static int getStackLimit() {
return Math.min(ConfigHandler.placedItemStackLimit, ABSOLUTE_MAX_STACKS);
}
private void markDirtyAndSync() {
markDirty();
if (worldObj != null) {
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
}
/**
* @return the first stack in this display, or null if empty. Retained for the single-item code paths (pick block,
* collision box).
*/
public ItemStack getStack() {
return stacks.isEmpty() ? null : stacks.get(0);
}
public ItemStack getStack(int index) {
return index >= 0 && index < stacks.size() ? stacks.get(index) : null;
}
public List<ItemStack> getStacks() {
return stacks;
}
public int getDisplayCount() {
return stacks.size();
}
@Override
public void writeToNBT(NBTTagCompound compound) {
super.writeToNBT(compound);
NBTTagCompound[] tag = new NBTTagCompound[1];
tag[0] = new NBTTagCompound();
if (stack != null) {
stack.writeToNBT(tag[0]);
compound.setByte("Count", (byte) stacks.size());
for (int i = 0; i < stacks.size(); i++) {
NBTTagCompound tag = new NBTTagCompound();
stacks.get(i).writeToNBT(tag);
compound.setTag("Item" + i, tag);
}
compound.setTag("Item" + 0, tag[0]);
compound.setFloat("Rotation", rotation);
}
@Override
public void readFromNBT(NBTTagCompound compound) {
super.readFromNBT(compound);
NBTTagCompound[] tag = new NBTTagCompound[1];
tag[0] = compound.getCompoundTag("Item" + 0);
stack = ItemStack.loadItemStackFromNBT(tag[0]);
if (stack == null) {
// the stack can be null if the placed item was
// an item that got removed in between mod updates
stack = new ItemStack(Blocks.stone);
stacks.clear();
// Old worlds have no Count tag and always stored a single stack in Item0.
int count = compound.hasKey("Count") ? compound.getByte("Count") : 1;
for (int i = 0; i < count && i < ABSOLUTE_MAX_STACKS; i++) {
ItemStack stack = ItemStack.loadItemStackFromNBT(compound.getCompoundTag("Item" + i));
if (stack != null) {
stacks.add(stack);
} else {
// the stack can be null if the placed item was
// an item that got removed in between mod updates
LogHelper.error(
"Cannot load a Placed Item stack at location "
+ Vec3.createVectorHelper(this.xCoord, this.yCoord, this.zCoord)
+ " because the associated item is null, it will be removed.");
}
}
if (stacks.isEmpty()) {
this.invalidate();
LogHelper.error(
"Cannot load the Placed Item at location "
+ Vec3.createVectorHelper(this.xCoord, this.yCoord, this.zCoord)
+ " because the associated item is null, it will be removed.");
}
rotation = compound.getFloat("Rotation");
}