diff --git a/gradle.properties b/gradle.properties index e2df4770..f9bbf678 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ modGroup = com.gtnewhorizon -modVersion = 1.0.6 +modVersion = 1.0.7 modBaseName = StructureLib forgeVersion = 1.7.10-10.13.4.1614-1.7.10 diff --git a/src/main/java/com/gtnewhorizon/structurelib/ConfigurationHandler.java b/src/main/java/com/gtnewhorizon/structurelib/ConfigurationHandler.java new file mode 100644 index 00000000..3ed09d42 --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/ConfigurationHandler.java @@ -0,0 +1,68 @@ +package com.gtnewhorizon.structurelib; + +import cpw.mods.fml.client.event.ConfigChangedEvent; +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.common.config.ConfigCategory; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; + +import java.io.File; +import java.util.Map; + +public enum ConfigurationHandler { + INSTANCE; + + private Configuration config; + private int maxCoexistingHologram; + private boolean removeCollidingHologram; + + ConfigurationHandler() { + FMLCommonHandler.instance().bus().register(this); + } + + void init(File f) { + config = new Configuration(f, ConfigurationVersion.latest().getVersionMarker()); + ConfigurationVersion.migrateToLatest(config); + loadConfig(); + setLanguageKeys(); + } + + private void setLanguageKeys() { + for (String categoryName : config.getCategoryNames()) { + ConfigCategory category = config.getCategory(categoryName); + category.setLanguageKey("structurelib.config." + categoryName); + for (Map.Entry entry : category.entrySet()) { + entry.getValue().setLanguageKey(String.format("%s.%s", category.getLanguagekey(), entry.getKey())); + } + } + } + + private void loadConfig() { + maxCoexistingHologram = config.getInt("maxCoexisting", "client.hologram", 1, 1, 100, "An attempt will be made to prune old holograms when a new hologram is about to be projected"); + removeCollidingHologram = config.getBoolean("removeColliding", "client.hologram", true, "An attempt will be made to remove an existing hologram if it collides with a new hologram."); + + if (config.hasChanged()) { + config.save(); + } + } + + @SubscribeEvent + public void onConfigChange(ConfigChangedEvent.PostConfigChangedEvent e) { + if (e.modID.equals(StructureLibAPI.MOD_ID)) { + loadConfig(); + } + } + + public int getMaxCoexistingHologram() { + return maxCoexistingHologram; + } + + public boolean isRemoveCollidingHologram() { + return removeCollidingHologram; + } + + Configuration getConfig() { + return config; + } +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/ConfigurationVersion.java b/src/main/java/com/gtnewhorizon/structurelib/ConfigurationVersion.java new file mode 100644 index 00000000..4df0964e --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/ConfigurationVersion.java @@ -0,0 +1,44 @@ +package com.gtnewhorizon.structurelib; + +import net.minecraftforge.common.config.Configuration; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Objects; + +enum ConfigurationVersion { + V1 { + @Override + protected void step(Configuration c) { + } + }; + + private static final ConfigurationVersion[] VALUES = values(); + + private final String versionMarker; + + ConfigurationVersion() { + this.versionMarker = name(); + } + + public static void migrateToLatest(Configuration c) { + for (int i = identify(c).ordinal() + 1; i < VALUES.length; i++) { + VALUES[i].step(c); + } + } + + public static ConfigurationVersion latest() { + return VALUES[VALUES.length - 1]; + } + + public static ConfigurationVersion identify(Configuration c) { + return Arrays.stream(VALUES).filter(v -> Objects.equals(c.getLoadedConfigVersion(), v.getVersionMarker())).findFirst().orElse(V1); + } + + @Nullable + public String getVersionMarker() { + return versionMarker; + } + + protected abstract void step(Configuration c); +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/GuiFactory.java b/src/main/java/com/gtnewhorizon/structurelib/GuiFactory.java new file mode 100644 index 00000000..879a12b6 --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/GuiFactory.java @@ -0,0 +1,28 @@ +package com.gtnewhorizon.structurelib; + +import cpw.mods.fml.client.IModGuiFactory; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; + +import java.util.Set; + +public class GuiFactory implements IModGuiFactory { + @Override + public void initialize(Minecraft minecraftInstance) { + } + + @Override + public Class mainConfigGuiClass() { + return GuiModConfig.class; + } + + @Override + public Set runtimeGuiCategories() { + return null; + } + + @Override + public RuntimeOptionGuiHandler getHandlerFor(RuntimeOptionCategoryElement element) { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/com/gtnewhorizon/structurelib/GuiModConfig.java b/src/main/java/com/gtnewhorizon/structurelib/GuiModConfig.java new file mode 100644 index 00000000..8e81af68 --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/GuiModConfig.java @@ -0,0 +1,25 @@ +package com.gtnewhorizon.structurelib; + +import cpw.mods.fml.client.config.GuiConfig; +import cpw.mods.fml.client.config.IConfigElement; +import net.minecraft.client.gui.GuiScreen; +import net.minecraftforge.common.config.ConfigElement; +import net.minecraftforge.common.config.Configuration; + +import java.util.List; +import java.util.stream.Collectors; + +public class GuiModConfig extends GuiConfig { + public GuiModConfig(GuiScreen guiScreen) { + super(guiScreen, getConfigElements(), StructureLibAPI.MOD_ID, false, false, GuiConfig.getAbridgedConfigPath(ConfigurationHandler.INSTANCE.getConfig().toString())); + } + + @SuppressWarnings("rawtypes") + private static List getConfigElements() { + final Configuration config = ConfigurationHandler.INSTANCE.getConfig(); + return config.getCategoryNames().stream() + .filter(name -> name.indexOf('.') == -1) + .map(name -> new ConfigElement(config.getCategory(name))) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/gtnewhorizon/structurelib/StructureLib.java b/src/main/java/com/gtnewhorizon/structurelib/StructureLib.java index 0494a667..7374361a 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/StructureLib.java +++ b/src/main/java/com/gtnewhorizon/structurelib/StructureLib.java @@ -1,6 +1,6 @@ package com.gtnewhorizon.structurelib; -import com.gtnewhorizon.structurelib.alignment.AlignmentMessage; +import com.gtnewhorizon.structurelib.net.AlignmentMessage; import com.gtnewhorizon.structurelib.block.BlockHint; import com.gtnewhorizon.structurelib.item.ItemBlockHint; import com.gtnewhorizon.structurelib.item.ItemConstructableTrigger; @@ -26,15 +26,14 @@ import org.apache.logging.log4j.Logger; /** * This class does not contain a stable API. Refrain from using this class. */ -@Mod(modid = StructureLib.MOD_ID, name = "StructureLib", version = "${version}", acceptableRemoteVersions = "*") +@Mod(modid = StructureLibAPI.MOD_ID, name = "StructureLib", version = "${version}", acceptableRemoteVersions = "*", guiFactory = "com.gtnewhorizon.structurelib.GuiFactory") public class StructureLib { - public static boolean DEBUG_MODE = true; + public static boolean DEBUG_MODE = Boolean.getBoolean("structurelib.debug"); public static Logger LOGGER = LogManager.getLogger("StructureLib"); - public static final String MOD_ID = "structurelib"; @SidedProxy(serverSide = "com.gtnewhorizon.structurelib.proxy.CommonProxy", clientSide = "com.gtnewhorizon.structurelib.proxy.ClientProxy") static CommonProxy proxy; - static SimpleNetworkWrapper net = NetworkRegistry.INSTANCE.newSimpleChannel(MOD_ID); + static SimpleNetworkWrapper net = NetworkRegistry.INSTANCE.newSimpleChannel(StructureLibAPI.MOD_ID); static { net.registerMessage(AlignmentMessage.ServerHandler.class, AlignmentMessage.AlignmentQuery.class, 0, Side.SERVER); @@ -57,10 +56,12 @@ public class StructureLib { @Mod.EventHandler public void preInit(FMLPreInitializationEvent e) { + ConfigurationHandler.INSTANCE.init(e.getSuggestedConfigurationFile()); GameRegistry.registerBlock(blockHint = new BlockHint(), ItemBlockHint.class, "blockhint"); itemBlockHint = ItemBlock.getItemFromBlock(StructureLibAPI.getBlockHint()); GameRegistry.registerItem(itemFrontRotationTool = new ItemFrontRotationTool(), itemFrontRotationTool.getUnlocalizedName()); GameRegistry.registerItem(itemConstructableTrigger = new ItemConstructableTrigger(), itemConstructableTrigger.getUnlocalizedName()); + proxy.preInit(e); } public static void addClientSideChatMessages(String... messages) { diff --git a/src/main/java/com/gtnewhorizon/structurelib/StructureLibAPI.java b/src/main/java/com/gtnewhorizon/structurelib/StructureLibAPI.java index 3e6d3b83..c50de5a4 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/StructureLibAPI.java +++ b/src/main/java/com/gtnewhorizon/structurelib/StructureLibAPI.java @@ -1,17 +1,24 @@ package com.gtnewhorizon.structurelib; -import com.gtnewhorizon.structurelib.alignment.AlignmentMessage; +import com.gtnewhorizon.structurelib.net.AlignmentMessage; import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider; +import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; import cpw.mods.fml.common.network.NetworkRegistry; import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; import net.minecraft.util.IIcon; import net.minecraft.world.World; import static com.gtnewhorizon.structurelib.StructureLib.proxy; +/** + * A stable interface into the structure lib's internals. Backwards compatibility is maintained to the maximum extend possible. + */ public class StructureLibAPI { + public static final String MOD_ID = "structurelib"; public static final int HINT_BLOCK_META_GENERIC_0 = 0; public static final int HINT_BLOCK_META_GENERIC_1 = 1; public static final int HINT_BLOCK_META_GENERIC_2 = 2; @@ -28,6 +35,25 @@ public class StructureLibAPI { public static final int HINT_BLOCK_META_AIR = 13; public static final int HINT_BLOCK_META_NOT_AIR = 14; public static final int HINT_BLOCK_META_ERROR = 15; + + /** + * Start a batch of hinting. All hints particles generated during one batch will be considered to belong to one hologram. + * + * You don't need to call this unless your constructable tool didn't call {@link com.gtnewhorizon.structurelib.alignment.constructable.ConstructableUtility#handle(ItemStack, EntityPlayer, World, int, int, int, int)} + */ + public static void startHinting(World w) { + proxy.startHinting(w); + } + + /** + * Start current batch of hinting. All hints particles generated during one batch will be considered to belong to one hologram. + * + * You don't need to call this unless your constructable tool didn't call {@link com.gtnewhorizon.structurelib.alignment.constructable.ConstructableUtility#handle(ItemStack, EntityPlayer, World, int, int, int, int)} + */ + public static void endHinting(World w) { + proxy.endHinting(w); + } + public static void hintParticleTinted(World w, int x, int y, int z, IIcon[] icons, short[] RGBa) { proxy.hintParticleTinted(w, x, y, z, icons, RGBa); } @@ -44,22 +70,45 @@ public class StructureLibAPI { proxy.hintParticle(w, x, y, z, block, meta); } + /** + * Query the ExtendedFacing of this tile entity. + * The ExtendedFacing will later be set onto given tile entity via {@link com.gtnewhorizon.structurelib.alignment.IAlignment#setExtendedFacing(ExtendedFacing)} + * upon arrival of server reply. + * @throws IllegalArgumentException if is not tile entity or provided a null alignment + */ public static void queryAlignment(IAlignmentProvider provider) { StructureLib.net.sendToServer(new AlignmentMessage.AlignmentQuery(provider)); } + /** + * Send the ExtendedFacing of this Tile Entity to all players. Can be called on server side only. + * @throws IllegalArgumentException if is not tile entity or provided a null alignment + */ public static void sendAlignment(IAlignmentProvider provider) { StructureLib.net.sendToAll(new AlignmentMessage.AlignmentData(provider)); } + /** + * Send the ExtendedFacing of this Tile Entity to given player. Can be called on server side only. + * @throws IllegalArgumentException if is not tile entity or provided a null alignment + */ public static void sendAlignment(IAlignmentProvider provider, EntityPlayerMP player) { StructureLib.net.sendTo(new AlignmentMessage.AlignmentData(provider), player); } + /** + * Send the ExtendedFacing of this Tile Entity to all players around target point. Can be called on server side only. + * @throws IllegalArgumentException if is not tile entity or provided a null alignment + */ public static void sendAlignment(IAlignmentProvider provider, NetworkRegistry.TargetPoint targetPoint) { StructureLib.net.sendToAllAround(new AlignmentMessage.AlignmentData(provider), targetPoint); } + + /** + * Send the ExtendedFacing of this Tile Entity to all players in that dimension. Can be called on server side only. + * @throws IllegalArgumentException if is not tile entity or provided a null alignment + */ public static void sendAlignment(IAlignmentProvider provider, World dimension) { StructureLib.net.sendToDimension(new AlignmentMessage.AlignmentData(provider), dimension.provider.dimensionId); } diff --git a/src/main/java/com/gtnewhorizon/structurelib/alignment/constructable/ConstructableUtility.java b/src/main/java/com/gtnewhorizon/structurelib/alignment/constructable/ConstructableUtility.java index 47943225..4369f1e5 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/alignment/constructable/ConstructableUtility.java +++ b/src/main/java/com/gtnewhorizon/structurelib/alignment/constructable/ConstructableUtility.java @@ -1,6 +1,7 @@ package com.gtnewhorizon.structurelib.alignment.constructable; import com.gtnewhorizon.structurelib.StructureLib; +import com.gtnewhorizon.structurelib.StructureLibAPI; import com.gtnewhorizon.structurelib.alignment.IAlignment; import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; import net.minecraft.entity.player.EntityPlayer; @@ -17,6 +18,13 @@ public class ConstructableUtility { } public static boolean handle(ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ, int aSide) { + StructureLibAPI.startHinting(aWorld); + boolean ret = handle0(aStack, aPlayer, aWorld, aX, aY, aZ, aSide); + StructureLibAPI.endHinting(aWorld); + return ret; + } + + private static boolean handle0(ItemStack aStack, EntityPlayer aPlayer, World aWorld, int aX, int aY, int aZ, int aSide) { TileEntity tTileEntity = aWorld.getTileEntity(aX, aY, aZ); if (tTileEntity == null || aPlayer instanceof FakePlayer) { return aPlayer instanceof EntityPlayerMP; diff --git a/src/main/java/com/gtnewhorizon/structurelib/alignment/constructable/IMultiblockInfoContainer.java b/src/main/java/com/gtnewhorizon/structurelib/alignment/constructable/IMultiblockInfoContainer.java index a1d7d35b..138ed968 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/alignment/constructable/IMultiblockInfoContainer.java +++ b/src/main/java/com/gtnewhorizon/structurelib/alignment/constructable/IMultiblockInfoContainer.java @@ -14,6 +14,10 @@ import java.util.HashMap; public interface IMultiblockInfoContainer { HashMap> MULTIBLOCK_MAP = new HashMap<>(); + /** + * There is no specific loading phase restriction, but you should generally not call it before the tile entity is + * properly registered. + */ static void registerTileClass(Class clazz, IMultiblockInfoContainer info) { MULTIBLOCK_MAP.put(clazz.getCanonicalName(), info); } diff --git a/src/main/java/com/gtnewhorizon/structurelib/alignment/package-info.java b/src/main/java/com/gtnewhorizon/structurelib/alignment/package-info.java new file mode 100644 index 00000000..b4757ad7 --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/alignment/package-info.java @@ -0,0 +1,5 @@ +/** + * All public stuff in this package and its subpackages are considered part of the public API. + * Backwards compatibility is maintained to the maximum extend possible. + */ +package com.gtnewhorizon.structurelib.alignment; \ No newline at end of file diff --git a/src/main/java/com/gtnewhorizon/structurelib/block/BlockHint.java b/src/main/java/com/gtnewhorizon/structurelib/block/BlockHint.java index 311e9258..25dce36c 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/block/BlockHint.java +++ b/src/main/java/com/gtnewhorizon/structurelib/block/BlockHint.java @@ -1,6 +1,7 @@ package com.gtnewhorizon.structurelib.block; import com.gtnewhorizon.structurelib.StructureLib; +import com.gtnewhorizon.structurelib.StructureLibAPI; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.block.Block; @@ -26,22 +27,22 @@ public class BlockHint extends Block { @Override public void registerBlockIcons(IIconRegister aIconRegister) { //super.registerBlockIcons(aIconRegister); - hint[0] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_0"); - hint[1] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_1"); - hint[2] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_2"); - hint[3] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_3"); - hint[4] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_4"); - hint[5] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_5"); - hint[6] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_6"); - hint[7] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_7"); - hint[8] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_8"); - hint[9] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_9"); - hint[10] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_10"); - hint[11] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_11"); - hint[12] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_DEFAULT"); - hint[13] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_AIR"); - hint[14] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_NOAIR"); - hint[15] = aIconRegister.registerIcon(StructureLib.MOD_ID + ":iconsets/HINT_ERROR"); + hint[0] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_0"); + hint[1] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_1"); + hint[2] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_2"); + hint[3] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_3"); + hint[4] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_4"); + hint[5] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_5"); + hint[6] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_6"); + hint[7] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_7"); + hint[8] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_8"); + hint[9] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_9"); + hint[10] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_10"); + hint[11] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_11"); + hint[12] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_DEFAULT"); + hint[13] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_AIR"); + hint[14] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_NOAIR"); + hint[15] = aIconRegister.registerIcon(StructureLibAPI.MOD_ID + ":iconsets/HINT_ERROR"); } @Override diff --git a/src/main/java/com/gtnewhorizon/structurelib/entity/fx/BlockHint.java b/src/main/java/com/gtnewhorizon/structurelib/entity/fx/EntityFXBlockHint.java similarity index 90% rename from src/main/java/com/gtnewhorizon/structurelib/entity/fx/BlockHint.java rename to src/main/java/com/gtnewhorizon/structurelib/entity/fx/EntityFXBlockHint.java index 148e3156..694e21e1 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/entity/fx/BlockHint.java +++ b/src/main/java/com/gtnewhorizon/structurelib/entity/fx/EntityFXBlockHint.java @@ -1,6 +1,7 @@ package com.gtnewhorizon.structurelib.entity.fx; import com.gtnewhorizon.structurelib.StructureLib; +import com.gtnewhorizon.structurelib.proxy.ClientProxy; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.block.Block; @@ -12,11 +13,11 @@ import net.minecraft.world.World; import org.lwjgl.opengl.GL11; @SideOnly(Side.CLIENT) -public class BlockHint extends EntityFX { +public class EntityFXBlockHint extends EntityFX { private IIcon[] icons; private short[] mRGBa = {255,255,255,0}; - public BlockHint(World world){ + public EntityFXBlockHint(World world){ this(world,0,0,0, Blocks.stone,0); } @@ -28,7 +29,7 @@ public class BlockHint extends EntityFX { * @param z * @param icons DOWN, UP, NORTH, SOUTH, WEST, EAST */ - public BlockHint(World world, int x, int y, int z, IIcon[] icons) { + public EntityFXBlockHint(World world, int x, int y, int z, IIcon[] icons) { super(world, x + .25, y + .5, z + .25); particleGravity = 0; prevPosX = posX; @@ -39,7 +40,7 @@ public class BlockHint extends EntityFX { this.icons=icons; } - public BlockHint(World world, int x, int y, int z, Block block, int meta) { + public EntityFXBlockHint(World world, int x, int y, int z, Block block, int meta) { super(world, x+.25, y+.5, z+.25); particleGravity = 0; prevPosX = posX; @@ -53,7 +54,7 @@ public class BlockHint extends EntityFX { } } - public BlockHint withColorTint(short[] coloure){ + public EntityFXBlockHint withColorTint(short[] coloure){ this.mRGBa =coloure; return this; } @@ -130,4 +131,10 @@ public class BlockHint extends EntityFX { public boolean shouldRenderInPass(int pass) { return pass==2; } + + @Override + public void setDead() { + super.setDead(); + ClientProxy.onHintDead(this); + } } diff --git a/src/main/java/com/gtnewhorizon/structurelib/item/ItemConstructableTrigger.java b/src/main/java/com/gtnewhorizon/structurelib/item/ItemConstructableTrigger.java index 8af6c210..3ff5e22e 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/item/ItemConstructableTrigger.java +++ b/src/main/java/com/gtnewhorizon/structurelib/item/ItemConstructableTrigger.java @@ -9,7 +9,7 @@ import net.minecraft.world.World; import java.util.List; -import static com.gtnewhorizon.structurelib.StructureLib.MOD_ID; +import static com.gtnewhorizon.structurelib.StructureLibAPI.MOD_ID; import static net.minecraft.util.EnumChatFormatting.BLUE; import static net.minecraft.util.StatCollector.translateToLocal; diff --git a/src/main/java/com/gtnewhorizon/structurelib/item/ItemFrontRotationTool.java b/src/main/java/com/gtnewhorizon/structurelib/item/ItemFrontRotationTool.java index 2d323163..8f0a9814 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/item/ItemFrontRotationTool.java +++ b/src/main/java/com/gtnewhorizon/structurelib/item/ItemFrontRotationTool.java @@ -12,7 +12,7 @@ import net.minecraft.world.World; import java.util.List; -import static com.gtnewhorizon.structurelib.StructureLib.MOD_ID; +import static com.gtnewhorizon.structurelib.StructureLibAPI.MOD_ID; import static net.minecraft.util.StatCollector.translateToLocal; public class ItemFrontRotationTool extends Item { diff --git a/src/main/java/com/gtnewhorizon/structurelib/alignment/AlignmentMessage.java b/src/main/java/com/gtnewhorizon/structurelib/net/AlignmentMessage.java similarity index 96% rename from src/main/java/com/gtnewhorizon/structurelib/alignment/AlignmentMessage.java rename to src/main/java/com/gtnewhorizon/structurelib/net/AlignmentMessage.java index 3c3fca91..1805433b 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/alignment/AlignmentMessage.java +++ b/src/main/java/com/gtnewhorizon/structurelib/net/AlignmentMessage.java @@ -1,6 +1,8 @@ -package com.gtnewhorizon.structurelib.alignment; +package com.gtnewhorizon.structurelib.net; import com.gtnewhorizon.structurelib.StructureLib; +import com.gtnewhorizon.structurelib.alignment.IAlignment; +import com.gtnewhorizon.structurelib.alignment.IAlignmentProvider; import com.gtnewhorizon.structurelib.alignment.enumerable.ExtendedFacing; import cpw.mods.fml.common.network.ByteBufUtils; import cpw.mods.fml.common.network.simpleimpl.IMessage; diff --git a/src/main/java/com/gtnewhorizon/structurelib/proxy/ClientProxy.java b/src/main/java/com/gtnewhorizon/structurelib/proxy/ClientProxy.java index ae5b7ca9..36b77959 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/proxy/ClientProxy.java +++ b/src/main/java/com/gtnewhorizon/structurelib/proxy/ClientProxy.java @@ -1,7 +1,12 @@ package com.gtnewhorizon.structurelib.proxy; -import com.gtnewhorizon.structurelib.entity.fx.BlockHint; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.gtnewhorizon.structurelib.ConfigurationHandler; +import com.gtnewhorizon.structurelib.entity.fx.EntityFXBlockHint; import com.gtnewhorizon.structurelib.entity.fx.WeightlessParticleFX; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; import net.minecraft.block.Block; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiNewChat; @@ -10,57 +15,173 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.ChatComponentText; import net.minecraft.util.IIcon; import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.world.WorldEvent; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; import static com.gtnewhorizon.structurelib.StructureLib.RANDOM; public class ClientProxy extends CommonProxy { - @Override - public void hintParticleTinted(World w, int x, int y, int z, IIcon[] icons, short[] RGBa) { - Minecraft.getMinecraft().effectRenderer.addEffect(new BlockHint(w, x, y, z, icons).withColorTint(RGBa)); + @Override + public void hintParticleTinted(World w, int x, int y, int z, IIcon[] icons, short[] RGBa) { + EntityFXBlockHint hint = new EntityFXBlockHint(w, x, y, z, icons).withColorTint(RGBa); + Minecraft.getMinecraft().effectRenderer.addEffect(hint); + ensureHinting(); + if (ConfigurationHandler.INSTANCE.isRemoveCollidingHologram()) { + HintParticleInfo info = new HintParticleInfo(x, y, z, currentHints); + EntityFXBlockHint dupe = allHints.inverse().get(info); + if (dupe != null) { + List owner = allHints.get(dupe).owner; + // in case someone forget to call endHinting + if (owner != currentHints) { + hintOwners.remove(owner); + owner.forEach(EntityFXBlockHint::setDead); + owner.clear(); + } + } + allHints.forcePut(hint, info); + } + currentHints.add(hint); - EntityFX particle = new WeightlessParticleFX(w, x + RANDOM.nextFloat() * 0.5F, y + RANDOM.nextFloat() * 0.5F, z + RANDOM.nextFloat() * 0.5F, 0, 0, 0); - particle.setRBGColorF(0, 0.6F * RANDOM.nextFloat(), 0.8f); - Minecraft.getMinecraft().effectRenderer.addEffect(particle); - } + EntityFX particle = new WeightlessParticleFX(w, x + RANDOM.nextFloat() * 0.5F, y + RANDOM.nextFloat() * 0.5F, z + RANDOM.nextFloat() * 0.5F, 0, 0, 0); + particle.setRBGColorF(0, 0.6F * RANDOM.nextFloat(), 0.8f); + Minecraft.getMinecraft().effectRenderer.addEffect(particle); + } - @Override - public void hintParticleTinted(World w, int x, int y, int z, Block block, int meta, short[] RGBa) { - hintParticleTinted(w, x, y, z, createIIconFromBlock(block, meta), RGBa); - } + @Override + public void hintParticleTinted(World w, int x, int y, int z, Block block, int meta, short[] RGBa) { + hintParticleTinted(w, x, y, z, createIIconFromBlock(block, meta), RGBa); + } - @Override - public void hintParticle(World w, int x, int y, int z, IIcon[] icons) { - hintParticleTinted(w, x, y, z, icons, new short[]{255, 255, 255, 0}); - } + @Override + public void hintParticle(World w, int x, int y, int z, IIcon[] icons) { + hintParticleTinted(w, x, y, z, icons, new short[]{255, 255, 255, 0}); + } - @Override - public void hintParticle(World w, int x, int y, int z, Block block, int meta) { - hintParticleTinted(w, x, y, z, createIIconFromBlock(block, meta), new short[]{255, 255, 255, 0}); - } + @Override + public void hintParticle(World w, int x, int y, int z, Block block, int meta) { + hintParticleTinted(w, x, y, z, createIIconFromBlock(block, meta), new short[]{255, 255, 255, 0}); + } - private static IIcon[] createIIconFromBlock(Block block, int meta) { - IIcon[] ret = new IIcon[6]; - for (int i = 0; i < 6; i++) { - ret[i] = block.getIcon(i, meta); - } - return ret; - } + private static IIcon[] createIIconFromBlock(Block block, int meta) { + IIcon[] ret = new IIcon[6]; + for (int i = 0; i < 6; i++) { + ret[i] = block.getIcon(i, meta); + } + return ret; + } - @Override - public void addClientSideChatMessages(String... messages) { - GuiNewChat chat = Minecraft.getMinecraft().ingameGUI.getChatGUI(); - for (String s : messages) { - chat.printChatMessage(new ChatComponentText(s)); - } - } + @Override + public void addClientSideChatMessages(String... messages) { + GuiNewChat chat = Minecraft.getMinecraft().ingameGUI.getChatGUI(); + for (String s : messages) { + chat.printChatMessage(new ChatComponentText(s)); + } + } - @Override - public EntityPlayer getCurrentPlayer() { - return Minecraft.getMinecraft().thePlayer; - } + @Override + public EntityPlayer getCurrentPlayer() { + return Minecraft.getMinecraft().thePlayer; + } - @Override - public boolean isCurrentPlayer(EntityPlayer player) { - return player == Minecraft.getMinecraft().thePlayer; - } + @Override + public boolean isCurrentPlayer(EntityPlayer player) { + return player == Minecraft.getMinecraft().thePlayer; + } + + private static final BiMap allHints = HashBiMap.create(); + private static final List> hintOwners = new ArrayList<>(); + private static List currentHints; + + public static void onHintDead(EntityFXBlockHint fx) { + if (ConfigurationHandler.INSTANCE.isRemoveCollidingHologram()) + allHints.remove(fx); + for (Iterator> iterator = hintOwners.iterator(); iterator.hasNext(); ) { + List list = iterator.next(); + if (list.remove(fx)) { + if (list.isEmpty()) + iterator.remove(); + break; + } + } + } + + @Override + public void startHinting(World w) { + if (!w.isRemote) + return; + if (currentHints != null) + hintOwners.add(currentHints); + currentHints = new LinkedList<>(); + } + + private void ensureHinting() { + if (currentHints == null) + currentHints = new LinkedList<>(); + } + + @Override + public void endHinting(World w) { + if (!w.isRemote) + return; + while (!hintOwners.isEmpty() && hintOwners.size() >= ConfigurationHandler.INSTANCE.getMaxCoexistingHologram()) { + List list = hintOwners.remove(0); + list.forEach(EntityFXBlockHint::setDead); + list.clear(); + } + if (!currentHints.isEmpty()) + hintOwners.add(currentHints); + currentHints = null; + } + + @Override + public void preInit(FMLPreInitializationEvent e) { + MinecraftForge.EVENT_BUS.register(new ForgeEventHandler()); + } + + private static class HintParticleInfo { + private final int x, y, z; + private final List owner; + + public HintParticleInfo(int x, int y, int z, List owner) { + this.x = x; + this.y = y; + this.z = z; + this.owner = owner; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + HintParticleInfo that = (HintParticleInfo) o; + + if (x != that.x) return false; + if (y != that.y) return false; + return z == that.z; + } + + @Override + public int hashCode() { + int result = x; + result = 31 * result + y; + result = 31 * result + z; + return result; + } + } + + public static class ForgeEventHandler { + @SubscribeEvent + public void onWorldLoad(WorldEvent.Load e) { + if (e.world.isRemote) { + allHints.clear(); + hintOwners.clear(); + } + } + } } diff --git a/src/main/java/com/gtnewhorizon/structurelib/proxy/CommonProxy.java b/src/main/java/com/gtnewhorizon/structurelib/proxy/CommonProxy.java index c7d622f1..17e9ebfd 100644 --- a/src/main/java/com/gtnewhorizon/structurelib/proxy/CommonProxy.java +++ b/src/main/java/com/gtnewhorizon/structurelib/proxy/CommonProxy.java @@ -1,5 +1,6 @@ package com.gtnewhorizon.structurelib.proxy; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; import net.minecraft.block.Block; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.util.IIcon; @@ -18,4 +19,8 @@ public class CommonProxy { } public void addClientSideChatMessages(String... messages){ } + public void startHinting(World w) {} + public void endHinting(World w) {} + + public void preInit(FMLPreInitializationEvent e) {} } diff --git a/src/main/java/com/gtnewhorizon/structurelib/structure/package-info.java b/src/main/java/com/gtnewhorizon/structurelib/structure/package-info.java new file mode 100644 index 00000000..1460b167 --- /dev/null +++ b/src/main/java/com/gtnewhorizon/structurelib/structure/package-info.java @@ -0,0 +1,5 @@ +/** + * All public stuff in this package and its subpackages are considered part of the public API. + * Backwards compatibility is maintained to the maximum extend possible. + */ +package com.gtnewhorizon.structurelib.structure; \ No newline at end of file diff --git a/src/main/resources/assets/structurelib/lang/en_US.lang b/src/main/resources/assets/structurelib/lang/en_US.lang index 2c23e835..c0b63e63 100644 --- a/src/main/resources/assets/structurelib/lang/en_US.lang +++ b/src/main/resources/assets/structurelib/lang/en_US.lang @@ -20,7 +20,7 @@ item.structurelib.frontRotationTool.desc.0=Triggers Front Rotation Interface item.structurelib.frontRotationTool.desc.1=Rotates only the front panel, item.structurelib.frontRotationTool.desc.2=which allows structure rotation. -item.structurelib.constructableTrigger.name=Multiblock Machine Blueprint (Standalone) +item.structurelib.constructableTrigger.name=Multiblock Structure Hologram Projector item.structurelib.constructableTrigger.desc.0=Triggers Constructable Interface item.structurelib.constructableTrigger.desc.1=Shows multiblock construction details, item.structurelib.constructableTrigger.desc.2=just Use on a multiblock controller. @@ -49,4 +49,13 @@ structurelib.blockhint.14.name=Hint no air structurelib.blockhint.desc.4=Make sure it does not contain Air material. structurelib.blockhint.15.name=Hint error structurelib.blockhint.desc.5=ERROR, what did u expect? -itemGroup.structurelib=StructureLib \ No newline at end of file +itemGroup.structurelib=StructureLib + +structurelib.config.client=Client Side Configurations +structurelib.config.client.tooltip=Configurations that only changes how the game looks like, but not how it functions. +structurelib.config.client.hologram=Hologram Configurations +structurelib.config.client.hologram.tooltip=Configurations that changes how the hologram got projected into the world by default. +structurelib.config.client.hologram.maxCoexisting=Max Coexisting Holograms +structurelib.config.client.hologram.maxCoexisting.tooltip=Number of holograms that can coexist. Usually all hints generated by one right click belongs to one hologram. An attempt will be made to prune old holograms when a new hologram is about to be projected and this limit would be exceeded. +structurelib.config.client.hologram.removeColliding=Remove Colliding Holograms +structurelib.config.client.hologram.removeColliding.tooltip=Whether an attempt will be made to remove any existing hologram that collides with a new hologram.