From b99bcba3426967dd6c2f7827f8bc41a3763a2b2f Mon Sep 17 00:00:00 2001 From: mallrat208 Date: Sat, 18 Oct 2014 01:17:33 -0400 Subject: [PATCH] Initial Commit Weapon Vault welcome to GitHub I need to clean up the API usage next. --- .gitignore | 21 + build.gradle | 63 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 51017 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 ++++++ gradlew.bat | 90 +++ src/main/java/appeng/api/AEApi.java | 38 ++ src/main/java/appeng/api/IAppEngApi.java | 71 +++ .../appeng/api/config/AccessRestriction.java | 48 ++ .../java/appeng/api/config/ActionItems.java | 6 + .../java/appeng/api/config/Actionable.java | 14 + .../appeng/api/config/CondenserOuput.java | 15 + src/main/java/appeng/api/config/CopyMode.java | 6 + .../java/appeng/api/config/FullnessMode.java | 6 + .../java/appeng/api/config/FuzzyMode.java | 21 + .../appeng/api/config/IncludeExclude.java | 6 + .../appeng/api/config/LevelEmitterMode.java | 10 + .../java/appeng/api/config/LevelType.java | 10 + .../java/appeng/api/config/ModSettings.java | 6 + .../appeng/api/config/NetworkEmitterMode.java | 12 + .../java/appeng/api/config/OperationMode.java | 6 + .../java/appeng/api/config/OutputMode.java | 6 + .../appeng/api/config/PowerMultiplier.java | 21 + .../java/appeng/api/config/PowerUnits.java | 42 ++ .../java/appeng/api/config/RedstoneMode.java | 6 + .../appeng/api/config/RelativeDirection.java | 6 + .../java/appeng/api/config/SearchBoxMode.java | 6 + .../api/config/SecurityPermissions.java | 47 ++ src/main/java/appeng/api/config/Settings.java | 46 ++ src/main/java/appeng/api/config/SortDir.java | 6 + .../java/appeng/api/config/SortOrder.java | 6 + .../java/appeng/api/config/StorageFilter.java | 10 + .../java/appeng/api/config/TerminalStyle.java | 12 + .../java/appeng/api/config/TunnelType.java | 15 + src/main/java/appeng/api/config/Upgrades.java | 39 ++ .../java/appeng/api/config/ViewItems.java | 6 + src/main/java/appeng/api/config/YesNo.java | 6 + .../java/appeng/api/definitions/Blocks.java | 89 +++ .../java/appeng/api/definitions/Items.java | 54 ++ .../appeng/api/definitions/Materials.java | 80 +++ .../java/appeng/api/definitions/Parts.java | 54 ++ .../api/events/LocatableEventAnnounce.java | 28 + .../api/exceptions/AppEngException.java | 11 + .../api/exceptions/FailedConnection.java | 10 + .../exceptions/MissingIngredientError.java | 11 + .../api/exceptions/ModNotInstalled.java | 12 + .../appeng/api/exceptions/RecipeError.java | 12 + .../api/exceptions/RegistrationError.java | 12 + .../appeng/api/features/IGrinderEntry.java | 96 ++++ .../appeng/api/features/IGrinderRegistry.java | 61 ++ .../features/IItemComparisionProvider.java | 30 + .../appeng/api/features/IItemComparison.java | 10 + .../java/appeng/api/features/ILocatable.java | 17 + .../api/features/ILocatableRegistry.java | 18 + .../features/IMatterCannonAmmoRegistry.java | 24 + .../api/features/INetworkEncodable.java | 28 + .../api/features/IP2PTunnelRegistry.java | 31 + .../appeng/api/features/IPlayerRegistry.java | 26 + .../api/features/IRecipeHandlerRegistry.java | 48 ++ .../api/features/IRegistryContainer.java | 76 +++ .../features/ISpecialComparisonRegistry.java | 27 + .../api/features/IWirelessTermHandler.java | 46 ++ .../api/features/IWirelessTermRegistery.java | 39 ++ .../java/appeng/api/features/IWorldGen.java | 20 + .../implementations/ICraftingPatternItem.java | 22 + .../implementations/IPowerChannelState.java | 19 + .../api/implementations/IUpgradeableHost.java | 23 + .../api/implementations/TransitionResult.java | 18 + .../implementations/guiobjects/IGuiItem.java | 15 + .../guiobjects/IGuiItemObject.java | 9 + .../guiobjects/INetworkTool.java | 14 + .../guiobjects/IPortableCell.java | 14 + .../items/IAEItemPowerStorage.java | 48 ++ .../api/implementations/items/IAEWrench.java | 24 + .../implementations/items/IBiometricCard.java | 64 +++ .../items/IGrowableCrystal.java | 14 + .../api/implementations/items/IItemGroup.java | 21 + .../implementations/items/IMemoryCard.java | 56 ++ .../items/ISpatialStorageCell.java | 69 +++ .../implementations/items/IStorageCell.java | 82 +++ .../items/IStorageComponent.java | 30 + .../implementations/items/IUpgradeModule.java | 15 + .../items/MemoryCardMessages.java | 9 + .../api/implementations/parts/IPartCable.java | 61 ++ .../implementations/parts/IPartMonitor.java | 18 + .../parts/IPartStorageMonitor.java | 26 + .../implementations/tiles/IChestOrDrive.java | 40 ++ .../implementations/tiles/IColorableTile.java | 14 + .../tiles/ICraftingMachine.java | 29 + .../api/implementations/tiles/ICrankable.java | 35 ++ .../tiles/ICrystalGrowthAccelerator.java | 8 + .../api/implementations/tiles/IMEChest.java | 8 + .../tiles/ISegmentedInventory.java | 17 + .../tiles/ITileStorageMonitorable.java | 15 + .../tiles/IViewCellStorage.java | 15 + .../tiles/IWirelessAccessPoint.java | 30 + .../api/integration/IBeeComparison.java | 20 + .../appeng/api/movable/IMovableHandler.java | 41 ++ .../appeng/api/movable/IMovableRegistry.java | 97 ++++ .../java/appeng/api/movable/IMovableTile.java | 23 + .../java/appeng/api/networking/GridFlags.java | 45 ++ .../api/networking/GridNotification.java | 9 + .../java/appeng/api/networking/IGrid.java | 71 +++ .../appeng/api/networking/IGridBlock.java | 88 +++ .../appeng/api/networking/IGridCache.java | 71 +++ .../api/networking/IGridCacheRegistry.java | 28 + .../networking/IGridConnecitonVisitor.java | 14 + .../api/networking/IGridConnection.java | 58 ++ .../java/appeng/api/networking/IGridHost.java | 43 ++ .../api/networking/IGridMultiblock.java | 20 + .../java/appeng/api/networking/IGridNode.java | 141 +++++ .../appeng/api/networking/IGridStorage.java | 18 + .../appeng/api/networking/IGridVisitor.java | 21 + .../appeng/api/networking/IMachineSet.java | 13 + .../networking/crafting/CraftingItemList.java | 6 + .../api/networking/crafting/ICraftingCPU.java | 35 ++ .../crafting/ICraftingCallback.java | 14 + .../networking/crafting/ICraftingGrid.java | 85 +++ .../api/networking/crafting/ICraftingJob.java | 33 ++ .../networking/crafting/ICraftingLink.java | 40 ++ .../networking/crafting/ICraftingMedium.java | 27 + .../crafting/ICraftingPatternDetails.java | 77 +++ .../crafting/ICraftingProvider.java | 19 + .../crafting/ICraftingProviderHelper.java | 21 + .../crafting/ICraftingRequester.java | 37 ++ .../networking/crafting/ICraftingWatcher.java | 10 + .../crafting/ICraftingWatcherHost.java | 24 + .../networking/energy/IAEPowerStorage.java | 46 ++ .../api/networking/energy/IEnergyGrid.java | 82 +++ .../energy/IEnergyGridProvider.java | 28 + .../api/networking/energy/IEnergySource.java | 19 + .../api/networking/energy/IEnergyWatcher.java | 8 + .../networking/energy/IEnergyWatcherHost.java | 21 + .../events/MENetworkBootingStatusChange.java | 14 + .../events/MENetworkCellArrayUpdate.java | 15 + .../events/MENetworkChannelChanged.java | 18 + .../events/MENetworkChannelsChanged.java | 13 + .../events/MENetworkControllerChange.java | 11 + .../events/MENetworkCraftingCpuChange.java | 14 + .../MENetworkCraftingPatternChange.java | 17 + .../api/networking/events/MENetworkEvent.java | 53 ++ .../events/MENetworkEventSubscribe.java | 15 + .../MENetworkPostCacheConstruction.java | 10 + .../events/MENetworkPowerIdleChange.java | 21 + .../events/MENetworkPowerStatusChange.java | 16 + .../events/MENetworkPowerStorage.java | 38 ++ .../events/MENetworkSecurityChange.java | 9 + .../events/MENetworkSpatialEvent.java | 26 + .../events/MENetworkStorageEvent.java | 25 + .../networking/pathing/ControllerState.java | 19 + .../api/networking/pathing/IPathingGrid.java | 24 + .../networking/security/BaseActionSource.java | 16 + .../api/networking/security/IActionHost.java | 19 + .../networking/security/ISecurityGrid.java | 40 ++ .../security/ISecurityProvider.java | 38 ++ .../security/ISecurityRegister.java | 21 + .../networking/security/MachineSource.java | 18 + .../api/networking/security/PlayerSource.java | 22 + .../api/networking/spatial/ISpatialCache.java | 39 ++ .../api/networking/storage/IBaseMonitor.java | 19 + .../api/networking/storage/IStackWatcher.java | 10 + .../networking/storage/IStackWatcherHost.java | 30 + .../api/networking/storage/IStorageGrid.java | 45 ++ .../api/networking/ticking/IGridTickable.java | 56 ++ .../api/networking/ticking/ITickManager.java | 44 ++ .../ticking/TickRateModulation.java | 34 ++ .../networking/ticking/TickingRequest.java | 54 ++ src/main/java/appeng/api/package-info.java | 5 + .../java/appeng/api/parts/BusSupport.java | 10 + .../appeng/api/parts/CableRenderMode.java | 17 + .../java/appeng/api/parts/IAlphaPassItem.java | 16 + .../java/appeng/api/parts/IBoxProvider.java | 13 + .../appeng/api/parts/IFacadeContainer.java | 30 + .../java/appeng/api/parts/IFacadePart.java | 76 +++ src/main/java/appeng/api/parts/IPart.java | 267 +++++++++ .../appeng/api/parts/IPartCollsionHelper.java | 42 ++ .../java/appeng/api/parts/IPartHelper.java | 62 ++ src/main/java/appeng/api/parts/IPartHost.java | 152 +++++ src/main/java/appeng/api/parts/IPartItem.java | 37 ++ .../appeng/api/parts/IPartRenderHelper.java | 178 ++++++ .../appeng/api/parts/ISimplifiedBundle.java | 7 + src/main/java/appeng/api/parts/LayerBase.java | 55 ++ .../java/appeng/api/parts/LayerFlags.java | 8 + .../java/appeng/api/parts/PartItemStack.java | 14 + .../java/appeng/api/parts/SelectedPart.java | 44 ++ .../appeng/api/recipes/ICraftHandler.java | 29 + .../java/appeng/api/recipes/IIngredient.java | 64 +++ .../appeng/api/recipes/IRecipeHandler.java | 22 + .../appeng/api/recipes/IRecipeLoader.java | 10 + .../appeng/api/recipes/ISubItemResolver.java | 13 + .../appeng/api/recipes/ResolverResult.java | 24 + .../appeng/api/recipes/ResolverResultSet.java | 19 + .../appeng/api/storage/ICellContainer.java | 18 + .../java/appeng/api/storage/ICellHandler.java | 102 ++++ .../appeng/api/storage/ICellInventory.java | 96 ++++ .../api/storage/ICellInventoryHandler.java | 20 + .../appeng/api/storage/ICellProvider.java | 29 + .../appeng/api/storage/ICellRegistry.java | 50 ++ .../api/storage/ICellWorkbenchItem.java | 45 ++ .../api/storage/IExternalStorageHandler.java | 37 ++ .../api/storage/IExternalStorageRegistry.java | 32 ++ .../java/appeng/api/storage/IMEInventory.java | 56 ++ .../api/storage/IMEInventoryHandler.java | 67 +++ .../java/appeng/api/storage/IMEMonitor.java | 24 + .../storage/IMEMonitorHandlerReceiver.java | 30 + .../appeng/api/storage/ISaveProvider.java | 9 + .../appeng/api/storage/IStorageHelper.java | 95 ++++ .../api/storage/IStorageMonitorable.java | 25 + .../appeng/api/storage/ITerminalHost.java | 8 + .../appeng/api/storage/MEMonitorHandler.java | 174 ++++++ .../appeng/api/storage/StorageChannel.java | 33 ++ .../api/storage/data/IAEFluidStack.java | 52 ++ .../appeng/api/storage/data/IAEItemStack.java | 82 +++ .../appeng/api/storage/data/IAEStack.java | 179 ++++++ .../api/storage/data/IAETagCompound.java | 33 ++ .../api/storage/data/IItemContainer.java | 42 ++ .../appeng/api/storage/data/IItemList.java | 59 ++ .../java/appeng/api/util/AECableType.java | 30 + src/main/java/appeng/api/util/AEColor.java | 90 +++ .../api/util/AEColoredItemDefinition.java | 46 ++ .../appeng/api/util/AEItemDefinition.java | 54 ++ .../appeng/api/util/DimensionalCoord.java | 73 +++ .../java/appeng/api/util/ICommonTile.java | 23 + .../java/appeng/api/util/IConfigManager.java | 62 ++ .../appeng/api/util/IConfigureableObject.java | 14 + .../appeng/api/util/INetworkToolAgent.java | 13 + .../java/appeng/api/util/IOrientable.java | 37 ++ .../appeng/api/util/IOrientableBlock.java | 25 + .../appeng/api/util/IReadOnlyCollection.java | 21 + src/main/java/appeng/api/util/WorldCoord.java | 138 +++++ .../mr208/WeaponVault/AE2/AE2Integration.java | 68 +++ .../Botania/BotaniaIntegration.java | 54 ++ .../Botania/Items/BotanicalItemFlail.java | 39 ++ .../Botania/Items/BotanicalItemMelee.java | 38 ++ .../Botania/Items/BotanicalItemMusket.java | 38 ++ .../mr208/WeaponVault/Botania/ManaHelper.java | 19 + .../mr208/WeaponVault/CustomMaterials.java | 57 ++ .../WeaponVault/IWeaponMaterialCheck.java | 7 + .../Items/GenericMetalsIntegration.java | 47 ++ .../mr208/WeaponVault/Items/WVItemFlail.java | 46 ++ .../mr208/WeaponVault/Items/WVItemMelee.java | 48 ++ .../mr208/WeaponVault/Items/WVItemMusket.java | 48 ++ .../java/mr208/WeaponVault/Materials.java | 35 ++ .../Thaumcraft/Items/ThaumicItemFlail.java | 18 + .../Thaumcraft/Items/ThaumicItemMelee.java | 27 + .../Thaumcraft/Items/ThaumicItemMusket.java | 24 + .../Thaumcraft/Items/VoidItemFlail.java | 49 ++ .../Thaumcraft/Items/VoidItemMelee.java | 51 ++ .../Thaumcraft/Items/VoidItemMusket.java | 55 ++ .../Thaumcraft/ThaumcraftIntegration.java | 109 ++++ src/main/java/mr208/WeaponVault/WVConfig.java | 79 +++ src/main/java/mr208/WeaponVault/WVRef.java | 10 + .../java/mr208/WeaponVault/WeaponVault.java | 52 ++ src/main/java/thaumcraft/api/IGoggles.java | 22 + src/main/java/thaumcraft/api/IRepairable.java | 13 + .../thaumcraft/api/IRepairableExtended.java | 17 + src/main/java/thaumcraft/api/IRunicArmor.java | 22 + .../java/thaumcraft/api/IScribeTools.java | 14 + .../java/thaumcraft/api/IVisDiscountGear.java | 20 + .../java/thaumcraft/api/IWarpingGear.java | 22 + src/main/java/thaumcraft/api/ItemApi.java | 70 +++ src/main/java/thaumcraft/api/ItemRunic.java | 21 + .../java/thaumcraft/api/ThaumcraftApi.java | 537 ++++++++++++++++++ .../thaumcraft/api/ThaumcraftApiHelper.java | 336 +++++++++++ .../java/thaumcraft/api/TileThaumcraft.java | 63 ++ .../java/thaumcraft/api/WorldCoordinates.java | 117 ++++ .../java/thaumcraft/api/aspects/Aspect.java | 201 +++++++ .../thaumcraft/api/aspects/AspectList.java | 280 +++++++++ .../api/aspects/AspectSourceHelper.java | 58 ++ .../api/aspects/IAspectContainer.java | 80 +++ .../thaumcraft/api/aspects/IAspectSource.java | 16 + .../api/aspects/IEssentiaContainerItem.java | 37 ++ .../api/aspects/IEssentiaTransport.java | 100 ++++ .../api/crafting/CrucibleRecipe.java | 91 +++ .../api/crafting/IArcaneRecipe.java | 35 ++ .../api/crafting/IInfusionStabiliser.java | 19 + .../crafting/InfusionEnchantmentRecipe.java | 154 +++++ .../api/crafting/InfusionRecipe.java | 125 ++++ .../api/crafting/ShapedArcaneRecipe.java | 261 +++++++++ .../api/crafting/ShapelessArcaneRecipe.java | 161 ++++++ .../DamageSourceIndirectThaumcraftEntity.java | 32 ++ .../damagesource/DamageSourceThaumcraft.java | 47 ++ .../thaumcraft/api/entities/ITaintedMob.java | 5 + src/main/java/thaumcraft/api/nodes/INode.java | 53 ++ .../java/thaumcraft/api/nodes/IRevealer.java | 22 + .../thaumcraft/api/nodes/NodeModifier.java | 6 + .../java/thaumcraft/api/nodes/NodeType.java | 6 + .../java/thaumcraft/api/package-info.java | 4 + .../api/potions/PotionFluxTaint.java | 67 +++ .../api/potions/PotionVisExhaust.java | 48 ++ .../api/research/IScanEventHandler.java | 9 + .../api/research/ResearchCategories.java | 101 ++++ .../api/research/ResearchCategoryList.java | 37 ++ .../thaumcraft/api/research/ResearchItem.java | 367 ++++++++++++ .../thaumcraft/api/research/ResearchPage.java | 193 +++++++ .../thaumcraft/api/research/ScanResult.java | 39 ++ .../thaumcraft/api/visnet/TileVisNode.java | 188 ++++++ .../thaumcraft/api/visnet/VisNetHandler.java | 284 +++++++++ .../java/thaumcraft/api/wands/IWandFocus.java | 64 +++ .../api/wands/IWandRodOnUpdate.java | 16 + .../api/wands/IWandTriggerManager.java | 15 + .../java/thaumcraft/api/wands/IWandable.java | 25 + .../thaumcraft/api/wands/ItemFocusBasic.java | 166 ++++++ .../java/thaumcraft/api/wands/StaffRod.java | 48 ++ .../java/thaumcraft/api/wands/WandCap.java | 129 +++++ .../java/thaumcraft/api/wands/WandRod.java | 158 ++++++ .../api/wands/WandTriggerRegistry.java | 126 ++++ .../java/vazkii/botania/api/BotaniaAPI.java | 363 ++++++++++++ .../api/internal/DummyManaNetwork.java | 51 ++ .../api/internal/DummyMethodHandler.java | 130 +++++ .../botania/api/internal/DummyPage.java | 35 ++ .../botania/api/internal/DummySubTile.java | 18 + .../api/internal/IGuiLexiconEntry.java | 57 ++ .../api/internal/IInternalMethodHandler.java | 79 +++ .../botania/api/internal/IManaBurst.java | 62 ++ .../botania/api/internal/IManaNetwork.java | 68 +++ .../botania/api/item/IExoflameHeatable.java | 44 ++ .../api/item/IExtendedPlayerController.java | 29 + .../botania/api/item/IPetalApothecary.java | 30 + .../botania/api/item/IPixieSpawner.java | 30 + .../botania/api/lexicon/IAddonEntry.java | 29 + .../vazkii/botania/api/lexicon/ILexicon.java | 21 + .../botania/api/lexicon/ILexiconable.java | 29 + .../api/lexicon/IRecipeKeyProvider.java | 24 + .../botania/api/lexicon/KnowledgeType.java | 20 + .../botania/api/lexicon/LexiconCategory.java | 32 ++ .../botania/api/lexicon/LexiconEntry.java | 97 ++++ .../botania/api/lexicon/LexiconPage.java | 67 +++ .../api/lexicon/LexiconRecipeMappings.java | 66 +++ .../botania/api/mana/BurstProperties.java | 37 ++ .../botania/api/mana/IClientManaHandler.java | 21 + .../api/mana/ICreativeManaProvider.java | 26 + .../vazkii/botania/api/mana/IKeyLocked.java | 30 + .../botania/api/mana/ILaputaImmobile.java | 23 + .../java/vazkii/botania/api/mana/ILens.java | 43 ++ .../vazkii/botania/api/mana/ILensEffect.java | 49 ++ .../vazkii/botania/api/mana/IManaBlock.java | 26 + .../botania/api/mana/IManaCollector.java | 43 ++ .../botania/api/mana/IManaCollisionGhost.java | 22 + .../vazkii/botania/api/mana/IManaItem.java | 69 +++ .../vazkii/botania/api/mana/IManaPool.java | 31 + .../botania/api/mana/IManaReceiver.java | 35 ++ .../vazkii/botania/api/mana/IManaTrigger.java | 24 + .../botania/api/mana/IManaUsingItem.java | 26 + .../api/mana/IPoolOverlayProvider.java | 26 + .../botania/api/mana/ITinyPlanetExcempt.java | 24 + .../botania/api/mana/ManaItemHandler.java | 201 +++++++ .../botania/api/mana/ManaNetworkEvent.java | 57 ++ .../botania/api/mana/TileSignature.java | 15 + .../api/mana/spark/ISparkAttachable.java | 54 ++ .../botania/api/mana/spark/ISparkEntity.java | 65 +++ .../botania/api/mana/spark/SparkHelper.java | 33 ++ .../java/vazkii/botania/api/package-info.java | 4 + .../vazkii/botania/api/recipe/IElvenItem.java | 14 + .../botania/api/recipe/IFlowerComponent.java | 26 + .../botania/api/recipe/RecipeElvenTrade.java | 94 +++ .../api/recipe/RecipeManaInfusion.java | 81 +++ .../botania/api/recipe/RecipePetals.java | 97 ++++ .../botania/api/recipe/RecipeRuneAltar.java | 31 + .../botania/api/subtile/ISpecialFlower.java | 21 + .../api/subtile/ISubTileContainer.java | 30 + .../botania/api/subtile/SubTileEntity.java | 126 ++++ .../api/subtile/SubTileFunctional.java | 212 +++++++ .../api/subtile/SubTileGenerating.java | 245 ++++++++ .../botania/api/wand/ICoordBoundItem.java | 18 + .../vazkii/botania/api/wand/ITileBound.java | 31 + .../botania/api/wand/IWandBindable.java | 36 ++ .../vazkii/botania/api/wand/IWandHUD.java | 26 + .../vazkii/botania/api/wand/IWandable.java | 29 + .../api/wand/IWireframeAABBProvider.java | 25 + .../botania/api/wiki/IWikiProvider.java | 39 ++ .../botania/api/wiki/SimpleWikiProvider.java | 73 +++ .../vazkii/botania/api/wiki/WikiHooks.java | 43 ++ .../assets/weaponmod/lang/en_US.lang | 113 ++++ .../textures/items/battleaxe.certus.png | Bin 0 -> 15683 bytes .../textures/items/battleaxe.manasteel.png | Bin 0 -> 359 bytes .../textures/items/battleaxe.quartz.png | Bin 0 -> 16426 bytes .../textures/items/battleaxe.thaumium.png | Bin 0 -> 15675 bytes .../textures/items/battleaxe.void.png | Bin 0 -> 15684 bytes .../textures/items/boomerang.certus.png | Bin 0 -> 15662 bytes .../textures/items/boomerang.manasteel.png | Bin 0 -> 16426 bytes .../textures/items/boomerang.quartz.png | Bin 0 -> 16426 bytes .../textures/items/boomerang.thaumium.png | Bin 0 -> 15659 bytes .../textures/items/boomerang.void.png | Bin 0 -> 15645 bytes .../weaponmod/textures/items/flail.certus.png | Bin 0 -> 15587 bytes .../textures/items/flail.manasteel.png | Bin 0 -> 323 bytes .../weaponmod/textures/items/flail.quartz.png | Bin 0 -> 16426 bytes .../textures/items/flail.thaumium.png | Bin 0 -> 15576 bytes .../weaponmod/textures/items/flail.void.png | Bin 0 -> 15570 bytes .../textures/items/halberd.certus.png | Bin 0 -> 15793 bytes .../textures/items/halberd.manasteel.png | Bin 0 -> 412 bytes .../textures/items/halberd.quartz.png | Bin 0 -> 19514 bytes .../textures/items/halberd.thaumium.png | Bin 0 -> 15808 bytes .../weaponmod/textures/items/halberd.void.png | Bin 0 -> 15807 bytes .../textures/items/katana.certus.png | Bin 0 -> 15526 bytes .../textures/items/katana.manasteel.png | Bin 0 -> 330 bytes .../textures/items/katana.quartz.png | Bin 0 -> 16426 bytes .../textures/items/katana.thaumium.png | Bin 0 -> 14654 bytes .../weaponmod/textures/items/katana.void.png | Bin 0 -> 15088 bytes .../weaponmod/textures/items/knife.certus.png | Bin 0 -> 15592 bytes .../textures/items/knife.manasteel.png | Bin 0 -> 323 bytes .../weaponmod/textures/items/knife.quartz.png | Bin 0 -> 16426 bytes .../textures/items/knife.thaumium.png | Bin 0 -> 15591 bytes .../weaponmod/textures/items/knife.void.png | Bin 0 -> 15602 bytes .../textures/items/musketbayonet.certus.png | Bin 0 -> 15689 bytes .../items/musketbayonet.manasteel.png | Bin 0 -> 351 bytes .../textures/items/musketbayonet.quartz.png | Bin 0 -> 16426 bytes .../textures/items/musketbayonet.thaumium.png | Bin 0 -> 15683 bytes .../textures/items/musketbayonet.void.png | Bin 0 -> 15693 bytes .../weaponmod/textures/items/spear.certus.png | Bin 0 -> 15704 bytes .../textures/items/spear.manasteel.png | Bin 0 -> 418 bytes .../weaponmod/textures/items/spear.quartz.png | Bin 0 -> 19508 bytes .../textures/items/spear.thaumium.png | Bin 0 -> 15683 bytes .../weaponmod/textures/items/spear.void.png | Bin 0 -> 15686 bytes .../textures/items/warhammer.certus.png | Bin 0 -> 15125 bytes .../textures/items/warhammer.manasteel.png | Bin 0 -> 353 bytes .../textures/items/warhammer.quartz.png | Bin 0 -> 16426 bytes .../textures/items/warhammer.thaumium.png | Bin 0 -> 14666 bytes .../textures/items/warhammer.void.png | Bin 0 -> 15106 bytes src/main/resources/mcmod.info | 16 + 420 files changed, 18260 insertions(+) create mode 100644 .gitignore create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 src/main/java/appeng/api/AEApi.java create mode 100644 src/main/java/appeng/api/IAppEngApi.java create mode 100644 src/main/java/appeng/api/config/AccessRestriction.java create mode 100644 src/main/java/appeng/api/config/ActionItems.java create mode 100644 src/main/java/appeng/api/config/Actionable.java create mode 100644 src/main/java/appeng/api/config/CondenserOuput.java create mode 100644 src/main/java/appeng/api/config/CopyMode.java create mode 100644 src/main/java/appeng/api/config/FullnessMode.java create mode 100644 src/main/java/appeng/api/config/FuzzyMode.java create mode 100644 src/main/java/appeng/api/config/IncludeExclude.java create mode 100644 src/main/java/appeng/api/config/LevelEmitterMode.java create mode 100644 src/main/java/appeng/api/config/LevelType.java create mode 100644 src/main/java/appeng/api/config/ModSettings.java create mode 100644 src/main/java/appeng/api/config/NetworkEmitterMode.java create mode 100644 src/main/java/appeng/api/config/OperationMode.java create mode 100644 src/main/java/appeng/api/config/OutputMode.java create mode 100644 src/main/java/appeng/api/config/PowerMultiplier.java create mode 100644 src/main/java/appeng/api/config/PowerUnits.java create mode 100644 src/main/java/appeng/api/config/RedstoneMode.java create mode 100644 src/main/java/appeng/api/config/RelativeDirection.java create mode 100644 src/main/java/appeng/api/config/SearchBoxMode.java create mode 100644 src/main/java/appeng/api/config/SecurityPermissions.java create mode 100644 src/main/java/appeng/api/config/Settings.java create mode 100644 src/main/java/appeng/api/config/SortDir.java create mode 100644 src/main/java/appeng/api/config/SortOrder.java create mode 100644 src/main/java/appeng/api/config/StorageFilter.java create mode 100644 src/main/java/appeng/api/config/TerminalStyle.java create mode 100644 src/main/java/appeng/api/config/TunnelType.java create mode 100644 src/main/java/appeng/api/config/Upgrades.java create mode 100644 src/main/java/appeng/api/config/ViewItems.java create mode 100644 src/main/java/appeng/api/config/YesNo.java create mode 100644 src/main/java/appeng/api/definitions/Blocks.java create mode 100644 src/main/java/appeng/api/definitions/Items.java create mode 100644 src/main/java/appeng/api/definitions/Materials.java create mode 100644 src/main/java/appeng/api/definitions/Parts.java create mode 100644 src/main/java/appeng/api/events/LocatableEventAnnounce.java create mode 100644 src/main/java/appeng/api/exceptions/AppEngException.java create mode 100644 src/main/java/appeng/api/exceptions/FailedConnection.java create mode 100644 src/main/java/appeng/api/exceptions/MissingIngredientError.java create mode 100644 src/main/java/appeng/api/exceptions/ModNotInstalled.java create mode 100644 src/main/java/appeng/api/exceptions/RecipeError.java create mode 100644 src/main/java/appeng/api/exceptions/RegistrationError.java create mode 100644 src/main/java/appeng/api/features/IGrinderEntry.java create mode 100644 src/main/java/appeng/api/features/IGrinderRegistry.java create mode 100644 src/main/java/appeng/api/features/IItemComparisionProvider.java create mode 100644 src/main/java/appeng/api/features/IItemComparison.java create mode 100644 src/main/java/appeng/api/features/ILocatable.java create mode 100644 src/main/java/appeng/api/features/ILocatableRegistry.java create mode 100644 src/main/java/appeng/api/features/IMatterCannonAmmoRegistry.java create mode 100644 src/main/java/appeng/api/features/INetworkEncodable.java create mode 100644 src/main/java/appeng/api/features/IP2PTunnelRegistry.java create mode 100644 src/main/java/appeng/api/features/IPlayerRegistry.java create mode 100644 src/main/java/appeng/api/features/IRecipeHandlerRegistry.java create mode 100644 src/main/java/appeng/api/features/IRegistryContainer.java create mode 100644 src/main/java/appeng/api/features/ISpecialComparisonRegistry.java create mode 100644 src/main/java/appeng/api/features/IWirelessTermHandler.java create mode 100644 src/main/java/appeng/api/features/IWirelessTermRegistery.java create mode 100644 src/main/java/appeng/api/features/IWorldGen.java create mode 100644 src/main/java/appeng/api/implementations/ICraftingPatternItem.java create mode 100644 src/main/java/appeng/api/implementations/IPowerChannelState.java create mode 100644 src/main/java/appeng/api/implementations/IUpgradeableHost.java create mode 100644 src/main/java/appeng/api/implementations/TransitionResult.java create mode 100644 src/main/java/appeng/api/implementations/guiobjects/IGuiItem.java create mode 100644 src/main/java/appeng/api/implementations/guiobjects/IGuiItemObject.java create mode 100644 src/main/java/appeng/api/implementations/guiobjects/INetworkTool.java create mode 100644 src/main/java/appeng/api/implementations/guiobjects/IPortableCell.java create mode 100644 src/main/java/appeng/api/implementations/items/IAEItemPowerStorage.java create mode 100644 src/main/java/appeng/api/implementations/items/IAEWrench.java create mode 100644 src/main/java/appeng/api/implementations/items/IBiometricCard.java create mode 100644 src/main/java/appeng/api/implementations/items/IGrowableCrystal.java create mode 100644 src/main/java/appeng/api/implementations/items/IItemGroup.java create mode 100644 src/main/java/appeng/api/implementations/items/IMemoryCard.java create mode 100644 src/main/java/appeng/api/implementations/items/ISpatialStorageCell.java create mode 100644 src/main/java/appeng/api/implementations/items/IStorageCell.java create mode 100644 src/main/java/appeng/api/implementations/items/IStorageComponent.java create mode 100644 src/main/java/appeng/api/implementations/items/IUpgradeModule.java create mode 100644 src/main/java/appeng/api/implementations/items/MemoryCardMessages.java create mode 100644 src/main/java/appeng/api/implementations/parts/IPartCable.java create mode 100644 src/main/java/appeng/api/implementations/parts/IPartMonitor.java create mode 100644 src/main/java/appeng/api/implementations/parts/IPartStorageMonitor.java create mode 100644 src/main/java/appeng/api/implementations/tiles/IChestOrDrive.java create mode 100644 src/main/java/appeng/api/implementations/tiles/IColorableTile.java create mode 100644 src/main/java/appeng/api/implementations/tiles/ICraftingMachine.java create mode 100644 src/main/java/appeng/api/implementations/tiles/ICrankable.java create mode 100644 src/main/java/appeng/api/implementations/tiles/ICrystalGrowthAccelerator.java create mode 100644 src/main/java/appeng/api/implementations/tiles/IMEChest.java create mode 100644 src/main/java/appeng/api/implementations/tiles/ISegmentedInventory.java create mode 100644 src/main/java/appeng/api/implementations/tiles/ITileStorageMonitorable.java create mode 100644 src/main/java/appeng/api/implementations/tiles/IViewCellStorage.java create mode 100644 src/main/java/appeng/api/implementations/tiles/IWirelessAccessPoint.java create mode 100644 src/main/java/appeng/api/integration/IBeeComparison.java create mode 100644 src/main/java/appeng/api/movable/IMovableHandler.java create mode 100644 src/main/java/appeng/api/movable/IMovableRegistry.java create mode 100644 src/main/java/appeng/api/movable/IMovableTile.java create mode 100644 src/main/java/appeng/api/networking/GridFlags.java create mode 100644 src/main/java/appeng/api/networking/GridNotification.java create mode 100644 src/main/java/appeng/api/networking/IGrid.java create mode 100644 src/main/java/appeng/api/networking/IGridBlock.java create mode 100644 src/main/java/appeng/api/networking/IGridCache.java create mode 100644 src/main/java/appeng/api/networking/IGridCacheRegistry.java create mode 100644 src/main/java/appeng/api/networking/IGridConnecitonVisitor.java create mode 100644 src/main/java/appeng/api/networking/IGridConnection.java create mode 100644 src/main/java/appeng/api/networking/IGridHost.java create mode 100644 src/main/java/appeng/api/networking/IGridMultiblock.java create mode 100644 src/main/java/appeng/api/networking/IGridNode.java create mode 100644 src/main/java/appeng/api/networking/IGridStorage.java create mode 100644 src/main/java/appeng/api/networking/IGridVisitor.java create mode 100644 src/main/java/appeng/api/networking/IMachineSet.java create mode 100644 src/main/java/appeng/api/networking/crafting/CraftingItemList.java create mode 100644 src/main/java/appeng/api/networking/crafting/ICraftingCPU.java create mode 100644 src/main/java/appeng/api/networking/crafting/ICraftingCallback.java create mode 100644 src/main/java/appeng/api/networking/crafting/ICraftingGrid.java create mode 100644 src/main/java/appeng/api/networking/crafting/ICraftingJob.java create mode 100644 src/main/java/appeng/api/networking/crafting/ICraftingLink.java create mode 100644 src/main/java/appeng/api/networking/crafting/ICraftingMedium.java create mode 100644 src/main/java/appeng/api/networking/crafting/ICraftingPatternDetails.java create mode 100644 src/main/java/appeng/api/networking/crafting/ICraftingProvider.java create mode 100644 src/main/java/appeng/api/networking/crafting/ICraftingProviderHelper.java create mode 100644 src/main/java/appeng/api/networking/crafting/ICraftingRequester.java create mode 100644 src/main/java/appeng/api/networking/crafting/ICraftingWatcher.java create mode 100644 src/main/java/appeng/api/networking/crafting/ICraftingWatcherHost.java create mode 100644 src/main/java/appeng/api/networking/energy/IAEPowerStorage.java create mode 100644 src/main/java/appeng/api/networking/energy/IEnergyGrid.java create mode 100644 src/main/java/appeng/api/networking/energy/IEnergyGridProvider.java create mode 100644 src/main/java/appeng/api/networking/energy/IEnergySource.java create mode 100644 src/main/java/appeng/api/networking/energy/IEnergyWatcher.java create mode 100644 src/main/java/appeng/api/networking/energy/IEnergyWatcherHost.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkBootingStatusChange.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkCellArrayUpdate.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkChannelChanged.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkChannelsChanged.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkControllerChange.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkCraftingCpuChange.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkCraftingPatternChange.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkEvent.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkEventSubscribe.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkPostCacheConstruction.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkPowerIdleChange.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkPowerStatusChange.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkPowerStorage.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkSecurityChange.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkSpatialEvent.java create mode 100644 src/main/java/appeng/api/networking/events/MENetworkStorageEvent.java create mode 100644 src/main/java/appeng/api/networking/pathing/ControllerState.java create mode 100644 src/main/java/appeng/api/networking/pathing/IPathingGrid.java create mode 100644 src/main/java/appeng/api/networking/security/BaseActionSource.java create mode 100644 src/main/java/appeng/api/networking/security/IActionHost.java create mode 100644 src/main/java/appeng/api/networking/security/ISecurityGrid.java create mode 100644 src/main/java/appeng/api/networking/security/ISecurityProvider.java create mode 100644 src/main/java/appeng/api/networking/security/ISecurityRegister.java create mode 100644 src/main/java/appeng/api/networking/security/MachineSource.java create mode 100644 src/main/java/appeng/api/networking/security/PlayerSource.java create mode 100644 src/main/java/appeng/api/networking/spatial/ISpatialCache.java create mode 100644 src/main/java/appeng/api/networking/storage/IBaseMonitor.java create mode 100644 src/main/java/appeng/api/networking/storage/IStackWatcher.java create mode 100644 src/main/java/appeng/api/networking/storage/IStackWatcherHost.java create mode 100644 src/main/java/appeng/api/networking/storage/IStorageGrid.java create mode 100644 src/main/java/appeng/api/networking/ticking/IGridTickable.java create mode 100644 src/main/java/appeng/api/networking/ticking/ITickManager.java create mode 100644 src/main/java/appeng/api/networking/ticking/TickRateModulation.java create mode 100644 src/main/java/appeng/api/networking/ticking/TickingRequest.java create mode 100644 src/main/java/appeng/api/package-info.java create mode 100644 src/main/java/appeng/api/parts/BusSupport.java create mode 100644 src/main/java/appeng/api/parts/CableRenderMode.java create mode 100644 src/main/java/appeng/api/parts/IAlphaPassItem.java create mode 100644 src/main/java/appeng/api/parts/IBoxProvider.java create mode 100644 src/main/java/appeng/api/parts/IFacadeContainer.java create mode 100644 src/main/java/appeng/api/parts/IFacadePart.java create mode 100644 src/main/java/appeng/api/parts/IPart.java create mode 100644 src/main/java/appeng/api/parts/IPartCollsionHelper.java create mode 100644 src/main/java/appeng/api/parts/IPartHelper.java create mode 100644 src/main/java/appeng/api/parts/IPartHost.java create mode 100644 src/main/java/appeng/api/parts/IPartItem.java create mode 100644 src/main/java/appeng/api/parts/IPartRenderHelper.java create mode 100644 src/main/java/appeng/api/parts/ISimplifiedBundle.java create mode 100644 src/main/java/appeng/api/parts/LayerBase.java create mode 100644 src/main/java/appeng/api/parts/LayerFlags.java create mode 100644 src/main/java/appeng/api/parts/PartItemStack.java create mode 100644 src/main/java/appeng/api/parts/SelectedPart.java create mode 100644 src/main/java/appeng/api/recipes/ICraftHandler.java create mode 100644 src/main/java/appeng/api/recipes/IIngredient.java create mode 100644 src/main/java/appeng/api/recipes/IRecipeHandler.java create mode 100644 src/main/java/appeng/api/recipes/IRecipeLoader.java create mode 100644 src/main/java/appeng/api/recipes/ISubItemResolver.java create mode 100644 src/main/java/appeng/api/recipes/ResolverResult.java create mode 100644 src/main/java/appeng/api/recipes/ResolverResultSet.java create mode 100644 src/main/java/appeng/api/storage/ICellContainer.java create mode 100644 src/main/java/appeng/api/storage/ICellHandler.java create mode 100644 src/main/java/appeng/api/storage/ICellInventory.java create mode 100644 src/main/java/appeng/api/storage/ICellInventoryHandler.java create mode 100644 src/main/java/appeng/api/storage/ICellProvider.java create mode 100644 src/main/java/appeng/api/storage/ICellRegistry.java create mode 100644 src/main/java/appeng/api/storage/ICellWorkbenchItem.java create mode 100644 src/main/java/appeng/api/storage/IExternalStorageHandler.java create mode 100644 src/main/java/appeng/api/storage/IExternalStorageRegistry.java create mode 100644 src/main/java/appeng/api/storage/IMEInventory.java create mode 100644 src/main/java/appeng/api/storage/IMEInventoryHandler.java create mode 100644 src/main/java/appeng/api/storage/IMEMonitor.java create mode 100644 src/main/java/appeng/api/storage/IMEMonitorHandlerReceiver.java create mode 100644 src/main/java/appeng/api/storage/ISaveProvider.java create mode 100644 src/main/java/appeng/api/storage/IStorageHelper.java create mode 100644 src/main/java/appeng/api/storage/IStorageMonitorable.java create mode 100644 src/main/java/appeng/api/storage/ITerminalHost.java create mode 100644 src/main/java/appeng/api/storage/MEMonitorHandler.java create mode 100644 src/main/java/appeng/api/storage/StorageChannel.java create mode 100644 src/main/java/appeng/api/storage/data/IAEFluidStack.java create mode 100644 src/main/java/appeng/api/storage/data/IAEItemStack.java create mode 100644 src/main/java/appeng/api/storage/data/IAEStack.java create mode 100644 src/main/java/appeng/api/storage/data/IAETagCompound.java create mode 100644 src/main/java/appeng/api/storage/data/IItemContainer.java create mode 100644 src/main/java/appeng/api/storage/data/IItemList.java create mode 100644 src/main/java/appeng/api/util/AECableType.java create mode 100644 src/main/java/appeng/api/util/AEColor.java create mode 100644 src/main/java/appeng/api/util/AEColoredItemDefinition.java create mode 100644 src/main/java/appeng/api/util/AEItemDefinition.java create mode 100644 src/main/java/appeng/api/util/DimensionalCoord.java create mode 100644 src/main/java/appeng/api/util/ICommonTile.java create mode 100644 src/main/java/appeng/api/util/IConfigManager.java create mode 100644 src/main/java/appeng/api/util/IConfigureableObject.java create mode 100644 src/main/java/appeng/api/util/INetworkToolAgent.java create mode 100644 src/main/java/appeng/api/util/IOrientable.java create mode 100644 src/main/java/appeng/api/util/IOrientableBlock.java create mode 100644 src/main/java/appeng/api/util/IReadOnlyCollection.java create mode 100644 src/main/java/appeng/api/util/WorldCoord.java create mode 100644 src/main/java/mr208/WeaponVault/AE2/AE2Integration.java create mode 100644 src/main/java/mr208/WeaponVault/Botania/BotaniaIntegration.java create mode 100644 src/main/java/mr208/WeaponVault/Botania/Items/BotanicalItemFlail.java create mode 100644 src/main/java/mr208/WeaponVault/Botania/Items/BotanicalItemMelee.java create mode 100644 src/main/java/mr208/WeaponVault/Botania/Items/BotanicalItemMusket.java create mode 100644 src/main/java/mr208/WeaponVault/Botania/ManaHelper.java create mode 100644 src/main/java/mr208/WeaponVault/CustomMaterials.java create mode 100644 src/main/java/mr208/WeaponVault/IWeaponMaterialCheck.java create mode 100644 src/main/java/mr208/WeaponVault/Items/GenericMetalsIntegration.java create mode 100644 src/main/java/mr208/WeaponVault/Items/WVItemFlail.java create mode 100644 src/main/java/mr208/WeaponVault/Items/WVItemMelee.java create mode 100644 src/main/java/mr208/WeaponVault/Items/WVItemMusket.java create mode 100644 src/main/java/mr208/WeaponVault/Materials.java create mode 100644 src/main/java/mr208/WeaponVault/Thaumcraft/Items/ThaumicItemFlail.java create mode 100644 src/main/java/mr208/WeaponVault/Thaumcraft/Items/ThaumicItemMelee.java create mode 100644 src/main/java/mr208/WeaponVault/Thaumcraft/Items/ThaumicItemMusket.java create mode 100644 src/main/java/mr208/WeaponVault/Thaumcraft/Items/VoidItemFlail.java create mode 100644 src/main/java/mr208/WeaponVault/Thaumcraft/Items/VoidItemMelee.java create mode 100644 src/main/java/mr208/WeaponVault/Thaumcraft/Items/VoidItemMusket.java create mode 100644 src/main/java/mr208/WeaponVault/Thaumcraft/ThaumcraftIntegration.java create mode 100644 src/main/java/mr208/WeaponVault/WVConfig.java create mode 100644 src/main/java/mr208/WeaponVault/WVRef.java create mode 100644 src/main/java/mr208/WeaponVault/WeaponVault.java create mode 100644 src/main/java/thaumcraft/api/IGoggles.java create mode 100644 src/main/java/thaumcraft/api/IRepairable.java create mode 100644 src/main/java/thaumcraft/api/IRepairableExtended.java create mode 100644 src/main/java/thaumcraft/api/IRunicArmor.java create mode 100644 src/main/java/thaumcraft/api/IScribeTools.java create mode 100644 src/main/java/thaumcraft/api/IVisDiscountGear.java create mode 100644 src/main/java/thaumcraft/api/IWarpingGear.java create mode 100644 src/main/java/thaumcraft/api/ItemApi.java create mode 100644 src/main/java/thaumcraft/api/ItemRunic.java create mode 100644 src/main/java/thaumcraft/api/ThaumcraftApi.java create mode 100644 src/main/java/thaumcraft/api/ThaumcraftApiHelper.java create mode 100644 src/main/java/thaumcraft/api/TileThaumcraft.java create mode 100644 src/main/java/thaumcraft/api/WorldCoordinates.java create mode 100644 src/main/java/thaumcraft/api/aspects/Aspect.java create mode 100644 src/main/java/thaumcraft/api/aspects/AspectList.java create mode 100644 src/main/java/thaumcraft/api/aspects/AspectSourceHelper.java create mode 100644 src/main/java/thaumcraft/api/aspects/IAspectContainer.java create mode 100644 src/main/java/thaumcraft/api/aspects/IAspectSource.java create mode 100644 src/main/java/thaumcraft/api/aspects/IEssentiaContainerItem.java create mode 100644 src/main/java/thaumcraft/api/aspects/IEssentiaTransport.java create mode 100644 src/main/java/thaumcraft/api/crafting/CrucibleRecipe.java create mode 100644 src/main/java/thaumcraft/api/crafting/IArcaneRecipe.java create mode 100644 src/main/java/thaumcraft/api/crafting/IInfusionStabiliser.java create mode 100644 src/main/java/thaumcraft/api/crafting/InfusionEnchantmentRecipe.java create mode 100644 src/main/java/thaumcraft/api/crafting/InfusionRecipe.java create mode 100644 src/main/java/thaumcraft/api/crafting/ShapedArcaneRecipe.java create mode 100644 src/main/java/thaumcraft/api/crafting/ShapelessArcaneRecipe.java create mode 100644 src/main/java/thaumcraft/api/damagesource/DamageSourceIndirectThaumcraftEntity.java create mode 100644 src/main/java/thaumcraft/api/damagesource/DamageSourceThaumcraft.java create mode 100644 src/main/java/thaumcraft/api/entities/ITaintedMob.java create mode 100644 src/main/java/thaumcraft/api/nodes/INode.java create mode 100644 src/main/java/thaumcraft/api/nodes/IRevealer.java create mode 100644 src/main/java/thaumcraft/api/nodes/NodeModifier.java create mode 100644 src/main/java/thaumcraft/api/nodes/NodeType.java create mode 100644 src/main/java/thaumcraft/api/package-info.java create mode 100644 src/main/java/thaumcraft/api/potions/PotionFluxTaint.java create mode 100644 src/main/java/thaumcraft/api/potions/PotionVisExhaust.java create mode 100644 src/main/java/thaumcraft/api/research/IScanEventHandler.java create mode 100644 src/main/java/thaumcraft/api/research/ResearchCategories.java create mode 100644 src/main/java/thaumcraft/api/research/ResearchCategoryList.java create mode 100644 src/main/java/thaumcraft/api/research/ResearchItem.java create mode 100644 src/main/java/thaumcraft/api/research/ResearchPage.java create mode 100644 src/main/java/thaumcraft/api/research/ScanResult.java create mode 100644 src/main/java/thaumcraft/api/visnet/TileVisNode.java create mode 100644 src/main/java/thaumcraft/api/visnet/VisNetHandler.java create mode 100644 src/main/java/thaumcraft/api/wands/IWandFocus.java create mode 100644 src/main/java/thaumcraft/api/wands/IWandRodOnUpdate.java create mode 100644 src/main/java/thaumcraft/api/wands/IWandTriggerManager.java create mode 100644 src/main/java/thaumcraft/api/wands/IWandable.java create mode 100644 src/main/java/thaumcraft/api/wands/ItemFocusBasic.java create mode 100644 src/main/java/thaumcraft/api/wands/StaffRod.java create mode 100644 src/main/java/thaumcraft/api/wands/WandCap.java create mode 100644 src/main/java/thaumcraft/api/wands/WandRod.java create mode 100644 src/main/java/thaumcraft/api/wands/WandTriggerRegistry.java create mode 100644 src/main/java/vazkii/botania/api/BotaniaAPI.java create mode 100644 src/main/java/vazkii/botania/api/internal/DummyManaNetwork.java create mode 100644 src/main/java/vazkii/botania/api/internal/DummyMethodHandler.java create mode 100644 src/main/java/vazkii/botania/api/internal/DummyPage.java create mode 100644 src/main/java/vazkii/botania/api/internal/DummySubTile.java create mode 100644 src/main/java/vazkii/botania/api/internal/IGuiLexiconEntry.java create mode 100644 src/main/java/vazkii/botania/api/internal/IInternalMethodHandler.java create mode 100644 src/main/java/vazkii/botania/api/internal/IManaBurst.java create mode 100644 src/main/java/vazkii/botania/api/internal/IManaNetwork.java create mode 100644 src/main/java/vazkii/botania/api/item/IExoflameHeatable.java create mode 100644 src/main/java/vazkii/botania/api/item/IExtendedPlayerController.java create mode 100644 src/main/java/vazkii/botania/api/item/IPetalApothecary.java create mode 100644 src/main/java/vazkii/botania/api/item/IPixieSpawner.java create mode 100644 src/main/java/vazkii/botania/api/lexicon/IAddonEntry.java create mode 100644 src/main/java/vazkii/botania/api/lexicon/ILexicon.java create mode 100644 src/main/java/vazkii/botania/api/lexicon/ILexiconable.java create mode 100644 src/main/java/vazkii/botania/api/lexicon/IRecipeKeyProvider.java create mode 100644 src/main/java/vazkii/botania/api/lexicon/KnowledgeType.java create mode 100644 src/main/java/vazkii/botania/api/lexicon/LexiconCategory.java create mode 100644 src/main/java/vazkii/botania/api/lexicon/LexiconEntry.java create mode 100644 src/main/java/vazkii/botania/api/lexicon/LexiconPage.java create mode 100644 src/main/java/vazkii/botania/api/lexicon/LexiconRecipeMappings.java create mode 100644 src/main/java/vazkii/botania/api/mana/BurstProperties.java create mode 100644 src/main/java/vazkii/botania/api/mana/IClientManaHandler.java create mode 100644 src/main/java/vazkii/botania/api/mana/ICreativeManaProvider.java create mode 100644 src/main/java/vazkii/botania/api/mana/IKeyLocked.java create mode 100644 src/main/java/vazkii/botania/api/mana/ILaputaImmobile.java create mode 100644 src/main/java/vazkii/botania/api/mana/ILens.java create mode 100644 src/main/java/vazkii/botania/api/mana/ILensEffect.java create mode 100644 src/main/java/vazkii/botania/api/mana/IManaBlock.java create mode 100644 src/main/java/vazkii/botania/api/mana/IManaCollector.java create mode 100644 src/main/java/vazkii/botania/api/mana/IManaCollisionGhost.java create mode 100644 src/main/java/vazkii/botania/api/mana/IManaItem.java create mode 100644 src/main/java/vazkii/botania/api/mana/IManaPool.java create mode 100644 src/main/java/vazkii/botania/api/mana/IManaReceiver.java create mode 100644 src/main/java/vazkii/botania/api/mana/IManaTrigger.java create mode 100644 src/main/java/vazkii/botania/api/mana/IManaUsingItem.java create mode 100644 src/main/java/vazkii/botania/api/mana/IPoolOverlayProvider.java create mode 100644 src/main/java/vazkii/botania/api/mana/ITinyPlanetExcempt.java create mode 100644 src/main/java/vazkii/botania/api/mana/ManaItemHandler.java create mode 100644 src/main/java/vazkii/botania/api/mana/ManaNetworkEvent.java create mode 100644 src/main/java/vazkii/botania/api/mana/TileSignature.java create mode 100644 src/main/java/vazkii/botania/api/mana/spark/ISparkAttachable.java create mode 100644 src/main/java/vazkii/botania/api/mana/spark/ISparkEntity.java create mode 100644 src/main/java/vazkii/botania/api/mana/spark/SparkHelper.java create mode 100644 src/main/java/vazkii/botania/api/package-info.java create mode 100644 src/main/java/vazkii/botania/api/recipe/IElvenItem.java create mode 100644 src/main/java/vazkii/botania/api/recipe/IFlowerComponent.java create mode 100644 src/main/java/vazkii/botania/api/recipe/RecipeElvenTrade.java create mode 100644 src/main/java/vazkii/botania/api/recipe/RecipeManaInfusion.java create mode 100644 src/main/java/vazkii/botania/api/recipe/RecipePetals.java create mode 100644 src/main/java/vazkii/botania/api/recipe/RecipeRuneAltar.java create mode 100644 src/main/java/vazkii/botania/api/subtile/ISpecialFlower.java create mode 100644 src/main/java/vazkii/botania/api/subtile/ISubTileContainer.java create mode 100644 src/main/java/vazkii/botania/api/subtile/SubTileEntity.java create mode 100644 src/main/java/vazkii/botania/api/subtile/SubTileFunctional.java create mode 100644 src/main/java/vazkii/botania/api/subtile/SubTileGenerating.java create mode 100644 src/main/java/vazkii/botania/api/wand/ICoordBoundItem.java create mode 100644 src/main/java/vazkii/botania/api/wand/ITileBound.java create mode 100644 src/main/java/vazkii/botania/api/wand/IWandBindable.java create mode 100644 src/main/java/vazkii/botania/api/wand/IWandHUD.java create mode 100644 src/main/java/vazkii/botania/api/wand/IWandable.java create mode 100644 src/main/java/vazkii/botania/api/wand/IWireframeAABBProvider.java create mode 100644 src/main/java/vazkii/botania/api/wiki/IWikiProvider.java create mode 100644 src/main/java/vazkii/botania/api/wiki/SimpleWikiProvider.java create mode 100644 src/main/java/vazkii/botania/api/wiki/WikiHooks.java create mode 100644 src/main/resources/assets/weaponmod/lang/en_US.lang create mode 100644 src/main/resources/assets/weaponmod/textures/items/battleaxe.certus.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/battleaxe.manasteel.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/battleaxe.quartz.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/battleaxe.thaumium.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/battleaxe.void.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/boomerang.certus.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/boomerang.manasteel.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/boomerang.quartz.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/boomerang.thaumium.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/boomerang.void.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/flail.certus.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/flail.manasteel.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/flail.quartz.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/flail.thaumium.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/flail.void.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/halberd.certus.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/halberd.manasteel.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/halberd.quartz.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/halberd.thaumium.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/halberd.void.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/katana.certus.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/katana.manasteel.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/katana.quartz.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/katana.thaumium.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/katana.void.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/knife.certus.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/knife.manasteel.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/knife.quartz.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/knife.thaumium.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/knife.void.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/musketbayonet.certus.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/musketbayonet.manasteel.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/musketbayonet.quartz.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/musketbayonet.thaumium.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/musketbayonet.void.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/spear.certus.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/spear.manasteel.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/spear.quartz.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/spear.thaumium.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/spear.void.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/warhammer.certus.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/warhammer.manasteel.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/warhammer.quartz.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/warhammer.thaumium.png create mode 100644 src/main/resources/assets/weaponmod/textures/items/warhammer.void.png create mode 100644 src/main/resources/mcmod.info diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2789a71 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +*.class + +# Package Files # +*.war +*.ear +/build +/eclipse +/bin +/run +/out + +*.mtl +*.classpath +*.project +/.gradle +/.settings +/libs + +*.ipr +*.iws +*.iml \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..03d7ccc --- /dev/null +++ b/build.gradle @@ -0,0 +1,63 @@ +buildscript { + repositories { + mavenCentral() + maven { + name = "forge" + url = "http://files.minecraftforge.net/maven" + } + maven { + name = "sonatype" + url = "https://oss.sonatype.org/content/repositories/snapshots/" + } + } + dependencies { + classpath 'net.minecraftforge.gradle:ForgeGradle:1.2-SNAPSHOT' + } +} + +apply plugin: 'forge' + +version = "1.7.10-1.0" +group= "mr208.WeaponVault" // http://maven.apache.org/guides/mini/guide-naming-conventions.html +archivesBaseName = "WeaponVault" + +minecraft { + version = "1.7.10-10.13.1.1226" + runDir = "run" +} + +dependencies { + // you may put jars on which you depend on in ./libs + // or you may define them like so.. + //compile "some.group:artifact:version:classifier" + //compile "some.group:artifact:version" + + // real examples + //compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env + //compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env + + // for more info... + // http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html + // http://www.gradle.org/docs/current/userguide/dependency_management.html + +} + +processResources +{ + // this will ensure that this task is redone when the versions change. + inputs.property "version", project.version + inputs.property "mcversion", project.minecraft.version + + // replace stuff in mcmod.info, nothing else + from(sourceSets.main.resources.srcDirs) { + include 'mcmod.info' + + // replace version and mcversion + expand 'version':project.version, 'mcversion':project.minecraft.version + } + + // copy everything else, thats not the mcmod.info + from(sourceSets.main.resources.srcDirs) { + exclude 'mcmod.info' + } +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..b7612167031001b7b84baf2a959e8ea8ad03c011 GIT binary patch literal 51017 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

N(DARnfPMFG|;(rIGZH1uB1rN;y7UlJ8 znb!RwO#5WS_%cPPlwSw94PTKP64}}J!~E1}ch9``2jvUrB*#@up8L&*`tqgq ztTAS@^33w-5hFZAH&{j)?l0<)9X(d`N|yLk!E=iT%PD-FTJ!|hqyj%RFFP`SaL;|_ z$(+VYhKm)K@Oe~+eZK(6ElQNdfimBrdKjeVl57_7p^|)jrzt|wyRonj$j9Bji!


f)EE4q$t9yObmyG04W0z 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 t|KH7qPwVTc?c*oWQQiM74F8)Y \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..8a0b282 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/appeng/api/AEApi.java b/src/main/java/appeng/api/AEApi.java new file mode 100644 index 0000000..1a2e31b --- /dev/null +++ b/src/main/java/appeng/api/AEApi.java @@ -0,0 +1,38 @@ +package appeng.api; + +/** + * + * Entry point for api. + * + * Available IMCs: + * + */ +public class AEApi +{ + + static private IAppEngApi api = null; + + /** + * API Entry Point. + * + * @return the {@link IAppEngApi} or null if the instance could not be retrieved + */ + public static IAppEngApi instance() + { + if ( api == null ) + { + try + { + Class c = Class.forName( "appeng.core.Api" ); + api = (IAppEngApi) c.getField( "instance" ).get( c ); + } + catch (Throwable e) + { + return null; + } + } + + return api; + } + +} diff --git a/src/main/java/appeng/api/IAppEngApi.java b/src/main/java/appeng/api/IAppEngApi.java new file mode 100644 index 0000000..ed14ed6 --- /dev/null +++ b/src/main/java/appeng/api/IAppEngApi.java @@ -0,0 +1,71 @@ +package appeng.api; + +import appeng.api.definitions.Blocks; +import appeng.api.definitions.Items; +import appeng.api.definitions.Materials; +import appeng.api.definitions.Parts; +import appeng.api.exceptions.FailedConnection; +import appeng.api.features.IRegistryContainer; +import appeng.api.networking.IGridBlock; +import appeng.api.networking.IGridConnection; +import appeng.api.networking.IGridHost; +import appeng.api.networking.IGridNode; +import appeng.api.parts.IPartHelper; +import appeng.api.storage.IStorageHelper; + +public interface IAppEngApi +{ + + /** + * @return Registry Container for the numerous registries in AE2. + */ + IRegistryContainer registries(); + + /** + * @return helper for working with storage data types. + */ + IStorageHelper storage(); + + /** + * @return helper for working with grids, and buses. + */ + IPartHelper partHelper(); + + /** + * @return an accessible list of all of AE's Items + */ + Items items(); + + /** + * @return an accessible list of all of AE's materials; materials are items + */ + Materials materials(); + + /** + * @return an accessible list of all of AE's blocks + */ + Blocks blocks(); + + /** + * @return an accessible list of all of AE's parts, parts are items + */ + Parts parts(); + + /** + * create a grid node for your {@link IGridHost} + * + * @param block + * @return + */ + IGridNode createGridNode(IGridBlock block); + + /** + * create a connection between two {@link IGridNode} + * + * @param a + * @param b + * @throws FailedConnection + */ + IGridConnection createGridConnection(IGridNode a, IGridNode b) throws FailedConnection; + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/AccessRestriction.java b/src/main/java/appeng/api/config/AccessRestriction.java new file mode 100644 index 0000000..56fac0f --- /dev/null +++ b/src/main/java/appeng/api/config/AccessRestriction.java @@ -0,0 +1,48 @@ +package appeng.api.config; + +public enum AccessRestriction +{ + NO_ACCESS(0), READ(1), WRITE(2), READ_WRITE(3); + + private final int permisionBit; + + private AccessRestriction(int v) { + permisionBit = v; + } + + public boolean hasPermission(AccessRestriction ar) + { + return (permisionBit & ar.permisionBit) == ar.permisionBit; + } + + public AccessRestriction restrictPermissions(AccessRestriction ar) + { + return getPermByBit( permisionBit & ar.permisionBit ); + } + + public AccessRestriction addPermissions(AccessRestriction ar) + { + return getPermByBit( permisionBit | ar.permisionBit ); + } + + public AccessRestriction removePermissions(AccessRestriction ar) + { + return getPermByBit( permisionBit & (~ar.permisionBit) ); + } + + private AccessRestriction getPermByBit(int bit) + { + switch (bit) + { + default: + case 0: + return NO_ACCESS; + case 1: + return READ; + case 2: + return WRITE; + case 3: + return READ_WRITE; + } + } +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/ActionItems.java b/src/main/java/appeng/api/config/ActionItems.java new file mode 100644 index 0000000..1a56591 --- /dev/null +++ b/src/main/java/appeng/api/config/ActionItems.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum ActionItems +{ + WRENCH, CLOSE, STASH, ENCODE, SUBSTITUTION +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/Actionable.java b/src/main/java/appeng/api/config/Actionable.java new file mode 100644 index 0000000..ce798f6 --- /dev/null +++ b/src/main/java/appeng/api/config/Actionable.java @@ -0,0 +1,14 @@ +package appeng.api.config; + +public enum Actionable +{ + /** + * Perform the intended action. + */ + MODULATE, + + /** + * Pretend to perform the action. + */ + SIMULATE +} diff --git a/src/main/java/appeng/api/config/CondenserOuput.java b/src/main/java/appeng/api/config/CondenserOuput.java new file mode 100644 index 0000000..db84fc2 --- /dev/null +++ b/src/main/java/appeng/api/config/CondenserOuput.java @@ -0,0 +1,15 @@ +package appeng.api.config; + + +public enum CondenserOuput +{ + + TRASH, // 0 + + MATTER_BALLS, // 256 + + SINGULARITY; // 250,000 + + public int requiredPower = 0; + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/CopyMode.java b/src/main/java/appeng/api/config/CopyMode.java new file mode 100644 index 0000000..31cda81 --- /dev/null +++ b/src/main/java/appeng/api/config/CopyMode.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum CopyMode +{ + CLEAR_ON_REMOVE, KEEP_ON_REMOVE +} diff --git a/src/main/java/appeng/api/config/FullnessMode.java b/src/main/java/appeng/api/config/FullnessMode.java new file mode 100644 index 0000000..43b22bc --- /dev/null +++ b/src/main/java/appeng/api/config/FullnessMode.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum FullnessMode +{ + EMPTY, HALF, FULL +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/FuzzyMode.java b/src/main/java/appeng/api/config/FuzzyMode.java new file mode 100644 index 0000000..e5fa8ce --- /dev/null +++ b/src/main/java/appeng/api/config/FuzzyMode.java @@ -0,0 +1,21 @@ +package appeng.api.config; + +public enum FuzzyMode +{ + // Note that percentage damaged, is the inverse of percentage durability. + IGNORE_ALL(-1), PERCENT_99(0), PERCENT_75(25), PERCENT_50(50), PERCENT_25(75); + + final public float breakPoint; + final public float percentage; + + private FuzzyMode(float p) { + percentage = p; + breakPoint = p / 100.0f; + } + + public int calculateBreakPoint(int maxDamage) + { + return (int) ((percentage * maxDamage) / 100.0f); + } + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/IncludeExclude.java b/src/main/java/appeng/api/config/IncludeExclude.java new file mode 100644 index 0000000..3e74db9 --- /dev/null +++ b/src/main/java/appeng/api/config/IncludeExclude.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum IncludeExclude +{ + WHITELIST, BLACKLIST +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/LevelEmitterMode.java b/src/main/java/appeng/api/config/LevelEmitterMode.java new file mode 100644 index 0000000..4fafbf9 --- /dev/null +++ b/src/main/java/appeng/api/config/LevelEmitterMode.java @@ -0,0 +1,10 @@ +package appeng.api.config; + +public enum LevelEmitterMode +{ + + STORED_AMOUNT, + + STOREABLE_AMOUNT + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/LevelType.java b/src/main/java/appeng/api/config/LevelType.java new file mode 100644 index 0000000..58d1a6b --- /dev/null +++ b/src/main/java/appeng/api/config/LevelType.java @@ -0,0 +1,10 @@ +package appeng.api.config; + +public enum LevelType +{ + + ITEM_LEVEL, + + ENERGY_LEVEL + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/ModSettings.java b/src/main/java/appeng/api/config/ModSettings.java new file mode 100644 index 0000000..9b578dc --- /dev/null +++ b/src/main/java/appeng/api/config/ModSettings.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum ModSettings +{ + +} diff --git a/src/main/java/appeng/api/config/NetworkEmitterMode.java b/src/main/java/appeng/api/config/NetworkEmitterMode.java new file mode 100644 index 0000000..19ae702 --- /dev/null +++ b/src/main/java/appeng/api/config/NetworkEmitterMode.java @@ -0,0 +1,12 @@ +package appeng.api.config; + +public enum NetworkEmitterMode +{ + + POWER_LEVEL, + + BOOTING, + + CHANNEL_ERROR + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/OperationMode.java b/src/main/java/appeng/api/config/OperationMode.java new file mode 100644 index 0000000..f6d80ea --- /dev/null +++ b/src/main/java/appeng/api/config/OperationMode.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum OperationMode +{ + FILL, EMPTY +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/OutputMode.java b/src/main/java/appeng/api/config/OutputMode.java new file mode 100644 index 0000000..ebb8cda --- /dev/null +++ b/src/main/java/appeng/api/config/OutputMode.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum OutputMode +{ + EXPORT_ONLY, EXPORT_OR_CRAFT, CRAFT_ONLY +} diff --git a/src/main/java/appeng/api/config/PowerMultiplier.java b/src/main/java/appeng/api/config/PowerMultiplier.java new file mode 100644 index 0000000..d1a6800 --- /dev/null +++ b/src/main/java/appeng/api/config/PowerMultiplier.java @@ -0,0 +1,21 @@ +package appeng.api.config; + +public enum PowerMultiplier +{ + ONE, CONFIG; + + /** + * please do not edit this value, it is set when AE loads its config files. + */ + public double multiplier = 1.0; + + public double multiply(double in) + { + return in * multiplier; + } + + public double divide(double in) + { + return in / multiplier; + } +} diff --git a/src/main/java/appeng/api/config/PowerUnits.java b/src/main/java/appeng/api/config/PowerUnits.java new file mode 100644 index 0000000..8a0d2f7 --- /dev/null +++ b/src/main/java/appeng/api/config/PowerUnits.java @@ -0,0 +1,42 @@ +package appeng.api.config; + +public enum PowerUnits +{ + AE("gui.appliedenergistics2.units.appliedenergstics"), // Native Units - AE Energy + MJ("gui.appliedenergistics2.units.buildcraft"), // BuildCraft - Minecraft Joules + EU("gui.appliedenergistics2.units.ic2"), // IndustrialCraft 2 - Energy Units + WA("gui.appliedenergistics2.units.rotarycraft"), // RotaryCraft - Watts + RF("gui.appliedenergistics2.units.thermalexpansion"), // ThermalExpansion - Redstone Flux + MK("gui.appliedenergistics2.units.mekanism"); // Mekanism - Joules + + private PowerUnits(String un) { + unlocalizedName = un; + } + + /** + * please do not edit this value, it is set when AE loads its config files. + */ + public double conversionRatio = 1.0; + + /** + * unlocalized name for the power unit. + */ + final public String unlocalizedName; + + /** + * do power conversion using AE's conversion rates. + * + * Example: PowerUnits.EU.convertTo( PowerUnits.AE, 32 ); + * + * will normally returns 64, as it will convert the EU, to AE with AE's power settings. + * + * @param target + * @param value + * @return value converted to target units, from this units. + */ + public double convertTo(PowerUnits target, double value) + { + return (value * conversionRatio) / target.conversionRatio; + } + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/RedstoneMode.java b/src/main/java/appeng/api/config/RedstoneMode.java new file mode 100644 index 0000000..91be115 --- /dev/null +++ b/src/main/java/appeng/api/config/RedstoneMode.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum RedstoneMode +{ + IGNORE, LOW_SIGNAL, HIGH_SIGNAL, SIGNAL_PULSE +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/RelativeDirection.java b/src/main/java/appeng/api/config/RelativeDirection.java new file mode 100644 index 0000000..6b02c3d --- /dev/null +++ b/src/main/java/appeng/api/config/RelativeDirection.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum RelativeDirection +{ + LEFT, RIGHT, UP, DOW +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/SearchBoxMode.java b/src/main/java/appeng/api/config/SearchBoxMode.java new file mode 100644 index 0000000..64fc28f --- /dev/null +++ b/src/main/java/appeng/api/config/SearchBoxMode.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum SearchBoxMode +{ + AUTOSEARCH, MANUAL_SEARCH, NEI_AUTOSEARCH, NEI_MANUAL_SEARCH +} diff --git a/src/main/java/appeng/api/config/SecurityPermissions.java b/src/main/java/appeng/api/config/SecurityPermissions.java new file mode 100644 index 0000000..85d3574 --- /dev/null +++ b/src/main/java/appeng/api/config/SecurityPermissions.java @@ -0,0 +1,47 @@ +package appeng.api.config; + +/** + * Represent the security systems basic permissions, these are not for anti-griefing, they are part of the mod as a + * gameplay feature. + */ +public enum SecurityPermissions +{ + /** + * required to insert items into the network via terminal ( also used for machines based on the owner of the + * network, which is determined by its Security Block. ) + */ + INJECT, + + /** + * required to extract items from the network via terminal ( also used for machines based on the owner of the + * network, which is determined by its Security Block. ) + */ + EXTRACT, + + /** + * required to request crafting from the network via terminal. + */ + CRAFT, + + /** + * required to modify automation, and make modifications to the networks physical layout. + */ + BUILD, + + /** + * required to modify the security blocks settings. + */ + SECURITY; + + final private String unlocalizedName = "gui.appliedenergistics2.security." + name().toLowerCase(); + + public String getUnlocalizedName() + { + return unlocalizedName + ".name"; + } + + public String getUnlocalizedTip() + { + return unlocalizedName + ".tip"; + } +} diff --git a/src/main/java/appeng/api/config/Settings.java b/src/main/java/appeng/api/config/Settings.java new file mode 100644 index 0000000..1925907 --- /dev/null +++ b/src/main/java/appeng/api/config/Settings.java @@ -0,0 +1,46 @@ +package appeng.api.config; + +import java.util.EnumSet; + +public enum Settings +{ + LEVEL_EMITTER_MODE(EnumSet.allOf( LevelEmitterMode.class )), + + REDSTONE_EMITTER(EnumSet.of( RedstoneMode.HIGH_SIGNAL, RedstoneMode.LOW_SIGNAL )), REDSTONE_CONTROLLED(EnumSet.allOf( RedstoneMode.class )), + + CONDENSER_OUTPUT(EnumSet.allOf( CondenserOuput.class )), + + POWER_UNITS(EnumSet.allOf( PowerUnits.class )), ACCESS(EnumSet.of( AccessRestriction.READ_WRITE, AccessRestriction.READ, AccessRestriction.WRITE )), + + SORT_DIRECTION(EnumSet.allOf( SortDir.class )), SORT_BY(EnumSet.allOf( SortOrder.class )), + + SEARCH_TOOLTIPS(EnumSet.of( YesNo.YES, YesNo.NO )), VIEW_MODE(EnumSet.allOf( ViewItems.class )), SEARCH_MODE(EnumSet.allOf( SearchBoxMode.class )), + + ACTIONS(EnumSet.allOf( ActionItems.class )), IO_DIRECTION(EnumSet.of( RelativeDirection.LEFT, RelativeDirection.RIGHT )), + + BLOCK(EnumSet.of( YesNo.YES, YesNo.NO )), OPERATION_MODE(EnumSet.allOf( OperationMode.class )), + + FULLNESS_MODE(EnumSet.allOf( FullnessMode.class )), CRAFT_ONLY(EnumSet.of( YesNo.YES, YesNo.NO )), + + FUZZY_MODE(EnumSet.allOf( FuzzyMode.class )), LEVEL_TYPE(EnumSet.allOf( LevelType.class )), + + TERMINAL_STYLE(EnumSet.of( TerminalStyle.TALL, TerminalStyle.SMALL )), COPY_MODE(EnumSet.allOf( CopyMode.class )), + + INTERFACE_TERMINAL(EnumSet.of( YesNo.YES, YesNo.NO )), CRAFT_VIA_REDSTONE(EnumSet.of( YesNo.YES, YesNo.NO )), + + STORAGE_FILTER(EnumSet.allOf( StorageFilter.class )); + + private EnumSet values; + + public EnumSet getPossibleValues() + { + return values; + } + + private Settings(EnumSet set) { + if ( set == null || set.isEmpty() ) + throw new RuntimeException( "Invalid configuration." ); + values = set; + } + +} diff --git a/src/main/java/appeng/api/config/SortDir.java b/src/main/java/appeng/api/config/SortDir.java new file mode 100644 index 0000000..305ebfb --- /dev/null +++ b/src/main/java/appeng/api/config/SortDir.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum SortDir +{ + ASCENDING, DESCENDING; +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/SortOrder.java b/src/main/java/appeng/api/config/SortOrder.java new file mode 100644 index 0000000..90d72c9 --- /dev/null +++ b/src/main/java/appeng/api/config/SortOrder.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum SortOrder +{ + NAME, AMOUNT, MOD, INVTWEAKS +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/StorageFilter.java b/src/main/java/appeng/api/config/StorageFilter.java new file mode 100644 index 0000000..d92f58a --- /dev/null +++ b/src/main/java/appeng/api/config/StorageFilter.java @@ -0,0 +1,10 @@ +package appeng.api.config; + +public enum StorageFilter +{ + + NONE, + + EXTACTABLE_ONLY + +} diff --git a/src/main/java/appeng/api/config/TerminalStyle.java b/src/main/java/appeng/api/config/TerminalStyle.java new file mode 100644 index 0000000..147aa9c --- /dev/null +++ b/src/main/java/appeng/api/config/TerminalStyle.java @@ -0,0 +1,12 @@ +package appeng.api.config; + +public enum TerminalStyle +{ + + TALL, + + FULL, + + SMALL + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/TunnelType.java b/src/main/java/appeng/api/config/TunnelType.java new file mode 100644 index 0000000..f45b987 --- /dev/null +++ b/src/main/java/appeng/api/config/TunnelType.java @@ -0,0 +1,15 @@ +package appeng.api.config; + +public enum TunnelType +{ + ME, // Network Tunnel + BC_POWER, // MJ Tunnel + IC2_POWER, // EU Tunnel + RF_POWER, // RF Tunnel + REDSTONE, // Redstone Tunnel + FLUID, // Fluid Tunnel + ITEM, // Item Tunnel + LIGHT, // Light Tunnel + BUNDLED_REDSTONE, // Bundled Redstone Tunnel + COMPUTER_MESSAGE // Computer Message Tunnel +} diff --git a/src/main/java/appeng/api/config/Upgrades.java b/src/main/java/appeng/api/config/Upgrades.java new file mode 100644 index 0000000..cd3a2d2 --- /dev/null +++ b/src/main/java/appeng/api/config/Upgrades.java @@ -0,0 +1,39 @@ +package appeng.api.config; + +import java.util.HashMap; + +import net.minecraft.item.ItemStack; + +public enum Upgrades +{ + /** + * Gold Tier Upgrades. + */ + CAPACITY(0), REDSTONE(0), CRAFTING(0), + + /** + * Diamond Tier Upgrades. + */ + FUZZY(1), SPEED(1), INVERTER(1); + + public final int myTier; + public final HashMap supportedMax = new HashMap(); + + private Upgrades(int tier) { + myTier = tier; + } + + /** + * @return list of Items/Blocks that support this upgrade, and how many it supports. + */ + public HashMap getSupported() + { + return supportedMax; + } + + public void registerItem(ItemStack myItem, int maxSupported) + { + if ( myItem != null ) + supportedMax.put( myItem, maxSupported ); + } +} diff --git a/src/main/java/appeng/api/config/ViewItems.java b/src/main/java/appeng/api/config/ViewItems.java new file mode 100644 index 0000000..ffb2e20 --- /dev/null +++ b/src/main/java/appeng/api/config/ViewItems.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum ViewItems +{ + ALL, STORED, CRAFTABLE +} \ No newline at end of file diff --git a/src/main/java/appeng/api/config/YesNo.java b/src/main/java/appeng/api/config/YesNo.java new file mode 100644 index 0000000..ccb35bd --- /dev/null +++ b/src/main/java/appeng/api/config/YesNo.java @@ -0,0 +1,6 @@ +package appeng.api.config; + +public enum YesNo +{ + YES, NO, UNDECIDED +} diff --git a/src/main/java/appeng/api/definitions/Blocks.java b/src/main/java/appeng/api/definitions/Blocks.java new file mode 100644 index 0000000..f8095dd --- /dev/null +++ b/src/main/java/appeng/api/definitions/Blocks.java @@ -0,0 +1,89 @@ +package appeng.api.definitions; + +import appeng.api.util.AEItemDefinition; + +public class Blocks +{ + + /* + * World Gen + */ + public AEItemDefinition blockQuartzOre; + public AEItemDefinition blockQuartzOreCharged; + public AEItemDefinition blockMatrixFrame; + + /* + * Decorative + */ + public AEItemDefinition blockQuartz; + public AEItemDefinition blockQuartzPiller; + public AEItemDefinition blockQuartzChiseled; + public AEItemDefinition blockQuartzGlass; + public AEItemDefinition blockQuartzVibrantGlass; + public AEItemDefinition blockQuartzTorch; + public AEItemDefinition blockFluix; + public AEItemDefinition blockSkyStone; + public AEItemDefinition blockSkyChest; + public AEItemDefinition blockSkyCompass; + + /* + * Misc + */ + public AEItemDefinition blockGrindStone; + public AEItemDefinition blockCrankHandle; + public AEItemDefinition blockInscriber; + public AEItemDefinition blockWireless; + public AEItemDefinition blockCharger; + public AEItemDefinition blockTinyTNT; + public AEItemDefinition blockSecurity; + + /* + * Quantum Network Bridge + */ + public AEItemDefinition blockQuantumRing; + public AEItemDefinition blockQuantumLink; + + /* + * Spatial IO + */ + public AEItemDefinition blockSpatialPylon; + public AEItemDefinition blockSpatialIOPort; + + /* + * Bus / Cables + */ + public AEItemDefinition blockMultiPart; + + /* + * Machines + */ + public AEItemDefinition blockController; + public AEItemDefinition blockDrive; + public AEItemDefinition blockChest; + public AEItemDefinition blockInterface; + public AEItemDefinition blockCellWorkbench; + public AEItemDefinition blockIOPort; + public AEItemDefinition blockCondenser; + public AEItemDefinition blockEnergyAcceptor; + public AEItemDefinition blockVibrationChamber; + public AEItemDefinition blockQuartzGrowthAccelerator; + + public AEItemDefinition blockEnergyCell; + public AEItemDefinition blockEnergyCellDense; + public AEItemDefinition blockEnergyCellCreative; + + // rv1 + public AEItemDefinition blockCraftingUnit; + public AEItemDefinition blockCraftingAccelerator; + public AEItemDefinition blockCraftingStorage1k; + public AEItemDefinition blockCraftingStorage4k; + public AEItemDefinition blockCraftingStorage16k; + public AEItemDefinition blockCraftingStorage64k; + public AEItemDefinition blockCraftingMonitor; + + public AEItemDefinition blockMolecularAssembler; + + public AEItemDefinition blockLightDetector; + public AEItemDefinition blockPaint; + +} diff --git a/src/main/java/appeng/api/definitions/Items.java b/src/main/java/appeng/api/definitions/Items.java new file mode 100644 index 0000000..f0b6a2a --- /dev/null +++ b/src/main/java/appeng/api/definitions/Items.java @@ -0,0 +1,54 @@ +package appeng.api.definitions; + +import appeng.api.util.AEColoredItemDefinition; +import appeng.api.util.AEItemDefinition; + +public class Items +{ + + public AEItemDefinition itemCertusQuartzAxe; + public AEItemDefinition itemCertusQuartzHoe; + public AEItemDefinition itemCertusQuartzShovel; + public AEItemDefinition itemCertusQuartzPick; + public AEItemDefinition itemCertusQuartzSword; + public AEItemDefinition itemCertusQuartzWrench; + public AEItemDefinition itemCertusQuartzKnife; + + public AEItemDefinition itemNetherQuartzAxe; + public AEItemDefinition itemNetherQuartzHoe; + public AEItemDefinition itemNetherQuartzShovel; + public AEItemDefinition itemNetherQuartzPick; + public AEItemDefinition itemNetherQuartzSword; + public AEItemDefinition itemNetherQuartzWrench; + public AEItemDefinition itemNetherQuartzKnife; + + public AEItemDefinition itemEntropyManipulator; + public AEItemDefinition itemWirelessTerminal; + public AEItemDefinition itemBiometricCard; + public AEItemDefinition itemChargedStaff; + public AEItemDefinition itemMassCannon; + public AEItemDefinition itemMemoryCard; + public AEItemDefinition itemNetworkTool; + public AEItemDefinition itemPortableCell; + + public AEItemDefinition itemCellCreative; + public AEItemDefinition itemViewCell; + + public AEItemDefinition itemCell1k; + public AEItemDefinition itemCell4k; + public AEItemDefinition itemCell16k; + public AEItemDefinition itemCell64k; + + public AEItemDefinition itemSpatialCell2; + public AEItemDefinition itemSpatialCell16; + public AEItemDefinition itemSpatialCell128; + + public AEItemDefinition itemFacade; + public AEItemDefinition itemCrystalSeed; + + // rv1 + public AEItemDefinition itemEncodedPattern; + public AEItemDefinition itemColorApplicator; + public AEColoredItemDefinition itemPaintBall; + public AEColoredItemDefinition itemLumenPaintBall; +} diff --git a/src/main/java/appeng/api/definitions/Materials.java b/src/main/java/appeng/api/definitions/Materials.java new file mode 100644 index 0000000..e3ba938 --- /dev/null +++ b/src/main/java/appeng/api/definitions/Materials.java @@ -0,0 +1,80 @@ +package appeng.api.definitions; + +import appeng.api.util.AEItemDefinition; + +public class Materials +{ + + public AEItemDefinition materialCell2SpatialPart; + public AEItemDefinition materialCell16SpatialPart; + public AEItemDefinition materialCell128SpatialPart; + + public AEItemDefinition materialSilicon; + public AEItemDefinition materialSkyDust; + + public AEItemDefinition materialCalcProcessorPress; + public AEItemDefinition materialEngProcessorPress; + public AEItemDefinition materialLogicProcessorPress; + + public AEItemDefinition materialCalcProcessorPrint; + public AEItemDefinition materialEngProcessorPrint; + public AEItemDefinition materialLogicProcessorPrint; + + public AEItemDefinition materialSiliconPress; + public AEItemDefinition materialSiliconPrint; + + public AEItemDefinition materialNamePress; + + public AEItemDefinition materialLogicProcessor; + public AEItemDefinition materialCalcProcessor; + public AEItemDefinition materialEngProcessor; + + public AEItemDefinition materialBasicCard; + public AEItemDefinition materialAdvCard; + + public AEItemDefinition materialPureifiedCertusQuartzCrystal; + public AEItemDefinition materialPureifiedNetherQuartzCrystal; + public AEItemDefinition materialPureifiedFluixCrystal; + + public AEItemDefinition materialCell1kPart; + public AEItemDefinition materialCell4kPart; + public AEItemDefinition materialCell16kPart; + public AEItemDefinition materialCell64kPart; + public AEItemDefinition materialEmptyStorageCell; + + public AEItemDefinition materialCardRedstone; + public AEItemDefinition materialCardSpeed; + public AEItemDefinition materialCardCapacity; + public AEItemDefinition materialCardFuzzy; + public AEItemDefinition materialCardInverter; + public AEItemDefinition materialCardCrafting; + + public AEItemDefinition materialEnderDust; + public AEItemDefinition materialFlour; + public AEItemDefinition materialGoldDust; + public AEItemDefinition materialIronDust; + public AEItemDefinition materialFluixDust; + public AEItemDefinition materialCertusQuartzDust; + public AEItemDefinition materialNetherQuartzDust; + + public AEItemDefinition materialMatterBall; + public AEItemDefinition materialIronNugget; + + public AEItemDefinition materialCertusQuartzCrystal; + public AEItemDefinition materialCertusQuartzCrystalCharged; + public AEItemDefinition materialFluixCrystal; + public AEItemDefinition materialFluixPearl; + + public AEItemDefinition materialWoodenGear; + + public AEItemDefinition materialWireless; + public AEItemDefinition materialWirelessBooster; + + public AEItemDefinition materialAnnihilationCore; + public AEItemDefinition materialFormationCore; + + public AEItemDefinition materialSingularity; + public AEItemDefinition materialQESingularity; + public AEItemDefinition materialBlankPattern; + +} diff --git a/src/main/java/appeng/api/definitions/Parts.java b/src/main/java/appeng/api/definitions/Parts.java new file mode 100644 index 0000000..00d6dad --- /dev/null +++ b/src/main/java/appeng/api/definitions/Parts.java @@ -0,0 +1,54 @@ +package appeng.api.definitions; + +import appeng.api.util.AEColoredItemDefinition; +import appeng.api.util.AEItemDefinition; + +public class Parts +{ + + public AEColoredItemDefinition partCableSmart; + public AEColoredItemDefinition partCableCovered; + public AEColoredItemDefinition partCableGlass; + public AEColoredItemDefinition partCableDense; + + public AEColoredItemDefinition partLumenCableSmart; + public AEColoredItemDefinition partLumenCableCovered; + public AEColoredItemDefinition partLumenCableGlass; + public AEColoredItemDefinition partLumenCableDense; + + public AEItemDefinition partQuartzFiber; + public AEItemDefinition partToggleBus; + public AEItemDefinition partInvertedToggleBus; + + public AEItemDefinition partStorageBus; + public AEItemDefinition partImportBus; + public AEItemDefinition partExportBus; + public AEItemDefinition partInterface; + + public AEItemDefinition partLevelEmitter; + + public AEItemDefinition partAnnihilationPlane; + public AEItemDefinition partFormationPlane; + + public AEItemDefinition partP2PTunnelME; + public AEItemDefinition partP2PTunnelRedstone; + public AEItemDefinition partP2PTunnelItems; + public AEItemDefinition partP2PTunnelLiquids; + public AEItemDefinition partP2PTunnelMJ; + public AEItemDefinition partP2PTunnelEU; + public AEItemDefinition partP2PTunnelRF; + public AEItemDefinition partP2PTunnelLight; + + public AEItemDefinition partCableAnchor; + public AEItemDefinition partMonitor; + public AEItemDefinition partSemiDarkMonitor; + public AEItemDefinition partDarkMonitor; + + public AEItemDefinition partInterfaceTerminal; + public AEItemDefinition partPatternTerminal; + public AEItemDefinition partCraftingTerminal; + public AEItemDefinition partTerminal; + public AEItemDefinition partStorageMonitor; + public AEItemDefinition partConversionMonitor; + +} diff --git a/src/main/java/appeng/api/events/LocatableEventAnnounce.java b/src/main/java/appeng/api/events/LocatableEventAnnounce.java new file mode 100644 index 0000000..f54f948 --- /dev/null +++ b/src/main/java/appeng/api/events/LocatableEventAnnounce.java @@ -0,0 +1,28 @@ +package appeng.api.events; + +import appeng.api.features.ILocatable; +import cpw.mods.fml.common.eventhandler.Event; + +/** + * Input Event: + * + * Used to Notify the Location Registry of objects, and their availability. + */ +public class LocatableEventAnnounce extends Event +{ + + public enum LocatableEvent + { + Register, // Adds the locatable to the registry + Unregister // Removes the locatable from the registry + }; + + final public ILocatable target; + final public LocatableEvent change; + + public LocatableEventAnnounce(ILocatable o, LocatableEvent ev) { + target = o; + change = ev; + } + +} diff --git a/src/main/java/appeng/api/exceptions/AppEngException.java b/src/main/java/appeng/api/exceptions/AppEngException.java new file mode 100644 index 0000000..9c3d9ea --- /dev/null +++ b/src/main/java/appeng/api/exceptions/AppEngException.java @@ -0,0 +1,11 @@ +package appeng.api.exceptions; + +public class AppEngException extends Exception +{ + + private static final long serialVersionUID = -9051434206368465494L; + + public AppEngException(String t) { + super( t ); + } +} diff --git a/src/main/java/appeng/api/exceptions/FailedConnection.java b/src/main/java/appeng/api/exceptions/FailedConnection.java new file mode 100644 index 0000000..f4abed6 --- /dev/null +++ b/src/main/java/appeng/api/exceptions/FailedConnection.java @@ -0,0 +1,10 @@ +package appeng.api.exceptions; + +public class FailedConnection extends Exception +{ + + private static final long serialVersionUID = -2544208090248293753L; + + public FailedConnection() { + } +} diff --git a/src/main/java/appeng/api/exceptions/MissingIngredientError.java b/src/main/java/appeng/api/exceptions/MissingIngredientError.java new file mode 100644 index 0000000..51a200a --- /dev/null +++ b/src/main/java/appeng/api/exceptions/MissingIngredientError.java @@ -0,0 +1,11 @@ +package appeng.api.exceptions; + +public class MissingIngredientError extends Exception { + + private static final long serialVersionUID = -998858343831371697L; + + public MissingIngredientError(String n) { + super( n ); + } + +} diff --git a/src/main/java/appeng/api/exceptions/ModNotInstalled.java b/src/main/java/appeng/api/exceptions/ModNotInstalled.java new file mode 100644 index 0000000..7744a1f --- /dev/null +++ b/src/main/java/appeng/api/exceptions/ModNotInstalled.java @@ -0,0 +1,12 @@ +package appeng.api.exceptions; + +public class ModNotInstalled extends Exception +{ + + private static final long serialVersionUID = -9052435206368425494L; + + public ModNotInstalled(String t) { + super( t ); + } + +} diff --git a/src/main/java/appeng/api/exceptions/RecipeError.java b/src/main/java/appeng/api/exceptions/RecipeError.java new file mode 100644 index 0000000..a07f643 --- /dev/null +++ b/src/main/java/appeng/api/exceptions/RecipeError.java @@ -0,0 +1,12 @@ +package appeng.api.exceptions; + +public class RecipeError extends Exception +{ + + private static final long serialVersionUID = -6602870588617670262L; + + public RecipeError(String n) { + super( n ); + } + +} diff --git a/src/main/java/appeng/api/exceptions/RegistrationError.java b/src/main/java/appeng/api/exceptions/RegistrationError.java new file mode 100644 index 0000000..30592ba --- /dev/null +++ b/src/main/java/appeng/api/exceptions/RegistrationError.java @@ -0,0 +1,12 @@ +package appeng.api.exceptions; + +public class RegistrationError extends Exception +{ + + private static final long serialVersionUID = -6602870588617670263L; + + public RegistrationError(String n) { + super( n ); + } + +} diff --git a/src/main/java/appeng/api/features/IGrinderEntry.java b/src/main/java/appeng/api/features/IGrinderEntry.java new file mode 100644 index 0000000..afd18af --- /dev/null +++ b/src/main/java/appeng/api/features/IGrinderEntry.java @@ -0,0 +1,96 @@ +package appeng.api.features; + +import net.minecraft.item.ItemStack; + +/** + * Registration Records for {@link IGrinderRegistry} + */ +public interface IGrinderEntry +{ + + /** + * the current input + * + * @return input that the grinder will accept. + */ + public ItemStack getInput(); + + /** + * lets you change the grinder recipe by changing its input. + * + * @param input + */ + public void setInput(ItemStack input); + + /** + * gets the current output + * + * @return output that the grinder will produce + */ + public ItemStack getOutput(); + + /** + * gets the current output + * + * @return output that the grinder will produce + */ + public ItemStack getOptionalOutput(); + + /** + * gets the current output + * + * @return output that the grinder will produce + */ + public ItemStack getSecondOptionalOutput(); + + /** + * allows you to change the output. + * + * @param output + */ + public void setOutput(ItemStack output); + + /** + * stack, and 0.0-1.0 chance that it will be generated. + * + * @param output + * @param chance + */ + public void setOptionalOutput(ItemStack output, float chance); + + /** + * 0.0 - 1.0 the chance that the optional output will be generated. + * + * @return + */ + public float getOptionalChance(); + + /** + * stack, and 0.0-1.0 chance that it will be generated. + * + * @param output + * @param chance + */ + public void setSecondOptionalOutput(ItemStack output, float chance); + + /** + * 0.0 - 1.0 the chance that the optional output will be generated. + * + * @return + */ + public float getSecondOptionalChance(); + + /** + * Energy cost, in turns. + * + * @return number of turns it takes to produce the output from the input. + */ + public int getEnergyCost(); + + /** + * Allows you to adjust the number of turns + * + * @param new number of turns to produce output. + */ + public void setEnergyCost(int c); +} diff --git a/src/main/java/appeng/api/features/IGrinderRegistry.java b/src/main/java/appeng/api/features/IGrinderRegistry.java new file mode 100644 index 0000000..1355ef1 --- /dev/null +++ b/src/main/java/appeng/api/features/IGrinderRegistry.java @@ -0,0 +1,61 @@ +package appeng.api.features; + +import java.util.List; + +import net.minecraft.item.ItemStack; + +/** + * Lets you manipulate Grinder Recipes, by adding or editing existing ones. + */ +public interface IGrinderRegistry +{ + + /** + * Current list of registered recipes, you can modify this if you want too. + * + * @return currentlyRegistredRecipes + */ + public List getRecipes(); + + /** + * add a new recipe the easy way, in -> out, how many turns., duplicates will not be added. + * + * @param in input + * @param out output + * @param turns amount of turns to turn the input into the output + */ + public void addRecipe(ItemStack in, ItemStack out, int turns); + + /** + * add a new recipe with optional outputs, duplicates will not be added. + * + * @param in input + * @param out output + * @param optional optional output + * @param chance chance to get the optional output within 0.0 - 1.0 + * @param turns amount of turns to turn the input into the outputs + */ + void addRecipe(ItemStack in, ItemStack out, ItemStack optional, float chance, int turns); + + /** + * add a new recipe with optional outputs, duplicates will not be added. + * + * @param in input + * @param out output + * @param optional optional output + * @param chance chance to get the optional output within 0.0 - 1.0 + * @param optional2 second optional output + * @param chance2 chance to get the second optional output within 0.0 - 1.0 + * @param turns amount of turns to turn the input into the outputs + */ + void addRecipe(ItemStack in, ItemStack out, ItemStack optional, float chance, ItemStack optional2, float chance2, int turns); + + /** + * Searches for a recipe for a given input, and returns it. + * + * @param input input + * @return identified recipe or null + */ + public IGrinderEntry getRecipeForInput(ItemStack input); + +} diff --git a/src/main/java/appeng/api/features/IItemComparisionProvider.java b/src/main/java/appeng/api/features/IItemComparisionProvider.java new file mode 100644 index 0000000..a64bf21 --- /dev/null +++ b/src/main/java/appeng/api/features/IItemComparisionProvider.java @@ -0,0 +1,30 @@ +package appeng.api.features; + +import net.minecraft.item.ItemStack; + +/** + * Provider for special comparisons. when an item is encountered AE Will request + * if the comparison function handles the item, by trying to request a + * IItemComparison class. + */ +public interface IItemComparisionProvider +{ + + /** + * should return a new IItemComparison, or return null if it doesn't handle + * the supplied item. + * + * @param is + * @return IItemComparison, or null + */ + IItemComparison getComparison(ItemStack is); + + /** + * Simple test for support ( AE generally skips this and calls the above function. ) + * + * @param stack + * @return true, if getComparison will return a valid IItemComparison Object + */ + public boolean canHandle(ItemStack stack); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/features/IItemComparison.java b/src/main/java/appeng/api/features/IItemComparison.java new file mode 100644 index 0000000..856049c --- /dev/null +++ b/src/main/java/appeng/api/features/IItemComparison.java @@ -0,0 +1,10 @@ +package appeng.api.features; + +public interface IItemComparison +{ + + public boolean sameAsPrecise(IItemComparison comp); + + public boolean sameAsFuzzy(IItemComparison comp); + +} diff --git a/src/main/java/appeng/api/features/ILocatable.java b/src/main/java/appeng/api/features/ILocatable.java new file mode 100644 index 0000000..e81ff42 --- /dev/null +++ b/src/main/java/appeng/api/features/ILocatable.java @@ -0,0 +1,17 @@ +package appeng.api.features; + +import appeng.api.events.LocatableEventAnnounce; + +/** + * A registration record for the {@link ILocatableRegistry} use the {@link LocatableEventAnnounce} event on the Forge + * Event bus to update the registry. + */ +public interface ILocatable +{ + + /** + * @return the serial for a locatable object + */ + long getLocatableSerial(); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/features/ILocatableRegistry.java b/src/main/java/appeng/api/features/ILocatableRegistry.java new file mode 100644 index 0000000..1d19ae8 --- /dev/null +++ b/src/main/java/appeng/api/features/ILocatableRegistry.java @@ -0,0 +1,18 @@ +package appeng.api.features; + +/** + * A Registry for locatable items, works based on serial numbers. + */ +public interface ILocatableRegistry +{ + + /** + * Attempts to find the object with the serial specified, if it can it + * returns the object. + * + * @param ser + * @return requestedObject, or null + */ + public abstract Object findLocateableBySerial(long ser); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/features/IMatterCannonAmmoRegistry.java b/src/main/java/appeng/api/features/IMatterCannonAmmoRegistry.java new file mode 100644 index 0000000..fd6051a --- /dev/null +++ b/src/main/java/appeng/api/features/IMatterCannonAmmoRegistry.java @@ -0,0 +1,24 @@ +package appeng.api.features; + +import net.minecraft.item.ItemStack; + +public interface IMatterCannonAmmoRegistry +{ + + /** + * register a new ammo, generally speaking this is based off of atomic weight to make it easier to guess at + * + * @param ammo + * @param weight + */ + void registerAmmo(ItemStack ammo, double weight); + + /** + * get the penetration value for a particular ammo, 0 indicates a non-ammo. + * + * @param is + * @return 0 or a valid penetration value. + */ + float getPenetration(ItemStack is); + +} diff --git a/src/main/java/appeng/api/features/INetworkEncodable.java b/src/main/java/appeng/api/features/INetworkEncodable.java new file mode 100644 index 0000000..57ef647 --- /dev/null +++ b/src/main/java/appeng/api/features/INetworkEncodable.java @@ -0,0 +1,28 @@ +package appeng.api.features; + +import net.minecraft.item.ItemStack; + +public interface INetworkEncodable { + + /** + * Used to get the current key from the item. + * + * @param player + * @param item + * @return + */ + String getEncryptionKey(ItemStack item); + + /** + * Encode the wireless frequency via the Controller. + * + * @param item + * the wireless terminal. + * @param encKey + * the wireless encryption key. + * @param name + * null for now. + */ + void setEncryptionKey(ItemStack item, String encKey, String name); + +} diff --git a/src/main/java/appeng/api/features/IP2PTunnelRegistry.java b/src/main/java/appeng/api/features/IP2PTunnelRegistry.java new file mode 100644 index 0000000..7717ce3 --- /dev/null +++ b/src/main/java/appeng/api/features/IP2PTunnelRegistry.java @@ -0,0 +1,31 @@ +package appeng.api.features; + +import net.minecraft.item.ItemStack; +import appeng.api.config.TunnelType; + +/** + * A Registry for how p2p Tunnels are attuned + */ +public interface IP2PTunnelRegistry +{ + + /** + * Allows third parties to register items from their mod as potential + * attunements for AE's P2P Tunnels + * + * @param trigger + * - the item which triggers attunement + * @param type + * - the type of tunnel + */ + public abstract void addNewAttunement(ItemStack trigger, TunnelType type); + + /** + * returns null if no attunement can be found. + * + * @param trigger + * @return + */ + TunnelType getTunnelTypeByItem(ItemStack trigger); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/features/IPlayerRegistry.java b/src/main/java/appeng/api/features/IPlayerRegistry.java new file mode 100644 index 0000000..04a824c --- /dev/null +++ b/src/main/java/appeng/api/features/IPlayerRegistry.java @@ -0,0 +1,26 @@ +package appeng.api.features; + +import net.minecraft.entity.player.EntityPlayer; + +import com.mojang.authlib.GameProfile; + +/** + * Maintains a save specific list of userids and username combinations this greatly simplifies storage internally and + * gives a common place to look up and get IDs for the security framework. + */ +public interface IPlayerRegistry +{ + + /** + * @param player + * @return user id of a username. + */ + int getID(GameProfile gameProfile); + + /** + * @param player + * @return user id of a player entity. + */ + int getID(EntityPlayer player); + +} diff --git a/src/main/java/appeng/api/features/IRecipeHandlerRegistry.java b/src/main/java/appeng/api/features/IRecipeHandlerRegistry.java new file mode 100644 index 0000000..5b8fe54 --- /dev/null +++ b/src/main/java/appeng/api/features/IRecipeHandlerRegistry.java @@ -0,0 +1,48 @@ +package appeng.api.features; + +import appeng.api.recipes.ICraftHandler; +import appeng.api.recipes.IRecipeHandler; +import appeng.api.recipes.ISubItemResolver; + +public interface IRecipeHandlerRegistry +{ + + /** + * Add a new Recipe Handler to the parser. + * + * MUST BE CALLED IN PRE-INIT + * + * @param name + * @param handler + */ + void addNewCraftHandler(String name, Class handler); + + /** + * Add a new resolver to the parser. + * + * MUST BE CALLED IN PRE-INIT + * + * @param sir + */ + void addNewSubItemResolver(ISubItemResolver sir); + + /** + * @param name + * @return A recipe handler by name, returns null on failure. + */ + ICraftHandler getCraftHandlerFor(String name); + + /** + * @return a new recipe handler, which can be used to parse, and read recipe files. + */ + public IRecipeHandler createNewRecipehandler(); + + /** + * resolve sub items by name. + * + * @param tmpName + * @return ResolerResult or ResolverResultSet + */ + Object resolveItem(String nameSpace, String itemName); + +} diff --git a/src/main/java/appeng/api/features/IRegistryContainer.java b/src/main/java/appeng/api/features/IRegistryContainer.java new file mode 100644 index 0000000..1e6b49a --- /dev/null +++ b/src/main/java/appeng/api/features/IRegistryContainer.java @@ -0,0 +1,76 @@ +package appeng.api.features; + +import appeng.api.movable.IMovableRegistry; +import appeng.api.networking.IGridCacheRegistry; +import appeng.api.storage.ICellRegistry; +import appeng.api.storage.IExternalStorageRegistry; + +public interface IRegistryContainer +{ + + /** + * Use the movable registry to white list your tiles. + */ + IMovableRegistry moveable(); + + /** + * Add new Grid Caches for use during run time, only use during loading phase. + */ + IGridCacheRegistry gridCache(); + + /** + * Add additional storage bus handlers to improve interplay with mod blocks that contains special inventories that + * function unlike vanilla chests. AE uses this internally for barrels, dsu's, quantum chests, AE Networks and more. + */ + IExternalStorageRegistry externalStorage(); + + /** + * Add additional special comparison functionality, AE Uses this internally for Bees. + */ + ISpecialComparisonRegistry specialComparson(); + + /** + * Lets you register your items as wireless terminals + */ + IWirelessTermRegistery wireless(); + + /** + * Allows you to register new cell types, these will function in drives + */ + ICellRegistry cell(); + + /** + * Manage grinder recipes via API + */ + IGrinderRegistry grinder(); + + /** + * get access to the locatable registry + */ + ILocatableRegistry locateable(); + + /** + * get access to the p2p tunnel registry. + */ + IP2PTunnelRegistry p2pTunnel(); + + /** + * get access to the ammo registry. + */ + IMatterCannonAmmoRegistry matterCannon(); + + /** + * get access to the player registry + */ + IPlayerRegistry players(); + + /** + * get access to the ae2 recipe api + */ + IRecipeHandlerRegistry recipes(); + + /** + * get access to the world-gen api. + */ + IWorldGen worldgen(); +} diff --git a/src/main/java/appeng/api/features/ISpecialComparisonRegistry.java b/src/main/java/appeng/api/features/ISpecialComparisonRegistry.java new file mode 100644 index 0000000..300a511 --- /dev/null +++ b/src/main/java/appeng/api/features/ISpecialComparisonRegistry.java @@ -0,0 +1,27 @@ +package appeng.api.features; + +import net.minecraft.item.ItemStack; + +/** + * A Registry of any special comparison handlers for AE To use. + * + */ +public interface ISpecialComparisonRegistry +{ + + /** + * return TheHandler or null. + * + * @param stack + * @return a handler it found for a specific item + */ + IItemComparison getSpecialComparion(ItemStack stack); + + /** + * Register a new special comparison function with AE. + * + * @param prov + */ + public void addComparisonProvider(IItemComparisionProvider prov); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/features/IWirelessTermHandler.java b/src/main/java/appeng/api/features/IWirelessTermHandler.java new file mode 100644 index 0000000..84ab938 --- /dev/null +++ b/src/main/java/appeng/api/features/IWirelessTermHandler.java @@ -0,0 +1,46 @@ +package appeng.api.features; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import appeng.api.util.IConfigManager; + +/** + * A handler for a wireless terminal. + */ +public interface IWirelessTermHandler extends INetworkEncodable +{ + + /** + * @param is + * @return true, if usePower, hasPower, etc... can be called for the provided item + */ + boolean canHandle(ItemStack is); + + /** + * use an amount of power, in AE units + * + * @param amount + * is in AE units ( 5 per MJ ), if you return false, the item should be dead and return false for + * hasPower + * @param is + * @return + */ + boolean usePower(EntityPlayer player, double amount, ItemStack is); + + /** + * gets the power status of the item. + * + * @param is + * @return returns true if there is any power left. + */ + boolean hasPower(EntityPlayer player, double amount, ItemStack is); + + /** + * Return the config manage for the wireless terminal. + * + * @param is + * @return + */ + IConfigManager getConfigManager(ItemStack is); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/features/IWirelessTermRegistery.java b/src/main/java/appeng/api/features/IWirelessTermRegistery.java new file mode 100644 index 0000000..0f14ce9 --- /dev/null +++ b/src/main/java/appeng/api/features/IWirelessTermRegistery.java @@ -0,0 +1,39 @@ +package appeng.api.features; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** + * Registration record for a Custom Cell handler. + */ +public interface IWirelessTermRegistery +{ + + /** + * add this handler to the list of other wireless handler. + * + * @param handler + */ + void registerWirelessHandler(IWirelessTermHandler handler); + + /** + * @param is + * @return true if there is a handler for this item + */ + boolean isWirelessTerminal(ItemStack is); + + /** + * @param is + * @return a register handler for the item in question, or null if there + * isn't one + */ + IWirelessTermHandler getWirelessTerminalHandler(ItemStack is); + + /** + * opens the wireless terminal gui, the wireless terminal item, must be in + * the active slot on the tool bar. + */ + void OpenWirelessTermainlGui(ItemStack item, World w, EntityPlayer player); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/features/IWorldGen.java b/src/main/java/appeng/api/features/IWorldGen.java new file mode 100644 index 0000000..f79017f --- /dev/null +++ b/src/main/java/appeng/api/features/IWorldGen.java @@ -0,0 +1,20 @@ +package appeng.api.features; + +import net.minecraft.world.World; +import net.minecraft.world.WorldProvider; + +public interface IWorldGen +{ + + public enum WorldGenType + { + CertusQuartz, ChargedCertusQuartz, Metorites + }; + + public void disableWorldGenForProviderID(WorldGenType type, Class provider); + + public void disableWorldGenForDimension(WorldGenType type, int dimid); + + boolean isWorldGenEnabled(WorldGenType type, World w); + +} diff --git a/src/main/java/appeng/api/implementations/ICraftingPatternItem.java b/src/main/java/appeng/api/implementations/ICraftingPatternItem.java new file mode 100644 index 0000000..b454c8c --- /dev/null +++ b/src/main/java/appeng/api/implementations/ICraftingPatternItem.java @@ -0,0 +1,22 @@ +package appeng.api.implementations; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import appeng.api.networking.crafting.ICraftingPatternDetails; + +/** + * Implemented on {@link Item} + */ +public interface ICraftingPatternItem +{ + + /** + * Access Details about a patern + * + * @param is + * @param w + * @return + */ + ICraftingPatternDetails getPatternForItem(ItemStack is, World w); +} diff --git a/src/main/java/appeng/api/implementations/IPowerChannelState.java b/src/main/java/appeng/api/implementations/IPowerChannelState.java new file mode 100644 index 0000000..9927685 --- /dev/null +++ b/src/main/java/appeng/api/implementations/IPowerChannelState.java @@ -0,0 +1,19 @@ +package appeng.api.implementations; + +/** + * This is intended for use on the client side to provide details to Waila. + */ +public interface IPowerChannelState +{ + + /** + * @return true if the part/tile is powered. + */ + boolean isPowered(); + + /** + * @return true if the part/tile isActive + */ + boolean isActive(); + +} diff --git a/src/main/java/appeng/api/implementations/IUpgradeableHost.java b/src/main/java/appeng/api/implementations/IUpgradeableHost.java new file mode 100644 index 0000000..45c5a71 --- /dev/null +++ b/src/main/java/appeng/api/implementations/IUpgradeableHost.java @@ -0,0 +1,23 @@ +package appeng.api.implementations; + +import net.minecraft.tileentity.TileEntity; +import appeng.api.config.Upgrades; +import appeng.api.implementations.tiles.ISegmentedInventory; +import appeng.api.util.IConfigureableObject; + +public interface IUpgradeableHost extends IConfigureableObject, ISegmentedInventory +{ + + /** + * determine how many of an upgrade are installed. + */ + int getInstalledUpgrades(Upgrades u); + + /** + * the tile... + * + * @return + */ + TileEntity getTile(); + +} diff --git a/src/main/java/appeng/api/implementations/TransitionResult.java b/src/main/java/appeng/api/implementations/TransitionResult.java new file mode 100644 index 0000000..4e0f983 --- /dev/null +++ b/src/main/java/appeng/api/implementations/TransitionResult.java @@ -0,0 +1,18 @@ +package appeng.api.implementations; + +/** + * Defines the result of performing a transition from the world into a storage + * cell, if its possible, and what the energy usage is. + */ +public class TransitionResult +{ + + public TransitionResult(boolean _success, double power) { + success = _success; + energyUsage = power; + } + + public final boolean success; + public final double energyUsage; + +} diff --git a/src/main/java/appeng/api/implementations/guiobjects/IGuiItem.java b/src/main/java/appeng/api/implementations/guiobjects/IGuiItem.java new file mode 100644 index 0000000..5ee7a83 --- /dev/null +++ b/src/main/java/appeng/api/implementations/guiobjects/IGuiItem.java @@ -0,0 +1,15 @@ +package appeng.api.implementations.guiobjects; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** + * Implemented on Item objects, to return objects used to manage, and interact + * with the contents. + */ +public interface IGuiItem +{ + + IGuiItemObject getGuiObject(ItemStack is, World world, int x, int y, int z); + +} diff --git a/src/main/java/appeng/api/implementations/guiobjects/IGuiItemObject.java b/src/main/java/appeng/api/implementations/guiobjects/IGuiItemObject.java new file mode 100644 index 0000000..1b1dfe6 --- /dev/null +++ b/src/main/java/appeng/api/implementations/guiobjects/IGuiItemObject.java @@ -0,0 +1,9 @@ +package appeng.api.implementations.guiobjects; + +import net.minecraft.item.ItemStack; + +public interface IGuiItemObject +{ + + public ItemStack getItemStack(); +} diff --git a/src/main/java/appeng/api/implementations/guiobjects/INetworkTool.java b/src/main/java/appeng/api/implementations/guiobjects/INetworkTool.java new file mode 100644 index 0000000..b4d1999 --- /dev/null +++ b/src/main/java/appeng/api/implementations/guiobjects/INetworkTool.java @@ -0,0 +1,14 @@ +package appeng.api.implementations.guiobjects; + +import net.minecraft.inventory.IInventory; +import appeng.api.networking.IGridHost; + +/** + * Obtained via {@link IGuiItem} getGuiObject + */ +public interface INetworkTool extends IInventory, IGuiItemObject +{ + + IGridHost getGridHost(); // null for most purposes. + +} diff --git a/src/main/java/appeng/api/implementations/guiobjects/IPortableCell.java b/src/main/java/appeng/api/implementations/guiobjects/IPortableCell.java new file mode 100644 index 0000000..779e741 --- /dev/null +++ b/src/main/java/appeng/api/implementations/guiobjects/IPortableCell.java @@ -0,0 +1,14 @@ +package appeng.api.implementations.guiobjects; + +import appeng.api.networking.energy.IEnergySource; +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.ITerminalHost; +import appeng.api.storage.data.IAEItemStack; + +/** + * Obtained via {@link IGuiItem} getGuiObject + */ +public interface IPortableCell extends ITerminalHost, IMEMonitor, IEnergySource, IGuiItemObject +{ + +} diff --git a/src/main/java/appeng/api/implementations/items/IAEItemPowerStorage.java b/src/main/java/appeng/api/implementations/items/IAEItemPowerStorage.java new file mode 100644 index 0000000..26d09fe --- /dev/null +++ b/src/main/java/appeng/api/implementations/items/IAEItemPowerStorage.java @@ -0,0 +1,48 @@ +package appeng.api.implementations.items; + +import net.minecraft.item.ItemStack; +import appeng.api.config.AccessRestriction; +import appeng.api.networking.energy.IAEPowerStorage; + +/** + * Basically the same as {@link IAEPowerStorage}, but for items. + */ +public interface IAEItemPowerStorage +{ + + /** + * Inject amt, power into the device, it will store what it can, and return + * the amount unable to be stored. + * + * @return + */ + public double injectAEPower(ItemStack is, double amt); + + /** + * Attempt to extract power from the device, it will extract what it can and + * return it. + * + * @param amt + * @return + */ + public double extractAEPower(ItemStack is, double amt); + + /** + * @return the current maximum power ( this can change :P ) + */ + public double getAEMaxPower(ItemStack is); + + /** + * @return the current AE Power Level, this may exceed getMEMaxPower() + */ + public double getAECurrentPower(ItemStack is); + + /** + * Control the power flow by telling what the network can do, either add? or + * subtract? or both! + * + * @return + */ + public AccessRestriction getPowerFlow(ItemStack is); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/implementations/items/IAEWrench.java b/src/main/java/appeng/api/implementations/items/IAEWrench.java new file mode 100644 index 0000000..b18100e --- /dev/null +++ b/src/main/java/appeng/api/implementations/items/IAEWrench.java @@ -0,0 +1,24 @@ +package appeng.api.implementations.items; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +/** + * Implemented on AE's wrench(s) as a substitute for if BC's API is not + * available. + */ +public interface IAEWrench +{ + + /** + * Check if the wrench can be used. + * + * @param player + * @param x + * @param y + * @param z + * @return + */ + boolean canWrench(ItemStack wrench, EntityPlayer player, int x, int y, int z); + +} diff --git a/src/main/java/appeng/api/implementations/items/IBiometricCard.java b/src/main/java/appeng/api/implementations/items/IBiometricCard.java new file mode 100644 index 0000000..a333d1a --- /dev/null +++ b/src/main/java/appeng/api/implementations/items/IBiometricCard.java @@ -0,0 +1,64 @@ +package appeng.api.implementations.items; + +import java.util.EnumSet; + +import net.minecraft.item.ItemStack; +import appeng.api.config.SecurityPermissions; +import appeng.api.features.IPlayerRegistry; +import appeng.api.networking.security.ISecurityRegister; + +import com.mojang.authlib.GameProfile; + +public interface IBiometricCard +{ + + /** + * Set the {@link GameProfile} to null, to clear it. + */ + void setProfile(ItemStack itemStack, GameProfile username); + + /** + * @return {@link GameProfile} of the player encoded on this card, or a blank string. + */ + GameProfile getProfile(ItemStack is); + + /** + * @param itemStack + * @return the full list of permissions encoded on the card. + */ + EnumSet getPermissions(ItemStack itemStack); + + /** + * Check if a permission is encoded on the card. + * + * @param permission + * @return true if this permission is set on the card. + */ + boolean hasPermission(ItemStack is, SecurityPermissions permission); + + /** + * remove a permission from the item stack. + * + * @param itemStack + * @param permission + */ + void removePermission(ItemStack itemStack, SecurityPermissions permission); + + /** + * add a permission to the item stack. + * + * @param itemStack + * @param permission + */ + void addPermission(ItemStack itemStack, SecurityPermissions permission); + + /** + * lets you handle submission of security values on the card for custom behavior. + * + * @param register + * @param pr + * @param is + */ + void registerPermissions(ISecurityRegister register, IPlayerRegistry pr, ItemStack is); + +} diff --git a/src/main/java/appeng/api/implementations/items/IGrowableCrystal.java b/src/main/java/appeng/api/implementations/items/IGrowableCrystal.java new file mode 100644 index 0000000..391482e --- /dev/null +++ b/src/main/java/appeng/api/implementations/items/IGrowableCrystal.java @@ -0,0 +1,14 @@ +package appeng.api.implementations.items; + +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.item.ItemStack; + +public interface IGrowableCrystal +{ + + ItemStack triggerGrowth(ItemStack is); + + float getMultiplier(Block blk, Material mat); + +} diff --git a/src/main/java/appeng/api/implementations/items/IItemGroup.java b/src/main/java/appeng/api/implementations/items/IItemGroup.java new file mode 100644 index 0000000..7dfa21e --- /dev/null +++ b/src/main/java/appeng/api/implementations/items/IItemGroup.java @@ -0,0 +1,21 @@ +package appeng.api.implementations.items; + +import java.util.Set; + +import net.minecraft.item.ItemStack; + +/** + * Lets you specify the name of the group of items this falls under. + */ +public interface IItemGroup +{ + + /** + * returning null, is the same as not implementing the interface at all. + * + * @param is + * @return an unlocalized string to use for the items group name. + */ + String getUnlocalizedGroupName(Set otherItems, ItemStack is); + +} diff --git a/src/main/java/appeng/api/implementations/items/IMemoryCard.java b/src/main/java/appeng/api/implementations/items/IMemoryCard.java new file mode 100644 index 0000000..34a9d84 --- /dev/null +++ b/src/main/java/appeng/api/implementations/items/IMemoryCard.java @@ -0,0 +1,56 @@ +package appeng.api.implementations.items; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +/** + * Memory Card API + * + * AE's Memory Card Item Class implements this interface. + */ +public interface IMemoryCard +{ + + /** + * Configures the data stored on the memory card, the SettingsName, will be + * localized when displayed. + * + * @param is + * @param SettingsName + * unlocalized string that represents the tile entity. + * @param data + * may contain a String called "tooltip" which is is a + * unlocalized string displayed after the settings name, optional + * but can be used to add details to the card for later. + */ + void setMemoryCardContents(ItemStack is, String SettingsName, NBTTagCompound data); + + /** + * returns the settings name provided by a pervious call to + * setMemoryCardContents, or "AppEng.GuiITooltip.Blank" if there was no + * previous call to setMemoryCardContents. + * + * @param is + * @return + */ + String getSettingsName(ItemStack is); + + /** + * @param is + * @return the NBT Data previously saved by setMemoryCardContents, or an + * empty NBTCompound + */ + NBTTagCompound getData(ItemStack is); + + /** + * notify the user of a outcome related to the memory card. + * + * @param player + * that used the card. + * @param settingsSaved + * which message to send. + */ + void notifyUser(EntityPlayer player, MemoryCardMessages msg); + +} diff --git a/src/main/java/appeng/api/implementations/items/ISpatialStorageCell.java b/src/main/java/appeng/api/implementations/items/ISpatialStorageCell.java new file mode 100644 index 0000000..581cf85 --- /dev/null +++ b/src/main/java/appeng/api/implementations/items/ISpatialStorageCell.java @@ -0,0 +1,69 @@ +package appeng.api.implementations.items; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import appeng.api.implementations.TransitionResult; +import appeng.api.util.WorldCoord; + +/** + * Implemented on a {@link Item} + */ +public interface ISpatialStorageCell +{ + + /** + * @param is + * @return true if this item is a spatial storage cell + */ + boolean isSpatialStorage(ItemStack is); + + /** + * @param is + * @return the maximum size of the spatial storage cell along any given axis + */ + int getMaxStoredDim(ItemStack is); + + /** + * @param is + * @return the world for this cell + */ + World getWorld(ItemStack is); + + /** + * get the currently stored size. + * + * @param is + * @return + */ + WorldCoord getStoredSize(ItemStack is); + + /** + * Minimum coordinates in its world for the storage cell. + * + * @param is + * @return + */ + WorldCoord getMin(ItemStack is); + + /** + * Maximum coordinates in its world for the storage cell. + * + * @param is + * @return + */ + WorldCoord getMax(ItemStack is); + + /** + * Perform a spatial swap with the contents of the cell, and the world. + * + * @param is + * @param w + * @param min + * @param max + * @param doTransition + * @return + */ + TransitionResult doSpatialTransition(ItemStack is, World w, WorldCoord min, WorldCoord max, boolean doTransition); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/implementations/items/IStorageCell.java b/src/main/java/appeng/api/implementations/items/IStorageCell.java new file mode 100644 index 0000000..425e5b1 --- /dev/null +++ b/src/main/java/appeng/api/implementations/items/IStorageCell.java @@ -0,0 +1,82 @@ +package appeng.api.implementations.items; + +import net.minecraft.item.ItemStack; +import appeng.api.storage.ICellWorkbenchItem; +import appeng.api.storage.data.IAEItemStack; + +/** + * Any item which implements this can be treated as an IMEInventory via + * Util.getCell / Util.isCell It automatically handles the internals and NBT + * data, which is both nice, and bad for you! + * + * Good cause it means you don't have to do anything, bad because you have + * little to no control over it. + * + * The standard AE implementation only provides 1-63 Types + * + */ +public interface IStorageCell extends ICellWorkbenchItem +{ + + /** + * If this returns something where N % 8 != 0 Then you will be shot on + * sight, or your car will explode, something like that least... + * + * @param cellItem + * @return numberofBytes + */ + int getBytes(ItemStack cellItem); + + /** + * Determines the number of bytes used for any type included on the cell. + * + * @param cellItem + * @return numberOfBytes + */ + int BytePerType(ItemStack cellItem); + + /** + * Must be between 1 and 63, indicates how many types you want to store on + * the item. + * + * @param cellItem + * @return numberOfTypes + */ + int getTotalTypes(ItemStack cellItem); + + /** + * Allows you to fine tune which items are allowed on a given cell, if you + * don't care, just return false; As the handler for this type of cell is + * still the default cells, the normal AE black list is also applied. + * + * @param cellItem + * @param requestedAddition + * @return true to preventAdditionOfItem + */ + boolean isBlackListed(ItemStack cellItem, IAEItemStack requestedAddition); + + /** + * Allows you to specify if this storage cell can be stored inside other + * storage cells, only set this for special items like the matter cannon + * that are not general purpose storage. + * + * @return true if the storage cell can be stored inside other storage + * cells, this is generally false, except for certain situations + * such as the matter cannon. + */ + boolean storableInStorageCell(); + + /** + * Allows an item to selectively enable or disable its status as a storage + * cell. + * + * @param i + * @return if the ItemStack should behavior as a storage cell. + */ + boolean isStorageCell(ItemStack i); + + /** + * @return drain in ae/t this storage cell will use. + */ + double getIdleDrain(); +} diff --git a/src/main/java/appeng/api/implementations/items/IStorageComponent.java b/src/main/java/appeng/api/implementations/items/IStorageComponent.java new file mode 100644 index 0000000..f22bec7 --- /dev/null +++ b/src/main/java/appeng/api/implementations/items/IStorageComponent.java @@ -0,0 +1,30 @@ +package appeng.api.implementations.items; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +/** + * Implemented on a {@link Item} + */ +public interface IStorageComponent +{ + + /** + * This isn't necessarily the same as if you make a storage cell out of it, + * but all of AE's default cells do it that way, its currently only used for + * the condenser. + * + * @param cellItem + * @return numberofBytes + */ + int getBytes(ItemStack is); + + /** + * Just true or false for the item stack. + * + * @param is + * @return + */ + boolean isStorageComponent(ItemStack is); + +} diff --git a/src/main/java/appeng/api/implementations/items/IUpgradeModule.java b/src/main/java/appeng/api/implementations/items/IUpgradeModule.java new file mode 100644 index 0000000..b950f5e --- /dev/null +++ b/src/main/java/appeng/api/implementations/items/IUpgradeModule.java @@ -0,0 +1,15 @@ +package appeng.api.implementations.items; + +import net.minecraft.item.ItemStack; +import appeng.api.config.Upgrades; + +public interface IUpgradeModule +{ + + /** + * @param itemstack + * @return null, or a valid upgrade type. + */ + Upgrades getType(ItemStack itemstack); + +} diff --git a/src/main/java/appeng/api/implementations/items/MemoryCardMessages.java b/src/main/java/appeng/api/implementations/items/MemoryCardMessages.java new file mode 100644 index 0000000..6a7f958 --- /dev/null +++ b/src/main/java/appeng/api/implementations/items/MemoryCardMessages.java @@ -0,0 +1,9 @@ +package appeng.api.implementations.items; + +/** + * Status Results for use with {@link IMemoryCard} + */ +public enum MemoryCardMessages +{ + INVALID_MACHINE, SETTINGS_LOADED, SETTINGS_SAVED, SETTINGS_CLEARED +} diff --git a/src/main/java/appeng/api/implementations/parts/IPartCable.java b/src/main/java/appeng/api/implementations/parts/IPartCable.java new file mode 100644 index 0000000..6aefda8 --- /dev/null +++ b/src/main/java/appeng/api/implementations/parts/IPartCable.java @@ -0,0 +1,61 @@ +package appeng.api.implementations.parts; + +import java.util.EnumSet; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.common.util.ForgeDirection; +import appeng.api.networking.IGridHost; +import appeng.api.parts.BusSupport; +import appeng.api.parts.IPart; +import appeng.api.parts.IPartHost; +import appeng.api.util.AECableType; +import appeng.api.util.AEColor; + +/** + * Implemented on the {@link IPart}s cable objects that can be placed at {@link ForgeDirection}.UNKNWON in + * {@link IPartHost}s + */ +public interface IPartCable extends IPart, IGridHost +{ + + /** + * does this cable support buses? + */ + BusSupport supportsBuses(); + + /** + * @return the current color of the cable. + */ + AEColor getCableColor(); + + /** + * @return the Cable type. + */ + AECableType getCableConnectionType(); + + /** + * Change the color of the cable, this should cost a small amount of dye, or something. + * + * @param newColor + * @return if the color change was successful. + */ + boolean changeColor(AEColor newColor, EntityPlayer who); + + /** + * Change sides on the cables node. + * + * Called by AE, do not invoke. + * + * @param sides + */ + void setValidSides(EnumSet sides); + + /** + * used to tests if a cable connects to neighbors visually. + * + * @param side + * @return true if this side is currently connects to an external block. + */ + boolean isConnected(ForgeDirection side); + +} diff --git a/src/main/java/appeng/api/implementations/parts/IPartMonitor.java b/src/main/java/appeng/api/implementations/parts/IPartMonitor.java new file mode 100644 index 0000000..2bf9366 --- /dev/null +++ b/src/main/java/appeng/api/implementations/parts/IPartMonitor.java @@ -0,0 +1,18 @@ +package appeng.api.implementations.parts; + +import appeng.api.networking.IGridHost; +import appeng.api.parts.IPart; + +/** + * Implemented by all screen like parts provided by AE. + */ +public interface IPartMonitor extends IPart, IGridHost +{ + + /** + * @return if the device is online you should check this before providing + * any other information. + */ + boolean isPowered(); + +} diff --git a/src/main/java/appeng/api/implementations/parts/IPartStorageMonitor.java b/src/main/java/appeng/api/implementations/parts/IPartStorageMonitor.java new file mode 100644 index 0000000..44def09 --- /dev/null +++ b/src/main/java/appeng/api/implementations/parts/IPartStorageMonitor.java @@ -0,0 +1,26 @@ +package appeng.api.implementations.parts; + +import appeng.api.networking.IGridHost; +import appeng.api.parts.IPart; +import appeng.api.storage.data.IAEStack; +import appeng.api.util.INetworkToolAgent; + +/** + * The Storage monitor is a {@link IPart} located on the sides of a IPartHost + */ +public interface IPartStorageMonitor extends IPartMonitor, IPart, IGridHost, INetworkToolAgent +{ + + /** + * @return the item being displayed on the storage monitor, in AEStack Form, can be either a IAEItemStack or an + * IAEFluidStack the quantity is important remember to use getStackSize() on the IAEStack, and not on the + * FluidStack/ItemStack acquired from it. + */ + IAEStack getDisplayed(); + + /** + * @return the current locked state of the Storage Monitor + */ + boolean isLocked(); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/implementations/tiles/IChestOrDrive.java b/src/main/java/appeng/api/implementations/tiles/IChestOrDrive.java new file mode 100644 index 0000000..76524f6 --- /dev/null +++ b/src/main/java/appeng/api/implementations/tiles/IChestOrDrive.java @@ -0,0 +1,40 @@ +package appeng.api.implementations.tiles; + +import appeng.api.networking.IGridHost; +import appeng.api.storage.ICellContainer; +import appeng.api.util.IOrientable; + +public interface IChestOrDrive extends ICellContainer, IGridHost, IOrientable +{ + + /** + * @return how many slots are available. Chest has 1, Drive has 10. + */ + int getCellCount(); + + /** + * 0 - cell is missing. + * + * 1 - green, + * + * 2 - orange, + * + * 3 - red + * + * @param slot + * @return status of the slot, one of the above indices. + */ + int getCellStatus(int slot); + + /** + * @return if the device is online you should check this before providing any other information. + */ + boolean isPowered(); + + /** + * @param slot + * @return is the cell currently blinking to show activity. + */ + boolean isCellBlinking(int slot); + +} diff --git a/src/main/java/appeng/api/implementations/tiles/IColorableTile.java b/src/main/java/appeng/api/implementations/tiles/IColorableTile.java new file mode 100644 index 0000000..03874ae --- /dev/null +++ b/src/main/java/appeng/api/implementations/tiles/IColorableTile.java @@ -0,0 +1,14 @@ +package appeng.api.implementations.tiles; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.common.util.ForgeDirection; +import appeng.api.util.AEColor; + +public interface IColorableTile +{ + + AEColor getColor(); + + boolean recolourBlock(ForgeDirection side, AEColor colour, EntityPlayer who); + +} diff --git a/src/main/java/appeng/api/implementations/tiles/ICraftingMachine.java b/src/main/java/appeng/api/implementations/tiles/ICraftingMachine.java new file mode 100644 index 0000000..11b5339 --- /dev/null +++ b/src/main/java/appeng/api/implementations/tiles/ICraftingMachine.java @@ -0,0 +1,29 @@ +package appeng.api.implementations.tiles; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraftforge.common.util.ForgeDirection; +import appeng.api.networking.crafting.ICraftingPatternDetails; + +public interface ICraftingMachine +{ + + /** + * inserts a crafting plan, and the necessary items into the crafting machine. + * + * @param patternDetails + * @param table + * @param ejectionDirection + * + * @return if it was accepted, all or nothing. + */ + boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table, ForgeDirection ejectionDirection); + + /** + * check if the crafting machine is accepting pushes via pushPattern, if this is false, all cals to push will fail, + * you can try inserting into the inventry instead. + * + * @return true, if pushPattern can complete, if its false push will always be false. + */ + boolean acceptsPlans(); + +} diff --git a/src/main/java/appeng/api/implementations/tiles/ICrankable.java b/src/main/java/appeng/api/implementations/tiles/ICrankable.java new file mode 100644 index 0000000..b709e23 --- /dev/null +++ b/src/main/java/appeng/api/implementations/tiles/ICrankable.java @@ -0,0 +1,35 @@ +package appeng.api.implementations.tiles; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Crank/Crankable API, + * + * Tiles that Implement this can receive power, from the crank, and have the + * crank placed on them. + * + * Tiles that access other tiles that implement this method can act as Cranks. + * + * This interface must be implemented by a tile entity. + */ +public interface ICrankable +{ + + /** + * Test if the crank can turn, return false if there is no work to be done. + * + * @return if crank should be allowed to turn. + */ + boolean canTurn(); + + /** + * The crank has completed one turn. + */ + void applyTurn(); + + /** + * @return true if the crank can attach on the given side. + */ + boolean canCrankAttach(ForgeDirection directionToCrank); + +} diff --git a/src/main/java/appeng/api/implementations/tiles/ICrystalGrowthAccelerator.java b/src/main/java/appeng/api/implementations/tiles/ICrystalGrowthAccelerator.java new file mode 100644 index 0000000..a9cccf8 --- /dev/null +++ b/src/main/java/appeng/api/implementations/tiles/ICrystalGrowthAccelerator.java @@ -0,0 +1,8 @@ +package appeng.api.implementations.tiles; + +public interface ICrystalGrowthAccelerator +{ + + boolean isPowered(); + +} diff --git a/src/main/java/appeng/api/implementations/tiles/IMEChest.java b/src/main/java/appeng/api/implementations/tiles/IMEChest.java new file mode 100644 index 0000000..71a7ec3 --- /dev/null +++ b/src/main/java/appeng/api/implementations/tiles/IMEChest.java @@ -0,0 +1,8 @@ +package appeng.api.implementations.tiles; + +import appeng.api.networking.energy.IEnergySource; + +public interface IMEChest extends IChestOrDrive, ITileStorageMonitorable, IEnergySource +{ + +} diff --git a/src/main/java/appeng/api/implementations/tiles/ISegmentedInventory.java b/src/main/java/appeng/api/implementations/tiles/ISegmentedInventory.java new file mode 100644 index 0000000..6d00177 --- /dev/null +++ b/src/main/java/appeng/api/implementations/tiles/ISegmentedInventory.java @@ -0,0 +1,17 @@ +package appeng.api.implementations.tiles; + +import net.minecraft.inventory.IInventory; + +public interface ISegmentedInventory +{ + + /** + * Access an internal inventory, note, not all inventories contain real items, some may be ghost items, and treating + * them a real inventories will result in duplication. + * + * @param name + * @return + */ + IInventory getInventoryByName(String name); + +} diff --git a/src/main/java/appeng/api/implementations/tiles/ITileStorageMonitorable.java b/src/main/java/appeng/api/implementations/tiles/ITileStorageMonitorable.java new file mode 100644 index 0000000..f6ef62f --- /dev/null +++ b/src/main/java/appeng/api/implementations/tiles/ITileStorageMonitorable.java @@ -0,0 +1,15 @@ +package appeng.api.implementations.tiles; + +import net.minecraftforge.common.util.ForgeDirection; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.storage.IStorageMonitorable; + +/** + * Implemented on inventories that can share their inventories with other networks, best example, ME Interface. + */ +public interface ITileStorageMonitorable +{ + + IStorageMonitorable getMonitorable(ForgeDirection side, BaseActionSource src); + +} diff --git a/src/main/java/appeng/api/implementations/tiles/IViewCellStorage.java b/src/main/java/appeng/api/implementations/tiles/IViewCellStorage.java new file mode 100644 index 0000000..ab926a4 --- /dev/null +++ b/src/main/java/appeng/api/implementations/tiles/IViewCellStorage.java @@ -0,0 +1,15 @@ +package appeng.api.implementations.tiles; + +import net.minecraft.inventory.IInventory; + +public interface IViewCellStorage +{ + + /** + * should contains at least 5 slot, the first 5 + * + * @return inventory with at least 5 slot + */ + IInventory getViewCellStorage(); + +} diff --git a/src/main/java/appeng/api/implementations/tiles/IWirelessAccessPoint.java b/src/main/java/appeng/api/implementations/tiles/IWirelessAccessPoint.java new file mode 100644 index 0000000..ea966ad --- /dev/null +++ b/src/main/java/appeng/api/implementations/tiles/IWirelessAccessPoint.java @@ -0,0 +1,30 @@ +package appeng.api.implementations.tiles; + +import appeng.api.networking.IGrid; +import appeng.api.networking.security.IActionHost; +import appeng.api.util.DimensionalCoord; + +public interface IWirelessAccessPoint extends IActionHost +{ + + /** + * @return location of WAP + */ + DimensionalCoord getLocation(); + + /** + * @return max range for this WAP + */ + double getRange(); + + /** + * @return can you use this WAP? + */ + boolean isActive(); + + /** + * @return + */ + IGrid getGrid(); + +} diff --git a/src/main/java/appeng/api/integration/IBeeComparison.java b/src/main/java/appeng/api/integration/IBeeComparison.java new file mode 100644 index 0000000..ab1ccb4 --- /dev/null +++ b/src/main/java/appeng/api/integration/IBeeComparison.java @@ -0,0 +1,20 @@ +package appeng.api.integration; + +/** + * An interface to get access to the individual settings for AE's Internal Bee + * Comparison handler. + * + * Assessable via: ( IBeeComparison ) + * IAEItemStack.getTagCompound().getSpecialComparison() + * + * If you don't have the forestry API, just delete this file when using the API. + */ +public interface IBeeComparison +{ + + /** + * @return the Forestry IIndividual for this comparison object - cast this to a IIndividual if you want to use it. + */ + Object getIndividual(); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/movable/IMovableHandler.java b/src/main/java/appeng/api/movable/IMovableHandler.java new file mode 100644 index 0000000..3706180 --- /dev/null +++ b/src/main/java/appeng/api/movable/IMovableHandler.java @@ -0,0 +1,41 @@ +package appeng.api.movable; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public interface IMovableHandler +{ + + /** + * if you return true from this, your saying you can handle the class, not + * that single entity, you cannot opt out of single entities. + * + * @param myClass + * @param tile + * @return + */ + boolean canHandle(Class myClass, TileEntity tile); + + /** + * request that the handler move the the tile from its current location to + * the new one. the tile has already been invalidated, and the blocks have + * already been fully moved. + * + * Potential Example: + * + * Chunk c = world.getChunkFromBlockCoords( x, z ); c.setChunkBlockTileEntity( x + * & 0xF, y + y, z & 0xF, tile ); + * + * if ( c.isChunkLoaded ) { world.addTileEntity( tile ); world.markBlockForUpdate( x, + * y, z ); } + * + * @param tile + * @param world + * @param x + * @param y + * @param z + * @return + */ + void moveTile(TileEntity tile, World world, int x, int y, int z); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/movable/IMovableRegistry.java b/src/main/java/appeng/api/movable/IMovableRegistry.java new file mode 100644 index 0000000..745bea7 --- /dev/null +++ b/src/main/java/appeng/api/movable/IMovableRegistry.java @@ -0,0 +1,97 @@ +package appeng.api.movable; + +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntity; + +/** + * Used to determine if a tile is marked as movable, a block will be considered movable, if... + * + * 1. The Tile or its super classes have been white listed with whiteListTileEntity. + * + * 2. The Tile has been register with the IMC ( which basically calls whiteListTileEntity. ) + * + * 3. The Tile implements IMovableTile 4. A IMovableHandler is register that returns canHandle = true for the Tile + * Entity Class + * + * IMC Example: FMLInterModComms.sendMessage( "appliedenergistics2", "movabletile", "appeng.common.AppEngTile" ); + * + * The movement process is as follows, + * + * 1. IMovableTile.prepareToMove() or TileEntity.invalidate() depending on your opt-in method. 2. The tile will be + * removed from the world. 3. Its world, coordinates will be changed. *** this can be overridden with a IMovableHandler + * *** 4. It will then be re-added to the world, or a new world. 5. TileEntity.validate() 6. IMovableTile.doneMoving ( + * if you implemented IMovableTile ) + * + * Please note, this is a 100% white list only feature, I will never opt in any non-vanilla, non-AE blocks. If you do + * not want to support your tiles being moved, you don't have to do anything. + * + * I appreciate anyone that takes the effort to get their tiles to work with this system to create a better use + * experience. + * + * If you need a build of deobf build of AE for testing, do not hesitate to ask. + */ +public interface IMovableRegistry +{ + + /** + * Black list a block from movement, please only use this to prevent exploits. + * + * You can also use the IMC, FMLInterModComms.sendMessage( "appliedenergistics2", "whitelist-spatial", + * "appeng.common.AppEngTile" ); + * + * @param blk + */ + void blacklistBlock(Block blk); + + /** + * White list your tile entity with the registry. + * + * You can also use the IMC, FMLInterModComms.sendMessage( "appliedenergistics2", "blacklist-block-spatial", new + * ItemStack(...) ); + * + * If you tile is handled with IMovableHandler or IMovableTile you do not need to white list it. + */ + void whiteListTileEntity(Class c); + + /** + * @param te + * @return true if the tile has accepted your request to move it + */ + boolean askToMove(TileEntity te); + + /** + * tells the tile you are done moving it. + * + * @param te + */ + void doneMoving(TileEntity te); + + /** + * add a new handler movable handler. + * + * @param handler + */ + void addHandler(IMovableHandler handler); + + /** + * handlers are used to perform movement, this allows you to override AE's internal version. + * + * only valid after askToMove(...) = true + * + * @param te + * @return + */ + IMovableHandler getHandler(TileEntity te); + + /** + * @return a copy of the default handler + */ + IMovableHandler getDefaultHandler(); + + /** + * @param blk + * @return true if this block is blacklisted + */ + boolean isBlacklisted(Block blk); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/movable/IMovableTile.java b/src/main/java/appeng/api/movable/IMovableTile.java new file mode 100644 index 0000000..dc65491 --- /dev/null +++ b/src/main/java/appeng/api/movable/IMovableTile.java @@ -0,0 +1,23 @@ +package appeng.api.movable; + +/** + * You can implement this, or use the IMovableRegistry to white list your tile, + * please see the registry for more information. + */ +public interface IMovableTile +{ + + /** + * notification that your block will be moved, called instead of invalidate, + * return false to prevent movement. + * + * @return + */ + boolean prepareToMove(); + + /** + * notification that your block was moved, called after validate. + */ + void doneMoving(); + +} diff --git a/src/main/java/appeng/api/networking/GridFlags.java b/src/main/java/appeng/api/networking/GridFlags.java new file mode 100644 index 0000000..3884cfa --- /dev/null +++ b/src/main/java/appeng/api/networking/GridFlags.java @@ -0,0 +1,45 @@ +package appeng.api.networking; + +/** + * Various flags to determine network node behavior. + */ +public enum GridFlags +{ + /** + * import/export buses, terminals, and other devices that use network features, will use this setting. + */ + REQUIRE_CHANNEL, + + /** + * P2P ME tunnels use this setting. + */ + COMPRESSED_CHANNEL, + + /** + * cannot carry channels over this node. + */ + CANNOT_CARRY, + + /** + * Used by P2P Tunnels to prevent tunnels from tunneling recursively. + */ + CANNOT_CARRY_COMPRESSED, + + /** + * This node can transmit 32 signals, this should only apply to Tier2 Cable, P2P Tunnels, and Quantum Network + * Bridges. + */ + DENSE_CAPACITY, + + /** + * This block is part of a multiblock, used in conjunction with REQUIRE_CANNEL, and {@link IGridMultiblock} see this + * interface for details. + */ + MULTIBLOCK, + + /** + * Indicates which path might be preferred, this only matters if two routes of equal length exist, ad only changes + * the order they are processed in. + */ + PREFERED +} diff --git a/src/main/java/appeng/api/networking/GridNotification.java b/src/main/java/appeng/api/networking/GridNotification.java new file mode 100644 index 0000000..78c4d19 --- /dev/null +++ b/src/main/java/appeng/api/networking/GridNotification.java @@ -0,0 +1,9 @@ +package appeng.api.networking; + +public enum GridNotification +{ + /** + * the visible connections for this node have changed, useful for cable. + */ + ConnectionsChanged, +} diff --git a/src/main/java/appeng/api/networking/IGrid.java b/src/main/java/appeng/api/networking/IGrid.java new file mode 100644 index 0000000..8ce3df1 --- /dev/null +++ b/src/main/java/appeng/api/networking/IGrid.java @@ -0,0 +1,71 @@ +package appeng.api.networking; + +import appeng.api.networking.events.MENetworkEvent; +import appeng.api.util.IReadOnlyCollection; + +/** + * Gives you access to Grid based information. + * + * Don't Implement. + */ +public interface IGrid +{ + + /** + * Get Access to various grid modules + * + * @param iface + * @return the IGridCache you requested. + */ + public C getCache(Class iface); + + /** + * Post an event into the network event bus. + * + * @param ev + * - event to post + * @return returns ev back to original poster + */ + public MENetworkEvent postEvent(MENetworkEvent ev); + + /** + * Post an event into the network event bus, but direct it at a single node. + * + * @param ev + * event to post + * @return returns ev back to original poster + */ + public MENetworkEvent postEventTo(IGridNode node, MENetworkEvent ev); + + /** + * get a list of the diversity of classes, you can use this to better detect which machines your interested in, + * rather then iterating the entire grid to test them. + * + * @return IReadOnlyCollection of all available host types (Of Type IGridHost). + */ + public IReadOnlyCollection> getMachinesClasses(); + + /** + * Get machines on the network. + * + * @param classofIGridHost + * @return IMachineSet of all nodes belonging to hosts of specified class. + */ + public IMachineSet getMachines(Class classofIGridHost); + + /** + * @return IReadOnlyCollection for all nodes on the network, node visitors are prefered. + */ + IReadOnlyCollection getNodes(); + + /** + * @return true if the last node has been removed from the grid. + */ + public boolean isEmpty(); + + /** + * @return the node considered the pivot point of the grid. + */ + public IGridNode getPivot(); + +} diff --git a/src/main/java/appeng/api/networking/IGridBlock.java b/src/main/java/appeng/api/networking/IGridBlock.java new file mode 100644 index 0000000..730e2e8 --- /dev/null +++ b/src/main/java/appeng/api/networking/IGridBlock.java @@ -0,0 +1,88 @@ +package appeng.api.networking; + +import java.util.EnumSet; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import appeng.api.parts.IPart; +import appeng.api.util.AEColor; +import appeng.api.util.DimensionalCoord; + +/** + * An Implementation is required to create your node for IGridHost + * + * Implement for use with IGridHost + */ +public interface IGridBlock +{ + + /** + * how much power to drain per tick as part of idle network usage. + * + * if the value of this changes, you must post a MENetworkPowerIdleChange + * + * @return ae/t to use. + */ + double getIdlePowerUsage(); + + /** + * Various flags that AE uses to modify basic behavior for various parts of the network. + * + * @return Set of flags for this IGridBlock + */ + EnumSet getFlags(); + + /** + * generally speaking you will return true for this, the one exception is buses, or worm holes where the node + * represents something that isn't a real connection in the world, but rather one represented internally to the + * block. + * + * @return if the world can connect to this node, and the node can connect to the world. + */ + boolean isWorldAccessable(); + + /** + * @return current location of this node + */ + DimensionalCoord getLocation(); + + /** + * @return Transparent, or a valid color, NULL IS NOT A VALID RETURN + */ + AEColor getGridColor(); + + /** + * Notifies your IGridBlock that changes were made to your connections + */ + void onGridNotification(GridNotification notification); + + /** + * Update Blocks network/connection/booting status. grid, + * + * @param isReady + */ + public void setNetworkStatus(IGrid grid, int channelsInUse); + + /** + * Determine which sides of the block can be connected too, only used when isWorldAccessable returns true, not used + * for {@link IPart} implementations. + */ + EnumSet getConnectableSides(); + + /** + * @return the IGridHost for the node, this will be an IGridPart or a TileEntity generally speaking. + */ + IGridHost getMachine(); + + /** + * called when the grid for the node has changed, the general grid state should not be trusted at this point. + */ + void gridChanged(); + + /** + * Determines what item stack is used to render this node in the GUI. + * + * @return the render item stack to use to render this node, null is valid, and will not show this node. + */ + public ItemStack getMachineRepresentation(); +} diff --git a/src/main/java/appeng/api/networking/IGridCache.java b/src/main/java/appeng/api/networking/IGridCache.java new file mode 100644 index 0000000..7fe0d45 --- /dev/null +++ b/src/main/java/appeng/api/networking/IGridCache.java @@ -0,0 +1,71 @@ +package appeng.api.networking; + +/** + * + * Allows you to create a network wise service, AE2 uses these for providing + * item, spatial, and tunnel services. + * + * Any Class that implements this, should have a public default constructor that + * takes a single argument of type IGrid. + * + */ +public interface IGridCache +{ + + /** + * Called each tick for the network, allows you to have active network wide + * behaviors. + * + */ + void onUpdateTick(); + + /** + * inform your cache, that a machine was removed from the grid. + * + * Important: Do not trust the grids state in this method, interact only + * with the node you are passed, if you need to manage other grid + * information, do it on the next updateTick. + * + * @param gridNode + * @param machine + */ + void removeNode(IGridNode gridNode, IGridHost machine); + + /** + * informs you cache that a machine was added to the grid. + * + * Important: Do not trust the grids state in this method, interact only + * with the node you are passed, if you need to manage other grid + * information, do it on the next updateTick. + * + * @param gridNode + * @param machine + */ + void addNode(IGridNode gridNode, IGridHost machine); + + /** + * Called when a grid splits into two grids, AE will call a split as it + * Iteratively processes changes. The destination should receive half, and + * the current cache should receive half. + * + * @param destinationStorage + */ + void onSplit(IGridStorage destinationStorage); + + /** + * Called when two grids merge into one, AE will call a join as it + * Iteratively processes changes. Use this method to incorporate all the + * data from the source into your cache. + * + * @param sourceStorage + */ + void onJoin(IGridStorage sourceStorage); + + /** + * Called when saving changes, + * + * @param destinationStorage + */ + void populateGridStorage(IGridStorage destinationStorage); + +} diff --git a/src/main/java/appeng/api/networking/IGridCacheRegistry.java b/src/main/java/appeng/api/networking/IGridCacheRegistry.java new file mode 100644 index 0000000..d1b68b8 --- /dev/null +++ b/src/main/java/appeng/api/networking/IGridCacheRegistry.java @@ -0,0 +1,28 @@ +package appeng.api.networking; + +import java.util.HashMap; + +/** + * A registry of grid caches to extend grid functionality. + */ +public interface IGridCacheRegistry +{ + + /** + * Register a new grid cache for use during operation, must be called during the loading phase. + * + * @param cl + * @return cache id ( can be used later to ask the grid for you cache. ) + */ + void registerGridCache(Class iface, Class implementation); + + /** + * requests a new instance of a grid cache for use, used internally + * + * @param grid + * + * @return a new HashMap of IGridCaches from the registry, called from IGrid when constructing a new grid. + */ + HashMap, IGridCache> createCacheInstance(IGrid grid); + +} diff --git a/src/main/java/appeng/api/networking/IGridConnecitonVisitor.java b/src/main/java/appeng/api/networking/IGridConnecitonVisitor.java new file mode 100644 index 0000000..b3da721 --- /dev/null +++ b/src/main/java/appeng/api/networking/IGridConnecitonVisitor.java @@ -0,0 +1,14 @@ +package appeng.api.networking; + +public interface IGridConnecitonVisitor extends IGridVisitor +{ + + /** + * Called for each connection on the network. + * + * @param n + * the connection. + */ + public void visitConnection(IGridConnection n); + +} diff --git a/src/main/java/appeng/api/networking/IGridConnection.java b/src/main/java/appeng/api/networking/IGridConnection.java new file mode 100644 index 0000000..9e07090 --- /dev/null +++ b/src/main/java/appeng/api/networking/IGridConnection.java @@ -0,0 +1,58 @@ +package appeng.api.networking; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Access to AE's internal grid connections. + * + * Messing with connection is generally completely unnecessary, you should be able to just use IGridNode.updateState() + * to have AE manage them for you. + * + * Don't Implement. + */ +public interface IGridConnection +{ + + /** + * lets you get the opposing node of the connection by passing your own node. + * + * @param gridNode + * @return the IGridNode which represents the opposite side of the connection. + */ + IGridNode getOtherSide(IGridNode gridNode); + + /** + * determine the direction of the connection based on your node. + * + * @param gridNode + * @return the direction of the connection, only valid for in world connections. + */ + ForgeDirection getDirection(IGridNode gridNode); + + /** + * by destroying a connection you may create new grids, and trigger un-expected behavior, you should only destroy + * connections if you created them. + */ + void destroy(); + + /** + * @return node A + */ + IGridNode a(); + + /** + * @return node B + */ + IGridNode b(); + + /** + * @return if the connection is invisible this returns false + */ + boolean hasDirection(); + + /** + * @return how many channels pass over this connections. + */ + int getUsedChannels(); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/networking/IGridHost.java b/src/main/java/appeng/api/networking/IGridHost.java new file mode 100644 index 0000000..f69b347 --- /dev/null +++ b/src/main/java/appeng/api/networking/IGridHost.java @@ -0,0 +1,43 @@ +package appeng.api.networking; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; +import appeng.api.parts.IPart; +import appeng.api.util.AECableType; + +/** + * + * Implement to create a networked {@link TileEntity} or {@link IPart} must + * be implemented for a part, or tile entity to become part of a grid. + * + */ +public interface IGridHost +{ + + /** + * get the grid node for a particular side of a block, you can return null, + * by returning a valid node later and calling updateState, you can join the + * Grid when your block is ready. + * + * @param dir + * feel free to ignore this, most blocks will use the same node + * for every side. + * @return a new IGridNode, create these with + * AEApi.instance().createGridNode( MyIGridBlock ) + */ + public IGridNode getGridNode(ForgeDirection dir); + + /** + * Determines how cables render when they connect to this block. Priority is + * Smart > Covered > Glass + * + * @param dir + */ + public AECableType getCableConnectionType(ForgeDirection dir); + + /** + * break this host, its violating security rules, just break your block, or part. + */ + public void securityBreak(); + +} diff --git a/src/main/java/appeng/api/networking/IGridMultiblock.java b/src/main/java/appeng/api/networking/IGridMultiblock.java new file mode 100644 index 0000000..83f580e --- /dev/null +++ b/src/main/java/appeng/api/networking/IGridMultiblock.java @@ -0,0 +1,20 @@ +package appeng.api.networking; + +import java.util.Iterator; + +/** + * An extension of IGridBlock, only means something when your getFlags() contains REQUIRE_CHANNEL, when done properly it + * will call the method to get a list of all related nodes and give each of them a channel simultaneously for the entire + * set. This means your entire Multiblock can work with a single channel, instead of one channel per block. + */ +public interface IGridMultiblock extends IGridBlock +{ + + /** + * Used to acquire a list of all nodes that are part of the multiblock. + * + * @return an iterator that will iterate all the nodes for the multiblock. ( read-only iterator expected. ) + */ + Iterator getMultiblockNodes(); + +} diff --git a/src/main/java/appeng/api/networking/IGridNode.java b/src/main/java/appeng/api/networking/IGridNode.java new file mode 100644 index 0000000..bb99e2c --- /dev/null +++ b/src/main/java/appeng/api/networking/IGridNode.java @@ -0,0 +1,141 @@ +package appeng.api.networking; + +import java.util.EnumSet; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import appeng.api.IAppEngApi; +import appeng.api.util.IReadOnlyCollection; + +/** + * + * Gives you a view into your Nodes connections and information. + * + * updateState, getGrid, destroy are required to implement a proper IGridHost. + * + * Don't Implement; Acquire from {@link IAppEngApi}.createGridNode + * + */ +public interface IGridNode +{ + + /** + * lets you walk the grid stating at the current node using a IGridVisitor, generally not needed, please use only if + * required. + * + * @param g + */ + void beginVisition(IGridVisitor g); + + /** + * inform the node that your IGridBlock has changed its internal state, and force the node to update. + * + * ALWAYS make sure that your tile entity is in the world, and has its node properly saved to be returned from the + * host before updating state, + * + * If your entity is not in the world, or if you IGridHost returns a different node for the same side you will + * likely crash the game. + * + */ + void updateState(); + + /** + * get the machine represented by the node. + * + * @return + */ + IGridHost getMachine(); + + /** + * get the grid for the node, this can change at a moments notice. + * + * @return + */ + IGrid getGrid(); + + /** + * By destroying your node, you destroy any connections, and its existence in the grid, use in invalidate, or + * onChunkUnload + */ + void destroy(); + + /** + * @return the world the node is located in + */ + World getWorld(); + + /** + * + * @return a set of the connected sides, UNKNOWN represents an invisible connection + */ + EnumSet getConnectedSides(); + + /** + * lets you iterate a nodes connections + * + * @return + */ + IReadOnlyCollection getConnections(); + + /** + * @return the IGridBlock for this node + */ + IGridBlock getGridBlock(); + + /** + * Reflects the networks status, returns true only if the network is powered, and the network is not booting, this + * also takes into account channels. + * + * @return true if is Network node active, and participating. + */ + boolean isActive(); + + /** + * this should be called for each node you create, if you have a nodeData compound to load from, you can store all + * your nods on a single compound using name. + * + * Important: You must call this before updateState. + * + * @param name + * @param nodeData + */ + void loadFromNBT(String name, NBTTagCompound nodeData); + + /** + * this should be called for each node you maintain, you can save all your nodes to the same tag with different + * names, if you fail to complete the load / save procedure, network state may be lost between game load/saves. + * + * @param name + * @param nodeData + */ + void saveToNBT(String name, NBTTagCompound nodeData); + + /** + * @return if the node's channel requirements are currently met, use this for display purposes, use isActive for + * status. + */ + boolean meetsChannelRequirements(); + + /** + * see if this node has a certain flag + * + * @param tier2Capacity + * @return + */ + boolean hasFlag(GridFlags flag); + + /** + * tell the node who was responsible for placing it, failure to do this may result in in-compatibility with the + * security system. Called instead of loadFromNBT when intialily placed, once set never required again, the value is saved with the Node NBT. + * + * @param p + */ + void setPlayerID(int playerID); + + /** + * @return the ownerID this represents the person who placed the node. + */ + int getPlayerID(); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/networking/IGridStorage.java b/src/main/java/appeng/api/networking/IGridStorage.java new file mode 100644 index 0000000..c4c7c1e --- /dev/null +++ b/src/main/java/appeng/api/networking/IGridStorage.java @@ -0,0 +1,18 @@ +package appeng.api.networking; + +import net.minecraft.nbt.NBTTagCompound; + +public interface IGridStorage +{ + + /** + * @return an NBTTagCompound that can be read, and written too. + */ + NBTTagCompound dataObject(); + + /** + * @return the id for this grid storage object, used internally + */ + long getID(); + +} diff --git a/src/main/java/appeng/api/networking/IGridVisitor.java b/src/main/java/appeng/api/networking/IGridVisitor.java new file mode 100644 index 0000000..2593160 --- /dev/null +++ b/src/main/java/appeng/api/networking/IGridVisitor.java @@ -0,0 +1,21 @@ +package appeng.api.networking; + +/** + * Simple Visitor pattern access to network nodes. + */ +public interface IGridVisitor +{ + + /** + * Called for each node on the network. + * + * By returning false your informing the host to stop visiting nodes beyond the current node. + * + * @param n + * the current node. + * + * @return true to continue visiting nodes beyond this node. + */ + public boolean visitNode(IGridNode n); + +} diff --git a/src/main/java/appeng/api/networking/IMachineSet.java b/src/main/java/appeng/api/networking/IMachineSet.java new file mode 100644 index 0000000..080eeb2 --- /dev/null +++ b/src/main/java/appeng/api/networking/IMachineSet.java @@ -0,0 +1,13 @@ +package appeng.api.networking; + +import appeng.api.util.IReadOnlyCollection; + +public interface IMachineSet extends IReadOnlyCollection +{ + + /** + * @return the machine class for this set. + */ + Class getMachineClass(); + +} diff --git a/src/main/java/appeng/api/networking/crafting/CraftingItemList.java b/src/main/java/appeng/api/networking/crafting/CraftingItemList.java new file mode 100644 index 0000000..1b2db3a --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/CraftingItemList.java @@ -0,0 +1,6 @@ +package appeng.api.networking.crafting; + +public enum CraftingItemList +{ + ALL, STORAGE, ACTIVE, PENDING +} diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingCPU.java b/src/main/java/appeng/api/networking/crafting/ICraftingCPU.java new file mode 100644 index 0000000..0f00e53 --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/ICraftingCPU.java @@ -0,0 +1,35 @@ +package appeng.api.networking.crafting; + +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.storage.IBaseMonitor; +import appeng.api.storage.data.IAEItemStack; + +public interface ICraftingCPU extends IBaseMonitor +{ + + /** + * @return true if the CPU currently has a job. + */ + boolean isBusy(); + + /** + * @return the action source for the CPU. + */ + BaseActionSource getActionSource(); + + /** + * @return the available storage in bytes + */ + long getAvailableStorage(); + + /** + * @return the number of co-processors in the CPU. + */ + int getCoProcessors(); + + /** + * @return an empty string or the name of the cpu. + */ + String getName(); + +} diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingCallback.java b/src/main/java/appeng/api/networking/crafting/ICraftingCallback.java new file mode 100644 index 0000000..e61ae2c --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/ICraftingCallback.java @@ -0,0 +1,14 @@ +package appeng.api.networking.crafting; + +public interface ICraftingCallback +{ + + /** + * this call back is synchronized with the world you passed. + * + * @param job + * - final job + */ + public void calculationComplete(ICraftingJob job); + +} diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingGrid.java b/src/main/java/appeng/api/networking/crafting/ICraftingGrid.java new file mode 100644 index 0000000..65890cc --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/ICraftingGrid.java @@ -0,0 +1,85 @@ +package appeng.api.networking.crafting; + +import java.util.concurrent.Future; + +import net.minecraft.world.World; +import appeng.api.networking.IGrid; +import appeng.api.networking.IGridCache; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.storage.data.IAEItemStack; + +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableSet; + +public interface ICraftingGrid extends IGridCache +{ + + /** + * @param whatToCraft + * @param world + * @param slot + * @param details + * @return a collection of crafting patterns for the item in question. + */ + ImmutableCollection getCraftingFor(IAEItemStack whatToCraft, ICraftingPatternDetails details, int slot, World world); + + /** + * Begin calculating a crafting job. + * + * @param world + * @param grid + * @param actionSrc + * @param craftWhat + * @param callback + * -- optional + * + * @return a future which will at an undetermined point in the future get you the {@link ICraftingJob} do not wait + * on this, your be waiting forever. + */ + Future beginCraftingJob(World world, IGrid grid, BaseActionSource actionSrc, IAEItemStack craftWhat, ICraftingCallback callback); + + /** + * Submit the job to the Crafting system for processing. + * + * @param result + * - the crafting job from beginCraftingJob + * @param requestingMachine + * - a machine if its being requested via automation, may be null. + * @param cpu + * - can be null + * + * @param prioritizePower + * - if cpu is null, this determine if the system should prioritize power, or if it should find the lower + * end cpus, automatic processes generally should pick lower end cpus. + * + * @param actionSrc + * - the action source to use when starting the job, this will be used for extracting items, should + * usually be the same as the one provided to beginCraftingJob. + * + * @return null ( if failed ) or an {@link ICraftingLink} other wise, if you send requestingMachine you need to + * properly keep track of this and handle the nbt saving and loading of the object as well as the + * {@link ICraftingRequester} methods. if you send null, this object should be discarded after verifying the + * return state. + */ + ICraftingLink submitJob(ICraftingJob job, ICraftingRequester requestingMachine, ICraftingCPU target, boolean prioritizePower, BaseActionSource src); + + /** + * @return list of all the crafting cpus on the grid + */ + ImmutableSet getCpus(); + + /** + * @param what + * @return true if the item can be requested via a crafting emitter. + */ + boolean canEmitFor(IAEItemStack what); + + /** + * is this item being crafted? + * + * @param aeStackInSlot + * @return + */ + boolean isRequesting(IAEItemStack aeStackInSlot); + +} diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingJob.java b/src/main/java/appeng/api/networking/crafting/ICraftingJob.java new file mode 100644 index 0000000..fcef0f9 --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/ICraftingJob.java @@ -0,0 +1,33 @@ +package appeng.api.networking.crafting; + +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; + +public interface ICraftingJob +{ + + /** + * @return if this job is a simulation, simulations cannot be submitted and only represent 1 possible future + * crafting job with fake items. + */ + boolean isSimulation(); + + /** + * @return total number of bytes to process this job. + */ + long getByteTotal(); + + /** + * Populates the plan list with stack size, and requestable values that represent the stored, and crafting job + * contents respectively. + * + * @param plan + */ + void populatePlan(IItemList plan); + + /** + * @return the final output of the job. + */ + IAEItemStack getOutput(); + +} diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingLink.java b/src/main/java/appeng/api/networking/crafting/ICraftingLink.java new file mode 100644 index 0000000..d1a480c --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/ICraftingLink.java @@ -0,0 +1,40 @@ +package appeng.api.networking.crafting; + +import net.minecraft.nbt.NBTTagCompound; + +public interface ICraftingLink +{ + + /** + * @return true if the job was canceled. + */ + boolean isCanceled(); + + /** + * @return true if the job was completed. + */ + boolean isDone(); + + /** + * cancels the job. + */ + void cancel(); + + /** + * @return true if this link was generated without a requesting machine, such as a player generated request. + */ + boolean isStandalone(); + + /** + * write the link to an NBT Tag + * + * @param tag + */ + void writeToNBT(NBTTagCompound tag); + + /** + * @return the crafting ID for this link. + */ + String getCraftingID(); + +} diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingMedium.java b/src/main/java/appeng/api/networking/crafting/ICraftingMedium.java new file mode 100644 index 0000000..ba27d8c --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/ICraftingMedium.java @@ -0,0 +1,27 @@ +package appeng.api.networking.crafting; + +import net.minecraft.inventory.InventoryCrafting; + +/** + * A place to send Items for crafting purposes, this is considered part of AE's External crafting system. + */ +public interface ICraftingMedium +{ + + /** + * instruct a medium to create the item represented by the pattern+details, the items on the table, and where if + * possible the output should be directed. + * + * @param pattern + * @param patternDetails + * @param table + * @return if the pattern was successfully pushed. + */ + boolean pushPattern(ICraftingPatternDetails patternDetails, InventoryCrafting table); + + /** + * @return if this is false, the crafting engine will refuse to send new jobs to this medium. + */ + boolean isBusy(); + +} diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingPatternDetails.java b/src/main/java/appeng/api/networking/crafting/ICraftingPatternDetails.java new file mode 100644 index 0000000..f364e5e --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/ICraftingPatternDetails.java @@ -0,0 +1,77 @@ +package appeng.api.networking.crafting; + +import net.minecraft.inventory.InventoryCrafting; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import appeng.api.implementations.ICraftingPatternItem; +import appeng.api.storage.data.IAEItemStack; + +/** + * do not implement provided by {@link ICraftingPatternItem} + * + * caching this instance will increase preformance of validation and checks. + */ +public interface ICraftingPatternDetails +{ + + /** + * @return source item. + */ + ItemStack getPattern(); + + /** + * @param slotIndex + * @param itemStack + * @param world + * + * @return if an item can be used in the specific slot for this pattern. + */ + boolean isValidItemForSlot(int slotIndex, ItemStack itemStack, World world); + + /** + * @return if this pattern is a crafting pattern ( work bench ) + */ + boolean isCraftable(); + + /** + * @return a list of the inputs, will include nulls. + */ + IAEItemStack[] getInputs(); + + /** + * @return a list of the inputs, will be clean + */ + IAEItemStack[] getCondencedInputs(); + + /** + * @return a list of the outputs, will be clean + */ + IAEItemStack[] getCondencedOutputs(); + + /** + * @return a list of the outputs, will include nulls. + */ + IAEItemStack[] getOutputs(); + + /** + * @return if this pattern is enabled to support substitutions. + */ + boolean canSubstitute(); + + /** + * Allow using this instance of the pattern details to preform the crafting action with preformance enhancements. + * + * @param craftingInv + * @param world + * @return the crafted ( work bench ) item. + */ + ItemStack getOutput(InventoryCrafting craftingInv, World world); + + /** + * Set the priority the of this pattern. + * + * @param priority + */ + void setPriority(int priority); + +} diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingProvider.java b/src/main/java/appeng/api/networking/crafting/ICraftingProvider.java new file mode 100644 index 0000000..11faa2b --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/ICraftingProvider.java @@ -0,0 +1,19 @@ +package appeng.api.networking.crafting; + +import appeng.api.networking.events.MENetworkCraftingPatternChange; + +/** + * Allows a IGridHost to provide crafting patterns to the network, post a {@link MENetworkCraftingPatternChange} to tell + * AE2 to update. + */ +public interface ICraftingProvider extends ICraftingMedium +{ + + /** + * called when the network is looking for possible crafting jobs. + * + * @param craftingTracker + */ + void provideCrafting(ICraftingProviderHelper craftingTracker); + +} diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingProviderHelper.java b/src/main/java/appeng/api/networking/crafting/ICraftingProviderHelper.java new file mode 100644 index 0000000..f31a01a --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/ICraftingProviderHelper.java @@ -0,0 +1,21 @@ +package appeng.api.networking.crafting; + +import appeng.api.storage.data.IAEItemStack; + +/** + * Passed to a ICraftingProvider as a interface to manipulate the available crafting jobs. + */ +public interface ICraftingProviderHelper +{ + + /** + * Add new Pattern to AE's crafting cache. + */ + void addCraftingOption(ICraftingMedium medium, ICraftingPatternDetails api); + + /** + * Set an item can Emitable + */ + void setEmitable(IAEItemStack what); + +} diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingRequester.java b/src/main/java/appeng/api/networking/crafting/ICraftingRequester.java new file mode 100644 index 0000000..c0eabbe --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/ICraftingRequester.java @@ -0,0 +1,37 @@ +package appeng.api.networking.crafting; + +import appeng.api.config.Actionable; +import appeng.api.networking.security.IActionHost; +import appeng.api.storage.data.IAEItemStack; + +import com.google.common.collect.ImmutableSet; + +public interface ICraftingRequester extends IActionHost +{ + + /** + * called when the host is added to the grid, and should return all crafting links it poses so they can be connected + * with the cpu that hosts the job. + * + * @return set of jobs, or an empty list. + */ + ImmutableSet getRequestedJobs(); + + /** + * items are injected into the requester as they are completed, any items that cannot be taken, or are unwanted can + * be returned. + * + * @param items + * @param mode + * @return + */ + IAEItemStack injectCratedItems(ICraftingLink link, IAEItemStack items, Actionable mode); + + /** + * called when the job changes from in progress, to either complete, or canceled. + * + * after this call the crafting link is "dead" and should be discarded. + */ + void jobStateChange(ICraftingLink link); + +} diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingWatcher.java b/src/main/java/appeng/api/networking/crafting/ICraftingWatcher.java new file mode 100644 index 0000000..64cffd3 --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/ICraftingWatcher.java @@ -0,0 +1,10 @@ +package appeng.api.networking.crafting; + +import java.util.Collection; + +import appeng.api.storage.data.IAEStack; + +public interface ICraftingWatcher extends Collection +{ + +} diff --git a/src/main/java/appeng/api/networking/crafting/ICraftingWatcherHost.java b/src/main/java/appeng/api/networking/crafting/ICraftingWatcherHost.java new file mode 100644 index 0000000..4cc7ee3 --- /dev/null +++ b/src/main/java/appeng/api/networking/crafting/ICraftingWatcherHost.java @@ -0,0 +1,24 @@ +package appeng.api.networking.crafting; + +import appeng.api.storage.data.IAEItemStack; + +public interface ICraftingWatcherHost +{ + + /** + * provides the ICraftngiWatcher for this host, for the current network, is called when the hot changes networks. + * You do not need to clear your old watcher, its already been removed by the time this gets called. + * + * @param newWatcher + */ + void updateWatcher(ICraftingWatcher newWatcher); + + /** + * Called when a crafting status changes. + * + * @param craftingGrid + * @param what + */ + void onRequestChange(ICraftingGrid craftingGrid, IAEItemStack what); + +} diff --git a/src/main/java/appeng/api/networking/energy/IAEPowerStorage.java b/src/main/java/appeng/api/networking/energy/IAEPowerStorage.java new file mode 100644 index 0000000..3256ed2 --- /dev/null +++ b/src/main/java/appeng/api/networking/energy/IAEPowerStorage.java @@ -0,0 +1,46 @@ +package appeng.api.networking.energy; + +import appeng.api.config.AccessRestriction; +import appeng.api.config.Actionable; + +/** + * Used to access information about AE's various power accepting blocks for monitoring purposes. + */ +public interface IAEPowerStorage extends IEnergySource +{ + + /** + * Inject amt, power into the device, it will store what it can, and return the amount unable to be stored. + * + * @param simulate + * + * @return + */ + public double injectAEPower(double amt, Actionable mode); + + /** + * @return the current maximum power ( this can change :P ) + */ + public double getAEMaxPower(); + + /** + * @return the current AE Power Level, this may exceed getMEMaxPower() + */ + public double getAECurrentPower(); + + /** + * Checked on network reset to see if your block can be used as a public power storage ( use getPowerFlow to control + * the behavior ) + * + * @return + */ + public boolean isAEPublicPowerStorage(); + + /** + * Control the power flow by telling what the network can do, either add? or subtract? or both! + * + * @return + */ + public AccessRestriction getPowerFlow(); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/networking/energy/IEnergyGrid.java b/src/main/java/appeng/api/networking/energy/IEnergyGrid.java new file mode 100644 index 0000000..041cfeb --- /dev/null +++ b/src/main/java/appeng/api/networking/energy/IEnergyGrid.java @@ -0,0 +1,82 @@ +package appeng.api.networking.energy; + +import appeng.api.config.Actionable; +import appeng.api.networking.IGridCache; +import appeng.api.networking.events.MENetworkPowerStatusChange; + +/** + * AE's Power system. + */ +public interface IEnergyGrid extends IGridCache, IEnergySource, IEnergyGridProvider +{ + + /** + * @return the current calculated idle energy drain each tick, is used internally to drain power for each tick. + */ + public double getIdlePowerUsage(); + + /** + * @return the average power drain over the past 10 ticks, includes idle usage during this time, and all use of + * extractPower. + */ + public double getAvgPowerUsage(); + + /** + * @return the average energy injected into the system per tick, for the last 10 ticks. + */ + public double getAvgPowerInjection(); + + /** + * AE maintains an idle draw of power separate from active power draw, it condenses this into a single operation + * that determines the networks "powered state" if the network is considered off-line, your machines should not + * function. + * + * {@link MENetworkPowerStatusChange} events are posted when this value changes if you need to be notified of the + * change, most machines can simply test the value when they operate. + * + * @return if the network is powered or not. + */ + public boolean isNetworkPowered(); + + /** + * AE will accept any power, and store it, to maintain sanity please don't send more then 10,000 at a time. + * + * IMPORTANT: Network power knows no bounds, for less spamy power flow, networks can store more then their alloted + * storage, however, it should be kept to a minimum, to help with this, this method returns the networks current + * OVERFLOW, this is not energy you can store some where else, its already stored in the network, you can extract it + * if you want, however it it owned by the network, this is different then IAEEnergyStore + * + * Another important note, is that if a network that had overflow is deleted, its power is gone, this is one of the + * reasons why keeping overflow to a minimum is important. + * + * @param amt + * power to inject into the network + * @param mode + * should the action be simulated or performed? + * @return the amount of power that the network has OVER the limit. + */ + public double injectPower(double amt, Actionable mode); + + /** + * this is should be considered an estimate, and not relied upon for real calculations. + * + * @return estimated available power. + */ + public double getStoredPower(); + + /** + * this is should be considered an estimate, and not relied upon for real calculations. + * + * @return estimated available power. + */ + double getMaxStoredPower(); + + /** + * Calculation will be capped at maxRequired, this improves performance by limiting the number of nodes needed to + * calculate the demand. + * + * @return Amount of power required to charge the grid, in AE. + */ + public double getEnergyDemand(double maxRequired); + +} diff --git a/src/main/java/appeng/api/networking/energy/IEnergyGridProvider.java b/src/main/java/appeng/api/networking/energy/IEnergyGridProvider.java new file mode 100644 index 0000000..a741263 --- /dev/null +++ b/src/main/java/appeng/api/networking/energy/IEnergyGridProvider.java @@ -0,0 +1,28 @@ +package appeng.api.networking.energy; + +import java.util.Set; + +import appeng.api.config.Actionable; + +/** + * internal use only. + */ +public interface IEnergyGridProvider +{ + + /** + * internal use only + */ + public double extractAEPower(double amt, Actionable mode, Set seen); + + /** + * internal use only + */ + public double injectAEPower(double amt, Actionable mode, Set seen); + + /** + * internal use only + */ + public double getEnergyDemand(double d, Set seen); + +} diff --git a/src/main/java/appeng/api/networking/energy/IEnergySource.java b/src/main/java/appeng/api/networking/energy/IEnergySource.java new file mode 100644 index 0000000..fa18d1e --- /dev/null +++ b/src/main/java/appeng/api/networking/energy/IEnergySource.java @@ -0,0 +1,19 @@ +package appeng.api.networking.energy; + +import appeng.api.config.Actionable; +import appeng.api.config.PowerMultiplier; + +public interface IEnergySource +{ + + /** + * Extract power from the network. + * + * @param amt + * @param mode + * should the action be simulated or performed? + * @return returns extracted power. + */ + public double extractAEPower(double amt, Actionable mode, PowerMultiplier usePowerMultiplier); + +} diff --git a/src/main/java/appeng/api/networking/energy/IEnergyWatcher.java b/src/main/java/appeng/api/networking/energy/IEnergyWatcher.java new file mode 100644 index 0000000..20e7a8e --- /dev/null +++ b/src/main/java/appeng/api/networking/energy/IEnergyWatcher.java @@ -0,0 +1,8 @@ +package appeng.api.networking.energy; + +import java.util.Collection; + +public interface IEnergyWatcher extends Collection +{ + +} diff --git a/src/main/java/appeng/api/networking/energy/IEnergyWatcherHost.java b/src/main/java/appeng/api/networking/energy/IEnergyWatcherHost.java new file mode 100644 index 0000000..c844d73 --- /dev/null +++ b/src/main/java/appeng/api/networking/energy/IEnergyWatcherHost.java @@ -0,0 +1,21 @@ +package appeng.api.networking.energy; + +public interface IEnergyWatcherHost +{ + + /** + * provides the IEnergyWatcher for this host, for the current network, is called when the hot changes networks. You + * do not need to clear your old watcher, its already been removed by the time this gets called. + * + * @param newWatcher + */ + void updateWatcher(IEnergyWatcher newWatcher); + + /** + * Called when a threshold is crossed. + * + * @param energyGrid + */ + void onThreshholdPass(IEnergyGrid energyGrid); + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkBootingStatusChange.java b/src/main/java/appeng/api/networking/events/MENetworkBootingStatusChange.java new file mode 100644 index 0000000..284c64e --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkBootingStatusChange.java @@ -0,0 +1,14 @@ +package appeng.api.networking.events; + +import appeng.api.networking.IGridNode; + +/** + * Posted by the network when the booting status of the network goes up + * or down, the change is reflected via {@link IGridNode}.isActive() + * + * Note: Most machines just need to check {@link IGridNode}.isActive() + */ +public class MENetworkBootingStatusChange extends MENetworkEvent +{ + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkCellArrayUpdate.java b/src/main/java/appeng/api/networking/events/MENetworkCellArrayUpdate.java new file mode 100644 index 0000000..1260216 --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkCellArrayUpdate.java @@ -0,0 +1,15 @@ +package appeng.api.networking.events; + +/** + * Posted by storage devices to inform AE to refreash its storage structure. + * + * This is done in cases such as a storage cell being removed or added to a + * drive. + * + * you do not need to send this event when your node is added / removed from the + * grid. + */ +public class MENetworkCellArrayUpdate extends MENetworkEvent +{ + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkChannelChanged.java b/src/main/java/appeng/api/networking/events/MENetworkChannelChanged.java new file mode 100644 index 0000000..85409c5 --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkChannelChanged.java @@ -0,0 +1,18 @@ +package appeng.api.networking.events; + +import appeng.api.networking.IGridNode; + +/** + * Posted by storage devices to inform AE he channel chache that the included node has changed its mind about its + * channel requirements. + */ +public class MENetworkChannelChanged extends MENetworkEvent +{ + + public final IGridNode node; + + public MENetworkChannelChanged(IGridNode n) { + node = n; + } + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkChannelsChanged.java b/src/main/java/appeng/api/networking/events/MENetworkChannelsChanged.java new file mode 100644 index 0000000..ebfed6c --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkChannelsChanged.java @@ -0,0 +1,13 @@ +package appeng.api.networking.events; + +import appeng.api.networking.IGridHost; + +/** + * Posted to the {@link IGridHost} when the channels on the node connections are altered. + * + * Never posted IGridCaches. + */ +public class MENetworkChannelsChanged extends MENetworkEvent +{ + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkControllerChange.java b/src/main/java/appeng/api/networking/events/MENetworkControllerChange.java new file mode 100644 index 0000000..97db164 --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkControllerChange.java @@ -0,0 +1,11 @@ +package appeng.api.networking.events; + +/** + * Event posted when the networks controller state changes, this can be from no + * controller to 1 controller, or any time the network changes from conflicted + * to not conflicted. + */ +public class MENetworkControllerChange extends MENetworkEvent +{ + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkCraftingCpuChange.java b/src/main/java/appeng/api/networking/events/MENetworkCraftingCpuChange.java new file mode 100644 index 0000000..a52eab5 --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkCraftingCpuChange.java @@ -0,0 +1,14 @@ +package appeng.api.networking.events; + +import appeng.api.networking.IGridNode; + +public class MENetworkCraftingCpuChange extends MENetworkEvent +{ + + public final IGridNode node; + + public MENetworkCraftingCpuChange(IGridNode n) { + node = n; + } + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkCraftingPatternChange.java b/src/main/java/appeng/api/networking/events/MENetworkCraftingPatternChange.java new file mode 100644 index 0000000..13f735f --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkCraftingPatternChange.java @@ -0,0 +1,17 @@ +package appeng.api.networking.events; + +import appeng.api.networking.IGridNode; +import appeng.api.networking.crafting.ICraftingProvider; + +public class MENetworkCraftingPatternChange extends MENetworkEvent +{ + + public final ICraftingProvider provider; + public final IGridNode node; + + public MENetworkCraftingPatternChange(ICraftingProvider p, IGridNode n) { + provider = p; + node = n; + } + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkEvent.java b/src/main/java/appeng/api/networking/events/MENetworkEvent.java new file mode 100644 index 0000000..3fb2dd3 --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkEvent.java @@ -0,0 +1,53 @@ +package appeng.api.networking.events; + +import appeng.api.networking.IGrid; + +/** + * Part of AE's Event Bus. + * + * Posted via {@link IGrid}.postEvent or {@link IGrid}.postEventTo + */ +public class MENetworkEvent +{ + + private int visited = 0; + private boolean canceled = false; + + /** + * Call to prevent AE from posting the event to any further objects. + */ + public void cancel() + { + canceled = true; + } + + /** + * called by AE after each object is called to cancel any future calls. + * + * @return + */ + public boolean isCanceled() + { + return canceled; + } + + /** + * the number of objects that were visited by the event. + * + * @return + */ + public int getVisitedObjects() + { + return visited; + } + + /** + * Called by AE after iterating the event subscribers. + * + * @param v + */ + public void setVisitedObjects(int v) + { + visited = v; + } +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkEventSubscribe.java b/src/main/java/appeng/api/networking/events/MENetworkEventSubscribe.java new file mode 100644 index 0000000..b3b8fb9 --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkEventSubscribe.java @@ -0,0 +1,15 @@ +package appeng.api.networking.events; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import appeng.api.networking.IGridCache; +import appeng.api.networking.IGridHost; + +/** + * Usable on any {@link IGridHost}, or {@link IGridCache} + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface MENetworkEventSubscribe { + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkPostCacheConstruction.java b/src/main/java/appeng/api/networking/events/MENetworkPostCacheConstruction.java new file mode 100644 index 0000000..05b2812 --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkPostCacheConstruction.java @@ -0,0 +1,10 @@ +package appeng.api.networking.events; + +/** + * Posted after all the caches are available, but before the grid is fully + * constructed, can be used to perform cross cache construction processes. + */ +public class MENetworkPostCacheConstruction extends MENetworkEvent +{ + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkPowerIdleChange.java b/src/main/java/appeng/api/networking/events/MENetworkPowerIdleChange.java new file mode 100644 index 0000000..5936684 --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkPowerIdleChange.java @@ -0,0 +1,21 @@ +package appeng.api.networking.events; + +import appeng.api.networking.IGridNode; + +/** + * Implementors of a IGridBlock must post this event when your getIdlePowerUsage + * starts returning a new value, if you do not post this event the network will + * not change the idle draw. + * + * you do not need to send this event when your node is added / removed from the grid. + */ +public class MENetworkPowerIdleChange extends MENetworkEvent +{ + + public final IGridNode node; + + public MENetworkPowerIdleChange(IGridNode nodeThatChanged) { + node = nodeThatChanged; + } + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkPowerStatusChange.java b/src/main/java/appeng/api/networking/events/MENetworkPowerStatusChange.java new file mode 100644 index 0000000..c89db97 --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkPowerStatusChange.java @@ -0,0 +1,16 @@ +package appeng.api.networking.events; + +import appeng.api.networking.IGridNode; +import appeng.api.networking.energy.IEnergyGrid; + +/** + * Posted by the network when the power status of the network goes up or down, + * the change is reflected via the {@link IEnergyGrid}.isNetworkPowered() or via + * {@link IGridNode}.isActive() + * + * Note: Most machines just need to check {@link IGridNode}.isActive() + */ +public class MENetworkPowerStatusChange extends MENetworkEvent +{ + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkPowerStorage.java b/src/main/java/appeng/api/networking/events/MENetworkPowerStorage.java new file mode 100644 index 0000000..cd907bc --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkPowerStorage.java @@ -0,0 +1,38 @@ +package appeng.api.networking.events; + +import appeng.api.networking.energy.IAEPowerStorage; + +/** + * informs the network, that a {@link IAEPowerStorage} block that had either run, + * out of power, or was full, is no longer in that state. + * + * failure to post this event when your {@link IAEPowerStorage} changes state will + * result in your block not charging, or not-discharging. + * + * you do not need to send this event when your node is added / removed from the grid. + */ +public class MENetworkPowerStorage extends MENetworkEvent +{ + + public enum PowerEventType + { + /** + * informs the network this tile is ready to receive power again. + */ + REQUEST_POWER, + + /** + * informs the network this tile is ready to provide power again. + */ + PROVIDE_POWER + }; + + public final IAEPowerStorage storage; + public final PowerEventType type; + + public MENetworkPowerStorage(IAEPowerStorage t, PowerEventType y) { + storage = t; + type = y; + } + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkSecurityChange.java b/src/main/java/appeng/api/networking/events/MENetworkSecurityChange.java new file mode 100644 index 0000000..b872f03 --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkSecurityChange.java @@ -0,0 +1,9 @@ +package appeng.api.networking.events; + +/** + * Posted by the security framework when permissions change + */ +public class MENetworkSecurityChange extends MENetworkEvent +{ + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkSpatialEvent.java b/src/main/java/appeng/api/networking/events/MENetworkSpatialEvent.java new file mode 100644 index 0000000..2ba0f7b --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkSpatialEvent.java @@ -0,0 +1,26 @@ +package appeng.api.networking.events; + +import appeng.api.networking.IGridHost; + +/** + * An event that is posted Whenever a spatial IO is Actived, called for IGridCache + * + * @param IGridHost ( instance of the SpatialIO block ) + * @param double ( the amount of energy that the SpatialIO uses) + */ + + +public class MENetworkSpatialEvent extends MENetworkEvent +{ + + public final IGridHost host; + public final double spatialEnergyUsage; + + + public MENetworkSpatialEvent(IGridHost SpatialIO, double EnergyUsage) { + host = SpatialIO; + spatialEnergyUsage = EnergyUsage; + + } + +} diff --git a/src/main/java/appeng/api/networking/events/MENetworkStorageEvent.java b/src/main/java/appeng/api/networking/events/MENetworkStorageEvent.java new file mode 100644 index 0000000..36a9362 --- /dev/null +++ b/src/main/java/appeng/api/networking/events/MENetworkStorageEvent.java @@ -0,0 +1,25 @@ +package appeng.api.networking.events; + +import appeng.api.storage.IMEMonitor; +import appeng.api.storage.StorageChannel; + +/** + * posted by the network when the networks Storage Changes, you can use the currentItems list to check levels, and + * update status. + * + * this is the least useful method of getting info about changes in the network. + * + * Do not modify the list or its contents in anyway. + */ +public class MENetworkStorageEvent extends MENetworkEvent +{ + + public final IMEMonitor monitor; + public final StorageChannel channel; + + public MENetworkStorageEvent(IMEMonitor o, StorageChannel chan) { + monitor = o; + channel = chan; + } + +} diff --git a/src/main/java/appeng/api/networking/pathing/ControllerState.java b/src/main/java/appeng/api/networking/pathing/ControllerState.java new file mode 100644 index 0000000..3704272 --- /dev/null +++ b/src/main/java/appeng/api/networking/pathing/ControllerState.java @@ -0,0 +1,19 @@ +package appeng.api.networking.pathing; + +public enum ControllerState +{ + /** + * No controller blocks are present in the network. + */ + NO_CONTROLLER, + + /** + * Controller rules followed, booting enabled. + */ + CONTROLLER_ONLINE, + + /** + * Controller rules not followed, lock up while booting. + */ + CONTROLLER_CONFLICT +} diff --git a/src/main/java/appeng/api/networking/pathing/IPathingGrid.java b/src/main/java/appeng/api/networking/pathing/IPathingGrid.java new file mode 100644 index 0000000..90f30e0 --- /dev/null +++ b/src/main/java/appeng/api/networking/pathing/IPathingGrid.java @@ -0,0 +1,24 @@ +package appeng.api.networking.pathing; + +import appeng.api.networking.IGridCache; + +public interface IPathingGrid extends IGridCache +{ + + /** + * @return true if the network is in its booting stage + */ + boolean isNetworkBooting(); + + /** + * @return the controller state of the network, useful if you want to + * require a controller for a feature. + */ + ControllerState getControllerState(); + + /** + * trigger a network reset, booting, pathfinding and all. + */ + void repath(); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/networking/security/BaseActionSource.java b/src/main/java/appeng/api/networking/security/BaseActionSource.java new file mode 100644 index 0000000..193b37e --- /dev/null +++ b/src/main/java/appeng/api/networking/security/BaseActionSource.java @@ -0,0 +1,16 @@ +package appeng.api.networking.security; + +public class BaseActionSource +{ + + public boolean isPlayer() + { + return false; + } + + public boolean isMachine() + { + return false; + } + +} diff --git a/src/main/java/appeng/api/networking/security/IActionHost.java b/src/main/java/appeng/api/networking/security/IActionHost.java new file mode 100644 index 0000000..e6aa7a1 --- /dev/null +++ b/src/main/java/appeng/api/networking/security/IActionHost.java @@ -0,0 +1,19 @@ +package appeng.api.networking.security; + +import appeng.api.networking.IGridHost; +import appeng.api.networking.IGridNode; + +public interface IActionHost extends IGridHost +{ + + /** + * Used to for calculating security rules, you must supply a node from your + * IGridHost for the security test, this should be the primary node for the + * machine, unless the action is preformed by a non primary node. + * + * @return the the gridnode that actions from this IGridHost are preformed + * by. + */ + IGridNode getActionableNode(); + +} diff --git a/src/main/java/appeng/api/networking/security/ISecurityGrid.java b/src/main/java/appeng/api/networking/security/ISecurityGrid.java new file mode 100644 index 0000000..6fb1d85 --- /dev/null +++ b/src/main/java/appeng/api/networking/security/ISecurityGrid.java @@ -0,0 +1,40 @@ +package appeng.api.networking.security; + +import net.minecraft.entity.player.EntityPlayer; +import appeng.api.config.SecurityPermissions; +import appeng.api.networking.IGridCache; + +public interface ISecurityGrid extends IGridCache +{ + + /** + * @return true if a security provider is in the network ( and only 1 ) + */ + boolean isAvailable(); + + /** + * Check if a player has permissions. + * + * @param player + * @param perm + * + * @return true if the player has permissions. + */ + boolean hasPermission(EntityPlayer player, SecurityPermissions perm); + + /** + * Check if a player has permissions. + * + * @param player + * @param perm + * + * @return true if the player has permissions. + */ + boolean hasPermission(int playerID, SecurityPermissions perm); + + /** + * @return PlayerID of the admin, or owner, this is the person who placed the security block. + */ + int getOwner(); + +} diff --git a/src/main/java/appeng/api/networking/security/ISecurityProvider.java b/src/main/java/appeng/api/networking/security/ISecurityProvider.java new file mode 100644 index 0000000..6db5f34 --- /dev/null +++ b/src/main/java/appeng/api/networking/security/ISecurityProvider.java @@ -0,0 +1,38 @@ +package appeng.api.networking.security; + +import java.util.EnumSet; +import java.util.HashMap; + +import appeng.api.config.SecurityPermissions; + +/** + * Implemented on Security Terminal to interface with security cache. + */ +public interface ISecurityProvider +{ + + /** + * used to represent the security key for the network, should be based on a unique timestamp. + * + * @return unique key. + */ + long getSecurityKey(); + + /** + * Push permission data into security cache. + * + * @param playerPerms + */ + void readPermissions(HashMap> playerPerms); + + /** + * @return is security on or off? + */ + boolean isSecurityEnabled(); + + /** + * @return player ID for who placed the security provider. + */ + int getOwner(); + +} diff --git a/src/main/java/appeng/api/networking/security/ISecurityRegister.java b/src/main/java/appeng/api/networking/security/ISecurityRegister.java new file mode 100644 index 0000000..1f1ef35 --- /dev/null +++ b/src/main/java/appeng/api/networking/security/ISecurityRegister.java @@ -0,0 +1,21 @@ +package appeng.api.networking.security; + +import java.util.EnumSet; + +import appeng.api.config.SecurityPermissions; + +/** + * Used by vanilla Security Terminal to post biometric data into the security cache. + */ +public interface ISecurityRegister +{ + + /** + * Submit Permissions into the register. + * + * @param PlayerID + * @param permissions + */ + void addPlayer(int PlayerID, EnumSet permissions); + +} diff --git a/src/main/java/appeng/api/networking/security/MachineSource.java b/src/main/java/appeng/api/networking/security/MachineSource.java new file mode 100644 index 0000000..ddce68f --- /dev/null +++ b/src/main/java/appeng/api/networking/security/MachineSource.java @@ -0,0 +1,18 @@ +package appeng.api.networking.security; + +public class MachineSource extends BaseActionSource +{ + + public final IActionHost via; + + @Override + public boolean isMachine() + { + return true; + } + + public MachineSource(IActionHost v) { + via = v; + } + +} diff --git a/src/main/java/appeng/api/networking/security/PlayerSource.java b/src/main/java/appeng/api/networking/security/PlayerSource.java new file mode 100644 index 0000000..335a16a --- /dev/null +++ b/src/main/java/appeng/api/networking/security/PlayerSource.java @@ -0,0 +1,22 @@ +package appeng.api.networking.security; + +import net.minecraft.entity.player.EntityPlayer; + +public class PlayerSource extends BaseActionSource +{ + + public final EntityPlayer player; + public final IActionHost via; + + @Override + public boolean isPlayer() + { + return true; + } + + public PlayerSource(EntityPlayer p, IActionHost v) { + player = p; + via = v; + } + +} diff --git a/src/main/java/appeng/api/networking/spatial/ISpatialCache.java b/src/main/java/appeng/api/networking/spatial/ISpatialCache.java new file mode 100644 index 0000000..3a97868 --- /dev/null +++ b/src/main/java/appeng/api/networking/spatial/ISpatialCache.java @@ -0,0 +1,39 @@ +package appeng.api.networking.spatial; + +import appeng.api.networking.IGridCache; +import appeng.api.util.DimensionalCoord; + +public interface ISpatialCache extends IGridCache +{ + + /** + * @return true if a region is defined at all, it dosn't have to be valid, but all points must be in the same world. + */ + boolean hasRegion(); + + /** + * @return true if the region defined is valid according to all rules. + */ + boolean isValidRegion(); + + /** + * @return the minimum anchor point for the spatial region. + */ + DimensionalCoord getMin(); + + /** + * @return the maximum anchor point for the spatial region. + */ + DimensionalCoord getMax(); + + /** + * @return how many AE units are required to preform the activation + */ + long requiredPower(); + + /** + * @return current 100% - 0% effiency. + */ + float currentEffiency(); + +} diff --git a/src/main/java/appeng/api/networking/storage/IBaseMonitor.java b/src/main/java/appeng/api/networking/storage/IBaseMonitor.java new file mode 100644 index 0000000..9f1848f --- /dev/null +++ b/src/main/java/appeng/api/networking/storage/IBaseMonitor.java @@ -0,0 +1,19 @@ +package appeng.api.networking.storage; + +import appeng.api.storage.IMEMonitorHandlerReceiver; +import appeng.api.storage.data.IAEStack; + +public interface IBaseMonitor +{ + + /** + * add a new Listener to the monitor, be sure to properly remove yourself when your done. + */ + void addListener(IMEMonitorHandlerReceiver l, Object verificationToken); + + /** + * remove a Listener to the monitor. + */ + void removeListener(IMEMonitorHandlerReceiver l); + +} diff --git a/src/main/java/appeng/api/networking/storage/IStackWatcher.java b/src/main/java/appeng/api/networking/storage/IStackWatcher.java new file mode 100644 index 0000000..f27ecf7 --- /dev/null +++ b/src/main/java/appeng/api/networking/storage/IStackWatcher.java @@ -0,0 +1,10 @@ +package appeng.api.networking.storage; + +import java.util.Collection; + +import appeng.api.storage.data.IAEStack; + +public interface IStackWatcher extends Collection +{ + +} diff --git a/src/main/java/appeng/api/networking/storage/IStackWatcherHost.java b/src/main/java/appeng/api/networking/storage/IStackWatcherHost.java new file mode 100644 index 0000000..f94ef3c --- /dev/null +++ b/src/main/java/appeng/api/networking/storage/IStackWatcherHost.java @@ -0,0 +1,30 @@ +package appeng.api.networking.storage; + +import appeng.api.networking.security.BaseActionSource; +import appeng.api.storage.StorageChannel; +import appeng.api.storage.data.IAEStack; +import appeng.api.storage.data.IItemList; + +public interface IStackWatcherHost +{ + + /** + * provides the IStackWatcher for this host, for the current network, is called when the hot changes networks. You + * do not need to clear your old watcher, its already been removed by the time this gets called. + * + * @param newWatcher + */ + void updateWatcher(IStackWatcher newWatcher); + + /** + * Called when a watched item changes amounts. + * + * @param o + * @param fullStack + * @param diffStack + * @param src + * @param chan + */ + void onStackChange(IItemList o, IAEStack fullStack, IAEStack diffStack, BaseActionSource src, StorageChannel chan); + +} diff --git a/src/main/java/appeng/api/networking/storage/IStorageGrid.java b/src/main/java/appeng/api/networking/storage/IStorageGrid.java new file mode 100644 index 0000000..76405d5 --- /dev/null +++ b/src/main/java/appeng/api/networking/storage/IStorageGrid.java @@ -0,0 +1,45 @@ +package appeng.api.networking.storage; + +import appeng.api.networking.IGridCache; +import appeng.api.networking.IGridHost; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.storage.ICellContainer; +import appeng.api.storage.ICellProvider; +import appeng.api.storage.IStorageMonitorable; +import appeng.api.storage.StorageChannel; +import appeng.api.storage.data.IAEStack; + +/** + * Common base class for item / fluid storage caches. + */ +public interface IStorageGrid extends IGridCache, IStorageMonitorable +{ + + /** + * Used to inform the network of alterations to the storage system that fall outside of the standard Network + * operations, Examples, ME Chest inputs from the world, or a Storage Bus detecting modifications made to the chest + * by an outside force. + * + * Expects the input to have either a negative or a positive stack size to correspond to the injection, or + * extraction operation. + * + * @param input + */ + void postAlterationOfStoredItems(StorageChannel chan, Iterable input, BaseActionSource src); + + /** + * Used to add a cell provider to the storage system + * + * THIS IT NOT FOR USE {@link IGridHost} THAT PROVIDE {@link ICellContainer} - those are automatically handled by + * the storage system. + * + * @param cc + */ + void registerCellProvider(ICellProvider cc); + + /** + * remove a provider added with addCellContainer + */ + void unregisterCellProvider(ICellProvider cc); + +} diff --git a/src/main/java/appeng/api/networking/ticking/IGridTickable.java b/src/main/java/appeng/api/networking/ticking/IGridTickable.java new file mode 100644 index 0000000..66d3c89 --- /dev/null +++ b/src/main/java/appeng/api/networking/ticking/IGridTickable.java @@ -0,0 +1,56 @@ +package appeng.api.networking.ticking; + +import appeng.api.networking.IGridNode; + +/** + * Implement on IGridHosts which want to use AE's Network Ticking Feature. + */ +public interface IGridTickable +{ + + /** + * Important note regarding IGridTickables with more then one one node, + * + * If your IGridHost hosts multiple nodes, it may be on multiple grids, or + * its node may be present on the same grid multiple times, this is as + * designed, however if you choose to use the grid to tick these Hosts you + * must be aware that they they should probably pick a single node to tick + * for, and not tick for each node. + * + */ + + /** + * You can return null, if you wish to tick using MC's ticking mechanism, or + * you can return a valid TickingRequest to tell AE a guide for which type + * of responsiveness your device wants. + * + * this will be called for your tile any time your tile changes grids, this + * can happen at any time, so if your using the sleep feature you may wish + * to preserve your sleep, in the result of this method. or you can simply + * reset it. + * + * @return null or a valid new TickingRequest + * + */ + TickingRequest getTickingRequest(IGridNode node); + + /** + * AE lets you adjust your tick rate based on the results of your tick, if + * your block as accomplished work you may wish to increase the ticking + * speed, if your block is idle you may wish to slow it down. + * + * Its up to you. + * + * Note: this is never called if you return null from getTickingRequest. + * + * @param TicksSinceLastCall + * the number of world ticks that were skipped since your last + * tick, you can use this to adjust speed of processing or adjust + * your tick rate. + * + * @return tick rate adjustment. + * + */ + TickRateModulation tickingRequest(IGridNode node, int TicksSinceLastCall); + +} diff --git a/src/main/java/appeng/api/networking/ticking/ITickManager.java b/src/main/java/appeng/api/networking/ticking/ITickManager.java new file mode 100644 index 0000000..aa7c032 --- /dev/null +++ b/src/main/java/appeng/api/networking/ticking/ITickManager.java @@ -0,0 +1,44 @@ +package appeng.api.networking.ticking; + +import appeng.api.networking.IGridCache; +import appeng.api.networking.IGridNode; + +/** + * + * The network tick manager. + * + */ +public interface ITickManager extends IGridCache +{ + + /** + * immediately sets the node to tick, only valid if your node is marked as "Alertable" in its TickingRequest + * + * Sleeping Devices Still Alertable, when your tile is alerted its new status is determined by the result of its + * tick. + * + * @param node + */ + boolean alertDevice(IGridNode node); + + /** + * + * disables ticking for your device. + * + * @param node + * + * @return if the call was successful. + */ + boolean sleepDevice(IGridNode node); + + /** + * + * enables ticking for your device, undoes a sleepDevice call. + * + * @param node + * + * @return if the call was successful. + */ + boolean wakeDevice(IGridNode node); + +} diff --git a/src/main/java/appeng/api/networking/ticking/TickRateModulation.java b/src/main/java/appeng/api/networking/ticking/TickRateModulation.java new file mode 100644 index 0000000..1298b5a --- /dev/null +++ b/src/main/java/appeng/api/networking/ticking/TickRateModulation.java @@ -0,0 +1,34 @@ +package appeng.api.networking.ticking; + +public enum TickRateModulation +{ + /** + * same as idle, but also puts the node to sleep. + */ + SLEEP, + + /** + * set tick rate to maximum. + */ + IDLE, + + /** + * decrease the tick rate marginally. + */ + SLOWER, + + /** + * continue at current rate. + */ + SAME, + + /** + * increase the tick rate marginally. + */ + FASTER, + + /** + * changes the tick rate to the minimum tick rate. + */ + URGENT +} diff --git a/src/main/java/appeng/api/networking/ticking/TickingRequest.java b/src/main/java/appeng/api/networking/ticking/TickingRequest.java new file mode 100644 index 0000000..02ac54e --- /dev/null +++ b/src/main/java/appeng/api/networking/ticking/TickingRequest.java @@ -0,0 +1,54 @@ +package appeng.api.networking.ticking; + +/** + * + * Describes how your tiles ticking is executed. + * + */ +public class TickingRequest +{ + + /** + * the minimum number of ticks that must pass between ticks. + * + * Valid Values are : 1+ + * + * Suggested is 5-20 + * + */ + public final int minTickRate; + + /** + * the maximum number of ticks that can pass between ticks, if this value is + * exceeded the tile must tick. + * + * Valid Values are 1+ + * + * Suggested is 20-40 + * + */ + public final int maxTickRate; + + /** + * + * Determines the current expected state of your node, if your node expects + * to be sleeping, then return true. + * + */ + public final boolean isSleeping; + + /** + * + * True only if you call {@link ITickManager}.alertDevice( IGridNode ); + * + */ + public final boolean canBeAlerted; + + public TickingRequest(int min, int max, boolean sleep, boolean alertable) { + minTickRate = min; + maxTickRate = max; + isSleeping = sleep; + canBeAlerted = alertable; + } + +} diff --git a/src/main/java/appeng/api/package-info.java b/src/main/java/appeng/api/package-info.java new file mode 100644 index 0000000..4d7c0f1 --- /dev/null +++ b/src/main/java/appeng/api/package-info.java @@ -0,0 +1,5 @@ +@API(apiVersion = "rv1", owner = "appliedenergistics2", provides = "appliedenergistics2|API") +package appeng.api; + +import cpw.mods.fml.common.API; + diff --git a/src/main/java/appeng/api/parts/BusSupport.java b/src/main/java/appeng/api/parts/BusSupport.java new file mode 100644 index 0000000..1702bbc --- /dev/null +++ b/src/main/java/appeng/api/parts/BusSupport.java @@ -0,0 +1,10 @@ +package appeng.api.parts; + +public enum BusSupport +{ + CABLE, + + DENSE_CABLE, + + NO_PARTS +} diff --git a/src/main/java/appeng/api/parts/CableRenderMode.java b/src/main/java/appeng/api/parts/CableRenderMode.java new file mode 100644 index 0000000..2e64f35 --- /dev/null +++ b/src/main/java/appeng/api/parts/CableRenderMode.java @@ -0,0 +1,17 @@ +package appeng.api.parts; + +public enum CableRenderMode +{ + + Standard(false), + + CableView(true); + + public final boolean transparentFacades; + public final boolean opaqueFacades; + + private CableRenderMode(boolean hideFacades) { + this.transparentFacades = hideFacades; + opaqueFacades = !hideFacades; + } +} diff --git a/src/main/java/appeng/api/parts/IAlphaPassItem.java b/src/main/java/appeng/api/parts/IAlphaPassItem.java new file mode 100644 index 0000000..106b86a --- /dev/null +++ b/src/main/java/appeng/api/parts/IAlphaPassItem.java @@ -0,0 +1,16 @@ +package appeng.api.parts; + +import net.minecraft.item.ItemStack; + +public interface IAlphaPassItem +{ + + /** + * Extend, and return true to enable a second pass for your parts in the bus rendering pipe line. + * + * @param is + * @return + */ + boolean useAlphaPass(ItemStack is); + +} diff --git a/src/main/java/appeng/api/parts/IBoxProvider.java b/src/main/java/appeng/api/parts/IBoxProvider.java new file mode 100644 index 0000000..639d293 --- /dev/null +++ b/src/main/java/appeng/api/parts/IBoxProvider.java @@ -0,0 +1,13 @@ +package appeng.api.parts; + +public interface IBoxProvider +{ + + /** + * add your collision information to the the list. + * + * @param boxes + */ + void getBoxes(IPartCollsionHelper bch); + +} diff --git a/src/main/java/appeng/api/parts/IFacadeContainer.java b/src/main/java/appeng/api/parts/IFacadeContainer.java new file mode 100644 index 0000000..5bcba34 --- /dev/null +++ b/src/main/java/appeng/api/parts/IFacadeContainer.java @@ -0,0 +1,30 @@ +package appeng.api.parts; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Used Internally. + * + * not intended for implementation. + */ +public interface IFacadeContainer +{ + + /** + * Attempts to add the {@link IFacadePart} to the given side. + * + * @return true if the facade as successfully added. + */ + boolean addFacade(IFacadePart a); + + /** + * Removed the facade on the given side, or does nothing. + */ + void removeFacade(IPartHost host, ForgeDirection side); + + /** + * @return the {@link IFacadePart} for a given side, or null. + */ + IFacadePart getFacade(ForgeDirection s); + +} diff --git a/src/main/java/appeng/api/parts/IFacadePart.java b/src/main/java/appeng/api/parts/IFacadePart.java new file mode 100644 index 0000000..4956535 --- /dev/null +++ b/src/main/java/appeng/api/parts/IFacadePart.java @@ -0,0 +1,76 @@ +package appeng.api.parts; + +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.entity.Entity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.AxisAlignedBB; +import net.minecraftforge.common.util.ForgeDirection; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * Used Internally. + * + * not intended for implementation. + */ +public interface IFacadePart +{ + + /** + * used to save the part. + */ + ItemStack getItemStack(); + + /** + * used to collide, and pick the part + * + * @param ch + * @param e + */ + void getBoxes(IPartCollsionHelper ch, Entity e); + + /** + * render the part. + * + * @param xCoord + * @param yCoord + * @param zCoord + * @param instance + * @param renderer + * @param busBounds + * @param b + */ + @SideOnly(Side.CLIENT) + void renderStatic(int x, int y, int z, IPartRenderHelper instance, RenderBlocks renderer, IFacadeContainer fc, AxisAlignedBB busBounds, boolean renderStilt); + + /** + * render the part in inventory. + * + * @param instance + * @param renderer + */ + @SideOnly(Side.CLIENT) + void renderInventory(IPartRenderHelper instance, RenderBlocks renderer); + + /** + * @return side the facade is in + */ + ForgeDirection getSide(); + + /** + * @return the box for the face of the facade + */ + AxisAlignedBB getPrimaryBox(); + + Item getItem(); + + int getItemDamage(); + + boolean isBC(); + + void setThinFacades(boolean useThinFacades); + + boolean isTransparent(); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/parts/IPart.java b/src/main/java/appeng/api/parts/IPart.java new file mode 100644 index 0000000..09227f7 --- /dev/null +++ b/src/main/java/appeng/api/parts/IPart.java @@ -0,0 +1,267 @@ +package appeng.api.parts; + +import io.netty.buffer.ByteBuf; + +import java.io.IOException; +import java.util.List; +import java.util.Random; + +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import appeng.api.networking.IGridNode; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public interface IPart extends IBoxProvider +{ + + /** + * get an ItemStack that represents the bus, should contain the settings for whatever, can also be used in + * conjunction with removePart to take a part off and drop it or something. + * + * This is used to drop the bus, and to save the bus, when saving the bus, wrenched is false, and writeToNBT will be + * called to save improtant details about the part, if the part is wrenched include in your NBT Data any settings + * you might want to keep around, you can restore those settings when constructing your part. + * + * @param type + * , what kind of ItemStack to return? + * @return + */ + ItemStack getItemStack(PartItemStack type); + + /** + * render item form for inventory, or entity. + * + * GL Available + * + * @param te + * @param rh + */ + @SideOnly(Side.CLIENT) + void renderInventory(IPartRenderHelper rh, RenderBlocks renderer); + + /** + * render world renderer ( preferred ) + * + * GL is NOT Available + * + * @param x + * @param y + * @param z + * @param te + * @param rh + */ + @SideOnly(Side.CLIENT) + void renderStatic(int x, int y, int z, IPartRenderHelper rh, RenderBlocks renderer); + + /** + * render TESR. + * + * GL Available + * + * @param x + * @param y + * @param z + * @param te + * @param rh + */ + @SideOnly(Side.CLIENT) + void renderDynamic(double x, double y, double z, IPartRenderHelper rh, RenderBlocks renderer); + + /** + * @return the Block sheet icon used when rendering the breaking particles, return null to use the ItemStack + * texture. + */ + @SideOnly(Side.CLIENT) + IIcon getBreakingTexture(); + + /** + * return true only if your part require dynamic rendering, must be consistent. + * + * @return true to enable renderDynamic + */ + boolean requireDynamicRender(); + + /** + * @return if the bus has a solid side, and you can place random stuff on it like torches or levers + */ + boolean isSolid(); + + /** + * @return true if this part can connect to redstone ( also MFR Rednet ) + */ + boolean canConnectRedstone(); + + /** + * Write the part information for saving, the part will be saved with getItemStack(false) and this method will be + * called after to load settings, inventory or other values from the world. + * + * @param data + */ + void writeToNBT(NBTTagCompound data); + + /** + * Read the previously written NBT Data. this is the mirror for writeToNBT + * + * @param data + */ + void readFromNBT(NBTTagCompound data); + + /** + * @return get the amount of light produced by the bus + */ + int getLightLevel(); + + /** + * does this part act like a ladder? + * + * @param entity + * @return + */ + boolean isLadder(EntityLivingBase entity); + + /** + * a block around the bus's host has been changed. + */ + void onNeighborChanged(); + + /** + * @return output redstone on facing side + */ + int isProvidingStrongPower(); + + /** + * @return output redstone on facing side + */ + int isProvidingWeakPower(); + + /** + * write data to bus packet. + * + * @param data + * @throws IOException + */ + void writeToStream(ByteBuf data) throws IOException; + + /** + * read data from bus packet. + * + * @param data + * @return true will re-draw the part. + * @throws IOException + */ + boolean readFromStream(ByteBuf data) throws IOException; + + /** + * get the Grid Node for the Bus, be sure your IGridBlock is NOT isWorldAccessable, if it is your going to cause + * crashes. + * + * or null if you don't have a grid node. + * + * @return + */ + IGridNode getGridNode(); + + /** + * called when an entity collides with the bus. + * + * @param entity + */ + void onEntityCollision(Entity entity); + + /** + * called when your part is being removed from the world. + */ + void removeFromWorld(); + + /** + * called when your part is being added to the world. + */ + void addToWorld(); + + /** + * used for tunnels. + * + * @return a grid node that represents the external facing side, these must be isWorldAccessable with the correct + * faces marked as external + */ + IGridNode getExternalFacingNode(); + + /** + * called by the Part host to keep your part informed. + * + * @param host + * @param tile + */ + void setPartHostInfo(ForgeDirection side, IPartHost host, TileEntity tile); + + /** + * Called when you right click the part, very similar to Block.onActivateBlock + * + * @param player + * @param pos + * @return if your activate method performed something. + */ + boolean onActivate(EntityPlayer player, Vec3 pos); + + /** + * Called when you right click the part, very similar to Block.onActivateBlock + * + * @param player + * @param pos + * @return if your activate method performed something, you should use false unless you really need it. + */ + boolean onShiftActivate(EntityPlayer player, Vec3 pos); + + /** + * Add drops to the items being dropped into the world, if your item stores its contents when wrenched use the + * wrenched boolean to control what data is saved vs dropped when it is broken. + * + * @param drops + * @param wrenched + */ + void getDrops(List drops, boolean wrenched); + + /** + * @return 0 - 8, reasonable default 3-4, this controls the cable connection to the node. + */ + int cableConnectionRenderTo(); + + /** + * same as Block.randomDisplayTick, for but parts. + * + * @param world + * @param x + * @param y + * @param z + * @param r + */ + void randomDisplayTick(World world, int x, int y, int z, Random r); + + /** + * Called when placed in the world by a player, this happens before addWorld. + * + * @param player + * @param held + * @param side + */ + void onPlacement(EntityPlayer player, ItemStack held, ForgeDirection side); + + /** + * Used to determine which parts can be placed on what cables. + * + * @param what + * @return true if the part can be placed on this support. + */ + boolean canBePlacedOn(BusSupport what); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/parts/IPartCollsionHelper.java b/src/main/java/appeng/api/parts/IPartCollsionHelper.java new file mode 100644 index 0000000..7aa4346 --- /dev/null +++ b/src/main/java/appeng/api/parts/IPartCollsionHelper.java @@ -0,0 +1,42 @@ +package appeng.api.parts; + +import net.minecraftforge.common.util.ForgeDirection; + +public interface IPartCollsionHelper +{ + + /** + * add a collision box, expects 0.0 - 16.0 block coords. + * + * No complaints about the size, I like using pixels :P + * + * @param minX + * @param minY + * @param minZ + * @param maxX + * @param maxY + * @param maxZ + */ + void addBox(double minX, double minY, double minZ, double maxX, double maxY, double maxZ); + + /** + * @return east in world space. + */ + ForgeDirection getWorldX(); + + /** + * @return up in world space. + */ + ForgeDirection getWorldY(); + + /** + * @return forward in world space. + */ + ForgeDirection getWorldZ(); + + /** + * @return true if this test is to get the BB Collision information. + */ + boolean isBBCollision(); + +} diff --git a/src/main/java/appeng/api/parts/IPartHelper.java b/src/main/java/appeng/api/parts/IPartHelper.java new file mode 100644 index 0000000..d13acf3 --- /dev/null +++ b/src/main/java/appeng/api/parts/IPartHelper.java @@ -0,0 +1,62 @@ +package appeng.api.parts; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface IPartHelper +{ + + /** + * Register a new layer with the part layer system, this allows you to write + * an in between between tile entities and parts. + * + * AE By Default includes, + * + * 1. ISidedInventory ( and by extension IInventory. ) + * + * 2. IFluidHandler Forge Fluids + * + * 3. IPowerEmitter BC Power output. + * + * 4. IPowerReceptor BC Power input. + * + * 5. IEnergySink IC2 Power input. + * + * 6. IEnergySource IC2 Power output. + * + * 7. IPipeConnection BC Pipe Connections + * + * As long as a valid layer is registered for a interface you can simply + * implement that interface on a part get implement it. + * + * @return true on success, false on failure, usually a error will be logged + * as well. + */ + boolean registerNewLayer(String string, String layerInterface); + + /** + * Register IBusItem with renderer + */ + void setItemBusRenderer(IPartItem i); + + /** + * use in use item, to try and place a IBusItem + * + * @param is + * ItemStack of an item which implements {@link IPartItem} + * @param x + * @param y + * @param z + * @param side + * @param player + * @param world + * @return + */ + boolean placeBus(ItemStack is, int x, int y, int z, int side, EntityPlayer player, World world); + + /** + * @return the render mode + */ + CableRenderMode getCableRenderMode(); +} diff --git a/src/main/java/appeng/api/parts/IPartHost.java b/src/main/java/appeng/api/parts/IPartHost.java new file mode 100644 index 0000000..697dcbb --- /dev/null +++ b/src/main/java/appeng/api/parts/IPartHost.java @@ -0,0 +1,152 @@ +package appeng.api.parts; + +import java.util.Set; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Vec3; +import net.minecraftforge.common.util.ForgeDirection; +import appeng.api.util.AEColor; +import appeng.api.util.DimensionalCoord; + +/** + * Implemented on AE's TileEntity or AE's FMP Part. + * + * Do Not Implement + */ +public interface IPartHost +{ + + /** + * @return the facade container + */ + IFacadeContainer getFacadeContainer(); + + /** + * Test if you can add a part to the specified side of the Part Host, {@link ForgeDirection}.UNKNOWN is used to + * represent the cable in the middle. + * + * @param is + * @param side + * @return returns false if the part cannot be added. + */ + boolean canAddPart(ItemStack part, ForgeDirection side); + + /** + * try to add a new part to the specified side, returns false if it failed to be added. + * + * @param is + * @param side + * @param owner + * @return null if the item failed to add, the side it was placed on other wise ( may different for cables, + * {@link ForgeDirection}.UNKNOWN ) + */ + ForgeDirection addPart(ItemStack is, ForgeDirection side, EntityPlayer owner); + + /** + * Get part by side ( center is {@link ForgeDirection}.UNKNOWN ) + * + * @param side + * @return the part located on the specified side, or null if there is no part. + */ + IPart getPart(ForgeDirection side); + + /** + * removes the part on the side, this doesn't drop it or anything, if you don't do something with it, its just + * "gone" and its never coming back; think about it. + * + * if you want to drop the part you must request it prior to removing it. + * + * @param side + * @param suppressUpdate + * - used if you need to replace a part's instance, without really removing it first. + */ + void removePart(ForgeDirection side, boolean suppressUpdate); + + /** + * something changed, might want to send a packet to clients to update state. + */ + void markForUpdate(); + + /** + * @return the physical location of the part host in the universe. + */ + DimensionalCoord getLocation(); + + /** + * @return the tile entity for the host, this can either be an FMP tile, or a AE tile + */ + TileEntity getTile(); + + /** + * @return the color of the host type ( this is determined by the middle cable. ) if no cable is present, it returns + * {@link AEColor} .Transparent other wise it returns the color of the cable in the center. + */ + AEColor getColor(); + + /** + * destroys the part container, for internal use. + */ + void clearContainer(); + + /** + * Used to test for FMP microblock blocking internally. + * + * @return returns if microblocks are blocking this cable path. + */ + boolean isBlocked(ForgeDirection side); + + /** + * finds the part located at the position ( pos must be relative, not global ) + * + * @param pos + * @return a new SelectedPart, this is never null. + */ + SelectedPart selectPart(Vec3 pos); + + /** + * can be used by parts to trigger the tile or part to save. + */ + void markForSave(); + + /** + * part of the {@link LayerBase} + */ + void partChanged(); + + /** + * get the redstone state of host on this side, this value is cached internally. + * + * @param side + * @return true of the part host is receieveing redstone from an external source. + */ + boolean hasRedstone(ForgeDirection side); + + /** + * returns false if this block contains any parts or facades, true other wise. + */ + boolean isEmpty(); + + /** + * @return a mutable list of flags you can adjust to track state. + */ + Set getLayerFlags(); + + /** + * remove host from world... + */ + void cleanup(); + + /** + * notify neightbors uf updated status. + */ + void notifyNeighbors(); + + /** + * true if the tile is in the world, other wise false. + * + * @return + */ + boolean isInWorld(); +} \ No newline at end of file diff --git a/src/main/java/appeng/api/parts/IPartItem.java b/src/main/java/appeng/api/parts/IPartItem.java new file mode 100644 index 0000000..584e8c8 --- /dev/null +++ b/src/main/java/appeng/api/parts/IPartItem.java @@ -0,0 +1,37 @@ +package appeng.api.parts; + +import net.minecraft.item.ItemStack; + +//@formatter:off +/** + * This is a pretty basic requirement, once you implement the interface, and createPartFromItemStack + * + * you must register your bus with the Bus renderer, using AEApi.instance().partHelper().setItemBusRenderer( this ); + * + * then simply add these two methods, which tell MC to use the Block Textures, and call AE's Bus Placement Code. + * + * @Override + * @SideOnly(Side.CLIENT) + * public int getSpriteNumber() + * { + * return 0; + * } + * + * @Override + * public boolean onItemUse(ItemStack is, EntityPlayer player, World world, int x, int y, int z, int side, float hitX, float hitY, float hitZ) + * { + * return AEApi.instance().partHelper().placeBus( is, x, y, z, side, player, world ); + * } + */ +public interface IPartItem +{ + + /** + * create a new part instance, from the item stack. + * + * @param is + * @return + */ + IPart createPartFromItemStack(ItemStack is); + +} diff --git a/src/main/java/appeng/api/parts/IPartRenderHelper.java b/src/main/java/appeng/api/parts/IPartRenderHelper.java new file mode 100644 index 0000000..8946b6f --- /dev/null +++ b/src/main/java/appeng/api/parts/IPartRenderHelper.java @@ -0,0 +1,178 @@ +package appeng.api.parts; + +import java.util.EnumSet; + +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.util.IIcon; +import net.minecraftforge.common.util.ForgeDirection; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public interface IPartRenderHelper +{ + + /** + * sets the Render Helpers Block Bounds. 0.0 - 16.0 block coords. + * + * No complaints about the size, I like using pixels :P + * + * @param minX + * @param minY + * @param minZ + * @param maxX + * @param maxY + * @param maxZ + */ + void setBounds(float minX, float minY, float minZ, float maxX, float maxY, float maxZ); + + /** + * static renderer + * + * render a single face. + * + * @param x + * @param y + * @param z + * @param ico + * @param face + * @param renderer + */ + @SideOnly(Side.CLIENT) + void renderFace(int x, int y, int z, IIcon ico, ForgeDirection face, RenderBlocks renderer); + + /** + * static renderer + * + * render a box with a cut out box in the center. + * + * @param x + * @param y + * @param z + * @param ico + * @param face + * @param edgeThickness + * @param renderer + */ + @SideOnly(Side.CLIENT) + void renderFaceCutout(int x, int y, int z, IIcon ico, ForgeDirection face, float edgeThickness, RenderBlocks renderer); + + /** + * static renderer + * + * render a block of specified bounds. + * + * @param x + * @param y + * @param z + * @param renderer + */ + @SideOnly(Side.CLIENT) + void renderBlock(int x, int y, int z, RenderBlocks renderer); + + /** + * render a single face in inventory renderer. + * + * @param IIcon + * @param south + * @param renderer + */ + @SideOnly(Side.CLIENT) + void renderInventoryFace(IIcon IIcon, ForgeDirection south, RenderBlocks renderer); + + /** + * render a box in inventory renderer. + * + * @param renderer + */ + @SideOnly(Side.CLIENT) + void renderInventoryBox(RenderBlocks renderer); + + /** + * inventory, and static renderer. + * + * set unique icons for each side of the block. + * + * @param Down + * @param Up + * @param North + * @param South + * @param West + * @param East + */ + void setTexture(IIcon Down, IIcon Up, IIcon North, IIcon South, IIcon West, IIcon East); + + /** + * inventory, and static renderer. + * + * set all sides to a single IIcon. + * + * @param ico + */ + void setTexture(IIcon ico); + + /** + * configure the color multiplier for the inventory renderer. + * + * @param whiteVariant + */ + void setInvColor(int whiteVariant); + + /** + * @return the block used for rendering, might need it for some reason... + */ + Block getBlock(); + + /** + * @return the east vector in world directions, rather then renderer + */ + ForgeDirection getWorldX(); + + /** + * @return the up vector in world directions, rather then renderer. + */ + ForgeDirection getWorldY(); + + /** + * @return the forward vector in world directions, rather then renderer. + */ + ForgeDirection getWorldZ(); + + /** + * Pre-Calculates default lighting for the part, call this before using the render helper to render anything else to + * get simplified, but faster lighting for more then one block. + * + * Only worth it if you render more then 1 block. + */ + ISimplifiedBundle useSimpliedRendering(int x, int y, int z, IBoxProvider p, ISimplifiedBundle sim); + + /** + * disables, useSimpliedRendering. + */ + void normalRendering(); + + /** + * render a block using the current renderer state. + * + * @param x + * @param y + * @param z + * @param renderer + */ + void renderBlockCurrentBounds(int x, int y, int z, RenderBlocks renderer); + + /** + * allow you to enable your part to render during the alpha pass or the standard pass. + * + * @param pass + */ + void renderForPass(int pass); + + /** + * Set which faces to render, remember to set back to ALL when you are done. + * + * @param complementOf + */ + void setFacesToRender(EnumSet complementOf); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/parts/ISimplifiedBundle.java b/src/main/java/appeng/api/parts/ISimplifiedBundle.java new file mode 100644 index 0000000..ad09345 --- /dev/null +++ b/src/main/java/appeng/api/parts/ISimplifiedBundle.java @@ -0,0 +1,7 @@ +package appeng.api.parts; + + +public interface ISimplifiedBundle +{ + +} diff --git a/src/main/java/appeng/api/parts/LayerBase.java b/src/main/java/appeng/api/parts/LayerBase.java new file mode 100644 index 0000000..2aa74fb --- /dev/null +++ b/src/main/java/appeng/api/parts/LayerBase.java @@ -0,0 +1,55 @@ +package appeng.api.parts; + +import java.util.Set; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +/** + * All Layers must extends this, this get part implementation is provided to interface with the parts, however a real + * implementation will be used at runtime. + */ +public class LayerBase extends TileEntity // implements IPartHost +{ + + /** + * Grants access for the layer to the parts of the host. + * + * This Method looks silly, thats because its not used at runtime, a real implementation will be used instead. + * + * @param side + * @return the part for the requested side. + */ + public IPart getPart(ForgeDirection side) + { + return null; // place holder. + } + + /** + * called when the parts change in the container, YOU MUST CALL super.PartChanged(); + */ + public void notifyNeighbors() + { + } + + /** + * called when the parts change in the container, YOU MUST CALL super.PartChanged(); + */ + public void partChanged() + { + } + + /** + * @return a mutable list of flags you can adjust to track state. + */ + public Set getLayerFlags() + { + return null; // place holder. + } + + public void markForSave() + { + // something! + } + +} diff --git a/src/main/java/appeng/api/parts/LayerFlags.java b/src/main/java/appeng/api/parts/LayerFlags.java new file mode 100644 index 0000000..08d720b --- /dev/null +++ b/src/main/java/appeng/api/parts/LayerFlags.java @@ -0,0 +1,8 @@ +package appeng.api.parts; + +public enum LayerFlags +{ + + IC2_ENET + +} diff --git a/src/main/java/appeng/api/parts/PartItemStack.java b/src/main/java/appeng/api/parts/PartItemStack.java new file mode 100644 index 0000000..4c8c72d --- /dev/null +++ b/src/main/java/appeng/api/parts/PartItemStack.java @@ -0,0 +1,14 @@ +package appeng.api.parts; + +public enum PartItemStack +{ + Pick, + + Break, + + Wrench, + + Network, + + World +} diff --git a/src/main/java/appeng/api/parts/SelectedPart.java b/src/main/java/appeng/api/parts/SelectedPart.java new file mode 100644 index 0000000..b381e11 --- /dev/null +++ b/src/main/java/appeng/api/parts/SelectedPart.java @@ -0,0 +1,44 @@ +package appeng.api.parts; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Reports a selected part from th IPartHost + */ +public class SelectedPart +{ + + /** + * selected part. + */ + public final IPart part; + + /** + * facade part. + */ + public final IFacadePart facade; + + /** + * side the part is mounted too, or {@link ForgeDirection}.UNKNOWN for cables. + */ + public final ForgeDirection side; + + public SelectedPart() { + part = null; + facade = null; + side = ForgeDirection.UNKNOWN; + } + + public SelectedPart(IPart part, ForgeDirection side) { + this.part = part; + facade = null; + this.side = side; + } + + public SelectedPart(IFacadePart facade, ForgeDirection side) { + part = null; + this.facade = facade; + this.side = side; + } + +} diff --git a/src/main/java/appeng/api/recipes/ICraftHandler.java b/src/main/java/appeng/api/recipes/ICraftHandler.java new file mode 100644 index 0000000..076768c --- /dev/null +++ b/src/main/java/appeng/api/recipes/ICraftHandler.java @@ -0,0 +1,29 @@ +package appeng.api.recipes; + +import java.util.List; + +import appeng.api.exceptions.MissingIngredientError; +import appeng.api.exceptions.RecipeError; +import appeng.api.exceptions.RegistrationError; + +public interface ICraftHandler +{ + + /** + * Called when your recipe handler receives a newly parsed list of inputs/outputs. + * + * @param input + * @param output + * @throws RecipeError + */ + public void setup(List> input, List> output) throws RecipeError; + + /** + * called when all recipes are parsed, and your required to register your recipe. + * + * @throws RegistrationError + * @throws MissingIngredientError + */ + public void register() throws RegistrationError, MissingIngredientError; + +} diff --git a/src/main/java/appeng/api/recipes/IIngredient.java b/src/main/java/appeng/api/recipes/IIngredient.java new file mode 100644 index 0000000..0785fd8 --- /dev/null +++ b/src/main/java/appeng/api/recipes/IIngredient.java @@ -0,0 +1,64 @@ +package appeng.api.recipes; + +import net.minecraft.item.ItemStack; +import appeng.api.exceptions.MissingIngredientError; +import appeng.api.exceptions.RegistrationError; + +public interface IIngredient { + + /** + * Acquire a single input stack for the current recipe, if more then one ItemStack is possible a + * RegistrationError exception will be thrown, ignore these and let the system handle the error. + * + * @return a single ItemStack for the recipe handler. + * + * @throws RegistrationError + * @throws MissingIngredientError + */ + ItemStack getItemStack() throws RegistrationError, MissingIngredientError; + + /** + * Acquire a list of all the input stacks for the current recipe, this is for handlers that support + * multiple inputs per slot. + * + * @return an array of ItemStacks for the recipe handler. + * @throws RegistrationError + * @throws MissingIngredientError + */ + ItemStack[] getItemStackSet() throws RegistrationError, MissingIngredientError; + + /** + * If you wish to support air, you must test before geting the ItemStack, or ItemStackSet + * + * @return true if this slot contains no ItemStack, this is passed as "_" + */ + public boolean isAir(); + + /** + * @return The Name Space of the item. Prefer getItemStack or getItemStackSet + */ + public String getNameSpace(); + + /** + * @return The Name of the item. Prefer getItemStack or getItemStackSet + */ + public String getItemName(); + + /** + * @return The Damage Value of the item. Prefer getItemStack or getItemStackSet + */ + public int getDamageValue(); + + /** + * @return The Damage Value of the item. Prefer getItemStack or getItemStackSet + */ + public int getQty(); + + /** + * Bakes the lists in for faster runtime lookups. + * @throws MissingIngredientError + * @throws RegistrationError + */ + void bake() throws RegistrationError, MissingIngredientError; + +} diff --git a/src/main/java/appeng/api/recipes/IRecipeHandler.java b/src/main/java/appeng/api/recipes/IRecipeHandler.java new file mode 100644 index 0000000..d52a815 --- /dev/null +++ b/src/main/java/appeng/api/recipes/IRecipeHandler.java @@ -0,0 +1,22 @@ +package appeng.api.recipes; + +/** + * Represents the AE2 Recipe Loading/Reading Class + */ +public interface IRecipeHandler +{ + + /** + * Call when you want to read recipes in from a file based on a loader + * + * @param loader + * @param path + */ + void parseRecipes(IRecipeLoader loader, String path); + + /** + * this loads the read recipes into minecraft, should be called in Init. + */ + void injectRecipes(); + +} diff --git a/src/main/java/appeng/api/recipes/IRecipeLoader.java b/src/main/java/appeng/api/recipes/IRecipeLoader.java new file mode 100644 index 0000000..a85dbeb --- /dev/null +++ b/src/main/java/appeng/api/recipes/IRecipeLoader.java @@ -0,0 +1,10 @@ +package appeng.api.recipes; + +import java.io.BufferedReader; + +public interface IRecipeLoader +{ + + BufferedReader getFile(String s) throws Exception; + +} diff --git a/src/main/java/appeng/api/recipes/ISubItemResolver.java b/src/main/java/appeng/api/recipes/ISubItemResolver.java new file mode 100644 index 0000000..a6a481b --- /dev/null +++ b/src/main/java/appeng/api/recipes/ISubItemResolver.java @@ -0,0 +1,13 @@ +package appeng.api.recipes; + +public interface ISubItemResolver +{ + + /** + * @param namespace + * @param fullName + * @return either a ResolveReslult, or a ResolverResultSet + */ + public Object resolveItemByName(String namespace, String fullName); + +} diff --git a/src/main/java/appeng/api/recipes/ResolverResult.java b/src/main/java/appeng/api/recipes/ResolverResult.java new file mode 100644 index 0000000..03e696f --- /dev/null +++ b/src/main/java/appeng/api/recipes/ResolverResult.java @@ -0,0 +1,24 @@ +package appeng.api.recipes; + +import net.minecraft.nbt.NBTTagCompound; + +public class ResolverResult +{ + + final public String itemName; + final public int damageValue; + final public NBTTagCompound compound; + + public ResolverResult(String name, int damage) { + itemName = name; + damageValue = damage; + compound = null; + } + + public ResolverResult(String name, int damage, NBTTagCompound data) { + itemName = name; + damageValue = damage; + compound = data; + } + +} diff --git a/src/main/java/appeng/api/recipes/ResolverResultSet.java b/src/main/java/appeng/api/recipes/ResolverResultSet.java new file mode 100644 index 0000000..d9e34aa --- /dev/null +++ b/src/main/java/appeng/api/recipes/ResolverResultSet.java @@ -0,0 +1,19 @@ +package appeng.api.recipes; + +import java.util.Arrays; +import java.util.List; + +import net.minecraft.item.ItemStack; + +public class ResolverResultSet +{ + + public final String name; + public final List results; + + public ResolverResultSet(String myName, ItemStack... set) { + results = Arrays.asList( set ); + name = myName; + } + +} diff --git a/src/main/java/appeng/api/storage/ICellContainer.java b/src/main/java/appeng/api/storage/ICellContainer.java new file mode 100644 index 0000000..44553ed --- /dev/null +++ b/src/main/java/appeng/api/storage/ICellContainer.java @@ -0,0 +1,18 @@ +package appeng.api.storage; + +import appeng.api.networking.security.IActionHost; + +/** + * Represents a IGridhost that contributes to storage, such as a ME Chest, or ME Drive. + */ +public interface ICellContainer extends IActionHost, ICellProvider, ISaveProvider +{ + + /** + * tell the Cell container that this slot should blink, the slot number is relative to the + * + * @param slot + */ + void blinkCell(int slot); + +} diff --git a/src/main/java/appeng/api/storage/ICellHandler.java b/src/main/java/appeng/api/storage/ICellHandler.java new file mode 100644 index 0000000..17ab7fa --- /dev/null +++ b/src/main/java/appeng/api/storage/ICellHandler.java @@ -0,0 +1,102 @@ +package appeng.api.storage; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import appeng.api.implementations.tiles.IChestOrDrive; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * Registration record for {@link ICellRegistry} + */ +public interface ICellHandler +{ + + /** + * return true if the provided item is handled by your cell handler. ( AE May choose to skip this method, and just + * request a handler ) + * + * @param is + * @return return true, if getCellHandler will not return null. + */ + boolean isCell(ItemStack is); + + /** + * If you cannot handle the provided item, return null + * + * @param is + * a storage cell item. + * @param save + * host, anytime the contents of your storage cell changes it should use this to request a save, please + * note, this value can be null. + * @param the + * storage channel requested. + * + * @return a new IMEHandler for the provided item + */ + IMEInventoryHandler getCellInventory(ItemStack is, ISaveProvider host, StorageChannel channel); + + /** + * @return the ME Chest texture for light pixels this storage cell type, should be 10x10 with 3px of transparent + * padding on a 16x16 texture, null is valid if your cell cannot be used in the ME Chest. refer to the + * assets for examples. + */ + @SideOnly(Side.CLIENT) + IIcon getTopTexture_Light(); + + /** + * @return the ME Chest texture for medium pixels this storage cell type, should be 10x10 with 3px of transparent + * padding on a 16x16 texture, null is valid if your cell cannot be used in the ME Chest. refer to the + * assets for examples. + */ + @SideOnly(Side.CLIENT) + IIcon getTopTexture_Medium(); + + /** + * @return the ME Chest texture for dark pixels this storage cell type, should be 10x10 with 3px of transparent + * padding on a 16x16 texture, null is valid if your cell cannot be used in the ME Chest. refer to the + * assets for examples. + */ + @SideOnly(Side.CLIENT) + IIcon getTopTexture_Dark(); + + /** + * + * Called when the storage cell is planed in an ME Chest and the user tries to open the terminal side, if your item + * is not available via ME Chests simply tell the user they can't use it, or something, other wise you should open + * your gui and display the cell to the user. + * + * @param player + * @param chest + * @param cellHandler + * @param inv + * @param is + * @param chan + */ + void openChestGui(EntityPlayer player, IChestOrDrive chest, ICellHandler cellHandler, IMEInventoryHandler inv, ItemStack is, StorageChannel chan); + + /** + * 0 - cell is missing. + * + * 1 - green, ( usually means available room for types or items. ) + * + * 2 - orange, ( usually means available room for items, but not types. ) + * + * 3 - red, ( usually means the cell is 100% full ) + * + * @param is + * the cell item. ( use the handler for any details you can ) + * @param the + * handler for the cell is provides for reference, you can cast this to your handler. + * + * @return get the status of the cell based on its contents. + */ + int getStatusForCell(ItemStack is, IMEInventory handler); + + /** + * @return the ae/t to drain for this storage cell inside a chest/drive. + */ + double cellIdleDrain(ItemStack is, IMEInventory handler); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/storage/ICellInventory.java b/src/main/java/appeng/api/storage/ICellInventory.java new file mode 100644 index 0000000..c48567d --- /dev/null +++ b/src/main/java/appeng/api/storage/ICellInventory.java @@ -0,0 +1,96 @@ +package appeng.api.storage; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import appeng.api.config.FuzzyMode; +import appeng.api.storage.data.IAEItemStack; + +public interface ICellInventory extends IMEInventory +{ + + /** + * @return the item stack of this storage cell. + */ + ItemStack getItemStack(); + + /** + * @return idle cost for this Storage Cell + */ + double getIdleDrain(); + + /** + * @return fuzzy setting + */ + FuzzyMode getFuzzyMode(); + + /** + * @return access configured list + */ + IInventory getConfigInventory(); + + /** + * @return access installed upgrades. + */ + IInventory getUpgradesInventory(); + + /** + * @return How many bytes are used for each type? + */ + int getBytesPerType(); + + /** + * @return true if a new item type can be added. + */ + boolean canHoldNewItem(); + + /** + * @return total byte storage. + */ + long getTotalBytes(); + + /** + * @return how many bytes are free. + */ + long getFreeBytes(); + + /** + * @return how many bytes are in use. + */ + long getUsedBytes(); + + /** + * @return max number of types. + */ + long getTotalItemTypes(); + + /** + * @return how many items are stored. + */ + long getStoredItemCount(); + + /** + * @return how many items types are currently stored. + */ + long getStoredItemTypes(); + + /** + * @return how many item types remain. + */ + long getRemainingItemTypes(); + + /** + * @return how many more items can be stored. + */ + long getRemainingItemCount(); + + /** + * @return how many items can be added without consuming another byte. + */ + int getUnusedItemCount(); + + /** + * @return the status number for this drive. + */ + int getStatusForCell(); + +} diff --git a/src/main/java/appeng/api/storage/ICellInventoryHandler.java b/src/main/java/appeng/api/storage/ICellInventoryHandler.java new file mode 100644 index 0000000..b7e0d61 --- /dev/null +++ b/src/main/java/appeng/api/storage/ICellInventoryHandler.java @@ -0,0 +1,20 @@ +package appeng.api.storage; + +import appeng.api.config.IncludeExclude; +import appeng.api.storage.data.IAEItemStack; + +public interface ICellInventoryHandler extends IMEInventoryHandler +{ + + /** + * @return get access to the Cell Inventory. + */ + ICellInventory getCellInv(); + + boolean isPreformatted(); + + boolean isFuzzy(); + + IncludeExclude getIncludeExcludeMode(); + +} diff --git a/src/main/java/appeng/api/storage/ICellProvider.java b/src/main/java/appeng/api/storage/ICellProvider.java new file mode 100644 index 0000000..643439d --- /dev/null +++ b/src/main/java/appeng/api/storage/ICellProvider.java @@ -0,0 +1,29 @@ +package appeng.api.storage; + +import java.util.List; + +/** + * Allows you to provide cells via non IGridHosts directly to the storage system, drives, and similar features should go + * though {@link ICellContainer} and be automatically handled by the storage system. + */ +public interface ICellProvider +{ + + /** + * Inventory of the tile for use with ME, should always return an valid list, never NULL. + * + * You must return the correct Handler for the correct channel, if your handler returns a IAEItemStack handler, for + * a Fluid Channel stuffs going to explode, same with the reverse. + * + * @return a valid list of handlers, NEVER NULL + */ + List getCellArray(StorageChannel channel); + + /** + * the storage's priority. + * + * Positive and negative are supported + */ + int getPriority(); + +} diff --git a/src/main/java/appeng/api/storage/ICellRegistry.java b/src/main/java/appeng/api/storage/ICellRegistry.java new file mode 100644 index 0000000..40c138c --- /dev/null +++ b/src/main/java/appeng/api/storage/ICellRegistry.java @@ -0,0 +1,50 @@ +package appeng.api.storage; + +import net.minecraft.item.ItemStack; +import appeng.api.IAppEngApi; + +/** + * Storage Cell Registry, used for specially implemented cells, if you just want to make a item act like a cell, or new + * cell with different bytes, then you should probably consider IStorageCell instead its considerably simpler. + * + * Do not Implement, obtained via {@link IAppEngApi}.getCellRegistry() + */ +public interface ICellRegistry +{ + + /** + * Register a new handler. + * + * @param handler + */ + void addCellHandler(ICellHandler handler); + + /** + * return true, if you can get a InventoryHandler for the item passed. + * + * @param is + * @return true if the provided item, can be handled by a handler in AE, ( AE May choose to skip this and just get + * the handler instead. ) + */ + boolean isCellHandled(ItemStack is); + + /** + * get the handler, for the requested type. + * + * @param is + * @return the handler registered for this item type. + */ + ICellHandler getHandler(ItemStack is); + + /** + * returns an IMEInventoryHandler for the provided item. + * + * @param is + * @param host can be null, or the hosting tile / part. + * @param the storage channel to request the handler for. + * + * @return new IMEInventoryHandler, or null if there isn't one. + */ + IMEInventoryHandler getCellInventory(ItemStack is, ISaveProvider host, StorageChannel chan); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/storage/ICellWorkbenchItem.java b/src/main/java/appeng/api/storage/ICellWorkbenchItem.java new file mode 100644 index 0000000..0682461 --- /dev/null +++ b/src/main/java/appeng/api/storage/ICellWorkbenchItem.java @@ -0,0 +1,45 @@ +package appeng.api.storage; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import appeng.api.config.FuzzyMode; + +public interface ICellWorkbenchItem +{ + + /** + * if this return false, the item will not be treated as a cell, and cannot be inserted into the work bench. + * + * @param is + * @return true if the item should be editable in the cell workbench. + */ + boolean isEditable(ItemStack is); + + /** + * used to edit the upgrade slots on your cell, should have a capacity of 0-24, you are also responsible for + * implementing the valid checks, and any storage/usage of them. + * + * onInventoryChange will be called when saving is needed. + */ + IInventory getUpgradesInventory(ItemStack is); + + /** + * Used to extract, or mirror the contents of the work bench onto the cell. + * + * - This should have exactly 63 slots, any more, or less might cause issues. + * + * onInventoryChange will be called when saving is needed. + */ + IInventory getConfigInventory(ItemStack is); + + /** + * @return the current fuzzy status. + */ + FuzzyMode getFuzzyMode(ItemStack is); + + /** + * sets the setting on the cell. + */ + void setFuzzyMode(ItemStack is, FuzzyMode fzMode); + +} diff --git a/src/main/java/appeng/api/storage/IExternalStorageHandler.java b/src/main/java/appeng/api/storage/IExternalStorageHandler.java new file mode 100644 index 0000000..7021261 --- /dev/null +++ b/src/main/java/appeng/api/storage/IExternalStorageHandler.java @@ -0,0 +1,37 @@ +package appeng.api.storage; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; +import appeng.api.networking.security.BaseActionSource; + +/** + * A Registration Record for {@link IExternalStorageRegistry} + */ +public interface IExternalStorageHandler +{ + + /** + * if this can handle the provided inventory, return true. ( Generally skipped by AE, and it just calls getInventory + * ) + * + * @param te + * @param mySrc + * @return true, if it can get a handler via getInventory + */ + boolean canHandle(TileEntity te, ForgeDirection d, StorageChannel channel, BaseActionSource mySrc); + + /** + * if this can handle the given inventory, return the a IMEInventory implementing class for it, if not return null + * + * please note that if your inventory changes and requires polling, you must use an {@link IMEMonitor} instead of an + * {@link IMEInventory} failure to do so will result in invalid item counts and reporting of the inventory. + * + * @param te + * @param d + * @param channel + * @param src + * @return The Handler for the inventory + */ + IMEInventory getInventory(TileEntity te, ForgeDirection d, StorageChannel channel, BaseActionSource src); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/storage/IExternalStorageRegistry.java b/src/main/java/appeng/api/storage/IExternalStorageRegistry.java new file mode 100644 index 0000000..ac23808 --- /dev/null +++ b/src/main/java/appeng/api/storage/IExternalStorageRegistry.java @@ -0,0 +1,32 @@ +package appeng.api.storage; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; +import appeng.api.IAppEngApi; +import appeng.api.networking.security.BaseActionSource; + +/** + * A Registry of External Storage handlers. + * + * Do not implement obtain via {@link IAppEngApi}.registries().getExternalStorageRegistry() + */ +public interface IExternalStorageRegistry +{ + + /** + * A registry for StorageBus interactions + * + * @param esh + */ + void addExternalStorageInterface(IExternalStorageHandler esh); + + /** + * @param te + * @param opposite + * @param channel + * @param mySrc + * @return the handler for a given tile / forge direction + */ + IExternalStorageHandler getHandler(TileEntity te, ForgeDirection opposite, StorageChannel channel, BaseActionSource mySrc); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/storage/IMEInventory.java b/src/main/java/appeng/api/storage/IMEInventory.java new file mode 100644 index 0000000..5dd9b58 --- /dev/null +++ b/src/main/java/appeng/api/storage/IMEInventory.java @@ -0,0 +1,56 @@ +package appeng.api.storage; + +import appeng.api.config.Actionable; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.storage.data.IAEStack; +import appeng.api.storage.data.IItemList; + +/** + * AE's Equivalent to IInventory, used to reading contents, and manipulating contents of ME Inventories. + * + * Implementations should COMPLETELY ignore stack size limits from an external view point, Meaning that you can inject + * Integer.MAX_VALUE items and it should work as defined, or be able to extract Integer.MAX_VALUE and have it work as + * defined, Translations to MC's max stack size are external to the AE API. + * + * If you want to request a stack of an item, you should should determine that prior to requesting the stack from the + * inventory. + */ +public interface IMEInventory +{ + + /** + * Store new items, or simulate the addition of new items into the ME Inventory. + * + * @param input + * item to add. + * @param mode + * @return returns the number of items not added. + */ + public StackType injectItems(StackType input, Actionable type, BaseActionSource src); + + /** + * Extract the specified item from the ME Inventory + * + * @param request + * item to request ( with stack size. ) + * @param mode + * simulate, or perform action? + * @return returns the number of items extracted, null + */ + public StackType extractItems(StackType request, Actionable mode, BaseActionSource src); + + /** + * request a full report of all available items, storage. + * + * @param out + * the IItemList the results will be written too + * @return returns same list that was passed in, is passed out + */ + public IItemList getAvailableItems(IItemList out); + + /** + * @return the type of channel your handler should be part of + */ + public StorageChannel getChannel(); + +} diff --git a/src/main/java/appeng/api/storage/IMEInventoryHandler.java b/src/main/java/appeng/api/storage/IMEInventoryHandler.java new file mode 100644 index 0000000..0815fc6 --- /dev/null +++ b/src/main/java/appeng/api/storage/IMEInventoryHandler.java @@ -0,0 +1,67 @@ +package appeng.api.storage; + +import appeng.api.config.AccessRestriction; +import appeng.api.storage.data.IAEStack; + +/** + * Thin logic layer that can be swapped with different IMEInventory implementations, used to handle features related to + * storage, that are Separate from the storage medium itself. + * + * @param + */ +public interface IMEInventoryHandler extends IMEInventory +{ + + /** + * determine if items can be injected/extracted. + * + * @return the access + */ + public AccessRestriction getAccess(); + + /** + * determine if a particular item is prioritized for this inventory handler, if it is, then it will be added to this + * inventory prior to any non-prioritized inventories. + * + * @param input + * - item that might be added + * @return if its prioritized + */ + public boolean isPrioritized(StackType input); + + /** + * determine if an item can be accepted and stored. + * + * @param input + * - item that might be added + * @return if the item can be added + */ + public boolean canAccept(StackType input); + + /** + * determine what the priority of the inventory is. + * + * @return the priority, zero is default, positive and negative are supported. + */ + public int getPriority(); + + /** + * pass back value for blinkCell. + * + * @return the slot index for the cell that this represents in the storage unit, the method on the + * {@link ICellContainer} will be called with this value, only trust the return value of this mehod if you + * are the implementor of the {@link IMEInventoryHandler}. + */ + public int getSlot(); + + /** + * AE Uses a two pass placement system, the first pass checks contents and tries to find a place where the item + * belongs, however in some cases you can save processor time, or require that the second, or first pass is simply + * ignored, this allows you to do that. + * + * @param i + * - pass number ( 1 or 2 ) + * @return true, if this inventory is valid for this pass. + */ + public boolean validForPass(int i); +} diff --git a/src/main/java/appeng/api/storage/IMEMonitor.java b/src/main/java/appeng/api/storage/IMEMonitor.java new file mode 100644 index 0000000..de3f999 --- /dev/null +++ b/src/main/java/appeng/api/storage/IMEMonitor.java @@ -0,0 +1,24 @@ +package appeng.api.storage; + +import appeng.api.networking.storage.IBaseMonitor; +import appeng.api.storage.data.IAEStack; +import appeng.api.storage.data.IItemList; + +public interface IMEMonitor extends IMEInventoryHandler, IBaseMonitor +{ + + @Override + @Deprecated + /** + * This method is discouraged when accessing data via a IMEMonitor + */ + public IItemList getAvailableItems(IItemList out); + + /** + * Get access to the full item list of the network, preferred over {@link IMEInventory} .getAvaialbleItems(...) + * + * @return full storage list. + */ + IItemList getStorageList(); + +} diff --git a/src/main/java/appeng/api/storage/IMEMonitorHandlerReceiver.java b/src/main/java/appeng/api/storage/IMEMonitorHandlerReceiver.java new file mode 100644 index 0000000..328acf1 --- /dev/null +++ b/src/main/java/appeng/api/storage/IMEMonitorHandlerReceiver.java @@ -0,0 +1,30 @@ +package appeng.api.storage; + +import appeng.api.networking.security.BaseActionSource; +import appeng.api.networking.storage.IBaseMonitor; +import appeng.api.storage.data.IAEStack; + +public interface IMEMonitorHandlerReceiver +{ + + /** + * return true if this object should remain as a listener. + * + * @param verificationToken + * @return + */ + boolean isValid(Object verificationToken); + + /** + * called when changes are made to the Monitor, but only if listener is still valid. + * + * @param change + */ + void postChange(IBaseMonitor monitor, Iterable change, BaseActionSource actionSource); + + /** + * called when the list updates its contents, this is mostly for handling power events. + */ + void onListUpdate(); + +} diff --git a/src/main/java/appeng/api/storage/ISaveProvider.java b/src/main/java/appeng/api/storage/ISaveProvider.java new file mode 100644 index 0000000..a88bfc5 --- /dev/null +++ b/src/main/java/appeng/api/storage/ISaveProvider.java @@ -0,0 +1,9 @@ +package appeng.api.storage; + + +public interface ISaveProvider +{ + + void saveChanges(IMEInventory cellInventory); + +} diff --git a/src/main/java/appeng/api/storage/IStorageHelper.java b/src/main/java/appeng/api/storage/IStorageHelper.java new file mode 100644 index 0000000..6a52c90 --- /dev/null +++ b/src/main/java/appeng/api/storage/IStorageHelper.java @@ -0,0 +1,95 @@ +package appeng.api.storage; + +import io.netty.buffer.ByteBuf; + +import java.io.IOException; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraftforge.fluids.FluidStack; +import appeng.api.networking.crafting.ICraftingLink; +import appeng.api.networking.crafting.ICraftingRequester; +import appeng.api.networking.energy.IEnergySource; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; + +public interface IStorageHelper +{ + + /** + * load a crafting link from nbt data. + * + * @param data + * @return + */ + ICraftingLink loadCraftingLink(NBTTagCompound data, ICraftingRequester req); + + /** + * @param is + * An ItemStack + * + * @return a new instance of {@link IAEItemStack} from a MC {@link ItemStack} + */ + IAEItemStack createItemStack(ItemStack is); + + /** + * @param is + * A FluidStack + * + * @return a new instance of {@link IAEFluidStack} from a Forge {@link FluidStack} + */ + IAEFluidStack createFluidStack(FluidStack is); + + /** + * @return a new instance of {@link IItemList} for items + */ + IItemList createItemList(); + + /** + * @return a new instance of {@link IItemList} for fluids + */ + IItemList createFluidList(); + + /** + * Read a AE Item Stack from a byte stream, returns a AE item stack or null. + * + * @param input + * @return + * @throws IOException + */ + IAEItemStack readItemFromPacket(ByteBuf input) throws IOException; + + /** + * Read a AE Fluid Stack from a byte stream, returns a AE fluid stack or null. + * + * @param input + * @return + * @throws IOException + */ + IAEFluidStack readFluidFromPacket(ByteBuf input) throws IOException; + + /** + * use energy from energy, to remove request items from cell, at the request of src. + * + * @param energy + * @param cell + * @param request + * @param src + * @return items that successfully extracted. + */ + IAEItemStack poweredExtraction(IEnergySource energy, IMEInventory cell, IAEItemStack request, BaseActionSource src); + + /** + * use energy from energy, to inject input items into cell, at the request of src + * + * @param energy + * @param cell + * @param input + * @param src + * @return items that failed to insert. + */ + IAEItemStack poweredInsert(IEnergySource energy, IMEInventory cell, IAEItemStack input, BaseActionSource src); + +} diff --git a/src/main/java/appeng/api/storage/IStorageMonitorable.java b/src/main/java/appeng/api/storage/IStorageMonitorable.java new file mode 100644 index 0000000..ea7293a --- /dev/null +++ b/src/main/java/appeng/api/storage/IStorageMonitorable.java @@ -0,0 +1,25 @@ +package appeng.api.storage; + +import appeng.api.implementations.tiles.ITileStorageMonitorable; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; + +/** + * represents the internal behavior of a {@link ITileStorageMonitorable} use it to get this value for a tile, or part. + * + * never check a tile for this, always go though ITileStorageMonitorable if you wish to use this interface. + */ +public interface IStorageMonitorable +{ + + /** + * Access the item inventory for the monitorable storage. + */ + IMEMonitor getItemInventory(); + + /** + * Access the fluid inventory for the monitorable storage. + */ + IMEMonitor getFluidInventory(); + +} diff --git a/src/main/java/appeng/api/storage/ITerminalHost.java b/src/main/java/appeng/api/storage/ITerminalHost.java new file mode 100644 index 0000000..fbb7084 --- /dev/null +++ b/src/main/java/appeng/api/storage/ITerminalHost.java @@ -0,0 +1,8 @@ +package appeng.api.storage; + +import appeng.api.util.IConfigureableObject; + +public interface ITerminalHost extends IStorageMonitorable, IConfigureableObject +{ + +} diff --git a/src/main/java/appeng/api/storage/MEMonitorHandler.java b/src/main/java/appeng/api/storage/MEMonitorHandler.java new file mode 100644 index 0000000..25ffdbc --- /dev/null +++ b/src/main/java/appeng/api/storage/MEMonitorHandler.java @@ -0,0 +1,174 @@ +package appeng.api.storage; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; + +import appeng.api.config.AccessRestriction; +import appeng.api.config.Actionable; +import appeng.api.networking.security.BaseActionSource; +import appeng.api.storage.data.IAEStack; +import appeng.api.storage.data.IItemList; + +import com.google.common.collect.ImmutableList; + +/** + * Common implementation of a simple class that monitors injection/extraction of a inventory to send events to a list of + * listeners. + * + * @param + */ +public class MEMonitorHandler implements IMEMonitor +{ + + private final IMEInventoryHandler internalHandler; + private final IItemList cachedList; + private final HashMap, Object> listeners = new HashMap, Object>(); + + protected boolean hasChanged = true; + + protected IMEInventoryHandler getHandler() + { + return internalHandler; + } + + protected Iterator, Object>> getListeners() + { + return listeners.entrySet().iterator(); + } + + protected void postChangesToListeners( Iterable changes, BaseActionSource src) + { + notifyListenersOfChange( changes, src ); + } + + protected void notifyListenersOfChange(Iterable diff, BaseActionSource src) + { + hasChanged = true;// need to update the cache. + Iterator, Object>> i = getListeners(); + while (i.hasNext()) + { + Entry, Object> o = i.next(); + IMEMonitorHandlerReceiver recv = o.getKey(); + if ( recv.isValid( o.getValue() ) ) + recv.postChange( this, diff, src ); + else + i.remove(); + } + } + + private StackType monitorDiffrence(IAEStack original, StackType leftOvers, boolean extraction, BaseActionSource src) + { + StackType diff = (StackType) original.copy(); + + if ( extraction ) + diff.setStackSize( leftOvers == null ? 0 : -leftOvers.getStackSize() ); + else if ( leftOvers != null ) + diff.decStackSize( leftOvers.getStackSize() ); + + if ( diff.getStackSize() != 0 ) + postChangesToListeners( ImmutableList.of( diff ), src ); + + return leftOvers; + } + + public MEMonitorHandler(IMEInventoryHandler t) { + internalHandler = t; + cachedList = (IItemList) t.getChannel().createList(); + } + + public MEMonitorHandler(IMEInventoryHandler t, StorageChannel chan) { + internalHandler = t; + cachedList = (IItemList) chan.createList(); + } + + @Override + public void addListener(IMEMonitorHandlerReceiver l, Object verificationToken) + { + listeners.put( l, verificationToken ); + } + + @Override + public void removeListener(IMEMonitorHandlerReceiver l) + { + listeners.remove( l ); + } + + @Override + public StackType injectItems(StackType input, Actionable mode, BaseActionSource src) + { + if ( mode == Actionable.SIMULATE ) + return getHandler().injectItems( input, mode, src ); + return monitorDiffrence( (StackType) input.copy(), getHandler().injectItems( input, mode, src ), false, src ); + } + + @Override + public StackType extractItems(StackType request, Actionable mode, BaseActionSource src) + { + if ( mode == Actionable.SIMULATE ) + return getHandler().extractItems( request, mode, src ); + return monitorDiffrence( (StackType) request.copy(), getHandler().extractItems( request, mode, src ), true, src ); + } + + @Override + public IItemList getStorageList() + { + if ( hasChanged ) + { + hasChanged = false; + cachedList.resetStatus(); + return getAvailableItems( cachedList ); + } + + return cachedList; + } + + @Override + public IItemList getAvailableItems(IItemList out) + { + return getHandler().getAvailableItems( out ); + } + + @Override + public StorageChannel getChannel() + { + return getHandler().getChannel(); + } + + @Override + public AccessRestriction getAccess() + { + return getHandler().getAccess(); + } + + @Override + public boolean isPrioritized(StackType input) + { + return getHandler().isPrioritized( input ); + } + + @Override + public boolean canAccept(StackType input) + { + return getHandler().canAccept( input ); + } + + @Override + public int getPriority() + { + return getHandler().getPriority(); + } + + @Override + public int getSlot() + { + return getHandler().getSlot(); + } + + @Override + public boolean validForPass(int i) + { + return getHandler().validForPass( i ); + } + +} diff --git a/src/main/java/appeng/api/storage/StorageChannel.java b/src/main/java/appeng/api/storage/StorageChannel.java new file mode 100644 index 0000000..1ada150 --- /dev/null +++ b/src/main/java/appeng/api/storage/StorageChannel.java @@ -0,0 +1,33 @@ +package appeng.api.storage; + +import appeng.api.AEApi; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IAEStack; +import appeng.api.storage.data.IItemList; + +public enum StorageChannel +{ + /** + * AE2's Default Storage. + */ + ITEMS( IAEItemStack.class ), + + /** + * AE2's Fluid Based Storage ( mainly added to better support ExtraCells ) + */ + FLUIDS( IAEFluidStack.class ); + + public final Class type; + + private StorageChannel( Class t ) { + type = t; + } + + public IItemList createList() { + if ( this == ITEMS ) + return AEApi.instance().storage().createItemList(); + else + return AEApi.instance().storage().createFluidList(); + } +} diff --git a/src/main/java/appeng/api/storage/data/IAEFluidStack.java b/src/main/java/appeng/api/storage/data/IAEFluidStack.java new file mode 100644 index 0000000..5d134c0 --- /dev/null +++ b/src/main/java/appeng/api/storage/data/IAEFluidStack.java @@ -0,0 +1,52 @@ +package appeng.api.storage.data; + +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; + +/** + * An alternate version of FluidStack for AE to keep tabs on things easier, and + * to support larger storage. stackSizes of getFluidStack will be capped. + * + * You may hold on to these if you want, just make sure you let go of them when + * your not using them. + * + * Don't Implement. + * + * Construct with Util.createFluidStack( FluidStack ) + * + */ +public interface IAEFluidStack extends IAEStack +{ + + /** + * creates a standard Forge FluidStack for the fluid. + * + * @return new FluidStack + */ + FluidStack getFluidStack(); + + /** + * create a AE Fluid clone. + * + * @return the copy. + */ + @Override + public IAEFluidStack copy(); + + /** + * Combines two IAEItemStacks via addition. + * + * @param option + * , to add to the current one. + */ + @Override + void add(IAEFluidStack option); + + /** + * quick way to get access to the Forge Fluid Definition. + * + * @return + */ + Fluid getFluid(); + +} diff --git a/src/main/java/appeng/api/storage/data/IAEItemStack.java b/src/main/java/appeng/api/storage/data/IAEItemStack.java new file mode 100644 index 0000000..5ccc031 --- /dev/null +++ b/src/main/java/appeng/api/storage/data/IAEItemStack.java @@ -0,0 +1,82 @@ +package appeng.api.storage.data; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +/** + * An alternate version of ItemStack for AE to keep tabs on things easier, and to support larger storage. stackSizes of + * getItemStack will be capped. + * + * You may hold on to these if you want, just make sure you let go of them when your not using them. + * + * Don't Implement. + * + * Construct with Util.createItemStack( ItemStack ) + */ +public interface IAEItemStack extends IAEStack +{ + + /** + * creates a standard MC ItemStack for the item. + * + * @return new ItemStack + */ + public ItemStack getItemStack(); + + /** + * create a AE Item clone + * + * @return the copy + */ + @Override + public IAEItemStack copy(); + + /** + * is there NBT Data for this item? + * + * @return if there is + */ + boolean hasTagCompound(); + + /** + * Combines two IAEItemStacks via addition. + * + * @param option + * to add to the current one. + */ + @Override + void add(IAEItemStack option); + + /** + * quick way to get access to the MC Item Definition. + * + * @return + */ + Item getItem(); + + /** + * @return the items damage value + */ + int getItemDamage(); + + /** + * Compare the Ore Dictionary ID for this to another item. + */ + boolean sameOre(IAEItemStack is); + + /** + * compare the item/damage/nbt of the stack. + * + * @param otherStack + * @return + */ + boolean isSameType(IAEItemStack otherStack); + + /** + * compare the item/damage/nbt of the stack. + * + * @param otherStack + * @return + */ + boolean isSameType(ItemStack stored); +} \ No newline at end of file diff --git a/src/main/java/appeng/api/storage/data/IAEStack.java b/src/main/java/appeng/api/storage/data/IAEStack.java new file mode 100644 index 0000000..86f72f5 --- /dev/null +++ b/src/main/java/appeng/api/storage/data/IAEStack.java @@ -0,0 +1,179 @@ +package appeng.api.storage.data; + +import io.netty.buffer.ByteBuf; + +import java.io.IOException; + +import net.minecraft.nbt.NBTTagCompound; +import appeng.api.config.FuzzyMode; +import appeng.api.storage.StorageChannel; + +public interface IAEStack +{ + + /** + * add two stacks together + * + * @param is + */ + void add(StackType is); + + /** + * number of items in the stack. + * + * @return basically ItemStack.stackSize + */ + long getStackSize(); + + /** + * changes the number of items in the stack. + * + * @param basically + * , ItemStack.stackSize = N + */ + StackType setStackSize(long stackSize); + + /** + * Same as getStackSize, but for requestable items. ( LP ) + * + * @return basically itemStack.stackSize but for requestable items. + */ + long getCountRequestable(); + + /** + * Same as setStackSize, but for requestable items. ( LP ) + * + * @return basically itemStack.stackSize = N but for setStackSize items. + */ + StackType setCountRequestable(long countRequestable); + + /** + * true, if the item can be crafted. + * + * @return true, if it can be crafted. + */ + boolean isCraftable(); + + /** + * change weather the item can be crafted. + * + * @param isCraftable + */ + StackType setCraftable(boolean isCraftable); + + /** + * clears, requsetable, craftable, and stack sizes. + */ + StackType reset(); + + /** + * returns true, if the item can be crafted, requested, or extracted. + * + * @return isThisRecordMeaningful + */ + boolean isMeaninful(); + + /** + * Adds more to the stack size... + * + * @param i + */ + void incStackSize(long i); + + /** + * removes some from the stack size. + */ + void decStackSize(long i); + + /** + * adds items to the requestable + * + * @param i + */ + void incCountRequestable(long i); + + /** + * removes items from the requsetable + * + * @param i + */ + void decCountRequestable(long i); + + /** + * write to a NBTTagCompound. + * + * @param i + */ + void writeToNBT(NBTTagCompound i); + + /** + * Compare stacks using precise logic. + * + * a IAEItemStack to another AEItemStack or a ItemStack. + * + * or + * + * IAEFluidStack, FluidStack + * + * @param obj + * @return true if they are the same. + */ + @Override + boolean equals(Object obj); + + /** + * compare stacks using fuzzy logic + * + * a IAEItemStack to another AEItemStack or a ItemStack. + * + * @param st + * @param mode + * @return true if two stacks are equal based on AE Fuzzy Comparison. + */ + boolean fuzzyComparison(Object st, FuzzyMode mode); + + /** + * Slower for disk saving, but smaller/more efficient for packets. + * + * @param data + * @throws IOException + */ + void writeToPacket(ByteBuf data) throws IOException; + + /** + * Clone the Item / Fluid Stack + * + * @return a new Stack, which is copied from the original. + */ + StackType copy(); + + /** + * create an empty stack. + * + * @return a new stack, which represents an empty copy of the original. + */ + StackType empty(); + + /** + * obtain the NBT Data for the item. + * + * @return + */ + IAETagCompound getTagCompound(); + + /** + * @return true if the stack is a {@link IAEItemStack} + */ + boolean isItem(); + + /** + * @return true if the stack is a {@link IAEFluidStack} + */ + boolean isFluid(); + + /** + * @return ITEM or FLUID + */ + StorageChannel getChannel(); + +} diff --git a/src/main/java/appeng/api/storage/data/IAETagCompound.java b/src/main/java/appeng/api/storage/data/IAETagCompound.java new file mode 100644 index 0000000..8fe65e8 --- /dev/null +++ b/src/main/java/appeng/api/storage/data/IAETagCompound.java @@ -0,0 +1,33 @@ +package appeng.api.storage.data; + +import net.minecraft.nbt.NBTTagCompound; +import appeng.api.features.IItemComparison; + +/** + * Don't cast this... either compare with it, or copy it. + * + * Don't Implement. + */ +public interface IAETagCompound +{ + + /** + * @return a copy ( the copy will not be a IAETagCompount, it will be a NBTTagCompound ) + */ + public NBTTagCompound getNBTTagCompoundCopy(); + + /** + * compare to other NBTTagCompounds or IAETagCompounds + * + * @param a + * @return true, if they are the same. + */ + @Override + boolean equals(Object a); + + /** + * @return the special comparison for this tag + */ + IItemComparison getSpecialComparison(); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/storage/data/IItemContainer.java b/src/main/java/appeng/api/storage/data/IItemContainer.java new file mode 100644 index 0000000..d8fd764 --- /dev/null +++ b/src/main/java/appeng/api/storage/data/IItemContainer.java @@ -0,0 +1,42 @@ +package appeng.api.storage.data; + +import java.util.Collection; + +import appeng.api.config.FuzzyMode; + +/** + * Represents a list of items in AE. + * + * Don't Implement. + * + * Construct with Util.createItemList() + */ +public interface IItemContainer +{ + + /** + * add a stack to the list, this will merge the stack with an item already in the list if found. + * + * @param option + */ + public void add(StackType option); // adds stack as is + + /** + * @param i + * @return a stack equivalent to the stack passed in, but with the correct stack size information, or null if its + * not present + */ + StackType findPrecise(StackType i); + + /** + * @param input + * @return a list of relevant fuzzy matched stacks + */ + public Collection findFuzzy(StackType input, FuzzyMode fuzzy); + + /** + * @return true if there are no items in the list + */ + public boolean isEmpty(); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/storage/data/IItemList.java b/src/main/java/appeng/api/storage/data/IItemList.java new file mode 100644 index 0000000..6968d23 --- /dev/null +++ b/src/main/java/appeng/api/storage/data/IItemList.java @@ -0,0 +1,59 @@ +package appeng.api.storage.data; + +import java.util.Iterator; + +/** + * Represents a list of items in AE. + * + * Don't Implement. + * + * Construct with Util.createItemList() + */ +public interface IItemList extends IItemContainer, Iterable +{ + + /** + * add a stack to the list stackSize is used to add to stackSize, this will merge the stack with an item already in + * the list if found. + * + * @param option + */ + public void addStorage(StackType option); // adds a stack as stored + + /** + * add a stack to the list as craftable, this will merge the stack with an item already in the list if found. + * + * @param option + */ + public void addCrafting(StackType option); + + /** + * add a stack to the list, stack size is used to add to requstable, this will merge the stack with an item already + * in the list if found. + * + * @param option + */ + public void addRequestable(StackType option); // adds a stack as requestable + + /** + * @return the first item in the list + */ + StackType getFirstItem(); + + /** + * @return the number of items in the list + */ + int size(); + + /** + * allows you to iterate the list. + */ + @Override + public Iterator iterator(); + + /** + * resets stack sizes to 0. + */ + void resetStatus(); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/util/AECableType.java b/src/main/java/appeng/api/util/AECableType.java new file mode 100644 index 0000000..c1ee4ee --- /dev/null +++ b/src/main/java/appeng/api/util/AECableType.java @@ -0,0 +1,30 @@ +package appeng.api.util; + +public enum AECableType +{ + /** + * No Cable present. + */ + NONE, + + /** + * Connections to this block should render as glass. + */ + GLASS, + + /** + * Connections to this block should render as covered. + */ + COVERED, + + /** + * Connections to this block should render as smart. + */ + SMART, + + /** + * Dense Cable, represents a tier 2 block that can carry 32 channels. + */ + DENSE, + +} diff --git a/src/main/java/appeng/api/util/AEColor.java b/src/main/java/appeng/api/util/AEColor.java new file mode 100644 index 0000000..214199c --- /dev/null +++ b/src/main/java/appeng/api/util/AEColor.java @@ -0,0 +1,90 @@ +package appeng.api.util; + +import net.minecraft.util.StatCollector; + +/** + * List of all colors supported by AE, their names, and various colors for display. + * + * Should be the same order as Dyes, excluding Transparent. + */ +public enum AEColor +{ + + White("gui.appliedenergistics2.White", 0xBEBEBE, 0xDBDBDB, 0xFAFAFA), + + Orange("gui.appliedenergistics2.Orange", 0xF99739, 0xFAAE44, 0xF4DEC3), + + Magenta("gui.appliedenergistics2.Magenta", 0x821E82, 0xB82AB8, 0xC598C8), + + LightBlue("gui.appliedenergistics2.LightBlue", 0x628DCB, 0x82ACE7, 0xD8F6FF), + + Yellow("gui.appliedenergistics2.Yellow", 0xFFF7AA, 0xF8FF4A, 0xFFFFE8), + + Lime("gui.appliedenergistics2.Lime", 0x7CFF4A, 0xBBFF51, 0xE7F7D7), + + Pink("gui.appliedenergistics2.Pink", 0xDC8DB5, 0xF8B5D7, 0xF7DEEB), + + Gray("gui.appliedenergistics2.Gray", 0x7C7C7C, 0xA0A0A0, 0xC9C9C9), + + LightGray("gui.appliedenergistics2.LightGray", 0x9D9D9D, 0xCDCDCD, 0xEFEFEF), + + Cyan("gui.appliedenergistics2.Cyan", 0x2F9BA5, 0x51AAC6, 0xAEDDF4), + + Purple("gui.appliedenergistics2.Purple", 0x8230B2, 0xA453CE, 0xC7A3CC), + + Blue("gui.appliedenergistics2.Blue", 0x2D29A0, 0x514AFF, 0xDDE6FF), + + Brown("gui.appliedenergistics2.Brown", 0x724E35, 0xB7967F, 0xE0D2C8), + + Green("gui.appliedenergistics2.Green", 0x45A021, 0x60E32E, 0xE3F2E3), + + Red("gui.appliedenergistics2.Red", 0xA50029, 0xFF003C, 0xFFE6ED), + + Black("gui.appliedenergistics2.Black", 0x2B2B2B, 0x565656, 0x848484), + + Transparent("gui.appliedenergistics2.Fluix", 0x1B2344, 0x895CA8, 0xD7BBEC); + + /** + * Unlocalized name for color. + */ + final public String unlocalizedName; + + /** + * Darkest Variant of the color, nearly black; as a RGB HEX Integer + */ + final public int blackVariant; + + /** + * The Variant of the color that is used to represent the color normally; as a RGB HEX Integer + */ + final public int mediumVariant; + + /** + * Lightest Variant of the color, nearly white; as a RGB HEX Integer + */ + final public int whiteVariant; + + AEColor(String unlocalizedName, int blackHex, int medHex, int whiteHex) { + this.unlocalizedName = unlocalizedName; + blackVariant = blackHex; + mediumVariant = medHex; + whiteVariant = whiteHex; + } + + /** + * Logic to see which colors match each other.. special handle for Transparent + */ + public boolean matches(AEColor color) + { + if ( equals( Transparent ) || color.equals( Transparent ) ) + return true; + return equals( color ); + } + + @Override + public String toString() + { + return StatCollector.translateToLocal( unlocalizedName ); + } + +} diff --git a/src/main/java/appeng/api/util/AEColoredItemDefinition.java b/src/main/java/appeng/api/util/AEColoredItemDefinition.java new file mode 100644 index 0000000..7feb00d --- /dev/null +++ b/src/main/java/appeng/api/util/AEColoredItemDefinition.java @@ -0,0 +1,46 @@ +package appeng.api.util; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +public interface AEColoredItemDefinition +{ + + /** + * @return the {@link Block} Implementation if applicable + */ + Block block(AEColor color); + + /** + * @return the {@link Item} Implementation if applicable + */ + Item item(AEColor color); + + /** + * @return the {@link TileEntity} Class if applicable. + */ + Class entity(AEColor color); + + /** + * @return an {@link ItemStack} with specified quantity of this item. + */ + ItemStack stack(AEColor color, int stackSize); + + /** + * @param stackSize + * - stack size of the result. + * @return an array of all colors. + */ + ItemStack[] allStacks(int stackSize); + + /** + * Compare {@link ItemStack} with this {@link AEItemDefinition} + * + * @param comparableItem + * @return true if the item stack is a matching item. + */ + boolean sameAs(AEColor color, ItemStack comparableItem); + +} diff --git a/src/main/java/appeng/api/util/AEItemDefinition.java b/src/main/java/appeng/api/util/AEItemDefinition.java new file mode 100644 index 0000000..2a42347 --- /dev/null +++ b/src/main/java/appeng/api/util/AEItemDefinition.java @@ -0,0 +1,54 @@ +package appeng.api.util; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; + +/** + * Gives easy access to different part of the various, items/blocks/materials in AE. + */ +public interface AEItemDefinition +{ + + /** + * @return the {@link Block} Implementation if applicable + */ + Block block(); + + /** + * @return the {@link Item} Implementation if applicable + */ + Item item(); + + /** + * @return the {@link TileEntity} Class if applicable. + */ + Class entity(); + + /** + * @return an {@link ItemStack} with specified quantity of this item. + */ + ItemStack stack(int stackSize); + + /** + * Compare {@link ItemStack} with this {@link AEItemDefinition} + * + * @param comparableItem + * @return true if the item stack is a matching item. + */ + boolean sameAsStack(ItemStack comparableItem); + + /** + * Compare Block with world. + * + * @param world + * @param x + * @param y + * @param z + * + * @return if the block is placed in the world at the specific location. + */ + boolean sameAsBlock(IBlockAccess world, int x, int y, int z); +} diff --git a/src/main/java/appeng/api/util/DimensionalCoord.java b/src/main/java/appeng/api/util/DimensionalCoord.java new file mode 100644 index 0000000..c602539 --- /dev/null +++ b/src/main/java/appeng/api/util/DimensionalCoord.java @@ -0,0 +1,73 @@ +package appeng.api.util; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +/** + * Represents a location in the Minecraft Universe + */ +public class DimensionalCoord extends WorldCoord +{ + + private World w; + private int dimId; + + public DimensionalCoord(DimensionalCoord s) { + super( s.x, s.y, s.z ); + w = s.w; + dimId = s.dimId; + } + + public DimensionalCoord(TileEntity s) { + super( s ); + w = s.getWorldObj(); + dimId = w.provider.dimensionId; + } + + public DimensionalCoord(World _w, int _x, int _y, int _z) { + super( _x, _y, _z ); + w = _w; + dimId = _w.provider.dimensionId; + } + + @Override + public DimensionalCoord copy() + { + return new DimensionalCoord( this ); + } + + public boolean isEqual(DimensionalCoord c) + { + return x == c.x && y == c.y && z == c.z && c.w == this.w; + } + + @Override + public boolean equals(Object obj) + { + if ( obj instanceof DimensionalCoord ) + return isEqual( (DimensionalCoord) obj ); + return false; + } + + @Override + public int hashCode() + { + return super.hashCode() ^ dimId; + } + + public boolean isInWorld(World world) + { + return w == world; + } + + @Override + public String toString() + { + return dimId + "," + super.toString(); + } + + public World getWorld() + { + return w; + } +} diff --git a/src/main/java/appeng/api/util/ICommonTile.java b/src/main/java/appeng/api/util/ICommonTile.java new file mode 100644 index 0000000..82a5250 --- /dev/null +++ b/src/main/java/appeng/api/util/ICommonTile.java @@ -0,0 +1,23 @@ +package appeng.api.util; + +import java.util.ArrayList; + +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface ICommonTile +{ + + /** + * implemented on AE's Tile Entities, Gets a list of drops that the entity will normally drop, this doesn't include + * the block itself. + * + * @param world + * @param x + * @param y + * @param z + * @param drops + */ + void getDrops(World world, int x, int y, int z, ArrayList drops); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/util/IConfigManager.java b/src/main/java/appeng/api/util/IConfigManager.java new file mode 100644 index 0000000..f8cddb8 --- /dev/null +++ b/src/main/java/appeng/api/util/IConfigManager.java @@ -0,0 +1,62 @@ +package appeng.api.util; + +import java.util.Set; + +import net.minecraft.nbt.NBTTagCompound; + +/** + * Used to adjust settings on an object, + * + * Obtained via {@link IConfigureableObject} + */ +public interface IConfigManager +{ + + /** + * get a list of different settings + * + * @return + */ + Set getSettings(); + + /** + * used to initialize the configuration manager, should be called for all settings. + * + * @param settingName + * @param defaultValue + * @return + */ + void registerSetting(Enum settingName, Enum defaultValue); + + /** + * Get Value of a particlar setting + * + * @param settingName + * @return + */ + Enum getSetting(Enum settingName); + + /** + * Change setting + * + * @param settingName + * @param newValue + * @return + */ + Enum putSetting(Enum settingName, Enum newValue); + + /** + * write all settings to the NBT Tag so they can be read later. + * + * @param dest + */ + void writeToNBT(NBTTagCompound dest); + + /** + * Only works after settings have been registered + * + * @param src + */ + void readFromNBT(NBTTagCompound src); + +} diff --git a/src/main/java/appeng/api/util/IConfigureableObject.java b/src/main/java/appeng/api/util/IConfigureableObject.java new file mode 100644 index 0000000..4e36b3f --- /dev/null +++ b/src/main/java/appeng/api/util/IConfigureableObject.java @@ -0,0 +1,14 @@ +package appeng.api.util; + +/** + * Implemented by various Tiles or Parts in AE + */ +public interface IConfigureableObject +{ + + /** + * get the config manager for the object. + */ + IConfigManager getConfigManager(); + +} diff --git a/src/main/java/appeng/api/util/INetworkToolAgent.java b/src/main/java/appeng/api/util/INetworkToolAgent.java new file mode 100644 index 0000000..c2e511b --- /dev/null +++ b/src/main/java/appeng/api/util/INetworkToolAgent.java @@ -0,0 +1,13 @@ +package appeng.api.util; + +import net.minecraft.util.MovingObjectPosition; + +/** + * Implement on Tile or part to customize if the info gui opens, or an action is preformed. + */ +public interface INetworkToolAgent +{ + + boolean showNetworkInfo(MovingObjectPosition where); + +} diff --git a/src/main/java/appeng/api/util/IOrientable.java b/src/main/java/appeng/api/util/IOrientable.java new file mode 100644 index 0000000..e130ccb --- /dev/null +++ b/src/main/java/appeng/api/util/IOrientable.java @@ -0,0 +1,37 @@ +package appeng.api.util; + +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Nearly all of AE's Tile Entities implement IOrientable. + * + * and it can be used to manipulate the direction of some machines, most of these orientations are purely visual. + * + * AE also responds to {@link Block}.rotateBlock + */ +public interface IOrientable +{ + + /** + * @return true or false, if the tile rotation is meaningful, or even changeable + */ + boolean canBeRotated(); + + /** + * @return the direction the tile is facing + */ + ForgeDirection getForward(); + + /** + * @return the direction top of the tile + */ + ForgeDirection getUp(); + + /** + * Update the orientation + * @param Forward + * @param Up + */ + void setOrientation(ForgeDirection Forward, ForgeDirection Up); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/util/IOrientableBlock.java b/src/main/java/appeng/api/util/IOrientableBlock.java new file mode 100644 index 0000000..95bf11e --- /dev/null +++ b/src/main/java/appeng/api/util/IOrientableBlock.java @@ -0,0 +1,25 @@ +package appeng.api.util; + +import net.minecraft.world.IBlockAccess; + +/** + * Implemented on many of AE's non Tile Entity Blocks as a way to get a IOrientable. + */ +public interface IOrientableBlock +{ + + /** + * @return if this block uses metadata to store its rotation. + */ + boolean usesMetadata(); + + /** + * @param world + * @param x + * @param y + * @param z + * @return a IOrientable if applicable + */ + IOrientable getOrientable(IBlockAccess world, int x, int y, int z); + +} \ No newline at end of file diff --git a/src/main/java/appeng/api/util/IReadOnlyCollection.java b/src/main/java/appeng/api/util/IReadOnlyCollection.java new file mode 100644 index 0000000..ab087ca --- /dev/null +++ b/src/main/java/appeng/api/util/IReadOnlyCollection.java @@ -0,0 +1,21 @@ +package appeng.api.util; + +public interface IReadOnlyCollection extends Iterable +{ + + /** + * @return the objects in in the set. + */ + int size(); + + /** + * @return true if there are objects in the set + */ + boolean isEmpty(); + + /** + * @return return true if the object is part of the set. + */ + boolean contains(Object node); + +} diff --git a/src/main/java/appeng/api/util/WorldCoord.java b/src/main/java/appeng/api/util/WorldCoord.java new file mode 100644 index 0000000..beb43b3 --- /dev/null +++ b/src/main/java/appeng/api/util/WorldCoord.java @@ -0,0 +1,138 @@ +package appeng.api.util; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; + +/** + * Represents a relative coordinate, either relative to another object, or + * relative to the origin of a dimension. + */ +public class WorldCoord +{ + + public int x; + public int y; + public int z; + + public WorldCoord add(ForgeDirection direction, int length) + { + x += direction.offsetX * length; + y += direction.offsetY * length; + z += direction.offsetZ * length; + return this; + } + + public WorldCoord subtract(ForgeDirection direction, int length) + { + x -= direction.offsetX * length; + y -= direction.offsetY * length; + z -= direction.offsetZ * length; + return this; + } + + public WorldCoord add(int _x, int _y, int _z) + { + x += _x; + y += _y; + z += _z; + return this; + } + + public WorldCoord subtract(int _x, int _y, int _z) + { + x -= _x; + y -= _y; + z -= _z; + return this; + } + + public WorldCoord multiple(int _x, int _y, int _z) + { + x *= _x; + y *= _y; + z *= _z; + return this; + } + + public WorldCoord divide(int _x, int _y, int _z) + { + x /= _x; + y /= _y; + z /= _z; + return this; + } + + public WorldCoord(int _x, int _y, int _z) { + x = _x; + y = _y; + z = _z; + } + + public WorldCoord(TileEntity s) { + this( s.xCoord, s.yCoord, s.zCoord ); + } + + /** + * Will Return NULL if it's at some diagonal! + */ + public ForgeDirection directionTo(WorldCoord loc) + { + int ox = x - loc.x; + int oy = y - loc.y; + int oz = z - loc.z; + + int xlen = Math.abs( ox ); + int ylen = Math.abs( oy ); + int zlen = Math.abs( oz ); + + if ( loc.isEqual( this.copy().add( ForgeDirection.EAST, xlen ) ) ) + return ForgeDirection.EAST; + + if ( loc.isEqual( this.copy().add( ForgeDirection.WEST, xlen ) ) ) + return ForgeDirection.WEST; + + if ( loc.isEqual( this.copy().add( ForgeDirection.NORTH, zlen ) ) ) + return ForgeDirection.NORTH; + + if ( loc.isEqual( this.copy().add( ForgeDirection.SOUTH, zlen ) ) ) + return ForgeDirection.SOUTH; + + if ( loc.isEqual( this.copy().add( ForgeDirection.UP, ylen ) ) ) + return ForgeDirection.UP; + + if ( loc.isEqual( this.copy().add( ForgeDirection.DOWN, ylen ) ) ) + return ForgeDirection.DOWN; + + return null; + } + + public boolean isEqual(WorldCoord c) + { + return x == c.x && y == c.y && z == c.z; + } + + public WorldCoord copy() + { + return new WorldCoord( x, y, z ); + } + + @Override + public boolean equals(Object obj) + { + if ( obj instanceof WorldCoord ) + return isEqual( (WorldCoord) obj ); + return false; + } + + @Override + public String toString() + { + return "" + x + "," + y + "," + z; + } + + @Override + public int hashCode() + { + return (y << 24) ^ x ^ z; + } +} diff --git a/src/main/java/mr208/WeaponVault/AE2/AE2Integration.java b/src/main/java/mr208/WeaponVault/AE2/AE2Integration.java new file mode 100644 index 0000000..8c2011f --- /dev/null +++ b/src/main/java/mr208/WeaponVault/AE2/AE2Integration.java @@ -0,0 +1,68 @@ +package mr208.WeaponVault.AE2; + +import appeng.api.AEApi; +import ckathode.weaponmod.entity.projectile.MaterialRegistry; +import ckathode.weaponmod.item.*; +import mr208.WeaponVault.CustomMaterials; +import mr208.WeaponVault.Items.WVItemFlail; +import mr208.WeaponVault.Items.WVItemMelee; +import mr208.WeaponVault.Items.WVItemMusket; +import mr208.WeaponVault.WVConfig; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import mr208.WeaponVault.Materials; + + +public class AE2Integration { + + public static Item battleaxeCertus; + public static Item boomerangCertus; + public static Item flailCertus; + public static Item halberdCertus; + public static Item katanaCertus; + public static Item knifeCertus; + public static Item musketbayonetCertus; + public static Item spearCertus; + public static Item warhammerCertus; + + public static Item battleaxeQuartz; + public static Item boomerangQuartz; + public static Item flailQuartz; + public static Item halberdQuartz; + public static Item katanaQuartz; + public static Item knifeQuartz; + public static Item musketbayonetQuartz; + public static Item spearQuartz; + public static Item warhammerQuartz; + + public static void initAE2() + { + if(WVConfig.enableCertusQuartz) initCertus(); + if(WVConfig.enableNetherQuartz) initNether(); + } + private static void initNether() + { + battleaxeQuartz = new WVItemMelee("battleaxe.quartz", new MeleeCompBattleaxe(Materials.netherQuartz)); + boomerangQuartz = new WVItemMelee("boomerang.quartz", new MeleeCompBoomerang(Materials.netherQuartz)); + flailQuartz = new WVItemFlail("flail.quartz", Materials.netherQuartz); + halberdQuartz = new WVItemMelee("halberd.quartz", new MeleeCompHalberd(Materials.netherQuartz)); + katanaQuartz = new WVItemMelee("katana.quartz", new MeleeComponent(MeleeComponent.MeleeSpecs.KATANA,Materials.netherQuartz)); + knifeQuartz = new WVItemMelee("knife.quartz", new MeleeCompKnife(Materials.netherQuartz)); + musketbayonetQuartz = new WVItemMusket("musketbayonet.quartz", new MeleeCompKnife(Materials.netherQuartz),knifeQuartz); + spearQuartz = new WVItemMelee("spear.quartz",new MeleeCompSpear(Materials.netherQuartz)); + warhammerQuartz = new WVItemMelee("warhammer.quartz", new MeleeCompWarhammer(Materials.netherQuartz)); + } + + private static void initCertus() + { + battleaxeCertus = new WVItemMelee("battleaxe.certus", new MeleeCompBattleaxe(Materials.certusQuartz)); + boomerangCertus = new WVItemMelee("boomerang.certus", new MeleeCompBoomerang(Materials.certusQuartz)); + flailCertus = new WVItemFlail("flail.certus", Materials.certusQuartz); + halberdCertus = new WVItemMelee("halberd.certus", new MeleeCompHalberd(Materials.certusQuartz)); + katanaCertus = new WVItemMelee("katana.certus", new MeleeComponent(MeleeComponent.MeleeSpecs.KATANA,Materials.certusQuartz)); + knifeCertus = new WVItemMelee("knife.certus", new MeleeCompKnife(Materials.certusQuartz)); + musketbayonetCertus = new WVItemMusket("musketbayonet.certus", new MeleeCompKnife(Materials.certusQuartz),knifeCertus); + spearCertus = new WVItemMelee("spear.certus",new MeleeCompSpear(Materials.certusQuartz)); + warhammerCertus = new WVItemMelee("warhammer.certus", new MeleeCompWarhammer(Materials.certusQuartz)); + } +} diff --git a/src/main/java/mr208/WeaponVault/Botania/BotaniaIntegration.java b/src/main/java/mr208/WeaponVault/Botania/BotaniaIntegration.java new file mode 100644 index 0000000..2376e10 --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Botania/BotaniaIntegration.java @@ -0,0 +1,54 @@ +package mr208.WeaponVault.Botania; + +import ckathode.weaponmod.entity.projectile.MaterialRegistry; +import ckathode.weaponmod.item.*; +import mr208.WeaponVault.Botania.Items.BotanicalItemFlail; +import mr208.WeaponVault.Botania.Items.BotanicalItemMelee; +import mr208.WeaponVault.Botania.Items.BotanicalItemMusket; +import mr208.WeaponVault.CustomMaterials; +import mr208.WeaponVault.WVConfig; +import vazkii.botania.api.BotaniaAPI; +import net.minecraft.item.Item; + +public class BotaniaIntegration { + + public static Item battleaxeManasteel; + public static Item boomerangManasteel; + public static Item flailManasteel; + public static Item halberdManasteel; + public static Item katanaManasteel; + public static Item knifeManasteel; + public static Item musketbayonetManasteel; + public static Item spearManasteel; + public static Item warhammerManasteel; + + public static void initBotania() + { + if(WVConfig.enableManaSteel) initManasteel(); + } + private static void initManasteel() + { + MaterialRegistry.registerCustomProjectileMaterial(new CustomMaterials(BotaniaAPI.manasteelToolMaterial, 0x7DC3E5FF)); + + battleaxeManasteel = new BotanicalItemMelee("battleaxe.manasteel", new MeleeCompBattleaxe(BotaniaAPI.manasteelToolMaterial)); + boomerangManasteel = new BotanicalItemMelee("boomerang.manasteel", new MeleeCompBoomerang(BotaniaAPI.manasteelToolMaterial)); + flailManasteel = new BotanicalItemFlail("flail.manasteel", BotaniaAPI.manasteelToolMaterial); + halberdManasteel = new BotanicalItemMelee("halberd.manasteel", new MeleeCompHalberd(BotaniaAPI.manasteelToolMaterial)); + katanaManasteel = new BotanicalItemMelee("katana.manasteel", new MeleeComponent(MeleeComponent.MeleeSpecs.KATANA,BotaniaAPI.manasteelToolMaterial)); + knifeManasteel = new BotanicalItemMelee("knife.manasteel", new MeleeCompKnife(BotaniaAPI.manasteelToolMaterial)); + musketbayonetManasteel = new BotanicalItemMusket("musketbayonet.manasteel", new MeleeCompKnife(BotaniaAPI.manasteelToolMaterial),knifeManasteel); + spearManasteel = new BotanicalItemMelee("spear.manasteel", new MeleeCompSpear(BotaniaAPI.manasteelToolMaterial)); + warhammerManasteel = new BotanicalItemMelee("warhammer.manasteel", new MeleeCompWarhammer(BotaniaAPI.manasteelToolMaterial)); + + } + private static void initTerrasteel() + { + MaterialRegistry.registerCustomProjectileMaterial(new CustomMaterials(BotaniaAPI.terrasteelToolMaterial, 0x79C958FF)); + + + } + private static void initElementium() + { + MaterialRegistry.registerCustomProjectileMaterial(new CustomMaterials(BotaniaAPI.elementiumToolMaterial, 0xFFACFFFF)); + } +} diff --git a/src/main/java/mr208/WeaponVault/Botania/Items/BotanicalItemFlail.java b/src/main/java/mr208/WeaponVault/Botania/Items/BotanicalItemFlail.java new file mode 100644 index 0000000..677744b --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Botania/Items/BotanicalItemFlail.java @@ -0,0 +1,39 @@ +package mr208.WeaponVault.Botania.Items; + +import mr208.WeaponVault.Botania.ManaHelper; +import mr208.WeaponVault.Items.WVItemFlail; +import net.minecraft.block.Block; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import vazkii.botania.api.mana.IManaUsingItem; + +/** + * Created by Andrew on 10/17/2014. + */ +public class BotanicalItemFlail extends WVItemFlail implements IManaUsingItem { + private static final int MANA_PER_DMG = 51; + public BotanicalItemFlail(String id, ToolMaterial toolmaterial) { + super(id, toolmaterial); + } + + + @Override + public boolean hitEntity(ItemStack itemWeapon, EntityLivingBase targetEntity, EntityLivingBase usingEntity) + { + if(usesMana(itemWeapon)) ManaHelper.damageItem(itemWeapon, 1, usingEntity, MANA_PER_DMG); + return true; + } + + @Override + public boolean onBlockDestroyed(ItemStack itemWeapon, World world, Block block, int x,int y, int z, EntityLivingBase player) + { + if(usesMana(itemWeapon) && block.getBlockHardness(world,x,y,z) !=0f) ManaHelper.damageItem(itemWeapon,1,player,MANA_PER_DMG); + return true; + } + + @Override + public boolean usesMana(ItemStack stack) { + return true; + } +} diff --git a/src/main/java/mr208/WeaponVault/Botania/Items/BotanicalItemMelee.java b/src/main/java/mr208/WeaponVault/Botania/Items/BotanicalItemMelee.java new file mode 100644 index 0000000..2d61b4d --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Botania/Items/BotanicalItemMelee.java @@ -0,0 +1,38 @@ +package mr208.WeaponVault.Botania.Items; + +import ckathode.weaponmod.item.MeleeComponent; +import mr208.WeaponVault.Botania.ManaHelper; +import mr208.WeaponVault.Items.WVItemMelee; +import net.minecraft.block.Block; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import vazkii.botania.api.mana.IManaUsingItem; + + + +public class BotanicalItemMelee extends WVItemMelee implements IManaUsingItem { + public static final int MANA_PER_DMG = 51; + public BotanicalItemMelee(String id, MeleeComponent meleecomponent) { + super(id, meleecomponent); + } + + @Override + public boolean hitEntity(ItemStack itemWeapon, EntityLivingBase targetEntity, EntityLivingBase usingEntity) + { + if(usesMana(itemWeapon)) ManaHelper.damageItem(itemWeapon,1,usingEntity,MANA_PER_DMG); + return true; + } + + @Override + public boolean onBlockDestroyed(ItemStack itemWeapon, World world, Block block, int x,int y, int z, EntityLivingBase player) + { + if(usesMana(itemWeapon) && block.getBlockHardness(world,x,y,z) !=0f) ManaHelper.damageItem(itemWeapon,1,player,MANA_PER_DMG); + return true; + } + + @Override + public boolean usesMana(ItemStack stack) { + return true; + } +} diff --git a/src/main/java/mr208/WeaponVault/Botania/Items/BotanicalItemMusket.java b/src/main/java/mr208/WeaponVault/Botania/Items/BotanicalItemMusket.java new file mode 100644 index 0000000..7a6b95c --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Botania/Items/BotanicalItemMusket.java @@ -0,0 +1,38 @@ +package mr208.WeaponVault.Botania.Items; + +import ckathode.weaponmod.item.ItemMusket; +import ckathode.weaponmod.item.MeleeComponent; +import mr208.WeaponVault.Botania.ManaHelper; +import mr208.WeaponVault.Items.WVItemMusket; +import net.minecraft.block.Block; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import vazkii.botania.api.mana.IManaUsingItem; + +public class BotanicalItemMusket extends WVItemMusket implements IManaUsingItem { + private static final int MANA_PER_DMG = 51; + public BotanicalItemMusket(String id, MeleeComponent meleecomponent, Item bayonetitem) { + super(id, meleecomponent, bayonetitem); + } + + @Override + public boolean hitEntity(ItemStack itemWeapon, EntityLivingBase targetEntity, EntityLivingBase usingEntity) + { + if(usesMana(itemWeapon)) ManaHelper.damageItem(itemWeapon, 1, usingEntity, MANA_PER_DMG); + return true; + } + + @Override + public boolean onBlockDestroyed(ItemStack itemWeapon, World world, Block block, int x,int y, int z, EntityLivingBase player) + { + if(usesMana(itemWeapon) && block.getBlockHardness(world,x,y,z) !=0f) ManaHelper.damageItem(itemWeapon,1,player,MANA_PER_DMG); + return true; + } + + @Override + public boolean usesMana(ItemStack stack) { + return true; + } +} diff --git a/src/main/java/mr208/WeaponVault/Botania/ManaHelper.java b/src/main/java/mr208/WeaponVault/Botania/ManaHelper.java new file mode 100644 index 0000000..fc47249 --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Botania/ManaHelper.java @@ -0,0 +1,19 @@ +package mr208.WeaponVault.Botania; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import vazkii.botania.api.mana.ManaItemHandler; + +/** + * Created by Andrew on 10/17/2014. + */ +public class ManaHelper { + + public static void damageItem(ItemStack item, int damage, EntityLivingBase player, int cost) + { + int mananeeded = damage * cost; + boolean manacostmet = player instanceof EntityPlayer ? ManaItemHandler.requestManaExact(item,(EntityPlayer) player,mananeeded,true) : false; + if(!manacostmet) item.damageItem(damage, player); + } +} diff --git a/src/main/java/mr208/WeaponVault/CustomMaterials.java b/src/main/java/mr208/WeaponVault/CustomMaterials.java new file mode 100644 index 0000000..f0dedd8 --- /dev/null +++ b/src/main/java/mr208/WeaponVault/CustomMaterials.java @@ -0,0 +1,57 @@ +package mr208.WeaponVault; + +import ckathode.weaponmod.entity.projectile.ICustomProjectileMaterials; +import mr208.WeaponVault.Thaumcraft.Items.*; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import thaumcraft.api.ThaumcraftApi; + +/** + * Created by Andrew on 10/16/2014. + */ +public class CustomMaterials implements ICustomProjectileMaterials { + + public final Item.ToolMaterial customMat; + private float[] entityColorF; + public final int entityColorI; + + public CustomMaterials(Item.ToolMaterial material, int color) + { + customMat = material; + entityColorI = color; + entityColorF = null; + } + + + + @Override + public int[] getAllMaterialIDs() { + int[] ids = {customMat.ordinal()}; + return ids; + } + + @Override + public int getMaterialID(ItemStack itemStack) { + + + if(itemStack.getItem() instanceof IWeaponMaterialCheck) + { + return ((IWeaponMaterialCheck) itemStack.getItem()).getMaterialID(); + } + return 0; + } + + @Override + public float[] getColorFromMaterialID(int i) { + + if(entityColorF==null) + { + entityColorF = new float[4]; + entityColorF[0] = ((entityColorI >> 24) & 0xFF)/255f; + entityColorF[1] = ((entityColorI >> 16) & 0xFF)/255f; + entityColorF[2] = ((entityColorI >> 8) & 0xFF)/255f; + entityColorF[3] = (entityColorI & 0xFF)/255f; + } + return entityColorF; + } +} diff --git a/src/main/java/mr208/WeaponVault/IWeaponMaterialCheck.java b/src/main/java/mr208/WeaponVault/IWeaponMaterialCheck.java new file mode 100644 index 0000000..9b2e4c4 --- /dev/null +++ b/src/main/java/mr208/WeaponVault/IWeaponMaterialCheck.java @@ -0,0 +1,7 @@ +package mr208.WeaponVault; + +public interface IWeaponMaterialCheck { + + public int getMaterialID(); + +} diff --git a/src/main/java/mr208/WeaponVault/Items/GenericMetalsIntegration.java b/src/main/java/mr208/WeaponVault/Items/GenericMetalsIntegration.java new file mode 100644 index 0000000..62fac48 --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Items/GenericMetalsIntegration.java @@ -0,0 +1,47 @@ +package mr208.WeaponVault.Items; + + +import ckathode.weaponmod.item.ItemMelee; +import ckathode.weaponmod.item.MeleeCompBattleaxe; +import net.minecraft.item.Item; +import net.minecraftforge.common.util.EnumHelper; + +public class GenericMetalsIntegration { + + public static Item battleaxeBronze; + public static Item boomerangBronze; + public static Item flailBronze; + public static Item halberdBronze; + public static Item katanaBronze; + public static Item knifeBronze; + public static Item musketbayonetBronze; + public static Item spearBronze; + public static Item warhammerBronze; + + public static Item battleaxeSteel; + public static Item boomerangSteel; + public static Item flailSteel; + public static Item halberdSteel; + public static Item katanaSteel; + public static Item knifeSteel; + public static Item musketbayonetSteel; + public static Item spearSteel; + public static Item warhammerSteel; + + + public void initGenericMetals() { + + + } + + public static void initBronze() { + ; + } + + + public static void initSteel() { + + } + + +} \ No newline at end of file diff --git a/src/main/java/mr208/WeaponVault/Items/WVItemFlail.java b/src/main/java/mr208/WeaponVault/Items/WVItemFlail.java new file mode 100644 index 0000000..9644637 --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Items/WVItemFlail.java @@ -0,0 +1,46 @@ +package mr208.WeaponVault.Items; + +import appeng.api.AEApi; +import ckathode.weaponmod.item.ItemFlail; +import mr208.WeaponVault.IWeaponMaterialCheck; +import mr208.WeaponVault.Materials; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; +import thaumcraft.api.ItemApi; +import thaumcraft.api.ThaumcraftApi; +import vazkii.botania.api.BotaniaAPI; + + +public class WVItemFlail extends ItemFlail implements IWeaponMaterialCheck { + private final int materialID; + private final ToolMaterial toolMat; + public WVItemFlail(String id, ToolMaterial toolmaterial) { + super(id, toolmaterial); + this.materialID = toolmaterial.ordinal(); + this.toolMat = toolmaterial; + } + + @Override + public int getMaterialID() { + return materialID; + } + + @Override + public boolean getIsRepairable(ItemStack weaponStack, ItemStack itemStack) + { + return itemStack.isItemEqual(getRepairItem(toolMat)) ? true: super.getIsRepairable(weaponStack, itemStack); + } + + private ItemStack getRepairItem(ToolMaterial material) + { + if(material == ThaumcraftApi.toolMatThaumium) return ItemApi.getItem("itemResource",2); + if(material == ThaumcraftApi.toolMatVoid) return ItemApi.getItem("itemResource",16); + if(material == Materials.netherQuartz) return new ItemStack(Items.quartz); + if(material == Materials.certusQuartz) return AEApi.instance().materials().materialCertusQuartzCrystal.stack(1); + if(material == BotaniaAPI.manasteelToolMaterial) return OreDictionary.getOres("ingotManasteel").get(0); + if(material == BotaniaAPI.terrasteelToolMaterial) return OreDictionary.getOres("ingotTerrasteel").get(0); + if(material == BotaniaAPI.elementiumToolMaterial) return OreDictionary.getOres("ingotElementium").get(0); + return new ItemStack(material.func_150995_f()); + } +} diff --git a/src/main/java/mr208/WeaponVault/Items/WVItemMelee.java b/src/main/java/mr208/WeaponVault/Items/WVItemMelee.java new file mode 100644 index 0000000..12c082d --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Items/WVItemMelee.java @@ -0,0 +1,48 @@ +package mr208.WeaponVault.Items; + +import appeng.api.AEApi; +import ckathode.weaponmod.item.ItemMelee; +import ckathode.weaponmod.item.MeleeComponent; +import cpw.mods.fml.common.registry.GameRegistry; +import mr208.WeaponVault.IWeaponMaterialCheck; +import mr208.WeaponVault.Materials; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; +import thaumcraft.api.ItemApi; +import thaumcraft.api.ThaumcraftApi; +import vazkii.botania.api.BotaniaAPI; + +public class WVItemMelee extends ItemMelee implements IWeaponMaterialCheck { + private final int materialID; + + public WVItemMelee(String id, MeleeComponent meleecomponent) { + super(id, meleecomponent); + this.materialID = meleecomponent.weaponMaterial.ordinal(); + + } + + @Override + public int getMaterialID() { + return materialID; + } + + @Override + public boolean getIsRepairable(ItemStack weaponStack, ItemStack itemStack) + { + return itemStack.isItemEqual(getRepairItem(this.meleeComponent.weaponMaterial)) ? true: super.getIsRepairable(weaponStack, itemStack); + } + + private ItemStack getRepairItem(ToolMaterial material) + { + if(material == ThaumcraftApi.toolMatThaumium) return ItemApi.getItem("itemResource",2); + if(material == ThaumcraftApi.toolMatVoid) return ItemApi.getItem("itemResource",16); + if(material == Materials.netherQuartz) return new ItemStack(Items.quartz); + if(material == Materials.certusQuartz) return AEApi.instance().materials().materialCertusQuartzCrystal.stack(1); + if(material == BotaniaAPI.manasteelToolMaterial) return OreDictionary.getOres("ingotManasteel").get(0); + if(material == BotaniaAPI.terrasteelToolMaterial) return OreDictionary.getOres("ingotTerrasteel").get(0); + if(material == BotaniaAPI.elementiumToolMaterial) return OreDictionary.getOres("ingotElementium").get(0); + return new ItemStack(material.func_150995_f()); + } + +} diff --git a/src/main/java/mr208/WeaponVault/Items/WVItemMusket.java b/src/main/java/mr208/WeaponVault/Items/WVItemMusket.java new file mode 100644 index 0000000..9a19b3f --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Items/WVItemMusket.java @@ -0,0 +1,48 @@ +package mr208.WeaponVault.Items; + +import appeng.api.AEApi; +import ckathode.weaponmod.item.ItemMusket; +import ckathode.weaponmod.item.MeleeComponent; +import mr208.WeaponVault.IWeaponMaterialCheck; +import mr208.WeaponVault.Materials; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; +import thaumcraft.api.ItemApi; +import thaumcraft.api.ThaumcraftApi; +import vazkii.botania.api.BotaniaAPI; + +/** + * Created by Andrew on 10/16/2014. + */ +public class WVItemMusket extends ItemMusket implements IWeaponMaterialCheck { + private final int materialID; + public WVItemMusket(String id, MeleeComponent meleecomponent, Item bayonetitem) { + super(id, meleecomponent, bayonetitem); + materialID = meleecomponent.weaponMaterial.ordinal(); + } + + @Override + public int getMaterialID() { + return materialID; + } + + @Override + public boolean getIsRepairable(ItemStack weaponStack, ItemStack itemStack) + { + return itemStack.isItemEqual(getRepairItem(this.meleeComponent.weaponMaterial)) ? true: super.getIsRepairable(weaponStack, itemStack); + } + private ItemStack getRepairItem(ToolMaterial material) + { + if(material == ThaumcraftApi.toolMatThaumium) return ItemApi.getItem("itemResource",2); + if(material == ThaumcraftApi.toolMatVoid) return ItemApi.getItem("itemResource",16); + if(material == Materials.netherQuartz) return new ItemStack(Items.quartz); + if(material == Materials.certusQuartz) return AEApi.instance().materials().materialCertusQuartzCrystal.stack(1); + if(material == BotaniaAPI.manasteelToolMaterial) return OreDictionary.getOres("ingotManasteel").get(0); + if(material == BotaniaAPI.terrasteelToolMaterial) return OreDictionary.getOres("ingotTerrasteel").get(0); + if(material == BotaniaAPI.elementiumToolMaterial) return OreDictionary.getOres("ingotElementium").get(0); + return new ItemStack(material.func_150995_f()); + } + +} diff --git a/src/main/java/mr208/WeaponVault/Materials.java b/src/main/java/mr208/WeaponVault/Materials.java new file mode 100644 index 0000000..5e16482 --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Materials.java @@ -0,0 +1,35 @@ +package mr208.WeaponVault; + +import ckathode.weaponmod.entity.projectile.MaterialRegistry; +import net.minecraft.item.Item; +import net.minecraftforge.common.util.EnumHelper; + +/** + * Created by Andrew on 10/17/2014. + */ +public class Materials { + + public static Item.ToolMaterial netherQuartz; + public static Item.ToolMaterial certusQuartz; + + + public static void initMaterials() + { + netherQuartz = EnumHelper.addToolMaterial("NETHER_QUARTZ", + Item.ToolMaterial.IRON.getHarvestLevel(), + Item.ToolMaterial.IRON.getMaxUses(), + Item.ToolMaterial.IRON.getEfficiencyOnProperMaterial(), + Item.ToolMaterial.IRON.getDamageVsEntity(), + Item.ToolMaterial.IRON.getEnchantability()); + + certusQuartz = EnumHelper.addToolMaterial("CERTUS_QUARTZ", + Item.ToolMaterial.IRON.getHarvestLevel(), + Item.ToolMaterial.IRON.getMaxUses(), + Item.ToolMaterial.IRON.getEfficiencyOnProperMaterial(), + Item.ToolMaterial.IRON.getDamageVsEntity(), + Item.ToolMaterial.IRON.getEnchantability()); + + MaterialRegistry.registerCustomProjectileMaterial(new CustomMaterials(certusQuartz, 0xADC6EEFF)); + MaterialRegistry.registerCustomProjectileMaterial(new CustomMaterials(netherQuartz, 0xBFB8AEFF)); + } +} diff --git a/src/main/java/mr208/WeaponVault/Thaumcraft/Items/ThaumicItemFlail.java b/src/main/java/mr208/WeaponVault/Thaumcraft/Items/ThaumicItemFlail.java new file mode 100644 index 0000000..0f6a736 --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Thaumcraft/Items/ThaumicItemFlail.java @@ -0,0 +1,18 @@ +package mr208.WeaponVault.Thaumcraft.Items; + +import net.minecraft.item.EnumRarity; +import net.minecraft.item.ItemStack; +import mr208.WeaponVault.Items.WVItemFlail; +import thaumcraft.api.IRepairable; + + +public class ThaumicItemFlail extends WVItemFlail implements IRepairable + { + private EnumRarity rarity; + public ThaumicItemFlail(String id, ToolMaterial toolmaterial, EnumRarity eRare) {super(id, toolmaterial);this.rarity = eRare;} + + public EnumRarity func_77613_e(ItemStack par1) + { + return rarity; + } + } \ No newline at end of file diff --git a/src/main/java/mr208/WeaponVault/Thaumcraft/Items/ThaumicItemMelee.java b/src/main/java/mr208/WeaponVault/Thaumcraft/Items/ThaumicItemMelee.java new file mode 100644 index 0000000..c20a67e --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Thaumcraft/Items/ThaumicItemMelee.java @@ -0,0 +1,27 @@ +package mr208.WeaponVault.Thaumcraft.Items; + +import ckathode.weaponmod.item.ItemMelee; +import ckathode.weaponmod.item.MeleeComponent; +import mr208.WeaponVault.IWeaponMaterialCheck; +import mr208.WeaponVault.Items.WVItemMelee; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import thaumcraft.api.IRepairable; + + +public class ThaumicItemMelee extends WVItemMelee implements IRepairable { + + private final EnumRarity rarity; + + public ThaumicItemMelee(String id, MeleeComponent meleecomponent,EnumRarity eRare) { + + super(id, meleecomponent); + this.rarity = eRare; + } + + public EnumRarity func_77613_e(ItemStack par1) + { + return rarity; + } +} diff --git a/src/main/java/mr208/WeaponVault/Thaumcraft/Items/ThaumicItemMusket.java b/src/main/java/mr208/WeaponVault/Thaumcraft/Items/ThaumicItemMusket.java new file mode 100644 index 0000000..66ed031 --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Thaumcraft/Items/ThaumicItemMusket.java @@ -0,0 +1,24 @@ +package mr208.WeaponVault.Thaumcraft.Items; + +import ckathode.weaponmod.item.MeleeComponent; +import mr208.WeaponVault.Items.WVItemMusket; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import thaumcraft.api.IRepairable; + +public class ThaumicItemMusket extends WVItemMusket implements IRepairable +{ + private final EnumRarity rarity; + + public ThaumicItemMusket(String id, MeleeComponent meleecomponent, Item bayonetitem, EnumRarity eRare) { + super(id, meleecomponent, bayonetitem); + this.rarity = eRare; + } + + public EnumRarity func_77613_e(ItemStack par1) + { + return rarity; + } + +} diff --git a/src/main/java/mr208/WeaponVault/Thaumcraft/Items/VoidItemFlail.java b/src/main/java/mr208/WeaponVault/Thaumcraft/Items/VoidItemFlail.java new file mode 100644 index 0000000..3aa457c --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Thaumcraft/Items/VoidItemFlail.java @@ -0,0 +1,49 @@ +package mr208.WeaponVault.Thaumcraft.Items; + +import ckathode.weaponmod.item.ItemFlail; +import mr208.WeaponVault.IWeaponMaterialCheck; +import mr208.WeaponVault.Items.WVItemFlail; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.World; +import thaumcraft.api.IRepairable; +import thaumcraft.api.IWarpingGear; + +public class VoidItemFlail extends WVItemFlail implements IRepairable, IWarpingGear { + private final EnumRarity rarity; + public VoidItemFlail(String id, ToolMaterial toolmaterial,EnumRarity eRare) { + super(id, toolmaterial); + this.rarity = eRare; + } + + public EnumRarity func_77613_e(ItemStack par1) + { + return rarity; + } + + @Override + public int getWarp(ItemStack itemStack, EntityPlayer player) { + return 1; + } + public void onUpdate(ItemStack stack, World world, Entity entity, int p_77663_4_, boolean p_77663_5_) + { + super.onUpdate(stack, world, entity, p_77663_4_, p_77663_5_); + if ((stack.isItemDamaged()) && (entity != null) && (entity.ticksExisted % 20 == 0) && ((entity instanceof EntityLivingBase))) + { stack.damageItem(-1, (EntityLivingBase)entity); } + } + public boolean onLeftClickEntity(ItemStack stack, EntityPlayer player, Entity entity) + { + if ((!player.capabilities.disableDamage) && ((entity instanceof EntityLivingBase)) && ((!(entity instanceof EntityPlayer)) || (MinecraftServer.getServer().isPVPEnabled()))) { + ( + (EntityLivingBase)entity).addPotionEffect(new PotionEffect(Potion.weakness.getId(), 80)); + } + + return super.onLeftClickEntity(stack, player, entity); + } +} diff --git a/src/main/java/mr208/WeaponVault/Thaumcraft/Items/VoidItemMelee.java b/src/main/java/mr208/WeaponVault/Thaumcraft/Items/VoidItemMelee.java new file mode 100644 index 0000000..fb7ee0a --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Thaumcraft/Items/VoidItemMelee.java @@ -0,0 +1,51 @@ +package mr208.WeaponVault.Thaumcraft.Items; + +import ckathode.weaponmod.item.MeleeComponent; +import mr208.WeaponVault.Items.WVItemMelee; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.World; +import thaumcraft.api.IRepairable; +import thaumcraft.api.IWarpingGear; + +public class VoidItemMelee extends WVItemMelee implements IRepairable, IWarpingGear { + private final EnumRarity rarity; + public VoidItemMelee(String id, MeleeComponent meleecomponent,EnumRarity eRare) { + super(id, meleecomponent); + this.rarity = eRare; + } + + public EnumRarity func_77613_e(ItemStack par1) + { + return rarity; + } + + @Override + public int getWarp(ItemStack itemStack, EntityPlayer player) { + return 1; + } + + public void onUpdate(ItemStack stack, World world, Entity entity, int p_77663_4_, boolean p_77663_5_) + { + super.onUpdate(stack, world, entity, p_77663_4_, p_77663_5_); + if ((stack.isItemDamaged()) && (entity != null) && (entity.ticksExisted % 20 == 0) && ((entity instanceof EntityLivingBase))) + { stack.damageItem(-1, (EntityLivingBase)entity); } + } + + public boolean onLeftClickEntity(ItemStack stack, EntityPlayer player, Entity entity) + { + if ((!player.capabilities.disableDamage) && ((entity instanceof EntityLivingBase)) && ((!(entity instanceof EntityPlayer)) || (MinecraftServer.getServer().isPVPEnabled()))) { + ( + (EntityLivingBase)entity).addPotionEffect(new PotionEffect(Potion.weakness.getId(), 80)); + } + + return super.onLeftClickEntity(stack, player, entity); + } +} diff --git a/src/main/java/mr208/WeaponVault/Thaumcraft/Items/VoidItemMusket.java b/src/main/java/mr208/WeaponVault/Thaumcraft/Items/VoidItemMusket.java new file mode 100644 index 0000000..09d01d2 --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Thaumcraft/Items/VoidItemMusket.java @@ -0,0 +1,55 @@ +package mr208.WeaponVault.Thaumcraft.Items; + +import ckathode.weaponmod.item.ItemMusket; +import ckathode.weaponmod.item.MeleeComponent; +import mr208.WeaponVault.IWeaponMaterialCheck; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.World; +import thaumcraft.api.IRepairable; +import thaumcraft.api.IWarpingGear; + +public class VoidItemMusket extends ItemMusket implements IRepairable, IWarpingGear { + + private final EnumRarity rarity; + + public VoidItemMusket(String id, MeleeComponent meleecomponent, Item bayonetitem,EnumRarity eRare) { + + super(id, meleecomponent, bayonetitem); + this.rarity = eRare; + } + + public EnumRarity func_77613_e(ItemStack par1) + { + return rarity; + } + + @Override + public int getWarp(ItemStack itemStack, EntityPlayer player) { + return 1; + } + + public void onUpdate(ItemStack stack, World world, Entity entity, int p_77663_4_, boolean p_77663_5_) + { + super.onUpdate(stack, world, entity, p_77663_4_, p_77663_5_); + if ((stack.isItemDamaged()) && (entity != null) && (entity.ticksExisted % 20 == 0) && ((entity instanceof EntityLivingBase))) + { stack.damageItem(-1, (EntityLivingBase)entity); } + } + + public boolean onLeftClickEntity(ItemStack stack, EntityPlayer player, Entity entity) + { + if ((!player.capabilities.disableDamage) && ((entity instanceof EntityLivingBase)) && ((!(entity instanceof EntityPlayer)) || (MinecraftServer.getServer().isPVPEnabled()))) { + ( + (EntityLivingBase)entity).addPotionEffect(new PotionEffect(Potion.weakness.getId(), 80)); + } + + return super.onLeftClickEntity(stack, player, entity); +} +} diff --git a/src/main/java/mr208/WeaponVault/Thaumcraft/ThaumcraftIntegration.java b/src/main/java/mr208/WeaponVault/Thaumcraft/ThaumcraftIntegration.java new file mode 100644 index 0000000..2cc3b5b --- /dev/null +++ b/src/main/java/mr208/WeaponVault/Thaumcraft/ThaumcraftIntegration.java @@ -0,0 +1,109 @@ +package mr208.WeaponVault.Thaumcraft; + +import ckathode.weaponmod.entity.projectile.MaterialRegistry; +import cpw.mods.fml.common.registry.GameRegistry; + + +import mr208.WeaponVault.CustomMaterials; +import mr208.WeaponVault.WVConfig; +import net.minecraft.init.Items; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + + +import mr208.WeaponVault.Thaumcraft.Items.ThaumicItemFlail; +import mr208.WeaponVault.Thaumcraft.Items.ThaumicItemMelee; +import mr208.WeaponVault.Thaumcraft.Items.ThaumicItemMusket; +import mr208.WeaponVault.Thaumcraft.Items.VoidItemFlail; +import mr208.WeaponVault.Thaumcraft.Items.VoidItemMelee; +import mr208.WeaponVault.Thaumcraft.Items.VoidItemMusket; + +import net.minecraftforge.oredict.ShapedOreRecipe; + +import ckathode.weaponmod.BalkonsWeaponMod; +import ckathode.weaponmod.item.*; + +import thaumcraft.api.ThaumcraftApi; +import thaumcraft.api.ThaumcraftApiHelper; + +public class ThaumcraftIntegration { + + public static Item battleaxeThaumium; + public static Item boomerangThaumium; + public static Item flailThaumium; + public static Item halberdThaumium; + public static Item katanaThaumium; + public static Item knifeThaumium; + public static Item musketbayonetThaumium; + public static Item spearThaumium; + public static Item warhammerThaumium; + + public static Item battleaxeVoidMetal; + public static Item boomerangVoidMetal; + public static Item flailVoidMetal; + public static Item halberdVoidMetal; + public static Item katanaVoidMetal; + public static Item knifeVoidMetal; + public static Item musketbayonetVoidMetal; + public static Item spearVoidMetal; + public static Item warhammerVoidMetal; + + public static void initThaumcraft() + { + if(WVConfig.enableThaumium) initThaumium(); + if(WVConfig.enableVoidMetal) initVoidMetal(); + } + + private static void initVoidMetal() + { + MaterialRegistry.registerCustomProjectileMaterial(new CustomMaterials(ThaumcraftApi.toolMatVoid, 0x2F1346FF)); + + battleaxeVoidMetal = new VoidItemMelee("battleaxe.void", new MeleeCompBattleaxe(ThaumcraftApi.toolMatVoid), EnumRarity.uncommon); + boomerangVoidMetal = new VoidItemMelee("boomerang.void", new MeleeCompBoomerang(ThaumcraftApi.toolMatVoid),EnumRarity.uncommon); + flailVoidMetal = new VoidItemFlail("flail.void", ThaumcraftApi.toolMatVoid,EnumRarity.uncommon); + halberdVoidMetal = new VoidItemMelee("halberd.void", new MeleeCompHalberd(ThaumcraftApi.toolMatVoid),EnumRarity.uncommon); + katanaVoidMetal = new VoidItemMelee("katana.void", new MeleeComponent(MeleeComponent.MeleeSpecs.KATANA, ThaumcraftApi.toolMatVoid),EnumRarity.uncommon); + knifeVoidMetal = new VoidItemMelee("knife.void", new MeleeCompKnife(ThaumcraftApi.toolMatVoid),EnumRarity.uncommon); + musketbayonetVoidMetal = new VoidItemMusket("musketbayonet.void", new MeleeCompKnife(ThaumcraftApi.toolMatVoid), knifeVoidMetal,EnumRarity.uncommon); + spearVoidMetal = new VoidItemMelee("spear.void", new MeleeCompSpear(ThaumcraftApi.toolMatVoid),EnumRarity.uncommon); + warhammerVoidMetal = new VoidItemMelee("warhammer.void", new MeleeCompWarhammer(ThaumcraftApi.toolMatVoid),EnumRarity.uncommon); + + GameRegistry.addRecipe(new ShapedOreRecipe(battleaxeVoidMetal, "###", "#X#", " X ", 'X', "stickWood", '#', "ingotVoid")); + GameRegistry.addRecipe(new ShapedOreRecipe(boomerangVoidMetal, "XX#", " X", " X", 'X', "plankWood", '#', "ingotVoid")); + GameRegistry.addRecipe(new ShapedOreRecipe(flailVoidMetal, " O", " XO", "X #", 'X', "stickWood", 'O', Items.string, '#', "ingotVoid")); + GameRegistry.addRecipe(new ShapedOreRecipe(halberdVoidMetal, " ##", " X#", "X ", 'X', "stickWood", '#', "ingotVoid")); + GameRegistry.addRecipe(new ShapedOreRecipe(katanaVoidMetal, " #", " # ", "X ", 'X', "stickWood", '#', "ingotVoid")); + GameRegistry.addRecipe(new ShapedOreRecipe(knifeVoidMetal, "#X", 'X', "stickWood", '#', "ingotVoid")); + GameRegistry.addRecipe(new ShapedOreRecipe(knifeVoidMetal, "#", "X", 'X', "stickWood", '#', "ingotVoid")); + GameRegistry.addShapelessRecipe(new ItemStack(musketbayonetVoidMetal), knifeVoidMetal, BalkonsWeaponMod.musket); + GameRegistry.addRecipe(new ShapedOreRecipe(spearVoidMetal, " #", " X ", "X ", 'X', "stickWood", '#', "ingotVoid")); + GameRegistry.addRecipe(new ShapedOreRecipe(warhammerVoidMetal, "#X#", "#X#", " X ", 'X', "stickWood", '#', "ingotVoid")); + } + private static void initThaumium() + { + MaterialRegistry.registerCustomProjectileMaterial(new CustomMaterials(ThaumcraftApi.toolMatThaumium, 0x46367dFF)); + + battleaxeThaumium = new ThaumicItemMelee("battleaxe.thaumium", new MeleeCompBattleaxe(ThaumcraftApi.toolMatThaumium),EnumRarity.uncommon); + boomerangThaumium = new ThaumicItemMelee("boomerang.thaumium", new MeleeCompBoomerang(ThaumcraftApi.toolMatThaumium),EnumRarity.uncommon); + flailThaumium = new ThaumicItemFlail("flail.thaumium", ThaumcraftApi.toolMatThaumium,EnumRarity.uncommon); + halberdThaumium = new ThaumicItemMelee("halberd.thaumium", new MeleeCompHalberd(ThaumcraftApi.toolMatThaumium),EnumRarity.uncommon); + katanaThaumium = new ThaumicItemMelee("katana.thaumium", new MeleeComponent(MeleeComponent.MeleeSpecs.KATANA, ThaumcraftApi.toolMatThaumium),EnumRarity.uncommon); + knifeThaumium = new ThaumicItemMelee("knife.thaumium", new MeleeCompKnife(ThaumcraftApi.toolMatThaumium),EnumRarity.uncommon); + musketbayonetThaumium = new ThaumicItemMusket("musketbayonet.thaumium", new MeleeCompKnife(ThaumcraftApi.toolMatThaumium), knifeThaumium,EnumRarity.uncommon); + spearThaumium = new ThaumicItemMelee("spear.thaumium", new MeleeCompSpear(ThaumcraftApi.toolMatThaumium),EnumRarity.uncommon); + warhammerThaumium = new ThaumicItemMelee("warhammer.thaumium", new MeleeCompWarhammer(ThaumcraftApi.toolMatThaumium),EnumRarity.uncommon); + + GameRegistry.addRecipe(new ShapedOreRecipe(battleaxeThaumium, "###", "#X#", " X ", 'X', "stickWood", '#', "ingotThaumium")); + GameRegistry.addRecipe(new ShapedOreRecipe(boomerangThaumium, "XX#", " X", " X", 'X', "plankWood", '#', "ingotThaumium")); + GameRegistry.addRecipe(new ShapedOreRecipe(flailThaumium, " O", " XO", "X #", 'X', "stickWood", 'O', Items.string, '#', "ingotThaumium")); + GameRegistry.addRecipe(new ShapedOreRecipe(halberdThaumium, " ##", " X#", "X ", 'X', "stickWood", '#', "ingotThaumium")); + GameRegistry.addRecipe(new ShapedOreRecipe(katanaThaumium, " #", " # ", "X ", 'X', "stickWood", '#', "ingotThaumium")); + GameRegistry.addRecipe(new ShapedOreRecipe(knifeThaumium, "#X", 'X', "stickWood", '#', "ingotThaumium")); + GameRegistry.addRecipe(new ShapedOreRecipe(knifeThaumium, "#", "X", 'X', "stickWood", '#', "ingotThaumium")); + GameRegistry.addShapelessRecipe(new ItemStack(musketbayonetThaumium), knifeThaumium, BalkonsWeaponMod.musket); + GameRegistry.addRecipe(new ShapedOreRecipe(spearThaumium, " #", " X ", "X ", 'X', "stickWood", '#', "ingotThaumium")); + GameRegistry.addRecipe(new ShapedOreRecipe(warhammerThaumium, "#X#", "#X#", " X ", 'X', "stickWood", '#', "ingotThaumium")); + } + +} diff --git a/src/main/java/mr208/WeaponVault/WVConfig.java b/src/main/java/mr208/WeaponVault/WVConfig.java new file mode 100644 index 0000000..4a65fb5 --- /dev/null +++ b/src/main/java/mr208/WeaponVault/WVConfig.java @@ -0,0 +1,79 @@ +package mr208.WeaponVault; + +import com.sun.org.apache.xpath.internal.operations.Bool; +import net.minecraftforge.common.config.Configuration; + +import java.io.File; + +public class WVConfig { + + public static Configuration conf; + //General Alloys and Metals + public static Boolean enableBronze; + public static Boolean enableSteel; + + //Flaxbeard's Steampower + public static Boolean enableFSP; + public static Boolean enableBrass; + public static Boolean enableGildedIron; + //Thaumcraft + public static Boolean enableThaumcraftWeapons; + public static Boolean enableThaumium; + public static Boolean enableVoidMetal; + //Applied Energistics 2 + public static Boolean enableAEWeapons; + public static Boolean enableCertusQuartz; + public static Boolean enableNetherQuartz; + //Botania + public static Boolean enableBotania; + public static Boolean enableManaSteel; + public static Boolean enableTerraSteel; + public static Boolean enableElementium; + + + + public static void init(File configFile) + { + if(conf == null) + { + conf = new Configuration(configFile); + loadConfiguration(); + } + } + + private static void loadConfiguration() + { + + //Generic Metals + conf.setCategoryComment("Generic Metals","These Weapons will only load if there is the ingot form of the Metal in question available in the OreDictionary"); + enableBronze = conf.getBoolean("1. Bronze Weapons","Generic Metals",true,"Enable Bronze Weapons?"); + enableSteel = conf.getBoolean("2. Steel Weapons","Generic Metals",true,"Enable Steel Weapons?"); + + + //Applied Energistics 2 + enableAEWeapons = conf.getBoolean("1. Enable AE2 Weapons","AE2", true,"Enables Certus and Nether Quartz weapons if enabled below"); + enableCertusQuartz = conf.getBoolean("2. Certus Quartz Weapons", "AE2", true,"Enable Certus Quartz Weapons?"); + enableNetherQuartz = conf.getBoolean("3. NetherQuartz Weapons", "AE2", true, "Enable Nether Quartz Weapons?"); + + //Flaxbeard's Steampower + enableFSP = conf.getBoolean("1. Enable FSP Weapons", "FSP", true, "Enables Brass and Gilded Iron Weapons if enabled below"); + enableBrass = conf.getBoolean("2. Brass Weapons","FSP", true,"Enable Brass Weapons?"); + enableGildedIron = conf.getBoolean("3. Gilded Iron Weapons","FSP",true,"Enable Gilded Iron?"); + + + //Thaumcraft! + enableThaumcraftWeapons = conf.getBoolean("1. Enable Thaumcraft Support","Thaumcraft",true,"Enables Thaumium and Void Metal weapons if enabled below. "); + enableThaumium = conf.getBoolean("2. Thaumium Weapons","Thaumcraft",true,"Enable Thaumium Weapons?"); + enableVoidMetal = conf.getBoolean("3. Void Metal Weapons","Thaumcraft",true,"Enable Void Metal Weapons?"); + + //Botania + enableBotania = conf.getBoolean("1. Enable Botania Support","Botania",true,"Enables Manasteel, Terrasteel, and Elementium if enabled below"); + enableManaSteel = conf.getBoolean("2. Manasteel Weapons","Botania",true,"Enable Manasteel Weapons?"); + enableTerraSteel = conf.getBoolean("3. Terrasteel Weapons","Botania",true,"Enable Terrasteel Weapons?"); + enableElementium = conf.getBoolean("4. Elementium Weapons","Botania",true,"Enable Elementium Weapons?"); + + + if (conf.hasChanged()) + {conf.save(); } + } + } diff --git a/src/main/java/mr208/WeaponVault/WVRef.java b/src/main/java/mr208/WeaponVault/WVRef.java new file mode 100644 index 0000000..78fac19 --- /dev/null +++ b/src/main/java/mr208/WeaponVault/WVRef.java @@ -0,0 +1,10 @@ +package mr208.WeaponVault; + +/** + * Created by Andrew on 10/16/2014. + */ +public class WVRef +{ + public final static String MOD_ID = "weaponvault"; + public final static String MOD_NAME="Weapon Vault"; +} diff --git a/src/main/java/mr208/WeaponVault/WeaponVault.java b/src/main/java/mr208/WeaponVault/WeaponVault.java new file mode 100644 index 0000000..c13616f --- /dev/null +++ b/src/main/java/mr208/WeaponVault/WeaponVault.java @@ -0,0 +1,52 @@ +package mr208.WeaponVault; + + +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import mr208.WeaponVault.AE2.AE2Integration; +import mr208.WeaponVault.Botania.BotaniaIntegration; +import mr208.WeaponVault.Items.GenericMetalsIntegration; +import mr208.WeaponVault.Thaumcraft.ThaumcraftIntegration; +import net.minecraft.item.Item; +import net.minecraftforge.common.util.EnumHelper; +import net.minecraftforge.oredict.OreDictionary; + + +@Mod(modid = WVRef.MOD_ID, name= WVRef.MOD_NAME, version="1.0", dependencies = "after:Botania;after:appliedenergistics2;after:Thaumcraft;required-after:weaponmod") +public class WeaponVault { + + @Mod.Instance + public static WeaponVault instance; + + public static Item.ToolMaterial steelMaterial; + public static Item.ToolMaterial bronzeMaterial; + + @Mod.EventHandler + public void preInit(FMLPreInitializationEvent event) + { + + WVConfig.init(event.getSuggestedConfigurationFile()); + + } + + @Mod.EventHandler + public void Init(FMLInitializationEvent event) + { + Materials.initMaterials(); + if(WVConfig.enableBotania && Loader.isModLoaded("Botania")) BotaniaIntegration.initBotania(); + if(WVConfig.enableAEWeapons && Loader.isModLoaded("appliedenergistics2")) AE2Integration.initAE2(); + if(WVConfig.enableThaumcraftWeapons && Loader.isModLoaded("Thaumcraft")) ThaumcraftIntegration.initThaumcraft(); + if(WVConfig.enableSteel && !OreDictionary.getOres("ingotSteel").isEmpty()) + { + steelMaterial = EnumHelper.addToolMaterial("WV_Steel", 2, 500, 7, 3, 10); + GenericMetalsIntegration.initSteel(); + } + if (WVConfig.enableBronze && !OreDictionary.getOres("ingotBronze").isEmpty()) + { + bronzeMaterial = EnumHelper.addToolMaterial("WV_Bronze", 2,375,6,2,12); + GenericMetalsIntegration.initBronze(); + } + } +} diff --git a/src/main/java/thaumcraft/api/IGoggles.java b/src/main/java/thaumcraft/api/IGoggles.java new file mode 100644 index 0000000..2f53d81 --- /dev/null +++ b/src/main/java/thaumcraft/api/IGoggles.java @@ -0,0 +1,22 @@ +package thaumcraft.api; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; + +/** + * + * @author Azanor + * + * Equipped head slot items that extend this class will be able to perform most functions that + * goggles of revealing can apart from view nodes which is handled by IRevealer. + * + */ + +public interface IGoggles { + + /* + * If this method returns true things like block essentia contents will be shown. + */ + public boolean showIngamePopups(ItemStack itemstack, EntityLivingBase player); + +} diff --git a/src/main/java/thaumcraft/api/IRepairable.java b/src/main/java/thaumcraft/api/IRepairable.java new file mode 100644 index 0000000..48c6dff --- /dev/null +++ b/src/main/java/thaumcraft/api/IRepairable.java @@ -0,0 +1,13 @@ +package thaumcraft.api; + + + +/** + * @author Azanor + * Items, armor and tools with this interface can receive the Repair enchantment. + * Repairs 1 point of durability every 10 seconds (2 for repair II) + */ +public interface IRepairable { + + +} diff --git a/src/main/java/thaumcraft/api/IRepairableExtended.java b/src/main/java/thaumcraft/api/IRepairableExtended.java new file mode 100644 index 0000000..3382712 --- /dev/null +++ b/src/main/java/thaumcraft/api/IRepairableExtended.java @@ -0,0 +1,17 @@ +package thaumcraft.api; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + + + +/** + * @author Azanor + * Items, armor and tools with this interface can receive the Repair enchantment. + * Repairs 1 point of durability every 10 seconds (2 for repair II) + */ +public interface IRepairableExtended extends IRepairable { + + public boolean doRepair(ItemStack stack, EntityPlayer player, int enchantlevel); + +} diff --git a/src/main/java/thaumcraft/api/IRunicArmor.java b/src/main/java/thaumcraft/api/IRunicArmor.java new file mode 100644 index 0000000..5dd3110 --- /dev/null +++ b/src/main/java/thaumcraft/api/IRunicArmor.java @@ -0,0 +1,22 @@ +package thaumcraft.api; + +import net.minecraft.item.ItemStack; + +/** + * + * @author Azanor + * + * Armor or bauble slot items that implement this interface can provide runic shielding. + * Recharging, hardening, etc. is handled internally by thaumcraft. + * + */ + +public interface IRunicArmor { + + /** + * returns how much charge this item can provide. This is the base shielding value - any hardening is stored and calculated internally. + */ + public int getRunicCharge(ItemStack itemstack); + + +} diff --git a/src/main/java/thaumcraft/api/IScribeTools.java b/src/main/java/thaumcraft/api/IScribeTools.java new file mode 100644 index 0000000..8800fa5 --- /dev/null +++ b/src/main/java/thaumcraft/api/IScribeTools.java @@ -0,0 +1,14 @@ +package thaumcraft.api; + + +/** + * + * @author Azanor + * + * Interface used to identify scribing tool items used in research table + * + */ + +public interface IScribeTools { + +} diff --git a/src/main/java/thaumcraft/api/IVisDiscountGear.java b/src/main/java/thaumcraft/api/IVisDiscountGear.java new file mode 100644 index 0000000..3793ea3 --- /dev/null +++ b/src/main/java/thaumcraft/api/IVisDiscountGear.java @@ -0,0 +1,20 @@ +package thaumcraft.api; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import thaumcraft.api.aspects.Aspect; + + + + +/** + * @author Azanor + * ItemArmor with this interface will grant a discount to the vis cost of actions the wearer performs with casting wands. + * The amount returned is the percentage by which the cost is discounted. There is a built-int max discount of 50%, but + * individual items really shouldn't have a discount more than 5% + */ +public interface IVisDiscountGear { + + int getVisDiscount(ItemStack stack, EntityPlayer player, Aspect aspect); + +} diff --git a/src/main/java/thaumcraft/api/IWarpingGear.java b/src/main/java/thaumcraft/api/IWarpingGear.java new file mode 100644 index 0000000..e7415ab --- /dev/null +++ b/src/main/java/thaumcraft/api/IWarpingGear.java @@ -0,0 +1,22 @@ +package thaumcraft.api; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +/** + * + * @author Azanor + * + * Armor, held items or bauble slot items that implement this interface add warp when equipped or held. + * + */ + +public interface IWarpingGear { + + /** + * returns how much warp this item adds while worn or held. + */ + public int getWarp(ItemStack itemstack, EntityPlayer player); + + +} diff --git a/src/main/java/thaumcraft/api/ItemApi.java b/src/main/java/thaumcraft/api/ItemApi.java new file mode 100644 index 0000000..25dda28 --- /dev/null +++ b/src/main/java/thaumcraft/api/ItemApi.java @@ -0,0 +1,70 @@ +package thaumcraft.api; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import cpw.mods.fml.common.FMLLog; + +/** + * @author Azanor + * + * This is used to gain access to the items in my mod. + * I only give some examples and it will probably still + * require a bit of work for you to get hold of everything you need. + * + */ +public class ItemApi { + + public static ItemStack getItem(String itemString, int meta) { + ItemStack item = null; + + try { + String itemClass = "thaumcraft.common.config.ConfigItems"; + Object obj = Class.forName(itemClass).getField(itemString).get(null); + if (obj instanceof Item) { + item = new ItemStack((Item) obj,1,meta); + } else if (obj instanceof ItemStack) { + item = (ItemStack) obj; + } + } catch (Exception ex) { + FMLLog.warning("[Thaumcraft] Could not retrieve item identified by: " + itemString); + } + + return item; + } + + public static ItemStack getBlock(String itemString, int meta) { + ItemStack item = null; + + try { + String itemClass = "thaumcraft.common.config.ConfigBlocks"; + Object obj = Class.forName(itemClass).getField(itemString).get(null); + if (obj instanceof Block) { + item = new ItemStack((Block) obj,1,meta); + } else if (obj instanceof ItemStack) { + item = (ItemStack) obj; + } + } catch (Exception ex) { + FMLLog.warning("[Thaumcraft] Could not retrieve block identified by: " + itemString); + } + + return item; + } + + /** + * + * Some examples + * + * Casting Wands: + * itemWandCasting + * + * Resources: + * itemEssence, itemWispEssence, itemResource, itemShard, itemNugget, + * itemNuggetChicken, itemNuggetBeef, itemNuggetPork, itemTripleMeatTreat + * + * Research: + * itemResearchNotes, itemInkwell, itemThaumonomicon + * + */ + +} diff --git a/src/main/java/thaumcraft/api/ItemRunic.java b/src/main/java/thaumcraft/api/ItemRunic.java new file mode 100644 index 0000000..80251f5 --- /dev/null +++ b/src/main/java/thaumcraft/api/ItemRunic.java @@ -0,0 +1,21 @@ +package thaumcraft.api; + +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +public class ItemRunic extends Item implements IRunicArmor { + + int charge; + + public ItemRunic (int charge) + { + super(); + this.charge = charge; + } + + @Override + public int getRunicCharge(ItemStack itemstack) { + return charge; + } + +} diff --git a/src/main/java/thaumcraft/api/ThaumcraftApi.java b/src/main/java/thaumcraft/api/ThaumcraftApi.java new file mode 100644 index 0000000..0d0a672 --- /dev/null +++ b/src/main/java/thaumcraft/api/ThaumcraftApi.java @@ -0,0 +1,537 @@ +package thaumcraft.api; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import net.minecraft.block.Block; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.Item.ToolMaterial; +import net.minecraft.item.ItemArmor.ArmorMaterial; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.EnumHelper; +import net.minecraftforge.oredict.OreDictionary; +import thaumcraft.api.aspects.Aspect; +import thaumcraft.api.aspects.AspectList; +import thaumcraft.api.crafting.CrucibleRecipe; +import thaumcraft.api.crafting.InfusionEnchantmentRecipe; +import thaumcraft.api.crafting.InfusionRecipe; +import thaumcraft.api.crafting.ShapedArcaneRecipe; +import thaumcraft.api.crafting.ShapelessArcaneRecipe; +import thaumcraft.api.research.IScanEventHandler; +import thaumcraft.api.research.ResearchCategories; +import thaumcraft.api.research.ResearchCategoryList; +import thaumcraft.api.research.ResearchItem; +import thaumcraft.api.research.ResearchPage; + + +/** + * @author Azanor + * + * + * IMPORTANT: If you are adding your own aspects to items it is a good idea to do it AFTER Thaumcraft adds its aspects, otherwise odd things may happen. + * + */ +public class ThaumcraftApi { + + //Materials + public static ToolMaterial toolMatThaumium = EnumHelper.addToolMaterial("THAUMIUM", 3, 400, 7F, 2, 22); + public static ToolMaterial toolMatVoid = EnumHelper.addToolMaterial("VOID", 4, 150, 8F, 3, 10); + public static ToolMaterial toolMatElemental = EnumHelper.addToolMaterial("THAUMIUM_ELEMENTAL", 3, 1500, 10F, 3, 18); + public static ArmorMaterial armorMatThaumium = EnumHelper.addArmorMaterial("THAUMIUM", 25, new int[] { 2, 6, 5, 2 }, 25); + public static ArmorMaterial armorMatSpecial = EnumHelper.addArmorMaterial("SPECIAL", 25, new int[] { 1, 3, 2, 1 }, 25); + public static ArmorMaterial armorMatThaumiumFortress = EnumHelper.addArmorMaterial("FORTRESS", 40, new int[] { 3, 7, 6, 3 }, 25); + public static ArmorMaterial armorMatVoid = EnumHelper.addArmorMaterial("VOID", 10, new int[] { 3, 7, 6, 3 }, 10); + public static ArmorMaterial armorMatVoidFortress = EnumHelper.addArmorMaterial("VOIDFORTRESS", 18, new int[] { 4, 8, 7, 4 }, 10); + + //Enchantment references + public static int enchantFrugal; + public static int enchantPotency; + public static int enchantWandFortune; + public static int enchantHaste; + public static int enchantRepair; + + //Miscellaneous + /** + * Portable Hole Block-id Blacklist. + * Simply add the block-id's of blocks you don't want the portable hole to go through. + */ + public static ArrayList portableHoleBlackList = new ArrayList(); + + + //RESEARCH///////////////////////////////////////// + public static ArrayList scanEventhandlers = new ArrayList(); + public static ArrayList scanEntities = new ArrayList(); + public static class EntityTagsNBT { + public EntityTagsNBT(String name, Object value) { + this.name = name; + this.value = value; + } + public String name; + public Object value; + } + public static class EntityTags { + public EntityTags(String entityName, AspectList aspects, EntityTagsNBT... nbts) { + this.entityName = entityName; + this.nbts = nbts; + this.aspects = aspects; + } + public String entityName; + public EntityTagsNBT[] nbts; + public AspectList aspects; + } + + /** + * not really working atm, so ignore it for now + * @param scanEventHandler + */ + public static void registerScanEventhandler(IScanEventHandler scanEventHandler) { + scanEventhandlers.add(scanEventHandler); + } + + /** + * This is used to add aspects to entities which you can then scan using a thaumometer. + * Also used to calculate vis drops from mobs. + * @param entityName + * @param aspects + * @param nbt you can specify certain nbt keys and their values + * to differentiate between mobs.
For example the normal and wither skeleton: + *
ThaumcraftApi.registerEntityTag("Skeleton", (new AspectList()).add(Aspect.DEATH, 5)); + *
ThaumcraftApi.registerEntityTag("Skeleton", (new AspectList()).add(Aspect.DEATH, 8), new NBTTagByte("SkeletonType",(byte) 1)); + */ + public static void registerEntityTag(String entityName, AspectList aspects, EntityTagsNBT... nbt ) { + scanEntities.add(new EntityTags(entityName,aspects,nbt)); + } + + //RECIPES///////////////////////////////////////// + private static ArrayList craftingRecipes = new ArrayList(); + private static HashMap smeltingBonus = new HashMap(); + + /** + * This method is used to determine what bonus items are generated when the infernal furnace smelts items + * @param in The input of the smelting operation. e.g. new ItemStack(Block.oreGold) + * @param out The bonus item that can be produced from the smelting operation e.g. new ItemStack(nuggetGold,0,0). + * Stacksize should be 0 unless you want to guarantee that at least 1 item is always produced. + */ + public static void addSmeltingBonus(ItemStack in, ItemStack out) { + smeltingBonus.put( + Arrays.asList(in.getItem(),in.getItemDamage()), + new ItemStack(out.getItem(),0,out.getItemDamage())); + } + + /** + * This method is used to determine what bonus items are generated when the infernal furnace smelts items + * @param in The ore dictionary input of the smelting operation. e.g. "oreGold" + * @param out The bonus item that can be produced from the smelting operation e.g. new ItemStack(nuggetGold,0,0). + * Stacksize should be 0 unless you want to guarantee that at least 1 item is always produced. + */ + public static void addSmeltingBonus(String in, ItemStack out) { + smeltingBonus.put( in, new ItemStack(out.getItem(),0,out.getItemDamage())); + } + + /** + * Returns the bonus item produced from a smelting operation in the infernal furnace + * @param in The input of the smelting operation. e.g. new ItemStack(oreGold) + * @return the The bonus item that can be produced + */ + public static ItemStack getSmeltingBonus(ItemStack in) { + ItemStack out = smeltingBonus.get(Arrays.asList(in.getItem(),in.getItemDamage())); + if (out==null) { + out = smeltingBonus.get(Arrays.asList(in.getItem(),OreDictionary.WILDCARD_VALUE)); + } + if (out==null) { + String od = OreDictionary.getOreName( OreDictionary.getOreID(in)); + out = smeltingBonus.get(od); + } + return out; + } + + public static List getCraftingRecipes() { + return craftingRecipes; + } + + /** + * @param research the research key required for this recipe to work. Leave blank if it will work without research + * @param result the recipe output + * @param aspects the vis cost per aspect. + * @param recipe The recipe. Format is exactly the same as vanilla recipes. Input itemstacks are NBT sensitive. + */ + public static ShapedArcaneRecipe addArcaneCraftingRecipe(String research, ItemStack result, AspectList aspects, Object ... recipe) + { + ShapedArcaneRecipe r= new ShapedArcaneRecipe(research, result, aspects, recipe); + craftingRecipes.add(r); + return r; + } + + /** + * @param research the research key required for this recipe to work. Leave blank if it will work without research + * @param result the recipe output + * @param aspects the vis cost per aspect + * @param recipe The recipe. Format is exactly the same as vanilla shapeless recipes. Input itemstacks are NBT sensitive. + */ + public static ShapelessArcaneRecipe addShapelessArcaneCraftingRecipe(String research, ItemStack result, AspectList aspects, Object ... recipe) + { + ShapelessArcaneRecipe r = new ShapelessArcaneRecipe(research, result, aspects, recipe); + craftingRecipes.add(r); + return r; + } + + /** + * @param research the research key required for this recipe to work. Leave blank if it will work without research + * @param result the recipe output. It can either be an itemstack or an nbt compound tag that will be added to the central item + * @param instability a number that represents the N in 1000 chance for the infusion altar to spawn an + * instability effect each second while the crafting is in progress + * @param aspects the essentia cost per aspect. + * @param aspects input the central item to be infused + * @param recipe An array of items required to craft this. Input itemstacks are NBT sensitive. + * Infusion crafting components are automatically "fuzzy" and the oredict will be checked for possible matches. + * + */ + public static InfusionRecipe addInfusionCraftingRecipe(String research, Object result, int instability, AspectList aspects, ItemStack input,ItemStack[] recipe) + { + if (!(result instanceof ItemStack || result instanceof Object[])) return null; + InfusionRecipe r= new InfusionRecipe(research, result, instability, aspects, input, recipe); + craftingRecipes.add(r); + return r; + } + + /** + * @param research the research key required for this recipe to work. Leave blank if it will work without research + * @param enchantment the enchantment that will be applied to the item + * @param instability a number that represents the N in 1000 chance for the infusion altar to spawn an + * instability effect each second while the crafting is in progress + * @param aspects the essentia cost per aspect. + * @param recipe An array of items required to craft this. Input itemstacks are NBT sensitive. + * Infusion crafting components are automatically "fuzzy" and the oredict will be checked for possible matches. + * + */ + public static InfusionEnchantmentRecipe addInfusionEnchantmentRecipe(String research, Enchantment enchantment, int instability, AspectList aspects, ItemStack[] recipe) + { + InfusionEnchantmentRecipe r= new InfusionEnchantmentRecipe(research, enchantment, instability, aspects, recipe); + craftingRecipes.add(r); + return r; + } + + /** + * @param stack the recipe result + * @return the recipe + */ + public static InfusionRecipe getInfusionRecipe(ItemStack res) { + for (Object r:getCraftingRecipes()) { + if (r instanceof InfusionRecipe) { + if (((InfusionRecipe)r).getRecipeOutput() instanceof ItemStack) { + if (((ItemStack) ((InfusionRecipe)r).getRecipeOutput()).isItemEqual(res)) + return (InfusionRecipe)r; + } + } + } + return null; + } + + + /** + * @param key the research key required for this recipe to work. + * @param result the output result + * @param catalyst an itemstack of the catalyst or a string if it is an ore dictionary item + * @param cost the vis cost + * @param tags the aspects required to craft this + */ + public static CrucibleRecipe addCrucibleRecipe(String key, ItemStack result, Object catalyst, AspectList tags) { + CrucibleRecipe rc = new CrucibleRecipe(key, result, catalyst, tags); + getCraftingRecipes().add(rc); + return rc; + } + + + /** + * @param stack the recipe result + * @return the recipe + */ + public static CrucibleRecipe getCrucibleRecipe(ItemStack stack) { + for (Object r:getCraftingRecipes()) { + if (r instanceof CrucibleRecipe) { + if (((CrucibleRecipe)r).getRecipeOutput().isItemEqual(stack)) + return (CrucibleRecipe)r; + } + } + return null; + } + + /** + * @param hash the unique recipe code + * @return the recipe + */ + public static CrucibleRecipe getCrucibleRecipeFromHash(int hash) { + for (Object r:getCraftingRecipes()) { + if (r instanceof CrucibleRecipe) { + if (((CrucibleRecipe)r).hash==hash) + return (CrucibleRecipe)r; + } + } + return null; + } + + /** + * Used by the thaumonomicon drilldown feature. + * @param stack the item + * @return the thaumcraft recipe key that produces that item. + */ + private static HashMap keyCache = new HashMap(); + + public static Object[] getCraftingRecipeKey(EntityPlayer player, ItemStack stack) { + int[] key = new int[] {Item.getIdFromItem(stack.getItem()),stack.getItemDamage()}; + if (keyCache.containsKey(key)) { + if (keyCache.get(key)==null) return null; + if (ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), (String)(keyCache.get(key))[0])) + return keyCache.get(key); + else + return null; + } + for (ResearchCategoryList rcl:ResearchCategories.researchCategories.values()) { + for (ResearchItem ri:rcl.research.values()) { + if (ri.getPages()==null) continue; + for (int a=0;a objectTags = new ConcurrentHashMap(); + + /** + * Checks to see if the passed item/block already has aspects associated with it. + * @param id + * @param meta + * @return + */ + public static boolean exists(Item item, int meta) { + AspectList tmp = ThaumcraftApi.objectTags.get(Arrays.asList(item,meta)); + if (tmp==null) { + tmp = ThaumcraftApi.objectTags.get(Arrays.asList(item,OreDictionary.WILDCARD_VALUE)); + if (meta==OreDictionary.WILDCARD_VALUE && tmp==null) { + int index=0; + do { + tmp = ThaumcraftApi.objectTags.get(Arrays.asList(item,index)); + index++; + } while (index<16 && tmp==null); + } + if (tmp==null) return false; + } + + return true; + } + + /** + * Used to assign apsects to the given item/block. Here is an example of the declaration for cobblestone:

+ * ThaumcraftApi.registerObjectTag(new ItemStack(Blocks.cobblestone), (new AspectList()).add(Aspect.ENTROPY, 1).add(Aspect.EARTH, 1)); + * @param item the item passed. Pass OreDictionary.WILDCARD_VALUE if all damage values of this item/block should have the same aspects + * @param aspects A ObjectTags object of the associated aspects + */ + public static void registerObjectTag(ItemStack item, AspectList aspects) { + if (aspects==null) aspects=new AspectList(); + try { + objectTags.put(Arrays.asList(item.getItem(),item.getItemDamage()), aspects); + } catch (Exception e) {} + } + + + /** + * Used to assign apsects to the given item/block. Here is an example of the declaration for cobblestone:

+ * ThaumcraftApi.registerObjectTag(new ItemStack(Blocks.cobblestone), new int[]{0,1}, (new AspectList()).add(Aspect.ENTROPY, 1).add(Aspect.EARTH, 1)); + * @param item + * @param meta A range of meta values if you wish to lump several item meta's together as being the "same" item (i.e. stair orientations) + * @param aspects A ObjectTags object of the associated aspects + */ + public static void registerObjectTag(ItemStack item, int[] meta, AspectList aspects) { + if (aspects==null) aspects=new AspectList(); + try { + objectTags.put(Arrays.asList(item.getItem(),meta), aspects); + } catch (Exception e) {} + } + + /** + * Used to assign apsects to the given ore dictionary item. + * @param oreDict the ore dictionary name + * @param aspects A ObjectTags object of the associated aspects + */ + public static void registerObjectTag(String oreDict, AspectList aspects) { + if (aspects==null) aspects=new AspectList(); + ArrayList ores = OreDictionary.getOres(oreDict); + if (ores!=null && ores.size()>0) { + for (ItemStack ore:ores) { + try { + objectTags.put(Arrays.asList(ore.getItem(), ore.getItemDamage()), aspects); + } catch (Exception e) {} + } + } + } + + /** + * Used to assign aspects to the given item/block. + * Attempts to automatically generate aspect tags by checking registered recipes. + * Here is an example of the declaration for pistons:

+ * ThaumcraftApi.registerComplexObjectTag(new ItemStack(Blocks.cobblestone), (new AspectList()).add(Aspect.MECHANISM, 2).add(Aspect.MOTION, 4)); + * IMPORTANT - this should only be used if you are not happy with the default aspects the object would be assigned. + * @param item, pass OreDictionary.WILDCARD_VALUE to meta if all damage values of this item/block should have the same aspects + * @param aspects A ObjectTags object of the associated aspects + */ + public static void registerComplexObjectTag(ItemStack item, AspectList aspects ) { + if (!exists(item.getItem(),item.getItemDamage())) { + AspectList tmp = ThaumcraftApiHelper.generateTags(item.getItem(), item.getItemDamage()); + if (tmp != null && tmp.size()>0) { + for(Aspect tag:tmp.getAspects()) { + aspects.add(tag, tmp.getAmount(tag)); + } + } + registerObjectTag(item,aspects); + } else { + AspectList tmp = ThaumcraftApiHelper.getObjectAspects(item); + for(Aspect tag:aspects.getAspects()) { + tmp.merge(tag, tmp.getAmount(tag)); + } + registerObjectTag(item,tmp); + } + } + + //WARP /////////////////////////////////////////////////////////////////////////////////////// + private static HashMap warpMap = new HashMap(); + + /** + * This method is used to determine how much warp is gained if the item is crafted. The warp + * added is "sticky" warp + * @param craftresult The item crafted + * @param amount how much warp is gained + */ + public static void addWarpToItem(ItemStack craftresult, int amount) { + warpMap.put(Arrays.asList(craftresult.getItem(),craftresult.getItemDamage()),amount); + } + + /** + * This method is used to determine how much permanent warp is gained if the research is completed + * @param in The item crafted + * @param amount how much warp is gained + */ + public static void addWarpToResearch(String research, int amount) { + warpMap.put(research, amount); + } + + /** + * Returns how much warp is gained from the item or research passed in + * @param in itemstack or string + * @return how much warp it will give + */ + public static int getWarp(Object in) { + if (in==null) return 0; + if (in instanceof ItemStack && warpMap.containsKey(Arrays.asList(((ItemStack)in).getItem(),((ItemStack)in).getItemDamage()))) { + return warpMap.get(Arrays.asList(((ItemStack)in).getItem(),((ItemStack)in).getItemDamage())); + } else + if (in instanceof String && warpMap.containsKey((String)in)) { + return warpMap.get((String)in); + } + return 0; + } + + //CROPS ////////////////////////////////////////////////////////////////////////////////////////// + + /** + * To define mod crops you need to use FMLInterModComms in your @Mod.Init method. + * There are two 'types' of crops you can add. Standard crops and clickable crops. + * + * Standard crops work like normal vanilla crops - they grow until a certain metadata + * value is reached and you harvest them by destroying the block and collecting the blocks. + * You need to create and ItemStack that tells the golem what block id and metadata represents + * the crop when fully grown. Sending a metadata of [OreDictionary.WILDCARD_VALUE] will mean the metadata won't get + * checked. + * Example for vanilla wheat: + * FMLInterModComms.sendMessage("Thaumcraft", "harvestStandardCrop", new ItemStack(Block.crops,1,7)); + * + * Clickable crops are crops that you right click to gather their bounty instead of destroying them. + * As for standard crops, you need to create and ItemStack that tells the golem what block id + * and metadata represents the crop when fully grown. The golem will trigger the blocks onBlockActivated method. + * Sending a metadata of [OreDictionary.WILDCARD_VALUE] will mean the metadata won't get checked. + * Example (this will technically do nothing since clicking wheat does nothing, but you get the idea): + * FMLInterModComms.sendMessage("Thaumcraft", "harvestClickableCrop", new ItemStack(Block.crops,1,7)); + * + * Stacked crops (like reeds) are crops that you wish the bottom block should remain after harvesting. + * As for standard crops, you need to create and ItemStack that tells the golem what block id + * and metadata represents the crop when fully grown. Sending a metadata of [OreDictionary.WILDCARD_VALUE] will mean the actualy md won't get + * checked. If it has the order upgrade it will only harvest if the crop is more than one block high. + * Example: + * FMLInterModComms.sendMessage("Thaumcraft", "harvestStackedCrop", new ItemStack(Block.reed,1,7)); + */ + + //NATIVE CLUSTERS ////////////////////////////////////////////////////////////////////////////////// + + /** + * You can define certain ores that will have a chance to produce native clusters via FMLInterModComms + * in your @Mod.Init method using the "nativeCluster" string message. + * The format should be: + * "[ore item/block id],[ore item/block metadata],[cluster item/block id],[cluster item/block metadata],[chance modifier float]" + * + * NOTE: The chance modifier is a multiplier applied to the default chance for that cluster to be produced (default 27.5% for a pickaxe of the core) + * + * Example for vanilla iron ore to produce one of my own native iron clusters (assuming default id's) at double the default chance: + * FMLInterModComms.sendMessage("Thaumcraft", "nativeCluster","15,0,25016,16,2.0"); + */ + + //LAMP OF GROWTH BLACKLIST /////////////////////////////////////////////////////////////////////////// + /** + * You can blacklist crops that should not be effected by the Lamp of Growth via FMLInterModComms + * in your @Mod.Init method using the "lampBlacklist" itemstack message. + * Sending a metadata of [OreDictionary.WILDCARD_VALUE] will mean the metadata won't get checked. + * Example for vanilla wheat: + * FMLInterModComms.sendMessage("Thaumcraft", "lampBlacklist", new ItemStack(Block.crops,1,OreDictionary.WILDCARD_VALUE)); + */ + + //DIMENSION BLACKLIST /////////////////////////////////////////////////////////////////////////// + /** + * You can blacklist a dimension to not spawn certain thaumcraft features + * in your @Mod.Init method using the "dimensionBlacklist" string message in the format "[dimension]:[level]" + * The level values are as follows: + * [0] stop all tc spawning and generation + * [1] allow ore and node generation + * [2] allow mob spawning + * [3] allow ore and node gen + mob spawning + * Example: + * FMLInterModComms.sendMessage("Thaumcraft", "dimensionBlacklist", "15:1"); + */ + + //BIOME BLACKLIST /////////////////////////////////////////////////////////////////////////// + /** + * You can blacklist a biome to not spawn certain thaumcraft features + * in your @Mod.Init method using the "biomeBlacklist" string message in the format "[biome id]:[level]" + * The level values are as follows: + * [0] stop all tc spawning and generation + * [1] allow ore and node generation + * [2] allow mob spawning + * [3] allow ore and node gen + mob spawning + * Example: + * FMLInterModComms.sendMessage("Thaumcraft", "biomeBlacklist", "180:2"); + */ +} diff --git a/src/main/java/thaumcraft/api/ThaumcraftApiHelper.java b/src/main/java/thaumcraft/api/ThaumcraftApiHelper.java new file mode 100644 index 0000000..8487a20 --- /dev/null +++ b/src/main/java/thaumcraft/api/ThaumcraftApiHelper.java @@ -0,0 +1,336 @@ +package thaumcraft.api; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Iterator; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.oredict.OreDictionary; +import thaumcraft.api.aspects.Aspect; +import thaumcraft.api.aspects.AspectList; +import thaumcraft.api.aspects.IEssentiaTransport; +import cpw.mods.fml.common.FMLLog; + +public class ThaumcraftApiHelper { + + public static AspectList cullTags(AspectList temp) { + AspectList temp2 = new AspectList(); + for (Aspect tag:temp.getAspects()) { + if (tag!=null) + temp2.add(tag, temp.getAmount(tag)); + } + while (temp2!=null && temp2.size()>10) { + Aspect lowest = null; + int low = Integer.MAX_VALUE; + for (Aspect tag:temp2.getAspects()) { + if (tag==null) continue; + if (temp2.getAmount(tag) allAspects= new HashMap(); + private static HashMap allCompoundAspects= new HashMap(); + + public static AspectList getAllAspects(int amount) { + if (allAspects.get(amount)==null) { + AspectList al = new AspectList(); + for (Aspect aspect:Aspect.aspects.values()) { + al.add(aspect, amount); + } + allAspects.put(amount, al); + } + return allAspects.get(amount); + } + + public static AspectList getAllCompoundAspects(int amount) { + if (allCompoundAspects.get(amount)==null) { + AspectList al = new AspectList(); + for (Aspect aspect:Aspect.getCompoundAspects()) { + al.add(aspect, amount); + } + allCompoundAspects.put(amount, al); + } + return allCompoundAspects.get(amount); + } + + static Method consumeVisFromWand; + /** + * Use to subtract vis from a wand for most operations + * Wands store vis differently so "real" vis costs need to be multiplied by 100 before calling this method + * @param wand the wand itemstack + * @param player the player using the wand + * @param cost the cost of the operation. + * @param doit actually subtract the vis from the wand if true - if false just simulate the result + * @param crafting is this a crafting operation or not - if + * false then things like frugal and potency will apply to the costs + * @return was the vis successfully subtracted + */ + public static boolean consumeVisFromWand(ItemStack wand, EntityPlayer player, + AspectList cost, boolean doit, boolean crafting) { + boolean ot = false; + try { + if(consumeVisFromWand == null) { + Class fake = Class.forName("thaumcraft.common.items.wands.ItemWandCasting"); + consumeVisFromWand = fake.getMethod("consumeAllVis", + ItemStack.class, EntityPlayer.class, AspectList.class, boolean.class, boolean.class); + } + ot = (Boolean) consumeVisFromWand.invoke( + consumeVisFromWand.getDeclaringClass().cast(wand.getItem()), wand, player, cost, doit, crafting); + } catch(Exception ex) { + FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.items.wands.ItemWandCasting method consumeAllVis"); + } + return ot; + } + + static Method consumeVisFromWandCrafting; + /** + * Subtract vis for use by a crafting mechanic. Costs are calculated slightly + * differently and things like the frugal enchant is ignored + * Must NOT be multiplied by 100 - send the actual vis cost + * @param wand the wand itemstack + * @param player the player using the wand + * @param cost the cost of the operation. + * @param doit actually subtract the vis from the wand if true - if false just simulate the result + * @return was the vis successfully subtracted + */ + public static boolean consumeVisFromWandCrafting(ItemStack wand, EntityPlayer player, + AspectList cost, boolean doit) { + boolean ot = false; + try { + if(consumeVisFromWandCrafting == null) { + Class fake = Class.forName("thaumcraft.common.items.wands.ItemWandCasting"); + consumeVisFromWandCrafting = fake.getMethod("consumeAllVisCrafting", + ItemStack.class, EntityPlayer.class, AspectList.class, boolean.class); + } + ot = (Boolean) consumeVisFromWandCrafting.invoke( + consumeVisFromWandCrafting.getDeclaringClass().cast(wand.getItem()), wand, player, cost, doit); + } catch(Exception ex) { + FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.items.wands.ItemWandCasting method consumeAllVisCrafting"); + } + return ot; + } + + static Method consumeVisFromInventory; + /** + * Subtract vis from a wand the player is carrying. Works like consumeVisFromWand in that actual vis + * costs should be multiplied by 100. The costs are handled like crafting however and things like + * frugal don't effect them + * @param player the player using the wand + * @param cost the cost of the operation. + * @return was the vis successfully subtracted + */ + public static boolean consumeVisFromInventory(EntityPlayer player, AspectList cost) { + boolean ot = false; + try { + if(consumeVisFromInventory == null) { + Class fake = Class.forName("thaumcraft.common.items.wands.WandManager"); + consumeVisFromInventory = fake.getMethod("consumeVisFromInventory", + EntityPlayer.class, AspectList.class); + } + ot = (Boolean) consumeVisFromInventory.invoke(null, player, cost); + } catch(Exception ex) { + FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.items.wands.WandManager method consumeVisFromInventory"); + } + return ot; + } + + + static Method addWarpToPlayer; + /** + * This adds permanents or temporary warp to a player. It will automatically be synced clientside + * @param player the player using the wand + * @param amount how much warp to add. Negative amounts are only valid for temporary warp + * @param temporary add temporary warp instead of permanent + */ + public static void addWarpToPlayer(EntityPlayer player, int amount, boolean temporary) { + boolean ot = false; + try { + if(addWarpToPlayer == null) { + Class fake = Class.forName("thaumcraft.common.Thaumcraft"); + addWarpToPlayer = fake.getMethod("addWarpToPlayer", + EntityPlayer.class, int.class, boolean.class); + } + addWarpToPlayer.invoke(null, player, amount, temporary); + } catch(Exception ex) { + FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.Thaumcraft method addWarpToPlayer"); + } + } + + static Method addStickyWarpToPlayer; + /** + * This "sticky" warp to a player. Sticky warp is permanent warp that can be removed. + * It will automatically be synced clientside + * @param player the player using the wand + * @param amount how much warp to add. Can have negative amounts. + */ + public static void addStickyWarpToPlayer(EntityPlayer player, int amount) { + boolean ot = false; + try { + if(addStickyWarpToPlayer == null) { + Class fake = Class.forName("thaumcraft.common.Thaumcraft"); + addStickyWarpToPlayer = fake.getMethod("addStickyWarpToPlayer", + EntityPlayer.class, int.class); + } + addStickyWarpToPlayer.invoke(null, player, amount); + } catch(Exception ex) { + FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.Thaumcraft method addStickyWarpToPlayer"); + } + } +} diff --git a/src/main/java/thaumcraft/api/TileThaumcraft.java b/src/main/java/thaumcraft/api/TileThaumcraft.java new file mode 100644 index 0000000..56ccae8 --- /dev/null +++ b/src/main/java/thaumcraft/api/TileThaumcraft.java @@ -0,0 +1,63 @@ +package thaumcraft.api; + +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; + +/** + * + * @author azanor + * + * Custom tile entity class I use for most of my tile entities. Setup in such a way that only + * the nbt data within readCustomNBT / writeCustomNBT will be sent to the client when the tile + * updates. Apart from all the normal TE data that gets sent that is. + * + */ +public class TileThaumcraft extends TileEntity { + + //NBT stuff + + @Override + public void readFromNBT(NBTTagCompound nbttagcompound) + { + super.readFromNBT(nbttagcompound); + readCustomNBT(nbttagcompound); + } + + public void readCustomNBT(NBTTagCompound nbttagcompound) + { + //TODO + } + + @Override + public void writeToNBT(NBTTagCompound nbttagcompound) + { + super.writeToNBT(nbttagcompound); + writeCustomNBT(nbttagcompound); + } + + public void writeCustomNBT(NBTTagCompound nbttagcompound) + { + //TODO + } + + //Client Packet stuff + @Override + public Packet getDescriptionPacket() { + NBTTagCompound nbttagcompound = new NBTTagCompound(); + this.writeCustomNBT(nbttagcompound); + return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, -999, nbttagcompound); + } + + @Override + public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt) { + super.onDataPacket(net, pkt); + this.readCustomNBT(pkt.func_148857_g()); + } + + + + +} diff --git a/src/main/java/thaumcraft/api/WorldCoordinates.java b/src/main/java/thaumcraft/api/WorldCoordinates.java new file mode 100644 index 0000000..6c620af --- /dev/null +++ b/src/main/java/thaumcraft/api/WorldCoordinates.java @@ -0,0 +1,117 @@ +package thaumcraft.api; + +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; + +public class WorldCoordinates implements Comparable +{ + public int x; + + /** the y coordinate */ + public int y; + + /** the z coordinate */ + public int z; + + public int dim; + + public WorldCoordinates() {} + + public WorldCoordinates(int par1, int par2, int par3, int d) + { + this.x = par1; + this.y = par2; + this.z = par3; + this.dim = d; + } + + public WorldCoordinates(TileEntity tile) + { + this.x = tile.xCoord; + this.y = tile.yCoord; + this.z = tile.zCoord; + this.dim = tile.getWorldObj().provider.dimensionId; + } + + public WorldCoordinates(WorldCoordinates par1ChunkCoordinates) + { + this.x = par1ChunkCoordinates.x; + this.y = par1ChunkCoordinates.y; + this.z = par1ChunkCoordinates.z; + this.dim = par1ChunkCoordinates.dim; + } + + public boolean equals(Object par1Obj) + { + if (!(par1Obj instanceof WorldCoordinates)) + { + return false; + } + else + { + WorldCoordinates coordinates = (WorldCoordinates)par1Obj; + return this.x == coordinates.x && this.y == coordinates.y && this.z == coordinates.z && this.dim == coordinates.dim ; + } + } + + public int hashCode() + { + return this.x + this.y << 8 + this.z << 16 + this.dim << 24; + } + + /** + * Compare the coordinate with another coordinate + */ + public int compareWorldCoordinate(WorldCoordinates par1) + { + return this.dim == par1.dim ? ( + this.y == par1.y ? (this.z == par1.z ? this.x - par1.x : this.z - par1.z) : this.y - par1.y) : -1; + } + + public void set(int par1, int par2, int par3, int d) + { + this.x = par1; + this.y = par2; + this.z = par3; + this.dim = d; + } + + /** + * Returns the squared distance between this coordinates and the coordinates given as argument. + */ + public float getDistanceSquared(int par1, int par2, int par3) + { + float f = (float)(this.x - par1); + float f1 = (float)(this.y - par2); + float f2 = (float)(this.z - par3); + return f * f + f1 * f1 + f2 * f2; + } + + /** + * Return the squared distance between this coordinates and the ChunkCoordinates given as argument. + */ + public float getDistanceSquaredToWorldCoordinates(WorldCoordinates par1ChunkCoordinates) + { + return this.getDistanceSquared(par1ChunkCoordinates.x, par1ChunkCoordinates.y, par1ChunkCoordinates.z); + } + + public int compareTo(Object par1Obj) + { + return this.compareWorldCoordinate((WorldCoordinates)par1Obj); + } + + public void readNBT(NBTTagCompound nbt) { + this.x = nbt.getInteger("w_x"); + this.y = nbt.getInteger("w_y"); + this.z = nbt.getInteger("w_z"); + this.dim = nbt.getInteger("w_d"); + } + + public void writeNBT(NBTTagCompound nbt) { + nbt.setInteger("w_x",x); + nbt.setInteger("w_y",y); + nbt.setInteger("w_z",z); + nbt.setInteger("w_d",dim); + } + +} diff --git a/src/main/java/thaumcraft/api/aspects/Aspect.java b/src/main/java/thaumcraft/api/aspects/Aspect.java new file mode 100644 index 0000000..3c33a4a --- /dev/null +++ b/src/main/java/thaumcraft/api/aspects/Aspect.java @@ -0,0 +1,201 @@ +package thaumcraft.api.aspects; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; + +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; + +import org.apache.commons.lang3.text.WordUtils; + +public class Aspect { + + String tag; + Aspect[] components; + int color; + private String chatcolor; + ResourceLocation image; + int blend; + + /** + * Use this constructor to register your own aspects. + * @param tag the key that will be used to reference this aspect, as well as its latin display name + * @param color color to display the tag in + * @param components the aspects this one is formed from + * @param image ResourceLocation pointing to a 32x32 icon of the aspect + * @param blend GL11 blendmode (1 or 771). Used for rendering nodes. Default is 1 + */ + public Aspect(String tag, int color, Aspect[] components, ResourceLocation image, int blend) { + if (aspects.containsKey(tag)) throw new IllegalArgumentException(tag+" already registered!"); + this.tag = tag; + this.components = components; + this.color = color; + this.image = image; + this.blend = blend; + aspects.put(tag, this); + } + + /** + * Shortcut constructor I use for the default aspects - you shouldn't be using this. + */ + public Aspect(String tag, int color, Aspect[] components) { + this(tag,color,components,new ResourceLocation("thaumcraft","textures/aspects/"+tag.toLowerCase()+".png"),1); + } + + /** + * Shortcut constructor I use for the default aspects - you shouldn't be using this. + */ + public Aspect(String tag, int color, Aspect[] components, int blend) { + this(tag,color,components,new ResourceLocation("thaumcraft","textures/aspects/"+tag.toLowerCase()+".png"),blend); + } + + /** + * Shortcut constructor I use for the primal aspects - + * you shouldn't use this as making your own primal aspects will break all the things. + */ + public Aspect(String tag, int color, String chatcolor, int blend) { + this(tag,color,(Aspect[])null, blend); + this.setChatcolor(chatcolor); + } + + public int getColor() { + return color; + } + + public String getName() { + return WordUtils.capitalizeFully(tag); + } + + public String getLocalizedDescription() { + return StatCollector.translateToLocal("tc.aspect."+tag); + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public Aspect[] getComponents() { + return components; + } + + public void setComponents(Aspect[] components) { + this.components = components; + } + + public ResourceLocation getImage() { + return image; + } + + public static Aspect getAspect(String tag) { + return aspects.get(tag); + } + + public int getBlend() { + return blend; + } + + public void setBlend(int blend) { + this.blend = blend; + } + + public boolean isPrimal() { + return getComponents()==null || getComponents().length!=2; + } + + /////////////////////////////// + public static ArrayList getPrimalAspects() { + ArrayList primals = new ArrayList(); + Collection pa = aspects.values(); + for (Aspect aspect:pa) { + if (aspect.isPrimal()) primals.add(aspect); + } + return primals; + } + + public static ArrayList getCompoundAspects() { + ArrayList compounds = new ArrayList(); + Collection pa = aspects.values(); + for (Aspect aspect:pa) { + if (!aspect.isPrimal()) compounds.add(aspect); + } + return compounds; + } + + public String getChatcolor() { + return chatcolor; + } + + public void setChatcolor(String chatcolor) { + this.chatcolor = chatcolor; + } + + + /////////////////////////////// + public static LinkedHashMap aspects = new LinkedHashMap(); + + //PRIMAL + public static final Aspect AIR = new Aspect("aer",0xffff7e,"e",1); + public static final Aspect EARTH = new Aspect("terra",0x56c000,"2",1); + public static final Aspect FIRE = new Aspect("ignis",0xff5a01,"c",1); + public static final Aspect WATER = new Aspect("aqua",0x3cd4fc,"3",1); + public static final Aspect ORDER = new Aspect("ordo",0xd5d4ec,"7",1); + public static final Aspect ENTROPY = new Aspect("perditio",0x404040,"8",771); + + //SECONDARY + public static final Aspect VOID = new Aspect("vacuos",0x888888, new Aspect[] {AIR, ENTROPY},771); + public static final Aspect LIGHT = new Aspect("lux",0xfff663, new Aspect[] {AIR, FIRE}); + public static final Aspect WEATHER = new Aspect("tempestas",0xFFFFFF, new Aspect[] {AIR, WATER}); + public static final Aspect MOTION = new Aspect("motus",0xcdccf4, new Aspect[] {AIR, ORDER}); + public static final Aspect COLD = new Aspect("gelum",0xe1ffff, new Aspect[] {FIRE, ENTROPY}); + public static final Aspect CRYSTAL = new Aspect("vitreus",0x80ffff, new Aspect[] {EARTH, ORDER}); + public static final Aspect LIFE = new Aspect("victus",0xde0005, new Aspect[] {WATER, EARTH}); + public static final Aspect POISON = new Aspect("venenum",0x89f000, new Aspect[] {WATER, ENTROPY}); + public static final Aspect ENERGY = new Aspect("potentia",0xc0ffff, new Aspect[] {ORDER, FIRE}); + public static final Aspect EXCHANGE = new Aspect("permutatio",0x578357, new Aspect[] {ENTROPY, ORDER}); +// public static final Aspect ?? = new Aspect("??",0xcdccf4, new Aspect[] {AIR, EARTH}); +// public static final Aspect ?? = new Aspect("??",0xcdccf4, new Aspect[] {FIRE, EARTH}); +// public static final Aspect ?? = new Aspect("??",0xcdccf4, new Aspect[] {FIRE, WATER}); +// public static final Aspect ?? = new Aspect("??",0xcdccf4, new Aspect[] {ORDER, WATER}); +// public static final Aspect ?? = new Aspect("??",0xcdccf4, new Aspect[] {EARTH, ENTROPY}); + + //TERTIARY + public static final Aspect METAL = new Aspect("metallum",0xb5b5cd, new Aspect[] {EARTH, CRYSTAL}); + public static final Aspect DEATH = new Aspect("mortuus",0x887788, new Aspect[] {LIFE, ENTROPY}); + public static final Aspect FLIGHT = new Aspect("volatus",0xe7e7d7, new Aspect[] {AIR, MOTION}); + public static final Aspect DARKNESS = new Aspect("tenebrae",0x222222, new Aspect[] {VOID, LIGHT}); + public static final Aspect SOUL = new Aspect("spiritus",0xebebfb, new Aspect[] {LIFE, DEATH}); + public static final Aspect HEAL = new Aspect("sano",0xff2f34, new Aspect[] {LIFE, ORDER}); + public static final Aspect TRAVEL = new Aspect("iter",0xe0585b, new Aspect[] {MOTION, EARTH}); + public static final Aspect ELDRITCH = new Aspect("alienis",0x805080, new Aspect[] {VOID, DARKNESS}); + public static final Aspect MAGIC = new Aspect("praecantatio",0x9700c0, new Aspect[] {VOID, ENERGY}); + public static final Aspect AURA = new Aspect("auram",0xffc0ff, new Aspect[] {MAGIC, AIR}); + public static final Aspect TAINT = new Aspect("vitium",0x800080, new Aspect[] {MAGIC, ENTROPY}); + public static final Aspect SLIME = new Aspect("limus",0x01f800, new Aspect[] {LIFE, WATER}); + public static final Aspect PLANT = new Aspect("herba",0x01ac00, new Aspect[] {LIFE, EARTH}); + public static final Aspect TREE = new Aspect("arbor",0x876531, new Aspect[] {AIR, PLANT}); + public static final Aspect BEAST = new Aspect("bestia",0x9f6409, new Aspect[] {MOTION, LIFE}); + public static final Aspect FLESH = new Aspect("corpus",0xee478d, new Aspect[] {DEATH, BEAST}); + public static final Aspect UNDEAD = new Aspect("exanimis",0x3a4000, new Aspect[] {MOTION, DEATH}); + public static final Aspect MIND = new Aspect("cognitio",0xffc2b3, new Aspect[] {EARTH, SOUL}); + public static final Aspect SENSES = new Aspect("sensus",0x0fd9ff, new Aspect[] {AIR, SOUL}); + public static final Aspect MAN = new Aspect("humanus",0xffd7c0, new Aspect[] {BEAST, MIND}); + public static final Aspect CROP = new Aspect("messis",0xe1b371, new Aspect[] {PLANT, MAN}); + public static final Aspect MINE = new Aspect("perfodio",0xdcd2d8, new Aspect[] {MAN, EARTH}); + public static final Aspect TOOL = new Aspect("instrumentum",0x4040ee, new Aspect[] {MAN, ORDER}); + public static final Aspect HARVEST = new Aspect("meto",0xeead82, new Aspect[] {CROP, TOOL}); + public static final Aspect WEAPON = new Aspect("telum",0xc05050, new Aspect[] {TOOL, ENTROPY}); + public static final Aspect ARMOR = new Aspect("tutamen",0x00c0c0, new Aspect[] {TOOL, EARTH}); + public static final Aspect HUNGER = new Aspect("fames",0x9a0305, new Aspect[] {LIFE, VOID}); + public static final Aspect GREED = new Aspect("lucrum",0xe6be44, new Aspect[] {MAN, HUNGER}); + public static final Aspect CRAFT = new Aspect("fabrico",0x809d80, new Aspect[] {MAN, TOOL}); + public static final Aspect CLOTH = new Aspect("pannus",0xeaeac2, new Aspect[] {TOOL, BEAST}); + public static final Aspect MECHANISM = new Aspect("machina",0x8080a0, new Aspect[] {MOTION, TOOL}); + public static final Aspect TRAP = new Aspect("vinculum",0x9a8080, new Aspect[] {MOTION, ENTROPY}); + + +} diff --git a/src/main/java/thaumcraft/api/aspects/AspectList.java b/src/main/java/thaumcraft/api/aspects/AspectList.java new file mode 100644 index 0000000..6fcfe98 --- /dev/null +++ b/src/main/java/thaumcraft/api/aspects/AspectList.java @@ -0,0 +1,280 @@ +package thaumcraft.api.aspects; + +import java.io.Serializable; +import java.util.LinkedHashMap; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import thaumcraft.api.ThaumcraftApiHelper; + +public class AspectList implements Serializable { + + public LinkedHashMap aspects = new LinkedHashMap();//aspects associated with this object + + + /** + * this creates a new aspect list with preloaded values based off the aspects of the given item. + * @param the itemstack of the given item + */ + public AspectList(ItemStack stack) { + try { + AspectList temp = ThaumcraftApiHelper.getObjectAspects(stack); + if (temp!=null) + for (Aspect tag:temp.getAspects()) { + add(tag,temp.getAmount(tag)); + } + } catch (Exception e) {} + } + + public AspectList() { + } + + public AspectList copy() { + AspectList out = new AspectList(); + for (Aspect a:this.getAspects()) + out.add(a, this.getAmount(a)); + return out; + } + + /** + * @return the amount of different aspects in this collection + */ + public int size() { + return aspects.size(); + } + + /** + * @return the amount of total vis in this collection + */ + public int visSize() { + int q = 0; + + for (Aspect as:aspects.keySet()) { + q+=this.getAmount(as); + } + + return q; + } + + /** + * @return an array of all the aspects in this collection + */ + public Aspect[] getAspects() { + Aspect[] q = new Aspect[1]; + return aspects.keySet().toArray(q); + } + + /** + * @return an array of all the aspects in this collection + */ + public Aspect[] getPrimalAspects() { + AspectList t = new AspectList(); + for (Aspect as:aspects.keySet()) { + if (as.isPrimal()) { + t.add(as,1); + } + } + Aspect[] q = new Aspect[1]; + return t.aspects.keySet().toArray(q); + } + + /** + * @return an array of all the aspects in this collection sorted by name + */ + public Aspect[] getAspectsSorted() { + try { + Aspect[] out = aspects.keySet().toArray(new Aspect[1]); + boolean change=false; + do { + change=false; + for(int a=0;a0) { + out[a] = e2; + out[a+1] = e1; + change = true; + break; + } + } + } while (change==true); + return out; + } catch (Exception e) { + return this.getAspects(); + } + } + + /** + * @return an array of all the aspects in this collection sorted by amount + */ + public Aspect[] getAspectsSortedAmount() { + try { + Aspect[] out = aspects.keySet().toArray(new Aspect[1]); + boolean change=false; + do { + change=false; + for(int a=0;a0 && e2>0 && e2>e1) { + Aspect ea = out[a]; + Aspect eb = out[a+1]; + out[a] = eb; + out[a+1] = ea; + change = true; + break; + } + } + } while (change==true); + return out; + } catch (Exception e) { + return this.getAspects(); + } + } + + /** + * @param key + * @return the amount associated with the given aspect in this collection + */ + public int getAmount(Aspect key) { + return aspects.get(key)==null?0:aspects.get(key); + } + + /** + * Reduces the amount of an aspect in this collection by the given amount. + * @param key + * @param amount + * @return + */ + public boolean reduce(Aspect key, int amount) { + if (getAmount(key)>=amount) { + int am = getAmount(key)-amount; + aspects.put(key, am); + return true; + } + return false; + } + + /** + * Reduces the amount of an aspect in this collection by the given amount. + * If reduced to 0 or less the aspect will be removed completely. + * @param key + * @param amount + * @return + */ + public AspectList remove(Aspect key, int amount) { + int am = getAmount(key)-amount; + if (am<=0) aspects.remove(key); else + this.aspects.put(key, am); + return this; + } + + /** + * Simply removes the aspect from the list + * @param key + * @param amount + * @return + */ + public AspectList remove(Aspect key) { + aspects.remove(key); + return this; + } + + /** + * Adds this aspect and amount to the collection. + * If the aspect exists then its value will be increased by the given amount. + * @param aspect + * @param amount + * @return + */ + public AspectList add(Aspect aspect, int amount) { + if (this.aspects.containsKey(aspect)) { + int oldamount = this.aspects.get(aspect); + amount+=oldamount; + } + this.aspects.put( aspect, amount ); + return this; + } + + + /** + * Adds this aspect and amount to the collection. + * If the aspect exists then only the highest of the old or new amount will be used. + * @param aspect + * @param amount + * @return + */ + public AspectList merge(Aspect aspect, int amount) { + if (this.aspects.containsKey(aspect)) { + int oldamount = this.aspects.get(aspect); + if (amount0?aspects:null; + } + return null; + } + + @Override + public void setAspects(ItemStack itemstack, AspectList aspects) { + if (!itemstack.hasTagCompound()) itemstack.setTagCompound(new NBTTagCompound()); + aspects.writeToNBT(itemstack.getTagCompound()); + } +*/ \ No newline at end of file diff --git a/src/main/java/thaumcraft/api/aspects/IEssentiaTransport.java b/src/main/java/thaumcraft/api/aspects/IEssentiaTransport.java new file mode 100644 index 0000000..fecbc16 --- /dev/null +++ b/src/main/java/thaumcraft/api/aspects/IEssentiaTransport.java @@ -0,0 +1,100 @@ +package thaumcraft.api.aspects; + +import net.minecraftforge.common.util.ForgeDirection; + + +/** + * @author Azanor + * This interface is used by tiles that use or transport vis. + * Only tiles that implement this interface will be able to connect to vis conduits or other thaumic devices + */ +public interface IEssentiaTransport { + /** + * Is this tile able to connect to other vis users/sources on the specified side? + * @param face + * @return + */ + public boolean isConnectable(ForgeDirection face); + + /** + * Is this side used to input essentia? + * @param face + * @return + */ + boolean canInputFrom(ForgeDirection face); + + /** + * Is this side used to output essentia? + * @param face + * @return + */ + boolean canOutputTo(ForgeDirection face); + + /** + * Sets the amount of suction this block will apply + * @param suction + */ + public void setSuction(Aspect aspect, int amount); + + /** + * Returns the type of suction this block is applying. + * @param loc + * the location from where the suction is being checked + * @return + * a return type of null indicates the suction is untyped and the first thing available will be drawn + */ + public Aspect getSuctionType(ForgeDirection face); + + /** + * Returns the strength of suction this block is applying. + * @param loc + * the location from where the suction is being checked + * @return + */ + public int getSuctionAmount(ForgeDirection face); + + /** + * remove the specified amount of essentia from this transport tile + * @return how much was actually taken + */ + public int takeEssentia(Aspect aspect, int amount, ForgeDirection face); + + /** + * add the specified amount of essentia to this transport tile + * @return how much was actually added + */ + public int addEssentia(Aspect aspect, int amount, ForgeDirection face); + + /** + * What type of essentia this contains + * @param face + * @return + */ + public Aspect getEssentiaType(ForgeDirection face); + + /** + * How much essentia this block contains + * @param face + * @return + */ + public int getEssentiaAmount(ForgeDirection face); + + + + /** + * Essentia will not be drawn from this container unless the suction exceeds this amount. + * @return the amount + */ + public int getMinimumSuction(); + + /** + * Return true if you want the conduit to extend a little further into the block. + * Used by jars and alembics that have smaller than normal hitboxes + * @return + */ + boolean renderExtendedTube(); + + + +} + diff --git a/src/main/java/thaumcraft/api/crafting/CrucibleRecipe.java b/src/main/java/thaumcraft/api/crafting/CrucibleRecipe.java new file mode 100644 index 0000000..595b6e5 --- /dev/null +++ b/src/main/java/thaumcraft/api/crafting/CrucibleRecipe.java @@ -0,0 +1,91 @@ +package thaumcraft.api.crafting; + +import java.util.ArrayList; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; +import thaumcraft.api.ThaumcraftApiHelper; +import thaumcraft.api.aspects.Aspect; +import thaumcraft.api.aspects.AspectList; + +public class CrucibleRecipe { + + private ItemStack recipeOutput; + + public Object catalyst; + public AspectList aspects; + public String key; + + public int hash; + + public CrucibleRecipe(String researchKey, ItemStack result, Object cat, AspectList tags) { + recipeOutput = result; + this.aspects = tags; + this.key = researchKey; + this.catalyst = cat; + if (cat instanceof String) { + this.catalyst = OreDictionary.getOres((String) cat); + } + String hc = researchKey + result.toString(); + for (Aspect tag:tags.getAspects()) { + hc += tag.getTag()+tags.getAmount(tag); + } + if (cat instanceof ItemStack) { + hc += ((ItemStack)cat).toString(); + } else + if (cat instanceof ArrayList && ((ArrayList)catalyst).size()>0) { + for (ItemStack is :(ArrayList)catalyst) { + hc += is.toString(); + } + } + + hash = hc.hashCode(); + } + + + + public boolean matches(AspectList itags, ItemStack cat) { + if (catalyst instanceof ItemStack && + !ThaumcraftApiHelper.itemMatches((ItemStack) catalyst,cat,false)) { + return false; + } else + if (catalyst instanceof ArrayList && ((ArrayList)catalyst).size()>0) { + ItemStack[] ores = ((ArrayList)catalyst).toArray(new ItemStack[]{}); + if (!ThaumcraftApiHelper.containsMatch(false, new ItemStack[]{cat},ores)) return false; + } + if (itags==null) return false; + for (Aspect tag:aspects.getAspects()) { + if (itags.getAmount(tag))catalyst).size()>0) { + ItemStack[] ores = ((ArrayList)catalyst).toArray(new ItemStack[]{}); + if (ThaumcraftApiHelper.containsMatch(false, new ItemStack[]{cat},ores)) return true; + } + return false; + } + + public AspectList removeMatching(AspectList itags) { + AspectList temptags = new AspectList(); + temptags.aspects.putAll(itags.aspects); + + for (Aspect tag:aspects.getAspects()) { + temptags.remove(tag, aspects.getAmount(tag)); + } + + itags = temptags; + return itags; + } + + public ItemStack getRecipeOutput() { + return recipeOutput; + } + + +} diff --git a/src/main/java/thaumcraft/api/crafting/IArcaneRecipe.java b/src/main/java/thaumcraft/api/crafting/IArcaneRecipe.java new file mode 100644 index 0000000..bb5036d --- /dev/null +++ b/src/main/java/thaumcraft/api/crafting/IArcaneRecipe.java @@ -0,0 +1,35 @@ +package thaumcraft.api.crafting; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import thaumcraft.api.aspects.AspectList; + +public interface IArcaneRecipe +{ + + + /** + * Used to check if a recipe matches current crafting inventory + * @param player + */ + boolean matches(IInventory var1, World world, EntityPlayer player); + + /** + * Returns an Item that is the result of this recipe + */ + ItemStack getCraftingResult(IInventory var1); + + /** + * Returns the size of the recipe area + */ + int getRecipeSize(); + + ItemStack getRecipeOutput(); + AspectList getAspects(); + AspectList getAspects(IInventory var1); + String getResearch(); + + +} diff --git a/src/main/java/thaumcraft/api/crafting/IInfusionStabiliser.java b/src/main/java/thaumcraft/api/crafting/IInfusionStabiliser.java new file mode 100644 index 0000000..d137ff2 --- /dev/null +++ b/src/main/java/thaumcraft/api/crafting/IInfusionStabiliser.java @@ -0,0 +1,19 @@ +package thaumcraft.api.crafting; + +import net.minecraft.world.World; + +/** + * + * @author Azanor + * + * Blocks that implement this interface act as infusion crafting stabilisers like candles and skulls + * + */ +public interface IInfusionStabiliser { + + /** + * returns true if the block can stabilise things + */ + public boolean canStabaliseInfusion(World world, int x, int y, int z); + +} diff --git a/src/main/java/thaumcraft/api/crafting/InfusionEnchantmentRecipe.java b/src/main/java/thaumcraft/api/crafting/InfusionEnchantmentRecipe.java new file mode 100644 index 0000000..773da34 --- /dev/null +++ b/src/main/java/thaumcraft/api/crafting/InfusionEnchantmentRecipe.java @@ -0,0 +1,154 @@ +package thaumcraft.api.crafting; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Map; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.oredict.OreDictionary; +import thaumcraft.api.ThaumcraftApiHelper; +import thaumcraft.api.aspects.AspectList; + +public class InfusionEnchantmentRecipe +{ + + public AspectList aspects; + public String research; + public ItemStack[] components; + public Enchantment enchantment; + public int recipeXP; + public int instability; + + public InfusionEnchantmentRecipe(String research, Enchantment input, int inst, + AspectList aspects2, ItemStack[] recipe) { + this.research = research; + this.enchantment = input; + this.aspects = aspects2; + this.components = recipe; + this.instability = inst; + this.recipeXP = Math.max(1, input.getMinEnchantability(1)/3); + } + + /** + * Used to check if a recipe matches current crafting inventory + * @param player + */ + public boolean matches(ArrayList input, ItemStack central, World world, EntityPlayer player) { + if (research.length()>0 && !ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), research)) { + return false; + } + + if (!enchantment.canApply(central) || !central.getItem().isItemTool(central)) { + return false; + } + + Map map1 = EnchantmentHelper.getEnchantments(central); + Iterator iterator = map1.keySet().iterator(); + while (iterator.hasNext()) + { + int j1 = ((Integer)iterator.next()).intValue(); + Enchantment ench = Enchantment.enchantmentsList[j1]; + if (j1 == enchantment.effectId && + EnchantmentHelper.getEnchantmentLevel(j1, central)>=ench.getMaxLevel()) + return false; + if (enchantment.effectId != ench.effectId && + (!enchantment.canApplyTogether(ench) || + !ench.canApplyTogether(enchantment))) { + return false; + } + } + + ItemStack i2 = null; + + ArrayList ii = new ArrayList(); + for (ItemStack is:input) { + ii.add(is.copy()); + } + + for (ItemStack comp:components) { + boolean b=false; + for (int a=0;a input, ItemStack central, World world, EntityPlayer player) { + if (getRecipeInput()==null) return false; + + if (research.length()>0 && !ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), research)) { + return false; + } + + ItemStack i2 = central.copy(); + if (getRecipeInput().getItemDamage()==OreDictionary.WILDCARD_VALUE) { + i2.setItemDamage(OreDictionary.WILDCARD_VALUE); + } + + if (!areItemStacksEqual(i2, getRecipeInput(), true)) return false; + + ArrayList ii = new ArrayList(); + for (ItemStack is:input) { + ii.add(is.copy()); + } + + for (ItemStack comp:getComponents()) { + boolean b=false; + for (int a=0;a itemMap = new HashMap(); + + for (; idx < recipe.length; idx += 2) + { + Character chr = (Character)recipe[idx]; + Object in = recipe[idx + 1]; + + if (in instanceof ItemStack) + { + itemMap.put(chr, ((ItemStack)in).copy()); + } + else if (in instanceof Item) + { + itemMap.put(chr, new ItemStack((Item)in)); + } + else if (in instanceof Block) + { + itemMap.put(chr, new ItemStack((Block)in, 1, OreDictionary.WILDCARD_VALUE)); + } + else if (in instanceof String) + { + itemMap.put(chr, OreDictionary.getOres((String)in)); + } + else + { + String ret = "Invalid shaped ore recipe: "; + for (Object tmp : recipe) + { + ret += tmp + ", "; + } + ret += output; + throw new RuntimeException(ret); + } + } + + input = new Object[width * height]; + int x = 0; + for (char chr : shape.toCharArray()) + { + input[x++] = itemMap.get(chr); + } + } + + @Override + public ItemStack getCraftingResult(IInventory var1){ return output.copy(); } + + @Override + public int getRecipeSize(){ return input.length; } + + @Override + public ItemStack getRecipeOutput(){ return output; } + + @Override + public boolean matches(IInventory inv, World world, EntityPlayer player) + { + if (research.length()>0 && !ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), research)) { + return false; + } + for (int x = 0; x <= MAX_CRAFT_GRID_WIDTH - width; x++) + { + for (int y = 0; y <= MAX_CRAFT_GRID_HEIGHT - height; ++y) + { + if (checkMatch(inv, x, y, false)) + { + return true; + } + + if (mirrored && checkMatch(inv, x, y, true)) + { + return true; + } + } + } + + return false; + } + + private boolean checkMatch(IInventory inv, int startX, int startY, boolean mirror) + { + for (int x = 0; x < MAX_CRAFT_GRID_WIDTH; x++) + { + for (int y = 0; y < MAX_CRAFT_GRID_HEIGHT; y++) + { + int subX = x - startX; + int subY = y - startY; + Object target = null; + + if (subX >= 0 && subY >= 0 && subX < width && subY < height) + { + if (mirror) + { + target = input[width - subX - 1 + subY * width]; + } + else + { + target = input[subX + subY * width]; + } + } + + ItemStack slot = ThaumcraftApiHelper.getStackInRowAndColumn(inv, x, y); + + if (target instanceof ItemStack) + { + if (!checkItemEquals((ItemStack)target, slot)) + { + return false; + } + } + else if (target instanceof ArrayList) + { + boolean matched = false; + + for (ItemStack item : (ArrayList)target) + { + matched = matched || checkItemEquals(item, slot); + } + + if (!matched) + { + return false; + } + } + else if (target == null && slot != null) + { + return false; + } + } + } + + return true; + } + + private boolean checkItemEquals(ItemStack target, ItemStack input) + { + if (input == null && target != null || input != null && target == null) + { + return false; + } + return (target.getItem() == input.getItem() && + (!target.hasTagCompound() || ThaumcraftApiHelper.areItemStackTagsEqualForCrafting(input,target)) && + (target.getItemDamage() == OreDictionary.WILDCARD_VALUE|| target.getItemDamage() == input.getItemDamage())); + } + + public ShapedArcaneRecipe setMirrored(boolean mirror) + { + mirrored = mirror; + return this; + } + + /** + * Returns the input for this recipe, any mod accessing this value should never + * manipulate the values in this array as it will effect the recipe itself. + * @return The recipes input vales. + */ + public Object[] getInput() + { + return this.input; + } + + @Override + public AspectList getAspects() { + return aspects; + } + + @Override + public AspectList getAspects(IInventory inv) { + return aspects; + } + + @Override + public String getResearch() { + return research; + } +} diff --git a/src/main/java/thaumcraft/api/crafting/ShapelessArcaneRecipe.java b/src/main/java/thaumcraft/api/crafting/ShapelessArcaneRecipe.java new file mode 100644 index 0000000..3b1eaeb --- /dev/null +++ b/src/main/java/thaumcraft/api/crafting/ShapelessArcaneRecipe.java @@ -0,0 +1,161 @@ +package thaumcraft.api.crafting; + +import java.util.ArrayList; +import java.util.Iterator; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.oredict.OreDictionary; +import thaumcraft.api.ThaumcraftApiHelper; +import thaumcraft.api.aspects.AspectList; + +public class ShapelessArcaneRecipe implements IArcaneRecipe +{ + private ItemStack output = null; + private ArrayList input = new ArrayList(); + + public AspectList aspects = null; + public String research; + + public ShapelessArcaneRecipe(String research, Block result, AspectList aspects, Object... recipe){ this(research,new ItemStack(result),aspects, recipe); } + public ShapelessArcaneRecipe(String research, Item result, AspectList aspects, Object... recipe){ this(research,new ItemStack(result),aspects, recipe); } + + public ShapelessArcaneRecipe(String research, ItemStack result, AspectList aspects, Object... recipe) + { + output = result.copy(); + this.research = research; + this.aspects = aspects; + for (Object in : recipe) + { + if (in instanceof ItemStack) + { + input.add(((ItemStack)in).copy()); + } + else if (in instanceof Item) + { + input.add(new ItemStack((Item)in)); + } + else if (in instanceof Block) + { + input.add(new ItemStack((Block)in)); + } + else if (in instanceof String) + { + input.add(OreDictionary.getOres((String)in)); + } + else + { + String ret = "Invalid shapeless ore recipe: "; + for (Object tmp : recipe) + { + ret += tmp + ", "; + } + ret += output; + throw new RuntimeException(ret); + } + } + } + + @Override + public int getRecipeSize(){ return input.size(); } + + @Override + public ItemStack getRecipeOutput(){ return output; } + + @Override + public ItemStack getCraftingResult(IInventory var1){ return output.copy(); } + + @Override + public boolean matches(IInventory var1, World world, EntityPlayer player) + { + if (research.length()>0 && !ThaumcraftApiHelper.isResearchComplete(player.getCommandSenderName(), research)) { + return false; + } + + ArrayList required = new ArrayList(input); + + for (int x = 0; x < 9; x++) + { + ItemStack slot = var1.getStackInSlot(x); + + if (slot != null) + { + boolean inRecipe = false; + Iterator req = required.iterator(); + + while (req.hasNext()) + { + boolean match = false; + + Object next = req.next(); + + if (next instanceof ItemStack) + { + match = checkItemEquals((ItemStack)next, slot); + } + else if (next instanceof ArrayList) + { + for (ItemStack item : (ArrayList)next) + { + match = match || checkItemEquals(item, slot); + } + } + + if (match) + { + inRecipe = true; + required.remove(next); + break; + } + } + + if (!inRecipe) + { + return false; + } + } + } + + return required.isEmpty(); + } + + private boolean checkItemEquals(ItemStack target, ItemStack input) + { + if (input == null && target != null || input != null && target == null) + { + return false; + } + return (target.getItem() == input.getItem() && + (!target.hasTagCompound() || ThaumcraftApiHelper.areItemStackTagsEqualForCrafting(input,target)) && + (target.getItemDamage() == OreDictionary.WILDCARD_VALUE|| target.getItemDamage() == input.getItemDamage())); + } + + /** + * Returns the input for this recipe, any mod accessing this value should never + * manipulate the values in this array as it will effect the recipe itself. + * @return The recipes input vales. + */ + public ArrayList getInput() + { + return this.input; + } + + @Override + public AspectList getAspects() { + return aspects; + } + + @Override + public AspectList getAspects(IInventory inv) { + return aspects; + } + + @Override + public String getResearch() { + return research; + } +} diff --git a/src/main/java/thaumcraft/api/damagesource/DamageSourceIndirectThaumcraftEntity.java b/src/main/java/thaumcraft/api/damagesource/DamageSourceIndirectThaumcraftEntity.java new file mode 100644 index 0000000..1562d05 --- /dev/null +++ b/src/main/java/thaumcraft/api/damagesource/DamageSourceIndirectThaumcraftEntity.java @@ -0,0 +1,32 @@ +package thaumcraft.api.damagesource; + +import net.minecraft.entity.Entity; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EntityDamageSourceIndirect; + +public class DamageSourceIndirectThaumcraftEntity extends EntityDamageSourceIndirect { + + private boolean fireDamage; + private float hungerDamage; + private boolean isUnblockable; + + + public DamageSourceIndirectThaumcraftEntity(String par1Str, + Entity par2Entity, Entity par3Entity) { + super(par1Str, par2Entity, par3Entity); + } + + + public DamageSource setFireDamage() + { + this.fireDamage = true; + return this; + } + + public DamageSource setDamageBypassesArmor() + { + this.isUnblockable = true; + this.hungerDamage = 0.0F; + return this; + } +} diff --git a/src/main/java/thaumcraft/api/damagesource/DamageSourceThaumcraft.java b/src/main/java/thaumcraft/api/damagesource/DamageSourceThaumcraft.java new file mode 100644 index 0000000..bb55672 --- /dev/null +++ b/src/main/java/thaumcraft/api/damagesource/DamageSourceThaumcraft.java @@ -0,0 +1,47 @@ +package thaumcraft.api.damagesource; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EntityDamageSource; + +public class DamageSourceThaumcraft extends DamageSource +{ + + public static DamageSource taint = new DamageSourceThaumcraft("taint").setDamageBypassesArmor().setMagicDamage(); + public static DamageSource tentacle = new DamageSourceThaumcraft("tentacle"); + public static DamageSource swarm = new DamageSourceThaumcraft("swarm"); + public static DamageSource dissolve = new DamageSourceThaumcraft("dissolve").setDamageBypassesArmor(); + + protected DamageSourceThaumcraft(String par1Str) { + super(par1Str); + } + + /** This kind of damage can be blocked or not. */ + private boolean isUnblockable = false; + private boolean isDamageAllowedInCreativeMode = false; + private float hungerDamage = 0.3F; + + /** This kind of damage is based on fire or not. */ + private boolean fireDamage; + + /** This kind of damage is based on a projectile or not. */ + private boolean projectile; + + /** + * Whether this damage source will have its damage amount scaled based on the current difficulty. + */ + private boolean difficultyScaled; + private boolean magicDamage = false; + private boolean explosion = false; + + public static DamageSource causeSwarmDamage(EntityLivingBase par0EntityLiving) + { + return new EntityDamageSource("swarm", par0EntityLiving); + } + + public static DamageSource causeTentacleDamage(EntityLivingBase par0EntityLiving) + { + return new EntityDamageSource("tentacle", par0EntityLiving); + } + +} diff --git a/src/main/java/thaumcraft/api/entities/ITaintedMob.java b/src/main/java/thaumcraft/api/entities/ITaintedMob.java new file mode 100644 index 0000000..83fb1fc --- /dev/null +++ b/src/main/java/thaumcraft/api/entities/ITaintedMob.java @@ -0,0 +1,5 @@ +package thaumcraft.api.entities; + +public interface ITaintedMob { + +} diff --git a/src/main/java/thaumcraft/api/nodes/INode.java b/src/main/java/thaumcraft/api/nodes/INode.java new file mode 100644 index 0000000..8c71414 --- /dev/null +++ b/src/main/java/thaumcraft/api/nodes/INode.java @@ -0,0 +1,53 @@ +package thaumcraft.api.nodes; + +import thaumcraft.api.aspects.Aspect; +import thaumcraft.api.aspects.AspectList; +import thaumcraft.api.aspects.IAspectContainer; + +public interface INode extends IAspectContainer { + + /** + * Unique identifier to distinguish nodes. Normal node id's are based on world id and coordinates + * @return + */ + public String getId(); + + public AspectList getAspectsBase(); + + /** + * Return the type of node + * @return + */ + public NodeType getNodeType(); + + /** + * Set the type of node + * @return + */ + public void setNodeType(NodeType nodeType); + + /** + * Return the node modifier + * @return + */ + public void setNodeModifier(NodeModifier nodeModifier); + + /** + * Set the node modifier + * @return + */ + public NodeModifier getNodeModifier(); + + /** + * Return the maximum capacity of each aspect the node can hold + * @return + */ + public int getNodeVisBase(Aspect aspect); + + /** + * Set the maximum capacity of each aspect the node can hold + * @return + */ + public void setNodeVisBase(Aspect aspect, short nodeVisBase); + +} diff --git a/src/main/java/thaumcraft/api/nodes/IRevealer.java b/src/main/java/thaumcraft/api/nodes/IRevealer.java new file mode 100644 index 0000000..14a19b5 --- /dev/null +++ b/src/main/java/thaumcraft/api/nodes/IRevealer.java @@ -0,0 +1,22 @@ +package thaumcraft.api.nodes; + +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; + +/** + * + * @author Azanor + * + * Equipped head slot items that extend this class will make nodes visible in world. + * + */ + +public interface IRevealer { + + /* + * If this method returns true the nodes will be visible. + */ + public boolean showNodes(ItemStack itemstack, EntityLivingBase player); + + +} diff --git a/src/main/java/thaumcraft/api/nodes/NodeModifier.java b/src/main/java/thaumcraft/api/nodes/NodeModifier.java new file mode 100644 index 0000000..885b867 --- /dev/null +++ b/src/main/java/thaumcraft/api/nodes/NodeModifier.java @@ -0,0 +1,6 @@ +package thaumcraft.api.nodes; + +public enum NodeModifier +{ + BRIGHT, PALE, FADING +} \ No newline at end of file diff --git a/src/main/java/thaumcraft/api/nodes/NodeType.java b/src/main/java/thaumcraft/api/nodes/NodeType.java new file mode 100644 index 0000000..355324b --- /dev/null +++ b/src/main/java/thaumcraft/api/nodes/NodeType.java @@ -0,0 +1,6 @@ +package thaumcraft.api.nodes; + +public enum NodeType +{ + NORMAL, UNSTABLE, DARK, TAINTED, HUNGRY, PURE +} \ No newline at end of file diff --git a/src/main/java/thaumcraft/api/package-info.java b/src/main/java/thaumcraft/api/package-info.java new file mode 100644 index 0000000..0de3926 --- /dev/null +++ b/src/main/java/thaumcraft/api/package-info.java @@ -0,0 +1,4 @@ +@API(owner = "Thaumcraft", apiVersion = "4.2.0.0", provides = "Thaumcraft|API") +package thaumcraft.api; + +import cpw.mods.fml.common.API; diff --git a/src/main/java/thaumcraft/api/potions/PotionFluxTaint.java b/src/main/java/thaumcraft/api/potions/PotionFluxTaint.java new file mode 100644 index 0000000..b950de0 --- /dev/null +++ b/src/main/java/thaumcraft/api/potions/PotionFluxTaint.java @@ -0,0 +1,67 @@ +package thaumcraft.api.potions; + +import net.minecraft.client.Minecraft; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.potion.Potion; +import net.minecraft.util.ResourceLocation; +import thaumcraft.api.damagesource.DamageSourceThaumcraft; +import thaumcraft.api.entities.ITaintedMob; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public class PotionFluxTaint extends Potion +{ + public static PotionFluxTaint instance = null; // will be instantiated at runtime + private int statusIconIndex = -1; + + public PotionFluxTaint(int par1, boolean par2, int par3) + { + super(par1,par2,par3); + setIconIndex(0, 0); + } + + public static void init() + { + instance.setPotionName("potion.fluxtaint"); + instance.setIconIndex(3, 1); + instance.setEffectiveness(0.25D); + } + + @Override + public boolean isBadEffect() { + return true; + } + + @Override + @SideOnly(Side.CLIENT) + public int getStatusIconIndex() { + Minecraft.getMinecraft().renderEngine.bindTexture(rl); + return super.getStatusIconIndex(); + } + + static final ResourceLocation rl = new ResourceLocation("thaumcraft","textures/misc/potions.png"); + + @Override + public void performEffect(EntityLivingBase target, int par2) { + if (target instanceof ITaintedMob) { + target.heal(1); + } else + if (!target.isEntityUndead() && !(target instanceof EntityPlayer)) + { + target.attackEntityFrom(DamageSourceThaumcraft.taint, 1); + } + else + if (!target.isEntityUndead() && (target.getMaxHealth() > 1 || (target instanceof EntityPlayer))) + { + target.attackEntityFrom(DamageSourceThaumcraft.taint, 1); + } + } + + public boolean isReady(int par1, int par2) + { + int k = 40 >> par2; + return k > 0 ? par1 % k == 0 : true; + } + +} diff --git a/src/main/java/thaumcraft/api/potions/PotionVisExhaust.java b/src/main/java/thaumcraft/api/potions/PotionVisExhaust.java new file mode 100644 index 0000000..cd7fc18 --- /dev/null +++ b/src/main/java/thaumcraft/api/potions/PotionVisExhaust.java @@ -0,0 +1,48 @@ +package thaumcraft.api.potions; + +import net.minecraft.client.Minecraft; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.potion.Potion; +import net.minecraft.util.ResourceLocation; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public class PotionVisExhaust extends Potion +{ + public static PotionVisExhaust instance = null; // will be instantiated at runtime + private int statusIconIndex = -1; + + public PotionVisExhaust(int par1, boolean par2, int par3) + { + super(par1,par2,par3); + setIconIndex(0, 0); + } + + public static void init() + { + instance.setPotionName("potion.visexhaust"); + instance.setIconIndex(5, 1); + instance.setEffectiveness(0.25D); + } + + @Override + public boolean isBadEffect() { + return true; + } + + @Override + @SideOnly(Side.CLIENT) + public int getStatusIconIndex() { + Minecraft.getMinecraft().renderEngine.bindTexture(rl); + return super.getStatusIconIndex(); + } + + static final ResourceLocation rl = new ResourceLocation("thaumcraft","textures/misc/potions.png"); + + @Override + public void performEffect(EntityLivingBase target, int par2) { + + } + + +} diff --git a/src/main/java/thaumcraft/api/research/IScanEventHandler.java b/src/main/java/thaumcraft/api/research/IScanEventHandler.java new file mode 100644 index 0000000..d0efac5 --- /dev/null +++ b/src/main/java/thaumcraft/api/research/IScanEventHandler.java @@ -0,0 +1,9 @@ +package thaumcraft.api.research; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface IScanEventHandler { + ScanResult scanPhenomena(ItemStack stack, World world, EntityPlayer player); +} diff --git a/src/main/java/thaumcraft/api/research/ResearchCategories.java b/src/main/java/thaumcraft/api/research/ResearchCategories.java new file mode 100644 index 0000000..82309b3 --- /dev/null +++ b/src/main/java/thaumcraft/api/research/ResearchCategories.java @@ -0,0 +1,101 @@ +package thaumcraft.api.research; + +import java.util.Collection; +import java.util.LinkedHashMap; + +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; + +import org.apache.logging.log4j.Level; + +import cpw.mods.fml.common.FMLLog; + +public class ResearchCategories { + + //Research + public static LinkedHashMap researchCategories = new LinkedHashMap (); + + /** + * @param key + * @return the research item linked to this key + */ + public static ResearchCategoryList getResearchList(String key) { + return researchCategories.get(key); + } + + /** + * @param key + * @return the name of the research category linked to this key. + * Must be stored as localization information in the LanguageRegistry. + */ + public static String getCategoryName(String key) { + return StatCollector.translateToLocal("tc.research_category."+key); + } + + /** + * @param key the research key + * @return the ResearchItem object. + */ + public static ResearchItem getResearch(String key) { + Collection rc = researchCategories.values(); + for (Object cat:rc) { + Collection rl = ((ResearchCategoryList)cat).research.values(); + for (Object ri:rl) { + if ((((ResearchItem)ri).key).equals(key)) return (ResearchItem)ri; + } + } + return null; + } + + /** + * This should only be done at the PostInit stage + * @param key the key used for this category + * @param icon the icon to be used for the research category tab + * @param background the resource location of the background image to use for this category + * @return the name of the research linked to this key + */ + public static void registerCategory(String key, ResourceLocation icon, ResourceLocation background) { + if (getResearchList(key)==null) { + ResearchCategoryList rl = new ResearchCategoryList(icon, background); + researchCategories.put(key, rl); + } + } + + public static void addResearch(ResearchItem ri) { + ResearchCategoryList rl = getResearchList(ri.category); + if (rl!=null && !rl.research.containsKey(ri.key)) { + + if (!ri.isVirtual()) { + for (ResearchItem rr:rl.research.values()) { + if (rr.displayColumn == ri.displayColumn && rr.displayRow == ri.displayRow) { + FMLLog.log(Level.FATAL, "[Thaumcraft] Research ["+ri.getName()+"] not added as it overlaps with existing research ["+rr.getName()+"]"); + return; + } + } + } + + + rl.research.put(ri.key, ri); + + if (ri.displayColumn < rl.minDisplayColumn) + { + rl.minDisplayColumn = ri.displayColumn; + } + + if (ri.displayRow < rl.minDisplayRow) + { + rl.minDisplayRow = ri.displayRow; + } + + if (ri.displayColumn > rl.maxDisplayColumn) + { + rl.maxDisplayColumn = ri.displayColumn; + } + + if (ri.displayRow > rl.maxDisplayRow) + { + rl.maxDisplayRow = ri.displayRow; + } + } + } +} diff --git a/src/main/java/thaumcraft/api/research/ResearchCategoryList.java b/src/main/java/thaumcraft/api/research/ResearchCategoryList.java new file mode 100644 index 0000000..7eed010 --- /dev/null +++ b/src/main/java/thaumcraft/api/research/ResearchCategoryList.java @@ -0,0 +1,37 @@ +package thaumcraft.api.research; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.util.ResourceLocation; + +public class ResearchCategoryList { + + /** Is the smallest column used on the GUI. */ + public int minDisplayColumn; + + /** Is the smallest row used on the GUI. */ + public int minDisplayRow; + + /** Is the biggest column used on the GUI. */ + public int maxDisplayColumn; + + /** Is the biggest row used on the GUI. */ + public int maxDisplayRow; + + /** display variables **/ + public ResourceLocation icon; + public ResourceLocation background; + + public ResearchCategoryList(ResourceLocation icon, ResourceLocation background) { + this.icon = icon; + this.background = background; + } + + //Research + public Map research = new HashMap(); + + + + +} diff --git a/src/main/java/thaumcraft/api/research/ResearchItem.java b/src/main/java/thaumcraft/api/research/ResearchItem.java new file mode 100644 index 0000000..55b3820 --- /dev/null +++ b/src/main/java/thaumcraft/api/research/ResearchItem.java @@ -0,0 +1,367 @@ +package thaumcraft.api.research; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; +import thaumcraft.api.aspects.Aspect; +import thaumcraft.api.aspects.AspectList; + +public class ResearchItem +{ + /** + * A short string used as a key for this research. Must be unique + */ + public final String key; + + /** + * A short string used as a reference to the research category to which this must be added. + */ + public final String category; + + /** + * The aspect tags and their values required to complete this research + */ + public final AspectList tags; + + /** + * This links to any research that needs to be completed before this research can be discovered or learnt. + */ + public String[] parents = null; + + /** + * Like parent above, but a line will not be displayed in the thaumonomicon linking them. Just used to prevent clutter. + */ + public String[] parentsHidden = null; + /** + * any research linked to this that will be unlocked automatically when this research is complete + */ + public String[] siblings = null; + + /** + * the horizontal position of the research icon + */ + public final int displayColumn; + + /** + * the vertical position of the research icon + */ + public final int displayRow; + + /** + * the icon to be used for this research + */ + public final ItemStack icon_item; + + /** + * the icon to be used for this research + */ + public final ResourceLocation icon_resource; + + /** + * How large the research grid is. Valid values are 1 to 3. + */ + private int complexity; + + /** + * Special research has a spiky border. Used for important research milestones. + */ + private boolean isSpecial; + + /** + * Research that can be directly purchased with RP in normal research difficulty. + */ + private boolean isSecondary; + + /** + * This indicates if the research should use a circular icon border. Usually used for "passive" research + * that doesn't have recipes and grants passive effects, or that unlock automatically. + */ + private boolean isRound; + + /** + * Stub research cannot be discovered by normal means, but can be unlocked via the sibling system. + */ + private boolean isStub; + + /** + * This indicated that the research is completely hidden and cannot be discovered by any + * player-controlled means. The recipes will never show up in the thaumonomicon. + * Usually used to unlock "hidden" recipes via sibling unlocking, like + * the various cap and rod combos for wands. + */ + private boolean isVirtual; + + @Deprecated + private boolean isLost; + + /** + * Concealed research does not display in the thaumonomicon until parent researches are discovered. + */ + private boolean isConcealed; + + /** + * Hidden research can only be discovered via scanning or knowledge fragments + */ + private boolean isHidden; + + /** + * These research items will automatically unlock for all players on game start + */ + private boolean isAutoUnlock; + + /** + * Scanning these items will have a chance of revealing hidden knowledge in the thaumonomicon + */ + private ItemStack[] itemTriggers; + + /** + * Scanning these entities will have a chance of revealing hidden knowledge in the thaumonomicon + */ + private String[] entityTriggers; + + /** + * Scanning things with these aspects will have a chance of revealing hidden knowledge in the thaumonomicon + */ + private Aspect[] aspectTriggers; + + private ResearchPage[] pages = null; + + public ResearchItem(String key, String category) + { + this.key = key; + this.category = category; + this.tags = new AspectList(); + this.icon_resource = null; + this.icon_item = null; + this.displayColumn = 0; + this.displayRow = 0; + this.setVirtual(); + + } + + public ResearchItem(String key, String category, AspectList tags, int col, int row, int complex, ResourceLocation icon) + { + this.key = key; + this.category = category; + this.tags = tags; + this.icon_resource = icon; + this.icon_item = null; + this.displayColumn = col; + this.displayRow = row; + this.complexity = complex; + if (complexity < 1) this.complexity = 1; + if (complexity > 3) this.complexity = 3; + } + + public ResearchItem(String key, String category, AspectList tags, int col, int row, int complex, ItemStack icon) + { + this.key = key; + this.category = category; + this.tags = tags; + this.icon_item = icon; + this.icon_resource = null; + this.displayColumn = col; + this.displayRow = row; + this.complexity = complex; + if (complexity < 1) this.complexity = 1; + if (complexity > 3) this.complexity = 3; + } + + public ResearchItem setSpecial() + { + this.isSpecial = true; + return this; + } + + public ResearchItem setStub() + { + this.isStub = true; + return this; + } + + @Deprecated + public ResearchItem setLost() + { + this.isLost = true; + return this; + } + + public ResearchItem setConcealed() + { + this.isConcealed = true; + return this; + } + + public ResearchItem setHidden() + { + this.isHidden = true; + return this; + } + + public ResearchItem setVirtual() + { + this.isVirtual = true; + return this; + } + + public ResearchItem setParents(String... par) + { + this.parents = par; + return this; + } + + + + public ResearchItem setParentsHidden(String... par) + { + this.parentsHidden = par; + return this; + } + + public ResearchItem setSiblings(String... sib) + { + this.siblings = sib; + return this; + } + + public ResearchItem setPages(ResearchPage... par) + { + this.pages = par; + return this; + } + + public ResearchPage[] getPages() { + return pages; + } + + public ResearchItem setItemTriggers(ItemStack... par) + { + this.itemTriggers = par; + return this; + } + + public ResearchItem setEntityTriggers(String... par) + { + this.entityTriggers = par; + return this; + } + + public ResearchItem setAspectTriggers(Aspect... par) + { + this.aspectTriggers = par; + return this; + } + + public ItemStack[] getItemTriggers() { + return itemTriggers; + } + + public String[] getEntityTriggers() { + return entityTriggers; + } + + public Aspect[] getAspectTriggers() { + return aspectTriggers; + } + + public ResearchItem registerResearchItem() + { + ResearchCategories.addResearch(this); + return this; + } + + public String getName() + { + return StatCollector.translateToLocal("tc.research_name."+key); + } + + public String getText() + { + return StatCollector.translateToLocal("tc.research_text."+key); + } + + public boolean isSpecial() + { + return this.isSpecial; + } + + public boolean isStub() + { + return this.isStub; + } + + @Deprecated + public boolean isLost() + { + return this.isLost; + } + + public boolean isConcealed() + { + return this.isConcealed; + } + + public boolean isHidden() + { + return this.isHidden; + } + + public boolean isVirtual() + { + return this.isVirtual; + } + + public boolean isAutoUnlock() { + return isAutoUnlock; + } + + public ResearchItem setAutoUnlock() + { + this.isAutoUnlock = true; + return this; + } + + public boolean isRound() { + return isRound; + } + + public ResearchItem setRound() { + this.isRound = true; + return this; + } + + public boolean isSecondary() { + return isSecondary; + } + + public ResearchItem setSecondary() { + this.isSecondary = true; + return this; + } + + public int getComplexity() { + return complexity; + } + + public ResearchItem setComplexity(int complexity) { + this.complexity = complexity; + return this; + } + + /** + * @return the aspect aspects ordinal with the highest value. Used to determine scroll color and similar things + */ + public Aspect getResearchPrimaryTag() { + Aspect aspect=null; + int highest=0; + if (tags!=null) + for (Aspect tag:tags.getAspects()) { + if (tags.getAmount(tag)>highest) { + aspect=tag; + highest=tags.getAmount(tag); + }; + } + return aspect; + } + +} diff --git a/src/main/java/thaumcraft/api/research/ResearchPage.java b/src/main/java/thaumcraft/api/research/ResearchPage.java new file mode 100644 index 0000000..fdada84 --- /dev/null +++ b/src/main/java/thaumcraft/api/research/ResearchPage.java @@ -0,0 +1,193 @@ +package thaumcraft.api.research; + +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.FurnaceRecipes; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.StatCollector; +import thaumcraft.api.aspects.AspectList; +import thaumcraft.api.crafting.CrucibleRecipe; +import thaumcraft.api.crafting.IArcaneRecipe; +import thaumcraft.api.crafting.InfusionEnchantmentRecipe; +import thaumcraft.api.crafting.InfusionRecipe; + +public class ResearchPage { + public static enum PageType + { + TEXT, + TEXT_CONCEALED, + IMAGE, + CRUCIBLE_CRAFTING, + ARCANE_CRAFTING, + ASPECTS, + NORMAL_CRAFTING, + INFUSION_CRAFTING, + COMPOUND_CRAFTING, + INFUSION_ENCHANTMENT, + SMELTING + } + + public PageType type = PageType.TEXT; + + public String text=null; + public String research=null; + public ResourceLocation image=null; + public AspectList aspects=null; + public Object recipe=null; + public ItemStack recipeOutput=null; + + /** + * @param text this can (but does not have to) be a reference to a localization variable, not the actual text. + */ + public ResearchPage(String text) { + this.type = PageType.TEXT; + this.text = text; + } + + /** + * @param research this page will only be displayed if the player has discovered this research + * @param text this can (but does not have to) be a reference to a localization variable, not the actual text. + */ + public ResearchPage(String research, String text) { + this.type = PageType.TEXT_CONCEALED; + this.research = research; + this.text = text; + } + + /** + * @param recipe a vanilla crafting recipe. + */ + public ResearchPage(IRecipe recipe) { + this.type = PageType.NORMAL_CRAFTING; + this.recipe = recipe; + this.recipeOutput = recipe.getRecipeOutput(); + } + + /** + * @param recipe a collection of vanilla crafting recipes. + */ + public ResearchPage(IRecipe[] recipe) { + this.type = PageType.NORMAL_CRAFTING; + this.recipe = recipe; + } + + /** + * @param recipe a collection of arcane crafting recipes. + */ + public ResearchPage(IArcaneRecipe[] recipe) { + this.type = PageType.ARCANE_CRAFTING; + this.recipe = recipe; + } + + /** + * @param recipe a collection of arcane crafting recipes. + */ + public ResearchPage(CrucibleRecipe[] recipe) { + this.type = PageType.CRUCIBLE_CRAFTING; + this.recipe = recipe; + } + + /** + * @param recipe a collection of infusion crafting recipes. + */ + public ResearchPage(InfusionRecipe[] recipe) { + this.type = PageType.INFUSION_CRAFTING; + this.recipe = recipe; + } + + /** + * @param recipe a compound crafting recipe. + */ + public ResearchPage(List recipe) { + this.type = PageType.COMPOUND_CRAFTING; + this.recipe = recipe; + } + + /** + * @param recipe an arcane worktable crafting recipe. + */ + public ResearchPage(IArcaneRecipe recipe) { + this.type = PageType.ARCANE_CRAFTING; + this.recipe = recipe; + this.recipeOutput = recipe.getRecipeOutput(); + } + + /** + * @param recipe an alchemy crafting recipe. + */ + public ResearchPage(CrucibleRecipe recipe) { + this.type = PageType.CRUCIBLE_CRAFTING; + this.recipe = recipe; + this.recipeOutput = recipe.getRecipeOutput(); + } + + /** + * @param recipe a furnace smelting crafting recipe. + */ + public ResearchPage(ItemStack input) { + this.type = PageType.SMELTING; + this.recipe = input; + this.recipeOutput = FurnaceRecipes.smelting().getSmeltingResult(input); + } + + /** + * @param recipe an infusion crafting recipe. + */ + public ResearchPage(InfusionRecipe recipe) { + this.type = PageType.INFUSION_CRAFTING; + this.recipe = recipe; + if (recipe.getRecipeOutput() instanceof ItemStack) { + this.recipeOutput = (ItemStack) recipe.getRecipeOutput(); + } else { + this.recipeOutput = recipe.getRecipeInput(); + } + } + + /** + * @param recipe an infusion crafting recipe. + */ + public ResearchPage(InfusionEnchantmentRecipe recipe) { + this.type = PageType.INFUSION_ENCHANTMENT; + this.recipe = recipe; +// if (recipe.recipeOutput instanceof ItemStack) { +// this.recipeOutput = (ItemStack) recipe.recipeOutput; +// } else { +// this.recipeOutput = recipe.recipeInput; +// } + } + + /** + * @param image + * @param caption this can (but does not have to) be a reference to a localization variable, not the actual text. + */ + public ResearchPage(ResourceLocation image, String caption) { + this.type = PageType.IMAGE; + this.image = image; + this.text = caption; + } + + /** + * This function should really not be called directly - used internally + */ + public ResearchPage(AspectList as) { + this.type = PageType.ASPECTS; + this.aspects = as; + } + + /** + * returns a localized text of the text field (if one exists). Returns the text field itself otherwise. + * @return + */ + public String getTranslatedText() { + String ret=""; + if (text != null) { + ret = StatCollector.translateToLocal(text); + if (ret.isEmpty()) ret = text; + } + return ret; + } + + +} diff --git a/src/main/java/thaumcraft/api/research/ScanResult.java b/src/main/java/thaumcraft/api/research/ScanResult.java new file mode 100644 index 0000000..e1498f3 --- /dev/null +++ b/src/main/java/thaumcraft/api/research/ScanResult.java @@ -0,0 +1,39 @@ +package thaumcraft.api.research; + +import net.minecraft.entity.Entity; + +public class ScanResult { + public byte type = 0; //1=blocks,2=entities,3=phenomena + public int id; + public int meta; + public Entity entity; + public String phenomena; + + public ScanResult(byte type, int blockId, int blockMeta, Entity entity, + String phenomena) { + super(); + this.type = type; + this.id = blockId; + this.meta = blockMeta; + this.entity = entity; + this.phenomena = phenomena; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ScanResult) { + ScanResult sr = (ScanResult) obj; + if (type != sr.type) + return false; + if (type == 1 + && (id != sr.id || meta != sr.meta)) + return false; + if (type == 2 && entity.getEntityId() != sr.entity.getEntityId()) + return false; + if (type == 3 && !phenomena.equals(sr.phenomena)) + return false; + } + return true; + } + +} diff --git a/src/main/java/thaumcraft/api/visnet/TileVisNode.java b/src/main/java/thaumcraft/api/visnet/TileVisNode.java new file mode 100644 index 0000000..84b1400 --- /dev/null +++ b/src/main/java/thaumcraft/api/visnet/TileVisNode.java @@ -0,0 +1,188 @@ +package thaumcraft.api.visnet; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; + +import thaumcraft.api.TileThaumcraft; +import thaumcraft.api.WorldCoordinates; +import thaumcraft.api.aspects.Aspect; + +/** + * @author Azanor + * + * The tile entity used by nodes in the vis energy network. A node is either a source (like an aura node), + * a transport relay or vis receiver (like the infernal furnace). + * + */ +public abstract class TileVisNode extends TileThaumcraft { + + WeakReference parent = null; + ArrayList> children = new ArrayList>(); + + /** + * @return the WorldCoordinates location of where this node is located + */ + public WorldCoordinates getLocation() { + return new WorldCoordinates(this); + } + + /** + * @return the number of blocks away this node will check for parent nodes to connect to. + */ + public abstract int getRange(); + + /** + * @return true if this is the source or root node of the vis network. + */ + public abstract boolean isSource(); + + /** + * This method should never be called directly. Use VisNetHandler.drainVis() instead + * @param aspect what aspect to drain + * @param vis how much to drain + * @return how much was actually drained + */ + public int consumeVis(Aspect aspect, int vis) { + if (VisNetHandler.isNodeValid(getParent())) { + int out = getParent().get().consumeVis(aspect, vis); + if (out>0) { + triggerConsumeEffect(aspect); + } + return out; + } + return 0; + } + + public void removeThisNode() { + for (WeakReference n:getChildren()) { + if (n!=null && n.get()!=null) { + n.get().removeThisNode(); + } + } + + children = new ArrayList>(); + if (VisNetHandler.isNodeValid(this.getParent())) { + this.getParent().get().nodeRefresh=true; + } + this.setParent(null); + this.parentChanged(); + + if (this.isSource()) { + HashMap> sourcelist = VisNetHandler.sources.get(worldObj.provider.dimensionId); + if (sourcelist==null) { + sourcelist = new HashMap>(); + } + sourcelist.remove(getLocation()); + VisNetHandler.sources.put( worldObj.provider.dimensionId, sourcelist ); + } + + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } + + + + @Override + public void invalidate() { + removeThisNode(); + super.invalidate(); + } + + public void triggerConsumeEffect(Aspect aspect) { } + + /** + * @return + */ + public WeakReference getParent() { + return parent; + } + + /** + * @return + */ + public WeakReference getRootSource() { + return VisNetHandler.isNodeValid(getParent()) ? + getParent().get().getRootSource() : this.isSource() ? + new WeakReference(this) : null; + } + + /** + * @param parent + */ + public void setParent(WeakReference parent) { + this.parent = parent; + } + + /** + * @return + */ + public ArrayList> getChildren() { + return children; + } + + @Override + public boolean canUpdate() { + return true; + } + + protected int nodeCounter = 0; + private boolean nodeRegged = false; + public boolean nodeRefresh = false; + + @Override + public void updateEntity() { + + if (!worldObj.isRemote && ((nodeCounter++) % 40==0 || nodeRefresh)) { + //check for changes + if (!nodeRefresh && children.size()>0) { + for (WeakReference n:children) { + if (n==null || n.get()==null) { + nodeRefresh=true; + break; + } + } + } + + //refresh linked nodes + if (nodeRefresh) { + for (WeakReference n:children) { + if (n.get()!=null) { + n.get().nodeRefresh=true; + } + } + children.clear(); + parent=null; + } + + //redo stuff + if (isSource() && !nodeRegged) { + VisNetHandler.addSource(getWorldObj(), this); + nodeRegged = true; + } else + if (!isSource() && !VisNetHandler.isNodeValid(getParent())) { + setParent(VisNetHandler.addNode(getWorldObj(), this)); + nodeRefresh=true; + } + + if (nodeRefresh) { + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + parentChanged(); + } + nodeRefresh=false; + } + + } + + public void parentChanged() { } + + /** + * @return the type of shard this is attuned to: + * none -1, air 0, fire 1, water 2, earth 3, order 4, entropy 5 + * Should return -1 for most implementations + */ + public byte getAttunement() { + return -1; + } + + +} diff --git a/src/main/java/thaumcraft/api/visnet/VisNetHandler.java b/src/main/java/thaumcraft/api/visnet/VisNetHandler.java new file mode 100644 index 0000000..cb9714c --- /dev/null +++ b/src/main/java/thaumcraft/api/visnet/VisNetHandler.java @@ -0,0 +1,284 @@ +package thaumcraft.api.visnet; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; + +import net.minecraft.world.World; +import thaumcraft.api.WorldCoordinates; +import thaumcraft.api.aspects.Aspect; +import cpw.mods.fml.common.FMLLog; + +public class VisNetHandler { + + // / NODE DRAINING + /** + * This method drains vis from a relay or source near the passed in + * location. The amount received can be less than the amount requested so + * take that into account. + * + * @param world + * @param x the x position of the draining block or entity + * @param y the y position of the draining block or entity + * @param z the z position of the draining block or entity + * @param aspect what aspect to drain + * @param amount how much to drain + * @return how much was actually drained + */ + public static int drainVis(World world, int x, int y, int z, Aspect aspect, int amount) { + + int drainedAmount = 0; + + WorldCoordinates drainer = new WorldCoordinates(x, y, z, + world.provider.dimensionId); + if (!nearbyNodes.containsKey(drainer)) { + calculateNearbyNodes(world, x, y, z); + } + + ArrayList> nodes = nearbyNodes.get(drainer); + if (nodes!=null && nodes.size()>0) + for (WeakReference noderef : nodes) { + + TileVisNode node = noderef.get(); + + if (node == null) continue; + + int a = node.consumeVis(aspect, amount); + drainedAmount += a; + amount -= a; + if (a>0) { + int color = Aspect.getPrimalAspects().indexOf(aspect); + generateVisEffect(world.provider.dimensionId, x, y, z, node.xCoord, node.yCoord, node.zCoord, color); + } + if (amount <= 0) { + break; + } + } + + return drainedAmount; + } + + static Method generateVisEffect; + public static void generateVisEffect(int dim, int x, int y, int z, int x2, int y2, int z2, int color) { + try { + if(generateVisEffect == null) { + Class fake = Class.forName("thaumcraft.common.lib.Utils"); + generateVisEffect = fake.getMethod("generateVisEffect", int.class, int.class, int.class, int.class, int.class, int.class, int.class, int.class); + } + generateVisEffect.invoke(null, dim, x,y,z,x2,y2,z2,color); + } catch(Exception ex) { + FMLLog.warning("[Thaumcraft API] Could not invoke thaumcraft.common.lib.Utils method generateVisEffect"); + } + } + + public static HashMap>> sources = new HashMap>>(); + + public static void addSource(World world, TileVisNode vs) { + HashMap> sourcelist = sources + .get(world.provider.dimensionId); + if (sourcelist == null) { + sourcelist = new HashMap>(); + } + sourcelist.put(vs.getLocation(), new WeakReference(vs)); + sources.put(world.provider.dimensionId, sourcelist); + nearbyNodes.clear(); + } + + public static boolean isNodeValid(WeakReference node) { + if (node == null || node.get() == null || node.get().isInvalid()) + return false; + return true; + } + + public static WeakReference addNode(World world, TileVisNode vn) { + WeakReference ref = new WeakReference(vn); + + HashMap> sourcelist = sources + .get(world.provider.dimensionId); + if (sourcelist == null) { + sourcelist = new HashMap>(); + return null; + } + + ArrayList nearby = new ArrayList(); + + for (WeakReference root : sourcelist.values()) { + if (!isNodeValid(root)) + continue; + + TileVisNode source = root.get(); + + float r = inRange(world, vn.getLocation(), source.getLocation(), + vn.getRange()); + if (r > 0) { + nearby.add(new Object[] { source, r - vn.getRange() * 2 }); + } + nearby = findClosestNodes(vn, source, nearby); + } + + float dist = Float.MAX_VALUE; + TileVisNode closest = null; + if (nearby.size() > 0) { + for (Object[] o : nearby) { + if ((Float) o[1] < dist) {// && canNodeBeSeen(vn,(TileVisNode) + // o[0])) { + dist = (Float) o[1]; + closest = (TileVisNode) o[0]; + } + } + } + if (closest != null) { + closest.getChildren().add(ref); + nearbyNodes.clear(); + return new WeakReference(closest); + } + + return null; + } + + public static ArrayList findClosestNodes(TileVisNode target, + TileVisNode root, ArrayList in) { + TileVisNode closestChild = null; + + for (WeakReference child : root.getChildren()) { + TileVisNode n = child.get(); + + if (n != null + && !n.equals(target) + && !n.equals(root) + && (target.getAttunement() == -1 || n.getAttunement() == -1 || n + .getAttunement() == target.getAttunement())) { + + float r2 = inRange(n.getWorldObj(), n.getLocation(), + target.getLocation(), target.getRange()); + if (r2 > 0) { + in.add(new Object[] { n, r2 }); + } + + in = findClosestNodes(target, n, in); + } + } + return in; + } + + private static float inRange(World world, WorldCoordinates cc1, + WorldCoordinates cc2, int range) { + float distance = cc1.getDistanceSquaredToWorldCoordinates(cc2); + return distance > range * range ? -1 : distance; + } + + private static HashMap>> nearbyNodes = new HashMap>>(); + + private static void calculateNearbyNodes(World world, int x, int y, int z) { + + HashMap> sourcelist = sources + .get(world.provider.dimensionId); + if (sourcelist == null) { + sourcelist = new HashMap>(); + return; + } + + ArrayList> cn = new ArrayList>(); + WorldCoordinates drainer = new WorldCoordinates(x, y, z, + world.provider.dimensionId); + + ArrayList nearby = new ArrayList(); + + for (WeakReference root : sourcelist.values()) { + + if (!isNodeValid(root)) + continue; + + TileVisNode source = root.get(); + + TileVisNode closest = null; + float range = Float.MAX_VALUE; + + float r = inRange(world, drainer, source.getLocation(), + source.getRange()); + if (r > 0) { + range = r; + closest = source; + } + + ArrayList> children = new ArrayList>(); + children = getAllChildren(source,children); + + for (WeakReference child : children) { + TileVisNode n = child.get(); + if (n != null && !n.equals(root)) { + + float r2 = inRange(n.getWorldObj(), n.getLocation(), + drainer, n.getRange()); + if (r2 > 0 && r2 < range) { + range = r2; + closest = n; + } + } + } + + if (closest != null) { + + cn.add(new WeakReference(closest)); + } + } + + nearbyNodes.put(drainer, cn); + } + + private static ArrayList> getAllChildren(TileVisNode source, ArrayList> list) { + for (WeakReference child : source.getChildren()) { + TileVisNode n = child.get(); + if (n != null) { + list.add(child); + list = getAllChildren(n,list); + } + } + return list; + } + + // public static boolean canNodeBeSeen(TileVisNode source,TileVisNode + // target) + // { + // double d = Math.sqrt(source.getDistanceFrom(target.xCoord, target.yCoord, + // target.zCoord)); + // double xd = (source.xCoord-target.xCoord) / d; + // double yd = (source.yCoord-target.yCoord) / d; + // double zd = (source.zCoord-target.zCoord) / d; + // return source.getWorldObj().rayTraceBlocks( + // Vec3.createVectorHelper(source.xCoord-xd+.5+.5, source.yCoord-yd, + // source.zCoord-zd), + // Vec3.createVectorHelper(target.xCoord+.5, target.yCoord+.5, + // target.zCoord+.5)) == null; + // } + + // public static HashMap> + // noderef = new HashMap>(); + // + // public static TileVisNode getClosestNodeWithinRadius(World world, int x, + // int y, int z, int radius) { + // TileVisNode out = null; + // WorldCoordinates wc = null; + // float cd = Float.MAX_VALUE; + // for (int sx = x - radius; sx <= x + radius; sx++) { + // for (int sy = y - radius; sy <= y + radius; sy++) { + // for (int sz = z - radius; sz <= z + radius; sz++) { + // wc = new WorldCoordinates(sx,sy,sz,world.provider.dimensionId); + // if (noderef.containsKey(wc)) { + // float d = wc.getDistanceSquared(x, y, z); + // if (dAs a guide build the sort string from two alphanumeric characters followed by + * two numeric characters based on... whatever. + */ + public String getSortingHelper(ItemStack itemstack); + + boolean onFocusBlockStartBreak(ItemStack itemstack, int x, int y, int z, EntityPlayer player); + + public boolean acceptsEnchant(int id); + + + + + +} diff --git a/src/main/java/thaumcraft/api/wands/IWandRodOnUpdate.java b/src/main/java/thaumcraft/api/wands/IWandRodOnUpdate.java new file mode 100644 index 0000000..4ef8c84 --- /dev/null +++ b/src/main/java/thaumcraft/api/wands/IWandRodOnUpdate.java @@ -0,0 +1,16 @@ +package thaumcraft.api.wands; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +/** + * + * @author azanor + * + * Implemented by a class that you wish to be called whenever a wand with this rod performs its + * update tick. + * + */ +public interface IWandRodOnUpdate { + void onUpdate(ItemStack itemstack, EntityPlayer player); +} diff --git a/src/main/java/thaumcraft/api/wands/IWandTriggerManager.java b/src/main/java/thaumcraft/api/wands/IWandTriggerManager.java new file mode 100644 index 0000000..7c299de --- /dev/null +++ b/src/main/java/thaumcraft/api/wands/IWandTriggerManager.java @@ -0,0 +1,15 @@ +package thaumcraft.api.wands; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public interface IWandTriggerManager { + + /** + * This class will be called by wands with the proper parameters. It is up to you to decide what to do with them. + */ + public boolean performTrigger(World world, ItemStack wand, EntityPlayer player, + int x, int y, int z, int side, int event); + +} diff --git a/src/main/java/thaumcraft/api/wands/IWandable.java b/src/main/java/thaumcraft/api/wands/IWandable.java new file mode 100644 index 0000000..aeb9bac --- /dev/null +++ b/src/main/java/thaumcraft/api/wands/IWandable.java @@ -0,0 +1,25 @@ +package thaumcraft.api.wands; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** + * + * @author azanor + * + * Add this to a tile entity that you wish wands to interact with in some way. + * + */ + +public interface IWandable { + + public int onWandRightClick(World world, ItemStack wandstack, EntityPlayer player, int x, int y, int z, int side, int md); + + public ItemStack onWandRightClick(World world, ItemStack wandstack, EntityPlayer player); + + public void onUsingWandTick(ItemStack wandstack, EntityPlayer player, int count); + + public void onWandStoppedUsing(ItemStack wandstack, World world, EntityPlayer player, int count); + +} diff --git a/src/main/java/thaumcraft/api/wands/ItemFocusBasic.java b/src/main/java/thaumcraft/api/wands/ItemFocusBasic.java new file mode 100644 index 0000000..3590052 --- /dev/null +++ b/src/main/java/thaumcraft/api/wands/ItemFocusBasic.java @@ -0,0 +1,166 @@ +package thaumcraft.api.wands; + +import java.text.DecimalFormat; +import java.util.List; +import java.util.Map; + +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.EnumRarity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.StatCollector; +import net.minecraft.world.World; +import thaumcraft.api.ThaumcraftApi; +import thaumcraft.api.aspects.Aspect; +import thaumcraft.api.aspects.AspectList; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public class ItemFocusBasic extends Item implements IWandFocus { + + public ItemFocusBasic () + { + super(); + maxStackSize = 1; + canRepair=false; + this.setMaxDamage(0); + } + + public IIcon icon; + + @SideOnly(Side.CLIENT) + @Override + public IIcon getIconFromDamage(int par1) { + return icon; + } + + @Override + public boolean isItemTool(ItemStack par1ItemStack) + { + return true; + } + + @Override + public boolean isDamageable() { + return true; + } + + @Override + public void addInformation(ItemStack stack,EntityPlayer player, List list, boolean par4) { + AspectList al = this.getVisCost(); + if (al!=null && al.size()>0) { + list.add(StatCollector.translateToLocal(isVisCostPerTick()?"item.Focus.cost2":"item.Focus.cost1")); + for (Aspect aspect:al.getAspectsSorted()) { + DecimalFormat myFormatter = new DecimalFormat("#####.##"); + String amount = myFormatter.format(al.getAmount(aspect)/100f); + list.add(" \u00A7"+aspect.getChatcolor()+aspect.getName()+"\u00A7r x "+ amount); + + } + } + } + + @Override + public int getItemEnchantability() { + return 5; + } + + @Override + public EnumRarity getRarity(ItemStack itemstack) + { + return EnumRarity.rare; + } + + + @Override + public int getFocusColor() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public AspectList getVisCost() { + // TODO Auto-generated method stub + return null; + } + + @Override + public ItemStack onFocusRightClick(ItemStack itemstack, World world, + EntityPlayer player, MovingObjectPosition movingobjectposition) { + // TODO Auto-generated method stub + return null; + } + + @Override + public void onUsingFocusTick(ItemStack itemstack, EntityPlayer player, + int count) { + // TODO Auto-generated method stub + } + + @Override + public void onPlayerStoppedUsingFocus(ItemStack itemstack, World world, + EntityPlayer player, int count) { + // TODO Auto-generated method stub + + } + + /** + * Just insert two alphanumeric characters before this string in your focus item class + */ + @Override + public String getSortingHelper(ItemStack itemstack) { + Map ench = EnchantmentHelper.getEnchantments(itemstack); + String out=""; + for (Integer lvl:ench.values()) { + out = out + lvl + ""; + } + return out; + } + + @Override + public boolean isVisCostPerTick() { + return false; + } + + @Override + public IIcon getOrnament() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean onFocusBlockStartBreak(ItemStack itemstack, int x, int y, + int z, EntityPlayer player) { + // TODO Auto-generated method stub + return false; + } + + @Override + public WandFocusAnimation getAnimation() { + return WandFocusAnimation.WAVE; + } + + @Override + public IIcon getFocusDepthLayerIcon() { + // TODO Auto-generated method stub + return null; + } + + /** + * @see thaumcraft.api.wands.IWandFocus#acceptsEnchant(int) + * By default fortune is off for all wands + **/ + @Override + public boolean acceptsEnchant(int id) { + if (id==ThaumcraftApi.enchantFrugal|| + id==ThaumcraftApi.enchantPotency) return true; + return false; + } + + + + + +} diff --git a/src/main/java/thaumcraft/api/wands/StaffRod.java b/src/main/java/thaumcraft/api/wands/StaffRod.java new file mode 100644 index 0000000..e7ae90f --- /dev/null +++ b/src/main/java/thaumcraft/api/wands/StaffRod.java @@ -0,0 +1,48 @@ +package thaumcraft.api.wands; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +/** + * + * @author Azanor + * + * This class is used to keep the material information for the various rods. + * It is also used to generate the wand recipes ingame. + * + */ +public class StaffRod extends WandRod { + + boolean runes=false; + + public StaffRod(String tag, int capacity, ItemStack item, int craftCost) { + super(tag+"_staff", capacity, item, craftCost); + this.texture = new ResourceLocation("thaumcraft","textures/models/wand_rod_"+tag+".png"); + } + + public StaffRod(String tag, int capacity, ItemStack item, int craftCost, + IWandRodOnUpdate onUpdate, ResourceLocation texture) { + super(tag+"_staff", capacity, item, craftCost, onUpdate, texture); + } + + public StaffRod(String tag, int capacity, ItemStack item, int craftCost, + IWandRodOnUpdate onUpdate) { + super(tag+"_staff", capacity, item, craftCost, onUpdate); + this.texture = new ResourceLocation("thaumcraft","textures/models/wand_rod_"+tag+".png"); + } + + public StaffRod(String tag, int capacity, ItemStack item, int craftCost, + ResourceLocation texture) { + super(tag+"_staff", capacity, item, craftCost, texture); + } + + public boolean hasRunes() { + return runes; + } + + public void setRunes(boolean hasRunes) { + this.runes = hasRunes; + } + + +} diff --git a/src/main/java/thaumcraft/api/wands/WandCap.java b/src/main/java/thaumcraft/api/wands/WandCap.java new file mode 100644 index 0000000..17b4581 --- /dev/null +++ b/src/main/java/thaumcraft/api/wands/WandCap.java @@ -0,0 +1,129 @@ +package thaumcraft.api.wands; + +import java.util.LinkedHashMap; +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import thaumcraft.api.aspects.Aspect; + +/** + * This class is used to keep the material information for the various caps. + * It is also used to generate the wand recipes ingame. + * @author Azanor + * + */ +public class WandCap { + + private String tag; + + /** + * Cost to craft this wand. Combined with the rod cost. + */ + private int craftCost; + + /** + * the amount by which all aspect costs are multiplied + */ + float baseCostModifier; + + /** + * specifies a list of primal aspects that use the special discount figure instead of the normal discount. + */ + List specialCostModifierAspects; + + /** + * the amount by which the specified aspect costs are multiplied + */ + float specialCostModifier; + + /** + * The texture that will be used for the ingame wand cap + */ + ResourceLocation texture; + + /** + * the actual item that makes up this cap and will be used to generate the wand recipes + */ + ItemStack item; + + public static LinkedHashMap caps = new LinkedHashMap(); + + public WandCap (String tag, float discount, ItemStack item, int craftCost) { + this.setTag(tag); + this.baseCostModifier = discount; + this.specialCostModifierAspects = null; + texture = new ResourceLocation("thaumcraft","textures/models/wand_cap_"+getTag()+".png"); + this.item=item; + this.setCraftCost(craftCost); + caps.put(tag, this); + } + + public WandCap (String tag, float discount, List specialAspects, float discountSpecial, ItemStack item, int craftCost) { + this.setTag(tag); + this.baseCostModifier = discount; + this.specialCostModifierAspects = specialAspects; + this.specialCostModifier = discountSpecial; + texture = new ResourceLocation("thaumcraft","textures/models/wand_cap_"+getTag()+".png"); + this.item=item; + this.setCraftCost(craftCost); + caps.put(tag, this); + } + + public float getBaseCostModifier() { + return baseCostModifier; + } + + public List getSpecialCostModifierAspects() { + return specialCostModifierAspects; + } + + public float getSpecialCostModifier() { + return specialCostModifier; + } + + public ResourceLocation getTexture() { + return texture; + } + + public void setTexture(ResourceLocation texture) { + this.texture = texture; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + + public ItemStack getItem() { + return item; + } + + public void setItem(ItemStack item) { + this.item = item; + } + + public int getCraftCost() { + return craftCost; + } + + public void setCraftCost(int craftCost) { + this.craftCost = craftCost; + } + + /** + * The research a player needs to have finished to be able to craft a wand with this cap. + */ + public String getResearch() { + return "CAP_"+getTag(); + } + + // Some examples: + // WandCap WAND_CAP_IRON = new WandCap("iron", 1.1f, Arrays.asList(Aspect.ORDER),1, new ItemStack(ConfigItems.itemWandCap,1,0),1); + // WandCap WAND_CAP_GOLD = new WandCap("gold", 1f, new ItemStack(ConfigItems.itemWandCap,1,1),3); + +} diff --git a/src/main/java/thaumcraft/api/wands/WandRod.java b/src/main/java/thaumcraft/api/wands/WandRod.java new file mode 100644 index 0000000..85954e4 --- /dev/null +++ b/src/main/java/thaumcraft/api/wands/WandRod.java @@ -0,0 +1,158 @@ +package thaumcraft.api.wands; + +import java.util.LinkedHashMap; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; + +/** + * + * @author Azanor + * + * This class is used to keep the material information for the various rods. + * It is also used to generate the wand recipes ingame. + * + */ +public class WandRod { + + + private String tag; + + /** + * Cost to craft this wand. Combined with the rod cost. + */ + private int craftCost; + + /** + * The amount of vis that can be stored - this number is actually multiplied + * by 100 for use by the wands internals + */ + int capacity; + + /** + * The texture that will be used for the ingame wand rod + */ + protected ResourceLocation texture; + + /** + * the actual item that makes up this rod and will be used to generate the wand recipes + */ + ItemStack item; + + /** + * A class that will be called whenever the wand onUpdate tick is run + */ + IWandRodOnUpdate onUpdate; + + /** + * Does the rod glow in the dark? + */ + boolean glow; + + public static LinkedHashMap rods = new LinkedHashMap(); + + public WandRod (String tag, int capacity, ItemStack item, int craftCost, ResourceLocation texture) { + this.setTag(tag); + this.capacity = capacity; + this.texture = texture; + this.item=item; + this.setCraftCost(craftCost); + rods.put(tag, this); + } + + public WandRod (String tag, int capacity, ItemStack item, int craftCost, IWandRodOnUpdate onUpdate, ResourceLocation texture) { + this.setTag(tag); + this.capacity = capacity; + this.texture = texture; + this.item=item; + this.setCraftCost(craftCost); + rods.put(tag, this); + this.onUpdate = onUpdate; + } + + public WandRod (String tag, int capacity, ItemStack item, int craftCost) { + this.setTag(tag); + this.capacity = capacity; + this.texture = new ResourceLocation("thaumcraft","textures/models/wand_rod_"+getTag()+".png"); + this.item=item; + this.setCraftCost(craftCost); + rods.put(tag, this); + } + + public WandRod (String tag, int capacity, ItemStack item, int craftCost, IWandRodOnUpdate onUpdate) { + this.setTag(tag); + this.capacity = capacity; + this.texture = new ResourceLocation("thaumcraft","textures/models/wand_rod_"+getTag()+".png"); + this.item=item; + this.setCraftCost(craftCost); + rods.put(tag, this); + this.onUpdate = onUpdate; + } + + public String getTag() { + return tag; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public int getCapacity() { + return capacity; + } + + public void setCapacity(int capacity) { + this.capacity = capacity; + } + + public ResourceLocation getTexture() { + return texture; + } + + public void setTexture(ResourceLocation texture) { + this.texture = texture; + } + + public ItemStack getItem() { + return item; + } + + public void setItem(ItemStack item) { + this.item = item; + } + + public int getCraftCost() { + return craftCost; + } + + public void setCraftCost(int craftCost) { + this.craftCost = craftCost; + } + + public IWandRodOnUpdate getOnUpdate() { + return onUpdate; + } + + public void setOnUpdate(IWandRodOnUpdate onUpdate) { + this.onUpdate = onUpdate; + } + + public boolean isGlowing() { + return glow; + } + + public void setGlowing(boolean hasGlow) { + this.glow = hasGlow; + } + + /** + * The research a player needs to have finished to be able to craft a wand with this rod. + */ + public String getResearch() { + return "ROD_"+getTag(); + } + + // Some examples: + // WandRod WAND_ROD_WOOD = new WandRod("wood",25,new ItemStack(Item.stick),1); + // WandRod WAND_ROD_BLAZE = new WandRod("blaze",100,new ItemStack(Item.blazeRod),7,new WandRodBlazeOnUpdate()); +} diff --git a/src/main/java/thaumcraft/api/wands/WandTriggerRegistry.java b/src/main/java/thaumcraft/api/wands/WandTriggerRegistry.java new file mode 100644 index 0000000..7224e12 --- /dev/null +++ b/src/main/java/thaumcraft/api/wands/WandTriggerRegistry.java @@ -0,0 +1,126 @@ +package thaumcraft.api.wands; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** + * This class serves a similar function to IWandable in that it allows wands to interact + * with object in the world. In this case it is most useful for adding interaction with non-mod + * blocks where you can't control what happens in their code. + * Example where it is used is in crafting the thaumonomicon from a bookshelf and the + * crucible from a cauldron + * + * @author azanor + * + */ +public class WandTriggerRegistry { + + private static HashMap> triggers = new HashMap>(); + private static final String DEFAULT = "default"; + + /** + * Registers an action to perform when a casting wand right clicks on a specific block. + * A manager class needs to be created that implements IWandTriggerManager. + * @param manager + * @param event a logical number that you can use to differentiate different events or actions + * @param block + * @param meta send -1 as a wildcard value for all possible meta values + * @param modid a unique identifier. It is best to register your own triggers using your mod id to avoid conflicts with mods that register triggers for the same block + */ + public static void registerWandBlockTrigger(IWandTriggerManager manager, int event, Block block, int meta, String modid) { + if (!triggers.containsKey(modid)) { + triggers.put(modid, new HashMap()); + } + HashMap temp = triggers.get(modid); + temp.put(Arrays.asList(block,meta),Arrays.asList(manager,event)); + triggers.put(modid, temp); + } + + /** + * for legacy support + */ + public static void registerWandBlockTrigger(IWandTriggerManager manager, int event, Block block, int meta) { + registerWandBlockTrigger(manager, event, block, meta, DEFAULT); + } + + /** + * Checks all trigger registries if one exists for the given block and meta + * @param block + * @param meta + * @return + */ + public static boolean hasTrigger(Block block, int meta) { + for (String modid:triggers.keySet()) { + HashMap temp = triggers.get(modid); + if (temp.containsKey(Arrays.asList(block,meta)) || + temp.containsKey(Arrays.asList(block,-1))) return true; + } + return false; + } + + /** + * modid sensitive version + */ + public static boolean hasTrigger(Block block, int meta, String modid) { + if (!triggers.containsKey(modid)) return false; + HashMap temp = triggers.get(modid); + if (temp.containsKey(Arrays.asList(block,meta)) || + temp.containsKey(Arrays.asList(block,-1))) return true; + return false; + } + + + /** + * This is called by the onItemUseFirst function in wands. + * Parameters and return value functions like you would expect for that function. + * @param world + * @param wand + * @param player + * @param x + * @param y + * @param z + * @param side + * @param block + * @param meta + * @return + */ + public static boolean performTrigger(World world, ItemStack wand, EntityPlayer player, + int x, int y, int z, int side, Block block, int meta) { + + for (String modid:triggers.keySet()) { + HashMap temp = triggers.get(modid); + List l = temp.get(Arrays.asList(block,meta)); + if (l==null) l = temp.get(Arrays.asList(block,-1)); + if (l==null) continue; + + IWandTriggerManager manager = (IWandTriggerManager) l.get(0); + int event = (Integer) l.get(1); + boolean result = manager.performTrigger(world, wand, player, x, y, z, side, event); + if (result) return true; + } + return false; + } + + /** + * modid sensitive version + */ + public static boolean performTrigger(World world, ItemStack wand, EntityPlayer player, + int x, int y, int z, int side, Block block, int meta, String modid) { + if (!triggers.containsKey(modid)) return false; + HashMap temp = triggers.get(modid); + List l = temp.get(Arrays.asList(block,meta)); + if (l==null) l = temp.get(Arrays.asList(block,-1)); + if (l==null) return false; + + IWandTriggerManager manager = (IWandTriggerManager) l.get(0); + int event = (Integer) l.get(1); + return manager.performTrigger(world, wand, player, x, y, z, side, event); + } + +} diff --git a/src/main/java/vazkii/botania/api/BotaniaAPI.java b/src/main/java/vazkii/botania/api/BotaniaAPI.java new file mode 100644 index 0000000..36f5aa5 --- /dev/null +++ b/src/main/java/vazkii/botania/api/BotaniaAPI.java @@ -0,0 +1,363 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 14, 2014, 6:15:28 PM (GMT)] + */ +package vazkii.botania.api; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.Item; +import net.minecraft.item.Item.ToolMaterial; +import net.minecraft.item.ItemArmor.ArmorMaterial; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.CraftingManager; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.EnumChatFormatting; +import net.minecraftforge.common.util.EnumHelper; +import vazkii.botania.api.internal.DummyMethodHandler; +import vazkii.botania.api.internal.DummySubTile; +import vazkii.botania.api.internal.IInternalMethodHandler; +import vazkii.botania.api.lexicon.KnowledgeType; +import vazkii.botania.api.lexicon.LexiconCategory; +import vazkii.botania.api.lexicon.LexiconEntry; +import vazkii.botania.api.recipe.RecipeElvenTrade; +import vazkii.botania.api.recipe.RecipeManaInfusion; +import vazkii.botania.api.recipe.RecipePetals; +import vazkii.botania.api.recipe.RecipeRuneAltar; +import vazkii.botania.api.subtile.SubTileEntity; +import vazkii.botania.api.wiki.IWikiProvider; +import vazkii.botania.api.wiki.SimpleWikiProvider; +import vazkii.botania.api.wiki.WikiHooks; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; + +public final class BotaniaAPI { + + private static List categories = new ArrayList(); + private static List allEntries = new ArrayList(); + + public static Map knowledgeTypes = new HashMap(); + + public static List petalRecipes = new ArrayList(); + public static List runeAltarRecipes = new ArrayList(); + public static List manaInfusionRecipes = new ArrayList(); + public static List elvenTradeRecipes = new ArrayList(); + + private static BiMap> subTiles = HashBiMap.> create(); + public static Set subtilesForCreativeMenu = new LinkedHashSet(); + + public static Map oreWeights = new HashMap(); + + public static Map seeds = new HashMap(); + + public static ArmorMaterial manasteelArmorMaterial = EnumHelper.addArmorMaterial("MANASTEEL", 16, new int[] { 2, 6, 5, 2 }, 18); + public static ToolMaterial manasteelToolMaterial = EnumHelper.addToolMaterial("MANASTEEL", 3, 300, 6.2F, 2F, 20); + + public static ArmorMaterial elementiumArmorMaterial = EnumHelper.addArmorMaterial("B_ELEMENTIUM", 18, new int[] { 2, 6, 5, 2 }, 18); + public static ToolMaterial elementiumToolMaterial = EnumHelper.addToolMaterial("B_ELEMENTIUM", 3, 720, 6.2F, 2F, 20); + + public static ArmorMaterial terrasteelArmorMaterial = EnumHelper.addArmorMaterial("TERRASTEEL", 34, new int[] {3, 8, 6, 3}, 26); + public static ToolMaterial terrasteelToolMaterial = EnumHelper.addToolMaterial("TERRASTEEL", 3, 2300, 9F, 3F, 26); + + public static KnowledgeType basicKnowledge, elvenKnowledge; + + static { + registerSubTile("", DummySubTile.class); + + basicKnowledge = registerKnowledgeType("minecraft", EnumChatFormatting.RESET, true); + elvenKnowledge = registerKnowledgeType("alfheim", EnumChatFormatting.DARK_GREEN, false); + + addOreWeight("oreAluminum", 3940); // Tinkers' Construct + addOreWeight("oreAmber", 2075); // Thaumcraft + addOreWeight("oreApatite", 1595); // Forestry + addOreWeight("oreBlueTopaz", 3195); // Ars Magica + addOreWeight("oreCassiterite", 1634); // GregTech + addOreWeight("oreCertusQuartz", 3975); // Applied Energistics + addOreWeight("oreChimerite", 3970); // Ars Magica + addOreWeight("oreCinnabar", 2585); // Thaumcraft + addOreWeight("oreCoal", 46525); // Vanilla + addOreWeight("oreCooperite", 5); // GregTech + addOreWeight("oreCopper", 8325); // IC2, Thermal Expansion, Tinkers' Construct, etc. + addOreWeight("oreDarkIron", 1700); // Factorization + addOreWeight("oreDiamond", 1265); // Vanilla + addOreWeight("oreEmerald", 780); // Vanilla + addOreWeight("oreEmery", 415); // GregTech + addOreWeight("oreGalena", 1000); // Factorization + addOreWeight("oreGold", 2970); // Vanilla + addOreWeight("oreInfusedAir", 925); // Thaumcraft + addOreWeight("oreInfusedEarth", 925); // Thaumcraft + addOreWeight("oreInfusedEntropy", 925); // Thaumcraft + addOreWeight("oreInfusedFire", 925); // Thaumcraft + addOreWeight("oreInfusedOrder", 925); // Thaumcraft + addOreWeight("oreInfusedWater", 925); // Thaumcraft + addOreWeight("oreIridium", 30); // GregTech + addOreWeight("oreIron", 20665); // Vanilla + addOreWeight("oreLapis", 1285); // Vanilla + addOreWeight("oreLead", 7985); // IC2, Thermal Expansion, Factorization, etc. + addOreWeight("oreMCropsEssence", 3085); // Magical Crops + addOreWeight("oreNickel", 2275); // Thermal Expansion + addOreWeight("oreOlivine", 1100); // Project RED + addOreWeight("oreRedstone", 6885); // Vanilla + addOreWeight("oreRuby", 1100); // Project RED + addOreWeight("oreSapphire", 1100); // Project RED + addOreWeight("oreSilver", 6300); // Thermal Expansion, Factorization, etc. + addOreWeight("oreSphalerite", 25); // GregTech + addOreWeight("oreSulfur", 1105); // Railcraft + addOreWeight("oreTetrahedrite", 4040); // GregTech + addOreWeight("oreTin", 9450); // IC2, Thermal Expansion, etc. + addOreWeight("oreTungstate", 20); // GregTech + addOreWeight("oreUranium", 1337); // IC2 + addOreWeight("oreVinteum", 5925); // Ars Magica + addOreWeight("oreYellorite", 3520); // Big Reactors + addOreWeight("oreZinc", 6485); // Flaxbeard's Steam Power + + addSeed(Items.wheat_seeds, Blocks.wheat); + addSeed(Items.potato, Blocks.potatoes); + addSeed(Items.carrot, Blocks.carrots); + addSeed(Items.nether_wart, Blocks.nether_wart); + addSeed(Items.pumpkin_seeds, Blocks.pumpkin_stem); + addSeed(Items.melon_seeds, Blocks.melon_stem); + + registerModWiki("Minecraft", new SimpleWikiProvider("Minecraft Wiki", "http://minecraft.gamepedia.com/%s")); + + IWikiProvider technicWiki = new SimpleWikiProvider("Technic Wiki", "http://wiki.technicpack.net/%s"); + IWikiProvider mekanismWiki = new SimpleWikiProvider("Mekanism Wiki", "http://wiki.aidancbrady.com/wiki/%s"); + IWikiProvider buildcraftWiki = new SimpleWikiProvider("BuildCraft Wiki", "http://www.mod-buildcraft.com/wiki/doku.php?id=%s"); + + registerModWiki("Mekanism", mekanismWiki); + registerModWiki("MekanismGenerators", mekanismWiki); + registerModWiki("MekanismTools", mekanismWiki); + registerModWiki("EnderIO", new SimpleWikiProvider("EnderIO Wiki", "http://wiki.enderio.com/%s")); + registerModWiki("TropiCraft", new SimpleWikiProvider("Tropicraft Wiki", "http://wiki.tropicraft.net/wiki/%s")); + registerModWiki("RandomThings", new SimpleWikiProvider("Random Things Wiki", "http://randomthingsminecraftmod.wikispaces.com/%s")); + registerModWiki("Witchery", new SimpleWikiProvider("Witchery Wiki", "https://sites.google.com/site/witcherymod/%s", "-")); + registerModWiki("AppliedEnergistics2", new SimpleWikiProvider("AE2 Wiki", "http://ae-mod.info/%s")); + registerModWiki("BigReactors", technicWiki); + registerModWiki("BuildCraft|Core", buildcraftWiki); + registerModWiki("BuildCraft|Builders", buildcraftWiki); + registerModWiki("BuildCraft|Energy", buildcraftWiki); + registerModWiki("BuildCraft|Factory", buildcraftWiki); + registerModWiki("BuildCraft|Silicon", buildcraftWiki); + registerModWiki("BuildCraft|Transport", buildcraftWiki); + registerModWiki("ArsMagica2", new SimpleWikiProvider("ArsMagica2 Wiki", "http://wiki.arsmagicamod.com/wiki/%s")); + registerModWiki("PneumaticCraft", new SimpleWikiProvider("PneumaticCraft Wiki", "http://www.minemaarten.com/wikis/pneumaticcraft-wiki/pneumaticcraft-wiki-%s")); + registerModWiki("StevesCarts2", new SimpleWikiProvider("Steve's Carts Wiki", "http://stevescarts2.wikispaces.com/%s")); + registerModWiki("GanysSurface", new SimpleWikiProvider("Gany's Surface Wiki", "http://ganys-surface.wikia.com/wiki/%s")); + registerModWiki("GanysNether", new SimpleWikiProvider("Gany's Nether Wiki", "http://ganys-nether.wikia.com/wiki/%s")); + registerModWiki("GanysEnd", new SimpleWikiProvider("Gany's End Wiki", "http://ganys-end.wikia.com/wiki/%s")); + } + + /** + * The internal method handler in use. Do not overwrite. + * @see IInternalMethodHandler + */ + public static IInternalMethodHandler internalHandler = new DummyMethodHandler(); + + + /** + * Registers a new Knowledge Type. + * @param id The ID for this knowledge type. + * @param color The color to display this knowledge type as. + */ + public static KnowledgeType registerKnowledgeType(String id, EnumChatFormatting color, boolean autoUnlock) { + KnowledgeType type = new KnowledgeType(id, color, autoUnlock); + knowledgeTypes.put(id, type); + return type; + } + + /** + * Registers a Petal Recipe. + * @param output The ItemStack to craft. + * @param inputs The objects for crafting. Can be ItemStack, MappableStackWrapper + * or String (case for Ore Dictionary). The array can't be larger than 16. + * @return The recipe created. + */ + public static RecipePetals registerPetalRecipe(ItemStack output, Object... inputs) { + RecipePetals recipe = new RecipePetals(output, inputs); + petalRecipes.add(recipe); + return recipe; + } + + /** + * Registers a Rune Altar + * @param output The ItemStack to craft. + * @param mana The amount of mana required. Don't go over 100000! + * @param inputs The objects for crafting. Can be ItemStack, MappableStackWrapper + * or String (case for Ore Dictionary). The array can't be larger than 16. + * @return The recipe created. + */ + public static RecipeRuneAltar registerRuneAltarRecipe(ItemStack output, int mana, Object... inputs) { + RecipeRuneAltar recipe = new RecipeRuneAltar(output, mana, inputs); + runeAltarRecipes.add(recipe); + return recipe; + } + + /** + * Registers a Mana Infusion Recipe (throw an item in a mana pool) + * @param output The ItemStack to craft + * @param input The input item, be it an ItemStack or an ore dictionary entry String. + * @param mana The amount of mana required. Don't go over 100000! + * @return The recipe created. + */ + public static RecipeManaInfusion registerManaInfusionRecipe(ItemStack output, Object input, int mana) { + RecipeManaInfusion recipe = new RecipeManaInfusion(output, input, mana); + manaInfusionRecipes.add(recipe); + return recipe; + } + + /** + * Register a Mana Infusion Recipe and flags it as an Alchemy recipe (requires an + * Alchemy Catalyst below the pool). + * @see BotaniaAPI#registerManaInfusionRecipe + */ + public static RecipeManaInfusion registerManaAlchemyRecipe(ItemStack output, Object input, int mana) { + RecipeManaInfusion recipe = registerManaInfusionRecipe(output, input, mana); + recipe.setAlchemy(true); + return recipe; + } + + /** + * Register a Mana Infusion Recipe and flags it as an Conjuration recipe (requires a + * Conjuration Catalyst below the pool). + * @see BotaniaAPI#registerManaInfusionRecipe + */ + public static RecipeManaInfusion registerManaConjurationRecipe(ItemStack output, Object input, int mana) { + RecipeManaInfusion recipe = registerManaInfusionRecipe(output, input, mana); + recipe.setConjuration(true); + return recipe; + } + + /** + * Registers a Elven Trade recipe (throw an item in an Alfheim Portal). + * @param output The ItemStack to return. + * @param inputs The items required, can be ItemStack or ore dictionary entry string. + * @return The recipe created. + */ + public static RecipeElvenTrade registerElvenTradeRecipe(ItemStack output, Object... inputs) { + RecipeElvenTrade recipe = new RecipeElvenTrade(output, inputs); + elvenTradeRecipes.add(recipe); + return recipe; + } + + /** + * Registers a SubTileEntity, a new special flower. Look in the subtile package of the API. + */ + public static void registerSubTile(String key, Class subtileClass) { + subTiles.put(key, subtileClass); + } + + /** + * Adds the key for a SubTileEntity into the creative menu. This goes into the + * subtilesForCreativeMenu Set. + */ + public static void addSubTileToCreativeMenu(String key) { + subtilesForCreativeMenu.add(key); + } + + /** + * Adds a category to the list of registered categories to appear in the Lexicon. + */ + public static void addCategory(LexiconCategory category) { + categories.add(category); + } + + /** + * Gets all registered categories. + */ + public static List getAllCategories() { + return categories; + } + + /** + * Gets all registered entries. + */ + public static List getAllEntries() { + return allEntries; + } + + /** + * Registers a Lexicon Entry and adds it to the category passed in. + */ + public static void addEntry(LexiconEntry entry, LexiconCategory category) { + allEntries.add(entry); + category.entries.add(entry); + } + + /** + * Maps an ore (ore dictionary key) to it's weight on the world generation. This + * is used for the Orechid flower. Check the static block in the BotaniaAPI class + * to get the weights for the vanilla blocks.
+ * Alternatively get the values with the OreDetector mod:
+ * https://gist.github.com/Vazkii/9493322 + */ + public static void addOreWeight(String ore, int weight) { + oreWeights.put(ore, weight); + } + + public static int getOreWeight(String ore) { + return oreWeights.get(ore); + } + + /** + * Allows an item to be counted as a seed. Any item in this list can be + * dispensed by a dispenser, the block is the block to be placed. + */ + public static void addSeed(Item item, Block block) { + seeds.put(item, block); + } + + /** + * Gets the last recipe to have been added to the recipe list. + */ + public static IRecipe getLatestAddedRecipe() { + List list = CraftingManager.getInstance().getRecipeList(); + return list.get(list.size() - 1); + } + + /** + * Gets the last x recipes added to the recipe list. + */ + public static List getLatestAddedRecipes(int x) { + List list = CraftingManager.getInstance().getRecipeList(); + List newList = new ArrayList(); + for(int i = x - 1; i >= 0; i--) + newList.add(list.get(list.size() - 1 - i)); + + return newList; + } + + /** + * Registers a Wiki provider for a mod so it uses that instead of the fallback + * FTB wiki. Make sure to call this on PostInit only! + */ + public static void registerModWiki(String mod, IWikiProvider provider) { + WikiHooks.registerModWiki(mod, provider); + } + + public static Class getSubTileMapping(String key) { + if(!subTiles.containsKey(key)) + key = ""; + + return subTiles.get(key); + } + + public static String getSubTileStringMapping(Class clazz) { + return subTiles.inverse().get(clazz); + } +} diff --git a/src/main/java/vazkii/botania/api/internal/DummyManaNetwork.java b/src/main/java/vazkii/botania/api/internal/DummyManaNetwork.java new file mode 100644 index 0000000..53a8e42 --- /dev/null +++ b/src/main/java/vazkii/botania/api/internal/DummyManaNetwork.java @@ -0,0 +1,51 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Mar 7, 2014, 3:47:43 PM (GMT)] + */ +package vazkii.botania.api.internal; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.world.World; +import vazkii.botania.api.mana.TileSignature; + +public class DummyManaNetwork implements IManaNetwork { + + public static final DummyManaNetwork instance = new DummyManaNetwork(); + + @Override + public void clear() { + // NO-OP + } + + @Override + public TileEntity getClosestPool(ChunkCoordinates pos, World world, int limit) { + return null; + } + + @Override + public TileEntity getClosestCollector(ChunkCoordinates pos, World world, int limit) { + return null; + } + + @Override + public List getAllCollectorsInWorld(World world) { + return new ArrayList(); + } + + @Override + public List getAllPoolsInWorld(World world) { + return new ArrayList(); + } + +} diff --git a/src/main/java/vazkii/botania/api/internal/DummyMethodHandler.java b/src/main/java/vazkii/botania/api/internal/DummyMethodHandler.java new file mode 100644 index 0000000..29675d6 --- /dev/null +++ b/src/main/java/vazkii/botania/api/internal/DummyMethodHandler.java @@ -0,0 +1,130 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 14, 2014, 6:43:03 PM (GMT)] + */ +package vazkii.botania.api.internal; + +import java.util.List; + +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; +import vazkii.botania.api.lexicon.LexiconPage; +import vazkii.botania.api.recipe.RecipeElvenTrade; +import vazkii.botania.api.recipe.RecipeManaInfusion; +import vazkii.botania.api.recipe.RecipePetals; +import vazkii.botania.api.recipe.RecipeRuneAltar; + +public class DummyMethodHandler implements IInternalMethodHandler { + + @Override + public LexiconPage textPage(String key) { + return dummyPage(key); + } + + @Override + public LexiconPage imagePage(String key, String resource) { + return dummyPage(key); + } + + @Override + public LexiconPage craftingRecipesPage(String key, List recipes) { + return dummyPage(key); + } + + @Override + public LexiconPage craftingRecipePage(String key, IRecipe recipe) { + return dummyPage(key); + } + + @Override + public LexiconPage petalRecipesPage(String key, List recipes) { + return dummyPage(key); + } + + @Override + public LexiconPage petalRecipePage(String key, RecipePetals recipe) { + return dummyPage(key); + } + + @Override + public LexiconPage runeRecipesPage(String key, List recipes) { + return dummyPage(key); + } + + @Override + public LexiconPage runeRecipePage(String key, RecipeRuneAltar recipe) { + return dummyPage(key); + } + + @Override + public LexiconPage manaInfusionRecipesPage(String key, List recipes) { + return dummyPage(key); + } + + @Override + public LexiconPage manaInfusionRecipePage(String key, RecipeManaInfusion recipe) { + return dummyPage(key); + } + + @Override + public LexiconPage elvenTradePage(String key, List recipes) { + return dummyPage(key); + } + + @Override + public LexiconPage elvenTradesPage(String key, RecipeElvenTrade recipe) { + return dummyPage(key); + } + + private LexiconPage dummyPage(String key) { + return new DummyPage(key); + } + + @Override + public ItemStack getSubTileAsStack(String subTile) { + return new ItemStack(Blocks.stone, 0, 0); + } + + @Override + public IIcon getSubTileIconForName(String name) { + return Blocks.red_flower.getIcon(0, 0); + } + + @Override + public IManaNetwork getManaNetworkInstance() { + return DummyManaNetwork.instance; + } + + @Override + public void drawSimpleManaHUD(int color, int mana, int maxMana, String name, ScaledResolution res) { + // NO-OP + } + + @Override + public void sparkleFX(World world, double x, double y, double z, float r, float g, float b, float size, int m) { + // NO-OP + } + + @Override + public IInventory getBaublesInventory(EntityPlayer player) { + return null; + } + + @Override + public boolean shouldForceCheck() { + return true; + } +} diff --git a/src/main/java/vazkii/botania/api/internal/DummyPage.java b/src/main/java/vazkii/botania/api/internal/DummyPage.java new file mode 100644 index 0000000..33cbcf8 --- /dev/null +++ b/src/main/java/vazkii/botania/api/internal/DummyPage.java @@ -0,0 +1,35 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 14, 2014, 6:41:23 PM (GMT)] + */ +package vazkii.botania.api.internal; + +import vazkii.botania.api.lexicon.LexiconPage; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * A dummy page. It does absolutely nothing and is only + * existant to make sure everything goes right even if + * Botania isn't loaded. + */ +public class DummyPage extends LexiconPage { + + public DummyPage(String unlocalizedName) { + super(unlocalizedName); + } + + @Override + @SideOnly(Side.CLIENT) + public void renderScreen(IGuiLexiconEntry gui, int x, int y) { + // NO-OP + } + +} diff --git a/src/main/java/vazkii/botania/api/internal/DummySubTile.java b/src/main/java/vazkii/botania/api/internal/DummySubTile.java new file mode 100644 index 0000000..d23adce --- /dev/null +++ b/src/main/java/vazkii/botania/api/internal/DummySubTile.java @@ -0,0 +1,18 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 24, 2014, 4:17:33 PM (GMT)] + */ +package vazkii.botania.api.internal; + +import vazkii.botania.api.subtile.SubTileEntity; + +public class DummySubTile extends SubTileEntity { + +} diff --git a/src/main/java/vazkii/botania/api/internal/IGuiLexiconEntry.java b/src/main/java/vazkii/botania/api/internal/IGuiLexiconEntry.java new file mode 100644 index 0000000..c8bf6da --- /dev/null +++ b/src/main/java/vazkii/botania/api/internal/IGuiLexiconEntry.java @@ -0,0 +1,57 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 14, 2014, 6:48:41 PM (GMT)] + */ +package vazkii.botania.api.internal; + +import vazkii.botania.api.lexicon.LexiconEntry; + +/** + * Internal interface for the Lexicon Entry GUI. This contains + * everything that can be accessed from it. It's safe to cast + * this type to GuiScreen. + */ +public interface IGuiLexiconEntry { + + /** + * Gets the entry currently portrayed in this gui. + */ + public LexiconEntry getEntry(); + + /** + * Gets the current page the lexicon GUI is browsing. + */ + public int getPageOn(); + + /** + * Gets the leftmost part of the GUI. + */ + public int getLeft(); + + /** + * Gets the topmost part of the GUI. + */ + public int getTop(); + + /** + * Gets the GUI's width. + */ + public int getWidth(); + + /** + * Gets the GUI's height + */ + public int getHeight(); + + /** + * Gets the GUI's Z level for rendering. + */ + public float getZLevel(); +} diff --git a/src/main/java/vazkii/botania/api/internal/IInternalMethodHandler.java b/src/main/java/vazkii/botania/api/internal/IInternalMethodHandler.java new file mode 100644 index 0000000..fa1934a --- /dev/null +++ b/src/main/java/vazkii/botania/api/internal/IInternalMethodHandler.java @@ -0,0 +1,79 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 14, 2014, 6:34:34 PM (GMT)] + */ +package vazkii.botania.api.internal; + +import java.util.List; + +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.IIcon; +import net.minecraft.world.World; +import vazkii.botania.api.lexicon.LexiconPage; +import vazkii.botania.api.recipe.RecipeElvenTrade; +import vazkii.botania.api.recipe.RecipeManaInfusion; +import vazkii.botania.api.recipe.RecipePetals; +import vazkii.botania.api.recipe.RecipeRuneAltar; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * Any methods that refer to internal methods in Botania are here. + * This is defaulted to a dummy handler, whose methods do nothing. + * This handler is set to a proper one on PreInit. Make sure to + * make your mod load after Botania if you have any intention of + * doing anythign with this on PreInit. + */ +public interface IInternalMethodHandler { + + public LexiconPage textPage(String key); + + public LexiconPage imagePage(String key, String resource); + + public LexiconPage craftingRecipesPage(String key, List recipes); + + public LexiconPage craftingRecipePage(String key, IRecipe recipe); + + public LexiconPage petalRecipesPage(String key, List recipes); + + public LexiconPage petalRecipePage(String key, RecipePetals recipe); + + public LexiconPage runeRecipesPage(String key, List recipes); + + public LexiconPage runeRecipePage(String key, RecipeRuneAltar recipe); + + public LexiconPage manaInfusionRecipesPage(String key, List recipes); + + public LexiconPage manaInfusionRecipePage(String key, RecipeManaInfusion recipe); + + public LexiconPage elvenTradePage(String key, List recipes); + + public LexiconPage elvenTradesPage(String key, RecipeElvenTrade recipe); + + public IManaNetwork getManaNetworkInstance(); + + public ItemStack getSubTileAsStack(String subTile); + + public IIcon getSubTileIconForName(String name); + + public boolean shouldForceCheck(); + + public IInventory getBaublesInventory(EntityPlayer player); + + @SideOnly(Side.CLIENT) + public void drawSimpleManaHUD(int color, int mana, int maxMana, String name, ScaledResolution res); + + public void sparkleFX(World world, double x, double y, double z, float r, float g, float b, float size, int m); + +} diff --git a/src/main/java/vazkii/botania/api/internal/IManaBurst.java b/src/main/java/vazkii/botania/api/internal/IManaBurst.java new file mode 100644 index 0000000..38c5fd8 --- /dev/null +++ b/src/main/java/vazkii/botania/api/internal/IManaBurst.java @@ -0,0 +1,62 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 31, 2014, 4:36:13 PM (GMT)] + */ +package vazkii.botania.api.internal; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.ChunkCoordinates; + +/** + * Interface for the Mana Burst entity. This can safely be casted to EntityThrowable. + */ +public interface IManaBurst { + + public boolean isFake(); + + public void setMotion(double x, double y, double z); + + public int getColor(); + + public void setColor(int color); + + public int getMana(); + + public void setMana(int mana); + + public int getStartingMana(); + + public void setStartingMana(int mana); + + public int getMinManaLoss(); + + public void setMinManaLoss(int minManaLoss); + + public float getManaLossPerTick(); + + public void setManaLossPerTick(float mana); + + public float getGravity(); + + public void setGravity(float gravity); + + public ChunkCoordinates getBurstSourceChunkCoordinates(); + + public void setBurstSourceCoords(int x, int y, int z); + + public ItemStack getSourceLens(); + + public void setSourceLens(ItemStack lens); + + public boolean hasAlreadyCollidedAt(int x, int y, int z); + + public int getTicksExisted(); + +} diff --git a/src/main/java/vazkii/botania/api/internal/IManaNetwork.java b/src/main/java/vazkii/botania/api/internal/IManaNetwork.java new file mode 100644 index 0000000..38e9419 --- /dev/null +++ b/src/main/java/vazkii/botania/api/internal/IManaNetwork.java @@ -0,0 +1,68 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Mar 7, 2014, 3:39:48 PM (GMT)] + */ +package vazkii.botania.api.internal; + +import java.util.List; + +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.world.World; +import vazkii.botania.api.mana.TileSignature; + +/** + * A basic interface for a world's Mana Network. + * @see IInternalMethodHandler#getManaNetworkInstance() + */ +public interface IManaNetwork { + + /** + * Clears the entire Mana Network of all it's contents, you probably + * don't want to call this unless you have a very good reason. + */ + public void clear(); + + /** + * Gets the closest Mana Collector (eg. Mana Spreader) in the network to the Chunk + * Coordinates passed in, in the given dimension.
+ * A way of getting the dimension is via worldObj.provider.dimensionId
+ * Note that this function *can* get performance intensive, it's reccomended you + * call it sparingly and take cache of the value returned. + * @param limit The maximum distance the closest block can be, if the closest block + * is farther away than that, null will be returned instead. + */ + public TileEntity getClosestCollector(ChunkCoordinates pos, World world, int limit); + + /** + * Gets the closest Mana Pool in the network to the Chunk Coordinates passed in, + * in the given dimension.
+ * A way of getting the dimension is via worldObj.provider.dimensionId
+ * Note that this function *can* get performance intensive, it's reccomended you + * call it sparingly and take cache of the value returned. + * @param limit The maximum distance the closest block can be, if the closest block + * is farther away than that, null will be returned instead. + */ + public TileEntity getClosestPool(ChunkCoordinates pos, World world, int limit); + + /** + * Gets the list of all Mana Collectors (eg. Mana Spreader) in the dimension + * passed in. Note that this is the actual list and not a copy, make sure to + * clone the list if you intend to change it in any way. + */ + public List getAllCollectorsInWorld(World world); + + /** + * Gets the list of all Mana Pools in the dimension passed in. Note that this + * is the actual list and not a copy, make sure to clone the list if you intend + * to change it in any way. + */ + public List getAllPoolsInWorld(World world); +} diff --git a/src/main/java/vazkii/botania/api/item/IExoflameHeatable.java b/src/main/java/vazkii/botania/api/item/IExoflameHeatable.java new file mode 100644 index 0000000..eb4815c --- /dev/null +++ b/src/main/java/vazkii/botania/api/item/IExoflameHeatable.java @@ -0,0 +1,44 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Aug 30, 2014, 4:28:29 PM (GMT)] + */ +package vazkii.botania.api.item; + +/** + * A TileEntity that implements this can be heated by an Exoflame flower. + */ +public interface IExoflameHeatable { + + /** + * Can this TileEntity smelt its contents. If true, the Exoflame is allowed + * to fuel it. + */ + public boolean canSmelt(); + + /** + * Gets the amount of ticks left for the fuel. If below 2, the exoflame + * will call boostBurnTime. + */ + public int getBurnTime(); + + /** + * Called to increase the amount of time this furnace should be burning + * the fuel for. Even if it doesn't have any fuel. + */ + public void boostBurnTime(); + + /** + * Called once every two ticks to increase the speed of the furnace. Feel + * free to not do anything if all you want is to allow the exoflame to feed + * it, not make it faster. + */ + public void boostCookTime(); + +} diff --git a/src/main/java/vazkii/botania/api/item/IExtendedPlayerController.java b/src/main/java/vazkii/botania/api/item/IExtendedPlayerController.java new file mode 100644 index 0000000..67db3e6 --- /dev/null +++ b/src/main/java/vazkii/botania/api/item/IExtendedPlayerController.java @@ -0,0 +1,29 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Aug 6, 2014, 6:02:29 PM (GMT)] + */ +package vazkii.botania.api.item; + +/** + * An interface that defines an instance of PlayerControllerMP with + * the ability to modify reach. See vazkii.botania.client.core.handler.BotaniaPlayerController + */ +public interface IExtendedPlayerController { + + /** + * Sets the extra reach the player should have. + */ + public void setReachDistanceExtension(float f); + + /** + * Gets the current reach extension. + */ + public float getReachDistanceExtension(); +} diff --git a/src/main/java/vazkii/botania/api/item/IPetalApothecary.java b/src/main/java/vazkii/botania/api/item/IPetalApothecary.java new file mode 100644 index 0000000..d96f73f --- /dev/null +++ b/src/main/java/vazkii/botania/api/item/IPetalApothecary.java @@ -0,0 +1,30 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Aug 30, 2014, 4:22:15 PM (GMT)] + */ +package vazkii.botania.api.item; + +/** + * Base Interface for the Petal Apothecary block. Can + * be safely casted to TileEntity. + */ +public interface IPetalApothecary { + + /** + * Sets if the the apothecary has water or not. + */ + public void setWater(boolean water); + + /** + * Does the apothecary have water in it? + */ + public boolean hasWater(); + +} diff --git a/src/main/java/vazkii/botania/api/item/IPixieSpawner.java b/src/main/java/vazkii/botania/api/item/IPixieSpawner.java new file mode 100644 index 0000000..c0d47f8 --- /dev/null +++ b/src/main/java/vazkii/botania/api/item/IPixieSpawner.java @@ -0,0 +1,30 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Aug 6, 2014, 6:06:27 PM (GMT)] + */ +package vazkii.botania.api.item; + +import net.minecraft.item.ItemStack; + +/** + * Any item that implements this allows for pixies to be spawned when the player takes damage when...
+ * - Case the item is armor, having it equipped.
+ * - Case the item is a bauble, having it worn.
+ * - On any other case, having the item being the current held item. + */ +public interface IPixieSpawner { + + /** + * The chance this item adds for pixies to be spawned. From 0.0 to 1.0. All values + * are put together when calculating. + */ + public float getPixieChance(ItemStack stack); + +} \ No newline at end of file diff --git a/src/main/java/vazkii/botania/api/lexicon/IAddonEntry.java b/src/main/java/vazkii/botania/api/lexicon/IAddonEntry.java new file mode 100644 index 0000000..fe2167b --- /dev/null +++ b/src/main/java/vazkii/botania/api/lexicon/IAddonEntry.java @@ -0,0 +1,29 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jun 8, 2014, 7:02:48 PM (GMT)] + */ +package vazkii.botania.api.lexicon; + +/** + * Have a LexiconEntry implement this to signify it's an "Addon entry", as + * in, one provided by an Addon. This allows it to draw a subtitle of + * sorts, to prevent the [Mod tag here] nonsense that happened with thaumcraft + * addons. It can also be used for other purposes, such as stating an + * entry is WIP. + */ +public interface IAddonEntry { + + /** + * Returns the unlocalized subtitle to show below the title. Here you'd + * return something like "(This Entry is provided by the Botanic Tinkerer addon)". + */ + public String getSubtitle(); + +} diff --git a/src/main/java/vazkii/botania/api/lexicon/ILexicon.java b/src/main/java/vazkii/botania/api/lexicon/ILexicon.java new file mode 100644 index 0000000..ee07e17 --- /dev/null +++ b/src/main/java/vazkii/botania/api/lexicon/ILexicon.java @@ -0,0 +1,21 @@ +package vazkii.botania.api.lexicon; + +import net.minecraft.item.ItemStack; + +/** + * Basic interface for the Lexica Botania. + */ +public interface ILexicon { + + /** + * Gets if a specific knowledge is unlocked. Check the knowledge types in + * BotaniaAPI. + */ + public boolean isKnowledgeUnlocked(ItemStack stack, KnowledgeType knowledge); + + /** + * Unlocks a specfic type of knowledge. + */ + public void unlockKnowledge(ItemStack stack, KnowledgeType knowledge); + +} diff --git a/src/main/java/vazkii/botania/api/lexicon/ILexiconable.java b/src/main/java/vazkii/botania/api/lexicon/ILexiconable.java new file mode 100644 index 0000000..e8777db --- /dev/null +++ b/src/main/java/vazkii/botania/api/lexicon/ILexiconable.java @@ -0,0 +1,29 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 20, 2014, 7:05:44 PM (GMT)] + */ +package vazkii.botania.api.lexicon; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** + * Any block that implements this can be right clicked with + * a Lexica Botania to open a entry page. + */ +public interface ILexiconable { + + /** + * Gets the lexicon entry to open at this location. null works too. + */ + public LexiconEntry getEntry(World world, int x, int y, int z, EntityPlayer player, ItemStack lexicon); + +} diff --git a/src/main/java/vazkii/botania/api/lexicon/IRecipeKeyProvider.java b/src/main/java/vazkii/botania/api/lexicon/IRecipeKeyProvider.java new file mode 100644 index 0000000..d07c032 --- /dev/null +++ b/src/main/java/vazkii/botania/api/lexicon/IRecipeKeyProvider.java @@ -0,0 +1,24 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Mar 20, 2014, 6:08:48 PM (GMT)] + */ +package vazkii.botania.api.lexicon; + +import net.minecraft.item.ItemStack; + +/** + * Have an Item implement this so that the method used for mapping it into + * the lexicon recipe mappings isn't the typical id:meta key. + */ +public interface IRecipeKeyProvider { + + public String getKey(ItemStack stack); + +} diff --git a/src/main/java/vazkii/botania/api/lexicon/KnowledgeType.java b/src/main/java/vazkii/botania/api/lexicon/KnowledgeType.java new file mode 100644 index 0000000..5a08c9c --- /dev/null +++ b/src/main/java/vazkii/botania/api/lexicon/KnowledgeType.java @@ -0,0 +1,20 @@ +package vazkii.botania.api.lexicon; + +import net.minecraft.util.EnumChatFormatting; + +public class KnowledgeType { + + public final String id; + public final EnumChatFormatting color; + public final boolean autoUnlock; + + public KnowledgeType(String id, EnumChatFormatting color, boolean autoUnlock) { + this.id = id; + this.color = color; + this.autoUnlock = autoUnlock; + } + + public String getUnlocalizedName() { + return "botania.knowledge." + id; + } +} diff --git a/src/main/java/vazkii/botania/api/lexicon/LexiconCategory.java b/src/main/java/vazkii/botania/api/lexicon/LexiconCategory.java new file mode 100644 index 0000000..7627341 --- /dev/null +++ b/src/main/java/vazkii/botania/api/lexicon/LexiconCategory.java @@ -0,0 +1,32 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 14, 2014, 6:23:47 PM (GMT)] + */ +package vazkii.botania.api.lexicon; + +import java.util.ArrayList; +import java.util.List; + +public final class LexiconCategory { + + public final String unlocalizedName; + public final List entries = new ArrayList(); + + /** + * @param unlocalizedName The unlocalized name of this category. This will be localized by the client display. + */ + public LexiconCategory(String unlocalizedName) { + this.unlocalizedName = unlocalizedName; + } + + public String getUnlocalizedName() { + return unlocalizedName; + } +} diff --git a/src/main/java/vazkii/botania/api/lexicon/LexiconEntry.java b/src/main/java/vazkii/botania/api/lexicon/LexiconEntry.java new file mode 100644 index 0000000..bbc475c --- /dev/null +++ b/src/main/java/vazkii/botania/api/lexicon/LexiconEntry.java @@ -0,0 +1,97 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 14, 2014, 6:17:06 PM (GMT)] + */ +package vazkii.botania.api.lexicon; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import net.minecraft.util.StatCollector; +import vazkii.botania.api.BotaniaAPI; + +public class LexiconEntry implements Comparable { + + public final String unlocalizedName; + public final LexiconCategory category; + + private KnowledgeType type = BotaniaAPI.basicKnowledge; + + public List pages = new ArrayList(); + private boolean priority = false; + + /** + * @param unlocalizedName The unlocalized name of this entry. This will be localized by the client display. + */ + public LexiconEntry(String unlocalizedName, LexiconCategory category) { + this.unlocalizedName = unlocalizedName; + this.category = category; + } + + /** + * Sets this page as prioritized, as in, will appear before others in the lexicon. + */ + public LexiconEntry setPriority() { + priority = true; + return this; + } + + /** + * Sets the Knowledge type of this entry. + */ + public LexiconEntry setKnowledgeType(KnowledgeType type) { + this.type = type; + return this; + } + + public KnowledgeType getKnowledgeType() { + return type; + } + + public boolean isPriority() { + return priority; + } + + public String getUnlocalizedName() { + return unlocalizedName; + } + + /** + * Sets what pages you want this entry to have. + */ + public LexiconEntry setLexiconPages(LexiconPage... pages) { + this.pages.addAll(Arrays.asList(pages)); + + for(int i = 0; i < this.pages.size(); i++) { + LexiconPage page = this.pages.get(i); + if(!page.skipRegistry) + page.onPageAdded(this, i); + } + + return this; + } + + /** + * Adds a page to the list of pages. + */ + public void addPage(LexiconPage page) { + pages.add(page); + } + + public final String getNameForSorting() { + return (priority ? 0 : 1) + StatCollector.translateToLocal(getUnlocalizedName()); + } + + @Override + public int compareTo(LexiconEntry o) { + return getNameForSorting().compareTo(o.getNameForSorting()); + } +} \ No newline at end of file diff --git a/src/main/java/vazkii/botania/api/lexicon/LexiconPage.java b/src/main/java/vazkii/botania/api/lexicon/LexiconPage.java new file mode 100644 index 0000000..f17f0c5 --- /dev/null +++ b/src/main/java/vazkii/botania/api/lexicon/LexiconPage.java @@ -0,0 +1,67 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 14, 2014, 6:17:24 PM (GMT)] + */ +package vazkii.botania.api.lexicon; + +import vazkii.botania.api.internal.IGuiLexiconEntry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +public abstract class LexiconPage { + + public String unlocalizedName; + public boolean skipRegistry; + + public LexiconPage(String unlocalizedName) { + this.unlocalizedName = unlocalizedName; + } + + /** + * Does the rendering for this page. + * @param gui The active GuiScreen + * @param mx The mouse's relative X position. + * @param my The mouse's relative Y position. + */ + @SideOnly(Side.CLIENT) + public abstract void renderScreen(IGuiLexiconEntry gui, int mx, int my); + + /** + * Called per update tick. + */ + @SideOnly(Side.CLIENT) + public void updateScreen() { + // NO-OP + } + + /** + * Called when a key is pressed. + */ + @SideOnly(Side.CLIENT) + public void onKeyPressed(char c, int key) { + // NO-OP + } + + /** + * Called when {@link LexiconEntry#setLexiconPages(LexiconPage...)} is called. + */ + public void onPageAdded(LexiconEntry entry, int index) { + // NO-OP + } + + public String getUnlocalizedName() { + return unlocalizedName; + } + + public LexiconPage setSkipRegistry() { + skipRegistry = true; + return this; + } +} diff --git a/src/main/java/vazkii/botania/api/lexicon/LexiconRecipeMappings.java b/src/main/java/vazkii/botania/api/lexicon/LexiconRecipeMappings.java new file mode 100644 index 0000000..49b2a13 --- /dev/null +++ b/src/main/java/vazkii/botania/api/lexicon/LexiconRecipeMappings.java @@ -0,0 +1,66 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Mar 6, 2014, 3:54:12 PM (GMT)] + */ +package vazkii.botania.api.lexicon; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.item.ItemStack; + +/** + * This class contains mappings for which entry and page correspond to each + * craftable ItemStack. Use the map method to map an ItemStack to a page in + * an entry in the lexicon. + */ +public final class LexiconRecipeMappings { + + private static Map mappings = new HashMap(); + + /** + * Maps the given stack to the given page of the entry. + */ + public static void map(ItemStack stack, LexiconEntry entry, int page, boolean force) { + EntryData data = new EntryData(entry, page); + String str = stackToString(stack); + + if(force || !mappings.containsKey(str)) + mappings.put(str, data); + } + + public static void map(ItemStack stack, LexiconEntry entry, int page) { + map(stack, entry, page, false); + } + + + public static EntryData getDataForStack(ItemStack stack) { + return mappings.get(stackToString(stack)); + } + + public static String stackToString(ItemStack stack) { + if(stack.hasTagCompound() && stack.getItem() instanceof IRecipeKeyProvider) + return ((IRecipeKeyProvider) stack.getItem()).getKey(stack); + + return stack.getUnlocalizedName() + "~" + stack.getItemDamage(); + } + + public static class EntryData { + + public final LexiconEntry entry; + public final int page; + + public EntryData(LexiconEntry entry, int page) { + this.entry = entry; + this.page = page; + } + + } +} diff --git a/src/main/java/vazkii/botania/api/mana/BurstProperties.java b/src/main/java/vazkii/botania/api/mana/BurstProperties.java new file mode 100644 index 0000000..eed7480 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/BurstProperties.java @@ -0,0 +1,37 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 31, 2014, 3:49:30 PM (GMT)] + */ +package vazkii.botania.api.mana; + +/** + * The properties of a mana burst, when shot. This is passed to the lens + * currently on the mana spreader to apply changes. + */ +public final class BurstProperties { + + public int maxMana; + public int ticksBeforeManaLoss; + public float manaLossPerTick; + public float gravity; + public float motionModifier; + + public int color; + + public BurstProperties(int maxMana, int ticksBeforeManaLoss, float manaLossPerTick, float gravity, float motionModifier, int color) { + this.maxMana = maxMana; + this.ticksBeforeManaLoss = ticksBeforeManaLoss; + this.manaLossPerTick = manaLossPerTick; + this.gravity = gravity; + this.motionModifier = motionModifier; + this.color = color; + } + +} diff --git a/src/main/java/vazkii/botania/api/mana/IClientManaHandler.java b/src/main/java/vazkii/botania/api/mana/IClientManaHandler.java new file mode 100644 index 0000000..889cfb5 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/IClientManaHandler.java @@ -0,0 +1,21 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jul 2, 2014, 5:26:02 PM (GMT)] + */ +package vazkii.botania.api.mana; + +/** + * A TileEntity that implements this will get it's recieveMana call + * called on both client and server. If this is not implemented + * the call will only occur on the server. + */ +public interface IClientManaHandler extends IManaReceiver { + +} diff --git a/src/main/java/vazkii/botania/api/mana/ICreativeManaProvider.java b/src/main/java/vazkii/botania/api/mana/ICreativeManaProvider.java new file mode 100644 index 0000000..51f3cce --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/ICreativeManaProvider.java @@ -0,0 +1,26 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [May 25, 2014, 7:34:00 PM (GMT)] + */ +package vazkii.botania.api.mana; + +import net.minecraft.item.ItemStack; + +/** + * Have an item implement this to flag it as an infinite + * mana source for the purposes of the HUD rendered when + * an IManaUserItem implementing item is present. + */ +public interface ICreativeManaProvider { + + public boolean isCreative(ItemStack stack); + +} + diff --git a/src/main/java/vazkii/botania/api/mana/IKeyLocked.java b/src/main/java/vazkii/botania/api/mana/IKeyLocked.java new file mode 100644 index 0000000..a7870e6 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/IKeyLocked.java @@ -0,0 +1,30 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jul 11, 2014, 4:29:32 PM (GMT)] + */ +package vazkii.botania.api.mana; + +/** + * A TileEntity that implements this interface has an IO key lock. This + * interface defines an input and output key.

+ * + * A Spreader can only shoot mana into a IKeyLocked interfaced TE if the Input + * key of the TE is equal to the Output key of the Spreader.

+ * + * A Spreader can only pull mana from a IKeyLocked interfaced IManaPool TE if the + * Output key of the IManaPool is equal to the Input key of the Spreader. + */ +public interface IKeyLocked { + + public String getInputKey(); + + public String getOutputKey(); + +} diff --git a/src/main/java/vazkii/botania/api/mana/ILaputaImmobile.java b/src/main/java/vazkii/botania/api/mana/ILaputaImmobile.java new file mode 100644 index 0000000..91cb0b9 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/ILaputaImmobile.java @@ -0,0 +1,23 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jul 26, 2014, 9:51:58 PM (GMT)] + */ +package vazkii.botania.api.mana; + +import net.minecraft.world.World; + +/** + * A block that implements this has a flag for whether it can be moved by the Shard of Laputa. + */ +public interface ILaputaImmobile { + + public boolean canMove(World world, int x, int y, int z); + +} diff --git a/src/main/java/vazkii/botania/api/mana/ILens.java b/src/main/java/vazkii/botania/api/mana/ILens.java new file mode 100644 index 0000000..628d102 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/ILens.java @@ -0,0 +1,43 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 31, 2014, 3:03:04 PM (GMT)] + */ +package vazkii.botania.api.mana; + +import net.minecraft.item.ItemStack; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * Have an Item implement this to be counted as a lens for the mana spreader. + */ +public interface ILens extends ILensEffect { + + @SideOnly(Side.CLIENT) + public int getLensColor(ItemStack stack); + + /** + * Can the source lens be combined with the composite lens? This is called + * for both the ILens instance of ItemStack.getItem() of sourceLens and compositeLens. + */ + public boolean canCombineLenses(ItemStack sourceLens, ItemStack compositeLens); + + /** + * Gets the composite lens in the stack passed in, return null for none. + */ + public ItemStack getCompositeLens(ItemStack stack); + + /** + * Sets the composite lens for the sourceLens as the compositeLens, returns + * the ItemStack with the combination. + */ + public ItemStack setCompositeLens(ItemStack sourceLens, ItemStack compositeLens); + +} diff --git a/src/main/java/vazkii/botania/api/mana/ILensEffect.java b/src/main/java/vazkii/botania/api/mana/ILensEffect.java new file mode 100644 index 0000000..d97095b --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/ILensEffect.java @@ -0,0 +1,49 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Apr 14, 2014, 7:30:00 PM (GMT)] + */ +package vazkii.botania.api.mana; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.MovingObjectPosition; +import vazkii.botania.api.internal.IManaBurst; + +/** + * Have an item implement this for it to count as a lens effect and + * be able to change the properties of Mana Bursts. + */ +public interface ILensEffect { + + /** + * Called when a mana spreader that has this focus shoots a burst. This is where + * you change the properties of the burst. + */ + public void apply(ItemStack stack, BurstProperties props); + + /** + * Called when a mana burst fired from a mana spreader with this focus collides against + * any block. This is called after the collision is handled. + * @return True to kill the burst. False to keep it alive. + */ + public boolean collideBurst(IManaBurst burst, MovingObjectPosition pos, boolean isManaBlock, boolean dead, ItemStack stack); + + /** + * Called when a mana burst fired from a mana spreader with this focus is updated. + * This is called before the update is handled. + */ + public void updateBurst(IManaBurst burst, ItemStack stack); + + /** + * Called when the mana burst should do it's particles. Return false to not + * do any particles. + */ + public boolean doParticles(IManaBurst burst, ItemStack stack); + +} diff --git a/src/main/java/vazkii/botania/api/mana/IManaBlock.java b/src/main/java/vazkii/botania/api/mana/IManaBlock.java new file mode 100644 index 0000000..6896f05 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/IManaBlock.java @@ -0,0 +1,26 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 22, 2014, 4:59:05 PM (GMT)] + */ +package vazkii.botania.api.mana; + +/** + * A TileEntity that implements this is considered a Mana Block. + * Just being a Mana Block doesn't mean much, look at the other IMana + * interfaces. + */ +public interface IManaBlock { + + /** + * Gets the amount of mana currently in this block. + */ + public int getCurrentMana(); + +} diff --git a/src/main/java/vazkii/botania/api/mana/IManaCollector.java b/src/main/java/vazkii/botania/api/mana/IManaCollector.java new file mode 100644 index 0000000..a54d8c9 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/IManaCollector.java @@ -0,0 +1,43 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 22, 2014, 5:01:19 PM (GMT)] + */ +package vazkii.botania.api.mana; + +import vazkii.botania.api.internal.IManaBurst; + +/** + * Any TileEntity that implements this is considered a mana collector, by + * which nearby generating flowers will pump mana into it.

+ * + * Implementation Instructions:
+ * - Override invalidate() and onChunkUnload(), calling ManaNetworkEvent.removeCollector(this); on both.
+ * - On the first tick of onUpdate(), call ManaNetworkEvent.addCollector(this); + */ +public interface IManaCollector extends IManaReceiver { + + /** + * Called every tick on the client case the player is holding a Wand of the Forest. + */ + public void onClientDisplayTick(); + + /** + * Get the multiplier of mana to input into the block, 1.0 is the original amount of mana + * in the burst. 0.9, for example, is 90%, so 10% of the mana in the burst will get + * dissipated. + */ + public float getManaYieldMultiplier(IManaBurst burst); + + /** + * Gets the maximum amount of mana this collector can have. + */ + public int getMaxMana(); + +} diff --git a/src/main/java/vazkii/botania/api/mana/IManaCollisionGhost.java b/src/main/java/vazkii/botania/api/mana/IManaCollisionGhost.java new file mode 100644 index 0000000..420f683 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/IManaCollisionGhost.java @@ -0,0 +1,22 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Mar 10, 2014, 7:49:19 PM (GMT)] + */ +package vazkii.botania.api.mana; + +/** + * Any TileEntity that implements this can be counted as a "ghost" block of + * sorts, that won't call the collision code for the mana bursts. + */ +public interface IManaCollisionGhost { + + public boolean isGhost(); + +} diff --git a/src/main/java/vazkii/botania/api/mana/IManaItem.java b/src/main/java/vazkii/botania/api/mana/IManaItem.java new file mode 100644 index 0000000..42dfef1 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/IManaItem.java @@ -0,0 +1,69 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Mar 6, 2014, 9:07:40 AM (GMT)] + */ +package vazkii.botania.api.mana; + +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; + +/** + * An item that implements this can be counted as an item that can + * contain mana. + */ +public interface IManaItem { + + /** + * Gets the amount of mana this item contains + */ + public int getMana(ItemStack stack); + + /** + * Gets the max amount of mana this item can hold. + */ + public int getMaxMana(ItemStack stack); + + /** + * Adds mana to this item. + */ + public void addMana(ItemStack stack, int mana); + + /** + * Can this item receive mana from a mana Pool? + * @param pool The pool it's receiving mana from, can be casted to IManaPool. + * @see IManaPool#isOutputtingPower() + */ + public boolean canReceiveManaFromPool(ItemStack stack, TileEntity pool); + + /** + * Can this item recieve mana from another item? + */ + public boolean canReceiveManaFromItem(ItemStack stack, ItemStack otherStack); + + /** + * Can this item export mana to a mana Pool? + * @param pool The pool it's exporting mana to, can be casted to IManaPool. + * @see IManaPool#isOutputtingPower() + */ + public boolean canExportManaToPool(ItemStack stack,TileEntity pool); + + /** + * Can this item export mana to another item? + */ + public boolean canExportManaToItem(ItemStack stack, ItemStack otherStack); + + /** + * If this item simply does not export mana at all, set this to true. This is + * used to skip items that contain mana but can't export it when drawing the + * mana bar above the XP bar. + */ + public boolean isNoExport(ItemStack stack); + +} diff --git a/src/main/java/vazkii/botania/api/mana/IManaPool.java b/src/main/java/vazkii/botania/api/mana/IManaPool.java new file mode 100644 index 0000000..b93bf6e --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/IManaPool.java @@ -0,0 +1,31 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 22, 2014, 5:03:09 PM (GMT)] + */ +package vazkii.botania.api.mana; + +/** + * Any TileEntity that implements this is considered a Mana Pool, + * by which nearby functional flowers will pull mana from it.
+ * Mana Distributors will also accept it as valid output.

+ * + * Implementation Instructions:
+ * - Override invalidate() and onChunkUnload(), calling ManaNetworkEvent.removePool(this); on both.
+ * - On the first tick of onUpdate(), call ManaNetworkEvent.addPool(this); + */ +public interface IManaPool extends IManaReceiver { + + /** + * Returns false if the mana pool is accepting power from other power items, + * true if it's sending power into them. + */ + public boolean isOutputtingPower(); + +} diff --git a/src/main/java/vazkii/botania/api/mana/IManaReceiver.java b/src/main/java/vazkii/botania/api/mana/IManaReceiver.java new file mode 100644 index 0000000..2838c7b --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/IManaReceiver.java @@ -0,0 +1,35 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 22, 2014, 4:55:00 PM (GMT)] + */ +package vazkii.botania.api.mana; + +/** + * Any TileEntity that implements this can receive mana from mana bursts. + */ +public interface IManaReceiver extends IManaBlock { + + /** + * Is this Mana Receiver is full? Being full means no mana bursts will be sent. + */ + public boolean isFull(); + + /** + * Called when this receiver receives mana. + */ + public void recieveMana(int mana); + + /** + * Can this tile receive mana from bursts? Generally set to false for + * implementations of IManaCollector. + */ + public boolean canRecieveManaFromBursts(); + +} diff --git a/src/main/java/vazkii/botania/api/mana/IManaTrigger.java b/src/main/java/vazkii/botania/api/mana/IManaTrigger.java new file mode 100644 index 0000000..684a2c1 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/IManaTrigger.java @@ -0,0 +1,24 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [May 16, 2014, 7:52:53 PM (GMT)] + */ +package vazkii.botania.api.mana; + +import net.minecraft.world.World; +import vazkii.botania.api.internal.IManaBurst; + +/** + * Have a block implement this class to make it do something when a mana burst collides with it. + */ +public interface IManaTrigger { + + public void onBurstCollision(IManaBurst burst, World world, int x, int y, int z); + +} diff --git a/src/main/java/vazkii/botania/api/mana/IManaUsingItem.java b/src/main/java/vazkii/botania/api/mana/IManaUsingItem.java new file mode 100644 index 0000000..d06cf74 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/IManaUsingItem.java @@ -0,0 +1,26 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [May 25, 2014, 7:32:10 PM (GMT)] + */ +package vazkii.botania.api.mana; + +import net.minecraft.item.ItemStack; + +/** + * Any item that implements this interface is an item that would use mana + * from the player's inventory. If there's any items in the inventory or + * equipped in either the baubles or armor inventories that implement + * this interface, a mana bar will be rendered. + */ +public interface IManaUsingItem { + + public boolean usesMana(ItemStack stack); + +} diff --git a/src/main/java/vazkii/botania/api/mana/IPoolOverlayProvider.java b/src/main/java/vazkii/botania/api/mana/IPoolOverlayProvider.java new file mode 100644 index 0000000..f677c3e --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/IPoolOverlayProvider.java @@ -0,0 +1,26 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jul 2, 2014, 6:36:54 PM (GMT)] + */ +package vazkii.botania.api.mana; + +import net.minecraft.util.IIcon; +import net.minecraft.world.World; + +/** + * A block that implements this can provide an IIcon (block icons only) + * to be used as an overlay for the mana pool, similarly to the mana void + * and catalysts. + */ +public interface IPoolOverlayProvider { + + public IIcon getIcon(World world, int x, int y, int z); + +} diff --git a/src/main/java/vazkii/botania/api/mana/ITinyPlanetExcempt.java b/src/main/java/vazkii/botania/api/mana/ITinyPlanetExcempt.java new file mode 100644 index 0000000..004c52e --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/ITinyPlanetExcempt.java @@ -0,0 +1,24 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jul 22, 2014, 2:26:14 PM (GMT)] + */ +package vazkii.botania.api.mana; + +import net.minecraft.item.ItemStack; + +/** + * Any Item that implements ILensEffect and this will have + * a check before being pulled by the Tiny Planet. + */ +public interface ITinyPlanetExcempt { + + public boolean shouldPull(ItemStack stack); + +} diff --git a/src/main/java/vazkii/botania/api/mana/ManaItemHandler.java b/src/main/java/vazkii/botania/api/mana/ManaItemHandler.java new file mode 100644 index 0000000..74fb005 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/ManaItemHandler.java @@ -0,0 +1,201 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Mar 13, 2014, 5:32:24 PM (GMT)] + */ +package vazkii.botania.api.mana; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import vazkii.botania.api.BotaniaAPI; + +public final class ManaItemHandler { + + /** + * Requests mana from items in a given player's inventory. + * @param manaToGet How much mana is to be requested, if less mana exists than this amount, + * the amount of mana existent will be returned instead, if you want exact values use requestManaExact. + * @param remove If true, the mana will be removed from the target item. Set to false to just check. + * @return The amount of mana received from the request. + */ + public static int requestMana(ItemStack stack, EntityPlayer player, int manaToGet, boolean remove) { + if(stack == null) + return 0; + + IInventory mainInv = player.inventory; + IInventory baublesInv = BotaniaAPI.internalHandler.getBaublesInventory(player); + + int invSize = mainInv.getSizeInventory(); + int size = invSize; + if(baublesInv != null) + size += baublesInv.getSizeInventory(); + + for(int i = 0; i < size; i++) { + boolean useBaubles = i >= invSize; + IInventory inv = useBaubles ? baublesInv : mainInv; + ItemStack stackInSlot = inv.getStackInSlot(i - (useBaubles ? invSize : 0)); + if(stackInSlot == stack) + continue; + + if(stackInSlot != null && stackInSlot.getItem() instanceof IManaItem) { + IManaItem manaItem = (IManaItem) stackInSlot.getItem(); + if(manaItem.canExportManaToItem(stackInSlot, stack) && manaItem.getMana(stackInSlot) > 0) { + if(stack.getItem() instanceof IManaItem && !((IManaItem) stack.getItem()).canReceiveManaFromItem(stack, stackInSlot)) + continue; + + int mana = Math.min(manaToGet, manaItem.getMana(stackInSlot)); + + if(remove) + manaItem.addMana(stackInSlot, -mana); + + return mana; + } + } + } + + return 0; + } + + /** + * Requests an exact amount of mana from items in a given player's inventory. + * @param manaToGet How much mana is to be requested, if less mana exists than this amount, + * false will be returned instead, and nothing will happen. + * @param remove If true, the mana will be removed from the target item. Set to false to just check. + * @return If the request was succesful. + */ + public static boolean requestManaExact(ItemStack stack, EntityPlayer player, int manaToGet, boolean remove) { + if(stack == null) + return false; + + IInventory mainInv = player.inventory; + IInventory baublesInv = BotaniaAPI.internalHandler.getBaublesInventory(player); + + int invSize = mainInv.getSizeInventory(); + int size = invSize; + if(baublesInv != null) + size += baublesInv.getSizeInventory(); + + for(int i = 0; i < size; i++) { + boolean useBaubles = i >= invSize; + IInventory inv = useBaubles ? baublesInv : mainInv; + ItemStack stackInSlot = inv.getStackInSlot(i - (useBaubles ? invSize : 0)); + if(stackInSlot == stack) + continue; + + if(stackInSlot != null && stackInSlot.getItem() instanceof IManaItem) { + IManaItem manaItemSlot = (IManaItem) stackInSlot.getItem(); + if(manaItemSlot.canExportManaToItem(stackInSlot, stack) && manaItemSlot.getMana(stackInSlot) > manaToGet) { + if(stack.getItem() instanceof IManaItem && !((IManaItem) stack.getItem()).canReceiveManaFromItem(stack, stackInSlot)) + continue; + + if(remove) + manaItemSlot.addMana(stackInSlot, -manaToGet); + + return true; + } + } + } + + return false; + } + + /** + * Dispatches mana to items in a given player's inventory. Note that this method + * does not automatically remove mana from the item which is exporting. + * @param manaToSend How much mana is to be sent. + * @param remove If true, the mana will be added from the target item. Set to false to just check. + * @return The amount of mana actually sent. + */ + public static int dispatchMana(ItemStack stack, EntityPlayer player, int manaToSend, boolean add) { + if(stack == null) + return 0; + + IInventory mainInv = player.inventory; + IInventory baublesInv = BotaniaAPI.internalHandler.getBaublesInventory(player); + + int invSize = mainInv.getSizeInventory(); + int size = invSize; + if(baublesInv != null) + size += baublesInv.getSizeInventory(); + + for(int i = 0; i < size; i++) { + boolean useBaubles = i >= invSize; + IInventory inv = useBaubles ? baublesInv : mainInv; + ItemStack stackInSlot = inv.getStackInSlot(i - (useBaubles ? invSize : 0)); + if(stackInSlot == stack) + continue; + + if(stackInSlot != null && stackInSlot.getItem() instanceof IManaItem) { + IManaItem manaItemSlot = (IManaItem) stackInSlot.getItem(); + + if(manaItemSlot.canReceiveManaFromItem(stackInSlot, stack)) { + if(stack.getItem() instanceof IManaItem && !((IManaItem) stack.getItem()).canExportManaToItem(stack, stackInSlot)) + continue; + + int received = 0; + if(manaItemSlot.getMana(stackInSlot) + manaToSend <= manaItemSlot.getMaxMana(stackInSlot)) + received = manaToSend; + else received = manaToSend - (manaItemSlot.getMana(stackInSlot) + manaToSend - manaItemSlot.getMaxMana(stackInSlot)); + + + if(add) + manaItemSlot.addMana(stackInSlot, manaToSend); + + return received; + } + } + } + + return 0; + } + + /** + * Dispatches an exact amount of mana to items in a given player's inventory. Note that this method + * does not automatically remove mana from the item which is exporting. + * @param manaToSend How much mana is to be sent. + * @param remove If true, the mana will be added from the target item. Set to false to just check. + * @return If an item received the mana sent. + */ + public static boolean dispatchManaExact(ItemStack stack, EntityPlayer player, int manaToSend, boolean add) { + if(stack == null) + return false; + + IInventory mainInv = player.inventory; + IInventory baublesInv = BotaniaAPI.internalHandler.getBaublesInventory(player); + + int invSize = mainInv.getSizeInventory(); + int size = invSize; + if(baublesInv != null) + size += baublesInv.getSizeInventory(); + + for(int i = 0; i < size; i++) { + boolean useBaubles = i >= invSize; + IInventory inv = useBaubles ? baublesInv : mainInv; + ItemStack stackInSlot = inv.getStackInSlot(i - (useBaubles ? invSize : 0)); + if(stackInSlot == stack) + continue; + + if(stackInSlot != null && stackInSlot.getItem() instanceof IManaItem) { + IManaItem manaItemSlot = (IManaItem) stackInSlot.getItem(); + if(manaItemSlot.getMana(stackInSlot) + manaToSend <= manaItemSlot.getMaxMana(stackInSlot) && manaItemSlot.canReceiveManaFromItem(stackInSlot, stack)) { + if(stack.getItem() instanceof IManaItem && !((IManaItem) stack.getItem()).canExportManaToItem(stack, stackInSlot)) + continue; + + if(add) + manaItemSlot.addMana(stackInSlot, manaToSend); + + return true; + } + } + } + + return false; + } +} diff --git a/src/main/java/vazkii/botania/api/mana/ManaNetworkEvent.java b/src/main/java/vazkii/botania/api/mana/ManaNetworkEvent.java new file mode 100644 index 0000000..e04253a --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/ManaNetworkEvent.java @@ -0,0 +1,57 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 22, 2014, 5:04:30 PM (GMT)] + */ +package vazkii.botania.api.mana; + +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.MinecraftForge; +import cpw.mods.fml.common.eventhandler.Event; + +public class ManaNetworkEvent extends Event { + + public final TileEntity tile; + public final ManaBlockType type; + public final Action action; + + public ManaNetworkEvent(TileEntity tile, ManaBlockType type, Action action) { + this.tile = tile; + this.type = type; + this.action = action; + } + + public static void addCollector(TileEntity tile) { + ManaNetworkEvent event = new ManaNetworkEvent(tile, ManaBlockType.COLLECTOR, Action.ADD); + MinecraftForge.EVENT_BUS.post(event); + } + + public static void removeCollector(TileEntity tile) { + ManaNetworkEvent event = new ManaNetworkEvent(tile, ManaBlockType.COLLECTOR, Action.REMOVE); + MinecraftForge.EVENT_BUS.post(event); + } + + public static void addPool(TileEntity tile) { + ManaNetworkEvent event = new ManaNetworkEvent(tile, ManaBlockType.POOL, Action.ADD); + MinecraftForge.EVENT_BUS.post(event); + } + + public static void removePool(TileEntity tile) { + ManaNetworkEvent event = new ManaNetworkEvent(tile, ManaBlockType.POOL, Action.REMOVE); + MinecraftForge.EVENT_BUS.post(event); + } + + public enum ManaBlockType { + POOL, COLLECTOR + } + + public enum Action { + REMOVE, ADD + } +} diff --git a/src/main/java/vazkii/botania/api/mana/TileSignature.java b/src/main/java/vazkii/botania/api/mana/TileSignature.java new file mode 100644 index 0000000..5573670 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/TileSignature.java @@ -0,0 +1,15 @@ +package vazkii.botania.api.mana; + +import net.minecraft.tileentity.TileEntity; + +public class TileSignature { + + public final TileEntity tile; + public final boolean remoteWorld; + + public TileSignature(TileEntity tile, boolean remoteWorld) { + this.tile = tile; + this.remoteWorld = remoteWorld; + } + +} diff --git a/src/main/java/vazkii/botania/api/mana/spark/ISparkAttachable.java b/src/main/java/vazkii/botania/api/mana/spark/ISparkAttachable.java new file mode 100644 index 0000000..4353f01 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/spark/ISparkAttachable.java @@ -0,0 +1,54 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Aug 21, 2014, 5:44:13 PM (GMT)] + */ +package vazkii.botania.api.mana.spark; + +import net.minecraft.item.ItemStack; +import vazkii.botania.api.mana.IManaReceiver; + +/** + * A TileEntity that implements this can have a Spark attached to it. + * For the Spark to be allowed to have upgrades, it needs to be an IManaPool. + */ +public interface ISparkAttachable extends IManaReceiver { + + /** + * Can this block have a Spark attached to it. Note that this will not + * unattach the Spark if it's changed later. + */ + public boolean canAttachSpark(ItemStack stack); + + /** + * Called when the Spark is attached. + */ + public void attachSpark(ISparkEntity entity); + + /** + * Gets the Spark that is attached to this block. A common implementation is + * to check for Spark entities above: + * + List sparks = worldObj.getEntitiesWithinAABB(ISparkEntity.class, AxisAlignedBB.getBoundingBox(xCoord, yCoord + 1, zCoord, xCoord + 1, yCoord + 2, zCoord + 1)); + if(sparks.size() == 1) { + Entity e = (Entity) sparks.get(0); + return (ISparkEntity) e; + } + + return null; + */ + public ISparkEntity getAttachedSpark(); + + /** + * Return true if this Tile no longer requires mana and all Sparks + * transferring mana to it should cancel their transfer. + */ + public boolean areIncomingTranfersDone(); + +} diff --git a/src/main/java/vazkii/botania/api/mana/spark/ISparkEntity.java b/src/main/java/vazkii/botania/api/mana/spark/ISparkEntity.java new file mode 100644 index 0000000..084b827 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/spark/ISparkEntity.java @@ -0,0 +1,65 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Aug 21, 2014, 5:44:07 PM (GMT)] + */ +package vazkii.botania.api.mana.spark; + +import java.util.Collection; + +/** + * An Entity that implements this is considered a Spark. + */ +public interface ISparkEntity { + + /** + * Which TileEntity is this Spark attached to? A common implementation is checking the block below. + * + int x = MathHelper.floor_double(posX); + int y = MathHelper.floor_double(posY) - 1; + int z = MathHelper.floor_double(posZ); + TileEntity tile = worldObj.getTileEntity(x, y, z); + if(tile != null && tile instanceof ISparkAttachable) + return (ISparkAttachable) tile; + + return null; + */ + public ISparkAttachable getAttachedTile(); + + /** + * Gets a collection of all Sparks this is tranfering to. + */ + public Collection getTransfers(); + + /** + * Registers the Spark passed in as a Spark meant for mana to be transfered towards. + */ + public void registerTransfer(ISparkEntity entity); + + /** + * Gets which upgrade is in this Spark.
+ * 0: None
+ * 1: Dispersive
+ * 2: Dominant
+ * 3: Recessive
+ * 4: Isolated + */ + public int getUpgrade(); + + /** + * Sets the upgrade on this Spark. See {@link ISparkEntity#getUpgrade} + */ + public void setUpgrade(int upgrade); + + /** + * See {@link ISparkAttachable#areIncomingTranfersDone()} + */ + public boolean areIncomingTransfersDone(); + +} diff --git a/src/main/java/vazkii/botania/api/mana/spark/SparkHelper.java b/src/main/java/vazkii/botania/api/mana/spark/SparkHelper.java new file mode 100644 index 0000000..6bb3196 --- /dev/null +++ b/src/main/java/vazkii/botania/api/mana/spark/SparkHelper.java @@ -0,0 +1,33 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Aug 21, 2014, 7:16:11 PM (GMT)] + */ +package vazkii.botania.api.mana.spark; + +import java.util.List; + +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; + +public final class SparkHelper { + + public static final int SPARK_SCAN_RANGE = 12; + + public static List getSparksAround(World world, double x, double y, double z) { + return SparkHelper.getEntitiesAround(ISparkEntity.class, world, x, y, z); + } + + public static List getEntitiesAround(Class clazz, World world, double x, double y, double z) { + int r = SPARK_SCAN_RANGE; + List entities = world.getEntitiesWithinAABB(clazz, AxisAlignedBB.getBoundingBox(x - r, y - r, z - r, x + r, y + r, z + r)); + return entities; + } + +} diff --git a/src/main/java/vazkii/botania/api/package-info.java b/src/main/java/vazkii/botania/api/package-info.java new file mode 100644 index 0000000..9422380 --- /dev/null +++ b/src/main/java/vazkii/botania/api/package-info.java @@ -0,0 +1,4 @@ +@API(owner = "Botania", apiVersion = "17", provides = "BotaniaAPI") +package vazkii.botania.api; +import cpw.mods.fml.common.API; + diff --git a/src/main/java/vazkii/botania/api/recipe/IElvenItem.java b/src/main/java/vazkii/botania/api/recipe/IElvenItem.java new file mode 100644 index 0000000..e614014 --- /dev/null +++ b/src/main/java/vazkii/botania/api/recipe/IElvenItem.java @@ -0,0 +1,14 @@ +package vazkii.botania.api.recipe; + +import net.minecraft.item.ItemStack; + +/** + * Any Item that implements this is classified as an "Elven Item", by which, + * it'll not go through the alfheim portal. Any item that comes out of it + * must implement this or it'll just go back in. + */ +public interface IElvenItem { + + public boolean isElvenItem(ItemStack stack); + +} diff --git a/src/main/java/vazkii/botania/api/recipe/IFlowerComponent.java b/src/main/java/vazkii/botania/api/recipe/IFlowerComponent.java new file mode 100644 index 0000000..fe5bf3c --- /dev/null +++ b/src/main/java/vazkii/botania/api/recipe/IFlowerComponent.java @@ -0,0 +1,26 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Feb 15, 2014, 2:36:35 PM (GMT)] + */ +package vazkii.botania.api.recipe; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; + +/** + * Have an Item implement this to allow it to be used in the Petal Apothecary. + */ +public interface IFlowerComponent { + + public boolean canFit(ItemStack stack, IInventory apothecary); + + public int getParticleColor(ItemStack stack); + +} diff --git a/src/main/java/vazkii/botania/api/recipe/RecipeElvenTrade.java b/src/main/java/vazkii/botania/api/recipe/RecipeElvenTrade.java new file mode 100644 index 0000000..dbea13e --- /dev/null +++ b/src/main/java/vazkii/botania/api/recipe/RecipeElvenTrade.java @@ -0,0 +1,94 @@ +package vazkii.botania.api.recipe; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; + +public class RecipeElvenTrade { + + ItemStack output; + List inputs; + + public RecipeElvenTrade(ItemStack output, Object... inputs) { + this.output = output; + + List inputsToSet = new ArrayList(); + for(Object obj : inputs) { + if(obj instanceof String || obj instanceof ItemStack) + inputsToSet.add(obj); + else throw new IllegalArgumentException("Invalid input"); + } + + this.inputs = inputsToSet; + } + + public boolean matches(List stacks, boolean remove) { + List inputsMissing = new ArrayList(inputs); + List stacksToRemove = new ArrayList(); + + for(ItemStack stack : stacks) { + if(stack == null) { + continue; + } + if(inputsMissing.isEmpty()) + break; + + int stackIndex = -1, oredictIndex = -1; + + for(int j = 0; j < inputsMissing.size(); j++) { + Object input = inputsMissing.get(j); + if(input instanceof String) { + List validStacks = OreDictionary.getOres((String) input); + boolean found = false; + for(ItemStack ostack : validStacks) { + ItemStack cstack = ostack.copy(); + if(cstack.getItemDamage() == Short.MAX_VALUE) + cstack.setItemDamage(stack.getItemDamage()); + + if(stack.isItemEqual(cstack)) { + if(!stacksToRemove.contains(stack)) + stacksToRemove.add(stack); + oredictIndex = j; + found = true; + break; + } + } + + if(found) + break; + } else if(input instanceof ItemStack && simpleAreStacksEqual((ItemStack) input, stack)) { + if(!stacksToRemove.contains(stack)) + stacksToRemove.add(stack); + stackIndex = j; + break; + } + } + + if(stackIndex != -1) + inputsMissing.remove(stackIndex); + else if(oredictIndex != -1) + inputsMissing.remove(oredictIndex); + } + + if(remove) + for(ItemStack r : stacksToRemove) + stacks.remove(r); + + return inputsMissing.isEmpty(); + } + + boolean simpleAreStacksEqual(ItemStack stack, ItemStack stack2) { + return stack.getItem() == stack2.getItem() && stack.getItemDamage() == stack2.getItemDamage(); + } + + public List getInputs() { + return new ArrayList(inputs); + } + + public ItemStack getOutput() { + return output; + } + +} diff --git a/src/main/java/vazkii/botania/api/recipe/RecipeManaInfusion.java b/src/main/java/vazkii/botania/api/recipe/RecipeManaInfusion.java new file mode 100644 index 0000000..e87b002 --- /dev/null +++ b/src/main/java/vazkii/botania/api/recipe/RecipeManaInfusion.java @@ -0,0 +1,81 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 30, 2014, 5:57:07 PM (GMT)] + */ +package vazkii.botania.api.recipe; + +import java.util.List; + +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; + +public class RecipeManaInfusion { + + ItemStack output; + Object input; + int mana; + boolean isAlchemy = false; + boolean isConjuration = false; + + public RecipeManaInfusion(ItemStack output, Object input, int mana) { + this.output = output; + this.input = input; + this.mana = mana; + } + + public boolean matches(ItemStack stack) { + if(input instanceof ItemStack) + return stack.isItemEqual((ItemStack) input); + + if(input instanceof String) { + List validStacks = OreDictionary.getOres((String) input); + + for(ItemStack ostack : validStacks) { + ItemStack cstack = ostack.copy(); + if(cstack.getItemDamage() == Short.MAX_VALUE) + cstack.setItemDamage(stack.getItemDamage()); + + if(stack.isItemEqual(cstack)) + return true; + } + } + + return false; + } + + public void setAlchemy(boolean alchemy) { + isAlchemy = alchemy; + } + + public boolean isAlchemy() { + return isAlchemy; + } + + public void setConjuration(boolean conjuration) { + isConjuration = conjuration; + } + + public boolean isConjuration() { + return isConjuration; + } + + public Object getInput() { + return input; + } + + public ItemStack getOutput() { + return output; + } + + public int getManaToConsume() { + return mana; + } +} + diff --git a/src/main/java/vazkii/botania/api/recipe/RecipePetals.java b/src/main/java/vazkii/botania/api/recipe/RecipePetals.java new file mode 100644 index 0000000..0dba51a --- /dev/null +++ b/src/main/java/vazkii/botania/api/recipe/RecipePetals.java @@ -0,0 +1,97 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 22, 2014, 2:02:44 PM (GMT)] + */ +package vazkii.botania.api.recipe; + +import java.util.ArrayList; +import java.util.List; + +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; + +public class RecipePetals { + + ItemStack output; + List inputs; + + public RecipePetals(ItemStack output, Object... inputs) { + this.output = output; + + List inputsToSet = new ArrayList(); + for(Object obj : inputs) { + if(obj instanceof String || obj instanceof ItemStack) + inputsToSet.add(obj); + else throw new IllegalArgumentException("Invalid input"); + } + + this.inputs = inputsToSet; + } + + public boolean matches(IInventory inv) { + List inputsMissing = new ArrayList(inputs); + + for(int i = 0; i < inv.getSizeInventory(); i++) { + ItemStack stack = inv.getStackInSlot(i); + if(stack == null) + break; + + int stackIndex = -1, oredictIndex = -1; + + for(int j = 0; j < inputsMissing.size(); j++) { + Object input = inputsMissing.get(j); + if(input instanceof String) { + List validStacks = OreDictionary.getOres((String) input); + boolean found = false; + for(ItemStack ostack : validStacks) { + ItemStack cstack = ostack.copy(); + if(cstack.getItemDamage() == Short.MAX_VALUE) + cstack.setItemDamage(stack.getItemDamage()); + + if(stack.isItemEqual(cstack)) { + oredictIndex = j; + found = true; + break; + } + } + + + if(found) + break; + } else if(input instanceof ItemStack && simpleAreStacksEqual((ItemStack) input, stack)) { + stackIndex = j; + break; + } + } + + if(stackIndex != -1) + inputsMissing.remove(stackIndex); + else if(oredictIndex != -1) + inputsMissing.remove(oredictIndex); + else return false; + } + + return inputsMissing.isEmpty(); + } + + boolean simpleAreStacksEqual(ItemStack stack, ItemStack stack2) { + return stack.getItem() == stack2.getItem() && stack.getItemDamage() == stack2.getItemDamage(); + } + + public List getInputs() { + return new ArrayList(inputs); + } + + public ItemStack getOutput() { + return output; + } + +} diff --git a/src/main/java/vazkii/botania/api/recipe/RecipeRuneAltar.java b/src/main/java/vazkii/botania/api/recipe/RecipeRuneAltar.java new file mode 100644 index 0000000..745c957 --- /dev/null +++ b/src/main/java/vazkii/botania/api/recipe/RecipeRuneAltar.java @@ -0,0 +1,31 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Feb 5, 2014, 1:41:14 PM (GMT)] + */ +package vazkii.botania.api.recipe; + +import net.minecraft.item.ItemStack; + +public class RecipeRuneAltar extends RecipePetals { + + ItemStack output; + int mana; + + public RecipeRuneAltar(ItemStack output, int mana, Object... inputs) { + super(output, inputs); + this.output = output; + this.mana = mana; + } + + public int getManaUsage() { + return mana; + } + +} diff --git a/src/main/java/vazkii/botania/api/subtile/ISpecialFlower.java b/src/main/java/vazkii/botania/api/subtile/ISpecialFlower.java new file mode 100644 index 0000000..0ef3149 --- /dev/null +++ b/src/main/java/vazkii/botania/api/subtile/ISpecialFlower.java @@ -0,0 +1,21 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 22, 2014, 7:12:28 PM (GMT)] + */ +package vazkii.botania.api.subtile; + +/** + * The special flowers in botania implement this. Used for cases where + * BlockFlower would be checked against, but isn't convenient for + * the special flowers with effects. For Azanor and Lycaon. + */ +public interface ISpecialFlower { + +} diff --git a/src/main/java/vazkii/botania/api/subtile/ISubTileContainer.java b/src/main/java/vazkii/botania/api/subtile/ISubTileContainer.java new file mode 100644 index 0000000..ddfaee7 --- /dev/null +++ b/src/main/java/vazkii/botania/api/subtile/ISubTileContainer.java @@ -0,0 +1,30 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Aug 26, 2014, 5:42:16 PM (GMT)] + */ +package vazkii.botania.api.subtile; + +/** + * A TileEntity that implements this contains a SubTileEntity. + */ +public interface ISubTileContainer { + + /** + * Gets the SubTile in this block. Generally shouldn't return null, but in that + * case use the fallback DummySubTile. + */ + public SubTileEntity getSubTile(); + + /** + * Sets the SubTile on this block from it's name. + */ + public void setSubTile(String name); + +} diff --git a/src/main/java/vazkii/botania/api/subtile/SubTileEntity.java b/src/main/java/vazkii/botania/api/subtile/SubTileEntity.java new file mode 100644 index 0000000..619d00f --- /dev/null +++ b/src/main/java/vazkii/botania/api/subtile/SubTileEntity.java @@ -0,0 +1,126 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 24, 2014, 3:59:06 PM (GMT)] + */ +package vazkii.botania.api.subtile; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.IIcon; +import vazkii.botania.api.BotaniaAPI; +import vazkii.botania.api.lexicon.LexiconEntry; +import vazkii.botania.api.wand.IWandBindable; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * A Sub-TileEntity, this is used for the flower system. Make sure to map subclasses + * of this using BotaniaAPI.mapSubTile(String, Class). Any subclass of this must have + * a no parameter constructor. + */ +public class SubTileEntity { + + protected TileEntity supertile; + + /** The Tag items should use to store which sub tile they are. **/ + public static final String TAG_TYPE = "type"; + + public void setSupertile(TileEntity tile) { + supertile = tile; + } + + public boolean canUpdate() { + return false; + } + + public void onUpdate() { } + + /** + * Writes some extra data to a network packet. This data is read + * by readFromPacketNBT on the client that receives the packet. + * Note: This method is also used to write to the world NBT. + */ + public void writeToPacketNBT(NBTTagCompound cmp) { } + + /** + * Reads data from a network packet. This data is written by + * writeToPacketNBT in the server. Note: This method is also used + * to read from the world NBT. + */ + public void readFromPacketNBT(NBTTagCompound cmp) { } + + public void sync() { + supertile.getWorldObj().markBlockForUpdate(supertile.xCoord, supertile.yCoord, supertile.zCoord); + } + + public String getUnlocalizedName() { + return BotaniaAPI.getSubTileStringMapping(getClass()); + } + + /** + * Gets the icon for this SubTileEntity, this is a block icon. + */ + @SideOnly(Side.CLIENT) + public IIcon getIcon() { + return BotaniaAPI.internalHandler.getSubTileIconForName(getUnlocalizedName()); + } + + /** + * Called when a Wand of the Forest is used on this sub tile. Note that the + * player parameter can be null if this is called from a dispenser. + */ + public boolean onWanded(EntityPlayer player, ItemStack wand) { + return false; + } + + /** + * Gets which Lexicon Entry to open when this sub tile is right clicked with a lexicon. + */ + public LexiconEntry getEntry() { + return null; + } + + /** + * Gets the block coordinates this is bound to, for use with the wireframe render + * when the sub tile is being hovered with a wand of the forest. + */ + @SideOnly(Side.CLIENT) + public ChunkCoordinates getBinding() { + return null; + } + + /** + * @see IWandBindable#canSelect(EntityPlayer, ItemStack, int, int, int, int) + */ + public boolean canSelect(EntityPlayer player, ItemStack wand, int x, int y, int z, int side) { + return false; + } + + /** + * @see IWandBindable#bindTo(EntityPlayer, ItemStack, int, int, int, int) + */ + public boolean bindTo(EntityPlayer player, ItemStack wand, int x, int y, int z, int side) { + return false; + } + + /** + * Called on the client when the block being pointed at is the one with this sub tile. + * Used to render a HUD portraying some data from this sub tile. + */ + @SideOnly(Side.CLIENT) + public void renderHUD(Minecraft mc, ScaledResolution res) { + // NO-OP + } +} diff --git a/src/main/java/vazkii/botania/api/subtile/SubTileFunctional.java b/src/main/java/vazkii/botania/api/subtile/SubTileFunctional.java new file mode 100644 index 0000000..7d95afe --- /dev/null +++ b/src/main/java/vazkii/botania/api/subtile/SubTileFunctional.java @@ -0,0 +1,212 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 24, 2014, 8:03:44 PM (GMT)] + */ +package vazkii.botania.api.subtile; + +import java.awt.Color; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.StatCollector; +import net.minecraftforge.common.util.ForgeDirection; +import vazkii.botania.api.BotaniaAPI; +import vazkii.botania.api.internal.IManaNetwork; +import vazkii.botania.api.mana.IManaPool; + +/** + * The basic class for a Functional Flower. + */ +public class SubTileFunctional extends SubTileEntity { + + private static final String TAG_MANA = "mana"; + + private static final String TAG_POOL_X = "poolX"; + private static final String TAG_POOL_Y = "poolY"; + private static final String TAG_POOL_Z = "poolZ"; + + public int mana; + + public int redstoneSignal = 0; + + int sizeLastCheck = -1; + TileEntity linkedPool = null; + public int knownMana = -1; + + ChunkCoordinates cachedPoolCoordinates = null; + + @Override + public boolean canUpdate() { + return true; + } + + /** + * If set to true, redstoneSignal will be updated every tick. + */ + public boolean acceptsRedstone() { + return false; + } + + @Override + public void onUpdate() { + super.onUpdate(); + + linkPool(); + + if(linkedPool != null) { + IManaPool pool = (IManaPool) linkedPool; + int manaInPool = pool.getCurrentMana(); + int manaMissing = getMaxMana() - mana; + int manaToRemove = Math.min(manaMissing, manaInPool); + pool.recieveMana(-manaToRemove); + addMana(manaToRemove); + } + + if(acceptsRedstone()) { + redstoneSignal = 0; + for(ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { + int redstoneSide = supertile.getWorldObj().getIndirectPowerLevelTo(supertile.xCoord + dir.offsetX, supertile.yCoord + dir.offsetY, supertile.zCoord + dir.offsetZ, dir.ordinal()); + redstoneSignal = Math.max(redstoneSignal, redstoneSide); + } + } + + if(supertile.getWorldObj().isRemote) { + double particleChance = 1F - (double) mana / (double) getMaxMana() / 3.5F; + Color color = new Color(getColor()); + if(Math.random() > particleChance) + BotaniaAPI.internalHandler.sparkleFX(supertile.getWorldObj(), supertile.xCoord + 0.3 + Math.random() * 0.5, supertile.yCoord + 0.5 + Math.random() * 0.5, supertile.zCoord + 0.3 + Math.random() * 0.5, color.getRed() / 255F, color.getGreen() / 255F, color.getBlue() / 255F, (float) Math.random(), 5); + } + } + + public void linkPool() { + final int range = 10; + + boolean needsNew = false; + if(linkedPool == null) { + needsNew = true; + + if(cachedPoolCoordinates != null && supertile.getWorldObj().blockExists(cachedPoolCoordinates.posX, cachedPoolCoordinates.posY, cachedPoolCoordinates.posZ)) { + TileEntity tileAt = supertile.getWorldObj().getTileEntity(cachedPoolCoordinates.posX, cachedPoolCoordinates.posY, cachedPoolCoordinates.posZ); + if(tileAt != null && tileAt instanceof IManaPool) { + linkedPool = tileAt; + needsNew = false; + } + cachedPoolCoordinates = null; + } + } + + if(!needsNew) { + TileEntity tileAt = supertile.getWorldObj().getTileEntity(linkedPool.xCoord, linkedPool.yCoord, linkedPool.zCoord); + if(!(tileAt instanceof IManaPool)) { + linkedPool = null; + needsNew = true; + } else linkedPool = tileAt; + } + + if(needsNew) { + IManaNetwork network = BotaniaAPI.internalHandler.getManaNetworkInstance(); + int size = network.getAllPoolsInWorld(supertile.getWorldObj()).size(); + if(BotaniaAPI.internalHandler.shouldForceCheck() || size != sizeLastCheck) { + ChunkCoordinates coords = new ChunkCoordinates(supertile.xCoord, supertile.yCoord, supertile.zCoord); + linkedPool = network.getClosestPool(coords, supertile.getWorldObj(), range); + sizeLastCheck = size; + } + } + } + + public void addMana(int mana) { + this.mana = Math.min(getMaxMana(), this.mana + mana); + } + + @Override + public boolean onWanded(EntityPlayer player, ItemStack wand) { + if(player == null) + return false; + + knownMana = mana; + player.worldObj.playSoundAtEntity(player, "botania:ding", 0.1F, 1F); + + return super.onWanded(player, wand); + } + + public int getMaxMana() { + return 20; + } + + public int getColor() { + return 0xFFFFFF; + } + + @Override + public void readFromPacketNBT(NBTTagCompound cmp) { + mana = cmp.getInteger(TAG_MANA); + + int x = cmp.getInteger(TAG_POOL_X); + int y = cmp.getInteger(TAG_POOL_Y); + int z = cmp.getInteger(TAG_POOL_Z); + + cachedPoolCoordinates = new ChunkCoordinates(x, y, z); + } + + @Override + public void writeToPacketNBT(NBTTagCompound cmp) { + cmp.setInteger(TAG_MANA, mana); + + int x = linkedPool == null ? 0 : linkedPool.xCoord; + int y = linkedPool == null ? -1 : linkedPool.yCoord; + int z = linkedPool == null ? 0 : linkedPool.zCoord; + + cmp.setInteger(TAG_POOL_X, x); + cmp.setInteger(TAG_POOL_Y, y); + cmp.setInteger(TAG_POOL_Z, z); + } + + @Override + public ChunkCoordinates getBinding() { + if(linkedPool == null) + return null; + return new ChunkCoordinates(linkedPool.xCoord, linkedPool.yCoord, linkedPool.zCoord); + } + + @Override + public boolean canSelect(EntityPlayer player, ItemStack wand, int x, int y, int z, int side) { + return true; + } + + @Override + public boolean bindTo(EntityPlayer player, ItemStack wand, int x, int y, int z, int side) { + int range = 10; + range *= range; + + double dist = (x - supertile.xCoord) * (x - supertile.xCoord) + (y - supertile.yCoord) * (y - supertile.yCoord) + (z - supertile.zCoord) * (z - supertile.zCoord); + if(range >= dist) { + TileEntity tile = player.worldObj.getTileEntity(x, y, z); + if(tile instanceof IManaPool) { + linkedPool = tile; + return true; + } + } + + return false; + } + + @Override + public void renderHUD(Minecraft mc, ScaledResolution res) { + String name = StatCollector.translateToLocal("tile.botania:flower." + getUnlocalizedName() + ".name"); + int color = 0x66000000 | getColor(); + BotaniaAPI.internalHandler.drawSimpleManaHUD(color, knownMana, getMaxMana(), name, res); + } + +} diff --git a/src/main/java/vazkii/botania/api/subtile/SubTileGenerating.java b/src/main/java/vazkii/botania/api/subtile/SubTileGenerating.java new file mode 100644 index 0000000..4137c77 --- /dev/null +++ b/src/main/java/vazkii/botania/api/subtile/SubTileGenerating.java @@ -0,0 +1,245 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 24, 2014, 8:03:36 PM (GMT)] + */ +package vazkii.botania.api.subtile; + +import java.awt.Color; + +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.StatCollector; +import vazkii.botania.api.BotaniaAPI; +import vazkii.botania.api.internal.IManaNetwork; +import vazkii.botania.api.mana.IManaCollector; +import vazkii.botania.api.mana.IManaPool; +import vazkii.botania.common.core.handler.ConfigHandler; + +/** + * The basic class for a Generating Flower. + */ +public class SubTileGenerating extends SubTileEntity { + + private static final String TAG_MANA = "mana"; + private static final String TAG_TICKS_EXISTED = "ticksExisted"; + + private static final String TAG_COLLECTOR_X = "collectorX"; + private static final String TAG_COLLECTOR_Y = "collectorY"; + private static final String TAG_COLLECTOR_Z = "collectorZ"; + + protected int mana; + + int ticksExisted = 0; + int sizeLastCheck = -1; + protected TileEntity linkedCollector = null; + public int knownMana = -1; + + ChunkCoordinates cachedCollectorCoordinates = null; + + @Override + public boolean canUpdate() { + return true; + } + + @Override + public void onUpdate() { + super.onUpdate(); + + linkCollector(); + + if(canGeneratePassively()) { + int delay = getDelayBetweenPassiveGeneration(); + if(delay > 0 && supertile.getWorldObj().getWorldTime() % delay == 0) { + if(shouldSyncPassiveGeneration()) + sync(); + addMana(getValueForPassiveGeneration()); + } + } + emptyManaIntoCollector(); + + if(supertile.getWorldObj().isRemote) { + double particleChance = 1F - (double) mana / (double) getMaxMana() / 3.5F; + Color color = new Color(getColor()); + if(Math.random() > particleChance) + BotaniaAPI.internalHandler.sparkleFX(supertile.getWorldObj(), supertile.xCoord + 0.3 + Math.random() * 0.5, supertile.yCoord + 0.5 + Math.random() * 0.5, supertile.zCoord + 0.3 + Math.random() * 0.5, color.getRed() / 255F, color.getGreen() / 255F, color.getBlue() / 255F, (float) Math.random(), 5); + } + + if(!supertile.getWorldObj().isRemote) { + ++ticksExisted; + if(isPassiveFlower() && ConfigHandler.hardcorePassiveGeneration > 0 && ticksExisted > ConfigHandler.hardcorePassiveGeneration) { + supertile.getWorldObj().playAuxSFX(2001, supertile.xCoord, supertile.yCoord, supertile.zCoord, Block.getIdFromBlock(supertile.getBlockType())); + supertile.getWorldObj().setBlockToAir(supertile.xCoord, supertile.yCoord, supertile.zCoord); + } + } + } + + public void linkCollector() { + final int range = 6; + + boolean needsNew = false; + if(linkedCollector == null) { + needsNew = true; + + if(cachedCollectorCoordinates != null && supertile.getWorldObj().blockExists(cachedCollectorCoordinates.posX, cachedCollectorCoordinates.posY, cachedCollectorCoordinates.posZ)) { + TileEntity tileAt = supertile.getWorldObj().getTileEntity(cachedCollectorCoordinates.posX, cachedCollectorCoordinates.posY, cachedCollectorCoordinates.posZ); + if(tileAt != null && tileAt instanceof IManaCollector) { + linkedCollector = tileAt; + needsNew = false; + } + cachedCollectorCoordinates = null; + } + } + + if(!needsNew) { + TileEntity tileAt = supertile.getWorldObj().getTileEntity(linkedCollector.xCoord, linkedCollector.yCoord, linkedCollector.zCoord); + if(!(tileAt instanceof IManaCollector)) { + linkedCollector = null; + needsNew = true; + } else linkedCollector = tileAt; + } + + if(needsNew) { + IManaNetwork network = BotaniaAPI.internalHandler.getManaNetworkInstance(); + int size = network.getAllCollectorsInWorld(supertile.getWorldObj()).size(); + if(BotaniaAPI.internalHandler.shouldForceCheck() || size != sizeLastCheck) { + ChunkCoordinates coords = new ChunkCoordinates(supertile.xCoord, supertile.yCoord, supertile.zCoord); + linkedCollector = network.getClosestCollector(coords, supertile.getWorldObj(), range); + sizeLastCheck = size; + } + } + } + + public void addMana(int mana) { + this.mana = Math.min(getMaxMana(), this.mana + mana); + } + + public void emptyManaIntoCollector() { + if(linkedCollector != null) { + IManaCollector collector = (IManaCollector) linkedCollector; + if(!collector.isFull() && mana > 0) { + int manaval = Math.min(mana, collector.getMaxMana() - collector.getCurrentMana()); + mana -= manaval; + collector.recieveMana(manaval); + } + } + } + + public boolean isPassiveFlower() { + return false; + } + + public boolean shouldSyncPassiveGeneration() { + return false; + } + + public boolean canGeneratePassively() { + return false; + } + + public int getDelayBetweenPassiveGeneration() { + return 20; + } + + public int getValueForPassiveGeneration() { + return 1; + } + + @Override + public boolean onWanded(EntityPlayer player, ItemStack wand) { + if(player == null) + return false; + + if(!player.worldObj.isRemote) + sync(); + + knownMana = mana; + player.worldObj.playSoundAtEntity(player, "botania:ding", 0.1F, 1F); + + return super.onWanded(player, wand); + } + + public int getMaxMana() { + return 20; + } + + public int getColor() { + return 0xFFFFFF; + } + + @Override + public void readFromPacketNBT(NBTTagCompound cmp) { + mana = cmp.getInteger(TAG_MANA); + if(!cmp.hasKey(TAG_TICKS_EXISTED)) + ticksExisted = cmp.getInteger(TAG_TICKS_EXISTED); + + int x = cmp.getInteger(TAG_COLLECTOR_X); + int y = cmp.getInteger(TAG_COLLECTOR_Y); + int z = cmp.getInteger(TAG_COLLECTOR_Z); + + cachedCollectorCoordinates = new ChunkCoordinates(x, y, z); + } + + @Override + public void writeToPacketNBT(NBTTagCompound cmp) { + cmp.setInteger(TAG_MANA, mana); + cmp.setInteger(TAG_TICKS_EXISTED, ticksExisted); + + int x = linkedCollector == null ? 0 : linkedCollector.xCoord; + int y = linkedCollector == null ? -1 : linkedCollector.yCoord; + int z = linkedCollector == null ? 0 : linkedCollector.zCoord; + + cmp.setInteger(TAG_COLLECTOR_X, x); + cmp.setInteger(TAG_COLLECTOR_Y, y); + cmp.setInteger(TAG_COLLECTOR_Z, z); + } + + @Override + public ChunkCoordinates getBinding() { + if(linkedCollector == null) + return null; + return new ChunkCoordinates(linkedCollector.xCoord, linkedCollector.yCoord, linkedCollector.zCoord); + } + + @Override + public boolean canSelect(EntityPlayer player, ItemStack wand, int x, int y, int z, int side) { + return true; + } + + @Override + public boolean bindTo(EntityPlayer player, ItemStack wand, int x, int y, int z, int side) { + int range = 6; + range *= range; + + double dist = (x - supertile.xCoord) * (x - supertile.xCoord) + (y - supertile.yCoord) * (y - supertile.yCoord) + (z - supertile.zCoord) * (z - supertile.zCoord); + if(range >= dist) { + TileEntity tile = player.worldObj.getTileEntity(x, y, z); + if(tile instanceof IManaCollector) { + linkedCollector = tile; + return true; + } + } + + return false; + } + + @Override + public void renderHUD(Minecraft mc, ScaledResolution res) { + String name = StatCollector.translateToLocal("tile.botania:flower." + getUnlocalizedName() + ".name"); + int color = 0x66000000 | getColor(); + BotaniaAPI.internalHandler.drawSimpleManaHUD(color, knownMana, getMaxMana(), name, res); + } + +} diff --git a/src/main/java/vazkii/botania/api/wand/ICoordBoundItem.java b/src/main/java/vazkii/botania/api/wand/ICoordBoundItem.java new file mode 100644 index 0000000..f7c8036 --- /dev/null +++ b/src/main/java/vazkii/botania/api/wand/ICoordBoundItem.java @@ -0,0 +1,18 @@ +package vazkii.botania.api.wand; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.ChunkCoordinates; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * The item equivalent of ITileBound, renders when the + * item is in hand. + * @see ITileBound + */ +public interface ICoordBoundItem { + + @SideOnly(Side.CLIENT) + public ChunkCoordinates getBinding(ItemStack stack); + +} diff --git a/src/main/java/vazkii/botania/api/wand/ITileBound.java b/src/main/java/vazkii/botania/api/wand/ITileBound.java new file mode 100644 index 0000000..25a8683 --- /dev/null +++ b/src/main/java/vazkii/botania/api/wand/ITileBound.java @@ -0,0 +1,31 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Mar 24, 2014, 6:47:53 PM (GMT)] + */ +package vazkii.botania.api.wand; + +import net.minecraft.util.ChunkCoordinates; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; + +/** + * Any TileEntity that implements this is technically bound + * to something, and the binding will be shown when hovering + * over with a Wand of the Forest. + */ +public interface ITileBound { + + /** + * Gets where this block is bound to, can return null. + */ + @SideOnly(Side.CLIENT) + public ChunkCoordinates getBinding(); + +} diff --git a/src/main/java/vazkii/botania/api/wand/IWandBindable.java b/src/main/java/vazkii/botania/api/wand/IWandBindable.java new file mode 100644 index 0000000..02d0771 --- /dev/null +++ b/src/main/java/vazkii/botania/api/wand/IWandBindable.java @@ -0,0 +1,36 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Oct 9, 2014, 3:01:58 PM (GMT)] + */ +package vazkii.botania.api.wand; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.MovingObjectPosition; + +/** + * A TileEntity that implements this can be bound to another block + * via the Wand of the Forest. Also see IWireframeAABBProvider to change + * the displayed bounding box. + */ +public interface IWandBindable extends ITileBound { + + /** + * Return true if the Wand can select this tile. + */ + public boolean canSelect(EntityPlayer player, ItemStack wand, int x, int y, int z, int side); + + /** + * Call to bind the TileEntity to where the player clicked. Return true to deselect + * the TileEntity for another bind or false case the TileEntity should stay selected. + */ + public boolean bindTo(EntityPlayer player, ItemStack wand, int x, int y, int z, int side); + +} diff --git a/src/main/java/vazkii/botania/api/wand/IWandHUD.java b/src/main/java/vazkii/botania/api/wand/IWandHUD.java new file mode 100644 index 0000000..57c7e31 --- /dev/null +++ b/src/main/java/vazkii/botania/api/wand/IWandHUD.java @@ -0,0 +1,26 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Feb 5, 2014, 1:34:44 PM (GMT)] + */ +package vazkii.botania.api.wand; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.world.World; + +/** + * Any block that implements this has a HUD rendered when being hovered + * with a Wand of the Forest. + */ +public interface IWandHUD { + + public void renderHUD(Minecraft mc, ScaledResolution res, World world, int x, int y, int z); + +} diff --git a/src/main/java/vazkii/botania/api/wand/IWandable.java b/src/main/java/vazkii/botania/api/wand/IWandable.java new file mode 100644 index 0000000..0cdcf1f --- /dev/null +++ b/src/main/java/vazkii/botania/api/wand/IWandable.java @@ -0,0 +1,29 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Jan 22, 2014, 5:12:53 PM (GMT)] + */ +package vazkii.botania.api.wand; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** + * Any block that implements this can be used with the Wand for the Forest for some purpose. + */ +public interface IWandable { + + /** + * Called when the block is used by a wand. Note that the player parameter can be null + * if this function is called from a dispenser. + */ + public boolean onUsedByWand(EntityPlayer player, ItemStack stack, World world, int x, int y, int z, int side); + +} diff --git a/src/main/java/vazkii/botania/api/wand/IWireframeAABBProvider.java b/src/main/java/vazkii/botania/api/wand/IWireframeAABBProvider.java new file mode 100644 index 0000000..d20b666 --- /dev/null +++ b/src/main/java/vazkii/botania/api/wand/IWireframeAABBProvider.java @@ -0,0 +1,25 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Apr 19, 2014, 7:23:59 PM (GMT)] + */ +package vazkii.botania.api.wand; + +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.World; + +/** + * A block that implements this can provide a custom AABB + * for rendering the wireframe with ITileBound. + */ +public interface IWireframeAABBProvider { + + public AxisAlignedBB getWireframeAABB(World world, int x, int y, int z); + +} diff --git a/src/main/java/vazkii/botania/api/wiki/IWikiProvider.java b/src/main/java/vazkii/botania/api/wiki/IWikiProvider.java new file mode 100644 index 0000000..42e6114 --- /dev/null +++ b/src/main/java/vazkii/botania/api/wiki/IWikiProvider.java @@ -0,0 +1,39 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Sep 2, 2014, 5:57:35 PM (GMT)] + */ +package vazkii.botania.api.wiki; + +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.world.World; + +/** + * An interface for a Wiki Provider, these are registered to allow a mod to provide a wiki + * for all the blocks in them, used for the world interaction with the Lexica Botania. + * A simple, mostly all-inclusive implementation can be found on SimpleWikiProvider. + */ +public interface IWikiProvider { + + /** + * Gets the name of the block being looked at for display. + */ + public String getBlockName(World world, MovingObjectPosition pos); + + /** + * Gets the URL to open when the block is clicked. + */ + public String getWikiURL(World world, MovingObjectPosition pos); + + /** + * Gets the name of the wiki for display. + */ + public String getWikiName(World world, MovingObjectPosition pos); + +} diff --git a/src/main/java/vazkii/botania/api/wiki/SimpleWikiProvider.java b/src/main/java/vazkii/botania/api/wiki/SimpleWikiProvider.java new file mode 100644 index 0000000..6105c71 --- /dev/null +++ b/src/main/java/vazkii/botania/api/wiki/SimpleWikiProvider.java @@ -0,0 +1,73 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Sep 2, 2014, 5:58:39 PM (GMT)] + */ +package vazkii.botania.api.wiki; + +import org.apache.commons.lang3.text.WordUtils; + +import net.minecraft.block.Block; +import net.minecraft.item.ItemStack; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.world.World; + +public class SimpleWikiProvider implements IWikiProvider { + + final String name, urlBase, replacement; + + public SimpleWikiProvider(String name, String urlBase) { + this(name, urlBase, "%20"); + } + + public SimpleWikiProvider(String name, String urlBase, String replacement) { + this.name = name; + this.urlBase = urlBase; + this.replacement = replacement; + } + + @Override + public String getBlockName(World world, MovingObjectPosition pos) { + int x = pos.blockX; + int y = pos.blockY; + int z = pos.blockZ; + + Block block = world.getBlock(x, y, z); + if(block == null) + return null; + + ItemStack stack = block.getPickBlock(pos, world, x, y, z); + + if(stack == null || stack.getItem() == null) + stack = new ItemStack(block, 1, world.getBlockMetadata(x, y, z)); + + if(stack.getItem() == null) + return null; + + String name = stack.getDisplayName(); + if(name == null || name.isEmpty()) + return null; + + return name; + } + + @Override + public String getWikiURL(World world, MovingObjectPosition pos) { + String name = getBlockName(world, pos); + if(name == null) + return null; + return String.format(urlBase, WordUtils.capitalizeFully(name).replaceAll(" ", replacement)); + } + + @Override + public String getWikiName(World world, MovingObjectPosition pos) { + return name; + } + +} diff --git a/src/main/java/vazkii/botania/api/wiki/WikiHooks.java b/src/main/java/vazkii/botania/api/wiki/WikiHooks.java new file mode 100644 index 0000000..40f586e --- /dev/null +++ b/src/main/java/vazkii/botania/api/wiki/WikiHooks.java @@ -0,0 +1,43 @@ +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + * + * Botania is Open Source and distributed under a + * Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License + * (http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_GB) + * + * File Created @ [Sep 2, 2014, 6:05:03 PM (GMT)] + */ +package vazkii.botania.api.wiki; + +import java.util.HashMap; +import java.util.Map; + +import net.minecraft.block.Block; +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.common.registry.GameRegistry.UniqueIdentifier; + +public class WikiHooks { + + private static final IWikiProvider FALLBACK_PROVIDER = new SimpleWikiProvider("FTB Wiki", "http://wiki.feed-the-beast.com/%s"); + + private static final Map modWikis = new HashMap(); + + public static IWikiProvider getWikiFor(Block block) { + UniqueIdentifier mod = GameRegistry.findUniqueIdentifierFor(block); + return getWikiFor(mod.modId.toLowerCase()); + } + + public static IWikiProvider getWikiFor(String mod) { + if(!modWikis.containsKey(mod)) + modWikis.put(mod, FALLBACK_PROVIDER); + + return modWikis.get(mod); + } + + public static void registerModWiki(String mod, IWikiProvider provider) { + modWikis.put(mod.toLowerCase(), provider); + } + +} diff --git a/src/main/resources/assets/weaponmod/lang/en_US.lang b/src/main/resources/assets/weaponmod/lang/en_US.lang new file mode 100644 index 0000000..49d713e --- /dev/null +++ b/src/main/resources/assets/weaponmod/lang/en_US.lang @@ -0,0 +1,113 @@ +item.battleaxe.thaumium.name=Thaumium Battleaxe +item.boomerang.thaumium.name=Thaumium Boomerang +item.flail.thaumium.name=Thaumium Flail +item.halberd.thaumium.name=Thaumium Halberd +item.katana.thaumium.name=Thaumium Katana +item.knife.thaumium.name=Thaumium Knife +item.musketbayonet.thaumium.name=Musket with Thaumium Bayonet +item.spear.thaumium.name=Thaumium Spear +item.warhammer.thaumium.name=Thaumium Warhammer + +item.battleaxe.void.name=Void Battleaxe +item.boomerang.void.name=Void Boomerang +item.flail.void.name=Void Flail +item.halberd.void.name=Void Halberd +item.katana.void.name=Void Katana +item.knife.void.name=Void Knife +item.musketbayonet.void.name=Musket with Void Bayonet +item.spear.void.name=Void Spear +item.warhammer.void.name=Void Warhammer + +item.battleaxe.certus.name=Certus Quartz Battleaxe +item.boomerang.certus.name=Certus Quartz Boomerang +item.flail.certus.name=Certus Quartz Flail +item.halberd.certus.name=Certus Quartz Halberd +item.katana.certus.name=Certus Quartz Katana +item.knife.certus.name=Certus Quartz Knife +item.musketbayonet.certus.name=Musket with Certus Quartz Bayonet +item.spear.certus.name=Certus Quartz Spear +item.warhammer.certus.name=Certus Quartz Warhammer + +item.battleaxe.quartz.name=Nether Quartz Battleaxe +item.boomerang.quartz.name=Nether Quartz Boomerang +item.flail.quartz.name=Nether Quartz Flail +item.halberd.quartz.name=Nether Quartz Halberd +item.katana.quartz.name=Nether Quartz Katana +item.knife.quartz.name=Nether Quartz Knife +item.musketbayonet.quartz.name=Musket with Nether Quartz Bayonet +item.spear.quartz.name=Nether Quartz Spear +item.warhammer.quartz.name=Nether Quartz Warhammer + +item.battleaxe.bronze.name=Bronze Battleaxe +item.boomerang.bronze.name=Bronze Boomerang +item.flail.bronze.name=Bronze Flail +item.halberd.bronze.name=Bronze Halberd +item.katana.bronze.name=Bronze Katana +item.knife.bronze.name=Bronze Knife +item.musketbayonet.bronze.name=Musket with Bronze Bayonet +item.spear.bronze.name=Bronze Spear +item.warhammer.bronze.name=Bronze Warhammer + +item.battleaxe.steel.name=Steel Battleaxe +item.boomerang.steel.name=Steel Boomerang +item.flail.steel.name=Steel Flail +item.halberd.steel.name=Steel Halberd +item.katana.steel.name=Steel Katana +item.knife.steel.name=Steel Knife +item.musketbayonet.steel.name=Musket with Steel Bayonet +item.spear.steel.name=Steel Spear +item.warhammer.steel.name=Steel Warhammer + +item.battleaxe.brass.name=Brass Battleaxe +item.boomerang.brass.name=Brass Boomerang +item.flail.brass.name=Brass Flail +item.halberd.brass.name=Brass Halberd +item.katana.brass.name=Brass Katana +item.knife.brass.name=Brass Knife +item.musketbayonet.brass.name=Musket with Brass Bayonet +item.spear.brass.name=Brass Spear +item.warhammer.brass.name=Brass Warhammer + +item.battleaxe.gildediron.name=Gilded Iron Battleaxe +item.boomerang.gildediron.name=Gilded Iron Boomerang +item.flail.gildediron.name=Gilded Iron Flail +item.halberd.gildediron.name=Gilded Iron Halberd +item.katana.gildediron.name=Gilded Iron Katana +item.knife.gildediron.name=Gilded Iron Knife +item.musketbayonet.gildediron.name=Musket with Gilded Iron Bayonet +item.spear.gildediron.name=Gilded Iron Spear +item.warhammer.gildediron.name=Gilded Iron Warhammer + +item.battleaxe.manasteel.name=Manasteel Battleaxe +item.boomerang.manasteel.name=Manasteel Boomerang +item.flail.manasteel.name=Manasteel Flail +item.halberd.manasteel.name=Manasteel Halberd +item.katana.manasteel.name=Manasteel Katana +item.knife.manasteel.name=Manasteel Knife +item.musketbayonet.manasteel.name=Musket with Manasteel Bayonet +item.spear.manasteel.name=Manasteel Spear +item.warhammer.manasteel.name=Manasteel Warhammer + +item.battleaxe.terrasteel.name=Terrasteel Battleaxe +item.boomerang.terrasteel.name=Terrasteel Boomerang +item.flail.terrasteel.name=Terrasteel Flail +item.halberd.terrasteel.name=Terrasteel Halberd +item.katana.terrasteel.name=Terrasteel Katana +item.knife.terrasteel.name=Terrasteel Knife +item.musketbayonet.terrasteel.name=Musket with Terrasteel Bayonet +item.spear.terrasteel.name=Terrasteel Spear +item.warhammer.terrasteel.name=Terrasteel Warhammer + +item.battleaxe.elementium.name=Elementium Battleaxe +item.boomerang.elementium.name=Elementium Boomerang +item.flail.elementium.name=Elementium Flail +item.halberd.elementium.name=Elementium Halberd +item.katana.elementium.name=Elementium Katana +item.knife.elementium.name=Elementium Knife +item.musketbayonet.elementium.name=Musket with Elementium Bayonet +item.spear.elementium.name=Elementium Spear +item.warhammer.elementium.name=Elementium Warhammer + +item.katana.shrouded.name=Aberrant Shrouded Blade + + diff --git a/src/main/resources/assets/weaponmod/textures/items/battleaxe.certus.png b/src/main/resources/assets/weaponmod/textures/items/battleaxe.certus.png new file mode 100644 index 0000000000000000000000000000000000000000..59a4713fa4c029e2f645b124f8b9c9c432df41e0 GIT binary patch literal 15683 zcmeI3e{2**6vqcmq!tkkget^%IUqu0ySsO{z20(nwf0(D;h^?MC`1C=-MMz zsuFN66vA9MUIRPT`rZU=?w#Kv_b!)xinA(M>Q9MCAO=mzk%~n%LrevnXWZeES^uK8CiCSBAb%pEMLyC#ex($9~19N zMAN6H$SjP)7}QJy#qmYs;+?vw8=d+nDf8}86Qi1h!};7r&o>q;n%XdHyAgsc(xQ<@ zOHUlKP0-N05;CmqMwc?J*wveAq)?n;N|tBTbB8H)lrYPa2}>`9OojaDTE&_KluSL* zqU+IMW|cMO5ISmV95WZHnxZF-S$-CuT_|-y2!6%pRb8R|`EJpN1OfrLNOzMDa zT6t5z{G{kV&9zH@kq|05_M#)MmNLu2!3a`KmOoi7cGZmc2 z#rS;fGUGwAJ{j^A9yu><3m+l9AfcirCq->@th4{8DT>I9NL8;IXleG?mMmJh={D93 zR}3G`IihO19mS=D0j-xfZ4j$|j)NE<36m7X=ah@nT!q?CZw9cWGb%{I>n4v)Z<{jAmVqw0T914HWm zcNK66vX^ticBYaO&=RloxEY_|78nUeWS0b$c8;seRrvZUz>5NEX?(67{Vx?LtX;WN z(mJ3LWOEml8@QQ@c5Qv{y0^{9d&tdQw9Nh+-UM^Eg^^9uZ#^`KsNtf`FQpqD?`KDh z6_!h8ew)=eqh0CwUKfWB^mK`iY^dFhhb|(A+TD0)A+l9d&7dor4I8#aSx+{Zdv7y( z2#3K60d00aix1-wjcN);+d?Y3Ng7t`=PR-?xT9#`qR|3vj%;A2RJOek@;X=iVFimHYqML zAIwW}VL-?x#YN_Wc_}Uo2-&2#$b2v_#f1SOn-mwB59Xz~Fd$@;;v)0Gyc8D(gltk= zWImXe;=+KCO^S=m2lG-~7!a~a#8p~&wH9jVecB{?adyg_{STp+ZXI%cQy75W82~)< zEC5%oqR;OE=;8qQVHp78D*%+~o0ksM0Wikb5UOrTo!#9On0vf&QsCXTonP{wRj#?S zPdoWy+0Of3t)2B}$+*+U`u7i|8Rb>WyzMD9@cAobKrl zFFqVUcj@As%iC98oH+f`jMxQ=^#)f#nQ37Bzt{rig@;Jtlg^(*1$L1lm&?5^uPy|8f^Flc9-hAtd^B%@^XF54blh=Z_v-Ij*Mh+z zv-b0ut-oD3?CClfJU_ej3CGqJZbMJ6`>_*C#SOj(&maHv$N|sqUz9w(ZpRofb*+2T U`skh&2smh{ogdo!@Up(Y0EEOQ`~Uy| literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/battleaxe.manasteel.png b/src/main/resources/assets/weaponmod/textures/items/battleaxe.manasteel.png new file mode 100644 index 0000000000000000000000000000000000000000..9d0578595962fc1426f2f8b08fc7cb0e188eebcd GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`3dtTpz6=aistgPb%?u1b{{!il z3=E|P3=FRl7#OT(FffScPl`Y422{&g;1OBOz`!j8!i<;h*8KqrN|m@qlmzFem6RtI zr7{F0X6BXX`MHKDlo{)p>KPike|9nlsygoJ;uvD#zjVSzUM52x*Y%4Wo8D=y5L~o; z$0{yYv7~eI^Y`BBO7#!Lyvvqv-m~J|DksiI1v}k- z{bk(rIVX70r;la-_cl)5dN9pwVyQj<@%Pm;Q#LNnwz_|{Xw~E+nK6`XpN41Rn%_RFL}T!3RZ(kK&`C;2&B+eGnhw%qF|poh0M+k4Rw__I7{s zoA2*8`F?mgtv^2rms7am;z0PJ3>R#wn;4?gd|7yUi(`%pudo!#oX3&5@i@RP7ts5bzGBZID{pNAgTfGyK1CU1QFX_7OIV)Beq z6KmZv+%T(K4qV+jS=YDD>vtQg~gIB`%jwNlGR!Nl$UID5V8S6y!WFNoppiN?C4vBufkEuHYC= zb)|BAoDNyVB39WjifF%IEWfC=0U8qaM7wX?fa!x7>rHAVHi8balt< zdZul0IIh;PdtNb_#EHUV{9K)Gn8<~p^pmhZ)B?_}dh8}9VJ*Vvt&Cmtdh8<{m zF49Reb=?iyv)v7QPRh_dH!+%%S}n{ybG)6-%+#)T>>@%iMmkgJ);GIQSb?tHb98v@ zB6^gAv!32Fo0G|jMZ%uBV}}ECjtqN7GJh$IW~hLkRV_PE^K7SX+wIb5l`RJdxpJ91 zbjGv{yYC(@2xRZcR8IoIisr!*T8bH75_w6fi=ry$RVBxZ8C4V`K}J1^7&Y54o15_% zxw@nvsVZlqF(N(57-;Jlnx}0mO0;hzj-jhf+v#Xt$?Rw?D0Hn>L6|f~dWH*1E!%C| zLBoQjbU~Qa98vj;OkJ{EPqTEmR4Ji`lxZ5O(uB>7l7sxB(U5pq%%pj(sfm167PGpM z&Wq`6&WBj5MdeeWE4JRl8)Y2YK%q5J%;pqH;j_8C&S%Ap%;)nBozFB3Bd?dMN4xtvSiW1^~=~Qybx~<9BtDtM_tWvA>M4o zWU$-9`W2QZtnoLks_D3pm2|uppivNFt&?Ge%CXFxp1|!<9>tHy=jZ5eK#R7aMxp#( z^Mkl{)9Y&vJlaBQ;$OD;C}3PcMlJ}r=C{rNU=CdE;_c0Vtmrv04IBKTsGudjh_+B( zNh`bto4Tw)qalim!3^Kp3`nYiN}3duqyJ?FCTmyU(5x0TN<#2ZLBriNY1^xNx4dnp z-ywJRq>c7pya)!hd%9>A@JEA+3NG6GnqTOof-u!KSuUggYq)T>dw&0%ETRK_U7}+w zjk-zcI$audlhTRuv}JlFd7O=Cj;QdL&FI~`iax?&DXXB(UJ%G;Qn73fV0*1%qL-wL zOTUyIYe>gT;rcvb#4#3*rYiEe?AOduEBY8m{|5-+KLS(bG<@OQ$(zX&-N~p#ES7`- zLN^&MIv>Kza1lW0Cc{PNLwFf30tnq?xafQcFT+Iup_>dBoe$wSMWVq;j2rt7$0HK=<7o88`Ww;0+bd%wt^C7$p7XgHBGF)^%gqPtWfY42bi_VAe zGF$`@y2)_S`4C=)ivU7587?{>!pm?GKPbK?3aAapUjAaEQ9z#<62N+SAn|L6*dOAAKH|;1STy`iau;w_kqn&vfe0 z5S_99_r$}+Eu8tvJMV&PUw;*MM69`wFiX7mzF)zCeLL~vB!U=o0|Xu9OxC|Gm&@Sw zOK$eZ`>@v!~O$o6@}n9ydR zsysM+t@*_8$^E-9eSaoC`S1h(I-VU6o04cSEN<2I`(oT41i({@#V8O!_h9BqT*~ep zBHG}yZ?1!HzyHH0j=+J(9(l-T@_hF~0>ecNrbiGRc63B|0pX0niALd%J~o0`nM360 z2Ca?I43~6}WnSjMKkphsi~^h2c~*Pu5yJ7^#0?@m9IjnI_2czd|GbQKOUF)D-hbxY GOaB0WaOVmD literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/battleaxe.thaumium.png b/src/main/resources/assets/weaponmod/textures/items/battleaxe.thaumium.png new file mode 100644 index 0000000000000000000000000000000000000000..5dee2964108e054ce868b9a558af7826c4c5fce3 GIT binary patch literal 15675 zcmeI3e{2(F7{`wc79D~xFd{L~6bL`Bch~m1_3XMp3v6J=97RR|<$CvaJ7{~gcU!yt zfeSO3Ndjh?p@<4ZBM^eJ1jUd5(clkafP~B_!9Qe)1_+2j1x;kW*Ppj{-76x-ki3^{ z?el)$=lkA$-uHd(`p0$E*DW4XHo1(Vs4=xQ{s#Ct&iH$v6#k!jV?cx-55{X&X%sbj zg7G(k+OcyIMLqF?5^U5P15XN)8nubC8UnUdG!A=Hl&3ls7o`nAw}e2G605TQbo98@ zqR3U&m3)8=#C@PyscBDu+1HjR7r#8YRqEziXpW{ud-T=f$~T8x}x#?Krt=L4pL-NVw~Y@EK@8=mhw6A zmP90dYO=(D2#A81uE9L6XkNTo)m5!o9cIY9JnX=5P6C1a*hSAb8ZA1srY~%T2(n0v zW@^Euq?BRO3?-A6UJ98R^1y2qd zDX^@`B-0b|2&l3WZX4|33bMRl=LDWNdzgBn9&qc(qAuQ%i@C4KN0x-Jnuv%X0 zi%us;yPQrJ9ST)CXoqYEl}^d+kX)fO#6ZBDKE&FuN-f4l$y&?MT4Y&Q1<&!ctHLeO zF4k$M-R_V?J43SUmH_8+N+4%#N*`jqETO<6Cq_(tjI;lzLlm(YGE|MC!KK+|TC#BA zrpwrJ@Z8|moDfmc>Ju}b$E-b7QwdQwb)`Au+5{LMDc7!J-rojr_E^CQZC zFbA60`tN4I&Px@n1BB>GmWNBc(&?bxyo0Aj5SHvBkV7n6nVaFen*mshU`gY0<>-Hz zfx_CAn#EWXkiAUqqH+!Q)1=*5-Mi~;GxQ#Ee@|Lw{|zpJx!OInXnKr?1_2gaxcS9& zq2oNvkha2d$@FhD3TLDx-M_-l!UH~C!Xuk%meJHz_*AourWP_+#1!3Y&yI#Po3e~2 zo6Nm;IeZ8QUKbBHyN5xW(TsW}1tN`p1>Phzqx5sGYz`_EO2T=(w1PDGPxbS=smEb~v;6s87&j(QnE(8cZB)IT=5S8FUfZ#)d3(p5p2`&T( zJ|wvCd=Qo3LV(~yf(y?FQ3);t2tFjZ@O%)J;6i}lLxKy>2T=(w1PDGPxbS=smEb~v z;6s87&j(QnE(8cZB)IT=5S8FUfZ#(cuCl_bwIBxHr%l2aXXi=POW{km7OAEoKvC^8 zD5|5AqJAHMpO+}Ag{7#=>nKWijiMe^yPrL|h@wVtwf_0R)cJS14=wq$e&XiibJxDK zy6fzWk(29pw9ejhgb0rZ+N65HdlJLR6aNHOy4MF zr~mk}akqA#`aJyG#%(`dUU2&D@*lRmy8XS?mu^meXz^0-@wzRiuWt42^pD)Qx3zrD zTT{Ev9k_A*)@L`aym2+4m%DKBPl$1=_+A}J3Zo-+qQ{(zho%r*a{>4rGUHkf{ zhv13MoONYQ@9UpTqx>Vse}D0-?xR;E_o0VR?p*QZo+BUk-Ynhn#kFlg{_7HI{jYst UTK?c?52yIWTr>&BK)SVkS4Q`z2|E`)!uFE z2BN@>N`xTq??xe#5M!eMfI)*XfJh=S5)*?lfoT*p5seA*5}42R_4cfLM8p`9=aQ}c zJ>Tc|eeOQb^Zf4m$Gz6DXuc&A-v3;QyI_3`p=}Orow?r>L=$ z%)b%Tu02yJs-jN~hKx{Pp(txHhoop>;7G+1us20{=cN*o+yM+*7__PJO8e!b$Luy$ zskATU18g8s4cgVZ-XvJkyC^94cF2NapXV#_rbK8E1BPTv#iDUtOjX*`z9Rf?HZyix zx{J|KX|FN|w1olFjOsWGkvA7)@fAQ?dCxFBYR!3M1G*So@ECqGASv+a1NF!mZZq}oJ40b znm#o}WWyD-%SBjA?|;DbxiO>->G@j;dqor1`h(X3l! zS&K=gC*l#%6gAQ_*uxWKdC~0_T~4cqr6=kEw~iti(rvj|`&xVyS&V4Om}L0WnA8TC zM7+(*6dEl(^9xF>)}mSxo)+-AyiBoXOICW3iS=>akm53^_xoUjLsb>HXJsIGB!w0{ z0!IrjH%phhxH8(~j<_OxL~@4}cN$_KU`-!l?bqZ^bE9Of6=*H7tf!3Uc-m7Y$h3!b zJ83}(%QUo91Q~E1w+wRDmh>Uki<2rWa#GaN$2|LgIz$nhAw$)vI$WAPmL&@pZn}&u z0nZO^%?VL8U5*k`QU~T{tF-5KTfTnf%afUt-n615n}y6Ln|lE$US?2h;k5FZ*)( zxm}940maAUE-Ke>FHPF*)xA63Hbd_r_x7Y^_TS(ln5*4Gi>B9nXb@q+g_~bW7dp<% z3~4JYmrVbVSvaGe>HcL-79Q~F5+2!9tBj^L<5R6Nnp((wDy|wnXLdBC*^*^G*<|j$ zOW;E|@OgN+*}V+fjAk^bDG&|$Rd|!s&C<_#vN@f2KHsu+6f+h4w_7*`rN z@W6x(M{gV(SaIyA?C%@!e|&n@vmYE8+YaQO?d+mG)_1mrMD>oi!s@Ze$ z*6;MiO*JP!nb_~XBJCQ}yLZ%x)~(a#99r+b^8UF#s`hHAcUtMox*zEE+#|5B7beq-Se+fJt5?%kJiMrW4m zr7LIL@A$ETX{p+$pZQ`mgkv8$@xr;Lix+-f^Ll*q)u*@4D*f~Dcl%HHgSU2`?r)>| XW~*UC(OvJJt;gD4?cLUH z8bf$91k^;AfS@rZL=b|+Xbh+k5Z}-cFh&vtBQO3V|A3N3NC@+}zTTd8kBAsU@?5gD zzvuh>zR%s~d7j^0|G4#`C67$3xvz$zsEIAjfmZlgYyOQJ3;#cGX;^|E&m z+x)Adw!AToqUNnp!|g_U@G()=;`NfEML>Nfo`k(A$~!-kl;j>@*dm}?P5A5=KG|=# zsfy3OR0y)cWD|(0%>yaWHn1ct5A?_$#XjF(y<+1#FbPT)NpH`nH1IVZ!hjKf27oXERH&SlFV zc7F~0=1nPGVryVgemEHU>`}u=iVTxZr|Z+sdM(w>a2}6`VI7RaLBk%j-k&g}44u%Y z=S&Jd0ieq%HEF0?!e;tP5v|wo+3n^)#Up=R@nmtJgq~*yDKZ%;$#C^7Qz=Q2i#f^O zR4jXHip+o*h=YWo!#u8HUNWi~njY0g8L}vkIxw7*V6ZrL#q*8FD-Nw23;Q5~JkpAp zdbmFcm{y=`y(t+i?1Pswz0%biYFBA;MmU+usOJtc>L_WZl1s}jh1?8z;kAlQDIghI zDy(TSe{Pk93J7gYO}5!f)r6v@^#{ES+PgH>B_j}!4B&@Lk*7J9=7ccIicVJKIGW`} zmbIAVdLkY{O;Nl0M|!x!tW$J2L`Q?w!_pJ=fLlkA4C%UDtbHv$iY#_%skmhL)wt9R zm}H{c%aj@|J&OxUY|>&{3Z545JH1S$W=mFfk%=t{-H;M8XbJdXL%pghqTrU?9B{d5 zk2Av4&IaB|dlV;2E3BJ$M0lPR_=YURV9=UgW*yMvUUQ@5trchuc$V{Ua9c+riidW2 zc#f7hS)tuL@8Wnj3j~i)u(qU^SwEgqVUd$!mOkd$|I;BV*pv;`tm<%S_FI-LT)5dX z)&`y(*;)`{YPK9DrIZfL&E~Tgc3ZK270Z*ElijqUB%6iIFPnP-C|+hnYw5I#nfWxe zd;+hJa?an9KKdBxC`jNoRL&~fYjhJ`>oU?(3N&`ZHSsswJZCsE19kQ?X3dYO|G^yS zQs2Lu0U5}k%frjGBDe+G?ciBD0$fhoB{&)cnU@7#mJ2g{V>7^s0<1`Up&b1$Gf-N) za#Tum1I5o2E~?OQD^1$<)x8_uHs$w_TYJ)S`)_0sEY$AuqUkjs8bnxd;pUgJg^u$w zWo@P9lI!1Y7S332w!hoK!UH~C!Xuw*mC@7=e5zGOQ%jjoBvixi$d86JTe8e2o7}y( z4L*beze^CD@IHn%qZuJJ17hs~72YIuv-ESWd=4s9Ozapf(IVs%b5mt`T+Y_aTq}GS zhra`u;tzqca$3CM+{`bfE4rDkh!+_I0fG++E<7JZCAbhE_>kbj^FdUC3ju-;2`)Sz zL?yToAo!5r!t+5?f(rqH4+$kbj^FdUC3ju-;2`)SzL?yToAo!5r!t+5?f(rqH4+$kbj z^FdUC3ju-;2`)SzL?yToAoviAtETj7El9xkY18n<+1RkMcd)!v~wmnTPlIWX%YUH#VQ8(v%$npDlS?ud?`GQj%A3A?v$ZvAR?-L%?` zho9<8uN%Jq+KJ^e?St#rD(Chd8T`=s+~u}R@9@sRuME$oZeX?#PwRruwP0PPHIOf3isslqO#xCob``x$3@nvI<4b>R~Z!e~2 zEV%uZL&wK&J@2@o_%wU(qZbIODpQGeDv9#t0!Iis;G6+w!@#Ey~Fmh96NdK&!(MMz15AOJ3})Z z&e@N|IuR9j literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/boomerang.manasteel.png b/src/main/resources/assets/weaponmod/textures/items/boomerang.manasteel.png new file mode 100644 index 0000000000000000000000000000000000000000..35148eecac9579b3d86bfa8fa408374119f1dc48 GIT binary patch literal 16426 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 UX6Kp8F&sR-??BIp=L&23Z+$ZQ7@DkaH2}E# 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 C?fDk~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/flail.manasteel.png b/src/main/resources/assets/weaponmod/textures/items/flail.manasteel.png new file mode 100644 index 0000000000000000000000000000000000000000..ce0c35c03e7432b6b91d7ea56018f6a421475dca GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`3dtTpz6=aistgPb%?u1b{{!il z3=E|P3=FRl7#OT(FffScPl`Y422{&g;1OBOz`!j8!i<;h*8KqrN|m@qlmzFem6RtI zr7{F0X6BXX`MHKDlo{)p>KPike|9nls#@&n;uvD#pZw$he|uMn)e4#tP7fGfbU8-M z?ti;~myY=a&jSoIm{NEy<)|I@pT~G&*4(*s8=X`n7%r{RY}+tXg?WRe^kIe=iMweM zYNr@-%nlnkG8f$BIdo!{qlBwa%SRxyg7-lB=DTY9@QFLFVdQ&MBb@0RHoCm;e9( literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/flail.quartz.png b/src/main/resources/assets/weaponmod/textures/items/flail.quartz.png new file mode 100644 index 0000000000000000000000000000000000000000..0f7f74950b0ebb3bf86821dd007f6e893e27b0c7 GIT binary patch literal 16426 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/halberd.manasteel.png b/src/main/resources/assets/weaponmod/textures/items/halberd.manasteel.png new file mode 100644 index 0000000000000000000000000000000000000000..8e2a3be942f56aed80c76631b902d6197b812389 GIT binary patch literal 412 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=k0Y$sR$z3=CDO3=9p;3=BX21L>Cx z45bDP46hOx7_4S6Fo@?*ia+WGRLfc55n0T@z;_sg8IR|$NC65;mAFQf1m~xflqVLY zG6W=M=9TFAxrQi|8S9zq85+8Ob}|R5`s3;17!u+BcA7QcAp-%I*oz7i*#Z@-T>L$~ zk9S&d3b{XIl4)uZE?|C~{b*{au(It_aTaAog>%NIfDBkzu@?XKsrGF+kEcpCy zee;jEe?MM-zIqO0osJ+2^V-LE61R37`tmZ;Qa{x#CZG>flLdU-jPSxuwOm9mR6&Nl* z>DVkB!>QKoe0yE1^3Klb<_0CtcL{CVx1w=lYcdx{x9fzyyIx-nrtRT+_N4gJs*HIx za=WL#O7yck`{c5;^?TEeo<%LIZD+PG_>#+G@tt+UdU+e&@B^N}aA5Fs^>bP0l+XkK DT`Zym literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/halberd.quartz.png b/src/main/resources/assets/weaponmod/textures/items/halberd.quartz.png new file mode 100644 index 0000000000000000000000000000000000000000..3c35d1e3b47715a193130fc901c1648b3b37f800 GIT binary patch literal 19514 zcmeI4Ux*t;7{DhYqNgndZPiM3O%W>XW_Ocp?y}}mYtr@(ntEI#y$WJCyOX=MNjA;y zHMx6HRFL9>A}Brx3JN|{^s$Q6f7F+vB7ISODJUwo#VRPp7vs!scC(ozbLm}jQkaEw zcjlY#&-}h`X6GKZCua`s-!Qgy3;?iUdMZ1M?i~Kzd=vWDT3-GO-EOH)9kBq|cozRc zukPG<4*(B6Z{+9fx!eIoGs_WGHw!S*C|A*F08+afRaH9%ZLR?4jml*B%EzCEIYXZe zAC_}su9|@h#?*2R9$G$_*OrfINjknb*Xq#EmB-k{nM;(k?D4N-;qag=mtOBqctsNC~cWh0|l` zDOJ;p%4~LD%N=S>h8JwRst7{8UXRpc5wkWgNXcYU5Timg%A*mywN$ay24AtZyGA@a zS!iiBqiP#wg~N8$g1Klmy)jeI@QHm$q7x@ z1XzM)Sg|dnC-u~;E||7yEtq{=`r^KhQBHC>-*?Y=%jKS~Eqm_?grJ4Ar>2!(szPBF zTIOO+gL_Y)sci2xd)p|slha`dOZvtR8%7^BEOFJGQgAbrLUUCzHK^KVEpM8ov|D8} z9zrgY;dUH0D!N&>9!v@3=ys~xhG15;VH%ZUoR>silJlad#6$(vq!?F3F<`_UN!ZAl zx=~!}v@xES;))zs;<2EOz(~>tS~|LFs{>gHjt$t+HKl0Q%Br0<%IZ86s+IYa(C!S3 z^b1PKm?g7@!h-2oO6b)c&~l1QnXXv2TG8NiHjO$WhM_A7QBO$G37wCsi8x;@#tXcv zj?27Mly#_UsxHC_2VyQ4RPQpKHMK>&P+F#SWIC?L(9*_pPsWqHIsp^BrWRw# z0*pozy6l+_sCSuuv}T}9PAvt-;OMW_MGrGwuBHqNmF7~QWKrQd+t?v^ytCI6lniG( zs;V^$;>9)@_Ewv}fBD-J)^QfCqH1^}OKW&7Ks_aN^tQwDHCt*%cLE2a?Ai~g_xDj> zfEC(;a!om-`Wvy#qFq;OaL+udi4~T)Yp_#;w44&~o?kLXkONCSv9=7Lg%VH1pv*@n z&^jt;sLm&1Qi6}ef~w0!SuSWrFT<1fLv(H+pjCmZ+Odk7uEVLBnpG4viIyGe~1 zqXA2ESp&T!Exh%|kS9ln6!cU)(oZoUXeqj>3LKZ6J=5()hjH|GfZ+cj(6ycVFPvdM zv}ZI-tAs7)gaATsGF)^%gp}bTfY6%^7o86wWw;0+^d`ea=R-&tE&>R>$#Bv65K@MV z077pvTy#E!l;I+P(3=bwoev>pxCkKhCc{PNLr57e0tmgyaMAe?Qih8FLT@r$bUuWX z;Ua+0n+zA74Tdb zA!WD-AoM1~Mdw3E87=|{y~%LV`4CcuivU7zGF)^%gp}bTfY6%^7o86wWw;0+^d`ea z=R-&tE&>R>NyRnR{n)lzm#c?~b0P_3O2!iY5 z)Q6vgP{?(Kou4^#27L3?Iq=%cFSUjY`G%eUap~vgC#OGXVu$GGd)U3}cBdc9vFt`) zGNcFW{Ec_sb!JGK#Ln-#D+CtnOO6PoAvDwgg3hDyL`M+V`NPr}c=Pn{;H|e`aPoo2 z47CPu08dqq`xEzqz%$;t8MDESpTjzu5cw^Q~V6`*% z0$3A)wanZLVATZHI&&|8RS_7*%)J1vnZU4S?gem71co_tFMxsX*g5U3Hn1UL;6N!D zHuhi)E2d!7*r^0YIdhLfUjn0^xfeiB0_!nzFMuur>os#PfQ~zMK8mH*;e=@TDOgYJ z!5Huv-9Ij0`sF9*+#Vb->Sw10&{5j)(>g$o+GmIT4gyHhac1urIid!tfoAjZbDPhe V+txt;?-u~mdk<#cf8^-1{{jBbuMYqK literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/halberd.thaumium.png b/src/main/resources/assets/weaponmod/textures/items/halberd.thaumium.png new file mode 100644 index 0000000000000000000000000000000000000000..f4bd7aacd670d370760b0d059f91684084b26d18 GIT binary patch literal 15808 zcmeI3d2AF_9LERRD6O`h@c=aA;>9tYV|TXQVRr$$XbWyBZPnJ3*_pTPq`N!I&a}I& z3JMy7iDxKy!~?mi2DQcu6;ZUJF;TG+?*jyh#t0ESYtT1)_wDwHSB%Nqq@De}@B96J zGoRmkznT4GmNhnJwp z0!2-~PHSm3Tm9!tiXN_#RXqTz65%MEO;PR{iKwh}0+SAab}izu?R{>ujn-6;?IO|7 z`J=U%ubJO zmX(lh^*7SBdJNEFmB=WZz|+;PDqeKBczzl!aJ-%6IaY8nJTEz_CEiJ=KQ?bU{N|3S zL8-}iZaN*bJhl$gj7lsUkH@Rx_9{Kr&hjpoi{%7X5EwXvF?u4VoM0lxq*Rbh93L>0 zm=-lPJwjV?<$&I0dTcf;QTCI*u5dJ)C}O19L5gfbjKE&c&G+KJ1fNcVX z-W5~8>~44|lZsuvsReVz84<}+Mm=|s&_;2yl$2X?DWodohSw_9#(-?6D=K=wrYyvM_iVlY77+!4QILXdQa7}U!iR1Euq-G*9 z{JN?Idq&1^ws4{(I3#;@evG`CXbiY@RN0gdDN6p_yf~^N1@%~1HoaO{ZU<~M((Yz+ zgLyNv3rechLwXFJ7Vz5LY_Z`yujC?=>LZ3JM-))+^TL5DO;e=+XLs2-A;>st1ep;; zhl6nmE(a43dAV8^#A;QB(F@!QLi=>3%i1XE&?*e=Q0;JQTZIVRYUq4V4eLeGn7u*u1xygAm{|Jf8p!W5*c(+s#Yd-9enT)4?L)(jSo9L)$J zE!mEua?AkMX7kuGyDi(lvhB(8Np4z6R;)(mRjj=LR5v?fGeJv&(y&^;9cD`Uph8i{w$U8(gtTL-RC$lf$)1@Sg%9KKcL1CH zAyCjxvp1Z7@=NZD{>i9FERqBPf;R~+JRd|QxDX(CliYCuO_Y8`O}qaD+bS{s4-8~`)0KyKKyvaz}&I(CvKfFZ^`EuS31t_KmC-Z zPJYz`r@cI@|D{3K%7Z0)9$341)dd~8w$OirbM>GR<0dvo>b2M2yZ_X?<~+E!=k22^ zZ@x0VcX)WwqR$RLE4s@0{8^7L-n(t`JI~$PROz{;^oupkCtqC=O3YKGz8y8)htbtn zFKlO?x%^c}#gyISskzU-GIjU(b=r{|27i41oy}(^dN;0}q(Gm6HFGDv_|zq}JJ-)& zdg%+VZ#&pW^)K%nx4q)PW6DR&`9n}^-9C0%|KL#P-B15`)V3>6oY_-CHSDy#RCC{k z>A$==ymRSVcgfZP`+2)IE?>E*G+HKpGk?|2ASm7?lrH~1boXTg%+ E0p62kdjJ3c literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/halberd.void.png b/src/main/resources/assets/weaponmod/textures/items/halberd.void.png new file mode 100644 index 0000000000000000000000000000000000000000..b18f76054abebbf4544c9519c2ccf94b836070f6 GIT binary patch literal 15807 zcmeI3du$Zf6^F+O5O4^2KugO*nrz;svoo{1vv{Ywi@D>Vs~df zGxo0CN(Mp*kU*jUArFX%5+wwZRKlT(gc4H(wbYF}h|BarWYw%-S zqO!@Ls0oLxzmlypCQPNMpRG~r8qLP=0#VjtPD#;Pfio3Lz}Xb#pOs2T@(N(mt)NYf z2OR(0-|wJRCE#cf!dy5}4%*eq9vv*|sjicIR>(fZF)LW=Pl-?<226=g#iDUTOa&Zi zT@ik_hFJ%lo?@;DIA&W3>BevkU9RbX7Mubjb1t5q>2vae$H((OrCl8FW_gZv`52xT zJu^k#OJ@&9uoQmt>q^Ws}LIGwF6}dK=68d_I}yG+;|`(lG6zRL)O)VscLcB(v@1ZPBY+eSc&pS_PSz;e4@CKWd|v;DJjA7PL3@W zq{#W0M5i82pPC}GAPQn2ZW=I-FB+F<*G$c5*G5R0caNAD)+8Lx=Pr7_u~^a6hFQ@C z5oD1TjWp`I6M(G+hSsUeprQ+2$^*r&-c%!n;tWx;JR_bvNU0-)S)NQ-dMRWoC5^}YEIPYT>VgmmNhS!wrRZUJj^TwmjuYLS z2-hU%5joB#l9`EUgf&HtbPv_=)^UR9@j@B9hHWOQ0k@7KnbIw(*yq}G6j_XDdQ38d zYD{VaY$D#~XA6V2nfV1JmTOT>ho=RCZa-UW*cO#uWMWm^Fr~N*szO0H;8aybRD5Ob z2q(x)gySO&Cwn}M6!E$lS!#7FZr;QO-_p1=2&O{Wm6Q98J4P2HQ>_hwk=t> zaMNvU5$G5?nsY?ebUR8&x&f@s7I5TtTfTqg+mjWO-n615Ta7FzTYCX0es;)c;k5FR z*)Vl@0dI|RM&A}ba*kv>h~qX?Mk+mPWD!G)m`O+4lOP=Lql1_I+MD^r+O8Lsm(xN{f}Xq6NpA_%Q=Bv;|DRsomD@$l}NYe(Nn z1qy3dZkOV1Knb$Bi^>grpNe*CeeWx8o8kA6?|0EM`)_Cy%=PZ!P1A2ZG>EX_!p$$G z8y)Xwhm94MOJ;tf)i|S_>G?h{2M_pk36E^3-HnDe;Y00iG_(*|A6LzwE1L}&wnbS_ zHko_xBKQyvf?h#z!}}OIj7HR`DG+T8sqiLgSgqd;Go@otN72BhkpgXwY+$BTw#Vgk z&&-U%hjI8jfX)997}ienH=J+sOW}&XNmWFPBtd}SO@a&02k{bI2oStUaN+qNUV;k& zf;R~+JRihMa3MhOCc%a0gLnxp1PI4T@Fu~9=Yx0& zE(8ePB)IT=5HG=n0KuCC7oHE|CAbhEc$475^Fh1>7Xk!t5?pvbh?n3(fZ$Dn3(p7f z5?lxnyh(83`5<0`3ju;R2`)Sz#7l4?K=39OS83tZS`dft(f|WuQVT_iFHzKF?Sq|#H zcKL}9PHY^v@7Z0k_-)4G`?vl4=GESd{SCWz&gng&oUL8GZrPsZb(LS7J-$I;-#q%G zffrNm>h|A^TlwelFZ_ZzbN!Q7ChNakLKYewVbJ>~yMlS99 zyy@P7x2|6@Z@ip(yZ*vw=ApK$Pb_=yZ_D5An*03vyLXhlznFS>_noKDtehci>HDH& zBHMC)^x?JKwPeYaHT#$RzWvl6)Z_Z+gMp{ocK-O0+Y%igA3b#Eg1Y`U{yLSuuz;-s=(sc3hdmlYG zcyQDP{o{L9Id-sXZd`mWd{t-^DqfpW-_m4i5(Fk6)nrPmK9++JT>Z RYQ17zRZ$&!e@@Hl{{bU$ZSepA literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/katana.certus.png b/src/main/resources/assets/weaponmod/textures/items/katana.certus.png new file mode 100644 index 0000000000000000000000000000000000000000..bcbea6e714b0da21b98af6cc89a1260bc22b6f3f GIT binary patch literal 15526 zcmeI3PmI)59LLK+v%3j`#6Uteq0WXxgPs1FKRd0R!DR;AiOjlL23Rl(ukD-N%1m3^ zE;G9!5nL{C|IWn({Hz7k_i zBOBYFDhVYg59iIvB^T~lnkwr{M|9bUZO@IU4Fw6*pbywat!jBnBO42K6?7gn^D#E; z;vdPzCV~Ok+0rzdw_V7l;werSB#|AL<6oaK!*McO(A z=;^NM_@-^KfiBSO1wR{$1p{?Ht?Q~eoq;T`#ST&A8^GbkxWM-dGW1T2v*1?4sTn#C ztFQ(w-$QX?-#BO9_HA$89x!CbJ#b)@lTxWOcHjBdYJG?H{GCS;f)>)gkzRSxf&2{g z>;+ecJCCAE8S8iTzFFxeXO&Xm88~;?Fb9MMo@Q9M6q*@Q(X}dh7XsgQ%eGz3HCNem z8zGy|vrp_dEyJ#RPpUlLyPN8+5G(*6=Fn11a-zVAsj?s_NwgXzPDm<(5D{ti#578_ zVOADbYmAqLgd%2?gb>w;^u#sL)-iw&?n))vH=<+cO2u|-z|WaAFb8?Znp631W29$i zK`D8=YP)D!FqcsIe$A1naFHoR%kzPy!(t(a8sesDD8hImqXCfSl3G&aB$$*rP19s9 zgG`|!%Na>XhY(ApXn2ow!PXaojna}fkaR+>NI=R!PE4TGB(x;pw2Urs9Rcm)zoyb<0*_*(-qukVwgbyC0J`XL@ zhH6TMy#|YTcEzs)7f#HfHSsswyeYUk0#{b~pypT2{~!k*IC^gx&;$S~2~gqEhLGV< zCCYFam^L_FlM+dJJOfh_szd)e1MPAo$nA3Uzht1hcJ+B+%|Ro_w=b&Q@E|4a?&{t> zC#`!Ad9ah#+<&W!V7qqr7ELvHXi!kWMVlXlg-%rYp0@6CY4)ED3TJg8>@TNeQAnbv zOY~`lM%{Sm0di>6jfZw4_gbc(LwBTbqF8ezDtNMK-h20;hj5rnr&5WO%Hz#=#I)If z)!BlHZjxS5`bBhG4P$Ue-@pTd0wa!AU^7*b$K|kQHe1odIQk#Jcm4?Ul+(@)=YF1a zujqcNVp?<%3<%kzxX64kFU5rcA)6EznGfcrxG*4Olj0)t!Mqd~283)J zkWGq<%m?#QTo@3tNpX?+U|xy~141?_E;1j?OL1X9$R@=_=7V`DE({3Sq`1g@FfYZ0 z0U?_d7nu*{rMNI4WRv0|^TE6n7Y2lEQe0#{n3v+hfRIg!i_8b}Qd}4ivPp4~`Cwj( z3j;znDK0V}%u8`$K*%P=MdpKfDJ~2M*`&D0d@wJ?g#jU(6c?Ef=B2nWAY_x`BJ;t# z6c+}BY!Y#ebYHE77J8qyj$WKScm4ez&`Yljn5C@@b9|X$e!GK?w-{zYV3_X@ zGmLVUVK&)k4qe-Y`kpHmCd!Q)@1Ef{FAM7npNwr=|J{wVFD{>Y=F4A3v-_q_T;IC% z_6NnECWbGr5fANNdE@hSlkcSd$cW!=P+u)>(Jmhz{xEaObnm(0m7y;xf1bbWl#Xv~j5R)8e(TqZuiqScX;}JwRC#aTo0m47 xIK9ouorcHGTwVG2R&Hwh!Nv4*FK}1ZFz3t14qh30ERW{N6n9P)F6=n`+FvYj)xH1# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/katana.manasteel.png b/src/main/resources/assets/weaponmod/textures/items/katana.manasteel.png new file mode 100644 index 0000000000000000000000000000000000000000..7a65747e8e91e726336b4d71842f8dcda52bb3e9 GIT binary patch literal 330 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`3dtTpz6=aistgPb%?u1b{{!il z3=E|P3=FRl7#OT(FffScPl`Y422{&g;1OBOz`(a3gc&VZgH?cnQYEetCBgY=CFO}l zsSE*$nRz98ey$-3WyX4@dWMGXpPkHss#bZrIEGmGPwm^t%Vfyo8XU;P+Vrf7t4c+R zOUgzapJ^zlgy^H2vwR?Zv4(W&oeW> z`LOqpyPMapo?Lx#6(MwTW4*dXzfZC2_%rnXGk**){W{TE-w6?V?jE~V-udb734~t# z(5r7p+qE}rCunD}8#G9^-|o=b2$e4OJJ`8RBB?=kJ-?iJ@YOdN$#ct@n`TX|b=Jt9 zw|>|q*AK7Nox|IX;lAvLXNM+w&Je2jzU_bP5daNI&H45 zvlm1`xECyFa-3e+FrAZHZQSu0t;0p+h-4 zZ}gGZoJ`J?6U!{@JL!81WGpk3#YWLAl;)qn}Qq0MkDr;t4RqY&Ijk>JnY*kH}3~K_9THt!kgK3XKUCY^~ zW}8OZBUKZ6(5>U*2ruQ5uAB049lIHH+c>ItZM;jAj=x({CWWb*;{|1}1+AbcWGlii%9%Z{7FvZWV`a^7v^RRdctE;M3@ zwOU#}V_glLeYR0X)-JU+tfr3jB9S$NPL0u^){Ua0%Z0pYk)}pWL)R1Qlzhhe&8|le zIowLsVZDFUCg#}8G_~%9bZH)>mMmSk@iBItygOZ*BwAj49CdIvBy6*lGs$inpI_tS ziD}|ZYh#BUWEF?)1>%;JsnSWe#>$b*o1MVrC=dNp^2KfR_K45hP(!P@)?$+|XhuEU zC6{*TnmA&c4-Kak(7B|rGr#5i2XheOJC8R54He_2ftz&Cs70BcL`Ats@~-SObR%aK zip13EIrOh*pioy0TPxbCl^jR^%M47`uCs^zUE)@hWKc=L(==(zoqLZlY492HbWhrF z|4ko)$=N-7XqMPZgG~=yy7_T@&}k)QrfjlYhV{4E!P(l6>szL!sX6*~Nk1cLIt`^e zd}%rjr4!{1--{~ri4=Df6sJ_|&1U%Qy-r`kNhNQZhFMZzF;r}NebU;ldh{U~vZG(i zk2EkbSGcoCm`aRLNWF2`r)u#~=x)4v0h@gD*+$LaWi^CWL3BYKjqz)Lg&fbc_s zi_ZsS1ug)D9|~N2J|HV_0U-QP;NtTES%C`x;fDejpAX0iTmT3^6u9_&Kvv)aK=`4+ z#peUE0v7khW^!-Enqg%;Y->M;Wcn+cWK0xTN0sa0Jp?wvh-)o30;7}@iWC#EK7>DFP(v=?Y; zgGFLGgrj=^#jI6!F>yQrJb*`uxdu?2j5%pJX?O-An;Ledr)rUSrUy(&#}^wU-#qa= z0|sYoa+G++;EM75fV_Tsst43?W|+zNrwkJDxzo?G9wa>(Pgh!$zCXtHQBJuq&|f}| z?)~r({rtOzQ-~DK1sXdk+bGp0iJ{_l9P2a~|9hod8NQ>D$?dD+c!x+Ln(eY1*_4XyWaeZuZZb2@ zOq%S9*jA`i!OK1r?Zc|zrG1eKDncLZLhFmKQmP=7K6!yER-r|to|$BmFWIEWN*_-k zJKvu3|NiI9?|kQEUgr4t*put}w)7!{){Ty&C&=|4|GVZc^7p}OH&t?3Yme-65n6xF z|E_rc;_MAfZ4j?~IFQ6rStS+iAb276o{Pa9@3^xN65L!6-} zLsN1_$k@ZUXpGD`cyewmtIf@5aXqv%)t9I##Gs5lm8+FYrmNJFp}j>SdsF-{W1C@%`U6c3A{5*tv&ey;HerTR#e zaP)#Qk>1@Hj{KJl6+O>Zc)nV#Myk<>QH0%D(^G3<)7@G(S@KC^ zS91*8Gc1$yebu~G@sgpCKTz}2xUaI^9LRJV>1Jnb%uis~ zsyG_nb%@-`)^2z28HLv3v^n`bJ?D;VMvpYVr=Av+LVbl2ef=XjBr}@aEg>-EG!CPQO*j25+l_pg@u?R2*9MS?C{7~ zx>1;I_vp_GvLeY!GzvX{veScX9bNU*|KtL-z(?1Vg5{J|FJ+X~Y0TT^bb@a+0%fzH zlwqr6Ib>Qm6;1Hnnn6}jWXh=Nda9}6(R7M5L<~b$qVa;HN`p8oMhU-YKBk8AgPIf` z=$GTTAYwTxNdd%62Bt5wPFq^V-zW`h{Wh&Z`ZDXijzJDNwFET&>~D97E;h@C8Zlf_ znzNu}N#O>^*d%_Ty>+RhWCX{NtvW9DH(N5awA-5JSMzxCbAnB)sG5I}r8IvpU_HUN zwYH|!%xt6?|91iF{vf^g7}X*+Z?&Q7R)MOwiE97thbU!1oCvkHy=;h7rD6y?r_k$qdRO2?bslY z1~q25sED9|;es@%F~dbg1O*Hiq(O}tE-E4@V7MR+YRqs^5kUdN1!+)YhKq^_3K%X( zgBmkjR76m~a6uZ>nBk%#f&zvM(xAo+7Zni{FkFxZHDIY zL5&$MDk3OgxF8K`%y3Z=K>@=BX;5Q^i;4&e7%oVI8Z%r}L{PwRK^oMU;i4jf0)`9H zpvDXr6%iCLT#yDeX1J(`pn&0mG^jDdMMVS!3>Tz9jTtT~A}C4TlAR%$vQ4(`VpG@MNK<^UlbM@j+GHl3 znKap@#agjYAB)I}_)ro1Rt29#)E4ZUpkmQdC{%q>5h{oeT4=p9`I@~+uB%pjxq*C~ zd+zz)JHLC*$-K;|*}YG$AKNkp09ZdWot;D98~pd`d(h|BUvFvXYfXK6zYD;<=l%B` z2fseG1_1eUGhgruxjl+**P@zX7h$wjtE1Tfq;|IIntlj+Oc9n%D;>H1;U^KsG}4iM zQjX8nGq7S#FFJ63ac^ECMM+GS^3&InO$O|z};5kud1wn}?6(PZNUJ-Q+{Yp7T zNtw&;?ktC_bfn^Wb%o=a&1SS2i`q_^6J%NDc##uD7R_MY1ReZ?-do6WJM0ieuBFvEAZf(*SEQ*SucU~7iX!78jl z%X3kjFf^`Su|3zNZ})q(b|IQs`Qhi~}{#cJj7eRohuM+eOG^ zGR$N9Ov|vF?v50P&+Z>}UkGM352`2?uL@BHhnu%+m(lInoTaik5Zb-+_m6Gk$G*2~aS{ZV6tDNHcgQ1zdgiH^eR$%rS}VoVd*iG-Gj zPss6P0_p+8TrM0wAf2`KhF>ThX#+{e2bI`nMTA5r26qe%+&?NX@ zfAp{DcB*1pbP)^)*`&D0d@wJ?g#jU(6c?Ef=B2nWAY_x`BJ;t#6c+}BY*JigKA4x{ z!hn!Xii^w#^HN+G5VA>ek@;X=iVFimHYqMLAIwW}VL-?x#YN_Wc_}Uo2-&2#$b2v_ z#f1SOn-mwB59Xz~Fd$@;;v)0Gyc8D(gltk=WImXe;=+KCO^S=m2lG-~7!a~aagq68 zUWy9?LN+NbG9S!KabZBnCdEbOgLx?~3<%kzxX64kFU5rcA)6EznGfcrxG*4Olj0)t z!Mqd~283)9agFt#(u5XzG_#4G!Q69GLC<*tMxUO`0kF6ofa5O#@cS+F{UZPk9)OJ+&5;jllj(_w@*L*z^d_eQ@VWd@a)ECbbjOJpTSoR@77bT%@0j{ zb~bbJl}E218-EdearM3VOM5PC8T<6?jS~;QwluDO>Ain)SLp&*D86GZy}1eevG(Kp z3)ki+KYI6Wb@gTQg}26!K2q7V_UMLJ%ja)g{9*gPUv|%a`|{SpbHYLU&Ql*;_-)5` x_q~2suA*&%nW??mbGr_l_!BzYU!(v4 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/knife.certus.png b/src/main/resources/assets/weaponmod/textures/items/knife.certus.png new file mode 100644 index 0000000000000000000000000000000000000000..20011b440c2c000916dd2f73a6b420851d6276c0 GIT binary patch literal 15592 zcmeI3U2GIp6vwAAAhdy0e2~}&mIdnv&d$f~?8mUX6uQMWxU?xtDG3U*Gk3Q`cV~u~ zDZA~91bu0u327u6B@q%Hh(w4cM2#k*!6pU`;)^MX)dz_|i9Vnbq6F{k=k)IG6%k`d z?j+mYbI(2hGxNLWo|!((^w8F)mbE|JPEpjdf&RoW{O)u4f2T!J z%g;HVw!`a|cTv>(7u3|KJ(_%4l=Zw%QuH+N74rt1O;OPeMMILuf$d3ytg6MlzkKkK z*P|*i?+zi!CXHS&ruI*nVB6Hzlsq*qM-=adczd)cLV-N6B~LM*(=4$V^Okf)_}dv~ zyq?k&dpzdd=p^)vCWkz|x(PgjPoQO%=RBc^j}rnBj(gI>vz(vdScZ?#947`sA{X>j z4sX02{)(DPMjTFTuB3xj%sXb=hR865Lcv$?`*btQaFIxaVR?qsJ&9-11*EG%;({0@v(_5shxmzZNYm!XXayLESe7RZl-iS z7cW=YP!*x4x7YL74pme1g7tWmL1)*Ox-J9~k`3ap6azHJ(wvZDS<%mm0gh$^BFnl& z$}Y7#jTlmkAUB#&;Z4$VT0aNxeWe)G(KK*pt3a2d5?Ed;*W+@jXO>6d!#MmufT{f> z(9lk6H=MiqqkctqQx(x7Nf01-li4T@Fu~9=Yx0&E(8ePB)IT=5HG=n0KuCC7oHE|CAbhE zc$475^Fh1>7Xk!t5?pvbh?n3(fZ$Dn3(p7f5?lxnyh(83`5<0`3ju;R2`)Sz#7l4? zK=3BPh3A8K2`&T(-Xys2d=M|eg#f{u1Q(tU;w88cAb6AD!t+7A1Q!AXZxUR1K8Tm# zLV(~+f(y?F@e*7J5WI=S)n0$K7HIH&+5&uW_Eh|(41DR8@pV|HCW;l0#Ah9u3ymWkqTYj*ov+vf*j!p8hMI-Zjrss~G z`ORnVI{Qh-mlrRt9PAlPpPnAxw`j|{OZuA4D|%jjBPU$j-97i{TCV%S7eD{?mCHRh zufPApmem`c={#}ao3{^i&3@7L+3CTzq>-7|1KE+8y~}=@+kH9tn%sHx3etjj5L1X z<14?PHJ>~5#PkwMTY0|YtJCjv&A!+DKxTf|n`;kt&GP4lR?it9#zRA^R?T0(Z}$5L Y74A-5m42R_hF3}r^leR?+O+53Uz}t4uK)l5 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/knife.manasteel.png b/src/main/resources/assets/weaponmod/textures/items/knife.manasteel.png new file mode 100644 index 0000000000000000000000000000000000000000..41ac1fc1e0f544449dd0b89d38fee2a5352c2445 GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`3dtTpz6=aistgPb%?u1b{{!il z3=E|P3=FRl7#OT(FffScPl`Y422{&g;1OBOz`%DHgc*KPike|9nls#@&n;uvD#zjVSz-WCHM*OeK5P4A>KR=$XA ze5ba{Q=(H*V@3lnkA0W!Y?YWr+Hp>E{@ZnQb^KGZ(owYX`8d!1$Oj#cr43u&u-9H+ zyT{@5jc%@_Pg_s#<-G5CvY(YB*5=fX=QRqS{ZCD7w0zMdBRPYaY1fnKJZBPfvS$4X z+vgxUbIvhcyC+W;Ry$6aSFVdQ&MBb@0A;Lkw*UYD literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/knife.quartz.png b/src/main/resources/assets/weaponmod/textures/items/knife.quartz.png new file mode 100644 index 0000000000000000000000000000000000000000..11246223f7bb8d0287f3b384990a8cd729f89cc6 GIT binary patch literal 16426 zcmeI3%ZnUE7{F^KNL<+vQ1FpMnhAjf?diw#yxN%w>r9eebmFp^kX<~Op6;66CNte_ zcTZ+^PohEy-UPv`R}b;%L81tHkq{6M{sH14dWhgjJd9QSnx2~Ja+8fnpc;C+zWVBW z)UT?(?mf({jY}6-mS0{50IaO9wKmc7IKGcQjsBkebE2WgGtSz!2f(rK@V)fOE5}X% z@Y;uFXUpGezp3i>Ag>vA7v{$U2aN`xc5duw`gQ1YUASXf_1uH6zR7W>QO{j1w#By7 zguCY2z6&q!U+U=l*Y&EAJJ(pQjaB4e0DX-c5Bip;j_bL=uZr5ZTgY+25dV5Tw~7OD zTkQ?5X}gds=8L>8$`V(u=B1)im84fWS(FNbBnonsmn2mwt5S)Ju3TdowQ8=>Q#V@| zqHsv6=XQPHQ3YW%8s$fYyzTA?QngwYL|Kq!9*y9=JPh@lD&} zuwSif5B+*BhXW;7G_Qe^1hTw{9ik|VHAj&0qOi!w&=VVH==Ouu3|)YIIDnS#Avj+<2|au0>hSyxG?i0} zX78K5>Eg_I!kWz7;n>VD!Ik+pA2!fdRCr0`rD8`E)qt)`$3@M6M0wT2!=38TLxN($h=4SXH__x(j@vQqgrul*$S$#jaE4bFSZV zO;qHxergQP{$WEba5EQb&GgXL+)Hg)v~hznb{W1q+Z!wTW>AhC&GjHYZ1r4x+LHQ} zlqYNx99mV=aUpBy_$)x9Cd~9s(@HEOGjo0c4@NokpEA#mG1`R|?LdXDf>GH{JiF(Q zG#9S!pgr*~$2@d6Ye9Oh3ApC>&HrExJnhEeR=_Y6D0P(zFUlg?-33&8D(E2bQnw^l zx=_}nVzR=IwgR#$$|`z4MkVckS%K-^)ps>(2O13_-nMbaleB0Dt9y@pZ06q~PxhjP z=Wn(M#RpD>6;1Nz-k* zX_s2r=>GsA`A1-`oF*@v$Jv<9=y7@_e6b(|5W2{4 z(fJTshKm3~7a1-(A41D;5kTl7!$s#qXc;a72wh~j=zIt*!$kn0iwqZ?520na2q1Kk z;iB^)vIv+yIa1lW0 zBEv=JLueT;0tj7XxafQcEyG0sp^FR`oe!a9xCkJ0k>R5AA+!t^0fa6xTy#E!mf<3R z&_#xe&WF%4Tm%rh$Z*m55L$+d074fTE;=7V%Wx4u=pw^K=R;^2E&>Q$q~cnh{9c+cf~xPXTzr{`j5mF92|a zTW_s)#!KM%kq3V-O(tmQA+DzmVH=npc^C(Za5hQz?vFn&1-5t!2e}LRGm}4l|8?^9 zmtRb9JGME{6maA_ckY0DcYgq~QkqRV_LTKZN5&aMa*}n@SmYqf7&%Jpl1A(R8=)J} zjIll*pEPg>Hi{v|z|v{s$Z2D2lL;{f)@(Kb0vIeAZlmSPhKRkVv%qZ}by4Ja3Nu^z zqVoLYFwJ$fBI|{J6b<~ LsdfAHYw!O9Ug+|n literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/knife.thaumium.png b/src/main/resources/assets/weaponmod/textures/items/knife.thaumium.png new file mode 100644 index 0000000000000000000000000000000000000000..35d0421cbc87898a0deb47fd3078bd0f9f26d263 GIT binary patch literal 15591 zcmeI3TWl0n7{>=O3QbCghD(sdaSIB;*}3fOc4ye#0^QbDU1&;?B_zn~%-MG6?#wbX zWw%YFRU|H{&A7Hi}yMsNR=!l8O6e)y(=8%}fD*A)AA}DJs%d$SLX|aOf21*Nv#}{JS6c zXkCl?)&>(?BG(QE^sW&LtR7j}r;ZG&lIClRHAMKQ>!_-AuCfn zHBDtf24sQZ*f5W8n3o$c9n&5#CmFITPdYH1lSHCAcEj_{W*ZJ|I~`jff-=&EnRefB z4zRtzHis+~bZmi_($eVa9X(x}oC!{@GU>U4f<8%_tCZ4;OQAGF5qPa~y9E@-wE9dl z6DzH$)bV0MWmL2FJ_!mS`3V#Kr>VmL`mG4K;$ z0^zW#@*LkPf>6cUlU`@N%FA{GAGFJ{#Y()|H};2)~-6B82vzt zv6W?8X}F#y?aJ!jRd1X6d&u=YX{G%)u?SXbcYV=}xDO37EVyv2T=(w1PDGPxbS=smEb~v;6s87&j(QnE(8cZB)IT=5S8FU zfZ#)d3(p5p2`&T(J|wvCd=Qo3LV(~yf(y?FQ3);t2tFjZ@O%)J;6i}lLxKy>2T=(w z1PDGPxbS=smEb~v;6s87&j(QnE(8cZB)IT=5S8FUfZ#)d3(p5p2`&T(J|wvCd=Qo3 zLV(~yf(y?FQ3);t2tLH(YO1|j3k>)^Z63ZjdsL<`!k2DowW~KlQ6mc}YHS-tUAzpx zf1;=%j-r0vNKx`$ikf5Ye(-oF?E7tZe0g8t^uFDE)3IeUJH~fxzxk<+ckDel`|zw2 z(@%YLEHLfmkMBz+vtaQ9A>aO6)-N%+(AQ&~>WZz=^B4Nh?L2U@BPt&lPlun_Ef|-= z-EZ8u`Pm;w-Z?(+%dOj~@k9C7-|k+zZB=3PtHT?zuRVRVZSJzzcyj)|W3T*n>CKkW zmkvxnv*`0PUAw+NJ?n)dduE+kG^J;7zJ6}XrXLUjvpMCh(vqJMGc%f8x$IAGj6&oM<3%QQ?6951J literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/knife.void.png b/src/main/resources/assets/weaponmod/textures/items/knife.void.png new file mode 100644 index 0000000000000000000000000000000000000000..d7ddf7a7357314dcdc1fe60f316e3d7b50f8fe51 GIT binary patch literal 15602 zcmeI3TZ|J`7{^E1h^$;pG>pVwFhM5v0k>*$V1lW_Hl|JiEJR`7Jc53C@x|pLG4H~E5o6v!@7ek>CFG##3ai|Ap4(k>ua=JOMY*O`! zLQ~0WIZHEi*7gMnW60`ox$J>zugZC4bG3nVv%(HhCNdPi&f(OBj`1T94`CkmYC8xRE9BgkHn6TGq@I84et zF^`y`YRTcr9{vHrCwqdjILX7&6Zb${M+FwRAQxv}hmWerNh6;HRz%B!6y$SyD$Lg# z9X)FcO71i=Mjjm&jCjI)vt~zDX_3i2x@iGjfj!X(YH(|sDhHB5zY+i{7fgga=))^< zz=vQ00f>ShNPbCGN)Tf)XL^Hm)KG@(jZ(2zk+t9j!2nG9Id4+&b3(|Q;LzK{d4fSj z5d|^eh5o9wBfY_TRbE3y4rCmC?4$puLo~5z7^+({(b61tELpU0OJ%GdZl2s)6*5|> z9OXdXg!X3Za8-9(t$x+YlbuuAv@%faLKac%y#UoPKdH5TShdVbn$|dh7e=}4??|6| zj6xdfqzzTJD)pM$#59st0p#J*6j~F1v(3wflQVGVFmKoVjP@VQfeE(!yBSbbFBB8r zASXxyTHPL0dxByJ)uV)82qvHeL|<)&FKz}TS&(FOeXNwU|78a1Ygb7FJq6VWUtPA< zhRbQvF0Afd^tNfdhFsp0R^ES;i(s{OHx|vXebXSLf{QjkC>1&}%r~^vmrJ>S+%BA% zp;G^lUqCN(cZpt=RHuxmt|O;9WjwW>xklHlh*TL3Yj$MWcQ)l~Z$G*ThY`Qe=kbMk zycy5v)rv3^k80>5Y1*Y_WImWmabZBnA;m@JgQ*l3280|^Tx33&N^xO8$RWi= z=7Xse7Y2kJQe0#{m`ZVBK*%A*MdpL46c+}B98z3lKA1{zVL-?s#YN_WsT3Cmgd9>_ zWImWmabZBnA;m@JgQ*l3280|^Tx33&N^xO8$RWi==7Xse7Y2kJQe0#{m`ZVBK*%A* zMdpL46c+}B98z3lKA1{zVL-?s#YN_WsT3Cmgd9>_WImWmabZBnA;m@JgQ*l3280|^ zTx33&N^xO8$RQC|YyHt$sH5j;3+Tbw@v+A}=%HIy>F$d$%*cF(+4cy-oI8)ce`1&+ zfnk2$$T0G=40D6=^oIAAqrN}(M3)W}zuY~3_^zW%uJ8JAeD253gO=%^99gpdm$thP z9yoS#!MF3SyzQxFN8gVxJiYHD_PH;{j-NQR^Vt6FXQFF%>}pTmFMhW-FdWctx@L#> zp}@YR{^W!;GG?3|9bGUSU*$PF>+@LG_isucd_DL0y(b4(Upe#0Q2!q*erp>{N%~>9 z=&|;_X?v^mMI^zOroN!+!xZ4*oR& literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/musketbayonet.certus.png b/src/main/resources/assets/weaponmod/textures/items/musketbayonet.certus.png new file mode 100644 index 0000000000000000000000000000000000000000..33e53e6964bacfa52298a889228bfe1baec39542 GIT binary patch literal 15689 zcmeI3ZHyB|7{~X5h!ii7kRV``%>oL6?e6yVy4Nc&SFnecm%9pgen7Un)9XUpE!{oZ zJ0TigLckzsL|#Q>5d9z+iK6j>h(aPJsK^JE07eoC5E3v1!HD8)U-#yEBO=C-%qDm3 zGyi%1v-_KwXSW}A&Fq-E8Ij%2tUc?rYngUV@cDck@8BE`7WQEE&XghL*pxoHU{dl4 z0$t9iX+zagwCO8FwGN|!Va$QbNAbFn>GD7+y~qwyWGBTL91YXMMYFBTlvC8E1a59xX&mH8{KGIC3kd|Kxg&Fe0YZV(aKr*yUMAH(1 z!YZ3xLP$3@(&Of-DMicb6ToqeJwtUEXK4?$Rhpp+otb>}|VQ!S7wF0dH@9{X@UckCNbsiSTF2F`z zF$XKx0hbpy(jS2 zC>Q)K>3xrpje`_!Llvy@z4|uMwV08WGGIzOToZq@%?pM-Gf-zgXV(0L`X9`JE-m?Y zGa$)s#pR2}*qAToVR?9WWF;5eM^TRgT#l&2>+yI?Gkkk9;1FR&a`2^c^uNqNW$nsw zDb)^?09U%GQp4ReX}4DQZhPDGzK7i1lUCS&J&RzecK0rte)FM0gasFFekot*1V7iS zt+HGS{aek#ndr#(_d0lZz^6-i6jQA-n%ag>waRE}CG*LYY6Kj`(U4|Kmic5;xc9ce zhj0+^xZO^-pF^9`jM-`qBwB+iyh-Y2=@&f398{>9*w$B~MJOf~rpofToUfUMR`@Uu ze+O{o9|FC~Y59h8C%;s#=uWyKUStpi2tFjZ@O%)J;6i}lLxKy>2T=(w1PDGPxbS=s zmEb~v;6s87&j(QnE(8cZB)IT=5S8FUfZ#)d3(p5p2`&T(J|wvCd=Qo3LV(~yf(y?F zQ3);t2tFjZ@O%)J;6i}lLxKy>2T=(w1PDGPxbS=smEb~v;6s87&j(QnE(8cZB)IT= z5S8FUfZ#)d3(p5p2`&T(J|wvCd=Qo3LV(~yf(y?FQ3);t2tFjZ@O%)J;6i}lLxKy> z2T=(w1PDGPxbS=smEb~v;6p4fTjkYSkb>{iX5ovo18ThHTf4LzY7SFW*I0^rZUsgC zb`yS{r>G8|qAo0;C~-4IJ)phx^x^3gRWqq6I3V~ch zN0xh4J$~Zsc>l}8Y|CoaFS}>dipF%K0NdlaO~Q$BfDRZ zXvb?qUi#w~&g`0DqZIxkMSZ>J>^af4d+vnnBVusG{q^a7%-S_?tv-Ho%&O~uKJ{H@ z>Dy@|uxVZB{Y}mL*ER32^@e^wdwSRvg=t$chPf!(>IXFDcC23b!P;MPH-28FoEme& zeRxLOkgwLh_RNRt-@CE-(2w6-y4LAza{h2?{*<|of3a|2_pa|xa?VZ5kHrslKR-0` z<@q<~Y~Rs-?9(eZIvNgUCv06gt=~_sBl|Y2N^hmNj%BtjZSUSS{J_M^`{*~?80vC> aTCn%(#-Ve5tv6qGZkjeTxM%8u<$nQV^CwLJ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/musketbayonet.manasteel.png b/src/main/resources/assets/weaponmod/textures/items/musketbayonet.manasteel.png new file mode 100644 index 0000000000000000000000000000000000000000..b07631276240fe027cb232c9cac1960027eb63a5 GIT binary patch literal 351 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`3dtTpz6=aistgPb%?u1b{{!il z3=E|P3=FRl7#OT(FffScPl`Y422{&g;1OBOz`!j8!i<;h*8KqrN|m@qlmzFem6RtI zr7{F0X6BXX`MHKDlo{)p>KPike|9nls@m`A;uvD#zjUG@-ys7YSL2NV8v`yfc1~qf z`Nos#nDm%KWnI0E z>O&_Eq2x8wcAWjnc2Hqwd{j@6>Oq#sCIc1I$qF`;WWu_&PJURxlDOvi<6qgHdK!!s z%TwO@o$+1to~1tP(qeOyIZNzIXMXy;)fh|OxVV-SEORV* zB3qWr%}KOmO|7=j@zrB<#_A~}Zzji!!-bBH1?tF!LZ@D9IC^I+>FetFo)k+-!LQ<; z8cR-)28H?Zj4)}pkdRGfMMF+2LN1?DvT9yYo)yxvl93cyO6NsI(bb%;XhQc$7Kia& zp=DO}+0xN&bJ!Y7F1c<~m!x*PooZ)Nc56{m^7*_Zr=@gS#5F``rQyPk*l-R7BB4$R zIY!HBx|ZD#h%T(y%kEe*Ng9fd?zrmBsG)|_WrrzB9oUqVlq?MjGL0yvx!kJxT{8^{ z)leNZTnEP~1LK-Ywre{}_9jh6?oAuUb5brxZ4c~ky*{vM$31cyBj_R>80pNdG?6rm z9DBKCpd+X8P!0_my=zr_le0mIcsA`j>R6kE5l;~2FNI)+3V5vgWD7ypZq3WC<-x-7>;f|`^@ z**2}}%0`XcoRZb$jE?nU8nK$R2HrX*bm6vC;&o#>rlD8uRvo%Us}2{D)NCvkq+VgH zX0)L6NxNpZaJNt~Q;-G~$D;g2rcXB<7d8wuT`J;&lx3N^V&pW%$f#n~7?DM2s1*@r z)SQ?@NUP=zt)jvJV!0d-?~^Xs#xmI`U1<|bBU#fj*&GtH+K471Lq%dmt)@j|1gSYx zfk=a@KR;MH7TzcQQp>_g4%T9INbh&r!~mJTrlu?hFU^(MlEn+xPh-c?Ya2^LN6qrn zQ4_WtL^j)4GTd!Z{)*BQiSakB4h@pXiU!#W$Sg=3N_*XkBD-N${{(K2a-bgz-@J|X z5^AtER3PQo+FZo3t8N>%(8MBM6I*QaKyYIOtz3{u&aYYj!5ld7^xe$>G_t0euT;fq zzN(2bemaU!RjXn}Gm)CEq;r~<3upMwW*|+{Q94RT|H};Y)~>Mx8;i&+O5vcwg8OOG zwwL$rc-!o`Vme~R z>Y&&DQIfq^GC3ye9sfx%S8UYGrx8IU;qE;b*^%W+Xa*e1ut=0kZoE(!?S|d?+u+MFC-(92c7p<>k02AZ(N4V)LQA92W(IZE{>}K9rZ^ zqJXeXj*HEQ@^V}h5Vpy2vH4J5j*9}qHaRXfAIi&dQ9#%x$HnGDc{wf$2;1bi*nB82 z$3+2Qn@n88y-#aV1AkB3#vjf;`u&sh_@i6Fn3^pEu=*4LufGYvEe~I>0kA9s@aqBq z`Z)j|v)_I7>!Sed7N$!RbDad(yZgr93D3h-@8TE=V@F3v?@WpGpxX;i*L8dw*xS7h z{l5N-hflDuumC0|Ccut+^7*G9d%s=3LQe2XX+Igpj(RebR<*!P?pyIDGgpIDh_pf&dE-rU0q*oVedRcpw2TUEdYPfG>Z%8i_kU4X&;K3APmQ zYvZ4AD8wcrMBvhun}9ilFnG|F1Yf>>6Jy3xw%vpD;_8iC;4hplNHB@RKc08-or9kg ShA$|jVEV|h(nrrPyzwt9h__V$ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/musketbayonet.thaumium.png b/src/main/resources/assets/weaponmod/textures/items/musketbayonet.thaumium.png new file mode 100644 index 0000000000000000000000000000000000000000..bb86d8559ea82a70ac66b5fe00d3f8bebd678540 GIT binary patch literal 15683 zcmeI3du$X%9LKk)1WSkoBQJ?w4l!!n?xVYVz4dxfdT6U&fpSO@5%%`x+LgQA^LDRy zttKcSDq0aR@dZ&LKBA~Wh$KQljS!+d1pY9f@qy9sP%r`pU*POLx6|v0h%qFyNqhI3 z@BF^A`F?)|ZkPHMhoQ02%*na3 zNx>%oOf{(`EX~kewyzR4QdXVYZ4XpD^4Aql6bI7HJUd8{$tVeit7e&UNfEV}lSn0F z*;9+C42Xd^&@B_@ab@!o?S^HT?M5F%7Uez%hI0}O7RN4ozVUe3p-pQ-2SkuZS~k-R zbtVAQ0!$;7RKbJ}cqyaHUA?76OOw;X$yWM2caYKgNVAn(T6QVqX2=JxRc=TE#WIp1 z!-)BFt87vMp{t?6b=@>gj~Hq5dLM)KE=_gG2m}-h_~B9%XpW^hF~qWR4J!+^G%Ls~ z>oCdnL_C5nii2Ij%7VS5ot+@ zinLc1M7kCLo|Zh`aIH`aqzK@$5Q9NydN1pMp{DGOlDCdPYrslUjpzZiDAh_dPz6AT zg(y#}wLtKIumU7SC|Envds$CRYOu&DF-IT!?EmQyWo&v4)u@?pX?8l6EL^zRGByR= z+q1PG#I$TVN+?Ma*qg1+UD$2K`c*7Xc20KF%8F_iGQVo?1rYHuJz7hrRm{w%X}u@# z>?r5_9qE0Kk!}Y%ZbRj)vc38?F^#B|R+6B;4X%m5+2%RJo*AgKkFjfhO#2V!z*IW^ z-3%zI7!kbTC>`}iC7OkIM_LhtC>@4-N8rP}N0K~+89uie;AOT(=Gj6y`d?Q zTWPuE`nTGJGnUHs_wXz{;L{~M@~KW4O`VQUb;@XJDRZi>S$;l08q(~@vY%{n_ueV+ zAsqN6QLGVt4BCulOwuwS)*8^@P13YWKPTmLP@!z%^u7`uLOwA!RgTByY|YHI!iRDA zJAf(v5a?A-i#MF}`K5G4=hGGOB7-16@FBs4=YyyO7Xkzy5?pvbh)QrFK=2{Kh3A8) z1Q!AX9}--6K8Q+iAwcjU!G-68s00@R1RoMycs__qa3MhOA;E>`gQx@-0t6otTzEc+ zN^l`S@FBs4=YyyO7Xkzy5?pvbh)QrFK=2{Kh3A8)1Q!AX9}--6K8Q+iAwcjU!G-68 zs00@R1RoMycs__qa3MhOA;E>`gQx@-0t6otTzEc+N^l`S@FBs4=YyyO7Xkzy5?pvb zh)QrFK=2{Kh3A8)1Q!AXA7XJ;mR_v|I((lt4PTsHvbo|%_|mOQZEOirRM!}adSE_9 z{dxv|9-^oeOHqesQh1a64=+l+ zIjnzl;Wy778?kBd)bGZw*}f`t!=K%&UcZ0p$}Qo^JLIEJzPI;|abK=`>5w&Y*YSfL z8-~nKgcB7f#_a@qjNM00{<3FHb8}7Dwf-{mo~h5@`tpz~!`%!0{ae!ePd&&VS|4s$ z{rhRLKcCs;p4I-bziQz7<9>eV70S11`}!wm8t%#6*SPO|WB;fXGY@oLwJ$dGv(y-g zdU5$$aoLcqYd`8Zrd4fQ-24aq#J8{Q_WJJ{edLOF?w-7JU)Pd}+Um-Y-3vR8>f2UH zPyhD8_ZzQWx^d@M>5DeKG5nEhmp=ZgvTl56>)xulLl^yUe8nf;8S}R+UHtNaUE?cG bjiT0kv7_Vj5%*;5*PNRsGzZ=qKYQL^0HH1M literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/musketbayonet.void.png b/src/main/resources/assets/weaponmod/textures/items/musketbayonet.void.png new file mode 100644 index 0000000000000000000000000000000000000000..fc3e471dce8fe01a7e3d20d34a646692efefc881 GIT binary patch literal 15693 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
fh#&8lM?K$Lf2=ES`}fs{4UfezJY9bJ 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/spear.void.png b/src/main/resources/assets/weaponmod/textures/items/spear.void.png new file mode 100644 index 0000000000000000000000000000000000000000..9041af05e74b08f4732a5e784c7f6e8107d90e18 GIT binary patch literal 15686 zcmeI3e{2(F7{_mH4jE%&G%gWMN*5DUu6Ng;>(Q0{D6pZ$xeeI@(_Qbb+ih*H+}&t9 zi3|}9i3(ZdM+DR;7>QtviHSr7VgNz@P&16g044^bh=v3-W`v;cU4Px)wy%g7WAa|I zwa@#!&-Z!n^S{~tpxwok&$1)$Fz8Bk4g|V zhxNa*%@5YhB8YiUNnPDqckp4Bm!mdLkVB#^8I6P91mT;XjC1^us98c{zZ7e*Ui|Q& z)glQE)@80B9gMe#15)dVB6f}}>EcI*c&}ic@2~PDSs)M!zim(4};w4Jedyf((=^fJs`i=Ad16hl*XFUc^h)59`u zOXjlrtH3v(B81tFz`{&AU^Q3=G%e0jR3eeEB^)+c>8BX4*GtiM%5En?4^mCVG%iWT z)Vj1tRwp2;yduRlNsd``T`nXKYYkSbo+x)^?kgJ4C5ovTc7P(4qoa*32Vcge(HPJ+Q)?xN$3MvJCawFRpHf(+84 zk!n{eE>az$Di15XxL_5ymAYbguSwzjwPz7pT3Re~mPs)|PN?_$D7bfis`El(fYU@jSc*=Pp-INoMboTF~g7~2+8H7>@BZ2>=Mut}1@3cS-TcszD8 zOmjRb*qvdrK3wl4T^z&l^-hP^P1_BK!Js+3Ksq4v!}>1CNDDyPrsA$yqja?Wtb&WEznrtkvkM-&NEI4)x9qmTaYrYIs)kg8Qu!MaSD)+<=G zMh)u}S59utIwF!$i{hN3iuz7#ux7Vfu6X5YlOAL2SeE1UD(2_)jUWm>YEo-{Sh>hd zm{d4{*GD<6ZwfD+BQYSxO75n#j?tyGf+~l#1gD5i{a``-#Rg9cPL6<;eUx79BhtSx z0V=oZpW%1$c8|y5;K+~w4nd9v`^U?9!XzDXdj;Obi5{;rJH0oC-_C+6#JIDy=s%f( z{KDl2xLCg^_^IqoWgGralXiVY?}qnG;Q{jhp0xD-n_L02g}bm~`t-*I7F1iX`8lJ? zF+QrGEx%mS{k!$585uVEgEI$Q;JFf9nNYJE4(&mQn%!_{K5}VH(){40GX@GZo1*k* zn)Jcj2_C;izuV<UG}%G8r+jqiA4HsX&t>6PTVV(}S{6 zGt;f$F&z8?pmIL}3d(8jw7HpI@^^GIRUs{$1OkFKF)lP8$cu47K+q<}h2{f!F)j!Q z+Qhifd>}8z1pz^u7#ErkN@?u;N z5VVPLq4_{wj0*ySHZd+VAIOVwK|s(Z#)aksc`+^s2-?KB(0m{-#svXEn-~|G59GzT zARuTH<3jU+ycib*1Z`qmXg-h^J9aiRG@UW^L@f;KTOG#|)| zaX~=PCdP&419>qn2ngE5xX^qcFUAD{L7PZiRr!}{#Ta;#HUVClwGDl0ysyi*b_5Ax zP1Tjn##7}($!EPgnT6ye=BMS+lthp`F)Rp|^;@q08ql=U^ z;mUhX4RZYl+P9vb`oqk} zW}H6IH`H{;FF%t5dv}gEE?4d#ne){l$N9w(-zhRRo*+gBYQ^SBQM&mJ4CNJYy# z&b?pVI(E@z2_6_9txWA+JO0Md18y$0c75{F;_@~h`Fq8RJy*xC-MNW+b?L#ug@gAl h>utR@TsFU)_`34)+t=cqyYx4m+ZHSdywlwG^q(52C9wbi literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/warhammer.certus.png b/src/main/resources/assets/weaponmod/textures/items/warhammer.certus.png new file mode 100644 index 0000000000000000000000000000000000000000..51ea6443d233c65f33941fc2eb9602b36f695954 GIT binary patch literal 15125 zcmeI3U5pb|6vrY2u4YGFd7qrUy+b#NE9CQi4chjCYnf)2XP<#Abw#&G{OrZX1&wT+1vKID#n*P zNjp9F-19#(zkAQ=yv+Wg!G{+2EbjpTEKUt1htYY7`&qaEecy9sMnsyPn*l|m8C1|YhjQk0b)&|${mgl@!qzn=KO$LMOz zHyTRw>0$!r^noc0j!X?^l&KwxsQNaBNPS^RSjW^4U%UtX zidw2B4JS9%(;+M7%Q;R_;<$3T>@NrXrZvF{q9}5FfC~gzG=sG#4M(o9hP|>T($Gml zTe0+_qniff>dND0$%*-VZldN<~q+A{RNq&vTuERHYeHELr*LrKt)B z^RNI7$3}5N$GBq7bWA&Ec1hWEcTJ4eB%N;N?s&b0LdVp$)4vlTs3YwdX=f&jkQ;`! zS+W$^zZ2cc%1(Fh=vr%WW+}OzuGbDLdY3TQQwytZh1v>5(Y;Cu3(AgZWlS?4ukEs- z20|v0U>+FN4b?2$tD_t~yS3CUA()gM7)M*Nj}>@U2xWLd5=1E&Vfj9Z=RG2|nV3e} zRCR4~wnjL^2PFYTi(U=SOk4w%jw(CyoK(DXJvyo)X{J?>ow#0*Cm>feCZb$x&@;2S zp`?VFH!XBoFdmF@orXP8)lDX)4BL?n1*Vd5G~m~DRnkI{u%amf8_)!iRkXeU8{x$O ztA=GEB!^|Cj~A;D(`j#bn{?7tN^YUlrBx&y6oiN-K#hew6xa~z8my>lDl0}p;jkh` zv_LT2koJVPNpG=q)a2y6XO4UIe>X)3nYL5|x{bExq-V>bjazMFBk+mYqYX!1uePJ2 zY}wE)wwSL`ZO#7GY)@`XwP+<-aT{4&accppQEt{~>#~}W^)S7C0p~`!rtb;wo}-+D z2C1NGQq@`AMQl@Z%CZGFPM|&U7iC@(oE?EHM>)6W=k@o4m5|468I(LR!^H6uj1wy{>`+Wf3r zgZWZ*emKCR13jpqqaNyYbJJrMTB+r7~Ih@aI9OP$59WgEtTiVt6F}wQS@Ag9x1uzGi6(4 zHhb5N{L#9j8>xzE(IglUvPp4~`Cwj(3j;znDK0V}%u8`$K*%P=MdpKfDJ~2M*`&D0 zd@wJ?g#jU(6c?Ef=B2nWAY_x`BJ;t#6c+}BY*JigKA4x{!hn!Xii^w#^HN+G5VA>e zk@;X=iVFimHYqMLAIwW}VL-?x#YN_Wc_}Uo2-&2#$b2v_#f1SOn-mwB59Xz~Fd$@; z;v)0Gyc8D(gltk=WImXe;=+KCO^S=m2lG-~7!a~aagq68UWy9?LN+NbG9S!KabZBn zCdEbOgLx?~3<%jI;_7L=r3nr6YGxU|gZamzpPxeSZ!*fja2kNARRBD_7l3Os=zIx) z5)Z&H+X0Xc0&s`<;^U_`p}D70$&H!H^pTfV-1ZT(r2os&P20yG**|aZ>5s22zr6al zlUuCbdl!7Nb$9=s6^p-0-FNZqsYNrFcV`!Z$IiW(*p^aXyCt{kyImjNb?({Yn!NVM z=hysnet~u2(f9V1?tkm(`Ztd6`)1p+UU_YA_6P3F?Q0IeE613JFPxF*f!r52$B(U_ z9-RJ6UAcMc)OGQq@b$O5eDA39Rp#KPike|9nlsygWD;uvD#zqEfNFOwmUYw$${S&@!cSsE`i zGhfc=@SKn*B9_3xrIx@vS^jRn&}~i+5&!hxpY}~wP^y2(XL|dyYuXum;|mUZ_TDS1 zwYfWC)x|l>s)ab4N<37jWb9nRW2p3T+h@%mkLs652kf1%l-(c@&c@Nv?&INU&LGp) zDsw!vYV$tMw2gW8jGyW@PrJLLWkTK|hEr!7g52a=4+xwp&S$R3J;l<#Q*^;`8+nGR s&1^ysb;Q@6y???rznH)LhqaJh^4e8K7x?THfSzISboFyt=akR{09|f-ga7~l literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/warhammer.quartz.png b/src/main/resources/assets/weaponmod/textures/items/warhammer.quartz.png new file mode 100644 index 0000000000000000000000000000000000000000..d97639ee20667e266f99c7d6ec6832086491a89e GIT binary patch literal 16426 zcmeI3O^n+_6vrn}A-YwiO0A$mm1?Cb0)*p_#7S(jsmi8p7BywHP1Ws*I`(+iYGQ}j zyUDJQ_^O29$O)mI5E3^ya3~T8xWEA_1V_%O2jEa7;D9)o8OL^;_4;Tu0JRgNzHVHBKG%WkwzHVO_30OR&NdhG7nPRS z>My|!ySX!f=XcJvjh!ooYUWSW7iuF73G|?^bE96@@wCxmKGfAv8+QwNE*#=tSC# zXgj7m^q#B<~~Uxz~9S+5C`&eX_cLupHH*Bzi~ z!FsVK%V z{J=&J)Yk_d#D{G$AD_0Q zekJ7z$ApJg(+yn6>IOaw(5wkly_0Drkx`gEX90Ibd90rb&(1O2fDY|Ijitg-*&?26 z`9pmGPp+dq@h``GEI1uOD%S*D^Skzcum+yKb$2UZDbKza1lW0Cc{PNLwFf30tnq?xafQcFT+Iup_>dBoe$wSMWVq;j2rt7$0HK=<7o88`Ww;0+bd%wt^C7$p7XgHBGF)^%gqPtWfY42bi_VAe zGF$`@y2)_S`4C=)ivU7587?{>!pm?GKQ_6`7#x^KVm z)oB3saLbL8?NJUK*mLXeTo9n4cX936O{`K9;w-suZ~QPFf@eUxOT|L)`Sp*2-+sLr z;5NFa#!nffQ2R_h48+0s#zLe>CW8yj6T!9jKbW3wWHp-0xD`Im19L~r>HO}-Hvr%G zdh6<|fID;`KuG{iAcr%>L2{{_$l`W1yMQJDKKtZ)ZtJC&=ZYk1B)GJFrgSiP10D~- z#Ve79iP|7@6>zY1_DJyfk$spx!1UwQz-`=@DUc4vGs0^hi^Rc^Jv)PV+BkFiaj*!^ z7~j~&{;7S?R1O745AOwEet!%6_|qS`1XR>OTRQ1Vwsf2&D|776`b;3kz_JEr^-n!Q hGQZnspyv#N=gg~rzW4Pb58}AxQ|B5VK70AKe*jJQ8ifD= literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/weaponmod/textures/items/warhammer.thaumium.png b/src/main/resources/assets/weaponmod/textures/items/warhammer.thaumium.png new file mode 100644 index 0000000000000000000000000000000000000000..8523884dd2f8cb3565ca446a04920941587072dd GIT binary patch literal 14666 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