Jade example of showing a block when looking at another
Angelin01 opened this issue ยท 5 comments
Sorry if this seems obvious, or an issue is not the correct place to ask. While I am a developer, I am not versed in the MC modding scene.
What I am trying to accomplish is having Jade show one block when looking at another. For example, when looking at a Trapped Chest, show a regular Chest instead.
Now, Jade already does this by default for Vanilla trapped chests, and a few other mods already have integrations by default (for example, Aether Mimics), but since this isn't the case for all blocks for all mods, I'm trying to patch the holes.
Is there an easy way to do this with KubeJS Additions, or should I try to add support directly to the mods themselves?
Much appreciated.
No worries at all!
I appreciate you sending that example, as that helped me figure out how Jade handles this.
Essentially, Jade registers a ray trace callback with a priority of -10 here that uses the callback method you posted here.
Which means that during the onClientRegistration event, you can use the event.addRayTraceCallback(priority, raytraceCallback) method to achieve the same effect that the base Jade mod achieves.
Full simplified example:
onClientRegistration((event) => {
event.addRayTraceCallback((hitResult, accessor, originalAccessor) => {
// Perform checks and change accessor here.
return accessor;
});
});
Hopefully this helps!
(P.S. This was written from my phone, and is untested, so there may be slight mistakes. I apologize in advance.)
Good catch! I appreciate the help. However, it seems my limited understandings of KubeJS and Minecraft modding in general are biting my ass. This simple code is enough to crash the game:
const $WAILA_CLIENT_REGISTRATION = Java.loadClass("snownee.jade.impl.WailaClientRegistration");
const $IWAILA_CONFIG = Java.loadClass("snownee.jade.api.config.IWailaConfig");
global["JadeHideBlocksCallback"] = (event, hitResult, accessor, originalAccessor) => {
const block = accessor.getBlock();
if (!block) {
return accessor;
}
return accessor;
}
JadeEvents.onClientRegistration(event => {
event.addRayTraceCallback(-5, (hitResult, accessor, originalAccessor) => global["JadeHideBlocksCallback"](event, hitResult, accessor, originalAccessor));
});
I get a java.lang.NullPointerException: Cannot invoke "Object.hashCode()" because "<parameter1>" is null
. This happens whenever I look at something that is not a block. So I thought: "Aha! I just need to check if the type of accessor is a BlockAcessor". So with a quick check:
if (accessor.getAccessorType().getName() !== "snownee.jade.api.BlockAccessor") {
return accessor;
}
... I get the exact same error. So now I am at a loss. The Accessor
interface clearly has a getAccessorType
method. I am starting to wonder if I just should open a patch to Jade itself.
Hi I'm trying to do something similar to hide framed block but it doesn't really work, like when I look at the framed block without camouflage it normally shows it in jade, when I apply the camouflage without stopping looking at it it shows the block used instead, but as soon as I stop looking at it and try to watch it again there are no more jade tooltips at all on the framed block (unless I remove and re-apply the camouflage each time I look at it)
client_scripts
const BlockAccessor = Java.loadClass("snownee.jade.api.BlockAccessor");
const BlockState = Java.loadClass("net.minecraft.world.level.block.state.BlockState");
JadeEvents.onClientRegistration((event) => {
event.addRayTraceCallback((hitResult, accessor, originalAccessor) => {
if (accessor instanceof BlockAccessor) {
let blockData = accessor.getBlock();
let blockName = blockData.id;
let nbt = {};
switch(blockName) {
case "framedblocks:framed_door":
nbt = accessor.getBlockEntity().serializeNBT();
if(nbt && nbt.camo && nbt.camo.state && nbt.camo.state.Name) {
let camoBlock = Block.getBlock(nbt.camo.state.Name).defaultBlockState();
return event.blockAccessor()
.from(BlockAccessor(accessor))
.blockState(BlockState(camoBlock))
.build();
}
break;
}
}
return accessor;
});
});
I think that it could still help, and if you find a solution to make it 100% functional I'm interested ^^
I appreciate it. I did not expect instanceof
to work here, at all.
Nonetheless, I still get a million instances of Cannot invoke "Object.hashCode()" because "<parameter1>" is null
every time I move a comma, it's making debugging this an absolute pain.
I'm going to share the small code I wrote (which still crashes the game) and am going to focus on other things for the time being, refresh my mind, and return later. Thank you both for your time. Feel free to close the issue, or leave it open if it doesn't bother anyone, and I might update it later. If I do figure it out, I might open a PR to the README with a full example.
const BlockAccessor = Java.loadClass("snownee.jade.api.BlockAccessor");
// const WailaClientRegistration = Java.loadClass("snownee.jade.impl.WailaClientRegistration");
// const IWailaConfig = Java.loadClass("snownee.jade.api.config.IWailaConfig");
const TRAPPED_CHEST_PATH_COMMON = "trapped_";
global["JadeHideBlocksCallback"] = (event, hitResult, accessor, originalAccessor) => {
if (!(accessor instanceof BlockAccessor)) {
return accessor;
}
// if (WailaClientRegistration.instance().maybeLowVisionUse || !IWailaConfig.get().getGeneral().getBuiltinCamouflage()) {
// return accessor;
// }
const block = accessor.getBlock();
if (!block) {
return accessor;
}
if (block.hasTag("forge:chests/trapped")) {
let path = block.id.getPath();
if (!path.includes(TRAPPED_CHEST_PATH_COMMON)) {
return accessor;
}
let newPath = path.replace(TRAPPED_CHEST_PATH_COMMON, "");
let newBlock = Block.getBlock(block.id.withPath(newPath));
if (!newBlock) {
return accessor;
}
let newState = newBlock.defaultBlockState();
return event.blockAccessor().from(block).blockState(newState).build();
}
return accessor;
}
JadeEvents.onClientRegistration(event => {
event.addRayTraceCallback(-5, (hitResult, accessor, originalAccessor) => {
return global["JadeHideBlocksCallback"](event, hitResult, accessor, originalAccessor);
});
});
Hello again! I'm glad to say that, after a break, and returning to it with a fresh mind, it was really simpler than I expected. This is the working code:
const BlockAccessor = Java.loadClass("snownee.jade.api.BlockAccessor");
const QuarkTrappedChestBlock = Java.loadClass("org.violetmoon.quark.content.building.block.VariantTrappedChestBlock");
const SupplementariesTrappedPresentBlock = Java.loadClass("net.mehvahdjukaar.supplementaries.common.block.blocks.TrappedPresentBlock");
global["JadeHideBlocksCallback"] = (event, hitResult, accessor, originalAccessor) => {
if (!(accessor instanceof BlockAccessor)) {
return accessor;
}
if (accessor.getPlayer().creative) {
return accessor;
}
const block = accessor.getBlock();
if (!block) {
return accessor;
}
if (!(block instanceof QuarkTrappedChestBlock || block instanceof SupplementariesTrappedPresentBlock)) {
return accessor;
}
const blockId = block.id;
const searchString = "trapped_";
const index = blockId.indexOf(searchString);
if (index < 0) {
return accessor;
}
const newBlockId = blockId.substring(0, index) + blockId.substring(index + searchString.length);
const newBlock = Block.getBlock(newBlockId);
const defaultBlockState = newBlock.defaultBlockState();
return event.blockAccessor()
.from(accessor)
.blockState(defaultBlockState)
.build();
}
JadeEvents.onClientRegistration(event => {
event.addRayTraceCallback(-5, (hitResult, accessor, originalAccessor) => {
return global["JadeHideBlocksCallback"](event, hitResult, accessor, originalAccessor);
});
});
I'm almost certain there's probably some... Better ways to achieve this, but this simple solution didn't seem to impact my performance and works for both Quark and Supplementaries! I even added the creative mode "see through" that original Jade has.
It does have a slight quirk, but that's on par with Supplementaries' default behavior: trapped presents don't show their contents in Jade, regular presents do. But that's very very minor.
@Hunter19823 if you'd like, you can add this code (or an improved version) to your examples, it might help someone!
@Dowar I appreciate your code snippet, it helped quite a bit. I figured you don't need to wrap the accessor and blockstates in the Java class' calls, but aside from that, I don't really know how to help you with your camouflage, I'm sorry.