Is there any programming method which will allow for

programmatically placing top-half slabs, slabs of the quartz or netherbrick variety, colored stained glass, smooth granite, etc. AKA the ‘data values’ of the base block.

Or are we still stuck until the data manipulators and such are completed for every block? Doomed to only be able to read every property for an already placed block, but not be able to set them, until later.

Actual working sample code rather than 'theoretically something like this" would be really appreciated if it does exist. I feel that I’m overlooking something to be able to do this - not complicated data handling and turning it to an datahandler thing, etc - just simply flipping a block axis, or its flavor

Look at BlockTraits.

1 Like

I know its not exactly what you want, but I dont see the issue after they get implemented.

BlockState state = BlockTypes.SLAB.getDefaultState().with(Keys.SLAB_TYPE, SlabTypes.NETHERBICK).get();
world.getLocation(X, Y, Z).setBlock(state);

You’re still using Data API in your code snippet. BlockTraits are fully implemented already.

I know I was using the Data API. Im saying I dont understanding what the issue is after they get implemented

Is this an ASSURANCE that if I keep banging my head against the wall trying to work through the various multisteps of methods to pull out and push in objects that I’ve been playing with, I will indeed be able to set a block trait at this moment in time and get the different slabs or slab orientation? That the block traits are writable and not just readonly and I just have to figure out still what code to chain together in thisd case

@gabizou

I’m afraid I just can’t see what I’m supposed to be seeing…
BlockTraits still appear to me to be read-only settings…

What example code is used to change/set a particular trait?

You use the methods that give you different BlockState instances with the desired data. That’s how BlockStates have always been for a while now, even with the Data API, when you request an ImmutableDataHolder#with(foo), you get a different instance of an ImmutableDataHolder contrary to DataHolder where you are mutating your current instance.

@gabizou

“You use the methods that give you different BlockStates instances with the desired data”

Methods which have evolved through many iterations of documentation that doesn’t work due to changes upon changes, yet exists somewhere known to few what the forms are now… and all that comes to my mind is the use of StoneData and WetnessData etc etc etc, and the consistantly stating “Those data manipulators have not been implimented yet” and the lack of nearly all block data stuff checked off on the implimentation checklist.

So I intepret your statement as "Duh - you use the same code snips as before that we keep saying “Dont work currently on anything execpt a few items, to put the DATA stuff into it” but yet if those DESIRED DATA things are not implimented… nothing will yet work still.

Which is why i asked IF the SPECIFICS of the types of block specifications listed are doable by some means currently, not “And this code will work one day once that stuff is caught up”. You throw “Traits” back as an answer, which appears to be read-only results , and then state that “its the same its always been” for setting them.

What is the spoon-feeding dang code that will, right now, today, not next month or whenever later, but now, give me a quartz slab , or a slab in the top position, or red stained glass… An example spoon-feed of one of those that does work, that can be copy-pasted, will spark the right path to be on, and then the rest of it is exploration from there and the wash of awareness and enlightenment that many of us need as a starting point to then poke from for making more sense of the methods involved from that point…

Please.

Okay, I will try to be as concrete with my example as possible.

So “placing” a block really means swapping out the current state of the block with a new, desired state.
The first thing we do is construct the new state, I’ll take stone slabs as an example:

// obtain the default state of stone slabs
BlockState slabState = BlockTypes.STONE_SLAB.getDefaultState();

Now we have to modify the state, so that the slab has the data we want. It’s possible to do this with the data API as @MoseMister mentioned, but we can do it with block traits. Because block states are immutable (you cannot modify them, but only produce a new instance with different data), we have to create a new state with the trait changed.

Note that the method we’re about to use, BlockState#withTrait, returns an Optional<BlockState>, meaning that the change can fail. How you handle a java.util.Optional is plugin-specific logic, but in this case I’ll call Optional#orElse() with the previous slab state if setting the trait fails, meaning that we’ll use the previously obtained state. Another option is to use an if/else block, checking if the optional is present before setting it.

BlockState slabStateChanged = slabState.withTrait(
    EnumTraits.STONE_SLAB_HALF,
    PortionTypes.TOP
).orElse(slabState);

I’m using PortionTypes.TOP (based on what I can gather from the implementation) to set the trait of the block. I found the STONE_SLAB_HALF trait by looking in the block traits package for what I wanted.

