Jump to content

[1.18.2] Block raycasting on the server?


azzy

Recommended Posts

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)

Link to comment
Share on other sites

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)

Link to comment
Share on other sites

Posted (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 by azzy
Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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
}

 

Link to comment
Share on other sites

Posted (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 by azzy
Link to comment
Share on other sites

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!

Link to comment
Share on other sites

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).

Link to comment
Share on other sites

@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.

Link to comment
Share on other sites

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 by dee12452
Removed my code, whoops
Link to comment
Share on other sites

Posted (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 by azzy
  • Haha 1
Link to comment
Share on other sites

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);
}

 

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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());
Link to comment
Share on other sites

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. 

 

Link to comment
Share on other sites

Posted (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 by azzy
Link to comment
Share on other sites

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...

Important Information

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