Jump to content

[1.11.2] MultiBlock Structure


abused_master

Recommended Posts

Hey guys, so i need some help creating a multiblock tank.

So the tank will be as so, 5x5x5, contains a tank controller and an input valve and output valve, and once put together will have a custom model.

Now I don't really know anything about making a multiblock, how would i do this? is it something along the lines of like when the controller is placed check if certain blocks are placed around it? or is there a much better way to do this?

once the multiblock is created how do i set the input and output blocks to only do their respective parts?

and lastly how would i specify the model? would it be ok to be a json made to a 5x5x5 size or would it have to be something like a java model/obj model? and would i need a TESR? i presume so to render the liquid

thanks for the help even though i think i'm asking a lot.

Edited by abused_master
Link to comment
Share on other sites

How will the multiblock look like? Will the controller, input valve & output valve have specific places where they have to be, or can they be located anywhere in the 5³?
I presume the tank is going to be empty, yes?

 

Have your tank, tick every ~20 ticks (1 second) and if the multiblock has not yet been formed, scan for the nearest corner block.

A corner is very important in an equilateral cube.
A corner is defined as having exactly 3 wanted blocks, 1 on each axis. Once you have found your corner, you can get the opposite corner. You know the structure is 5³.
The opposite corner will exist ±4 blocks away along the x, y & z-axis.
Once you have your 2 corners, you know your structure, without knowing the structure.
Scan once more, inside this 5³ cube, (Using BlockPos#getAllInBox) and skip over any blocks "inside" your tank, only going along the outer layer. If you encounter 1 input valve, and 1 output valve, and all other blocks consist of the tank-blocks, woohoo, we know the tank is complete!

 

As for models: JSON models can not extend outside the "blockspace", though the model itself can be translated along any axis. This means that you will not be able to use a normal JSON for this.
You can use a TESR, but over-use, and non-optimized, will kill FPS.
You can start with a TESR; but I would recommend that you at least eventually make use of a custom IBakedModel, with the List<BakedQuad> scaled to fit the 5³. Custom IBakedModels take a bit to get comfortable with, but once you do, they are very easy.
For fluids, you can look at Tinkers' Construct, but I would also recommend that you view Vazkii's Botania mod. The manapools render themselves through a JSON, but the mana inside is rendered with a TESR, and are optimized.

Edited by Matryoshika
  • Like 1

Also previously known as eAndPi.

"Pi, is there a station coming up where we can board your train of thought?" -Kronnn

Published Mods: Underworld

Handy links: Vic_'s Forge events Own WIP Tutorials.

Link to comment
Share on other sites

21 minutes ago, Matryoshika said:

How will the multiblock look like? Will the controller, input valve & output valve have specific places where they have to be, or can they be located anywhere in the 5³?
I presume the tank is going to be empty, yes?

 

Have your tank, tick every ~20 ticks (1 second) and if the multiblock has not yet been formed, scan for the nearest corner block.

A corner is very important in an equilateral cube.
A corner is defined as having exactly 3 wanted blocks, 1 on each axis. Once you have found your corner, you can get the opposite corner. You know the structure is 5³.
The opposite corner will exist ±4 blocks away along the x, y & z-axis.
Once you have your 2 corners, you know your structure, without knowing the structure.
Scan once more, inside this 5³ cube, (Using BlockPos#getAllInBox) and skip over any blocks "inside" your tank, only going along the outer layer. If you encounter 1 input valve, and 1 output valve, and all other blocks consist of the tank-blocks, woohoo, we know the tank is complete!

 

As for models: JSON models can not extend outside the "blockspace", though the model itself can be translated along any axis. This means that you will not be able to use a normal JSON for this.
You can use a TESR, but over-use, and non-optimized, will kill FPS.
You can start with a TESR; but I would recommend that you at least eventually make use of a custom IBakedModel, with the List<BakedQuad> scaled to fit the 5³. Custom IBakedModels take a bit to get comfortable with, but once you do, they are very easy.
For fluids, you can look at Tinkers' Construct, but I would also recommend that you view Vazkii's Botania mod. The manapools render themselves through a JSON, but the mana inside is rendered with a TESR, and are optimized.

I'd like the controller to be placed at the bottom middle, here is a picture of roughly how it will be

https://gyazo.com/e40ca6e3b4d682f087e1892208163631

Andesite = frame

glass is tank glass, so you can see liquid inside,

iron block = input

redstone = output

furnace = controller

yes it will be empty,

i want to make it so that those cannot be moved elsewhere 

with that first part i think i get will, will give it a shot in a little and reply if i have any questions/problems,

but is there any place that goes over IBakedModels, how to use them, and an implementation example i could look at?

 

Link to comment
Share on other sites

Easy. Either use a tool to "activate" the construction (the way Immersive Engineering does) and look for that controller block. From there look for the rest of the construction. If it's all there, activate, do The Thing, give feedback to the player that it was successful, change the models, etc. etc.

 

OR

 

Require that the controller be placed last and on-place check for the rest of the structure, if it's all there, active...etc etc

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Well, with a well-defined structure I wouldn't use getAllInBox. I'd go "this is the core, so at x+1 I should find BlockY, at x+2 I should find...  And do a big query that way.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

Well, this is a dynamic multi-block; It just needs x <block> within the structure, and doesn't care where they are, if I'm understanding this correctly.

If so, local variables before the for-each-loop, can be used to keep count of the blocks inside; one variable for input, one for output, one for the controller, and one for the actual walls/bounds of the tank.

Inside the for-each-loop, if it encounters a wanted block, add it to the appropriate counter for that type.

After the for-each-loop, check these values.
If you got more, or less than 1 controller? Incorrect.
If you do not have an input, nor an output? Incorrect.
If controller+input+output+walls less than (or greater than, for redundancy) 5³-4³ blocks (hollow 5³ structure), then the multiblock is not yet complete

Also previously known as eAndPi.

"Pi, is there a station coming up where we can board your train of thought?" -Kronnn

Published Mods: Underworld

Handy links: Vic_'s Forge events Own WIP Tutorials.

Link to comment
Share on other sites

17 minutes ago, abused_master said:

wouldn't that just cause a huge mess in code? and would't i have to do a check for every facing?

It is a little messy, and facings can be mitigated.

 

You can convert a facing (EnumWest) into x and z offsets.  "Forward" gets translated to facing.offsetX() + facing.offsetZ() because a facing will only ever have one of those values as non-zero. For right, you use facing.rotate(UP).offsetX() + facing.rotate(UP).offsetZ() (you can store the rotated facings as their own variables as well).

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

private void setMultiblockAndRotate()
	{
		Hashtable<BlockPos, Block> blocks = new Hashtable<BlockPos, Block>();
		Hashtable<BlockPos, TileEntity> entities = new Hashtable<BlockPos, TileEntity>();
		int offset = getFacingOffset(facing);
		
		for(int x = bx; x <= ex; x++)
		{
			for(int y = by; y <= ey; y++)
			{
				for(int z = bz; z <= ez; z++)
				{	
					BlockPos oldpos = new BlockPos(x,y,z);
					
                    //this puts the blockpos in a 2d vector and rotates it, so it will face correctly
					Vector2d vec = new Vector2d(oldpos.getX(), oldpos.getZ());
					vec = Util.getNormalVector(vec, offset);
					
					BlockPos newpos = new BlockPos(vec.x, oldpos.getY(), vec.y);
					
					if(newpos.equals(BlockPos.ORIGIN))
					{
						blocks.put(newpos, BlockRegistry.basicmachine);
					}
					else //'blocks' is a hashtable simelar to blocks in this method. But, that table already has values that I set earlier.
					if(this.blocks.containsKey(oldpos))
					{
						blocks.put(newpos, this.blocks.get(oldpos));
					}
					else
					{
						blocks.put(newpos, fillerBlock); //fillerBlock is a block that I also defined earlier. Its just there so that I dont have to put those blocks at a position. This code just assumes that everything that isnt defined should be this block
					}
					
					if(this.tileentities.containsKey(oldpos))
					{
						entities.put(newpos, this.tileentities.get(oldpos));
					}
				}
			}
		}
		frame = blocks;
		tileentities = entities;
	}

This is how I've done it. It works by indexing blocks by their relative blockpositions (relative to the controller). Later you'd check if all the blocks defined in 'frame' are actually in the world, and if so, it'll form the multiblock. This way you could also add new tileEntities to handle things like in- and outputting liquids. 

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.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
    • It is an issue with quark - update it to this build: https://www.curseforge.com/minecraft/mc-mods/quark/files/3642325
    • Remove Instant Massive Structures Mod from your server     Add new crash-reports with sites like https://paste.ee/  
    • Update your drivers: https://www.amd.com/en/support/graphics/amd-radeon-r9-series/amd-radeon-r9-200-series/amd-radeon-r9-280x
  • Topics

×
×
  • Create New...

Important Information

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