Jump to content

jabelar

Members
  • Posts

    3266
  • Joined

  • Last visited

  • Days Won

    39

Everything posted by jabelar

  1. Yep, that is how its done. One other point, depending on the symmetry of your structure you might want to take different approaches regarding whether the rotations are handled "algorithmically" or "brute force". If you have a structure that is symmetric in both X and Z then obviously you have to only scan once since the shape is same in any rotation. If you have a structure otherwise you need to decide the best way to handle the rotation. The brute force way is to pre-compute the structure in each rotation (really four different structures) and check each with same logic as you outlined above. I generally recommend that way. But if the symmetry is simple you could choose to handle the rotation within the loop -- like when you detect the unique elements they would indicate the rotation and then you apply it. I've seen a lot of people work hard at getting rotation to work, and in the end I recommend just considering each rotation a separate structure and then have very simple checking. Not sure which situation applies to your structure.
  2. I don't have time at the moment to look at your code, but I would suspect it would be an issue with your BiomeProvider. Did you associate instances of BiomeProviderSingle to your dimensions and do they properly point to your custom biome?
  3. The key is to use loops with escapes (break and continue keywords in Java)-- your loops should give up as soon as they "know" there isn't a match. Secondly it is good to find the lack of match as early in the loop as possible, so if you can find unique parts (least likely to spawn naturally and/or uncommon to build) of the structure to check first that is helpful.
  4. As mentioned you are trying to call a client method. Just copy the code (and any further client-only code involved) into your own method. You'll also need to modify the part regarding the reach distance. Overall ray-tracing is pretty simple concept so you should be able to implement your own version.
  5. One of many ways: In Eclipse you can find the Event class (in net.minecraftforge.event) and look at the Type Hierarchy (you can get there by highlighting the class name and right-clicking and choosing Type Hierarchy). That should open a pane in the window that contains all classes that extend Event.
  6. Yeah, I'm continuing to track it down the code but it seems hard to do. Basically when every entity including vanilla is added to the world there is a call to track(), but that method does a "try" for tracking which seems to rely on it being registered as a mod entity. In other words it checks to see if a mod entity is registered for it. But it is weird because if you look at the code I posted in spoiler a few posts back, a fair number of vanilla things are given a tracker entry. But not all of them. If you look at the update packets like S17PacketEntityLookMove, or SPacketEntityVelocity, they are only called the EntityTracker class. So does that mean they are only sent for mod entities and not vanilla? It is very convoluted (at least to me). I'm traveling so don't have a computer (or time) to try to really trace through what's happening. I might later, but would be interesting if any of y'all could figure it out. In particular it would be interesting to print out the EntityTracker entries list to see if vanilla entities get in there somehow.
  7. Starting and Stopping Tracking A little more tracing of the code. In this case, this is the part that starts tracking or stops tracking. So MinecraftServer#tick() method calls MinecraftServer#updateTimeLightAndEntities() method every tick. That method firstly actually updates the entities on the server then calls WorldServer#getEntityTracker().tick() method. The EntityTracker#tick() method first creates a list of all EntityPlayerMP then loops through that list and takes all EntityTrackerEntry instances in the EntityTracker and calls updatePlayerEntity() while passing the EntityPlayerMP instance. So that makes sense -- every tick every multiplayer player gets opportunity to get info on every tracked entity. The updatePlayerEntity() method which is run on every entity for every multiplayer player firstly checks if the entity is visible (based on distance from the player) to the player and if not it removes the player from the tracking. If it is visible then and not already tracked it will start tracking. Tracking For Entity State Change It looks like a key method related to actually sending tracking updates is the WorldServer#setEntityState() method. That is called from a huge number of places in the code. In fact it looks like if you want to send a packet for your own custom entities, the proper way would be to call that method instead of "send to all" as it will only send to those players who are tracking (so should be less of a performance hit). Note that vanilla is a bit inconsistent in this regard as in some places it calls EntityTracker#sendToTracking() or sendToTrackingAndSelf() directly.
  8. Confirmed you're correct. The update frequency is used in only one place (line 191 in EntityTrackerEntry) where the code to decide to send update has the condition: if (this.updateCounter % this.updateFrequency == 0 || this.trackedEntity.isAirBorne || this.trackedEntity.getDataManager().isDirty()) Note the isAirBorne check. So I guess the idea is that projectiles are covered with that? To fully understand how things are updated, it seems most of the code is in the EntityTrackerEntry#updatePlayerList() method which has following code: One interesting thing is the EntityArrow is specially handled. Also Elytra flying is also specially handled.
  9. I think that is the opposite. "Frequency" means how often, so if you want more you would increase it. But I'm not entirely sure, let me check the code and I'll respond on the thread. Some of the special vanilla trackers are set as follows: public void track(Entity entityIn) { if (net.minecraftforge.fml.common.registry.EntityRegistry.instance().tryTrackingEntity(this, entityIn)) return; if (entityIn instanceof EntityPlayerMP) { this.track(entityIn, 512, 2); EntityPlayerMP entityplayermp = (EntityPlayerMP)entityIn; for (EntityTrackerEntry entitytrackerentry : this.entries) { if (entitytrackerentry.getTrackedEntity() != entityplayermp) { entitytrackerentry.updatePlayerEntity(entityplayermp); } } } else if (entityIn instanceof EntityFishHook) { this.track(entityIn, 64, 5, true); } else if (entityIn instanceof EntityArrow) { this.track(entityIn, 64, 20, false); } else if (entityIn instanceof EntitySmallFireball) { this.track(entityIn, 64, 10, false); } else if (entityIn instanceof EntityFireball) { this.track(entityIn, 64, 10, true); } else if (entityIn instanceof EntitySnowball) { this.track(entityIn, 64, 10, true); } else if (entityIn instanceof EntityLlamaSpit) { this.track(entityIn, 64, 10, false); } else if (entityIn instanceof EntityEnderPearl) { this.track(entityIn, 64, 10, true); } else if (entityIn instanceof EntityEnderEye) { this.track(entityIn, 64, 4, true); } else if (entityIn instanceof EntityEgg) { this.track(entityIn, 64, 10, true); } else if (entityIn instanceof EntityPotion) { this.track(entityIn, 64, 10, true); } else if (entityIn instanceof EntityExpBottle) { this.track(entityIn, 64, 10, true); } else if (entityIn instanceof EntityFireworkRocket) { this.track(entityIn, 64, 10, true); } else if (entityIn instanceof EntityItem) { this.track(entityIn, 64, 20, true); } else if (entityIn instanceof EntityMinecart) { this.track(entityIn, 80, 3, true); } else if (entityIn instanceof EntityBoat) { this.track(entityIn, 80, 3, true); } else if (entityIn instanceof EntitySquid) { this.track(entityIn, 64, 3, true); } else if (entityIn instanceof EntityWither) { this.track(entityIn, 80, 3, false); } else if (entityIn instanceof EntityShulkerBullet) { this.track(entityIn, 80, 3, true); } else if (entityIn instanceof EntityBat) { this.track(entityIn, 80, 3, false); } else if (entityIn instanceof EntityDragon) { this.track(entityIn, 160, 3, true); } else if (entityIn instanceof IAnimals) { this.track(entityIn, 80, 3, true); } else if (entityIn instanceof EntityTNTPrimed) { this.track(entityIn, 160, 10, true); } else if (entityIn instanceof EntityFallingBlock) { this.track(entityIn, 160, 20, true); } else if (entityIn instanceof EntityHanging) { this.track(entityIn, 160, Integer.MAX_VALUE, false); } else if (entityIn instanceof EntityArmorStand) { this.track(entityIn, 160, 3, true); } else if (entityIn instanceof EntityXPOrb) { this.track(entityIn, 160, 20, true); } else if (entityIn instanceof EntityAreaEffectCloud) { this.track(entityIn, 160, Integer.MAX_VALUE, true); } else if (entityIn instanceof EntityEnderCrystal) { this.track(entityIn, 256, Integer.MAX_VALUE, false); } else if (entityIn instanceof EntityEvokerFangs) { this.track(entityIn, 160, 2, false); } } So you can see that fast moving things have higher numbers for higher frequency. I think people are getting a bit confused. The actual movement of the entities on the server happens according to the movement (speed, pathfinding, etc.) but that information has to make it to all the clients attached to the game. The tracking range and frequency indicate how often that synchronization happen. There is a balance because if something is fast moving it should also have higher tracking frequency as it can get more out of sync between sync packets. Anyway, again I would suggest using values similar to the vanilla.
  10. Then you have to trace back further. Why is the code that is calling the method passing zeros. Keep working backwards until you find where the values are determined.
  11. It is not recommended for normal use in a mod, but for debugging purposes this might help -- basically you remember the channel from the connection event and then try to substitute your own channel handler. I give a bit more detail here: http://jabelarminecraft.blogspot.com/p/minecraft-forge-modding.html but you'll have to do the rest of the work not sure how tricky it is.
  12. Yes, I understand that goal but the point of Forge intervening is to make it amenable to modders. And in any case I offered a way to do it without patch to ItemShield -- they could test instanceof ItemShield instead of = Items.SHIELD. The way it is currently, a person might extend ItemShield and then wonder why it isn't working. The onus is on the modder to understand there is a hard-coded method in the parent class that needs to be overwritten. It would be nice to simply extend ItemShield and have it immediately work as a shield.
  13. Good point -- so it is bad Forge practice! Still doesn't change the criticism. They should have done like they did and replace all the checks with the isShield() call but the default implementation of isShield() in the Item class should have just returned false and should have been overridden to return true in ItemShield.
  14. Minecraft code is pretty inconsistent, and sometimes uses direct instance checking and sometimes uses instanceof. However it DOES use instanceof sometimes and you'll probably want to take advantage of it. For example, the getAttackDamage() method only gets called from EntityLiving if the item is an instanceof ItemSword. As an example of inconsistency (or not the best programming practice). the Item#isShield() method is implemented as: public boolean isShield(ItemStack stack, @Nullable EntityLivingBase entity) { return stack.getItem() == Items.SHIELD; } That is frankly a "dumb" way to do it. Better programming (from type hierarchy point of view) would be simply return false and let ItemShield return true. Alternatively, it should check for instanceof ItemShield. However, this implementation means that for your custom shield you need to override this method directly. It would be better programming practice to be able to extend ItemShield and automatically it would know that isShield() is true... So you'll need to do a mix of extending the class, overriding things that shouldn't be necessary, and working around places where the instance is hard-coded in vanilla. There are times when you don't want to extend though -- if you don't want your item to be always treated as a sword. I have a tutorial about deciding whether to extend or copy a vanilla class: https://jabelarminecraft.blogspot.com/p/minecraft-forge-172-know-when-to-copy.html?showComment=1538061795434
  15. That admonition only applies when JSON can do the job. In this case it cannot (well practically not, for as you said it won't scale as you could quickly need thousands of recipes) so you gotta code it. If you're going to code it you can either do it the simple way I already mentioned (generate a bunch of regular IRecipe instances using loops) or you can be a bit more sophisticated and create an IRecipe implementation that directly accepts all the axe types as being equivalent. However, with all that being said, are you sure the Ore Dictionary can't do what you want? You could make a new ore dictionary definition for your axes and register all the axe types against that, then your JSON recipe could just refer to the ore dictionary ingredient.
  16. GuiOverlayDebug does it like this: if (this.mc.objectMouseOver != null && this.mc.objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK && this.mc.objectMouseOver.getBlockPos() != null) { BlockPos blockpos = this.mc.objectMouseOver.getBlockPos(); IBlockState iblockstate = this.mc.world.getBlockState(blockpos); if (this.mc.world.getWorldType() != WorldType.DEBUG_ALL_BLOCK_STATES) { iblockstate = iblockstate.getActualState(this.mc.world, blockpos); } list.add(""); list.add(String.valueOf(Block.REGISTRY.getNameForObject(iblockstate.getBlock()))); IProperty<T> iproperty; String s; for (UnmodifiableIterator unmodifiableiterator = iblockstate.getProperties().entrySet().iterator(); unmodifiableiterator.hasNext(); list.add(iproperty.getName() + ": " + s)) { Entry < IProperty<?>, Comparable<? >> entry = (Entry)unmodifiableiterator.next(); iproperty = (IProperty)entry.getKey(); T t = (T)entry.getValue(); s = iproperty.getName(t); if (Boolean.TRUE.equals(t)) { s = TextFormatting.GREEN + s; } else if (Boolean.FALSE.equals(t)) { s = TextFormatting.RED + s; } } } return list; } Of course you don't need to do the list part and actually the code is a bit weird cause that string s never seems to be printed out, but you should be able to get the idea -- you should get the "actual state" and you can use the getProperties() from that and iterate through the list.
  17. I think you might be able to get past the "brute force" by using code-based recipe registration. You'd handle the registry event for IRecipe and then create the IRecipe instances within loops that iterates through collections (like a list of the axes and a list of the logs). In that way you only have to type in each item type once but get all the combinations built for you by the power of nested loops. Shouldn't be that painful and would scale well.
  18. You should generally copy the vanilla values for similar sorts of entities unless you have a specific reason. For fast moving objects the update frequency is usually increased and the send velocity updates help smooth things -- basically use those for projectiles. I have made bird entities before where I needed to greatly increase the tracking range (and render distance) because they were already flying like 80 blocks above the ground so if they would start not being tracked. But it is only in unusual cases where you need to do something different than the vanilla.
  19. In a large world the number of entities could get very large, so the server and the multiple clients only sync information about entities within a certain "tracking" distance. There is no need for server to be sending packets every tick to every client for entities that are not close to any of those players.
  20. For those who are wondering why, the problem is shifting right does not always produce the same results as dividing by 2. Since right shifting rounds toward negative infinity and integer division rounds to zero, some values (like -1 in two's complement) will just not work as expected when divided.
  21. If the method is getting called then you need to confirm that the if statement is working as expected. Add more console print statement in the loop to see what the task list contains and whether they meet the if condition. Should be quickly clear what the problem is after that.
  22. Yes. I think they call it "Structure" view. In any case, all modders should literally just scroll through the list of methods for all the major classes to get a good sense of what is available. You can even get new modding ideas by doing this.
  23. There are already keybindings for the built-in functions, which are set in the GameSettings class. So you just need the input handler for KeyInputEvent and check if the GameSettings.keyBindJump.isPressed().
  24. I have a tutorial here: http://jabelarminecraft.blogspot.com/p/minecraft-forge-1721710-keybinding.html Basically you can handle the KeyInputEvent and compare against the "key bindings" (i.e. the user settings for which key does which function). In my tutorial it explains how to make a new keybinding but you don't need that, you can just use the existing one for the jumping. But you should still handle the event.
  25. No, the problem he had was different. The LivingSpawnEvent is only intended for "natural" spawning. Any spawning that is controlled by the player (command or spawn egg) has no event. As mentioned above he has already solved the problem and is using the more general EntityJoinedWorldEvent.
×
×
  • Create New...

Important Information

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