Closed Nubebuster closed 2 months ago
Thanks for the PR. What version(s) did you test this on?
1.8 I don't see any reason why it wouldn't work on other versions though. It only sends a spawn and destroy packet. As for the event handlers I don't see any reason why it wouldn't work either.
Please hold this pull request. I've decided I want to add the velocity and handle the tracking better overall.
I've gotten further than I expected. Unfortunately I went down a rabbit hole creating the nonexistent WrapperPlayServerExplosion packet. I've used the build tools to decompile many versions as there is no reliable documentation for this kind of thing.
1.20 is now fully working! I am going to finish 1.8 this weekend or monday.
Side note: I also fixed/am fixing a few other compatibility issues.
Looks like this packet is sent after an explosion https://wiki.vg/Protocol#Explosion, it will probably look a bit different for 1.8
Looks like this packet is sent after an explosion https://wiki.vg/Protocol#Explosion, it will probably look a bit different for 1.8
Correct. I have this part already working and implemented.
I now need to figure out at which version the server stops sending the sound packet. I already know 1.8 needs a sound packet. And 1.20 has it included. What happens with the versions in between I dont know.
I've also rewritten the logic to be more packet based, as I was getting my fingers knotted trying to keep track of the entity ids for the velocity packets. But I realised that most of the logic can be done in the packet listener. I only use the spigot listener for determining which block needs to be removed for the tnt spawn, and what the block data was before the explosion. But sending the block remove packet is included in the explosion packet. So I've added a no-send flag to the BlockData class. I will push these changes in the coming days.
I'm excited to contribute. I was disappointed at first that the first video shows TNT not working, so I decided I wanted to fix that.
I now need to figure out at which version the server stops sending the sound packet. I already know 1.8 needs a sound packet. And 1.20 has it included. What happens with the versions in between I dont know.
Don't worry too much about other versions, I think going forward it makes the most sense to mainly support 1.8 and the current latest minecraft version (1.21) for new features.
Material material = getBlockMaterial(blockChange.getBefore());
System.out.println(material);
if (material == null) {
System.out.println("Material is null");
} else {
// Use equals for comparison
System.out.println(material.equals(Material.TNT));
System.out.println(material == Material.TNT);
// Log the material's class name to check if it's a standard Material enum
System.out.println("Material class: " + material.getClass().getName());
try {
// Convert to string safely
System.out.println(material.toString());
} catch (Exception e) {
System.out.println("Error converting material to string: " + e.getMessage());
}
try {
// Convert to name safely
System.out.println(material.name());
} catch (Exception e) {
System.out.println("Error converting material to name: " + e.getMessage());
}
}
TNT false false Material class: org.bukkit.Material Error converting material to string: Range [7, 3) out of bounds for length 3 Error converting material to name: Range [7, 3) out of bounds for length 3
I am having some trouble detecting if I should play a fuse sound. Could someone explain how the above happens in 1.20/1.21? It's quite confusing to me. In the new versions blockChange.getAfter().getId() returns 0 always
It has to do with specifying an api-version in the plugin.yml says someone from papermc. I am completely inexperienced with the multi version material stuff. So I'd like to request some help from you @Jumper251
Here is my current code in the ReplayingUtils
private void setBlockChange(BlockChangeData blockChange) {
final Location loc = LocationData.toLocation(blockChange.getLocation());
if (ConfigManager.WORLD_RESET && !this.replayer.getBlockChanges().containsKey(loc)) {
this.replayer.getBlockChanges().put(loc, blockChange.getBefore());
}
new BukkitRunnable() {
@SuppressWarnings("deprecation")
@Override
public void run() {
if (blockChange.doPlayEffect()) {
if (blockChange.getAfter().getId() == 0 && blockChange.getBefore().getId() != 0 && MaterialBridge.fromID(blockChange.getBefore().getId()) != Material.FIRE && blockChange.getBefore().getId() != 11 && blockChange.getBefore().getId() != 9 && blockChange.getBefore().getId() != 10 && blockChange.getBefore().getId() != 8) {
loc.getWorld().playEffect(loc, Effect.STEP_SOUND, blockChange.getBefore().getId(), 15);
}
} else if (blockChange.doBlockChange()) {// && MaterialBridge.fromID(blockChange.getBefore().getId()) == Material.TNT
if (VersionUtil.isCompatible(VersionEnum.V1_8)) {
loc.getWorld().playSound(loc, Sound.valueOf("FUSE"), 1, 1);
} else {
System.out.println("PLAY FUZE");
Material material = getBlockMaterial(blockChange.getBefore());
if (material == null) {
System.out.println("Material is null");
} else {
// Log material details
System.out.println("Material: " + material);
System.out.println("Material class: " + material.getClass().getName());
System.out.println("Material.equals(Material.TNT): " + material.equals(Material.TNT));
System.out.println("Material hashCode: " + material.hashCode());
// Inspect methods and properties
try {
System.out.println("Material toString: " + material.toString());
} catch (Exception e) {
System.out.println("[AdvancedReplay] [STDOUT] Error converting material to string: ");
e.printStackTrace();
}
try {
System.out.println("Material name: " + material.name());
} catch (Exception e) {
System.out.println("[AdvancedReplay] [STDOUT] Error converting material to name: ");
e.printStackTrace();
}
// Additional checks if needed
try {
System.out.println("Material ordinal: " + material.ordinal());
} catch (Exception e) {
System.out.println("[AdvancedReplay] [STDOUT] Error accessing material ordinal: ");
e.printStackTrace();
}
}
loc.getWorld().playSound(loc, Sound.ENTITY_TNT_PRIMED, 1, 1);
}
}
int id = blockChange.getAfter().getId();
int subId = blockChange.getAfter().getSubId();
if (id == Material.STATIONARY_WATER.getId()) id = Material.WATER.getId();
if (id == Material.STATIONARY_LAVA.getId()) id = Material.LAVA.getId();
if (ConfigManager.REAL_CHANGES) {
if (VersionUtil.isCompatible(VersionEnum.V1_13) || VersionUtil.isCompatible(VersionEnum.V1_14) || VersionUtil.isCompatible(VersionEnum.V1_15) || VersionUtil.isCompatible(VersionEnum.V1_16) || VersionUtil.isCompatible(VersionEnum.V1_17) || VersionUtil.isCompatible(VersionEnum.V1_18) || VersionUtil.isCompatible(VersionEnum.V1_19) || VersionUtil.isCompatible(VersionEnum.V1_20) || VersionUtil.isCompatible(VersionEnum.V1_21)) {
loc.getBlock().setType(getBlockMaterial(blockChange.getAfter()), true);
} else {
loc.getBlock().setTypeIdAndData(id, (byte) subId, true);
}
} else if (blockChange.doBlockChange()) {
if (VersionUtil.isCompatible(VersionEnum.V1_13) || VersionUtil.isCompatible(VersionEnum.V1_14) || VersionUtil.isCompatible(VersionEnum.V1_15) || VersionUtil.isCompatible(VersionEnum.V1_16) || VersionUtil.isCompatible(VersionEnum.V1_17) || VersionUtil.isCompatible(VersionEnum.V1_18) || VersionUtil.isCompatible(VersionEnum.V1_19) || VersionUtil.isCompatible(VersionEnum.V1_20) || VersionUtil.isCompatible(VersionEnum.V1_21)) {
replayer.getWatchingPlayer().sendBlockChange(loc, getBlockMaterial(blockChange.getAfter()), (byte) subId);
} else {
replayer.getWatchingPlayer().sendBlockChange(loc, id, (byte) subId);
}
}
}
}.runTask(ReplaySystem.getInstance());
}
The goal is to check if the blockChange.getBefore() was TNT. If so, we need to play the fuse sound. This works in 1.8 with
&& MaterialBridge.fromID(blockChange.getBefore().getId()) == Material.TNT
But I cannot get it to work in the newer versions
At some point I want to switch to the new API, until then a workaround might be to directly acccess the SerializableItemStack in the BlockChangeData when above 1.13.
blockChange.getBefore().getItemStack().getItemStack().get("type").equals("TNT")
https://youtu.be/x3SuwYr0Oyk No sounds recorded unfortunately. But they work :)
As far as I am aware this pull request is ready to merge.
Looks good, thank you for the contribution. I will post the update in the next couple of days.
It'd be nice if this PR can become a end-crystal explosion support as well.
Forgive me for the formatting changes. It found the formatting is inconsistent and I've chosen the more common formatting.
This tracks igniting TNT by player, and the TNT that is triggered thereafter. It also sends a destroy packet for the TNT based on when it explodes because the fuseticks are a server side thing and the derived TNT has random fuse ticks.
I've tested this and it works pretty great. Only problem is that due to TNTPrimeEvent being bugged (in 1.8) we cannot track the TNT movement on spawn so well. Furthermore, TNT being launched by other TNT unfortunately does not show in the replay. But this is already much better than nothing.