azzy Posted March 12 Posted March 12 So I'm currently trying to cast a ray from a position (whether its from a BlockPos or Vec3), but the problem I face is that I can't even seem to find a way to cast rays on the server. Is there some obscurely named method I don't know about that does just what I'm looking for? (currently on 1.18.2) Quote
dee12452 Posted March 14 Posted March 14 Does level.clip(...) exist in 1.18.x? If so you could use that! Quote
azzy Posted March 14 Author Posted March 14 32 minutes ago, dee12452 said: Does level.clip(...) exist in 1.18.x? If so you could use that! It does, but so does level.isBlockInLine, which i looked at both of their code, and they do almost exactly the same thing. But now a new problem arises. I'm casting 4 rays per loop (in a for loop) once a world is loaded for the first time, and it causes the generation to hang for a moment (stuck at 100% until the loop completes). Casting those 4 rays that are 128 blocks in length 10 times can take roughly 20-30 seconds before the world finally loads. Is there any better way to optimize it? (without decreasing the ray length because I need it to be 128 blocks) Quote
dee12452 Posted March 14 Posted March 14 Dang, what exactly are you trying to do? Why are you doing 4 raycasts of that magnitude? That's a big set of operations. Quote
azzy Posted March 14 Author Posted March 14 (edited) Checking the terrain around an area to see if its suitable enough to generate a volcano (not block generation, instead marking that specific spot a volcano) in that spot (and if it isn't, roll a dice with a small chance to spawn the volcano anyway). My goal is to make certain areas in the world that look like they could be volcanoes as volcanoes. One attempt where I tried to make it run faster was to put each volcano spawn attempt in a new thread. Made zero difference though. Edited March 14 by azzy Quote
dee12452 Posted March 15 Posted March 15 Ah gotchya. What if instead you spawn block entities that once loaded into a chunk, rolled the dice first (despawn if false), then did the raycasting in its surroundings? That should stop the generation problems. You might get some more in-game lag as the player explores to other chunks, but depending on implementation it might not be bad or too noticeable. public class VolcanoCheckSpawnBlockEntity extends BlockEntity implements ITickingBlockEntity { @Override public void onLoad() { // Roll dice. Not a spot? Do nothing and despawn // Do raycast otherwise, spawn volcano features if viable. } } Now this ^ is from my 1.20.2 mod so it might not be the same. If you don't have an onLoad() to override, you could just do it on tick and just make sure to do the work here on the first tick. Quote
azzy Posted March 15 Author Posted March 15 IntelliJ is saying that "ITickingBlockEntity" doesn't exist. And I can't import it either. (I'm using the latest version of forge in 1.18.2) Quote
dee12452 Posted March 15 Posted March 15 Oh shoot you're right, that's my own interface in my project lol. Try following this guide (specifically for a ticking block entity) https://docs.minecraftforge.net/en/1.18.x/blockentities/ Here's the meat If you need a ticking BlockEntity, for example to keep track of the progress during a smelting process, another method must be implemented and overridden within EntityBlock: EntityBlock#getTicker(Level, BlockState, BlockEntityType). This can implement different tickers depending on which logical side the user is on, or just implement one general ticker. In either case, a BlockEntityTicker must be returned. Since this is a functional interface, it can just take in a method representing the ticker instead: // Inside some Block subclass @Nullable @Override public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level level, BlockState state, BlockEntityType<T> type) { return type == MyBlockEntityTypes.MYBE.get() ? MyBlockEntity::tick : null; } // Inside MyBlockEntity public static void tick(Level level, BlockPos pos, BlockState state, T blockEntity) { // Do stuff } Quote
azzy Posted March 16 Author Posted March 16 (edited) BlockEntity sounds like an interesting solution. My only question is how would the game handle thousands of these being created all around the world (these volcanoes can generate hundreds of thousands of blocks from spawn, and are usually spaced very far apart). Right now with my current methods, attempting to generate 10 takes roughly 30 seconds (I couldn't imagine 10000 attempts). This also feels like it would solve my other thing that I need to implement, which would be saving the generates volcanoes in a list. (right now, the volcanoes that generate are saved into a list, and I somehow need to save that list per world) Edited March 16 by azzy Quote
dee12452 Posted March 16 Posted March 16 Well the blockentity code to check for generation I would think would only run once the player is close enough to it in the world. You might have to do more research on how that’d work exactly and if that’s a solution that could work with the calcs you’re running to determine volcano viability. It might lag an exploring player significantly and make the game unplayable. Only other option I can think of is just changing world gen to just mend the areas you spawn a volcano to be viable rather than checking if the area is viable if that makes sense. Good luck! Quote
azzy Posted March 17 Author Posted March 17 Excuse me for my late response (I was watching an ongoing volcanic eruption in Reykjanes Iceland). Did a bit of testing with the block entity its self before I implemented the logic and methods for the volcano. Right now my questions are how would I make the block entity completely invisible to the world (think air block), and whether all the properties of the volcano block entity would save or not when saving and logging back into a world. Among other things I'll say later (its 3 am as of writing this). Quote
azzy Posted March 18 Author Posted March 18 @dee12452 Don't know if your still there, but I did more testing with the block entity, and I run into a major roadblock. The tick event method in my block entity is marked as static, which is a problem since the properties of the volcano block entity its self are not static, and have to be non static otherwise all the volcanoes that generate around the world will all have the same properties. I can't make the tick event method non static, because then the volcano generation block (not block entity) wont be able to access it in the volcano generation block entity. Sort of lost on what to do here since the previous way I tried to generate volcanoes was to just make a "volcano" class with all the fields and methods (to process logic for the volcano), with some of the methods being events (which I can't use because they have to be static, and making all the properties static causes all volcanoes to have the same properties). And I have also yet to optimize the generation speed of these volcanoes (the raycasting is a big contributor, and I kind of really need it for volcanic looking formations to actually be marked as volcanic). I can show code if I need too. Quote
dee12452 Posted March 19 Posted March 19 (edited) I know what ur saying, this is what I'd suggest you do to get around this. ITickingBlockEntity.java public interface ITickingBlockEntity { /** * Client + Server tick callback. * * @param level the server level * @param pos the block pos * @param state the block state */ void tick(Level level, BlockPos pos, BlockState state); } GlobalBlockTicker.java public class GlobalBlockEntityTicker { private GlobalBlockEntityTicker() {} public static <T extends BlockEntity> void ticker(Level level, BlockPos pos, BlockState state, T blockEntity) { if(!(blockEntity instanceof ITickingBlockEntity tickingEntity)) { return; } tickingEntity.tick(level, pos, state); } } VolcanoBlock.java (or whatever it is named) public class VolcanoBlock extends Block implements EntityBlock { // ... constructor and stuff @Nullable @Override public <T extends BlockEntity> BlockEntityTicker<T> getTicker(@NotNull Level level, @NotNull BlockState state, @NotNull BlockEntityType<T> type ) { return GlobalBlockEntityTicker::ticker; } } VolcanoBlockEntity.java (or whatever it is named) public class VolcanoBlockEntity extends BlockEntity implements ITickingBlockEntity { // Constructor and stuff @Override public void tick(Level level, BlockPos pos, BlockState state) { // Non static tick method! } } Edited March 19 by dee12452 Removed my code, whoops Quote
azzy Posted March 19 Author Posted March 19 (edited) I went back to using a class (not a block entity) for volcanoes. But I will try this once I can fix setBlock method not updating clients on the blocks set (volcanoes are being generated on the server and only the server via world tick/load event if your wondering). Edited March 19 by azzy 1 Quote
azzy Posted March 20 Author Posted March 20 Just tried out the code you provided and it is functional, but the tick event method does not run at all. Quote
azzy Posted March 20 Author Posted March 20 I figured. Here is the code that I have rn. VolcanoGenerationBlock.java public class VolcanoGenerationBlock extends Block implements EntityBlock { public VolcanoGenerationBlock(Properties properties) { super(properties); } @Nullable @Override public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) { return new VolcanoGenerationBlockEntity(pPos, pState); } @Nullable @Override public <T extends BlockEntity> BlockEntityTicker<T> getTicker(@NotNull Level level, @NotNull BlockState state, @NotNull BlockEntityType<T> type) { return GlobalBlockEntityTicker::ticker; } } VolcanoGenerationBlockEntity.Java public class VolcanoGenerationBlockEntity extends BlockEntity implements ITickingBlockEntity { // code above this line taken out for the sake of readability public VolcanoGenerationBlockEntity(BlockPos pPos, BlockState pBlockState) { super(ModBlockEntities.VOLCANO_GENERATION_BLOCK_ENTITY.get(), pPos, pBlockState); } @Override public void tick(Level level, BlockPos blockPos, BlockState blockState) { // code in here taken out for the sake of readability } } GlobalBlockEntityTicker.Java public class GlobalBlockEntityTicker { private GlobalBlockEntityTicker() {} public static <T extends BlockEntity> void ticker(Level level, BlockPos pos, BlockState state, T blockEntity) { if (!(blockEntity instanceof ITickingBlockEntity tickingEntity)) return; tickingEntity.tick(level, pos, state); } } ITickingBlockEntity.Java public interface ITickingBlockEntity { /** * Client + Server tick callback. * * @param level the server level * @param pos the block pos * @param state the block state */ void tick(Level level, BlockPos pos, BlockState state); } Quote
dee12452 Posted March 21 Posted March 21 I mean that all looks good. Have you tried doing any debugging into where the hold up is? Have you made sure that the block is in the world / can you see it (if it's being rendered)? If you can, use your IDE to start stepping through some of this code, such as does it even get to this line in GlobalBlockEntityTicker.Java? `if (!(blockEntity instanceof ITickingBlockEntity tickingEntity))` If not, some `System.out.println(xxx);` might also do the trick. Good luck Quote
azzy Posted March 21 Author Posted March 21 I have added a debug print statement in the GlobalBlockEntityTicker after the if statement before, and it did not run. Though maybe its the way that I'm generating the block, since in my volcano spawner, I'm spawning volcanoes by using the setBlock method, and all of the events like onLoad and onChunkUnloaded do work, but tick does not. Here is how I'm spawning the volcanoes: level.setBlockAndUpdate(pos, ModBlocks.VOLCANO_GENERATION_BLOCK.get().defaultBlockState()); Quote
dee12452 Posted March 21 Posted March 21 If those other methods are being called, I'd imagine the block and its block entity are being placed in the world correctly. At this point I'd just try and follow this as closely as possible, and continue to do debugging https://docs.minecraftforge.net/en/1.18.x/blockentities/ as I can't tell you what the problem is without seeing the whole codebase and playing around with it myself. FWIW though you could do most of your work on onLoad though so that's somewhere you could at least start in the meantime. Quote
azzy Posted March 21 Author Posted March 21 (edited) I just did some more poking around. Apparently when i actually place down the volcano generation block, the tick event is running. Clearly it has to do with the setBlock method, maybe from the fact that it wont update clients on block changes (what I'm currently trying to fix along side the tick event not running). What I don't get though is why the onLoad event still runs, whether its placed by a player or the world. The onLoad event also runs twice for whatever reason (when I place it down) Edited March 22 by azzy Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.