-
Posts
1773 -
Joined
-
Last visited
-
Days Won
61
Everything posted by V0idWa1k3r
-
1.12.2 - Info bar above inventory bar completely artifacted
V0idWa1k3r replied to Frontear's topic in Modder Support
RenderGameOverlayEvent gets called once per HUD element. It is called once for health, once for hunger, once for experience, etc. It is additionally called twice with Pre and Post subclasses. You need to Subscribe to either Pre or Post instead of the parent event class Check whether the HUD type the event is fired for is the desired for your case. Otherwise you are drawing your text many times over which is not good for performance. As for the "artifacting" issue: When the game renders the HUD it binds the HUD texture once before drawing it. Rendering any text however binds a corresponding font texture. Since you are rendering in the middle of HUD rendering the font texture stays bound and is used to draw the rest of the HUD which leads to incorrect things being drawn. You need to either draw before/after all the HUD or rebind the HUD texture back. -
[1.12.2] Blocks and Items won't show in creative tab
V0idWa1k3r replied to JimiIT92's topic in Modder Support
public static final Item RUBY = new ItemMW(); public static final Item SAPPHIRE = new ItemMW(); public static final Item BRONZE_INGOT = new ItemMW(); public static final Item COPPER_INGOT = new ItemMW(); public static final Item SILVER_INGOT = new ItemMW(); public static final Item ALUMINIUM_INGOT = new ItemMW(); public static final Item PYRITE = new ItemMW(); 2 words - static initializers. When the items are instantinated the creative tab is still null and thus they get assigned a null creative tab. Yet another reason to not use static initializers. Instantinate your stuff in the registry event directly. This reason is absolute nonesense. Consider this way of instantinating your stuff: public static Item item1; public static Item item2; ... @SubscribeEvent public static void onRegistry(Register<Item> event) { event.register(item1 = new Item1()); event.register(item2 = new Item2()); ... } This takes the same amount of effort as your reflection stuff. Or even better - just add your items to some kind of a list you can iterate later to register models, if an item is complex don't add it to the list but handle it separately with a similar approach shown in my example above and if you need a reference to the item either store it in the static field or use ObjectHolders. This is probably the worst way to handle exceptions in cases like this one. You spit out a warning and continue as usual if you are dealing with something that can easily break on you like networking. In pretty much any other case you need to handle the exception by crashing your application. Especially in this case here - if something goes wrong with your reflection here then anything can go wrong later. Just crash the game if an impossible exception occurs. -
[1.12.2] [SOLVED] spawnParticle not working
V0idWa1k3r replied to dalobstah's topic in Modder Support
You either need the data to be consistent for the client with DataParameter variables or use packets. -
[1.12.2] [SOLVED] spawnParticle not working
V0idWa1k3r replied to dalobstah's topic in Modder Support
Particles are a client-side thing. Calling the spawn particle method on the server does nothing. You also do not need a proxy to spawn a particle. The spawning method is present on both sides, but only the client actually does something, the server has a noop implementation. Blocks spawn particle in a special method Block#randomDisplayTick that is called on the client only. If you need to spawn particles for every player either make sure that the data for those players stays consistent so their clients are aware of when to spawn particles or use packets. -
[1.12.2] Rending entity in GUI + exporting it to PNG?
V0idWa1k3r replied to Kinniken's topic in Modder Support
Okay, I normally do not provide people with ready-to-use code because it is my firm belief that people need to learn how to code themselves, not use ready solutions. However this might be a special case because it requires a descent OpenGL knowledge that you might not be willing to learn because you don't really need it in minecraft modding or even usual java programming. It is also quite difficult to understand out of the box if you've never worked with it before. So I will deviate from my usual ideas and provide you with some code that will be commented so you have an understanding of what's going on and can actually learn something from it. // Define the width and the height of the framebuffer, the texture and as a result the final png file. int width = 256; int height = 256; // Get the framebuffer object that was already in use since we have to restore the state when we are done Framebuffer fbo = Minecraft.getMinecraft().getFramebuffer(); // Create a new framebuffer object with the width and the height defined. The last parameter defines whether to use depth or not. Framebuffer framebuffer = new Framebuffer(width, height, true); // Bind the created framebuffer as the active framebuffer. The last parameter also adjusts the viewport to the dimensions of our framebuffer. framebuffer.bindFramebuffer(true); // These are not really needed, however I prefer do draw over black. By default the texture would be white. GlStateManager.clearColor(0, 0, 0, 1); // No need to clear depth/stencil since those are clean as is since nothing has been drawn yet. GlStateManager.clear(GL11.GL_COLOR_BUFFER_BIT); // Draw the actual entity. You might want to play with positions and scaling. GuiInventory.drawEntityOnScreen(200, 200, 100, 0, 0, new EntitySheep(Minecraft.getMinecraft().world)); // Alternatively if the GL matrix isn't as desired: /* GlStateManager.pushMatrix(); // Do matrix manipulations - scaling, translating, rotating. GuiInventory.drawEntityOnScreen(200, 200, 100, 0, 0, new EntitySheep(Minecraft.getMinecraft().world)); GlStateManager.popMatrix(); */ // Allocate a buffer for GL to dump pixels into. IntBuffer pixels = BufferUtils.createIntBuffer(width * height); // Bind the framebuffer's texture. GlStateManager.bindTexture(framebuffer.framebufferTexture); // Dump the pixels onto the IntBuffer. Note that the pixel format is BGRA and the pixel type is 8 bits per color. GlStateManager.glGetTexImage(GL11.GL_TEXTURE_2D, 0, GL12.GL_BGRA, GL12.GL_UNSIGNED_INT_8_8_8_8_REV, pixels); // Allocate the array to hold pixel values. int[] vals = new int[width * height]; // Copy the buffer to the array. pixels.get(vals); // Rearrange pixel values to correct positions so they can be read by the BufferedImage correctly. TextureUtil.processPixelValues(vals, width, height); // Create the BufferedImage object. BufferedImage bufferedimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // Copy the pixels from the array onto the BufferedImage. bufferedimage.setRGB(0, 0, width, height, vals, 0, width); // Create a file to store the image within. Here the file will be outputted to the game's base directory with a name of img.png. File f = new File(Minecraft.getMinecraft().mcDataDir, "img.png"); f.createNewFile(); // Finally write the buffered image into the file. ImageIO.write(bufferedimage, "png", f); // Delete the framebuffer from memory. It is no longer needed. framebuffer.deleteFramebuffer(); // If the game had a buffer bound. In most cases it did but who knows what could be the case with mods and such. if (fbo != null) { // Restore the original framebuffer. The parameter set to true also restores the viewport. fbo.bindFramebuffer(true); } else { // If the game didn't have a framebuffer bound we need to restore the default one. It's ID is always 0. GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, 0); // We also need to restore the viewport back in this case. GL11.glViewport(0, 0, Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight); } And here is the resulting image: Note that you must do all this in a thread that is the main render thread! -
[1.12.2] Rending entity in GUI + exporting it to PNG?
V0idWa1k3r replied to Kinniken's topic in Modder Support
Do you mean the same way the player is rendered in their inventory screen? Use GuiInventory#drawEntityOnScreen. A render of what? The entity? The GUI? The screen? If it's the screen then you can do the same thing the game does when taking screenshots. Otherwise you would need to create a framebuffer, bind a texture as a render output to that, bind that framebuffer, render your stuff, get the texture from that framebuffer, read that texture into a BufferedImage and save it to a file. You can see how vanilla does the last 3 actions in ScreenShotHelper.createScreenshot, but everything else you would have to do yourself since the game never does anything similar. Feel free to ask for help though. -
Use an interface instead. Like IProxy or something. You can use registerAll if you want. Just don't have your blocks/items/whatever instantinated in a static initializers static BlockMetallicSyphon blockmetallicsyphon = new BlockMetallicSyphon(); static BlockTestContainer blocktestcontainer = new BlockTestContainer(); ^ This is wrong. Instantinate your registry entries directly in the registry event. detectAndSendChanges is a server-side method that compares the fields in the TE to the fields in the Container checking whether the fields in the TE were changed. If they were it sends the changed data to all listeners together with an index for that data. updateProgressBar is the client-side method that receives the data and the index and is responsible for setting the fields in the client TE with the new server data.
-
You can check your git repository yourself, there is really no need to be asking us whether everything is okay. CommonProxy is still there. And blocks/items are still instantinated in static initializers. But you don't have to. set/getField are just getting/setting values of various fields. You can instead simply access the fields directly, without these getters. You are not implementing IInventory anyway, why mirror it's concepts?
-
When you override the method the access level stays the same as it was on the original method by default(with automatic overriding). There is usually no reason for subclasses to expose the method so it stays with the original access level. Especially if the method is considered not public API/internal. And since minecraft doesn't really consider mods there is no need to expose anything beyound the places where the base game needs it. Same reasoning goes for other mods - they won't expect their subclasses to be referenced by anyone else either, especially if they are not a part of the API of the mod. So as D7 said you will likely be breaking any mod that subclasses CompiledChunk. You might want to consider a PR instead. Or just use reflection.
-
Can't create basic project to modding
V0idWa1k3r replied to DevilRiseAgain's topic in Modder Support
So... you ran the gradlew task and then extracted a fresh MDK into your project folder? That seems incorrect... Also you do not need to run gradle with no tasks. Try doing this: Download and extract MDK into a folder. Open IntelliJ Click File -> Open Navigate to your folder and click OK. Click OK in the popup dialog, making sure that "Create separate module per source set" is selected. Wait for Build: Sync to finish. Mouse over a square icon in the bottom left of IDEA and select Gradle from the dropdown. Open Tasks -> forgegradle. Double-click on setupDecompWorkspace Wait for the process to be done. Optionally run genIntellijRuns. If you don't run this you will need to create the run configurations yourself. Main classes are GradleStart and GradleStartServer. After the tasks are done click Refresh all Gradle projects button(looks like 2 circular arrows in the top right, next to the + and - signs) Now you can start modding. Do not move any files/folders around! This sets up the workspace in the folder where you extracted the MDK. -
Can't create basic project to modding
V0idWa1k3r replied to DevilRiseAgain's topic in Modder Support
We do not support jar mods here. Either that or you are extremely confused as to how mods work in general. Normal mods do not edit the game's base code and they certainly don't redistribute recompiled minecraft classes. Could you tell us step-by-step what have you done so far to try and get a working workspace? -
These methods are a way to serialize/deserialize blockstate properties to a metadata. Metadata can only go as high as 15(4 bits). So if you needed to store the facing + whether the block is "active" you would store the facing in the first 3 bits(6 possible variants) and use the last bit as a boolean for the active property. 1 111 ^ ^ isActive facing Then you can read the facing as EnumFacing.values[meta & 7(0111)] and the active as meta & 8 == 8 and write them as facing.ordinal | (isActive ? 8 : 0); The issue with your current setus is that while you are reading the facing value you are blindly setting the active value to false, this is what I mean by incompatible - you do not restore to the same state you saved as, you loose the active property. Well first of all you are setting the state twice for no apparent reason considering that it is the same in both cases. Why do the same operation twice in a row like that? And secondly I mostly meant the whole tileentity nonesense. You do not need to validate and set the tile entity. Just override the method in TileEntity I told you about and you are good. Because the Container doesn't need to sync anything, it is a base class for things. Look at ContainerFurnace for example of usage. Unless you haven't updated your git yet no, it is very much still there. And it needs to be gone completely. Unless you are using extremely outdated forge or minecraft the resourcelocation method is there and the other one is explicitly marked as deprecated and not to be used.
-
public class ReflectionTest { static int ctr = 0; static int op = 0; public static void foo() { ++ctr; int a = (int) Math.max(1, Math.sqrt(ctr)); op = (int) Math.pow(a, 3); } }
-
I wasn't really able to get a consistent result, but here are the averages of 10 runs of code that does 10000000 operations with direct access to a method VS a reflection invocation of a method: Direct: Took 15ms, avg 1.5E-5ms per operation. Reflection: Took 25ms, avg 2.5E-5ms per operation. I don't think the JIT optimizations were a thing either in a debug environment. Here is the benchmark code: private static Method foo; public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { foo = ReflectionTest.class.getDeclaredMethod("foo"); foo.setAccessible(true); long currentTimeMillis = System.currentTimeMillis(); for (int i = 0; i < 10000000; ++i) { ReflectionTest.foo(); } long diff = System.currentTimeMillis() - currentTimeMillis; System.out.println("Direct: Took " + diff + "ms, avg " + (float)diff / 1000000F + "ms per operation."); currentTimeMillis = System.currentTimeMillis(); for (int i = 0; i < 10000000; ++i) { foo.invoke(null, null); } diff = System.currentTimeMillis() - currentTimeMillis; System.out.println("Reflection: Took " + diff + "ms, avg " + (float)diff / 1000000F + "ms per operation."); }
-
There are a lot of isRemote checks in your code like this one if (this.world.isRemote) However this check ensures that whatever happens afterwards happens on the client and not on the server. As the server is the driving logic this makes sure nothing actually happens, only the client sees something changed. Untill the server is forced to sync the items to the client that is. This is the reason for In your deserialization method: this.currentBurnTime = getItemBurnTime((ItemStack)this.handler.getStackInSlot(2)); What if the fuel is consumed completely and the itemstack left in the slot 2 is an empty itemstack? Then when deserializing the fuel will be set to 0, even though there might have been some left. compound.setInteger("BurnTime", (short)this.burnTime); compound.setInteger("CookTime", (short)this.cookTime); compound.setInteger("CookTimeTotal", (short)this.totalCookTime); Any reason you are storing these as integers(4 bytes) yet casting them to shorts beforehand(2 bytes)? Define "isn't saving as it should". What is wrong? Why are you using get/setField methods? They are a horrible abomination of IInventory. Don't have them, access the fields directly. implements ITileEntityProvider Don't. Just override Block#hasTileEntity and Block#createTileEntity. this.setRegistryName("blockmetallicsyphon"); Your registry name should be prefixed with your modid. @SideOnly(Side.CLIENT) public void initModel() IHasModel and it's substitutes are stupid. All items need models and there is nothing about model registration that requires access to something private/protected in your block/item classes. Register your models in the model registry event, not in your block/item classes. Instead of setting the state for rotation in Block#onBlockAdded or Block#onBlockPlacedBy just return the state you want in Block#getStateForPlacement. Your getMetaFromState and getStateFromMeta are not compatible. The data that is read isn't the one that is being written. Instead of the weird TE manipulations done in your setState method just override TileEntity#shouldRefresh to not change the TE when the blockstate property changes. ItemBase/BlockBase is an antipattern. You do not need it. static BlockMetallicSyphon blockmetallicsyphon = new BlockMetallicSyphon(); static BlockTestContainer blocktestcontainer = new BlockTestContainer(); Don't ever use static initializers for IForgeRegistryEntry. Instantinate your stuff directly in the appropriate RegistryEvent. You never actually sync the data in your container implementation. You just tell the server that it needs to be synced yet you never do anything when the data arrives on the client. You are missing the Container#updateProgressBar method. IItemHandler itemHandler = this.te.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, null); Any reason you are doing a capability lookup instead of just accessing your ItemStackHandler field? CommonProxy makes no sense. Proxies are classes that are supposed to separate sided code. If your code is common it goes into your main mod class, not into a proxy. This is me nitpicking but in java you usually prefix something with an I if it is an interface, not a class. GameRegistry.registerTileEntity(TileEntityMetallicSyphon.class, Index.MODID + "_metallicsyphoncontainerblock"); Don't use methods that are ~1.5 years outdated. Use the version that takes a ResourceLocation as it's second argument.
-
Have your random chance happen in the event. Add a new ItemStack to the list that is your nuggets with a count of 1 - 3 based on random number, then check against a random value and if it is within the range you want add an Iron ingot. drops.add(new ItemStack(Items.IRON_NUGGET, 1 + rand.nextInt(2), 0)); if (rand.nextFloat() <= 0.1F) { drops.add(new ItemStack(Items.IRON_INGOT, 1, 0)); }
-
This is not true. BlockEvent.HarvestDropsEvent has a List<ItemStack> that contains all drops. You can access the list with HarvestDropsEvent#getDrops. You can then modify the list's contents as you want.
-
Entity class to spawn, weight, min spawned, max spawned.
-
Why did you commit compiled class files to github? You do realize we can't open them and look at your code right? Git is where you upload your sources, not your compiled application. As a side note - that is not how you setup a minecraft mod repository. The root directory must be your workspace directory.
-
[1.12.2] Random damage for sword every time it's crafted
V0idWa1k3r replied to Jiro7's topic in Modder Support
You need to store the additional value to your ItemStack's NBT data or a capability, then override Item#getAttributeModifiers and make the damage attribute add the itemDamage + yourDamage as the modifier. See how ItemSword does that. Edit: Thanks for @Animefan8888 for correcting my mistake, whoops, had ItemStack written as the base class instead of Item. -
Add splash texts to main menu (without overwriting existing?)
V0idWa1k3r replied to Insane96MCP's topic in Modder Support
Unfortunately splash texts are a normal resource meaning you can only replace it, not add new entries. The only resource you can add entries to are lang files since they are merged after being collected. Any other resource is just replaced by the one supplied by the last resource pack to be loaded. The best you can do is use the GuiOpenEvent, detect the GuiMainMenu, read the splash text yourself, collect a list of entries, then do a random.nextInt(list.size) == 0 and if it is true change the value of GuiMainMenu.splashText -
This is happening because java doesn't allow overrides to lower the access level of the overriden method. If the method in class A is public, then class B that extends A and overrides the method must also have that method as public, not protected or private. In your case you are making This as public but look at public static final CompiledChunk DUMMY = new CompiledChunk() { //LINE 17 - THIS DOESNT APPEAR TO BE BEING MADE PUBLIC protected void setLayerUsed(BlockRenderLayer layer) { throw new UnsupportedOperationException(); } public void setLayerStarted(BlockRenderLayer layer) { throw new UnsupportedOperationException(); } public boolean isVisible(EnumFacing facing, EnumFacing facing2) { return false; } }; In this class. It overrides the method and has it as protected which isn't allowed in java. You need to change this method as well. Try to also add this inner class to the AT as net.minecraft.client.renderer.chunk.CompiledChunk$1. This may or may not work. If it doesn't revert to your field tactic. Or use reflection. It is not that bad. Method lookups and changing the access levels are expensive with reflection. Simply invoking a cached method that already had it's access level set to accessible isn't.
-
This is a pretty good way to sync the config values. The only problem with this approach is that when the player leaves the server it's config values will still be the server's so I would also keep a backup copy before accepting server configs and revert to it when the player disconnects. You could iterate the properties in the config, write their values to the buffer prefixing everything with the size of the property map, then read them as raw byte arrays as long as there is something to read from the buffer, then recreate the values in the handler from the byte arrays. This approach is however worse than the one you are using since It assumes that all values in the config are 4-byte values(but there are ways around that but that makes the packet way longer and thus adds even more data to be transferred to the client when they log in) It will not work well if the config versions differ from client to server(a new mod version or something) but to be fair your current approach won't work either and again there are ways around that but again that would make the packet even longer.
-
[1.12.2] Properly registering dimension biomes
V0idWa1k3r replied to Dizzlepop12's topic in Modder Support
Yes they do get registered. That is the whole purpose of the registry event. They just don't generate. There is a difference. A registered object doesn't necessairly need to appear in the game at all. Also as @Cadiboo said instantinate your biomes in the event too. BiomeManager.addBiome(biomeType, new BiomeEntry(biome, 10)); BiomeManager.addSpawnBiome(biome); This is why your biomes were spawning in the first place. This adds the biome to the biome entry list that the biomes will get pulled from. The second line allows the player's spawn biome to be yours. To have your biome spawn in your dimension you need to change the BiomeProvider in your WorldProvider and make that BiomeProvider have your biome as a possible biome to spawn. See WorldProviderEnd#init for an example of a single biome per dimension that only generates in that dimension or look at BiomeProvider itself to see how it keeps an array of biomes that can be generated. -
This will fire each time a HUD element is drawn. Once for health, once for hunger, once for experience, etc. You need to check the current element being drawn with RenderGameOverlayEvent#getType. Otherwise you will be drawing your text many times per frame. Also I don't believe RenderGameOverlayEvent itself is ever thrown. It's either Pre, Post or another child of that class. You probably need to handle one of the children events instead. This wouldn't even compile. Minecraft.fontRenderer is not static. Actually speaking of this, fontRendererObj got renamed to fontRenderer a while back. What version are you using exactly?