Okay, we have the desired state, now let’s set it into our location. Assuming you already have a location that you want to set the data into:

Location loc; // the location of the block we want to set into
loc.setState(slabStateChanged); // set the state to the new state
1 Like

@gabizou

So the reason I requested this "Is there ANY programming method … " question for these blocks is because all the data-manipulator stuff for them is not yet implimented to do them via the several other ways that are promised to work for those when they finally are implimented, and wanted to know if there was a simpler way to currently trip the properties and settings on these right now, since the getTraits works so nicely to identify what is present for everything…

Your response - very good, I got encouraged, and figured “If this works, I’m going to poke at it more, and then volunteer to add a section to the documentation about it to help get this down and the process to find the stuff to change”, cause
that definitely puts a flag firmly in the middle of new territory to look around from within. The Enums for the traits is good, the example of portiontypes shows to look in the data.types package for a list of ones that pretty much jumps off as the one to use, the process seems fairly clear.

Question first:
Would the placing of two trait changes (like quartz top slabs) rquire making a blockstate default, a blockstateA with top-block properties from the default; and a blockstateB with quartz-properties from the blockstateA ??

Eitherway - NONE OF THIS WORKS for me right now still, defeating my question.

==============================
I used your EXACT code, SpongeForge 1521-dev 726, Forge 1521, API-102

With the orElse() I just get stone slab still. Drop the or else with a get() (Which in a true implimentation, would be the way I woudl go if I am precisely writing a method to place quartz slabs, they WILL be slabs, they WILL be quartz slabs, thus the blockstate WILL support the property required and wont return null, no option needed…) … with just get() I get the following error;

Could not pass InteractBlockEvent$Secondary$Impl to SpongePlugin:BoosUFOInvaders{unknown}
java.util.NoSuchElementException: No value present
        at java.util.Optional.get(Unknown Source) ~[?:1.8.0_65]
        at com.prennet.boomod.ufoinvaders.UFOBuilder.placeTopSlabQuartz(UFOBuilder.java:94) ~[UFOBuilder.class:?]

I tried with the one-state at a time change, with TOP first, followed by Quartz, then switched the order and the results were no different, the first instance in my method of the block-state withTrait() assignment throws that error.

BlockState slabStateChanged = slabState.withTrait(
    EnumTraits.STONE_SLAB_HALF,
    PortionTypes.TOP
).orElse(slabState);
                                                             AND the other one is
BlockState slabStateChanged = slabState.withTrait(
   EnumTraits.STONE_SLAB_VARIANT,
   SlabTypes.QUARTZ
).orElse(slabState);

No go with either one, and that error message to me says “This has not yet been implimented” for those traits or datatypes features to be added (Also, assumed you meant setBlock() since no setState() method…) OR ELSE we’re still missing something from the process that needs to be in there…

So if indeed these SHOULD Be working this way and it is not, what is the missing link, since these are throwing non-implimented errors…

1 Like

You’ll have to forgive me for my curtness, my weekend has been very busy, minimizing my time that otherwise I would be spending on studying and this project to a matter of at most a few minutes at a time. However, now that I am home (but it’s very late, and I should be heading to sleep in a few minuets), I’ll try to give you a reply with as much explanation as possible.

That build is quite old, mind re-running the test with the latest build?

Also, there’s some issues with some of the code examples: Namely that only some of the api.data.types will directly be “mixed” in at runtime to the actual Enums being used by the EnumTraits. To avoid this: I would use something similar to this:

public void makeQuartzPillar(Location location) {
  final BlockState quartz = BlockTypes.QUARTZ_BLOCK.getDefaultState();
  Comparable<?> chiseledVariant = quartz.getTraitValue(EnumTraits.QUARTZ_BLOCK_VARIANT).get();
  for (Enum<?> e : EnumTraits.QUARTZ_BLOCK_VARIANT.getPossibleValues()) {
    if (e.name().equalsIgnoreCase("chiseled")) {
      chiseledVariant = e;
    }
  }

  final BlockState chiseled = quartz.withTrait(EnumTraits.QUARTZ_BLOCK_VARIANT, chiseledVariant).orElse(quartz);
  location.setBlock(chiseled);
}

And the reasoning here is the following:

  1. It’s not always a guarantee that every CatalogType in the api.data.type package will be directly translatable to the Enums being used by Minecraft internally, what may work for one version may not work for another.
  2. You’re able to safely find ANY of the “traits” used by not just vanilla blocks, but also those found with mods.

