This commit is contained in:
Electroblob77
2019-01-05 22:18:14 +00:00
parent b374f71533
commit 224ee281ef
33 changed files with 160 additions and 273 deletions
@@ -134,12 +134,12 @@ public class CommonProxy {
*
* @param entity The source of the sound
* @param sound The SoundEvent to play
* @param category The SoundCategory to use
* @param volume Volume relative to 1
* @param pitch Pitch relative to 1
* @param repeat Whether to repeat the sound for as long as the entity is alive (or until stopped manually)
*/
public void playMovingSound(Entity entity, SoundEvent sound, float volume, float pitch, boolean repeat){
}
public void playMovingSound(Entity entity, SoundEvent sound, SoundCategory category, float volume, float pitch, boolean repeat){}
/**
* Gets the client side world using Minecraft.getMinecraft().world. <b>Only to be called client side!</b> Returns
@@ -153,5 +153,4 @@ public class CommonProxy {
public Set<String> getSpellHUDSkins(){
return null;
}
}
@@ -144,7 +144,7 @@ public final class Settings {
// Gamemodes
/**
* <b>[Synchronised]</b> When set to true, spells a player hasn't cast yet will be unreadable until they are cast
* (on a per-world basis). Has no effect when in creative mode. Spells of identification will be unobtainable in
* (on a per-world basis). Has no effect when in creative mode. Scrolls of identification will be unobtainable in
* survival mode if this is false.
*/
public boolean discoveryMode = true;
@@ -507,7 +507,6 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
NBTTagCompound properties = new NBTTagCompound();
// ...so Java 8 allows you to do stuff like this:
properties.setTag("imbuements", WizardryUtilities.mapToNBT(this.imbuementDurations,
imbuement -> new NBTTagInt(Enchantment.getEnchantmentID((Enchantment)imbuement)), NBTTagInt::new));
@@ -523,7 +522,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
properties.setLong("clairvoyanceLocation", this.clairvoyanceLocation.toLong());
properties.setInteger("clairvoyanceDimension", this.getClairvoyanceDimension());
// THIS is why I wrote the list/map <-> NBT methods. Look how neat this is!
// Mmmmmm Java 8....
properties.setTag("allies", WizardryUtilities.listToNBT(this.allies, WizardryUtilities::UUIDtoTagCompound));
properties.setTag("allyNames", WizardryUtilities.listToNBT(this.allyNames, NBTTagString::new));
properties.setTag("soulboundCreatures", WizardryUtilities.listToNBT(this.soulboundCreatures, WizardryUtilities::UUIDtoTagCompound));
@@ -661,54 +660,4 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
}
// Ended up deleting IWizardData because it was unnecessary. This is the comment that was at the start of it:
/* I'm not going to lie, I will never find the capabilities system even remotely intuitive so this is a bare-minimum
* approach just to get things working (four classes where one would have done?!) At one point I considered simply
* wrapping my old IEEP inside a single-field capability, but I eventually decided I would at least *try* to do it
* properly.
*
* "...without having to directly implement many interfaces." - Forge Docs. I still can't see what's wrong with
* implementing many interfaces; surely that's what Java interfaces are designed for?
*
* Other things I find annoying: - IStorage. It's completely redundant in the majority of cases, and I don't
* understand why we need yet another separate class. - Making an interface, only to implement it once and once
* only. This completely defeats the point of interfaces. - The EnumFacing parameter, which is again redundant for
* everything that isn't a tile entity. So much for a clean, neat system.
*
* What Forge has effectively done is conflated two different functions: attaching data to stuff and cross-mod
* integration/soft dependencies. I think this is bad design; it would have been better to keep the two features
* separate.
*
* Here's my current understanding of how the capability system works: - You make an interface which defines the
* things your capability can do (this class). I will call this the TEMPLATE. - You implement that interface with
* your default implementation (WizardData). This is the closest analog to your old IEEP implementation class. THIS
* CLASS STORES ALL THE VARIABLES, and hence has one instance for each instance of whatever it is attached to. I
* will call this the DATA. - The DATA class implements INBTSerializable (assuming you want it to be saved, which is
* nearly always the case) - Despite its name, Capability<T> does NOT represent a capability itself. Instead, it
* acts as a sort of identifier/key, the idea being that you can access a particular instance of your DATA given the
* key (which tells forge that you want a capability of type TEMPLATE) and the object you want the DATA for. This is
* what Entity.getCapability(...) does.
*
* To really understand what's going on though, you need to sift through Forge's verbose data structures and find
* where capabilities are actually hooked into vanilla: - Anything that implements ICapabilityProvider will have a
* private CapabilityDispatcher field. This holds other ICapabilityProviders. (I know. This inheritance pattern DOES
* NOT MAKE SENSE, because these could, in theory, be OTHER ENTITIES!) - This field is assigned a value through
* Forge's event factory, which, as we are all familiar with, calls all the methods marked with @SubscribeEvent.
* These methods add individual ICapabilityProviders to a Map stored in the event, which the event factory then
* wraps in a CapabilityDispatcher (which is itself an ICapabilityProvider) for the object that called it. - In your
* event handler, you return a custom ICapabilityProvider which is effectively bolted on to the player, and
* duplicates the ICapabilityProvider methods so you can hook into them and return an instance of your DATA class. -
* Where before there was a simple collection of IEEPs stored in the player, there is now a tree of
* ICapabilityProviders:
*
* - Entity/TileEntity/ItemStack - Vanilla ICapabilityProviders, mostly IItemHandlers, stored as fields. -
* CapabilityDispatcher, stored as a field. - Custom ICapabilityProviders - Custom CapabilityDispatchers - ...
*
* Most importantly, EACH PLAYER HOLDS THEIR OWN INSTANCE OF THIS TREE.
*
* When a capability is retrieved, the following process happens: 1. For the Entity/TileEntity/ItemStack instance,
* ICapabilityProvider.getCapability(...) is called. 2. The request propogates through the tree and finds the
* requested capability. */
}
@@ -79,7 +79,6 @@ public class Wizardry {
// TODO: Switch from IInventory to IItemHandler (Or don't. It's only useful for automation really.)
// TODO: Have particles obey Minecraft's particle setting where appropriate
// (see https://github.com/RootsTeam/Embers/blob/master/src/main/java/teamroots/embers/particle/ParticleUtil.java)
// TODO: Interfaces for various things, like 'stuff that can be put in the central slot of an arcane workbench'
// TODO: Go over all the worldgen code, use IWorldGenerator
// TODO: Implement a continuous sound system using MovingSoundEntity, allowing continuous spells to have a long sound
// loop as well as a start and end sound
@@ -88,6 +87,9 @@ public class Wizardry {
// TODO: Replace spell IDs in packets with ResourceLocation strings
// TODO: Forcefield needs looking at, esp. with regards to projectiles and explosions
// TODO: TileEntityArcaneWorkbench needs looking at, esp. regarding inventory and markDirty
// TODO: Fireskin somehow lost its particles
// TODO: Convert settings over to the @Config system
// TODO: Go through listeners of LivingHurtEvent and decide whether they should change to LivingDamageEvent
// NOTE: Add melee upgrades to loot tables when they are added.
@@ -208,7 +210,7 @@ public class Wizardry {
for(RegistryEvent.MissingMappings.Mapping<Item> mapping : event.getAllMappings()){
if(mapping.key.getResourceDomain().equals(Wizardry.MODID)){
Item replacement = null;
Item replacement;
switch(mapping.key.getResourcePath()){
@@ -1,5 +1,6 @@
package electroblob.wizardry;
import electroblob.wizardry.client.gui.handbook.GuiWizardHandbook;
import electroblob.wizardry.item.ItemSpellBook;
import electroblob.wizardry.item.ItemWizardHandbook;
import electroblob.wizardry.spell.Spell;
@@ -45,7 +46,7 @@ public class WizardryGuiHandler implements IGuiHandler {
}
}else if(id == WIZARD_HANDBOOK && (player.getHeldItemMainhand().getItem() instanceof ItemWizardHandbook
|| player.getHeldItemOffhand().getItem() instanceof ItemWizardHandbook)){
return new electroblob.wizardry.client.gui.GuiWizardHandbook();
return new GuiWizardHandbook();
}else if(id == SPELL_BOOK){
if(player.getHeldItemMainhand().getItem() instanceof ItemSpellBook){
return new electroblob.wizardry.client.gui.GuiSpellBook(Spell.get(player.getHeldItemMainhand().getItemDamage()));
@@ -533,8 +533,8 @@ public class ClientProxy extends CommonProxy {
RenderingRegistry.registerEntityRenderingHandler(EntityForceArrow.class, RenderForceArrow::new);
// Creatures
RenderingRegistry.registerEntityRenderingHandler(EntitySpiritWolf.class, manager -> new RenderSpiritWolf(manager));
RenderingRegistry.registerEntityRenderingHandler(EntitySpiritHorse.class, manager -> new RenderSpiritHorse(manager));
RenderingRegistry.registerEntityRenderingHandler(EntitySpiritWolf.class, RenderSpiritWolf::new);
RenderingRegistry.registerEntityRenderingHandler(EntitySpiritHorse.class, RenderSpiritHorse::new);
RenderingRegistry.registerEntityRenderingHandler(EntityWizard.class, RenderWizard::new);
RenderingRegistry.registerEntityRenderingHandler(EntityEvilWizard.class, RenderEvilWizard::new);
RenderingRegistry.registerEntityRenderingHandler(EntityDecoy.class, RenderDecoy::new);
@@ -48,7 +48,7 @@ import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
/**
* Event handler responsible for all client-side only events, mostly rendering.
* Event handler responsible for client-side only events, mostly rendering.
*
* @author Electroblob
* @since Wizardry 1.0
@@ -4,9 +4,14 @@ import net.minecraft.client.model.ModelBiped;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityArmorStand;
public class ModelWtfMojang extends ModelBiped {
/**
* Fixes custom armour models 'breathing' on the stand and rotates the helmet properly.
* @author Shadows-of-Fire
* @since Wizardry 4.1.2
*/
public class ModelArmourFixer extends ModelBiped {
public ModelWtfMojang(float modelSize, float rotationYOffset, int textureWidth, int textureHeight) {
public ModelArmourFixer(float modelSize, float rotationYOffset, int textureWidth, int textureHeight) {
super(modelSize, rotationYOffset, textureWidth, textureHeight);
}
@@ -5,64 +5,71 @@ import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;
public class ModelHammer extends ModelBase {
ModelRenderer Shape1;
ModelRenderer Shape2;
ModelRenderer Shape3;
ModelRenderer Shape4;
ModelRenderer Shape5;
ModelRenderer Shape6;
ModelRenderer hammerHead;
ModelRenderer handle;
ModelRenderer handleEnd;
ModelRenderer handleBase;
ModelRenderer ring1;
ModelRenderer ring2;
public ModelHammer(){
textureWidth = 64;
textureHeight = 64;
Shape1 = new ModelRenderer(this, 0, 0);
Shape1.addBox(0F, 0F, 0F, 20, 12, 12);
Shape1.setRotationPoint(-10F, 12F, -6F);
Shape1.setTextureSize(64, 64);
Shape1.mirror = true;
setRotation(Shape1, 0F, 0F, 0F);
Shape2 = new ModelRenderer(this, 0, 24);
Shape2.addBox(0F, 0F, 0F, 4, 14, 4);
Shape2.setRotationPoint(-2F, -2F, -2F);
Shape2.setTextureSize(64, 64);
Shape2.mirror = true;
setRotation(Shape2, 0F, 0F, 0F);
Shape3 = new ModelRenderer(this, 0, 49);
Shape3.addBox(0F, 0F, 0F, 5, 5, 5);
Shape3.setRotationPoint(-2.5F, -7F, -2.5F);
Shape3.setTextureSize(64, 64);
Shape3.mirror = true;
setRotation(Shape3, 0F, 0F, 0F);
Shape4 = new ModelRenderer(this, 0, 42);
Shape4.addBox(0F, 0F, 0F, 5, 2, 5);
Shape4.setRotationPoint(-2.5F, 10F, -2.5F);
Shape4.setTextureSize(64, 64);
Shape4.mirror = true;
setRotation(Shape4, 0F, 0F, 0F);
Shape5 = new ModelRenderer(this, 20, 24);
Shape5.addBox(0F, 0F, 0F, 2, 14, 14);
Shape5.setRotationPoint(-8F, 11F, -7F);
Shape5.setTextureSize(64, 64);
Shape5.mirror = true;
setRotation(Shape5, 0F, 0F, 0F);
Shape6 = new ModelRenderer(this, 20, 24);
Shape6.addBox(0F, 0F, 0F, 2, 14, 14);
Shape6.setRotationPoint(6F, 11F, -7F);
Shape6.setTextureSize(64, 64);
Shape6.mirror = true;
setRotation(Shape6, 0F, 0F, 0F);
hammerHead = new ModelRenderer(this, 0, 0);
hammerHead.addBox(0F, 0F, 0F, 20, 12, 12);
hammerHead.setRotationPoint(-10F, 12F, -6F);
hammerHead.setTextureSize(64, 64);
hammerHead.mirror = true;
setRotation(hammerHead, 0F, 0F, 0F);
handle = new ModelRenderer(this, 0, 24);
handle.addBox(0F, 0F, 0F, 4, 14, 4);
handle.setRotationPoint(-2F, -2F, -2F);
handle.setTextureSize(64, 64);
handle.mirror = true;
setRotation(handle, 0F, 0F, 0F);
handleEnd = new ModelRenderer(this, 0, 49);
handleEnd.addBox(0F, 0F, 0F, 5, 5, 5);
handleEnd.setRotationPoint(-2.5F, -7F, -2.5F);
handleEnd.setTextureSize(64, 64);
handleEnd.mirror = true;
setRotation(handleEnd, 0F, 0F, 0F);
handleBase = new ModelRenderer(this, 0, 42);
handleBase.addBox(0F, 0F, 0F, 5, 2, 5);
handleBase.setRotationPoint(-2.5F, 10F, -2.5F);
handleBase.setTextureSize(64, 64);
handleBase.mirror = true;
setRotation(handleBase, 0F, 0F, 0F);
ring1 = new ModelRenderer(this, 20, 24);
ring1.addBox(0F, 0F, 0F, 2, 14, 14);
ring1.setRotationPoint(-8F, 11F, -7F);
ring1.setTextureSize(64, 64);
ring1.mirror = true;
setRotation(ring1, 0F, 0F, 0F);
ring2 = new ModelRenderer(this, 20, 24);
ring2.addBox(0F, 0F, 0F, 2, 14, 14);
ring2.setRotationPoint(6F, 11F, -7F);
ring2.setTextureSize(64, 64);
ring2.mirror = true;
setRotation(ring2, 0F, 0F, 0F);
}
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){
super.render(entity, f, f1, f2, f3, f4, f5);
setRotationAngles(f, f1, f2, f3, f4, f5, entity);
Shape1.render(f5);
Shape2.render(f5);
Shape3.render(f5);
Shape4.render(f5);
Shape5.render(f5);
Shape6.render(f5);
hammerHead.render(f5);
handle.render(f5);
handleEnd.render(f5);
handleBase.render(f5);
ring1.render(f5);
ring2.render(f5);
}
private void setRotation(ModelRenderer model, float x, float y, float z){
@@ -3,7 +3,7 @@ package electroblob.wizardry.client.model;
import net.minecraft.client.model.ModelRenderer;
import net.minecraft.entity.Entity;
public class ModelWizardArmour extends ModelWtfMojang {
public class ModelWizardArmour extends ModelArmourFixer {
ModelRenderer Shape1;
ModelRenderer Shape2;
ModelRenderer Shape3;
@@ -166,9 +166,8 @@ public final class WizardryItemModels {
* Registers an item model, using the item's registry name as the model name (this convention makes it easier to
* keep track of everything). Variant defaults to "normal". Registers the model for metadata 0 automatically, plus
* all the other metadata values that the item can take, as defined in
* {@link Item#getSubItems(Item, net.minecraft.creativetab.CreativeTabs, java.util.List)}. The passed in item
* <b>must</b> allow null to be passed in for the creative tab parameter in the aforementioned method, or a
* {@link NullPointerException} will result.
* {@link Item#getSubItems(Item, net.minecraft.creativetab.CreativeTabs, java.util.List)}. The creative tab supplied
* to the aforementioned method will be whichever one the item is in.
*/
private static void registerItemModel(Item item){
@@ -68,8 +68,7 @@ public enum Tier {
int totalWeight = 0;
for(Tier tier : tiers)
totalWeight += tier.weight;
for(Tier tier : tiers) totalWeight += tier.weight;
int randomiser = random.nextInt(totalWeight);
int cumulativeWeight = 0;
@@ -137,8 +137,7 @@ public class EntityTornado extends EntityMagicConstruct {
Type type = null;
if(block.getMaterial() == Material.LEAVES) type = Type.LEAF;
if(block.getMaterial() == Material.SNOW || block.getMaterial() == Material.CRAFTED_SNOW)
type = Type.SNOW;
if(block.getMaterial() == Material.SNOW || block.getMaterial() == Material.CRAFTED_SNOW) type = Type.SNOW;
if(type != null){
double yPos1 = rand.nextDouble() * 8;
@@ -108,6 +108,7 @@ public class EntityAIAttackSpell<T extends EntityLiving & ISpellCaster> extends
new PacketNPCCastSpell.Message(attacker.getEntityId(), target == null ? -1 : target.getEntityId(),
EnumHand.MAIN_HAND, spell.id(), modifiers),
// Particles are usually only visible from 16 blocks away, so 128 is more than far enough.
// TODO: Why is this one a 128 block radius, whilst the other one is all in dimension?
new TargetPoint(attacker.dimension, attacker.posX, attacker.posY, attacker.posZ, 128));
}
@@ -146,29 +146,26 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
this.tasks.addTask(7, new EntityAIWander(this, 0.6D));
this.tasks.addTask(8, new EntityAIWatchClosest(this, EntityLiving.class, 8.0F));
this.targetSelector = new Predicate<Entity>(){
this.targetSelector = entity -> {
public boolean apply(Entity entity){
// If the target is valid and not invisible...
if(entity != null && !entity.isInvisible()
&& WizardryUtilities.isValidTarget(EntityWizard.this, entity)){
// If the target is valid and not invisible...
if(entity != null && !entity.isInvisible()
&& WizardryUtilities.isValidTarget(EntityWizard.this, entity)){
// ... and is a mob, a summoned creature ...
if((entity instanceof IMob || entity instanceof ISummonedCreature
// ... or in the whitelist ...
|| Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist)
.contains(EntityList.getKey(entity.getClass())))
// ... and isn't in the blacklist ...
&& !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist)
.contains(EntityList.getKey(entity.getClass()))){
// ... it can be attacked.
return true;
}
// ... and is a mob, a summoned creature ...
if((entity instanceof IMob || entity instanceof ISummonedCreature
// ... or in the whitelist ...
|| Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist)
.contains(EntityList.getKey(entity.getClass())))
// ... and isn't in the blacklist ...
&& !Arrays.asList(Wizardry.settings.summonedCreatureTargetsBlacklist)
.contains(EntityList.getKey(entity.getClass()))){
// ... it can be attacked.
return true;
}
return false;
}
return false;
};
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, true));
@@ -157,7 +157,7 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData {
* Called by the client when it receives a Entity spawn packet. Data should be read out of the stream in the same
* way as it was written. <b>Implementors must call super when overriding.</b>
*
* @param additionalData The packet data stream
* @param buffer The packet data stream
*/
@Override
default void readSpawnData(ByteBuf buffer){
@@ -241,11 +241,11 @@ public interface ISummonedCreature extends IEntityAdditionalSpawnData {
* to do something when a successful attack is made. This was added because the event-based damage source system can
* cause parts of attackEntityAsMob not to fire, since attackEntityFrom is intercepted and canceled.
* <p>
* Usage examples: {@link EntitySliverfishMinion} uses this to summon more silverfish if the target is killed,
* Usage examples: {@link EntitySilverfishMinion} uses this to summon more silverfish if the target is killed,
* {@link EntitySkeletonMinion} and {@link EntitySpiderMinion} use this to add potion effects to the target.
*/
default void onSuccessfulAttack(EntityLivingBase target){
};
}
// Delegates
@@ -34,8 +34,7 @@ public class EntityFirebolt extends EntityMagicProjectile {
if(world.isRemote){
for(int i = 0; i < 8; i++){
world.spawnParticle(EnumParticleTypes.LAVA, this.posX + rand.nextFloat() - 0.5,
this.posY + this.height / 2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0,
0);
this.posY + this.height / 2 + rand.nextFloat() - 0.5, this.posZ + rand.nextFloat() - 0.5, 0, 0, 0);
}
}
@@ -7,7 +7,7 @@ import net.minecraft.item.ItemStack;
/**
* Items that implement this interface may be placed in the central slot of the arcane workbench as long as
* {@link IWorkbenchItem#canPlace(ItemStack)} returns true.The number of spell book slots displayed is also specified
* {@link IWorkbenchItem#canPlace(ItemStack)} returns true. The number of spell book slots displayed is also specified
* using {@link IWorkbenchItem#getSpellSlotCount(ItemStack)}.
* <p>
* Items that implement this interface define what happens if they are in the central slot of the arcane workbench and
@@ -52,7 +52,7 @@ import net.minecraftforge.fml.relauncher.SideOnly;
* written the {@link WandHelper} class.<i> I strongly recommend you use it for interacting with wand items wherever
* possible.</i>
* <p>
* It's unikely that anything in this class will be of much use externally, but should you wish to use it for whatever
* It's unlikely that anything in this class will be of much use externally, but should you wish to use it for whatever
* reason (perhaps if you extend it), it works as follows:
* <p>
* - onItemRightClick is where non-continuous spells are cast, and it sets the item in use for continuous spells<br>
@@ -37,9 +37,9 @@ import net.minecraftforge.fml.relauncher.SideOnly;
@Mod.EventBusSubscriber
public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem {
//VanillaCopy, ItemArmor has this set to private for some reason.
// VanillaCopy, ItemArmor has this set to private for some reason.
public static final UUID[] ARMOR_MODIFIERS = new UUID[] {UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"), UUID.fromString("D8499B04-0E66-4726-AB29-64469D734E0D"), UUID.fromString("9F3D476D-C118-4544-8365-64846904B48E"), UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150")};
//Damage reduction values that used to be in WizardryItems.SILK [feet, legs, chest, head]
// Damage reduction values that used to be in WizardryItems.SILK [feet, legs, chest, head]
private static int[] reductions = new int[]{2, 4, 5, 2};
public Element element;
@@ -34,11 +34,11 @@ public class PotionDecay extends Potion {
}
@Override
public boolean isReady(int p_76397_1_, int p_76397_2_){
public boolean isReady(int duration, int amplifier){
// Copied from the vanilla wither effect. It does the timing stuff. 25 is the number of ticks between hits at
// amplifier 0
int k = 25 >> p_76397_2_;
return k > 0 ? p_76397_1_ % k == 0 : true;
int k = 25 >> amplifier;
return k > 0 ? duration % k == 0 : true;
}
@Override
@@ -54,7 +54,8 @@ import net.minecraftforge.registries.IForgeRegistry;
import net.minecraftforge.registries.RegistryBuilder;
/**
* Class responsible for defining, storing and registering all of wizardry's spells.
* Class responsible for defining, storing and registering all of wizardry's spells. Use this to access individual
* spell instances, similar to the {@code Blocks} and {@code Items} classes.
*
* @author Electroblob
* @since Wizardry 2.1
@@ -75,7 +76,8 @@ public final class Spells {
public static void createRegistry(RegistryEvent.NewRegistry event){
// Beats me why we need both of these. Surely the type parameter means it already knows?
RegistryBuilder<Spell> builder = new RegistryBuilder<Spell>();
// EDIT: It's probably because of type erasure, thinking about it.
RegistryBuilder<Spell> builder = new RegistryBuilder<>();
builder.setType(Spell.class);
builder.setName(new ResourceLocation(Wizardry.MODID, "spells"));
builder.setIDRange(0, 5000); // Is there any penalty for using a larger number?
@@ -26,13 +26,6 @@ import net.minecraftforge.registries.IForgeRegistry;
@Mod.EventBusSubscriber
public final class WizardryBlocks {
// I get registry events, they make sense - even I doubted myself with when to do various things in the load
// process,
// so I can see why the folks at Forge wanted to save us having to think about it.
// What I do not understand is why you would use @ObjectHolder for your own blocks and items. What's the point in
// making your code longer and more complicated, when you can just define the blocks as constants and register them
// later?
// Found a very nice way of registering things using arrays, which might make @ObjectHolder actually useful.
// http://www.minecraftforge.net/forum/topic/49497-1112-is-using-registryevent-this-way-ok/
@@ -17,12 +17,11 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@Mod.EventBusSubscriber
public final class WizardryEnchantments {
// At the moment these enchantments generate on books in dungeon chests due to a bad bit of code
// (EnchantRandomly:50).
// At the moment these enchantments generate on books in dungeon chests due to a bad bit of code (EnchantRandomly:49).
// No idea how to fix this because I have no way of hooking into that code... removing the enchantments from the
// registry works, but breaks everything else!
// TODO: For the time being, a dynamic solution will have to do, i.e. intercept the book when it is generated and
// For the time being, a dynamic solution will have to do, i.e. intercept the book when it is generated and
// reassign its enchantment.
// All of these have custom classes, so the unlocalised name (referred to simply as 'name' for enchantments) is
@@ -1,74 +1,18 @@
package electroblob.wizardry.registry;
import java.util.List;
import com.google.common.collect.Lists;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.constants.Element;
import electroblob.wizardry.constants.Tier;
import electroblob.wizardry.entity.EntityArc;
import electroblob.wizardry.entity.EntityMeteor;
import electroblob.wizardry.entity.EntityShield;
import electroblob.wizardry.entity.construct.EntityArrowRain;
import electroblob.wizardry.entity.construct.EntityBlackHole;
import electroblob.wizardry.entity.construct.EntityBlizzard;
import electroblob.wizardry.entity.construct.EntityBubble;
import electroblob.wizardry.entity.construct.EntityDecay;
import electroblob.wizardry.entity.construct.EntityEarthquake;
import electroblob.wizardry.entity.construct.EntityFireRing;
import electroblob.wizardry.entity.construct.EntityFireSigil;
import electroblob.wizardry.entity.construct.EntityForcefield;
import electroblob.wizardry.entity.construct.EntityFrostSigil;
import electroblob.wizardry.entity.construct.EntityHailstorm;
import electroblob.wizardry.entity.construct.EntityHammer;
import electroblob.wizardry.entity.construct.EntityHealAura;
import electroblob.wizardry.entity.construct.EntityIceSpike;
import electroblob.wizardry.entity.construct.EntityLightningPulse;
import electroblob.wizardry.entity.construct.EntityLightningSigil;
import electroblob.wizardry.entity.construct.EntityTornado;
import electroblob.wizardry.entity.living.EntityBlazeMinion;
import electroblob.wizardry.entity.living.EntityDecoy;
import electroblob.wizardry.entity.living.EntityEvilWizard;
import electroblob.wizardry.entity.living.EntityIceGiant;
import electroblob.wizardry.entity.living.EntityIceWraith;
import electroblob.wizardry.entity.living.EntityLightningWraith;
import electroblob.wizardry.entity.living.EntityMagicSlime;
import electroblob.wizardry.entity.living.EntityPhoenix;
import electroblob.wizardry.entity.living.EntityShadowWraith;
import electroblob.wizardry.entity.living.EntitySilverfishMinion;
import electroblob.wizardry.entity.living.EntitySkeletonMinion;
import electroblob.wizardry.entity.living.EntitySpiderMinion;
import electroblob.wizardry.entity.living.EntitySpiritHorse;
import electroblob.wizardry.entity.living.EntitySpiritWolf;
import electroblob.wizardry.entity.living.EntityStormElemental;
import electroblob.wizardry.entity.living.EntityWitherSkeletonMinion;
import electroblob.wizardry.entity.living.EntityWizard;
import electroblob.wizardry.entity.living.EntityZombieMinion;
import electroblob.wizardry.entity.projectile.EntityDarknessOrb;
import electroblob.wizardry.entity.projectile.EntityDart;
import electroblob.wizardry.entity.projectile.EntityFirebolt;
import electroblob.wizardry.entity.projectile.EntityFirebomb;
import electroblob.wizardry.entity.projectile.EntityForceArrow;
import electroblob.wizardry.entity.projectile.EntityForceOrb;
import electroblob.wizardry.entity.projectile.EntityIceCharge;
import electroblob.wizardry.entity.projectile.EntityIceLance;
import electroblob.wizardry.entity.projectile.EntityIceShard;
import electroblob.wizardry.entity.projectile.EntityLightningArrow;
import electroblob.wizardry.entity.projectile.EntityLightningDisc;
import electroblob.wizardry.entity.projectile.EntityMagicMissile;
import electroblob.wizardry.entity.projectile.EntityPoisonBomb;
import electroblob.wizardry.entity.projectile.EntitySmokeBomb;
import electroblob.wizardry.entity.projectile.EntitySpark;
import electroblob.wizardry.entity.projectile.EntitySparkBomb;
import electroblob.wizardry.entity.projectile.EntityThunderbolt;
import electroblob.wizardry.entity.construct.*;
import electroblob.wizardry.entity.living.*;
import electroblob.wizardry.entity.projectile.*;
import electroblob.wizardry.loot.RandomSpell;
import electroblob.wizardry.loot.WizardSpell;
import electroblob.wizardry.tileentity.TileEntityArcaneWorkbench;
import electroblob.wizardry.tileentity.TileEntityMagicLight;
import electroblob.wizardry.tileentity.TileEntityPlayerSave;
import electroblob.wizardry.tileentity.TileEntityStatue;
import electroblob.wizardry.tileentity.TileEntityTimer;
import electroblob.wizardry.tileentity.*;
import electroblob.wizardry.util.WizardryUtilities;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EnumCreatureType;
@@ -91,6 +35,8 @@ import net.minecraftforge.oredict.OreDictionary;
import net.minecraftforge.oredict.ShapelessOreRecipe;
import net.minecraftforge.registries.IForgeRegistry;
import java.util.List;
/**
* Class responsible for registering all the things that don't have (or need) instances: entities, loot tables, recipes,
* etc.
@@ -101,13 +47,11 @@ import net.minecraftforge.registries.IForgeRegistry;
@Mod.EventBusSubscriber
public final class WizardryRegistry {
// NOTE: In 1.12, recipes have a registry (they can still stay here though since we don't keep references to them)
/** Called from the preInit method in the main mod class to register the custom dungeon loot. */
public static void registerLoot(){
/* Loot tables work as follows: Minecraft goes through each pool in turn. For each pool, it does a certain
* number or rolls, which can either be set to always be one number or a random number from a range. Each roll,
* number of rolls, which can either be set to always be one number or a random number from a range. Each roll,
* it generates one stack of a single random entry in that pool, weighted according to the weights of the
* entries. Functions allow properties of that stack (stack size, damage, nbt) to be set, and even allow it to
* be replaced dynamically with a completely different item (though there's very little point in doing that as
@@ -246,7 +190,7 @@ public final class WizardryRegistry {
/** Now only deals with the dynamic crafting recipes and the smelting recipes. */
@SubscribeEvent
public static void registerRecipes(RegistryEvent.Register<IRecipe> event){
IForgeRegistry<IRecipe> registry = event.getRegistry();
FurnaceRecipes.instance().addSmeltingRecipeForBlock(WizardryBlocks.crystal_ore, new ItemStack(WizardryItems.magic_crystal), 0.5f);
@@ -8,8 +8,7 @@ import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
/**
* Class responsible for defining, storing and registering all of wizardry's sound events. For some reason, these worked
* in the beta versions despite not being registered...
* Class responsible for defining, storing and registering all of wizardry's sound events.
*
* @author Electroblob
* @since Wizardry 2.1
@@ -59,7 +59,6 @@ public class Light extends Spell {
BlockPos pos = new BlockPos(x, y, z);
if(world.isAirBlock(pos)){
// world.playSound(x, y, z, "sound.ambient.cave.cave", 1.0f, 1.5f, false);
if(!world.isRemote){
world.setBlockState(pos, WizardryBlocks.magic_light.getDefaultState());
if(world.getTileEntity(pos) instanceof TileEntityTimer){
@@ -272,7 +272,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
return modID;
}
/** Returns the ResourceLocation for this spell's icon. */
/** Returns the {@code ResourceLocation} for this spell's icon. */
public final ResourceLocation getIcon(){
return icon;
}
@@ -368,7 +368,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
/**
* Returns the total number of registered spells, excluding the 'None' spell. Returns the same number that would be
* returned by Spell.getSpells(Spell.allSpells).size(), but this method is more efficient.
* returned by {@code Spell.getSpells(Spell.allSpells).size()}, but this method is more efficient.
*/
public static int getTotalSpellCount(){
return registry.getValuesCollection().size() - 1;
@@ -40,7 +40,7 @@ import net.minecraft.world.World;
*/
public class SpellConstruct<T extends EntityMagicConstruct> extends Spell {
/** A factory that creates projectile entities. */
/** A factory that creates construct entities. */
protected final Function<World, T> constructFactory;
/** The base lifetime of the construct created by this spell, or -1 if the construct does not despawn. */
protected final int baseDuration;
@@ -276,6 +276,10 @@ public abstract class SpellRay extends Spell {
spawnParticle(world, x, y, z, velocity.x, velocity.y, velocity.z);
}
}
// The exact behaviour of the returned values of the following three methods can be a little confusing. Normally,
// either onEntityHit or onBlockHit (or both) will return true when the spell succeeded in hitting the block or
// entity, and false if not (note that those two methods are mutually exclusive). If false is returned, onMiss will
// be called - onMiss will never be called if either of the other methods returns true.
/**
* Called when the spell hits an entity. Will never be called if ignoreEntities is true.
@@ -26,10 +26,8 @@ public class ContainerArcaneWorkbench extends Container {
/** The arcane workbench tile entity associated with this container. */
public TileEntityArcaneWorkbench tileentity;
public static final ResourceLocation EMPTY_SLOT_CRYSTAL = new ResourceLocation(Wizardry.MODID,
"gui/empty_slot_crystal");
public static final ResourceLocation EMPTY_SLOT_UPGRADE = new ResourceLocation(Wizardry.MODID,
"gui/empty_slot_upgrade");
public static final ResourceLocation EMPTY_SLOT_CRYSTAL = new ResourceLocation(Wizardry.MODID, "gui/empty_slot_crystal");
public static final ResourceLocation EMPTY_SLOT_UPGRADE = new ResourceLocation(Wizardry.MODID, "gui/empty_slot_upgrade");
public static final int CRYSTAL_SLOT = 8;
public static final int CENTRE_SLOT = 9;
@@ -260,7 +258,7 @@ public class ContainerArcaneWorkbench extends Container {
if(((IWorkbenchItem)centre.getStack().getItem())
.onApplyButtonPressed(player, centre, this.getSlot(CRYSTAL_SLOT), this.getSlot(UPGRADE_SLOT), spellBooks)){
// TODO: Sound and possibly animation for spell binding
// Probably don't need to do anything here, unless we're going to use packets to control the animation
}
}
}
@@ -26,8 +26,8 @@ import net.minecraftforge.fml.common.network.ByteBufUtils;
* that not all wand upgrades affect spells). SpellModifiers objects are <i>mutable</i>, so you can simply change the
* values they contain to modify the spell.
* <p>
* To use a SpellModifiers object within the <code>Spell.cast</code> methods, simply retrieve the desired multiplier
* using {@link SpellModifiers#get(Item)} for wand upgrades, or {@link SpellModifiers#get(String)} if the multiplier is
* To use a SpellModifiers object within the <code>Spell.cast</code> methods, simply retrieve the desired modifier
* using {@link SpellModifiers#get(Item)} for wand upgrades, or {@link SpellModifiers#get(String)} if the modifier is
* not from a wand upgrade.
*
* @author Electroblob
@@ -139,6 +139,9 @@ public final class SpellModifiers {
buf.writeFloat(entry.getValue());
}
}
// These two don't use the Map <-> NBT methods in WizardryUtilities because it's better to use the strings as keys
// themselves rather than storing them separately.
/**
* Creates a new SpellModifiers object from the given NBTTagCompound. The NBTTagCompound should have 1 or more float
@@ -80,17 +80,15 @@ import net.minecraftforge.fml.relauncher.SideOnly;
*/
public final class WizardryUtilities {
/**
* Constant which is simply an array of the four armour slots. (Could've sworn this exists somewhere in vanilla, but
* I can't find it anywhere...)
*/
/** Constant which is simply an array of the four armour slots. (Could've sworn this exists somewhere in vanilla,
* but I can't find it anywhere...) */
public static final EntityEquipmentSlot[] ARMOUR_SLOTS;
/** Changed to a constant in wizardry 2.1, since this is a lot more efficient. */
private static final DataParameter<Boolean> POWERED;
static{
static {
// The list of slots needs to be mutable.
List<EntityEquipmentSlot> slots = new ArrayList<EntityEquipmentSlot>(
List<EntityEquipmentSlot> slots = new ArrayList<>(
Arrays.asList(EntityEquipmentSlot.values()));
slots.removeIf(slot -> slot.getSlotType() != Type.ARMOR);
ARMOUR_SLOTS = slots.toArray(new EntityEquipmentSlot[0]);
@@ -146,13 +144,11 @@ public final class WizardryUtilities {
/**
* Returns whether the block at the given coordinates is unbreakable in survival mode. In vanilla this is true for
* bedrock and end portal frame, for example. This is a shortcut for
* world.getBlockState(pos).getBlockHardness(world, pos) == -1.0f. Not much of a shortcut any more, since block ids
* have been phased out.
* bedrock and end portal frame, for example. This is a shortcut for:<p>
* {@code world.getBlockState(pos).getBlockHardness(world, pos) == -1.0f}
*/
public static boolean isBlockUnbreakable(World world, BlockPos pos){
return world.isAirBlock(new BlockPos(pos)) ? false
: world.getBlockState(pos).getBlockHardness(world, pos) == -1.0f;
return !world.isAirBlock(new BlockPos(pos)) && world.getBlockState(pos).getBlockHardness(world, pos) == -1.0f;
}
/**
@@ -160,11 +156,9 @@ public final class WizardryUtilities {
* Liquids and other blocks that cannot be built on top of do not count, but stuff like signs does. (Technically any
* block is allowed to be the floor according to the code, but seeing as it searches upwards and non-solid blocks
* usually need a supporting block, the floor is likely to always be solid).
*
* @param world
* @param x The x coordinate to search in
* @param y The y coordinate to search from
* @param z The z coordinate to search in
*
* @param world The world to search in
* @param pos The coordinates to search from
* @param range The maximum distance from the given y coordinate to search.
* @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the
* floor as would be seen in the debug screen when the player is standing on it.
@@ -189,10 +183,8 @@ public final class WizardryUtilities {
* Finds the nearest floor level to the given y coord within the range specified at the given x and z coords. Only
* works if the block above the floor is actually air and the floor is solid or a liquid.
*
* @param world
* @param x The x coordinate to search in
* @param y The y coordinate to search from
* @param z The z coordinate to search in
* @param world The world to search in
* @param pos The coordinates to search from
* @param range The maximum distance from the given y coordinate to search.
* @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the
* floor as would be seen in the debug screen when the player is standing on it.
@@ -216,11 +208,9 @@ public final class WizardryUtilities {
/**
* Finds the nearest floor level to the given y coord within the range specified at the given x and z coords.
* Everything that is not air is treated as floor, even stuff that can't be walked on.
*
* @param world
* @param x The x coordinate to search in
* @param y The y coordinate to search from
* @param z The z coordinate to search in
*
* @param world The world to search in
* @param pos The coordinates to search from
* @param range The maximum distance from the given y coordinate to search.
* @return The y coordinate of the closest floor level, or -1 if there is none. Returns the actual level of the
* floor as would be seen in the debug screen when the player is standing on it.
@@ -300,7 +290,7 @@ public final class WizardryUtilities {
/**
* Gets the blockstate of the block the specified entity is standing on. Uses
* {@link MathHelper#floor_double(double)} because casting to int will not return the correct coordinate when x or z
* {@link MathHelper#floor(double)} because casting to int will not return the correct coordinate when x or z
* is negative.
*/
public static IBlockState getBlockEntityIsStandingOn(Entity entity){
@@ -331,7 +321,7 @@ public final class WizardryUtilities {
* this does not exclude any entities; if any specific entities are to be excluded this must be checked when
* iterating through the list.
*
* @see {@link WizardryUtilities#getEntitiesWithinRadius(double, double, double, double, World)}
* @see WizardryUtilities#getEntitiesWithinRadius(double, double, double, double, World)
* @param radius The search radius
* @param x The x coordinate to search around
* @param y The y coordinate to search around
@@ -396,12 +386,11 @@ public final class WizardryUtilities {
/**
* Returns the entity riding the given entity, or null if there is none. Allows for neater code now that entities
* have a list of passengers, because it is necessary to check that the list is not null or empty first.
* have a list of passengers, because it is necessary to check that the list is not empty first.
*/
@Nullable
public static Entity getRider(Entity entity){
return entity.getPassengers() != null && !entity.getPassengers().isEmpty() ? entity.getPassengers().get(0)
: null;
return !entity.getPassengers().isEmpty() ? entity.getPassengers().get(0) : null;
}
/**
@@ -542,8 +531,8 @@ public final class WizardryUtilities {
/**
* Turns the given creeper into a charged creeper. In 1.10, this requires reflection since the DataManager keys are
* private. (You <i>could</i> call {@link EntityCreeper#onStruckByLightning(...)} and then heal it and extinguish
* it, but that's a bit awkward.)
* private. (You <i>could</i> call {@link EntityCreeper#onStruckByLightning(EntityLightningBolt)} and then heal it
* and extinguish it, but that's a bit awkward, and it'll trigger events and stuff...)
*/
// The reflection here only gets done once to initialise the POWERED field, so it's not a performance issue at all.
public static void chargeCreeper(EntityCreeper creeper){
@@ -578,7 +567,7 @@ public final class WizardryUtilities {
* Helper method which performs a ray trace for blocks and entities from an entity's eye position in the direction
* they are looking, over a specified range, using {@link WizardryUtilities#rayTrace(World, Vec3d, Vec3d, float,
* boolean, Class, Predicate)}. Aim assist is zero, the entity type is simply {@code Entity} (all entities), and the
* filter removes the given entity and allows all others.
* filter removes the given entity and any dying entities and allows all others.
*
* @param world The world in which to perform the ray trace.
* @param entity The entity from which to perform the ray trace. The ray trace will start from this entity's eye