Jump to content

coolAlias

Members
  • Posts

    2805
  • Joined

  • Last visited

Posts posted by coolAlias

  1. You can't just create a new entity whenever you want - you need the instance of the entity that already exists in the world. Luckily, there is an Item method called whenever you right-click on an entity with your item, which you can override to do whatever you want, e.g. teleport:

    @Override
    public boolean itemInteractionForEntity(ItemStack stack, EntityPlayer player, EntityLivingBase entity) {
        if (entity instanceof YourTargetEntityClass) {
              // put teleportation code or whatever here
              return true;
        }
        return false;
    }
    

  2. Can you show the code that spawns the entity, then? I don't see anything in the render or entity class that should make it behave differently in multiplayer.

     

    However, on a side note: looking at your renderer registrations in the ClientProxy and then at your RenderCapricorn class, I think you'd be a lot better off with a little OOP action, e.g.:

    @SideOnly(Side.CLIENT)
    public class RenderGenericEntity extends RenderBiped
    {
        private final ResourceLocation texture;
    
        public RenderCapricorn(ModelBiped model, float shadowSize, String textureName)
        {
            super(model, shadowSize);
            this.texture = new ResourceLocation(RefStrings.MODID + ":textures/entity/" + textureName + ".png");
        }
    
        @Override
        protected ResourceLocation getEntityTexture(Entity entity) {
            return this.texture;
        }
    }
    

    Then, every single one of your registrations can use the same class:

    RenderingRegistry.registerEntityRenderingHandler(EntityCapricorn.class, new RenderGenericEntity(new ModelBiped(), 0.3F, "capricorn"));
    

    Just a suggestion.

  3. That's not code from a Techne model - it's just Tesselator / addVertex calls that form a shape.

     

    And yes, if you have access to the icons, you can render each face using them:

    // renderer is a RenderBlocks instance; lots of values set above basically copied from RenderBlocks
    Tessellator tessellator = Tessellator.instance;
    		tessellator.setColorOpaque_F(r, g, b);
    		tessellator.setBrightness(983055);
    		int brightness = block.getMixedBrightnessForBlock(world, x, y, z);
    		if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y - 1, z, 0)) {
    			tessellator.setBrightness(renderer.renderMinY > 0.0D ? brightness : block.getMixedBrightnessForBlock(world, x, y - 1, z));
    			tessellator.setColorOpaque_F(f10, f13, f16);
    			renderer.renderFaceYNeg(block, x, y, z, block.getIcon(0, meta));
    			rendered = true;
    		}
    		if (renderer.renderAllFaces || block.shouldSideBeRendered(world, x, y + 1, z, 1)) {
    			tessellator.setBrightness(renderer.renderMaxY < 1.0D ? brightness : block.getMixedBrightnessForBlock(world, x, y + 1, z));
    			tessellator.setColorOpaque_F(f7, f8, f9);
    			renderer.renderFaceYPos(block, x, y, z, block.getIcon(1, meta));
    			rendered = true;
    		}
    // etc for the rest of the faces
    

    I would only do that if the block has different icons based on the metadata, though, or if you don't have access to an instance of the block. If it doesn't use metadata for rendering and you have a Block instance, you can render the block just by calling this:

    renderer.renderBlockByRenderType(block, x, y, z);
    

    There are all sorts of useful things to see in RenderBlocks, many of which are public methods you can use.

  4. There's not really anything wrong with sending a packet each tick if that's really what your code requires - Minecraft sends dozens if not hundreds of packets each tick.

     

    However, I don't see why you would need to send the same packet back to the client; can't you just run the code directly from the client side before or after you send the packet to the server, or are you relying on something happening on the server that gets sent in the response?

     

    As a comparison, most Minecraft code that sends a packet to the server just sends it one way and runs the code directly on the client, e.g. when a player left-clicks an entity, the attack/action packet is sent to the server, and the client immediately starts processing the player's left click action without waiting for any further data. This is all under the expectation that client-side code is mostly irrelevant except for animations, particles, and the like, so any 'effects' such as damage mean nothing unless on the server.

     

    TLDR; cut your packet numbers in half by eliminating the packet from server -> client.

  5. 1. No, unless the code also runs on the server and it sets the value to the same thing - not the same as synchronization, but often used by vanilla to make things 'snappier' on the client side.

     

    2. Yes, you can send packets to all entities tracking a given entity using

    ((WorldServer) worldObj).getEntityTracker().sendToAllTrackingEntity(entity, packet)

    ; DataWatcher does this for you automatically.

     

    3. Yes and no - you can write an abstract message class or interface that all of your packets inherit from that has a method to allow them to process themselves, then write a generic packet handler that calls that method. So you have a generic packet handler, but all it does is ask the packet to take care of the actual handling - this is the approach I use, but YMMV.

  6. Why do you need AbstractClientPlayer specifically? That is a CLIENT side only class, for one, so you'll want to check side before you check for instanceof, and the possible actual classes could be either EntityOtherPlayerMP or EntityPlayerSP... neither of which seem particularly useful.

     

    What are you trying to do, and what have you tried?

  7. Any mod entity will have been registered with EntityRegistry#registerModEntity which adds entries to both EntityList.classToStringMapping and EntityList.stringToClassMapping; the first has class to "mod_id.entity_name"  mappings, and the other has "mod_id.entity_name" to class mappings, so you can find it either with a name comparison or checking if the map contains the entity's class, depending on the actual implementation of whatever you are doing.

     

    The EntityList should also contain all vanilla entities, as far as I understand it.

  8. Looks like you are on 1.7.x - you'll want to override #onBlockPlacedBy which is called when a player places the block, and then #getIcon to return the appropriate texture based on the side and current metadata. You can basically copy the implementations from BlockFurnace provided that you are not using metadata for anything else, though I would recommend you take some time to understand how it works.

  9. @OP Lol, so your title proclaims indeed! Totally missed that, and didn't read anything about it in the main thread. :P

     

    As for recipes with NBT, that can be done, but ONLY for the output, e.g.:

    ItemStack output = new ItemStack(Items.wooden_sword); // create desired ItemStack
    output.addEnchantment(Enchantment.sharpness, 5); // add NBT data, e.g. enchantments
    GameRegistry.addShapelessRecipe(output, Blocks.dirt, Blocks.gravel)); // get a sharpness 5 sword with dirt and gravel! yay!
    

    The only way to handle NBT on the inputs, however, is to implement IRecipe and check for it yourself.

     

    @WeiseGuy - you should start your own topic, post your code, and explain more thoroughly what you are trying to accomplish.

     

  10. Unless you have a version of the BucketFull item for EVERY fluid (in which case the 'containedBlock' class member would be final and could then easily designate what the recipe output was), then your design is completely broken.

     

    Assuming you have one version of the full bucket for every fluid, you would do this:

    // new Object[]{} is added automatically by Java, but can (and should) be omitted
    GameRegistry.addRecipe(new ShapelessOreRecipe(new ItemStack(Blocks.clay), ModItems.bucketWoodFullWater, Blocks.dirt, Blocks.gravel));
    

     

    If that's not the case, then as I said, your design is broken: Items are singletons, so if you have one and only one bucketWoodFull Item, when you call 'setConatainedBlock(Blocks.water)' or whatever, EVERY SINGLE ONE of those wooden buckets in the entire world will now contain water, even if before they contained something else. Next time someone clicks an empty bucket on, say, sludge, now they all contain sludge.

     

    You should probably be storing the contained block type in the ItemStack's NBT, then it will be unique for every stack, meaning I can have a wooden bucket full of water and you filling up yours with sludge won't bother me in the least.

     

    To use an ItemStack with NBT in a recipe is possible, but you probably need to create a class that implements IRecipe and register that - in your implementation, you will be able to check the NBT data of the ingredients when determining the outcome.

  11. Code is code - as long as you write it using intelligible naming, anyone with coding experience can probably figure out what it's doing, even if they couldn't write it themselves.

     

    Anyway, assuming that your texture is the correct path and that your code is being called at the correct time (i.e. during block rendering), then I would say it may be that you the problem probably lies with your vertices - they are either out of order and/or the calls to addVertex are not using the correct values (as in all 0s and 1s is probably incorrect).

     

    To see what I mean, take a look at RenderBlocks#renderStandardBlock and trace it down to the individual face rendering, and you will see the values passed to #addVertex are much more complex than one may at first imagine - it's not as straightforward as the .JSON description of the block would have one believe. Just my guess - it could very well be something completely banal that I'm overlooking.

     

    As a further example, here is a custom model handled via ISBRH:

     

    Tessellator tessellator = Tessellator.instance;
    	block.setBlockBoundsForItemRender();
    	renderer.setRenderBoundsFromBlock(block);
    	GL11.glRotatef(90.0F, 0.0F, 1.0F, 0.0F);
    	GL11.glTranslatef(-0.5F, -0.5F, -0.5F);
    	tessellator.startDrawingQuads();
    	tessellator.setNormal(0.0F, -1.0F, 0.0F);
    	renderer.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 0, metadata));
    	tessellator.draw();
    	tessellator.startDrawingQuads();
    	tessellator.setNormal(0.0F, 1.0F, 0.0F);
    	renderer.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 1, metadata));
    	tessellator.draw();
    	tessellator.startDrawingQuads();
    	tessellator.setNormal(0.0F, 0.0F, -1.0F);
    	renderer.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 2, metadata));
    	tessellator.draw();
    	tessellator.startDrawingQuads();
    	tessellator.setNormal(0.0F, 0.0F, 1.0F);
    	renderer.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 3, metadata));
    	tessellator.draw();
    	tessellator.startDrawingQuads();
    	tessellator.setNormal(-1.0F, 0.0F, 0.0F);
    	renderer.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 4, metadata));
    	tessellator.draw();
    	tessellator.startDrawingQuads();
    	tessellator.setNormal(1.0F, 0.0F, 0.0F);
    	renderer.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 5, metadata));
    	tessellator.draw();
    	GL11.glTranslatef(0.5F, 0.5F, 0.5F);
    

     

    Note that I'm not adding vertices directly, but calling the RenderBlock methods to do it for me using the registered block icons. I'm not sure if that is an option for you, but if so, it might be worth pursuing.

  12. There's a little dance you have to do to make sure your extra data actually loads from the save file:

    // where 'saveData' is an instance of YourSaveDataClass that extends WorldSavedData
    /**
     * If saveData is null, it is loaded from world storage if available or a new one is created
     */
    protected final void loadOrCreateData(World world) {
    	if (saveData == null) {
    		// where #getTagName() simply returns a unique name for your storage
    		saveData = (YourSaveDataClass) world.getPerWorldStorage().loadData(YourSaveDataClass.class, getTagName());
    		if (saveData == null) {
    			saveData = new YourSaveDataClass(getTagName());
    			world.getPerWorldStorage().setData(getTagName(), saveData );
    		} else {
    			// saveData should have all of its NBT data now, but you'll probably want to translate
    			// that into a useful form e.g. populating your Maps, Lists, etc. from the stored data
    		}
    	}
    }
    

    You can put that method in the same class and make sure you call it every time before you try to access your saved data, or create a wrapper class with public-facing methods that call it for you, e.g.:

    public abstract class ZSSMapGenBase
    {
    /** Saved and loaded world data */
    private YourSaveDataClass saveData;
    
    private Map<String, String> someMapThatIsActuallyUseful = Maps.newHashMap();
    
    public String getSomethingFromMyMap(World world, String key) {
    	loadOrCreateData(world); // this should populate the 'actually useful' map with data
    	return someMapThatIsActuallyUseful.get(key);
    }
    
    // #loadOrCreateData, as described above, should be included here
    }
    

  13. What Draco said. You can try the GSON library from Google, which should already be included in the workspace.

     

    Note that .JSON is technically just text with a specific format - it is often used, for example, to serialize data for storage in a database (e.g. MySQL) or to transmit over a network (e.g. for an AJAX operation). The major benefit of it is that it facilitates the serialization of complex objects or arrays as simple text.

  14. Unfortunately, my geometry / math skills are quite rusty, but I can usually make do by finding something in vanilla that is similar and then tweaking the values.

     

    In this case, I'd recommend taking a look at the Iron Golem model, specifically the arm swinging animation when it attacks - that gives a fairly smooth up/down rotation that you could adapt to a horizontal one for your fish tail. The golem attack timer starts at 10 and decrements to 0, so the formula is multiplied in a way that 10-6 (or so) is moving up, and the rest is moving back down.

     

    If you're not familiar with the unit circle, especially the sine and cosine oscillations between -1 and 1 as you travel around it, I recommend some Googling of that as it is the basis of probably all swinging animations.

  15. Okay, so I type EntityHorse in, plus a period.  I don't see anything in the autocomplete even mentioning said variable of getHorseType().  I'd have to type in "this" to get anywhere, and even then it says "cannot convert from int to boolean".  I then try putting  =  1 at the end, and the error changes to "the left-hand side of an assignment must be a variable".

    EntityHorse#getHorseType() is not valid Java code (which you should know, since you know Java, right? Right?)

    Apparently not...  :o

     

    OP, the drop Event has the entity instance in it already. You cannot literally type 'EntityHorse.' and expect magic to happen - as diesieben said, it is NOT a static method.

     

    Get the entity from the event, check if that entity is an instanceof EntityHorse, and then cast the entity to EntityHorse to access the method. If you don't know what any of those terms mean, Google them.

  16. I don't think Techne supports exporting as JSON, but if it does, you would only be able to use those in 1.8 for Blocks and Items - anything else and any prior version you have to use a .java file, be it a model or a custom render class that makes OpenGL calls directly (which is more difficult than just using the generated model file).

     

    Why don't you want to use a .java file?

  17. 1. Are you using Entity#ticksExisted anywhere to control your animation? If so, that value starts at 0 for all entities every time the world loads, so if you spawn a bunch, quit, then start again, they will all be synchronized. If that is the case, you can either do a hack such as adding a (small) random amount to their ticksExisted each time they are constructed on the client, or use some other field for your animation timer.

     

    2. If you want smooth animations, you need to use partial ticks (the last float parameter of the method, I believe) and interpolate the rotation values between what it started at and what it should end at * partialTicks (a value that increases from 0 to 1 each tick; render ticks may be happen multiple times per regular tick depending on how fast the client side processes rendering).

  18. If you want your structure to 'meld' better into the surrounding environment, one trick is to allow certain blocks to not be placed if there is already a block there.

     

    The major example is air blocks - if you can avoid overwriting huge sections of the land with air blocks, i.e. leave the land as it is, that's a big win as far as looks go.

     

    Another example is your stone steps, especially toward the lower levels - instead of forcing the stone steps to go all the way down, you could place them instead only if there isn't already a solid block there. This way they only go down as far as they need to.

     

    Other than that, it's looking pretty good.

  19. Assuming that x, y, and z are the coordinates for the floor-level northwestern corner of your structure then yes, that code should check all of the blocks. As jeffryfisher pointed out, however, it might be wiser to make a function to handle the check, e.g. instead of:

    if (!world.getBlockState(new BlockPos(i, j, k)).getBlock() == Blocks.air) {
    return false;
    }
    

    You would put:

    if (!myIsBlockValidMethod(world, new BlockPos(i, j, k))) {
            return false;
    }
    

    Then you can add as much complexity as you want to the block check within that method without a. having all the code indented 5 times and b. making a huge mess in the for-loop. Of course, it probably will not have any functional benefit for you, but it is cleaner stylistically.

     

    On another note, you have some weird / incorrect syntax:

    if (!world.getBlockState(new BlockPos(i, j, k)).getBlock() == Blocks.air) {
    
    // the not '!' should go with the '=', not in front of the method, as the method does not return true/false
    if (world.getBlockState(new BlockPos(i, j, k)).getBlock() != Blocks.air) {
    

×
×
  • Create New...

Important Information

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