Of course, what is the reasoning for this to be so ambiguous? Changes with each and every Minecraft version will affect the BlockTrait “vanilla defaults” until the underlying BlockState system is relatively finalized.

Why not just use Data

Well, in a perfect world, when API is written, there is an implementation to accompany it. Of course, being in alpha phase, that world is far from the truth. It’s very well possible to just do this in the Data API with the following:

public void changeChiseledBlock(Location location) {
  final BlockState quartz = BlockTypes.QUARTZ_BLOCK.getDefaultState();
  final BlockState chiseled = quartz.with(Keys.QUARTZ_TYPE, QuartzTypes.CHISELED).orElse(quartz);
  location.setBlock(chiseled);
}

As of this afternoon, the implementation for handling this was merged, however a SpongeForge build has not been pushed yet (mostly because I haven’t been able to just update the submodule yet). So, your case for changing specific Block related data values will be supported.

Of course, if this doesn’t work with the latest build (block traits example, not the data api example), then please let me know and we’ll see why its’ not working and probably fix it within the next day or so.

Those builds are quite old:::: Does this mean that the build download sites are still fubared then, because those were the latest builds listed on the site Repository - Nexus Repository Manager and currently still is, as is Repository - Nexus Repository Manager

Ooooh, as i post that, I realize the forge site link instead, dang. The other one should have some kind of warning added to the head of the display…
I will look into the newer server version and see what happens, and this more thorough outline y ou have presented will be very helpful as well. I would be more than happy to even test every block-trait out to confirm they work if one of these gets us somewhere :slight_smile:

Okay, Forge 1530 + spongeforge 1530-dev777
The fewer-line code from yesterday with PortionTypes still produces no block with the orElse() (other than stone slab) , for either a Half-slab and with that changed to get() throws the same errors

Could not pass InteractBlockEvent$Secondary$Impl to SpongePlugin:BoosUFOInvaders{unknown} java.util.NoSuchElementException: No value present
        at java.util.Optional.get(Unknown Source) ~[?:1.8.0_65]
        at com.prennet.boomod.ufoinvaders.UFOBuilder.placeTopSlabQuartz(UFOBuilder.java:98) ~[UFOBuilder.class:?]

when used to set Just the Top state

and produces errors like these for the new method approach you introduced

Could not pass InteractBlockEvent$Secondary$Impl to SpongePlugin:BoosUFOInvaders{unknown}
java.lang.AbstractMethodError: net.minecraft.block.properties.PropertyEnum.getValueClass()Ljava/lang/Class;
        at net.minecraft.block.state.BlockState$StateImplementation.getTraitValue(BlockState.java:375) ~[beg.class:?]
        at com.prennet.boomod.ufoinvaders.UFOBuilder.placeBottomSlabQuartz(UFOBuilder.java:106) ~[UFOBuilder.class:?]

when using this code to set just the quartz flavor of slab. The code fails simlarly for changing JUST the slab half-ness of the block as well – the error is thrown for the Comparible<?> line in each case.

   final BlockState slab = BlockTypes.STONE_SLAB.getDefaultState();
        Comparable<?> quartzVariant = slab.getTraitValue(EnumTraits.STONE_SLAB_VARIANT).get();
        for (Enum<?> e : EnumTraits.STONE_SLAB_VARIANT.getPossibleValues()) {
            if (e.name().equalsIgnoreCase("quartz")) {
                quartzVariant = e;
            }
        }
        final BlockState quartzSlab = slab.withTrait(EnumTraits.STONE_SLAB_VARIANT, quartzVariant).orElse(slab);
        for (Vector3d v : bottomquartzslab) {
            ufoBayCenter.add(v).setBlock(quartzSlab);
        }

A SIDE QUESTION: what would be the default to return there in an .orElse() case when this works right, since the orElse() getting stone slab at least would in theory return something to move forward each time, until finding a build version where it suddenly works…

Or is what you meant about “code has been merged but not pushed” meaning, that when I asked this question, there was absolutely no way to place/change blocks to half slab quartz, upper-block halfs, coolored glass pane varients, etc – but that the code was in the staging area between is-done and ‘in-the-files-you-can-use’, and as such, the reality is, this is ‘working code’ that still wont work until a release comes out with these things implimented in them, just, a different implimentation from all the data manipulators implimentation for the blocks yet to be done??

