Jump to content

coolAlias

Members
  • Posts

    2805
  • Joined

  • Last visited

Posts posted by coolAlias

  1. You can intercept all mouse actions using MouseEvent from minecraft.forge.net.client.event.

    event.button // id of button: 0 left, 1, right, -1 wheel
    event.buttonstate // true when pressed, false when released
    event.dwheel // mouse wheel amount
    event.setResult(Event.Result.DENY) // prevents the click from processing, but button.pressed will still be true
    event.setCanceled(true) // completely cancels the button press, such that button.pressed is not set to true
    

    If you want to see this in action, you can take a look at how I handle user input for my Zelda Sword Skills mod. In the ZSSEventHandler class, search for 'onMouseChanged'. Here's the github link:

    https://github.com/coolAlias/ZeldaSwordSkills/blob/master/src/zeldaswordskills/handler/ZSSEventHandler.java

  2. But on a side note, in your tutorial it does say you haven't found a use for your Init method. You have figured out what that does, correct?

    It's the same as entityInit in Entity classes; it gets called during entity construction, so you could put the exact same code in your constructor and it would have the same effect. The benefit of the init method in IExtendedEntityProperties is that it provides a world object, but I haven't found it (the extra world parameter) particularly useful because the entity itself isn't yet finished constructing.

  3. If everything is saving and loading properly, then you're fine. The problem is that the client-side data is not automatically synchronized, so you have to do it yourself.

     

    Either:

    a) send a packet to the client with the data and set it manually; this is best done from somewhere like the EntityJoinWorldEvent to avoid NPE of the client-side properties

     

    b) use DataWatcher to store your data instead of class fields; advantage is that everything else is automatic; disadvantage is you are using an extremely limited resource (data watcher slots)

     

    There are tutorials on the Forge wiki about both packets and data watcher, both of which are referenced on this list:

    http://mazetar.com/mctuts/displayTutorials.php

     

    Alternatively, you can check out my tutorial on IExtendedEntityProperties here:

    http://www.minecraftforum.net/topic/1952901-eventhandler-and-iextendedentityproperties/#entry24051513

  4. Which means....an explosion that has enough force...could destroy water blocks and beyond.

    That would be pretty dangerous :P Instead, I've just coded a custom explosion class that can handle much wider variety of specifications, yet still retains the functionality of and can be substituted for the vanilla class.

     

    This way, I can just set a variable to ignore liquids and still maintain a not-too destructive explosion, along with all sorts of other fun things. Thanks again for the help. I still don't know why I didn't check the actual explosion resistance of water...

  5. It has to do with the fact that water has an explosion resistance of 500, which completely negates the explosion rays, I believe.

     

    *Checks*

     

    Yep.  If I force water to have a resistance of 0, explosions happen as if they were in air.

    Ah, Draco to the rescue ;) Don't know why I didn't see that myself <facepalm>. Derp.

  6. I'm not trying to destroy the water, I'm trying to destroy blocks with explosions that happen IN the water.

     

    Of course I could just write my own methods instead of using the vanilla Explosion class, but I'm puzzled that I can't seem to find where Minecraft decides that the explosion is in water and then prevents it from destroying blocks.

     

    Thanks for the reply, though.

  7. I've been poring through all the code related to Explosions that I can find, which apparently isn't much, because I can't find where it decides that blocks cannot be destroyed while underwater.

     

    Here's everything I could find out about explosions:

     

     

    World->createExplosion-> creates an Explosion object -> does the explosion.

     

    doExplosionA first sets up a hash set of all the chunk positions that will be affected, using either Block or Entity's getBlockExplosionResistance and Entity.shouldExplodeBlock to determine if it's valid. None of those methods check anything to do with water.

     

    After adding all affected blocks to the hashset, part A goes on to inflict damage to entities, using getBlockDensity and distance from the explosion center to determine damage inflicted.

     

    doExplosionB runs through all of the affected blocks in the set, blowing them up and dropping drops as necessary if the explosion 'isSmoking'; the method parameter simply determines if particles will spawn, so it is always true when called from World, and always false from WorldServer.

     

    As long as the block has a valid id, it is blown up with no further checks, only some calls to determine if it should drop drops, handle tile entities, etc. Still no sign of water, and the explosion is at its end.

     

     

    Nowhere in there do I see any reference to water or anything that would prevent blocks from being destroyed when the explosion occurs in water. What am I missing here?

     

  8. If your container Item is kept in sync when using it from the equipped slot, then it should be as simple as using that exact same method for when it's accessed from the custom slot.

     

    For example, if you are using the Item's onUpdate method to save the inventory contents, it is not called automatically for custom slots, only vanilla inventory slots.

     

    Use Forge's LivingUpdateEvent to check if the entity/player has your custom inventory slot and, if so, get the stack from there and call the onUpdate method for the item.

     

    If you don't have your container Item inventory saved and synchronized even just when right-clicked, then you need to go back and get that part working first.

  9. Thanks for confirming my suspicions. Looking more closely into the code, I see the portal is created in ServerConfigurationManager.transferEntityToWorld, which seems to get called no matter what method was originally used to teleport.

     

    I haven't had any luck using setPositionAndUpdate unless I send the player back to the original portal; how far away did you set their position? This is what I tried which works for not returning to the nether, but it still spawns a portal:

     

    double dy = (double) player.worldObj.getHeightValue((int) player.posX - 10, (int) player.posZ + 10);
    player.setPositionAndUpdate(player.posX - 10, dy + 1, player.posZ + 10);
    

     

  10. Solution (thanks to Draco):

    Set the player's position with setPositionAndUpdate, adjusting x and z by at least one so the player doesn't spawn directly in the created portal. If you don't want a portal to generate at all, you must set the player's position at least 32+ blocks away from their initial position as set by travelToDimension. Be sure to use the player's world object rather than one passed in from the method parameters after using travelToDimension, as the worldObj has changed.

     

    Problem:

    I'm trying to make an item that when used teleports the player back to the overworld from the nether, but everytime I use it, the change dimension screen shows but I end up right back in the nether:

    public void onPlayerStoppedUsing(ItemStack stack, World world, EntityPlayer player, int ticksRemaining) {
    switch(player.dimension) {
    case -1:
    player.travelToDimension(0);
    break;
    }
    default: ;
    }
    

    If I travel far enough from the first nether portal, this code will create a new nether portal in whatever chunk I happen to spawn in (still in the Nether). I do see the overworld for a second, so I believe I am teleporting, but it is immediately sending me back... I'm thinking it spawns the player directly in a portal...

     

    I tried using 'player.setInPortal()' before changing dimension to try to prevent the player from teleporting immediately, but that didn't work. Any ideas?

  11. Thanks for the idea, but I just ended up using a packet:

    // this is in the Item's onUpdate method:
    if (isHeld) {
    		if (entity instanceof EntityPlayer) {
    			if (world.isRemote && Minecraft.getMinecraft().currentScreen == null) {
    				PacketDispatcher.sendPacketToServer(new BombTickPacket().makePacket());
    			}
    		} else {
    			tickBomb(stack, world, entity);
    		}
    	} else {
    		stack.getTagCompound().setInteger("time", 0);
    	}
    

    As you can see, when held by a player, it does nothing if on the server side; instead, it checks for an open screen on the client side and if there isn't one, sends a packet telling the server to 'tick' the bomb, which is a method that has the same stuff that used to be in the onUpdate method.

     

    It's a simple solution to a simple problem; I was just wondering if there wasn't another way to do it is all.

  12. That's what my plan is, I was just hoping that I may have overlooked something that would obviate the need for an extra packet. It just seems like something that should be easily detectable with an instance of the player, even the server side version, but I have combed through the available methods and fields multiple times and come up with nada. Thanks, though.

  13. I've got an item that writes to NBT while held on each Item update tick, but I only want it to update if no gui screens are open.

     

    player.openContainer is never null; in normal gameplay ContainerPlayer is constantly open, which also happens to be open when the player's normal inventory is open.

     

    FMLClientHandler.instance().getClient().inGameHasFocus would seem like a good choice, and it works when only running the regular client, but this crashes if run on the server (obviously) and I can't just run the Item update on the client side. So it would seem this option is not SMP compatible.

     

    Am I just failing to see how to use these to solve my problem, or are there any other options that are SMP compatible?

  14. Be sure you only register your SoundHandler class on the client side, or you will crash when you try to run your mod on a server environment (because the event's SoundManager is a client side only class). Easiest way to ensure that is to put the registration in your ClientProxy.

     

    P.S. volume AND pitch can both have pretty much any value; vanilla often uses random values for the pitch especially so that the sound doesn't always sound the same:

    // from ItemBow; note the final parameter for pitch is different every time the bow fires,
    // but volume, in this particular case, is set at 1.0F
    par2World.playSoundAtEntity(par3EntityPlayer, "random.bow", 1.0F, 1.0F / (itemRand.nextFloat() * 0.4F + 1.2F) + f * 0.5F);
    

  15. While adding items to LivingDropsEvent's drops list, I noticed that sometimes when I killed the mob my item would spawn, but then quickly disappear. Using spawnEntityInWorld directly from the event has the same effect.

    EntityLivingBase mob = event.entityLiving;
    ItemStack orb = getOrbDrop(mob); // this just returns an itemstack to drop
    if (orb != null) {
    // tried this one first:
    event.drops.add(new EntityItem(mob.worldObj, mob.posX, mob.posY, mob.posZ, orb));
    
    // then I tried the following instead:
    mob.worldObj.spawnEntityInWorld(new EntityItem(mob.worldObj, mob.posX, mob.posY, mob.posZ, orb));
    
    // both with the same result
    }
    

    I thought it might be something to do with spawning the item directly on the mob's position, getting cleared when the mob is marked for removal or something like that, but in the entityDropItem method that's exactly how they create the EntityItems, so... what's going on here?

     

    EDIT: Figured it out. If I use 'copy()' on the ItemStack when I construct the EntityItem, everything works as intended. I suppose that's what I get for using a static method to return my ItemStack :P

    // working code
    mob.worldObj.spawnEntityInWorld(new EntityItem(mob.worldObj, mob.posX, mob.posY, mob.posZ, orb.copy()));
    

  16. Ooooh, I never thought of adding a class to a vanilla package! I was trying to figure out how to make a wrapper like that, and all I could think of was making a class extend EntityLivingBase, which of course wouldn't help at all because none of the vanilla mobs would even use that class... Is it not considered taboo to add custom classes to vanilla packages? It's not editing any vanilla code, though, so I don't see why not ;)

     

    Anyway, that's a great idea! I've got my flag built in to the way the skill works, so the second event shouldn't be a problem. Thanks for the tip though.

  17. Thanks for the reply. Yes, AttackEntityEvent could work, but if I'm not mistaken then once attackTargetEntityWithCurrentItem is called it's back to the same problem - getting it to use the new DamageSource - because attacking with the current item always causes 'player' damage.

     

    As for reflection, yes, that thought crossed my mind, but it seems so dirty :P I'll wait a while and see if any new ideas are forthcoming, but reflection may indeed be the best bet in this scenario.

  18. I'm making a skill that allows the player to charge up an attack and then strike, causing all of the normal sword damage but ignoring armor. I've considered many different ways of doing this, but all of them seem to require me to simulate (read 'copy / paste') significant portions of the vanilla attack code or are otherwise not good options.

     

    Let me outline what I've considered:

    1. In LivingHurtEvent, make a call to 'damageEntity' with a new, armor-ignoring DamageSource and either cancel the event or set the ammount to zero; Benefits: no adverse effect on any of the other attack calculations Problem is that 'damageEntity' is protected, so I'd have to copy / paste that code into my own method

     

    2. somehow reassign the DamageSource in LivingAttackEvent; this would be ideal, but I don't think it's possible because the event's DamageSource field is 'final' (which makes perfect sense, but still :( )

     

    3. cancel LivingAttackEvent and make a new call to attackEntityFrom with the new DamageSource; this one just no, the problems far outweigh any benefit that might be gained, since among other things this would cause 'attackEntityFrom' to return false in the player's 'attackTargetEntityWithCurrentItem' method mid-strike, but I still need that to return true for the rest of the calculation

     

    Number '1' is currently my top option, but I thought I'd ask if anyone knows of a better way. Thanks for any ideas.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.