Jump to content

jabelar

Members
  • Posts

    3266
  • Joined

  • Last visited

  • Days Won

    39

Everything posted by jabelar

  1. Minecraft is Java and you can do whatever Java can do. However in this case I think even Java it may be "impossible" (at least not normal or easy) to change assets within the JAR. However, you can write and read from filesystem like normal Java. For example, you could put this asset in the configuration folder (which is usually in user directory). So imagine you have a default asset inside your JAR, then when game starts you check to see if there is a newer copy in some file location in user directory, and if not copy it there. After that you can write it how you like.
  2. You can use file like methods to access an asset, but only read access, not write access because resources are in the JAR which is technically compressed. If you just want to read the file, then you can use various file and streaming Java methods. For example I use the getResourceAsStream() method: readIn = new BufferedReader(new InputStreamReader(getClass().getClassLoader() .getResourceAsStream("assets/magicbeans/structures/schematic.txt"), "UTF-8"));
  3. So modding is just using Java, so you should just do file operations like you would normally. Perhaps you can use the user home directory. In your pre-init method (the method that handles the FMLPreInitializationEvent event), the event that is passed has a field called: getSuggestedConfigurationFile() You could take the path to that file and use same path for your file. The point is that this is a place that the user already expects some Minecraft mod specific files, so it shouldn't be annoying to them if you do some other file activity there.
  4. First of all, for changing vanilla behavior you should look for these things in the following order 1. Public fields and methods. Many vanilla classes have public fields and methods that you can directly access. For example if you look at EntityLiving, the living sound time and the AI list are public fields, and there are public getter methods for the look helper, move helper, jump helper, navigator, setting the attack target and so on. Use Eclipse to check the "type hierarchy" of the class to see all the fields and methods available to you. 2. Registries and dictionaries. You can find out a lot about what blocks, items, entities, recipes, ores, etc. are available and possibly modify them. 3. Events. Forge has tried to provide hooks for many common, useful places to intercept the vanilla processing. for example, you can change what an entity drops when it dies, you can change how pretty much everything renders, etc. 4. Java Reflection. Java is a funny language but you can get access to private and protected fields and methods with reflection. It is a lot easier than it sounds. 5. Replacing vanilla stuff with your own custom copy. You can intercept spawns, placements, registrations and use your own custom class instead. If your custom class extends the vanilla class it is replacing, then other code should generally consider it like the vanilla class (e.g. instanceof tests would pass). 6. Access transformers (ASM). I don't know much about this, but you can basically change how the vanilla code executes. Anyway, don't just jump into using events. First of all check for public methods.
  5. It is always good feeling of accomplishment when you've really worked through this stuff and achieved full understanding and useful result. Thanks for sharing!
  6. I actually think, that for your own custom mobs, that keeping track of your own lastAttacker type field is easiest thing to do. You can simply update it in the attackEntityFrom() method. I really think that various Entity lastAttacker fields are unreliable because some classes are implemented that override the entire attackEntityFrom() and attackEntityAsMob() or the various attack AI classes and therefore I suspect that there are least a couple entity classes that don't keep that field properly up to date. Anyway, I think if you have custom entities that extend various entity classes you should carefully inspect the behavior of lastAttacker.
  7. For furnace there is PlayerEvent.ItemSmeltedEvent. If you're interested in crafting table there is PlayerEvent.ItemCraftedEvent. And there is a PotionBrewedEvent. But for others I don't think there is. One thing you can do is replace the vanilla ones with your own that extend the original but fire a custom event (or maybe just execute some code) when you want.
  8. The reason you guys are arguing about this is that you don't understand what he was asking for. Yes, the command prompt only says "access denied" but it says that AFTER you typed in something. He wanted to see the command you typed in that got the response "access denied". By seeing the command he might have seen something like the directory you were in, maybe a typographical issue, maybe you used some gradlew parameter that you shouldn't be using. So he was asking for what exactly you put in. Since people often make typos when using computers, that is why he wanted a screen shot instead of just a description. Like maybe you accidentally misspelled gradlew, or maybe you tried to run gradle instead of gradlew, etc.
  9. Okay, I looked through the code and I think you are actually right, depending on how you made your custom mob. What class did you extend? Anyway, in EntityLivingBase the getLastAttacker() returns the lastAttacker field value and the lastAttacker field is set in the setAttacker() method which is called in the attackEntityAsMob() method. So looking at this the other way around if the entity attacksAsMob() then it will set that entity as the lastAttacker. Actually, the code seems fairly inconsistent. EntityMob has its own attackEntityAsMob() code that doesn't call super methods but also doesn't update lastAttacker. There doesn't seem to be any update of lastAttacker anywhere in the class. EntityPlayer also calls setLastAttacker() but you're right it is set to the entity the player attacks. Can someone else check this? It is late at night, but it seems to me that the logic is backwards just like knokko says. I think this is example where the naming of the methods is wrong. There are several other logical naming errors in this attack code actually. For example, the hitByEntity() method is actually a method to check if you can hit the entity and it returns false if you can. It should really be named something like isEntityInvulnerable(). Anyway, in your custom mob you can create your own true variable to track the last attacker. You could set it in the attackEntityFrom() method which is method called when your mob is attacked.
  10. I have a tutorial on organizing and using sound assets in 1.7.x: http://jabelarminecraft.blogspot.com/p/minecraft-forge-1721710-organizing-and.html I do think you have to have your sounds in OGG format, but I discuss how to convert them in the tutorial.
  11. That should be the right method. Why do you think it is the other way? Often both attack each other, so the last attacker and the last attacked would be the same thing. But lastAttacker should be the mob that attacked player.
  12. I tried googling and git related documentation, but my search terms just ended up at a tutorials on branching, so hopefully someone here can help. Basically I'm using git (via Source tree and github) to "collaborate with myself" -- meaning work on projects from several different computers. Most of my projects are fine, with local repository having proper package names in format of com.blogspot.jabelarminecraft but one repository ended up with packages as src.main.java.com.blogspot.jabelarminecraft. I don't see any obvious differences in the github repositories between the working and non working one. I will probably just try a fresh setup, but I like to understand when things go wrong. Anyone have a idea on what I did wrong?
  13. Okay, I went ahead and made a regular spawn egg. I made it quickly, but seems to work. Anyway, hopefully it gives you the right idea. Create your own class as extension of ItemMonsterPlacer: /** Copyright (C) 2014 by jabelar This file is part of jabelar's Minecraft Forge modding examples; as such, you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. For a copy of the GNU General Public License see <http://www.gnu.org/licenses/>. */ package com.blogspot.jabelarminecraft.wildanimals.items; import java.util.List; import net.minecraft.block.Block; import net.minecraft.block.BlockLiquid; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityList; import net.minecraft.entity.EntityLiving; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.IEntityLivingData; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemMonsterPlacer; import net.minecraft.item.ItemStack; import net.minecraft.util.Facing; import net.minecraft.util.IIcon; import net.minecraft.util.MathHelper; import net.minecraft.util.MovingObjectPosition; import net.minecraft.world.World; import com.blogspot.jabelarminecraft.wildanimals.WildAnimals; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; public class WildAnimalsMonsterPlacer extends ItemMonsterPlacer { @SideOnly(Side.CLIENT) private IIcon theIcon; protected int colorBase = 0x000000; protected int colorSpots = 0xFFFFFF; protected String entityToSpawnName = ""; protected String entityToSpawnNameFull = ""; protected EntityLiving entityToSpawn = null; public WildAnimalsMonsterPlacer() { super(); } public WildAnimalsMonsterPlacer(String parEntityToSpawnName, int parPrimaryColor, int parSecondaryColor) { setHasSubtypes(false); maxStackSize = 64; setCreativeTab(CreativeTabs.tabMisc); setEntityToSpawnName(parEntityToSpawnName); colorBase = parPrimaryColor; colorSpots = parSecondaryColor; // DEBUG System.out.println("Spawn egg constructor for "+entityToSpawnName); } /** * Callback for item usage. If the item does something special on right clicking, he will have one of those. Return * True if something happen and false if it don't. This is for ITEMS, not BLOCKS */ @Override public boolean onItemUse(ItemStack par1ItemStack, EntityPlayer par2EntityPlayer, World par3World, int par4, int par5, int par6, int par7, float par8, float par9, float par10) { if (par3World.isRemote) { return true; } else { Block block = par3World.getBlock(par4, par5, par6); par4 += Facing.offsetsXForSide[par7]; par5 += Facing.offsetsYForSide[par7]; par6 += Facing.offsetsZForSide[par7]; double d0 = 0.0D; if (par7 == 1 && block.getRenderType() == 11) { d0 = 0.5D; } Entity entity = spawnEntity(par3World, par4 + 0.5D, par5 + d0, par6 + 0.5D); if (entity != null) { if (entity instanceof EntityLivingBase && par1ItemStack.hasDisplayName()) { ((EntityLiving)entity).setCustomNameTag(par1ItemStack.getDisplayName()); } if (!par2EntityPlayer.capabilities.isCreativeMode) { --par1ItemStack.stackSize; } } return true; } } /** * Called whenever this item is equipped and the right mouse button is pressed. Args: itemStack, world, entityPlayer */ @Override public ItemStack onItemRightClick(ItemStack par1ItemStack, World par2World, EntityPlayer par3EntityPlayer) { if (par2World.isRemote) { return par1ItemStack; } else { MovingObjectPosition movingobjectposition = getMovingObjectPositionFromPlayer(par2World, par3EntityPlayer, true); if (movingobjectposition == null) { return par1ItemStack; } else { if (movingobjectposition.typeOfHit == MovingObjectPosition.MovingObjectType.BLOCK) { int i = movingobjectposition.blockX; int j = movingobjectposition.blockY; int k = movingobjectposition.blockZ; if (!par2World.canMineBlock(par3EntityPlayer, i, j, k)) { return par1ItemStack; } if (!par3EntityPlayer.canPlayerEdit(i, j, k, movingobjectposition.sideHit, par1ItemStack)) { return par1ItemStack; } if (par2World.getBlock(i, j, k) instanceof BlockLiquid) { Entity entity = spawnEntity(par2World, i, j, k); if (entity != null) { if (entity instanceof EntityLivingBase && par1ItemStack.hasDisplayName()) { ((EntityLiving)entity).setCustomNameTag(par1ItemStack.getDisplayName()); } if (!par3EntityPlayer.capabilities.isCreativeMode) { --par1ItemStack.stackSize; } } } } return par1ItemStack; } } } /** * Spawns the creature specified by the egg's type in the location specified by the last three parameters. * Parameters: world, entityID, x, y, z. */ public Entity spawnEntity(World parWorld, double parX, double parY, double parZ) { if (!parWorld.isRemote) // never spawn entity on client side { entityToSpawnNameFull = WildAnimals.MODID+"."+entityToSpawnName; if (EntityList.stringToClassMapping.containsKey(entityToSpawnNameFull)) { entityToSpawn = (EntityLiving) EntityList.createEntityByName(entityToSpawnNameFull, parWorld); // entityToSpawn.setPosition(parX, parY, parZ); entityToSpawn.setLocationAndAngles(parX, parY, parZ, MathHelper.wrapAngleTo180_float(parWorld.rand.nextFloat() * 360.0F), 0.0F); parWorld.spawnEntityInWorld(entityToSpawn); entityToSpawn.onSpawnWithEgg((IEntityLivingData)null); entityToSpawn.playLivingSound(); } else { //DEBUG System.out.println("Entity not found "+entityToSpawnName); } } return entityToSpawn; } // EntityLiving entityToSpawn = (EntityLiving) EntityList.createEntityByName(entityToSpawnName, parWorld); // EntityTiger entityToSpawn = new EntityTiger(parWorld); // // DEBUG // System.out.println("Created entity"); // entityToSpawn.setPosition(parX, parY, parZ); // // DEBUG // System.out.println("Setting position"); // parWorld.spawnEntityInWorld(entityToSpawn); // System.out.println("Spawned in world"); // entityToSpawn.rotationYawHead = entityToSpawn.rotationYaw; // entityToSpawn.renderYawOffset = entityToSpawn.rotationYaw; // entityToSpawn.onSpawnWithEgg((IEntityLivingData)null); // entityToSpawn.playLivingSound(); // // return entityToSpawn; // } // return null; // // } /** * returns a list of items with the same ID, but different meta (eg: dye returns 16 items) */ @Override @SideOnly(Side.CLIENT) public void getSubItems(Item parItem, CreativeTabs parTab, List parList) { parList.add(new ItemStack(parItem, 1, 0)); } @Override @SideOnly(Side.CLIENT) public int getColorFromItemStack(ItemStack par1ItemStack, int parColorType) { return (parColorType == 0) ? colorBase : colorSpots; } @Override @SideOnly(Side.CLIENT) public boolean requiresMultipleRenderPasses() { return true; } @Override // Doing this override means that there is no localization for language // unless you specifically check for localization here and convert public String getItemStackDisplayName(ItemStack par1ItemStack) { return "Spawn "+entityToSpawnName; } @Override @SideOnly(Side.CLIENT) public void registerIcons(IIconRegister par1IconRegister) { super.registerIcons(par1IconRegister); theIcon = par1IconRegister.registerIcon(getIconString() + "_overlay"); } /** * Gets an icon index based on an item's damage value and the given render pass */ @Override @SideOnly(Side.CLIENT) public IIcon getIconFromDamageForRenderPass(int parDamageVal, int parRenderPass) { return parRenderPass > 0 ? theIcon : super.getIconFromDamageForRenderPass(parDamageVal, parRenderPass); } public void setColors(int parColorBase, int parColorSpots) { colorBase = parColorBase; colorSpots = parColorSpots; } public int getColorBase() { return colorBase; } public int getColorSpots() { return colorSpots; } public void setEntityToSpawnName(String parEntityToSpawnName) { entityToSpawnName = parEntityToSpawnName; entityToSpawnNameFull = WildAnimals.MODID+"."+entityToSpawnName; // need to extend with name of mod } }[code] Make sure you register it like a normal item, in your common proxy pre-init handling method. Something like this: [code] // can't use vanilla spawn eggs with entities registered with modEntityID, so use custom eggs. // name passed must match entity name string public void registerSpawnEgg(String parSpawnName, int parEggColor, int parEggSpotsColor) { Item itemSpawnEgg = new WildAnimalsMonsterPlacer(parSpawnName, parEggColor, parEggSpotsColor).setUnlocalizedName("spawn_egg_"+parSpawnName.toLowerCase()).setTextureName("wildanimals:spawn_egg"); GameRegistry.registerItem(itemSpawnEgg, "spawnEgg"+parSpawnName); } Of course you need to call the above method for each custom entity you create, passing it an egg color, etc. Lastly, you need to copy the vanilla textures for the egg base and the egg spots and name them such that it matches the icon registration. Hope that helps!
  14. Thank you for your reply, I am having a problem because your tutorial for the spawn egg is throwable. How would I do it normally? Yeah I need to update the tutorial to include a regular spawn egg. The problem is that the new way of registering entities does not allow you to register spawn egg at the same time. So you have to create your own. To create your own spawn egg, you need to extend ItemMonsterPlacer. "Monster Placer" is what spawn eggs are called in the code. Then you can @Override the spawnCreature() method to return your custom entity instead of looking it up in the egg registry. You'll also want to @Override other methods that look up the entity or spawn egg registery, like the getDisplayName() and such. You may also have to do something to get the color right, I need to look at that more. It is an item so you'll want to register it as a item.
  15. I have a tutorial on custom entities. In this case they are creatures, not mobs, but most of the information is the same. If your entity is truly custom (like custom model, AI, sounds, etc.) then there are actually quite a few steps you need to do and my tutorial should help you with many of them: http://jabelarminecraft.blogspot.com/p/creating-custom-entities.html
  16. Well the break block event handler method shouldn't be in your actual block, but instead probably best to make an event handler class and put it in there. Because the break block event will be fired for EVERY block that breaks. So what you need to do in that method is check which block got broken and then proceed from there. The event handling code there shouldn't crash things (it doesn't even do anything). So it must be something else. What is the crash log say?
  17. What are you trying to accomplish? All modding is "overriding" the base classes. Generally, if you want to change behavior of base classes you should first look for public methods and fields. For example, the AI task lists of entities are public and so you can totally replace the entity AI. Secondly, you can look at events. Forge specifically intercepts many places where modders may want to change base behavior. You can cancel many default behaviors and replace with your own code. Thirdly you can use Java reflection. This can help you access many protected and private fields and methods directly. Fourthly you can use access transformers to truly modify the way the code operates. Fifthly, many things are in registries which are public and you can de-register and re-register your own version of things. Lastly, you can create custom versions (meaning extend in Java) of things and replace the base versions. Like whenever a creeper spawns you could replace it with your own custom creeper, whenever a block gets placed put your own custom block instead, and so on. So there is very little reason to actually want to change the actual base classes, since you have all the techniques above to use.
  18. That isn't fair. Although the tone may have sounded critical, they answered every question you posted with correct information in a quick manner. You can't complain about that. You even got pointed to the right track by one of the most revered guys LexManos! The confusion arose because you did not understand that these exceptions have a built-in "GUI" message ability that doesn't need a lot of GUI screen work. LexManos and diesieben07 are sometimes terse with their answers, but they give good advice and that is what counts.
  19. Wow! You've got some time on your hands. Good stuff though! I'm going to study these when I'm not so tired.
  20. Okay, one of the biggest tips I can give new modders and programmers is to learn to use your IDE (Eclipse or IntelliJ) to *explore* and *investigate* the Minecraft / Forge / FML code. So if you know the name of a class, method or field, you can find it in several ways. In Eclipse you could do a Java search, but just make sure you correctly select what you're searching for (a method if it is a method, etc.) In this case you would search for a type of CustomModLoadingErrorDisplayException . You should see it come up in the search results pane and you can double-click to open the class. Another way is to take some class you've already got coded, type in CustomModLoadingErrorDisplayException somewhere and when Eclipse red-underlines it hover above and accept the suggested import. Then right click on it and select Open Declaration. That will take you right to the class. Lastly, you can hunt through the reference libraries themselves. I find this works okay if you already have a good idea where to look, but for something like this you might not be familiar enough to guess the right packages to check.
  21. Actually it is still not clear what the OP wants to do. Maybe he just wants a count of all TileEntities or something, in which a list might suffice. Maybe he cares about processing based on ID after his initial search for them, in which case a map might be convenient. Maybe quickly referencing position is useful and so hashmap keyed of position might be useful. I think the point is there are many standard Java data structures that can help keep track, and the coding isn't that advanced to use them.
  22. Hmmm, interesting point. I guess I have never fully realized that the static was across both sides since I thought that somehow even in SP that the Java was fully segregated. But I guess that doesn't make sense since SP only kicks off one Java runtime. So each has own instances but still are technically same class with shared static. I get it. Back to the question: It's not clear what the OP really wants to do with these tile entities that he's tracking. So he may want to track both, or I guess probably better is only track on server and let client sync naturally? @robertcars, you might want to create two lists, one for tile entities found on server side and one for tile entities found on client side. (To understand this, the server and client run their own "copies" of many class instances which then are synced via built-in packets. The problem is that if your client iterates the list it would not be good to try to process the server instances and vice versa. Depending on what you're doing, you would use the list appropriate to the side you're interested in.
  23. All he meant was to create a List of your own. So imagine your tile entity class had a static field that was a list and every time an instance was contructed it added it to that list. Then each tile entity could access this shared list and just check that for ones that may have same id. You'd also want to make sure that every time the tile entity was destroyed it would remove it from the list as well. So nothing too difficult.
  24. @ForgeSubscribe was used for 1.6.4 I think but for 1.7.x you should use @SubscribeEvent instead. You use it in same way (annotation before the method).
  25. Well, even post init might work better. But there are several more of these "FML lifecycle events" like server starting, server started, etc. that might also be appropriate. In my tutorial on events about a quarter of the way down, I list out all the FML lifecycle events: http://jabelarminecraft.blogspot.com/p/minecraft-forge-172-event-handling.html
×
×
  • Create New...

Important Information

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