Alternate method was

 final BlockState slab = BlockTypes.STONE_SLAB.getDefaultState();
        Comparable<?> positionVariant = slab.getTraitValue(EnumTraits.STONE_SLAB_HALF).get();
        for (Enum<?> e : EnumTraits.STONE_SLAB_HALF.getPossibleValues()) {
            System.out.println(e.toString());
            if (e.name().equalsIgnoreCase("top")) {
                positionVariant = e;
            }
        }
        final BlockState topSlab = slab.withTrait(EnumTraits.STONE_SLAB2_HALF, positionVariant).orElse(slab);
        for (Vector3d v : topquartzslabblocks) {
            ufoBayCenter.add(v).setBlock(topSlab);
        }

forgot to tag you @gabizou and i dont know if tagging an edit works or not

Here is how you would alter all top half stone slab states via ChangeBlockEvent.Place done by players :

@Listener
public void onChangeBlockEventPlace(ChangeBlockEvent.Place event) {
    if (event.getCause().first(Player.class).isPresent()) {
        for (Transaction<BlockSnapshot> transaction : event.getTransactions()) {
            if (transaction.getFinal().getState().getType() == BlockTypes.DOUBLE_STONE_SLAB) {
                Optional<? extends Enum<?>> enumProperty = transaction.getFinal().getState().getTraitValue(EnumTraits.DOUBLE_STONE_SLAB_VARIANT);
                if (enumProperty.isPresent()) {
                    BlockState defaultSlabState = BlockTypes.DOUBLE_STONE_SLAB.getDefaultState();
                    BlockState quartzState = defaultSlabState.withTrait(EnumTraits.DOUBLE_STONE_SLAB_VARIANT, "quartz").orElse(defaultSlabState);
                    transaction.setCustom(transaction.getFinal().withState(quartzState));
                }
            }
        }
    } 
}

Now outside the event, you would do the following

BlockState defaultSlabState = BlockTypes.DOUBLE_STONE_SLAB.getDefaultState();
BlockState quartzState = defaultSlabState.withTrait(EnumTraits.DOUBLE_STONE_SLAB_VARIANT, "quartz").orElse(defaultSlabState);
world.setBlock(position, quartzState);
1 Like
BlockState defaultSlabState = BlockTypes.DOUBLE_STONE_SLAB.getDefaultState();
BlockState quartzState = defaultSlabState.withTrait(EnumTraits.DOUBLE_STONE_SLAB_VARIANT, "quartz").orElse(defaultSlabState);
world.setBlock(position, quartzState);

@blood Ding ding ding we have a winner for setting a block At least, that code makes a double-slab of quartz, which is exactly what the code says it is going to do contrary to the dialog description :smile:

BlockState defaultSlabState = BlockTypes.STONE_SLAB.getDefaultState();
BlockState topState =
	defaultSlabState.withTrait(EnumTraits.STONE_SLAB_HALF, "top").orElse(defaultSlabState);
BlockState topQuartzState =
	topState.withTrait(EnumTraits.STONE_SLAB_VARIANT, "quartz").orElse(topState);

for (Vector3i v : topquartzslabblocks) {
	ufoBayCenter.getExtent().setBlock(ufoBayCenter.getBlockPosition().add(v), topQuartzState);
}

works to make top, quartz slabs - i see no other way to apply multiple traits but to chain blockstates together this way.

So the difference between working and not working was withTrait() vs withTraitValues(), and using raw strings for the traits rather than the enums …

Hopefully this is just the temporary state, and the need for raw strings is due to the mixins issue mentioned, that will one day be not an issue… Though when that day happens, there will be several other ways to accomplish this as well

Thank you guys.

That code for changing it on-block-place looks mighty intimidating, and lacks context of explaining what exactly you are trying to work with to convert things there, because of the double-slab and not actually top-slab issue. Is it trying to replace a double-slab stone block with double-slab quartz block on placing only, cause then this would seem something for yes, unplaceable blocks. But for REAL code for a TOP-block of quartz only, not double-slab problem – there should be no need to adjust the quartz top slab being placed… unless it was a matter of saying that ANY stone-slab placement in the top position were to be autoconverted to top quartz automatically, then that would work with direct code replacement…

I look forward to making a test suite tonight to test as many block traits this way as possible.