jabelar
Members-
Posts
3266 -
Joined
-
Last visited
-
Days Won
39
Everything posted by jabelar
-
Yeah, I am not aware of anything much changing for 1.8 with respect to GUIs, or even items (except for the JSON model stuff). What are you trying to do -- just open a GUI when an item is used by the player?
-
Okay, I made it as fast as I could -- I used actual blocks instead of strings (I converted the array from strings to blocks before I tried the generation), I removed all testing for special cases, and did 11000 blocks in one pass. It still takes about 40 seconds. In fact it didn't really improve on looking up from strings or my original implementation. Here is the console output showing the duration (console statements generally can slow things down so I just output every 500 blocks placed: My code is simply this: for (int index = 0; index < numSparseElements; index++) { // DEBUG if (index % 500 == 0) System.out.println("Index = "+index); theWorld.setBlock(startX+theSparseArray[index].posX, startY+theSparseArray[index].posY, startZ+theSparseArray[index].posZ, theSparseArray[index].theBlock, theSparseArray[index].theMetaData, 2); } And I'm holding the block and position in an array of a custom class: public class StructureSparseArrayElement { public Block theBlock; public int theMetaData; public int posX; public int posY; public int posZ; public StructureSparseArrayElement(Block parBlock, int parMetaData, int parX, int parY, int parZ) { theBlock = parBlock; theMetaData = parMetaData; posX = parX; posY = parY; posZ = parZ; } } So that should be about as efficient as I can imagine. One dimensional array containing actual block, metadata and position, and just setting that. Anyway, it works well enough I guess. Just one of the charms of Minecraft -- that new block rendering into view is fairly laggy.
-
I find that some meta blocks won't place right if there isn't already the basic blocks. Like placing a torch wants to have a wall already. I actually do a third pass as well for things like tripwire. If you place tripwire before the block under it then it ends up as a entity item not placed block. And if I break up the generation over multiple ticks you especially have to worry about order of placement -- for example placing a lava flow block without a source might drain before you place the source several ticks later.
-
Thanks. Yeah, basically I'm working on what you said above. Each tick I'm only doing one y-layer. It doesn't seem to really change overall generation time but it makes the generation seem a bit more managed -- client gets to see it grow up. And like you said, I'm looking at pre-converting the strings to a temporary map. Although I ran a test where instead of looking up any blocks I just placed sandstone. Still took a long time.
-
This is not during world-gen. I want structure to appear during gameplay based on an item's use. It's not premature optimization -- I have a simple structure that is freezing the game for many seconds. It is 46 x 30 x 24. It is stored in a string array (name of block) plus an int array (metadata). It simply loops through the dimensions, takes the array and sets the block using Block.getBlockFromName() using the string from the array. I do two passes through because some metadata blocks need to be placed after basic blocks. The just do a few checks (they don't look onerous) in the inner loop is I check for tripwire (just by looking at string from my array) since that needs to be generated after other blocks or it ends up as entity item, I check for dirt (just by looking at string) to allow replacement with a custom block, and I check for lava because I found that if I don't convert all lava to lava source blocks the delay in generation can allow it to flow before structure completes. Lastly I also check if block has a tile entity and create that if necessary (there are only a few in the structure I'm currently trying). Here's the main code for the generation loops: for (int indY = 0; indY < dimY; indY++) { for (int indX = 0; indX < dimX; indX++) { for (int indZ = 0; indZ < dimZ; indZ++) { if (blockMetaArray[indX][indY][indZ]==0) // check for basic block { String blockName = blockNameArray[indX][indY][indZ]; if (!(blockName.equals("minecraft:tripwire"))) // tripwire/string needs to be placed after other blocks { if (blockName.equals("minecraft:dirt") || blockName.equals("minecraft:grass")) { theWorld.setBlock(startX+indX, startY+indY, startZ+indZ, MagicBeans.blockCloud, 0, 2); } else if (!(theWorld.getBlock(startX+indX, startY+indY, startZ+indZ) instanceof BlockMagicBeanStalk)) { theWorld.setBlock(startX+indX, startY+indY, startZ+indZ, Block.getBlockFromName(blockName), 0, 2); } } } } } } for (int indY = 0; indY < dimY; indY++) { for (int indX = 0; indX < dimX; indX++) { for (int indZ = 0; indZ < dimZ; indZ++) { if (!(blockMetaArray[indX][indY][indZ]==0)) { Block theBlock = Block.getBlockFromName(blockNameArray[indX][indY][indZ]); int theMetadata = blockMetaArray[indX][indY][indZ]; if (theBlock == Blocks.lava) // in Jaden's castle there was issue with lava so making them all sources { theMetadata = 0; } theWorld.setBlock(startX+indX, startY+indY, startZ+indZ, theBlock, theMetadata, 2); if (theBlock.hasTileEntity(theMetadata)) { customizeTileEntity(theBlock, theMetadata, startX+indX, startY+indY, startZ+indZ); } } } } } } This takes about 50 seconds to generate on a very good gaming computer (Intel i5, 16GB RAM, solild state drive and GTX780 graphics). Is one of the methods I'm using slow? Is the problem that I'm using flag 2 in the set block method -- is this creating unnecessary overhead of trying to sync the client block by block? Should I generate them all without update and then update the chunks after block placement is complete? Or is it because I'm looking up the blocks using strings, is that too slow?
-
If one has code that generates a lot of blocks (e.g. custom structure) Minecraft will understandably start to lag. And even a "small" structure can have a lot of blocks -- 20 x 20 x 20 = 8000! I can break up the structure into small parts, but how small is recommended? To continue the example, if you need to place 8000 blocks and do it 20 at a time it would take 400 ticks which is 20 seconds -- kinda slow. I guess it also depends on the computer's processing power, and I haven't timed it but I suspect that some Forge versions are faster than others in block set speed. I'm going to play around with it, but just wondering if there is a consensus on what is good limit. One other question, when the console complains about ticks taking too long and then says it skips ticks -- what does that mean exactly? Does it simply add to the tick counter, or is it actually short-cutting other code execution in some way?
-
I think the getStateFromMeta() method looks suspicious to me -- a little too clever. I understand what he's trying to do, but why not just set the properties one by one? I wonder what happens if it doesn't match the states in your JSON -- it might default to the model name it is trying to access. That is why I would confirm that your state actually matches an entry in the blockstates. Lastly, is the JSON case-sensitive? because your enum properties are all caps but are lower case in the JSON.
-
[1.7.10] Player hitbox and hit mechanics - how to change stuff
jabelar replied to Thornack's topic in Modder Support
Thanks for the feedback. Regarding the variable names, I have been going through the code to rename them but it is copied mostly from the vanilla getMouseOver and frankly a few of the things it is doing aren't quite clear to me. But yeah, I'll make it more readable if I can. Regarding the ByteBufUtils, I like to let people know about that class because it helps with more complicated messages including NBT and stuff. But I'll explain it better. Moving to the input event is good idea. I started with the other mod's code and they had it in player tick so I didn't think to move it, but it makes sense. Thanks again, as always! -
[1.7.10] Player hitbox and hit mechanics - how to change stuff
jabelar replied to Thornack's topic in Modder Support
Okay, I checked it all with dedicated server and it works well. I've updated my tutorial -- I'd appreciate your reviews: http://jabelarminecraft.blogspot.com/p/minecraft-modding-extending-reach-of.html I think this could be a good approach for a gun mod, rather than creating invisible projectiles. The targeting seems quite precise -- could pick off entities that were mostly hidden by blocks. -
[1.7.10] Player hitbox and hit mechanics - how to change stuff
jabelar replied to Thornack's topic in Modder Support
Okay, with custom packet it seems to work like a charm. I was sniping pigs from 30 blocks away with a "sword". I'm going to bed now, but will update the tutorial tomorrow and maybe you can give it a review. You're right I should prevent hacking by double-checking the range on the server side, as right now I basically created a "kill any entity" packet. Should be easy fix. -
[1.7.10] Player hitbox and hit mechanics - how to change stuff
jabelar replied to Thornack's topic in Modder Support
Okay, it does look like the entity attack packet processing limits the distance (to 6), here's the code: public void processUseEntity(C02PacketUseEntity p_147340_1_) { WorldServer worldserver = this.serverController.worldServerForDimension(this.playerEntity.dimension); Entity entity = p_147340_1_.func_149564_a(worldserver); this.playerEntity.func_143004_u(); if (entity != null) { boolean flag = this.playerEntity.canEntityBeSeen(entity); double d0 = 36.0D; if (!flag) { d0 = 9.0D; } if (this.playerEntity.getDistanceSqToEntity(entity) < d0) { if (p_147340_1_.func_149565_c() == C02PacketUseEntity.Action.INTERACT) { this.playerEntity.interactWith(entity); } else if (p_147340_1_.func_149565_c() == C02PacketUseEntity.Action.ATTACK) { if (entity instanceof EntityItem || entity instanceof EntityXPOrb || entity instanceof EntityArrow || entity == this.playerEntity) { this.kickPlayerFromServer("Attempting to attack an invalid entity"); this.serverController.logWarning("Player " + this.playerEntity.getCommandSenderName() + " tried to attack an invalid entity"); return; } this.playerEntity.attackTargetEntityWithCurrentItem(entity); } } } } You can see that the distance squared needs to be less than or equal to 36 if you can see the entity. Okay, going to make a custom packet. -
[1.7.10] Player hitbox and hit mechanics - how to change stuff
jabelar replied to Thornack's topic in Modder Support
I understand what you're saying, but there is still something weird (or at least that I don't understand). I understand your point about some classes that are client side only being available in integrated server but crashing on dedicated server. But like you said my original intention was to process the mouse over on client side and use the built in attack packet to tell server. That fails though and I suspect it is due to something verifying whether it is a valid attack -- although I traced the code for a ways and couldn't see where (in the built-in mouseOver method it clearly limits the reach though, but I don't think that would be called again). I think that the FMLClientHandler.instance().getClient() doesn't crash the server side so I think that is where some of my confusion was coming from -- I think it actually was running the server code on the client world!, which I guess is possible in integrated server? Okay, I returned to the original idea -- run player tick on isRemote only and use the player controller attack method to send the vanilla attack packet. Here is my code: The MovingObjectPosition works because the console statements show the detection of the entity (or not) and also the entity will do a hurt animation (turn red and kick its legs) when hit. However, the attack is only processed client side which is obvious since the entity doesn't die but I also created a test entity and put a console statement in the attackEntityFrom() method and that is only getting called client side. So the packet never seems to initiate an attack on server side...I'm going to trace that code, and also probably try making a custom packet. I'm glad you're responding though -- maybe try it out yourself if you're inclined. I'm sure it is something simple. -
[1.7.10] Player hitbox and hit mechanics - how to change stuff
jabelar replied to Thornack's topic in Modder Support
I'm using FMLClientHandler.getClient() because that is what the vanilla EntityRenderer getMouseOver() code uses which I essentially copied. I actually tried Minecraft.getMinecraft() and other variations as well. Also tried a lot of variations on the attack. Tried player attack with item, entity attack as mob, target entity attack from, etc. The interesting thing is that I'm getting the entity fine, so the moving object position isn't the problem. But the attack doesn't process. Then like I said, just to confirm that something could be done I tried setDead() and it does kill (well makes it disappear without any drops) the entity from a distance. Conceptually, I think it should work: I should be able to only process on client side and then send attack packet. However, as Ernio says, that seems like it potentially would be a hacking opportunity so it seems reasonable that the server might override any attacks that fall outside normal distance. I'm sure it is something simple. I think I'm going to add a custom entity so I can do more tracing of what is happening. -
I must be missing something. In a PlayerTickEvent handler I'm setting an entity to dead with a setDead(). It dies (disappears from game) but if I save game and load the entity comes back. I've tried setDead() on server side, and on both sides, to same effect. What am I missing? EDIT: Solved. The world I was using was from FMLClientHandler.getClient() which doesn't fail on an integrated server. So I guess the server side was actually operating on the client world...
-
[1.7.10] Player hitbox and hit mechanics - how to change stuff
jabelar replied to Thornack's topic in Modder Support
Okay, I looked at it some more. The following code can definitely detect entities at a distance on both client and server: I have console statements in the code and if I run it and try to hit an entity 20 blocks away (I set reach to 20 in the item I'm using) multiple times the console shows: You can see that both client and server identify the pig. When I click elsewhere it shows null, and if I click on other pigs it shows different ID. However, the attack doesn't seem to be actually processed. You can see I tried the attack in different ways (look at the commented out versions). I followed the code for each method and can't find anywhere it is specifcally deciding not to do the full attack. Interestingly, if I use mov.entityHit.setDead(); I can instant kill the pigs from a distance, but even if I do a !worldObj.isRemote check (to confirm only server side), the kill isn't persistent -- if I save then load the pig reappears. Why would that happen? So if anyone can tell me what the proper attack method to call would be, it should all work. I guess I'll try using custom packet. -
[1.7.10] Player hitbox and hit mechanics - how to change stuff
jabelar replied to Thornack's topic in Modder Support
Yeah, I noticed the dead code myself today -- result of simplifying a previously more complex if-else-if construct. I'm not sure what you mean by "BWM"? But player tick runs on both, right? I put console statements in and see it running on both... I have been looking through the EntityRenderer code for getMouseOver() and it does limit the reach (it calls "extended reach" by checking creative mode is on). I think the flaw in my current code is that ray trace actually doesn't return an entity, so isn't doing anything. To get entity I believe is why getMouseOver() goes through a bunch of trouble to create a bounding box around the vector and checking for entities with and such. -
[1.7.10] Player hitbox and hit mechanics - how to change stuff
jabelar replied to Thornack's topic in Modder Support
Hmmm, actually I'm not sure it is working at really. I need to do more testing. Let me debug it this weekend. -
[1.7.10] Player hitbox and hit mechanics - how to change stuff
jabelar replied to Thornack's topic in Modder Support
I'm not doing it in a "client event", but rather PlayerTick which I believe runs on both sides? I've only tested it on integrated server single player, so I'll try it on separate server to see if there are issues. And the attack is run through the FMLClientHandler which I suppose helps manage the sync. I'm not that familiar with that. I haven't checked how far you can extend the reach, but the code basically uses ray trace so I think it would simply be limited by whatever that method can handle. -
First of all, you should learn to use your IDE (Eclipse or whatever) to help you. If you hover over the sendToServer() method it should tell you the parameter types needed, and that should give you a clue. It his case I think will tell you you need an IMessage. As mentioned above, you need to implement your own IMessage and message handler implementation. Now, in the message itself you actually get to choose what goes in. You create a "payload" using a ByteBuf that it is up to you what you put in and what order you put it in. But you have to make sure that the packet receiving method takes it out in same order.
-
[1.7.10] Player hitbox and hit mechanics - how to change stuff
jabelar replied to Thornack's topic in Modder Support
I tried it out and got it working. I made a quick tutorial for it here: http://jabelarminecraft.blogspot.com/p/minecraft-modding-extending-reach-of.html -
[1.7.10] Detect if player is looking at the sun.
jabelar replied to Tinker's topic in Modder Support
I personally wouldn't much math. I'd just simply record the rotation pitch and yaw of the player at set time intervals and look those up. Depending on the resolution/error allowed, you might only need like 24 data points. -
Okay, in 1.8 that function is called canBeHovered(). But the point then is that you need a custom slot then and the code in those methods would have to somehow get the information from the gui state, I guess via container then inventory?
-
Actually I saw your question -- you want to change textures dynamically. But the answer is the same, you have to change the property so that the block states JSON looks up a different model JSON (which can have different texture).
-
You can have the slot graphic portion exist separately from the background and draw it only when needed, like how the furnace draws the arrow filling up or the heat meter going down. Only instead of a progress bar, it'd be a yes/no type thing. No, the problem is that the slot is still there even if there is not graphic to show its position -- you could still place an item in that location for example, and if you hover over it there will be an indication that it is there. You'd have to deactivate or move the actual slot as well, not just the graphic for the slot.