Cleanup SpigotCore

This commit is contained in:
2026-05-15 14:02:27 +02:00
parent 13185f0e05
commit 060364abb5
94 changed files with 1168 additions and 6935 deletions
@@ -26,8 +26,8 @@ tasks.compileJava {
} }
java { java {
sourceCompatibility = JavaVersion.VERSION_17 sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_21
} }
dependencies { dependencies {
-28
View File
@@ -1,28 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
dependencies {
compileOnly(project(":SpigotCore:SpigotCore_Main", "default"))
compileOnly(libs.nms10)
}
-29
View File
@@ -1,29 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
dependencies {
compileOnly(project(":CommonCore", "default"))
compileOnly(project(":SpigotCore:SpigotCore_Main", "default"))
compileOnly(libs.nms12)
}
@@ -1,34 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerLocaleChangeEvent;
import java.util.Locale;
public class LocaleChangeWrapper12 implements LocaleChangeWrapper {
@EventHandler
private void onLocale(PlayerLocaleChangeEvent event) {
SteamwarUser.get(event.getPlayer().getUniqueId()).setLocale(Locale.forLanguageTag(event.getLocale()), false);
}
}
-32
View File
@@ -1,32 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
dependencies {
compileOnly(project(":CommonCore", "default"))
compileOnly(project(":SpigotCore:SpigotCore_Main", "default"))
compileOnly(project(":SpigotCore:SpigotCore_8", "default"))
compileOnly(project(":SpigotCore:SpigotCore_9", "default"))
compileOnly(libs.nms14)
compileOnly(libs.worldedit15)
}
@@ -1,361 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class FlatteningWrapper14 implements FlatteningWrapper.IFlatteningWrapper {
private static final Map<String, Material> renamedLegacy = new HashMap<>();
static{
renamedLegacy.put("WOOD", Material.OAK_WOOD);
renamedLegacy.put("SAPLING", Material.OAK_SAPLING);
renamedLegacy.put("STATIONARY_WATER", Material.WATER);
renamedLegacy.put("STATIONARY_LAVA", Material.LAVA);
renamedLegacy.put("LOG", Material.OAK_LOG);
renamedLegacy.put("LEAVES", Material.OAK_LEAVES);
renamedLegacy.put("BED_BLOCK", Material.RED_BED);
renamedLegacy.put("BED", Material.RED_BED);
renamedLegacy.put("PISTON_STICKY_BASE", Material.STICKY_PISTON);
renamedLegacy.put("WEB", Material.COBWEB);
renamedLegacy.put("LONG_GRASS", Material.TALL_GRASS);
renamedLegacy.put("PISTON_BASE", Material.PISTON);
renamedLegacy.put("PISTON_EXTENSION", Material.PISTON_HEAD);
renamedLegacy.put("WOOL", Material.WHITE_WOOL);
renamedLegacy.put("PISTON_MOVING_PIECE", Material.MOVING_PISTON);
renamedLegacy.put("YELLOW_FLOWER", Material.DANDELION);
renamedLegacy.put("RED_ROSE", Material.POPPY);
renamedLegacy.put("DOUBLE_STEP", Material.SMOOTH_STONE);
renamedLegacy.put("STEP", Material.SMOOTH_STONE_SLAB);
renamedLegacy.put("MOB_SPAWNER", Material.SPAWNER);
renamedLegacy.put("WOOD_STAIRS", Material.OAK_STAIRS);
renamedLegacy.put("WORKBENCH", Material.CRAFTING_TABLE);
renamedLegacy.put("CROPS", Material.WHEAT_SEEDS);
renamedLegacy.put("SEEDS", Material.WHEAT_SEEDS);
renamedLegacy.put("SOIL", Material.FARMLAND);
renamedLegacy.put("BURNING_FURNACE", Material.FURNACE);
renamedLegacy.put("SIGN_POST", Material.OAK_SIGN);
renamedLegacy.put("SIGN", Material.OAK_SIGN);
renamedLegacy.put("WOODEN_DOOR", Material.OAK_DOOR);
renamedLegacy.put("WOOD_DOOR", Material.OAK_DOOR);
renamedLegacy.put("RAILS", Material.RAIL);
renamedLegacy.put("WALL_SIGN", Material.OAK_WALL_SIGN);
renamedLegacy.put("STONE_PLATE", Material.STONE_PRESSURE_PLATE);
renamedLegacy.put("WOOD_PLATE", Material.OAK_PRESSURE_PLATE);
renamedLegacy.put("GLOWING_REDSTONE_ORE", Material.REDSTONE_ORE);
renamedLegacy.put("REDSTONE_TORCH_OFF", Material.REDSTONE_TORCH);
renamedLegacy.put("REDSTONE_TORCH_ON", Material.REDSTONE_TORCH);
renamedLegacy.put("IRON_DOOR_BLOCK", Material.IRON_DOOR);
renamedLegacy.put("SUGAR_CANE_BLOCK", Material.SUGAR_CANE);
renamedLegacy.put("CAKE_BLOCK", Material.CAKE);
renamedLegacy.put("MELON_BLOCK", Material.MELON);
renamedLegacy.put("BEETROOT_BLOCK", Material.BEETROOT);
renamedLegacy.put("FENCE", Material.OAK_FENCE);
renamedLegacy.put("PORTAL", Material.NETHER_PORTAL);
renamedLegacy.put("DIODE_BLOCK_OFF", Material.REPEATER);
renamedLegacy.put("DIODE_BLOCK_ON", Material.REPEATER);
renamedLegacy.put("DIODE", Material.REPEATER);
renamedLegacy.put("STAINED_GLASS", Material.WHITE_STAINED_GLASS);
renamedLegacy.put("TRAP_DOOR", Material.OAK_TRAPDOOR);
renamedLegacy.put("MONSTER_EGGS", Material.SKELETON_SPAWN_EGG);
renamedLegacy.put("MONSTER_EGG", Material.SKELETON_SPAWN_EGG);
renamedLegacy.put("SMOOTH_BRICK", Material.STONE_BRICKS);
renamedLegacy.put("HUGE_MUSHROOM_1", Material.MUSHROOM_STEM);
renamedLegacy.put("HUGE_MUSHROOM_2", Material.RED_MUSHROOM);
renamedLegacy.put("IRON_FENCE", Material.IRON_BARS);
renamedLegacy.put("THIN_GLASS", Material.GLASS_PANE);
renamedLegacy.put("FENCE_GATE", Material.OAK_FENCE_GATE);
renamedLegacy.put("SMOOTH_STAIRS", Material.STONE_BRICK_STAIRS);
renamedLegacy.put("MYCEL", Material.MYCELIUM);
renamedLegacy.put("WATER_LILY", Material.LILY_PAD);
renamedLegacy.put("NETHER_FENCE", Material.NETHER_BRICK_FENCE);
renamedLegacy.put("NETHER_WARTS", Material.NETHER_WART);
renamedLegacy.put("NETHER_STALK", Material.NETHER_WART);
renamedLegacy.put("ENCHANTMENT_TABLE", Material.ENCHANTING_TABLE);
renamedLegacy.put("ENDER_PORTAL", Material.END_PORTAL);
renamedLegacy.put("ENDER_PORTAL_FRAME", Material.END_PORTAL_FRAME);
renamedLegacy.put("ENDER_STONE", Material.END_STONE);
renamedLegacy.put("REDSTONE_LAMP_OFF", Material.REDSTONE_LAMP);
renamedLegacy.put("REDSTONE_LAMP_ON", Material.REDSTONE_LAMP);
renamedLegacy.put("WOOD_DOUBLE_STEP", Material.OAK_SLAB);
renamedLegacy.put("WOOD_STEP", Material.OAK_SLAB);
renamedLegacy.put("SPRUCE_WOOD_STAIRS", Material.SPRUCE_STAIRS);
renamedLegacy.put("BIRCH_WOOD_STAIRS", Material.BIRCH_STAIRS);
renamedLegacy.put("JUNGLE_WOOD_STAIRS", Material.JUNGLE_STAIRS);
renamedLegacy.put("COMMAND", Material.COMMAND_BLOCK);
renamedLegacy.put("COBBLE_WALL", Material.COBBLESTONE_WALL);
renamedLegacy.put("WOOD_BUTTON", Material.OAK_BUTTON);
renamedLegacy.put("SKULL", Material.SKELETON_SKULL);
renamedLegacy.put("SKULL_ITEM", Material.SKELETON_SKULL);
renamedLegacy.put("GOLD_PLATE", Material.LIGHT_WEIGHTED_PRESSURE_PLATE);
renamedLegacy.put("IRON_PLATE", Material.HEAVY_WEIGHTED_PRESSURE_PLATE);
renamedLegacy.put("REDSTONE_COMPARATOR_OFF", Material.COMPARATOR);
renamedLegacy.put("REDSTONE_COMPARATOR_ON", Material.COMPARATOR);
renamedLegacy.put("REDSTONE_COMPARATOR", Material.COMPARATOR);
renamedLegacy.put("QUARTZ_ORE", Material.QUARTZ);
renamedLegacy.put("STAINED_CLAY", Material.WHITE_TERRACOTTA);
renamedLegacy.put("STAINED_GLASS_PANE", Material.WHITE_STAINED_GLASS_PANE);
renamedLegacy.put("LEAVES_2", Material.ACACIA_LEAVES);
renamedLegacy.put("LOG_2", Material.ACACIA_LOG);
renamedLegacy.put("CARPET", Material.WHITE_CARPET);
renamedLegacy.put("HARD_CLAY", Material.TERRACOTTA);
renamedLegacy.put("DOUBLE_PLANT", Material.SUNFLOWER);
renamedLegacy.put("STANDING_BANNER", Material.WHITE_BANNER);
renamedLegacy.put("BANNER", Material.WHITE_BANNER);
renamedLegacy.put("WALL_BANNER", Material.WHITE_WALL_BANNER);
renamedLegacy.put("DAYLIGHT_DETECTOR_INVERTED", Material.DAYLIGHT_DETECTOR);
renamedLegacy.put("DOUBLE_STONE_SLAB2", Material.RED_SANDSTONE_SLAB);
renamedLegacy.put("STONE_SLAB2", Material.RED_SANDSTONE_SLAB);
renamedLegacy.put("PURPUR_DOUBLE_SLAB", Material.PURPUR_SLAB);
renamedLegacy.put("END_BRICKS", Material.END_STONE_BRICKS);
renamedLegacy.put("COMMAND_REPEATING", Material.REPEATING_COMMAND_BLOCK);
renamedLegacy.put("COMMAND_CHAIN", Material.CHAIN_COMMAND_BLOCK);
renamedLegacy.put("MAGMA", Material.MAGMA_BLOCK);
renamedLegacy.put("RED_NETHER_BRICK", Material.RED_NETHER_BRICKS);
renamedLegacy.put("SILVER_SHULKER_BOX", Material.LIGHT_GRAY_SHULKER_BOX);
renamedLegacy.put("SILVER_GLAZED_TERRACOTTA", Material.LIGHT_GRAY_TERRACOTTA);
renamedLegacy.put("CONCRETE", Material.WHITE_CONCRETE);
renamedLegacy.put("CONCRETE_POWDER", Material.WHITE_CONCRETE_POWDER);
renamedLegacy.put("IRON_SPADE", Material.IRON_SHOVEL);
renamedLegacy.put("WOOD_SWORD", Material.WOODEN_SWORD);
renamedLegacy.put("WOOD_SPADE", Material.WOODEN_SHOVEL);
renamedLegacy.put("WOOD_PICKAXE", Material.WOODEN_PICKAXE);
renamedLegacy.put("WOOD_AXE", Material.WOODEN_AXE);
renamedLegacy.put("STONE_SPADE", Material.STONE_SHOVEL);
renamedLegacy.put("DIAMOND_SPADE", Material.DIAMOND_SHOVEL);
renamedLegacy.put("MUSHROOM_SOUP", Material.MUSHROOM_STEW);
renamedLegacy.put("GOLD_SWORD", Material.GOLDEN_SWORD);
renamedLegacy.put("GOLD_SPADE", Material.GOLDEN_SHOVEL);
renamedLegacy.put("GOLD_PICKAXE", Material.GOLDEN_PICKAXE);
renamedLegacy.put("GOLD_AXE", Material.GOLDEN_AXE);
renamedLegacy.put("SULPHUR", Material.GUNPOWDER);
renamedLegacy.put("WOOD_HOE", Material.WOODEN_HOE);
renamedLegacy.put("GOLD_HOE", Material.GOLDEN_HOE);
renamedLegacy.put("GOLD_HELMET", Material.GOLDEN_HELMET);
renamedLegacy.put("GOLD_CHESTPLATE", Material.GOLDEN_CHESTPLATE);
renamedLegacy.put("GOLD_LEGGINGS", Material.GOLDEN_LEGGINGS);
renamedLegacy.put("GOLD_BOOTS", Material.GOLDEN_BOOTS);
renamedLegacy.put("PORK", Material.PORKCHOP);
renamedLegacy.put("GRILLED_PORK", Material.COOKED_PORKCHOP);
renamedLegacy.put("SNOW_BALL", Material.SNOWBALL);
renamedLegacy.put("BOAT", Material.OAK_BOAT);
renamedLegacy.put("CLAY_BRICK", Material.BRICKS);
renamedLegacy.put("STORAGE_MINECART", Material.CHEST_MINECART);
renamedLegacy.put("POWERED_MINECART", Material.FURNACE_MINECART);
renamedLegacy.put("WATCH", Material.CLOCK);
renamedLegacy.put("RAW_FISH", Material.SALMON);
renamedLegacy.put("COOKED_FISH", Material.COOKED_SALMON);
renamedLegacy.put("INK_SACK", Material.INK_SAC);
renamedLegacy.put("RAW_BEEF", Material.BEEF);
renamedLegacy.put("RAW_CHICKEN", Material.CHICKEN);
renamedLegacy.put("EYE_OF_ENDER", Material.ENDER_EYE);
renamedLegacy.put("SPECKLED_MELON", Material.GLISTERING_MELON_SLICE);
renamedLegacy.put("EXP_BOTTLE", Material.EXPERIENCE_BOTTLE);
renamedLegacy.put("FIREBALL", Material.FIRE_CHARGE);
renamedLegacy.put("BOOK_AND_QUILL", Material.WRITABLE_BOOK);
renamedLegacy.put("FLOWER_POT_ITEM", Material.FLOWER_POT);
renamedLegacy.put("EMPTY_MAP", Material.MAP);
renamedLegacy.put("BREWING_STAND_ITEM", Material.BREWING_STAND);
renamedLegacy.put("CAULDRON_ITEM", Material.CAULDRON);
renamedLegacy.put("CARROT_ITEM", Material.CARROT);
renamedLegacy.put("POTATO_ITEM", Material.POTATO);
renamedLegacy.put("SPRUCE_DOOR_ITEM", Material.SPRUCE_DOOR);
renamedLegacy.put("BIRCH_DOOR_ITEM", Material.BIRCH_DOOR);
renamedLegacy.put("JUNGLE_DOOR_ITEM", Material.JUNGLE_DOOR);
renamedLegacy.put("ACACIA_DOOR_ITEM", Material.ACACIA_DOOR);
renamedLegacy.put("DARK_OAK_DOOR_ITEM", Material.DARK_OAK_DOOR);
renamedLegacy.put("CARROT_STICK", Material.CARROT_ON_A_STICK);
renamedLegacy.put("FIREWORK", Material.FIREWORK_ROCKET);
renamedLegacy.put("FIREWORK_CHARGE", Material.FIREWORK_STAR);
renamedLegacy.put("NETHER_BRICK_ITEM", Material.NETHER_BRICKS);
renamedLegacy.put("EXPLOSIVE_MINECART", Material.TNT_MINECART);
renamedLegacy.put("IRON_BARDING", Material.IRON_HORSE_ARMOR);
renamedLegacy.put("GOLD_BARDING", Material.GOLDEN_HORSE_ARMOR);
renamedLegacy.put("DIAMOND_BARDING", Material.DIAMOND_HORSE_ARMOR);
renamedLegacy.put("LEASH", Material.LEAD);
renamedLegacy.put("COMMAND_MINECART", Material.COMMAND_BLOCK_MINECART);
renamedLegacy.put("CHORUS_FRUIT_POPPED", Material.POPPED_CHORUS_FRUIT);
renamedLegacy.put("DRAGONS_BREATH", Material.DRAGON_BREATH);
renamedLegacy.put("BOAT_SPRUCE", Material.SPRUCE_BOAT);
renamedLegacy.put("BOAT_BIRCH", Material.BIRCH_BOAT);
renamedLegacy.put("BOAT_JUNGLE", Material.JUNGLE_BOAT);
renamedLegacy.put("BOAT_ACACIA", Material.ACACIA_BOAT);
renamedLegacy.put("BOAT_DARK_OAK", Material.DARK_OAK_BOAT);
renamedLegacy.put("TOTEM", Material.TOTEM_OF_UNDYING);
renamedLegacy.put("GOLD_RECORD", Material.MUSIC_DISC_13);
renamedLegacy.put("GREEN_RECORD", Material.MUSIC_DISC_CAT);
renamedLegacy.put("RECORD_3", Material.MUSIC_DISC_BLOCKS);
renamedLegacy.put("RECORD_4", Material.MUSIC_DISC_CHIRP);
renamedLegacy.put("RECORD_5", Material.MUSIC_DISC_FAR);
renamedLegacy.put("RECORD_6", Material.MUSIC_DISC_MALL);
renamedLegacy.put("RECORD_7", Material.MUSIC_DISC_MELLOHI);
renamedLegacy.put("RECORD_8", Material.MUSIC_DISC_STAL);
renamedLegacy.put("RECORD_9", Material.MUSIC_DISC_STRAD);
renamedLegacy.put("RECORD_10", Material.MUSIC_DISC_WARD);
renamedLegacy.put("RECORD_11", Material.MUSIC_DISC_11);
renamedLegacy.put("RECORD_12", Material.MUSIC_DISC_WAIT);
}
private static final Reflection.Field<?> scoreboardName = Reflection.getField(FlatteningWrapper.scoreboardObjective, Reflection.getClass("net.minecraft.network.chat.Component"), 0);
@Override
public void setScoreboardTitle(Object packet, String title) {
scoreboardName.set(packet, ChatWrapper.impl.stringToChatComponent(title));
}
private static final Class<?> scoreActionEnum = Core.getVersion() < 21 ? Reflection.getClass("net.minecraft.server.ServerScoreboard$Method") : null;
private static final Reflection.Field<?> scoreAction = Core.getVersion() < 21 ? Reflection.getField(FlatteningWrapper.scoreboardScore, scoreActionEnum, 0) : null;
private static final Object scoreActionChange = Core.getVersion() < 21 ? scoreActionEnum.getEnumConstants()[0] : null;
@Override
public void setScoreAction(Object packet) {
scoreAction.set(packet, scoreActionChange);
}
@Override
public Material getMaterial(String material) {
try{
return Material.valueOf(material);
}catch(IllegalArgumentException e){
return renamedLegacy.get(material);
}
}
@Override
public Material getDye(int colorCode) {
switch(colorCode){
case 1:
return Material.RED_DYE;
case 2:
return Material.GREEN_DYE;
case 3:
return Material.BROWN_DYE;
case 4:
return Material.LAPIS_LAZULI;
case 5:
return Material.PURPLE_DYE;
case 6:
return Material.CYAN_DYE;
case 7:
return Material.LIGHT_GRAY_DYE;
case 8:
return Material.GRAY_DYE;
case 9:
return Material.PINK_DYE;
case 10:
return Material.LIME_DYE;
case 11:
return Material.YELLOW_DYE;
case 12:
return Material.LIGHT_BLUE_DYE;
case 13:
return Material.MAGENTA_DYE;
case 14:
return Material.ORANGE_DYE;
case 15:
return Material.WHITE_DYE;
default:
return Material.BLACK_DYE;
}
}
@SuppressWarnings("deprecation")
@Override
public ItemStack setSkullOwner(String player) {
ItemStack head = new ItemStack(Material.PLAYER_HEAD, 1);
SkullMeta headmeta = (SkullMeta) head.getItemMeta();
assert headmeta != null;
headmeta.setOwningPlayer(Bukkit.getOfflinePlayer(player.startsWith(".") ? player.substring(1) : player));
headmeta.setDisplayName(player);
head.setItemMeta(headmeta);
return head;
}
protected static final Class<?> entityPose = Reflection.getClass("net.minecraft.world.entity.Pose");
protected static final Object standing = entityPose.getEnumConstants()[0];
protected static final Object swimming = entityPose.getEnumConstants()[3];
protected static final Object sneaking = entityPose.getEnumConstants()[5];
@Override
public Object getPose(FlatteningWrapper.EntityPose pose) {
switch (pose) {
case SNEAKING:
return sneaking;
case SWIMMING:
return swimming;
case NORMAL:
default:
return standing;
}
}
@Override
public void setNamedSpawnPacketDataWatcher(Object packet) {
// field not present
}
@Override
public Object formatDisplayName(String displayName) {
return displayName != null ? Optional.of(ChatWrapper.impl.stringToChatComponent(displayName)) : Optional.empty();
}
private static final Class<?> registryBlocks = Reflection.getClass("net.minecraft.core.DefaultedRegistry");
private static final Class<?> entityTypes = Reflection.getClass("net.minecraft.world.entity.EntityType");
private static final Object entityTypesRegistry = Reflection.getField(Reflection.getClass(Core.getVersion() > 18 ? "net.minecraft.core.registries.BuiltInRegistries" : "net.minecraft.core.IRegistry"), registryBlocks, 0, entityTypes).get(null);
private static final Reflection.Method get = Reflection.getMethod(registryBlocks, null, Reflection.getClass("net.minecraft.resources.ResourceLocation"));
private static final Reflection.Field<?> spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, entityTypes, 0);
private static final Reflection.Field<?> spawnLivingType = Core.getVersion() > 18 ? spawnType : Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 1);
private static final Reflection.Method toMinecraft = Reflection.getMethod("org.bukkit.craftbukkit.util.CraftNamespacedKey", "toMinecraft", NamespacedKey.class);
private static final Map<EntityType, Object> types = new HashMap<>();
static {
types.put(EntityType.ARMOR_STAND, 1);
}
@Override
public void setSpawnPacketType(Object packet, EntityType type) {
if(type.isAlive()) {
spawnLivingType.set(packet, Core.getVersion() > 18 ? get.invoke(entityTypesRegistry, toMinecraft.invoke(null, type.getKey())) : types.get(type));
} else {
spawnType.set(packet, get.invoke(entityTypesRegistry, toMinecraft.invoke(null, type.getKey())));
}
}
@Override
public int getViewDistance(Player player) {
return player.getClientViewDistance();
}
private static final Reflection.Method getHandle = Reflection.getMethod("org.bukkit.craftbukkit.CraftWorld", "getHandle");
private static final Reflection.Method save = Reflection.getMethod("net.minecraft.server.level.ServerLevel", null, Reflection.getClass("net.minecraft.util.ProgressListener"), boolean.class, boolean.class);
@Override
public void syncSave(World world) {
save.invoke(getHandle.invoke(world), null, true, false);
}
}
@@ -1,30 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerRecipeDiscoverEvent;
public class RecipeDiscoverWrapper14 implements RecipeDiscoverWrapper {
@EventHandler
public void onRecipeDiscover(PlayerRecipeDiscoverEvent e) {
e.setCancelled(true);
}
}
@@ -1,30 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import org.bukkit.Material;
public class TrickyTrialsWrapper14 extends TrickyTrialsWrapper8 {
@Override
public Material getTurtleScute() {
return Material.SCUTE;
}
}
@@ -1,634 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.sk89q.jnbt.*;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.*;
import com.sk89q.worldedit.extent.clipboard.io.legacycompat.*;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.registry.LegacyMapper;
import de.steamwar.sql.NoClipboardException;
import de.steamwar.sql.NodeData;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
@SuppressWarnings("removal")
public class WorldEditWrapper14 implements WorldEditWrapper {
@Override
public InputStream getPlayerClipboard(Player player) {
return WorldEditWrapper.getPlayerClipboard(player, (outputStream, clipboard, clipboardHolder) -> {
ClipboardWriter writer = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(outputStream);
writer.write(clipboard);
writer.close();
});
}
@Override
public void setPlayerClipboard(Player player, Clipboard clipboard) {
Actor actor = WorldEditWrapper.getWorldEditPlugin().wrapCommandSender(player);
WorldEditWrapper.getWorldEditPlugin().getWorldEdit().getSessionManager().get(actor).setClipboard(new ClipboardHolder(clipboard));
}
@Override
public Clipboard getClipboard(NodeData data) throws IOException {
InputStream is = data.schemData(true);
return readClipboard(is, data.getNodeFormat());
}
@Override
public Clipboard getClipboard(InputStream inputStream) throws IOException {
return readClipboard(inputStream, getNativeFormat());
}
private Clipboard readClipboard(InputStream is, NodeData.SchematicFormat format) throws IOException {
switch (format) {
case SPONGE_V2:
case SPONGE_V3:
return new SpongeSchematicReader(new NBTInputStream(is), this).read();
case MCEDIT:
return new MCEditSchematicReader(new NBTInputStream(is)).read();
default:
throw new IOException("This schematic format is currently not supported");
}
}
@Override
public org.bukkit.util.Vector getOrigin(Clipboard clipboard) {
return new org.bukkit.util.Vector(clipboard.getOrigin().getX(), clipboard.getOrigin().getY(), clipboard.getOrigin().getZ());
}
@Override
public Vector getMinimum(Region region) {
return new Vector(region.getMinimumPoint().getX(), region.getMinimumPoint().getY(), region.getMinimumPoint().getZ());
}
@Override
public Vector getMaximum(Region region) {
return new Vector(region.getMaximumPoint().getX(), region.getMaximumPoint().getY(), region.getMaximumPoint().getZ());
}
@Override
public Vector applyTransform(Vector vector, Transform transform) {
Vector3 v = Vector3.at(vector.getX(), vector.getY(), vector.getZ());
v = transform.apply(v);
return new org.bukkit.util.Vector(v.getX(), v.getY(), v.getZ());
}
@Override
public NodeData.SchematicFormat getNativeFormat() {
return NodeData.SchematicFormat.SPONGE_V2;
}
public Map<String, Tag> applyDataFixer(DataFixer fixer, int dataVersion, Map<String, Tag> values) {
return fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values), dataVersion).getValue();
}
private static class MCEditSchematicReader extends NBTSchematicReader {
private final NBTInputStream inputStream;
private final DataFixer fixer;
private boolean faweSchem = false;
private static final ImmutableList<NBTCompatibilityHandler> COMPATIBILITY_HANDLERS
= ImmutableList.of(
new SignCompatibilityHandler(),
new FlowerPotCompatibilityHandler(),
new NoteBlockCompatibilityHandler(),
new SkullBlockCompatibilityHandler()
);
/**
* Create a new instance.
*
* @param inputStream the input stream to read from
*/
MCEditSchematicReader(NBTInputStream inputStream) {
checkNotNull(inputStream);
this.inputStream = inputStream;
this.fixer = null;
}
@Override
public Clipboard read() throws IOException {
// Schematic tag
NamedTag rootTag = inputStream.readNamedTag();
if (!rootTag.getName().equals("Schematic")) {
throw new IOException("Tag 'Schematic' does not exist or is not first");
}
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
// Check
Map<String, Tag> schematic = schematicTag.getValue();
if (!schematic.containsKey("Blocks")) {
throw new IOException("Schematic file is missing a 'Blocks' tag");
}
// Check type of Schematic
String materials = requireTag(schematic, "Materials", StringTag.class).getValue();
if (!materials.equals("Alpha")) {
throw new IOException("Schematic file is not an Alpha schematic");
}
// ====================================================================
// Metadata
// ====================================================================
BlockVector3 origin;
Region region;
// Get information
short width = requireTag(schematic, "Width", ShortTag.class).getValue();
short height = requireTag(schematic, "Height", ShortTag.class).getValue();
short length = requireTag(schematic, "Length", ShortTag.class).getValue();
int originX = 0;
int originY = 0;
int originZ = 0;
try {
originX = requireTag(schematic, "WEOriginX", IntTag.class).getValue();
originY = requireTag(schematic, "WEOriginY", IntTag.class).getValue();
originZ = requireTag(schematic, "WEOriginZ", IntTag.class).getValue();
BlockVector3 min = BlockVector3.at(originX, originY, originZ);
int offsetX = requireTag(schematic, "WEOffsetX", IntTag.class).getValue();
int offsetY = requireTag(schematic, "WEOffsetY", IntTag.class).getValue();
int offsetZ = requireTag(schematic, "WEOffsetZ", IntTag.class).getValue();
BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ);
origin = min.subtract(offset);
region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE));
} catch (IOException ignored) {
origin = BlockVector3.ZERO;
region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE));
}
// ====================================================================
// Blocks
// ====================================================================
// Get blocks
byte[] blockId = requireTag(schematic, "Blocks", ByteArrayTag.class).getValue();
byte[] blockData = requireTag(schematic, "Data", ByteArrayTag.class).getValue();
byte[] addId = new byte[0];
short[] blocks = new short[blockId.length]; // Have to later combine IDs
// We support 4096 block IDs using the same method as vanilla Minecraft, where
// the highest 4 bits are stored in a separate byte array.
if (schematic.containsKey("AddBlocks")) {
addId = requireTag(schematic, "AddBlocks", ByteArrayTag.class).getValue();
}
// Combine the AddBlocks data with the first 8-bit block ID
for (int index = 0; index < blockId.length; index++) {
if ((index >> 1) >= addId.length) { // No corresponding AddBlocks index
blocks[index] = (short) (blockId[index] & 0xFF);
} else {
if ((index & 1) == 0) {
blocks[index] = (short) (((addId[index >> 1] & 0x0F) << 8) + (blockId[index] & 0xFF));
} else {
blocks[index] = (short) (((addId[index >> 1] & 0xF0) << 4) + (blockId[index] & 0xFF));
}
}
}
// Need to pull out tile entities
final ListTag tileEntityTag = getTag(schematic, "TileEntities", ListTag.class);
List<Tag> tileEntities = tileEntityTag == null ? new ArrayList<>() : tileEntityTag.getValue();
Map<BlockVector3, Map<String, Tag>> tileEntitiesMap = new HashMap<>();
Map<BlockVector3, BlockState> blockStates = new HashMap<>();
for (Tag tag : tileEntities) {
if (!(tag instanceof CompoundTag)) continue;
CompoundTag t = (CompoundTag) tag;
int x = t.getInt("x");
int y = t.getInt("y");
int z = t.getInt("z");
int index = y * width * length + z * width + x;
if(index < 0 || index >= blocks.length)
faweSchem = true;
}
for (Tag tag : tileEntities) {
if (!(tag instanceof CompoundTag)) continue;
CompoundTag t = (CompoundTag) tag;
Map<String, Tag> values = new HashMap<>(t.getValue());
String id = t.getString("id");
values.put("id", new StringTag(convertBlockEntityId(id)));
int x = t.getInt("x");
int y = t.getInt("y");
int z = t.getInt("z");
if(faweSchem){
x -= originX;
y -= originY;
z -= originZ;
}
int index = y * width * length + z * width + x;
try{
BlockState block = getBlockState(blocks[index], blockData[index]);
BlockState newBlock = block;
if (newBlock != null) {
for (NBTCompatibilityHandler handler : COMPATIBILITY_HANDLERS) {
if (handler.isAffectedBlock(newBlock)) {
newBlock = handler.updateNBT(block, values);
if (newBlock == null || values.isEmpty()) {
break;
}
}
}
}
if (values.isEmpty()) {
t = null;
} else {
t = new CompoundTag(values);
}
if (fixer != null && t != null) {
t = fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, t, -1);
}
BlockVector3 vec = BlockVector3.at(x, y, z);
if (t != null) {
tileEntitiesMap.put(vec, t.getValue());
}
blockStates.put(vec, newBlock);
}catch(ArrayIndexOutOfBoundsException e){
//ignored
}
}
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(origin);
for (int x = 0; x < width; ++x) {
for (int y = 0; y < height; ++y) {
for (int z = 0; z < length; ++z) {
int index = y * width * length + z * width + x;
BlockVector3 pt = BlockVector3.at(x, y, z);
BlockState state = blockStates.computeIfAbsent(pt, p -> getBlockState(blocks[index], blockData[index]));
try {
if (state != null) {
if (tileEntitiesMap.containsKey(pt)) {
clipboard.setBlock(region.getMinimumPoint().add(pt), state.toBaseBlock(new CompoundTag(tileEntitiesMap.get(pt))));
} else {
clipboard.setBlock(region.getMinimumPoint().add(pt), state);
}
}
} catch (WorldEditException ignored) { // BlockArrayClipboard won't throw this
}
}
}
}
return clipboard;
}
private String convertBlockEntityId(String id) {
switch (id) {
case "Cauldron":
return "brewing_stand";
case "Control":
return "command_block";
case "DLDetector":
return "daylight_detector";
case "Trap":
return "dispenser";
case "EnchantTable":
return "enchanting_table";
case "EndGateway":
return "end_gateway";
case "AirPortal":
return "end_portal";
case "EnderChest":
return "ender_chest";
case "FlowerPot":
return "flower_pot";
case "RecordPlayer":
return "jukebox";
case "MobSpawner":
return "mob_spawner";
case "Music":
case "noteblock":
return "note_block";
case "Structure":
return "structure_block";
case "Chest":
return "chest";
case "Sign":
return "sign";
case "Banner":
return "banner";
case "Beacon":
return "beacon";
case "Comparator":
return "comparator";
case "Dropper":
return "dropper";
case "Furnace":
return "furnace";
case "Hopper":
return "hopper";
case "Skull":
return "skull";
default:
return id;
}
}
private BlockState getBlockState(int id, int data) {
return LegacyMapper.getInstance().getBlockFromLegacy(id, data);
}
@Override
public void close() throws IOException {
inputStream.close();
}
}
public static class SpongeSchematicReader extends NBTSchematicReader {
private final NBTInputStream inputStream;
private DataFixer fixer = null;
private int schematicVersion = -1;
private int dataVersion = -1;
private boolean faweSchem = false;
private final WorldEditWrapper14 wrapper;
/**
* Create a new instance.
*
* @param inputStream the input stream to read from
*/
public SpongeSchematicReader(NBTInputStream inputStream, WorldEditWrapper14 wrapper) {
checkNotNull(inputStream);
this.inputStream = inputStream;
this.wrapper = wrapper;
}
@Override
public Clipboard read() throws IOException {
CompoundTag schematicTag = getBaseTag();
Map<String, Tag> schematic = schematicTag.getValue();
final Platform platform = WorldEdit.getInstance().getPlatformManager()
.queryCapability(Capability.WORLD_EDITING);
int liveDataVersion = platform.getDataVersion();
if (schematicVersion == 1) {
dataVersion = 1631; // this is a relatively safe assumption unless someone imports a schematic from 1.12, e.g. sponge 7.1-
fixer = platform.getDataFixer();
return readVersion1(schematicTag);
} else if (schematicVersion == 2 || schematicVersion == 3) {
dataVersion = requireTag(schematic, "DataVersion", IntTag.class).getValue();
if (dataVersion < liveDataVersion) {
fixer = platform.getDataFixer();
}
return readVersion1(schematicTag);
}
throw new IOException("This schematic version is currently not supported");
}
@Override
public OptionalInt getDataVersion() {
try {
CompoundTag schematicTag = getBaseTag();
Map<String, Tag> schematic = schematicTag.getValue();
if (schematicVersion == 1) {
return OptionalInt.of(1631);
} else if (schematicVersion == 2) {
return OptionalInt.of(requireTag(schematic, "DataVersion", IntTag.class).getValue());
}
return OptionalInt.empty();
} catch (IOException e) {
return OptionalInt.empty();
}
}
private CompoundTag getBaseTag() throws IOException {
NamedTag rootTag = inputStream.readNamedTag();
CompoundTag schematicTag = (CompoundTag) rootTag.getTag();
// Check
Map<String, Tag> schematic = schematicTag.getValue();
if (schematic.size() == 1) {
schematicTag = requireTag(schematic, "Schematic", CompoundTag.class);
schematic = schematicTag.getValue();
} else if (!rootTag.getName().equals("Schematic")) {
throw new IOException("Tag 'Schematic' does not exist or is not first");
}
schematicVersion = requireTag(schematic, "Version", IntTag.class).getValue();
return schematicTag;
}
private BlockArrayClipboard readVersion1(CompoundTag schematicTag) throws IOException {
BlockVector3 origin;
Region region;
Map<String, Tag> schematic = schematicTag.getValue();
int width = requireTag(schematic, "Width", ShortTag.class).getValue();
int height = requireTag(schematic, "Height", ShortTag.class).getValue();
int length = requireTag(schematic, "Length", ShortTag.class).getValue();
IntArrayTag offsetTag = getTag(schematic, "Offset", IntArrayTag.class);
int[] offsetParts;
if (offsetTag != null) {
offsetParts = offsetTag.getValue();
if (offsetParts.length != 3) {
throw new IOException("Invalid offset specified in schematic.");
}
} else {
offsetParts = new int[] {0, 0, 0};
}
BlockVector3 min = BlockVector3.at(offsetParts[0], offsetParts[1], offsetParts[2]);
CompoundTag metadataTag = getTag(schematic, "Metadata", CompoundTag.class);
int offsetX = 0;
int offsetY = 0;
int offsetZ = 0;
if (metadataTag != null && metadataTag.containsKey("WEOffsetX")) {
// We appear to have WorldEdit Metadata
Map<String, Tag> metadata = metadataTag.getValue();
offsetX = requireTag(metadata, "WEOffsetX", IntTag.class).getValue();
offsetY = requireTag(metadata, "WEOffsetY", IntTag.class).getValue();
offsetZ = requireTag(metadata, "WEOffsetZ", IntTag.class).getValue();
BlockVector3 offset = BlockVector3.at(offsetX, offsetY, offsetZ);
origin = min.subtract(offset);
region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector3.ONE));
} else {
origin = min;
region = new CuboidRegion(origin, origin.add(width, height, length).subtract(BlockVector3.ONE));
}
Map<String, Tag> blockContainer = null;
boolean v3Mode = false;
if (schematicVersion == 3) {
blockContainer = requireTag(schematic, "Blocks", CompoundTag.class).getValue();
v3Mode = true;
}
Map<String, Tag> paletteObject = requireTag(v3Mode ? blockContainer: schematic, "Palette", CompoundTag.class).getValue();
Map<Integer, BlockState> palette = new HashMap<>();
ParserContext parserContext = new ParserContext();
parserContext.setRestricted(false);
parserContext.setTryLegacy(false);
parserContext.setPreferringWildcard(false);
for (String palettePart : paletteObject.keySet()) {
int id = requireTag(paletteObject, palettePart, IntTag.class).getValue();
if (fixer != null) {
palettePart = fixer.fixUp(DataFixer.FixTypes.BLOCK_STATE, palettePart, dataVersion);
}
BlockState state;
try {
state = WorldEdit.getInstance().getBlockFactory().parseFromInput(palettePart, parserContext).toImmutableState();
} catch (InputParseException e) {
state = BlockTypes.AIR.getDefaultState();
}
palette.put(id, state);
}
byte[] blocks = requireTag(v3Mode ? blockContainer: schematic, v3Mode ? "Data" : "BlockData", ByteArrayTag.class).getValue();
Map<BlockVector3, Map<String, Tag>> tileEntitiesMap = new HashMap<>();
ListTag tileEntities = getTag(v3Mode ? blockContainer: schematic, "BlockEntities", ListTag.class);
if (tileEntities == null) {
tileEntities = getTag(v3Mode ? blockContainer: schematic, "TileEntities", ListTag.class);
}
if (tileEntities != null) {
List<Map<String, Tag>> tileEntityTags = tileEntities.getValue().stream()
.map(tag -> (CompoundTag) tag)
.map(CompoundTag::getValue)
.collect(Collectors.toList());
for (Map<String, Tag> tileEntity : tileEntityTags) {
int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue();
if(pos[0] < 0 || pos[0] >= width || pos[1] < 0 || pos[1] >= height || pos[2] < 0 || pos[2] >= length)
faweSchem = true;
}
for (Map<String, Tag> tileEntity : tileEntityTags) {
int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue();
final BlockVector3 pt = BlockVector3.at(pos[0], pos[1], pos[2]);
Map<String, Tag> values = Maps.newHashMap(v3Mode ? requireTag(tileEntity, "Data", CompoundTag.class).getValue() : tileEntity);
if(faweSchem){
values.put("x", new IntTag(pt.getBlockX() - offsetX));
values.put("y", new IntTag(pt.getBlockY() - offsetY));
values.put("z", new IntTag(pt.getBlockZ() - offsetZ));
}else{
values.putIfAbsent("x", new IntTag(pt.getBlockX()));
values.putIfAbsent("y", new IntTag(pt.getBlockY()));
values.putIfAbsent("z", new IntTag(pt.getBlockZ()));
}
values.putIfAbsent("id", values.get("Id"));
values.remove("Id");
values.remove("Pos");
if (fixer != null) {
tileEntity = wrapper.applyDataFixer(fixer, dataVersion, values);
} else {
tileEntity = values;
}
tileEntitiesMap.put(pt, tileEntity);
}
}
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(origin);
int index = 0;
int i = 0;
int value;
int varintLength;
while (i < blocks.length) {
value = 0;
varintLength = 0;
while (true) {
value |= (blocks[i] & 127) << (varintLength++ * 7);
if (varintLength > 5) {
throw new IOException("VarInt too big (probably corrupted data)");
}
if ((blocks[i] & 128) != 128) {
i++;
break;
}
i++;
}
// index = (y * length * width) + (z * width) + x
int y = index / (width * length);
int z = (index % (width * length)) / width;
int x = (index % (width * length)) % width;
BlockState state = palette.get(value);
BlockVector3 pt = BlockVector3.at(x, y, z);
try {
if (tileEntitiesMap.containsKey(pt)) {
clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state.toBaseBlock(new CompoundTag(tileEntitiesMap.get(pt))));
} else {
clipboard.setBlock(clipboard.getMinimumPoint().add(pt), state);
}
} catch (WorldEditException e) {
throw new IOException("Failed to load a block in the schematic");
}
index++;
}
return clipboard;
}
@Override
public void close() throws IOException {
inputStream.close();
}
}
}
@@ -1,73 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
import de.steamwar.Reflection;
import com.google.common.collect.ImmutableList;
import org.bukkit.Material;
import java.util.HashSet;
import java.util.Set;
public class BlockIds14 implements BlockIds {
private static final Class<?> blockStateList = Reflection.getClass("net.minecraft.world.level.block.state.StateDefinition");
private static final Class<?> fluidTypeFlowing = Reflection.getClass("net.minecraft.world.level.material.FlowingFluid");
private static final Class<?> fluid = Reflection.getClass("net.minecraft.world.level.material.FluidState");
private static final Reflection.Method getBlockData = Reflection.getTypedMethod(TechHider.block, null, TechHider.iBlockData);
@Override
public int materialToId(Material material) {
return getCombinedId(getBlockData.invoke(getBlock(material)));
}
private static final Reflection.Method getStates = Reflection.getTypedMethod(TechHider.block, null, blockStateList);
private static final Reflection.Method getStateList = Reflection.getTypedMethod(blockStateList, null, ImmutableList.class);
private static final Object water = Reflection.getTypedMethod(fluidTypeFlowing, null, fluid, boolean.class).invoke(Reflection.getField(Reflection.getClass("net.minecraft.world.level.material.Fluids"), fluidTypeFlowing, 1).get(null), false);
private static final Iterable<?> registryBlockId = (Iterable<?>) Reflection.getField(TechHider.block, Reflection.getClass("net.minecraft.core.IdMapper"), 0).get(null);
private static final Reflection.Method getFluid = Reflection.getTypedMethod(TechHider.iBlockData, null, fluid);
@Override
public Set<Integer> materialToAllIds(Material material) {
Set<Integer> ids = new HashSet<>();
for(Object data : (ImmutableList<?>) getStateList.invoke(getStates.invoke(getBlock(material)))) {
ids.add(getCombinedId(data));
}
if(material == Material.WATER) {
for(Object data : registryBlockId) {
if(getFluid.invoke(data) == water) {
ids.add(getCombinedId(data));
}
}
}
return ids;
}
private static final Reflection.Method getBlock = Reflection.getTypedMethod(TechHider.craftMagicNumbers, "getBlock", TechHider.block, Material.class);
private Object getBlock(Material material) {
return getBlock.invoke(null, material);
}
@Override
public int getCombinedId(Object blockData) {
return (int) getCombinedId.invoke(null, blockData);
}
}
@@ -1,44 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
public class ChunkHider14 extends ChunkHider9 {
@Override
protected void dataHider(SectionHider section) {
section.copyBlockCount();
section.copyBitsPerBlock();
boolean hasPalette = section.getBitsPerBlock() < 9;
if(hasPalette)
section.processPalette();
if(section.isSkipSection()) {
section.skipDataArray();
} else {
if(hasPalette && !section.blockPrecise()) {
section.skipDataArray();
return;
}
processDataArray(section);
}
}
}
@@ -1,55 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
import de.steamwar.Reflection;
import org.bukkit.entity.Player;
import java.util.function.BiFunction;
import java.util.function.UnaryOperator;
public class ProtocolWrapper14 extends ProtocolWrapper8 {
@Override
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider) {
UnaryOperator<Object> blockBreakCloner = ProtocolUtils.shallowCloneGenerator(blockBreakPacket);
Reflection.Field<?> blockBreakPosition = Reflection.getField(blockBreakPacket, TechHider.blockPosition, 0);
Reflection.Field<?> blockBreakBlockData = Reflection.getField(blockBreakPacket, TechHider.iBlockData, 0);
return (p, packet) -> {
switch (techHider.getLocationEvaluator().checkBlockPos(p, blockBreakPosition.get(packet))) {
case SKIP:
return packet;
case CHECK:
if(!techHider.iBlockDataHidden(blockBreakBlockData.get(packet)))
return packet;
case HIDE:
packet = blockBreakCloner.apply(packet);
blockBreakBlockData.set(packet, techHider.getObfuscationTarget());
return packet;
case HIDE_AIR:
default:
packet = blockBreakCloner.apply(packet);
blockBreakBlockData.set(packet, TechHider.AIR);
return packet;
}
};
}
}
-28
View File
@@ -1,28 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
dependencies {
compileOnly(project(":SpigotCore:SpigotCore_Main", "default"))
compileOnly(libs.nms15)
}
-40
View File
@@ -1,40 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
tasks.compileJava {
options.isWarnings = false
}
dependencies {
compileOnly(project(":CommonCore", "default"))
compileOnly(project(":SpigotCore:SpigotCore_Main", "default"))
compileOnly(project(":SpigotCore:SpigotCore_14", "default"))
compileOnly(libs.spigotapi)
compileOnly(libs.nms18)
compileOnly(libs.fawe18)
compileOnly(libs.datafixer)
compileOnly(libs.netty)
compileOnly(libs.authlib)
}
@@ -1,40 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.world.level.World;
import net.minecraft.world.level.chunk.Chunk;
import net.minecraft.world.level.lighting.LightEngine;
import org.bukkit.entity.Player;
public class CraftbukkitWrapper18 implements CraftbukkitWrapper.ICraftbukkitWrapper {
private static final Reflection.Method getHandle = Reflection.getMethod("org.bukkit.craftbukkit.CraftChunk", "getHandle");
private static final Reflection.Method getLightEngine = Reflection.getTypedMethod(World.class, null, LightEngine.class);
@Override
public void sendChunk(Player p, int chunkX, int chunkZ) {
Chunk chunk = (Chunk) getHandle.invoke(p.getWorld().getChunkAt(chunkX, chunkZ));
TinyProtocol.instance.sendPacket(p, new ClientboundLevelChunkWithLightPacket(chunk, (LightEngine) getLightEngine.invoke(chunk.q), null, null, false, true));
}
}
@@ -1,61 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Pair;
import org.bukkit.GameMode;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
public class ProtocolWrapper18 implements ProtocolWrapper {
private static final Reflection.Field<List> equipmentStack = Reflection.getField(equipmentPacket, List.class, 0);
@Override
public void setEquipmentPacketStack(Object packet, Object slot, Object stack) {
equipmentStack.set(packet, Collections.singletonList(new Pair<>(slot, stack)));
}
private static final Class<?> playerInfoPacket = Reflection.getClass("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo");
private static final Class<?> playerInfoActionClass = Reflection.getClass("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo$EnumPlayerInfoAction");
private static final Reflection.Field<?> playerInfoAction = Reflection.getField(playerInfoPacket, playerInfoActionClass, 0);
private static final Reflection.Field<List> playerInfoData = Reflection.getField(playerInfoPacket, List.class, 0);
private static final EnumMap<PlayerInfoAction, Object> actions = new EnumMap<>(PlayerInfoAction.class);
static {
Object[] nativeActions = playerInfoActionClass.getEnumConstants();
actions.put(PlayerInfoAction.ADD, nativeActions[0]);
actions.put(PlayerInfoAction.GAMEMODE, nativeActions[1]);
actions.put(PlayerInfoAction.REMOVE, nativeActions[4]);
}
private static final Class<?> iChatBaseComponent = Reflection.getClass("net.minecraft.network.chat.Component");
private static final Reflection.Constructor playerInfoDataConstructor = Reflection.getConstructor("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo$PlayerInfoData", GameProfile.class, int.class, enumGamemode, iChatBaseComponent);
@Override
@SuppressWarnings("deprecation")
public Object playerInfoPacketConstructor(PlayerInfoAction action, GameProfile profile, GameMode mode) {
Object packet = Reflection.newInstance(playerInfoPacket);
playerInfoAction.set(packet, actions.get(action));
playerInfoData.set(packet, Collections.singletonList(playerInfoDataConstructor.invoke(profile, 0, ProtocolWrapper.getGameModeById.invoke(null, mode.getValue()), null)));
return packet;
}
}
@@ -1,36 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import com.sk89q.jnbt.AdventureNBTConverter;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.world.DataFixer;
import java.util.Map;
public class WorldEditWrapper18 extends WorldEditWrapper14 {
@Override
@SuppressWarnings("removal")
public Map<String, Tag> applyDataFixer(DataFixer fixer, int dataVersion, Map<String, Tag> values) {
return ((CompoundTag) AdventureNBTConverter.fromAdventure(fixer.fixUp(DataFixer.FixTypes.BLOCK_ENTITY, new CompoundTag(values).asBinaryTag(), dataVersion))).getValue();
}
}
@@ -1,152 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
import de.steamwar.Reflection;
import de.steamwar.core.Core;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.core.IRegistry;
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.resources.MinecraftKey;
import net.minecraft.util.SimpleBitStorage;
import net.minecraft.world.level.block.entity.TileEntityTypes;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
public class ChunkHider18 implements ChunkHider {
@Override
public Class<?> mapChunkPacket() {
return ClientboundLevelChunkWithLightPacket.class;
}
private static final UnaryOperator<Object> chunkPacketCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkWithLightPacket.class);
private static final UnaryOperator<Object> chunkDataCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkPacketData.class);
private static final Reflection.Field<Integer> chunkXField = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 0);
private static final Reflection.Field<Integer> chunkZField = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 1);
private static final Reflection.Field<ClientboundLevelChunkPacketData> chunkData = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class, 0);
private static final Reflection.Field<byte[]> dataField = Reflection.getField(ClientboundLevelChunkPacketData.class, byte[].class, 0);
private static final Reflection.Field<List> tileEntities = Reflection.getField(ClientboundLevelChunkPacketData.class, List.class, 0);
@Override
public BiFunction<Player, Object, Object> chunkHiderGenerator(TechHider techHider) {
return (p, packet) -> {
int chunkX = chunkXField.get(packet);
int chunkZ = chunkZField.get(packet);
if (techHider.getLocationEvaluator().skipChunk(p, chunkX, chunkZ))
return packet;
packet = chunkPacketCloner.apply(packet);
Object dataWrapper = chunkDataCloner.apply(chunkData.get(packet));
Set<String> hiddenBlockEntities = techHider.getHiddenBlockEntities();
tileEntities.set(dataWrapper, ((List<?>)tileEntities.get(dataWrapper)).stream().filter(te -> tileEntityVisible(hiddenBlockEntities, te)).collect(Collectors.toList()));
ByteBuf in = Unpooled.wrappedBuffer(dataField.get(dataWrapper));
ByteBuf out = Unpooled.buffer(in.readableBytes() + 64);
for(int yOffset = p.getWorld().getMinHeight(); yOffset < p.getWorld().getMaxHeight(); yOffset += 16) {
SectionHider section = new SectionHider(p, techHider, in, out, chunkX, yOffset/16, chunkZ);
section.copyBlockCount();
blocks(section);
biomes(section);
}
out.writeBytes(in); // MC appends a 0 byte at the end if there is a full chunk, idk why
byte[] data = new byte[out.readableBytes()];
out.readBytes(data);
dataField.set(dataWrapper, data);
chunkData.set(packet, dataWrapper);
return packet;
};
}
public static final Class<?> tileEntity = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo");
protected static final Reflection.Field<TileEntityTypes> entityType = Reflection.getField(tileEntity, TileEntityTypes.class, 0);
private static final IRegistry<?> tileEntityTypes = Reflection.getField(Core.getVersion() > 18 ? Reflection.getClass("net.minecraft.core.registries.BuiltInRegistries") : IRegistry.class, IRegistry.class, 0, TileEntityTypes.class).get(null);
private static final Reflection.Method getKey = Reflection.getTypedMethod(IRegistry.class, null, MinecraftKey.class, Object.class);
private static final Reflection.Method getName = Reflection.getTypedMethod(MinecraftKey.class, null, String.class);
protected boolean tileEntityVisible(Set<String> hiddenBlockEntities, Object tile) {
return !hiddenBlockEntities.contains((String) getName.invoke(getKey.invoke(tileEntityTypes, entityType.get(tile))));
}
private void blocks(SectionHider section) {
section.copyBitsPerBlock();
boolean singletonPalette = section.getBitsPerBlock() == 0;
if(singletonPalette) {
int value = ProtocolUtils.readVarInt(section.getIn());
ProtocolUtils.writeVarInt(section.getOut(), !section.isSkipSection() && section.getObfuscate().contains(value) ? section.getTarget() : value);
}else if(section.getBitsPerBlock() < 15) {
section.processPalette();
}
if(section.isSkipSection() || singletonPalette || (!section.blockPrecise() && section.isPaletted())) {
section.skipDataArray();
return;
}
SimpleBitStorage values = new SimpleBitStorage(section.getBitsPerBlock(), 4096, section.readDataArray());
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int pos = (((y * 16) + z) * 16) + x;
switch (section.test(x, y, z)) {
case SKIP:
break;
case CHECK:
if(!section.getObfuscate().contains(values.a(pos)))
break;
case HIDE:
values.b(pos, section.getTarget());
break;
case HIDE_AIR:
default:
values.b(pos, section.getAir());
}
}
}
}
section.writeDataArray(values.a());
}
private void biomes(SectionHider section) {
section.copyBitsPerBlock();
boolean singletonPalette = section.getBitsPerBlock() == 0;
if(singletonPalette)
section.copyVarInt();
else if(section.getBitsPerBlock() < 6)
section.skipPalette();
section.skipDataArray();
}
}
@@ -1,109 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
import de.steamwar.Reflection;
import net.minecraft.core.SectionPosition;
import net.minecraft.network.protocol.game.PacketPlayOutBlockBreak;
import net.minecraft.world.level.block.entity.TileEntitySign;
import net.minecraft.world.level.block.entity.TileEntityTypes;
import net.minecraft.world.level.block.state.IBlockData;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.function.BiFunction;
public class ProtocolWrapper18 implements ProtocolWrapper {
private static final Reflection.Field<SectionPosition> multiBlockChangeChunk = Reflection.getField(TechHider.multiBlockChangePacket, SectionPosition.class, 0);
private static final Reflection.Field<short[]> multiBlockChangePos = Reflection.getField(TechHider.multiBlockChangePacket, short[].class, 0);
private static final Reflection.Field<IBlockData[]> multiBlockChangeBlocks = Reflection.getField(TechHider.multiBlockChangePacket, IBlockData[].class, 0);
@Override
public BiFunction<Player, Object, Object> multiBlockChangeGenerator(TechHider techHider) {
return (p, packet) -> {
TechHider.LocationEvaluator locationEvaluator = techHider.getLocationEvaluator();
Object chunkCoords = multiBlockChangeChunk.get(packet);
int chunkX = TechHider.blockPositionX.get(chunkCoords);
int chunkY = TechHider.blockPositionY.get(chunkCoords);
int chunkZ = TechHider.blockPositionZ.get(chunkCoords);
if(locationEvaluator.skipChunkSection(p, chunkX, chunkY, chunkZ))
return packet;
packet = TechHider.multiBlockChangeCloner.apply(packet);
final short[] oldPos = multiBlockChangePos.get(packet);
final IBlockData[] oldBlocks = multiBlockChangeBlocks.get(packet);
ArrayList<Short> poss = new ArrayList<>(oldPos.length);
ArrayList<IBlockData> blocks = new ArrayList<>(oldPos.length);
for(int i = 0; i < oldPos.length; i++) {
short pos = oldPos[i];
IBlockData block = oldBlocks[i];
switch(locationEvaluator.check(p, 16*chunkX + (pos >> 8 & 0xF), 16*chunkY + (pos & 0xF), 16*chunkZ + (pos >> 4 & 0xF))) {
case SKIP:
poss.add(pos);
blocks.add(block);
break;
case CHECK:
poss.add(pos);
blocks.add(techHider.iBlockDataHidden(block) ? (IBlockData) techHider.getObfuscationTarget() : block);
break;
default:
break;
}
}
if(blocks.isEmpty())
return null;
short[] newPos = new short[poss.size()];
for(int i = 0; i < newPos.length; i++)
newPos[i] = poss.get(i);
multiBlockChangePos.set(packet, newPos);
multiBlockChangeBlocks.set(packet, blocks.toArray(new IBlockData[0]));
return packet;
};
}
private static final Reflection.Field<TileEntityTypes> tileEntityType = Reflection.getField(TechHider.tileEntityDataPacket, TileEntityTypes.class, 0);
private static final TileEntityTypes<?> signType = Reflection.getField(TileEntityTypes.class, TileEntityTypes.class, 0, TileEntitySign.class).get(null);
@Override
public boolean unfilteredTileEntityDataAction(Object packet) {
return tileEntityType.get(packet) != signType;
}
@Override
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider) {
return (p, packet) -> {
PacketPlayOutBlockBreak breakPacket = (PacketPlayOutBlockBreak) packet;
switch (techHider.getLocationEvaluator().checkBlockPos(p, breakPacket.b())) {
case SKIP:
return packet;
case CHECK:
if(!techHider.iBlockDataHidden(breakPacket.c()))
return packet;
case HIDE:
return new PacketPlayOutBlockBreak(breakPacket.b(), (IBlockData) techHider.getObfuscationTarget(), breakPacket.d(), breakPacket.a());
case HIDE_AIR:
default:
return new PacketPlayOutBlockBreak(breakPacket.b(), (IBlockData) TechHider.AIR, breakPacket.d(), breakPacket.a());
}
};
}
}
-37
View File
@@ -1,37 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
dependencies {
compileOnly(project(":CommonCore", "default"))
compileOnly(project(":SpigotCore:SpigotCore_Main", "default"))
compileOnly(project(":SpigotCore:SpigotCore_14", "default"))
compileOnly(project(":SpigotCore:SpigotCore_18", "default"))
compileOnly(libs.worldedit15)
compileOnly(libs.nms19)
compileOnly(libs.spigotapi)
compileOnly(libs.brigadier)
compileOnly(libs.datafixer)
compileOnly(libs.authlib)
}
@@ -1,45 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import net.minecraft.network.chat.IChatMutableComponent;
import net.minecraft.network.chat.contents.LiteralContents;
import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata;
import net.minecraft.network.syncher.DataWatcher;
import java.util.ArrayList;
public class ChatWrapper19 implements ChatWrapper {
@Override
public Object stringToChatComponent(String text) {
return IChatMutableComponent.a(new LiteralContents(text));
}
@Override
public Object getDataWatcherPacket(int entityId, Object... dataWatcherKeyValues) {
ArrayList<DataWatcher.b<?>> nativeWatchers = new ArrayList<>(1);
for(int i = 0; i < dataWatcherKeyValues.length; i+=2) {
nativeWatchers.add(((DataWatcher.Item<?>) BountifulWrapper.impl.getDataWatcherItem(dataWatcherKeyValues[i], dataWatcherKeyValues[i+1])).e());
}
return new PacketPlayOutEntityMetadata(entityId, nativeWatchers);
}
}
@@ -1,64 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Pair;
import net.minecraft.SystemUtils;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import net.minecraft.world.level.EnumGamemode;
import org.bukkit.GameMode;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.function.LongSupplier;
public class ProtocolWrapper19 implements ProtocolWrapper {
private static final Reflection.Field<List> equipmentStack = Reflection.getField(equipmentPacket, List.class, 0);
@Override
public void setEquipmentPacketStack(Object packet, Object slot, Object stack) {
equipmentStack.set(packet, Collections.singletonList(new Pair<>(slot, stack)));
}
private static final Reflection.Constructor removePacketConstructor = Reflection.getConstructor(ClientboundPlayerInfoRemovePacket.class, List.class);
private static final Reflection.Field<EnumSet> updateActions = Reflection.getField(ClientboundPlayerInfoUpdatePacket.class, EnumSet.class, 0);
private static final Reflection.Field<List> updatePlayers = Reflection.getField(ClientboundPlayerInfoUpdatePacket.class, List.class, 0);
@Override
@SuppressWarnings("deprecation")
public Object playerInfoPacketConstructor(PlayerInfoAction action, GameProfile profile, GameMode mode) {
if(action == PlayerInfoAction.REMOVE)
return removePacketConstructor.invoke(Collections.singletonList(profile.getId()));
Object packet = Reflection.newInstance(ClientboundPlayerInfoUpdatePacket.class);
updateActions.set(packet, action == PlayerInfoAction.ADD ? EnumSet.of(ClientboundPlayerInfoUpdatePacket.a.a, ClientboundPlayerInfoUpdatePacket.a.c) : EnumSet.of(ClientboundPlayerInfoUpdatePacket.a.c));
updatePlayers.set(packet, Collections.singletonList(new ClientboundPlayerInfoUpdatePacket.b(profile.getId(), profile, false, 0, EnumGamemode.a(mode.getValue()), null, null)));
return packet;
}
@Override
public void initTPSWarp(LongSupplier longSupplier) {
SystemUtils.a = () -> System.nanoTime() + longSupplier.getAsLong();
}
}
@@ -1,68 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.Reflection;
import net.minecraft.network.protocol.game.PacketPlayOutLogin;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.World;
public class WorldIdentifier19 implements WorldIdentifier.IWorldIdentifier {
private static ResourceKey<World> resourceKey = null;
private static final Class<?> resourceKeyClass = Reflection.getClass("net.minecraft.resources.ResourceKey");
private static final Class<?> minecraftKeyClass = Reflection.getClass("net.minecraft.resources.MinecraftKey");
private static final Reflection.Constructor resourceKeyConstructor = Reflection.getConstructor(resourceKeyClass, minecraftKeyClass, minecraftKeyClass);
private static final Reflection.Constructor minecraftKeyConstructor = Reflection.getConstructor(minecraftKeyClass, String.class, String.class);
@Override
public void setResourceKey(String name) {
resourceKey = (ResourceKey<World>) resourceKeyConstructor.invoke(minecraftKeyConstructor.invoke("minecraft", "dimension"), minecraftKeyConstructor.invoke("steamwar", name));
}
public WorldIdentifier19() {
TinyProtocol.instance.addFilter(PacketPlayOutLogin.class, (player, o) -> {
if (resourceKey == null) return o;
PacketPlayOutLogin packet = (PacketPlayOutLogin) o;
return new PacketPlayOutLogin(
packet.b(),
packet.c(),
packet.d(),
packet.e(),
packet.f(),
packet.g(),
packet.h(),
resourceKey,
packet.j(),
packet.k(),
packet.l(),
packet.m(),
packet.n(),
packet.o(),
packet.p(),
packet.q(),
packet.r()
);
});
}
}
@@ -1,68 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core.authlib;
import com.mojang.authlib.Agent;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.GameProfileRepository;
import com.mojang.authlib.ProfileLookupCallback;
import de.steamwar.Reflection;
import de.steamwar.sql.SteamwarUser;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.Services;
import java.util.ArrayList;
import java.util.List;
public class SteamwarGameProfileRepository19 extends SteamwarGameProfileRepository {
private static final GameProfileRepository fallback;
private static final Reflection.Field<Services> field;
private static final Services current;
static {
Class<?> clazz = MinecraftServer.getServer().getClass();
field = Reflection.getField(clazz, Services.class, 0);
current = field.get(MinecraftServer.getServer());
fallback = current.c();
}
@Override
public void inject() {
Services newServices = new Services(current.a(), current.b(), this, current.d(), current.paperConfigurations());
field.set(MinecraftServer.getServer(), newServices);
}
@Override
public void findProfilesByNames(String[] strings, Agent agent, ProfileLookupCallback profileLookupCallback) {
List<String> unknownNames = new ArrayList<>();
for (String name:strings) {
SteamwarUser user = SteamwarUser.get(name);
if(user == null) {
unknownNames.add(name);
continue;
}
profileLookupCallback.onProfileLookupSucceeded(new GameProfile(user.getUUID(), user.getUserName()));
}
if(!unknownNames.isEmpty()) {
fallback.findProfilesByNames(unknownNames.toArray(new String[0]), agent, profileLookupCallback);
}
}
}
@@ -1,32 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
import org.bukkit.entity.Player;
import java.util.function.BiFunction;
public class ProtocolWrapper19 extends ProtocolWrapper18 {
@Override
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider) {
return null;
}
}
-31
View File
@@ -1,31 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
dependencies {
compileOnly(project(":SpigotCore:SpigotCore_Main", "default"))
compileOnly(libs.spigotapi)
compileOnly(libs.fawe18)
compileOnly(libs.nms20)
}
@@ -1,41 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.world.level.World;
import net.minecraft.world.level.chunk.Chunk;
import net.minecraft.world.level.chunk.ChunkStatus;
import net.minecraft.world.level.lighting.LevelLightEngine;
import org.bukkit.entity.Player;
public class CraftbukkitWrapper20 implements CraftbukkitWrapper.ICraftbukkitWrapper {
private static final Reflection.Method getHandle = Reflection.getMethod("org.bukkit.craftbukkit.CraftChunk", "getHandle", ChunkStatus.class);
private static final Reflection.Method getLightEngine = Reflection.getTypedMethod(World.class, null, LevelLightEngine.class);
@Override
public void sendChunk(Player p, int chunkX, int chunkZ) {
Chunk chunk = (Chunk) getHandle.invoke(p.getWorld().getChunkAt(chunkX, chunkZ), ChunkStatus.n);
TinyProtocol.instance.sendPacket(p, new ClientboundLevelChunkWithLightPacket(chunk, (LevelLightEngine) getLightEngine.invoke(chunk.r), null, null, true));
}
}
@@ -1,117 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.entity.CWireframe;
import de.steamwar.entity.REntityServer;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import java.util.HashMap;
import java.util.Map;
public class WorldEditRendererWrapper20 implements WorldEditRendererWrapper {
private static final class BoxPair {
private CWireframe regionBox;
private CWireframe clipboardBox;
public CWireframe get(boolean clipboard) {
if (clipboard) {
return clipboardBox;
} else {
return regionBox;
}
}
public void set(boolean clipboard, CWireframe box) {
if (clipboard) {
this.clipboardBox = box;
} else {
this.regionBox = box;
}
}
public void die() {
if (clipboardBox != null) {
clipboardBox.die();
}
if (regionBox != null) {
regionBox.die();
}
}
}
private static final Map<Player, REntityServer> servers = new HashMap<>();
private static final Map<Player, BoxPair> boxes = new HashMap<>();
@Override
public void draw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) {
REntityServer server = servers.computeIfAbsent(player, __ -> {
REntityServer entityServer = new REntityServer();
entityServer.addPlayer(player);
return entityServer;
});
WorldEditRendererCUIEditor.Type type = clipboard ? WorldEditRendererCUIEditor.Type.CLIPBOARD : WorldEditRendererCUIEditor.Type.SELECTION;
float width = type.getWidth(player).value;
Material material = type.getMaterial(player);
if (material == Material.BARRIER) {
hide(player, clipboard, true);
return;
}
BlockData block = material.createBlockData();
BoxPair boxPair = boxes.computeIfAbsent(player, __ -> new BoxPair());
CWireframe box = boxPair.get(clipboard);
if (box == null) {
box = new CWireframe(server);
boxPair.set(clipboard, box);
}
box.setPos1And2(pos1.toLocation(player.getWorld()), pos2.toLocation(player.getWorld()));
box.setWidth(width);
box.setBlock(block);
}
@Override
public void tick(Player player) {
REntityServer server = servers.get(player);
if (server != null) server.tick();
}
@Override
public void hide(Player player, boolean clipboard, boolean hide) {
BoxPair boxPair = boxes.get(player);
if (boxPair == null) return;
CWireframe box = boxPair.get(clipboard);
if (box == null) return;
box.hide(hide);
}
@Override
public void remove(Player player) {
BoxPair boxPair = boxes.remove(player);
if (boxPair != null) boxPair.die();
REntityServer server = servers.remove(player);
if (server != null) server.close();
}
}
@@ -1,70 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.Reflection;
import net.minecraft.network.protocol.game.PacketPlayOutLogin;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.World;
public class WorldIdentifier20 implements WorldIdentifier.IWorldIdentifier {
private static ResourceKey<World> resourceKey = null;
private static final Reflection.Field<Integer> playerId = Reflection.getField(PacketPlayOutLogin.class, int.class, 0);
private static final Class<?> resourceKeyClass = Reflection.getClass("net.minecraft.resources.ResourceKey");
private static final Class<?> minecraftKeyClass = Reflection.getClass("net.minecraft.resources.MinecraftKey");
private static final Reflection.Constructor resourceKeyConstructor = Reflection.getConstructor(resourceKeyClass, minecraftKeyClass, minecraftKeyClass);
private static final Reflection.Constructor minecraftKeyConstructor = Reflection.getConstructor(minecraftKeyClass, String.class, String.class);
@Override
public void setResourceKey(String name) {
resourceKey = (ResourceKey<World>) resourceKeyConstructor.invoke(minecraftKeyConstructor.invoke("minecraft", "dimension"), minecraftKeyConstructor.invoke("steamwar", name));
}
public WorldIdentifier20() {
TinyProtocol.instance.addFilter(PacketPlayOutLogin.class, (player, o) -> {
if (resourceKey == null) return o;
PacketPlayOutLogin packet = (PacketPlayOutLogin) o;
return new PacketPlayOutLogin(
playerId.get(packet),
packet.c(),
packet.d(),
packet.e(),
packet.f(),
packet.g(),
packet.h(),
resourceKey,
packet.j(),
packet.k(),
packet.l(),
packet.m(),
packet.n(),
packet.o(),
packet.p(),
packet.q(),
packet.r(),
packet.s()
);
});
}
}
-44
View File
@@ -1,44 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
dependencies {
compileOnly(project(":CommonCore", "default"))
compileOnly(project(":SpigotCore:SpigotCore_Main", "default"))
compileOnly(project(":SpigotCore:SpigotCore_18", "default"))
compileOnly(project(":SpigotCore:SpigotCore_14", "default"))
compileOnly(project(":SpigotCore:SpigotCore_9", "default"))
compileOnly(libs.fawe21)
compileOnly(libs.paperapi21)
compileOnly(libs.nms21)
compileOnly(libs.authlib2)
compileOnly(libs.datafixer)
compileOnly(libs.netty)
compileOnly(libs.authlib)
}
@@ -1,42 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import net.minecraft.world.entity.PositionMoveRotation;
import net.minecraft.world.phys.Vec3;
public class BountifulWrapper21 extends BountifulWrapper9 {
@Override
public BountifulWrapper.PositionSetter getPositionSetter(Class<?> packetClass, int fieldOffset) {
try {
Reflection.Field<PositionMoveRotation> field = Reflection.getField(packetClass, PositionMoveRotation.class, 0);
return (packet, x, y, z, pitch, yaw) -> {
PositionMoveRotation pos = field.get(packet);
field.set(packet, new PositionMoveRotation(new Vec3(x, y, z), pos.deltaMovement(), yaw, pitch));
};
} catch (IllegalArgumentException e) {
return super.getPositionSetter(packetClass, fieldOffset);
}
}
}
@@ -1,44 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.contents.PlainTextContents;
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
import net.minecraft.network.syncher.SynchedEntityData;
import java.util.ArrayList;
public class ChatWrapper21 implements ChatWrapper {
@Override
public Object stringToChatComponent(String text) {
return MutableComponent.create(PlainTextContents.create(text));
}
@Override
public Object getDataWatcherPacket(int entityId, Object... dataWatcherKeyValues) {
ArrayList<SynchedEntityData.DataValue<?>> nativeWatchers = new ArrayList<>(1);
for(int i = 0; i < dataWatcherKeyValues.length; i+=2) {
nativeWatchers.add(((SynchedEntityData.DataItem<?>) BountifulWrapper.impl.getDataWatcherItem(dataWatcherKeyValues[i], dataWatcherKeyValues[i+1])).value());
}
return new ClientboundSetEntityDataPacket(entityId, nativeWatchers);
}
}
@@ -1,39 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import org.bukkit.craftbukkit.CraftChunk;
import org.bukkit.entity.Player;
public class CraftbukkitWrapper21 implements CraftbukkitWrapper.ICraftbukkitWrapper {
private static final Reflection.Method getHandle = Reflection.getMethod("org.bukkit.craftbukkit.CraftChunk", "getHandle", ChunkStatus.class);
@Override
public void sendChunk(Player p, int chunkX, int chunkZ) {
LevelChunk chunk = (LevelChunk) ((CraftChunk) p.getWorld().getChunkAt(chunkX, chunkZ)).getHandle(ChunkStatus.FULL);
TinyProtocol.instance.sendPacket(p, new ClientboundLevelChunkWithLightPacket(chunk, chunk.level.getLightEngine(), null, null, true));
}
}
@@ -1,53 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import com.destroystokyo.paper.profile.PlayerProfile;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
public class FlatteningWrapper21 extends FlatteningWrapper14 implements FlatteningWrapper.IFlatteningWrapper {
@Override
public ItemStack setSkullOwner(String player) {
ItemStack head = new ItemStack(Material.PLAYER_HEAD, 1);
head.editMeta(SkullMeta.class, skullMeta -> {
try {
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player.startsWith(".") ? player.substring(1) : player);
PlayerProfile playerProfile = offlinePlayer.getPlayerProfile();
playerProfile.complete();
skullMeta.setPlayerProfile(playerProfile);
} catch (Exception e) {
// Ignore
}
});
return head;
}
protected static final Object shooting = entityPose.getEnumConstants()[16];
@Override
public Object getPose(FlatteningWrapper.EntityPose pose) {
if (pose == FlatteningWrapper.EntityPose.SHOOTING) return shooting;
return super.getPose(pose);
}
}
@@ -1,51 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Pair;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameType;
import org.bukkit.GameMode;
import java.util.Collections;
import java.util.EnumSet;
public class ProtocolWrapper21 implements ProtocolWrapper {
@Override
public void setEquipmentPacketStack(Object packet, Object slot, Object stack) {
ClientboundSetEquipmentPacket setEquipmentPacket = (ClientboundSetEquipmentPacket) packet;
setEquipmentPacket.getSlots().add(Pair.of((EquipmentSlot) slot, (ItemStack) stack));
}
@Override
public Object playerInfoPacketConstructor(PlayerInfoAction action, GameProfile profile, GameMode mode) {
if(action == PlayerInfoAction.REMOVE)
return new ClientboundPlayerInfoRemovePacket(Collections.singletonList(profile.getId()));
return new ClientboundPlayerInfoUpdatePacket(action == PlayerInfoAction.ADD ?
EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE) : EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE),
Collections.singletonList(new ClientboundPlayerInfoUpdatePacket.Entry(profile.getId(), profile, false, 0, GameType.byId(mode.getValue()), null, false, 0, null)));
}
}
@@ -1,29 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import org.bukkit.Particle;
public class TrickyParticleWrapper21 implements TrickyParticleWrapper {
@Override
public Particle getVillagerHappy() {
return Particle.HAPPY_VILLAGER;
}
}
@@ -1,49 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import com.mojang.authlib.properties.Property;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
public class TrickyTrialsWrapper21 implements TrickyTrialsWrapper {
@Override
public EntityType getTntEntityType() {
return EntityType.TNT;
}
@Override
public Enchantment getUnbreakingEnchantment() {
return Enchantment.UNBREAKING;
}
@Override
public Material getTurtleScute() {
return Material.TURTLE_SCUTE;
}
@Override
public String getValue(Property property) {
return property.value();
}
}
@@ -1,182 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV2;
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV3;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.*;
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV1Reader;
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV2Reader;
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder;
import de.steamwar.sql.NodeData;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
import org.enginehub.linbus.stream.LinBinaryIO;
import java.io.DataInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public class WorldEditWrapper21 implements WorldEditWrapper {
@Override
public InputStream getPlayerClipboard(Player player) {
return WorldEditWrapper.getPlayerClipboard(player, (outputStream, clipboard, clipboardHolder) -> {
ClipboardWriter writer = BuiltInClipboardFormat.FAST_V3.getWriter(outputStream);
writer.write(clipboard);
writer.close();
});
}
@Override
public void setPlayerClipboard(Player player, Clipboard clipboard) {
Actor actor = WorldEditWrapper.getWorldEditPlugin().wrapCommandSender(player);
WorldEditWrapper.getWorldEditPlugin().getWorldEdit().getSessionManager().get(actor).setClipboard(new ClipboardHolder(clipboard));
}
@Override
public Clipboard getClipboard(NodeData data) throws IOException {
ResetableInputStream is = new ResetableInputStream(data.schemData(false));
for (ClipboardFormat clipboardFormat : ClipboardFormats.getAll()) {
FilterInputStream fis = new FilterInputStream(is) {
@Override
public void close() throws IOException {
// Ignore close call!
}
};
boolean canBeRead = clipboardFormat.isFormat(fis);
is.reset();
if (!canBeRead) continue;
return clipboardFormat.load(is);
}
throw new IOException("No clipboard found");
}
private static final Function<InputStream, ClipboardReader> FastV3 = FastSchematicReaderV3::new;
@SuppressWarnings("removal")
private static final Function<InputStream, ClipboardReader> FastV2 = inputStream -> new FastSchematicReaderV2(new NBTInputStream(inputStream));
@SuppressWarnings("removal")
private static final Function<InputStream, ClipboardReader> McEdit = inputStream -> new MCEditSchematicReader(new NBTInputStream(inputStream));
private static final Function<InputStream, ClipboardReader> SpongeV3 = inputStream -> new SpongeSchematicV3Reader(LinBinaryIO.read(new DataInputStream(inputStream)));
private static final Function<InputStream, ClipboardReader> SpongeV2 = inputStream -> new SpongeSchematicV2Reader(LinBinaryIO.read(new DataInputStream(inputStream)));
private static final Function<InputStream, ClipboardReader> SpongeV1 = inputStream -> new SpongeSchematicV1Reader(LinBinaryIO.read(new DataInputStream(inputStream)));
private static final Function<InputStream, ClipboardReader>[] READERS = new Function[]{
FastV3,
FastV2,
SpongeV3,
SpongeV2,
SpongeV1,
McEdit
};
@Override
public Clipboard getClipboard(InputStream inputStream) throws IOException {
ResetableInputStream is = new ResetableInputStream(inputStream);
for (Function<InputStream, ClipboardReader> reader : READERS) {
FilterInputStream fis = new FilterInputStream(is) {
@Override
public void close() throws IOException {
// Ignore close call!
}
};
try {
return reader.apply(fis).read();
} catch (Exception e) {
is.reset();
}
}
is.close();
throw new IOException("No clipboard found");
}
private static class ResetableInputStream extends InputStream {
private InputStream inputStream;
private int pointer = 0;
private List<Integer> list = new ArrayList<>();
public ResetableInputStream(InputStream in) {
this.inputStream = in;
}
@Override
public int read() throws IOException {
if (pointer >= list.size()) {
int data = inputStream.read();
list.add(data);
pointer++;
return data;
}
int data = list.get(pointer);
pointer++;
return data;
}
@Override
public void reset() throws IOException {
pointer = 0;
}
@Override
public void close() throws IOException {
list.clear();
pointer = -1;
}
}
@Override
public org.bukkit.util.Vector getOrigin(Clipboard clipboard) {
return new org.bukkit.util.Vector(clipboard.getOrigin().x(), clipboard.getOrigin().y(), clipboard.getOrigin().z());
}
@Override
public Vector getMinimum(Region region) {
return new Vector(region.getMinimumPoint().x(), region.getMinimumPoint().y(), region.getMinimumPoint().z());
}
@Override
public Vector getMaximum(Region region) {
return new Vector(region.getMaximumPoint().x(), region.getMaximumPoint().y(), region.getMaximumPoint().z());
}
@Override
public Vector applyTransform(Vector vector, Transform transform) {
Vector3 v = Vector3.at(vector.getX(), vector.getY(), vector.getZ());
v = transform.apply(v);
return new org.bukkit.util.Vector(v.x(), v.y(), v.z());
}
@Override
public NodeData.SchematicFormat getNativeFormat() {
return NodeData.SchematicFormat.SPONGE_V3;
}
}
@@ -1,73 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.Reflection;
import net.minecraft.network.protocol.game.ClientboundLoginPacket;
import net.minecraft.network.protocol.game.CommonPlayerSpawnInfo;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.Level;
public class WorldIdentifier21 implements WorldIdentifier.IWorldIdentifier {
private static ResourceKey<Level> resourceKey = null;
private static final Class<?> resourceKeyClass = Reflection.getClass("net.minecraft.resources.ResourceKey");
private static final Class<?> minecraftKeyClass = Reflection.getClass("net.minecraft.resources.MinecraftKey");
private static final Reflection.Constructor resourceKeyConstructor = Reflection.getConstructor(resourceKeyClass, minecraftKeyClass, minecraftKeyClass);
private static final Reflection.Constructor minecraftKeyConstructor = Reflection.getConstructor(minecraftKeyClass, String.class, String.class);
@Override
public void setResourceKey(String name) {
resourceKey = (ResourceKey<Level>) resourceKeyConstructor.invoke(minecraftKeyConstructor.invoke("minecraft", "dimension"), minecraftKeyConstructor.invoke("steamwar", name));
}
public WorldIdentifier21() {
TinyProtocol.instance.addFilter(ClientboundLoginPacket.class, (player, o) -> {
if (resourceKey == null) return o;
ClientboundLoginPacket packet = (ClientboundLoginPacket) o;
return new ClientboundLoginPacket(packet.playerId(),
packet.hardcore(),
packet.levels(),
packet.maxPlayers(),
packet.chunkRadius(),
packet.simulationDistance(),
packet.reducedDebugInfo(),
packet.showDeathScreen(),
packet.doLimitedCrafting(),
new CommonPlayerSpawnInfo(
packet.commonPlayerSpawnInfo().dimensionType(),
resourceKey,
packet.commonPlayerSpawnInfo().seed(),
packet.commonPlayerSpawnInfo().gameType(),
packet.commonPlayerSpawnInfo().previousGameType(),
packet.commonPlayerSpawnInfo().isDebug(),
packet.commonPlayerSpawnInfo().isFlat(),
packet.commonPlayerSpawnInfo().lastDeathLocation(),
packet.commonPlayerSpawnInfo().portalCooldown(),
packet.commonPlayerSpawnInfo().seaLevel()
),
packet.enforcesSecureChat()
);
});
}
}
@@ -1,73 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core.authlib;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.GameProfileRepository;
import com.mojang.authlib.ProfileLookupCallback;
import de.steamwar.Reflection;
import de.steamwar.sql.SteamwarUser;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.Services;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class SteamwarGameProfileRepository21 extends SteamwarGameProfileRepository {
private static final GameProfileRepository fallback;
private static final Reflection.Field<Services> field;
private static final Services current;
static {
Class<?> clazz = MinecraftServer.getServer().getClass();
field = Reflection.getField(clazz, Services.class, 0);
current = field.get(MinecraftServer.getServer());
fallback = current.profileRepository();
}
@Override
public void findProfilesByNames(String[] strings, ProfileLookupCallback profileLookupCallback) {
List<String> unknownNames = new ArrayList<>();
for (String name:strings) {
SteamwarUser user = SteamwarUser.get(name);
if(user == null) {
unknownNames.add(name);
continue;
}
profileLookupCallback.onProfileLookupSucceeded(new GameProfile(user.getUUID(), user.getUserName()));
}
if(!unknownNames.isEmpty()) {
fallback.findProfilesByNames(unknownNames.toArray(new String[0]), profileLookupCallback);
}
}
@Override
public Optional<GameProfile> findProfileByName(String s) {
return fallback.findProfileByName(s);
}
@Override
public void inject() {
Services newServices = new Services(current.sessionService(), current.servicesKeySet(), this, current.profileCache(), current.paperConfigurations());
field.set(MinecraftServer.getServer(), newServices);
}
}
@@ -1,53 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.entity;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.PositionMoveRotation;
import net.minecraft.world.phys.Vec3;
import java.util.Collections;
public class PacketConstructor21 implements PacketConstructor{
@Override
public Object teleportPacket(int entityId, double x, double y, double z, float yaw, float pitch) {
PositionMoveRotation rot = new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, pitch, yaw);
return new ClientboundTeleportEntityPacket(entityId, rot, Collections.emptySet(), false);
}
@Override
public Object createRPlayerSpawn(RPlayer player) {
return new ClientboundAddEntityPacket(
player.entityId,
player.uuid,
player.x,
player.y,
player.z,
player.yaw,
player.pitch,
EntityType.PLAYER,
0,
Vec3.ZERO,
player.headYaw
);
}
}
@@ -1,74 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.scoreboard;
import de.steamwar.core.Core;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Scoreboard;
import java.util.HashMap;
import java.util.Map;
public class SWScoreboard21 implements SWScoreboard {
private static final HashMap<Player, ScoreboardCallback> playerBoards = new HashMap<>();
private static final String SIDEBAR = "sw-sidebar";
static {
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
for(Map.Entry<Player, ScoreboardCallback> scoreboard : playerBoards.entrySet()) {
render(scoreboard.getKey(), scoreboard.getValue());
}
}, 10, 5);
}
private static void render(Player player, ScoreboardCallback callback) {
if (player.getScoreboard().getObjective(SIDEBAR) != null) {
player.getScoreboard().getObjective(SIDEBAR).unregister();
}
Objective objective = player.getScoreboard().registerNewObjective(SIDEBAR, "dummy", Component.text(callback.getTitle()));
objective.setAutoUpdateDisplay(true);
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
callback.getData().forEach((text, score) -> objective.getScore(text).setScore(score));
}
@Override
public boolean createScoreboard(Player player, ScoreboardCallback callback) {
Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
player.setScoreboard(scoreboard);
render(player, callback);
playerBoards.put(player, callback);
return true;
}
@Override
public void removeScoreboard(Player player) {
player.getScoreboard().getObjective(SIDEBAR).unregister();
playerBoards.remove(player);
}
}
@@ -1,161 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
import de.steamwar.Reflection;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.util.SimpleBitStorage;
import net.minecraft.world.level.block.entity.BlockEntityType;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
public class ChunkHider21 implements ChunkHider {
@Override
public Class<?> mapChunkPacket() {
return ClientboundLevelChunkWithLightPacket.class;
}
private static final UnaryOperator<Object> chunkPacketCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkWithLightPacket.class);
private static final UnaryOperator<Object> chunkDataCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkPacketData.class);
private static final Reflection.Field<Integer> chunkXField = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 0);
private static final Reflection.Field<Integer> chunkZField = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 1);
private static final Reflection.Field<ClientboundLevelChunkPacketData> chunkData = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class, 0);
private static final Reflection.Field<byte[]> dataField = Reflection.getField(ClientboundLevelChunkPacketData.class, byte[].class, 0);
private static final Reflection.Field<List> tileEntities = Reflection.getField(ClientboundLevelChunkPacketData.class, List.class, 0);
@Override
public BiFunction<Player, Object, Object> chunkHiderGenerator(TechHider techHider) {
return (p, packet) -> {
int chunkX = chunkXField.get(packet);
int chunkZ = chunkZField.get(packet);
if (techHider.getLocationEvaluator().skipChunk(p, chunkX, chunkZ))
return packet;
packet = chunkPacketCloner.apply(packet);
Object dataWrapper = chunkDataCloner.apply(chunkData.get(packet));
Set<String> hiddenBlockEntities = techHider.getHiddenBlockEntities();
tileEntities.set(dataWrapper, ((List<?>)tileEntities.get(dataWrapper)).stream().filter(te -> tileEntityVisible(hiddenBlockEntities, te)).collect(Collectors.toList()));
ByteBuf in = Unpooled.wrappedBuffer(dataField.get(dataWrapper));
ByteBuf out = Unpooled.buffer(in.readableBytes() + 64);
for(int yOffset = p.getWorld().getMinHeight(); yOffset < p.getWorld().getMaxHeight(); yOffset += 16) {
SectionHider section = new SectionHider(p, techHider, in, out, chunkX, yOffset/16, chunkZ);
section.copyBlockCount();
blocks(section);
biomes(section);
}
if (in.readableBytes() != 0) {
throw new IllegalStateException("ChunkHider21: Incomplete chunk data, " + in.readableBytes() + " bytes left");
}
byte[] data = new byte[out.readableBytes()];
out.readBytes(data);
dataField.set(dataWrapper, data);
chunkData.set(packet, dataWrapper);
return packet;
};
}
public static final Class<?> tileEntity = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo");
protected static final Reflection.Field<BlockEntityType> entityType = Reflection.getField(tileEntity, BlockEntityType.class, 0);
private static final Class<?> builtInRegestries = Reflection.getClass("net.minecraft.core.registries.BuiltInRegistries");
private static final Class<?> registry = Reflection.getClass("net.minecraft.core.Registry");
private static final Reflection.Field<?> nameField = Reflection.getField(builtInRegestries, "BLOCK_ENTITY_TYPE", registry);
private static final Class<?> resourceLocation = Reflection.getClass("net.minecraft.resources.ResourceLocation");
private static final Reflection.Method getKey = Reflection.getTypedMethod(registry, "getKey", resourceLocation, Object.class);
private static final Reflection.Method getName = Reflection.getTypedMethod(resourceLocation, "getPath", String.class);
protected boolean tileEntityVisible(Set<String> hiddenBlockEntities, Object tile) {
return !hiddenBlockEntities.contains(getName.invoke(getKey.invoke(nameField.get(null), entityType.get(tile))));
}
private void blocks(SectionHider section) {
section.copyBitsPerBlock();
boolean singleValued = section.getBitsPerBlock() == 0;
if (singleValued) {
int value = ProtocolUtils.readVarInt(section.getIn());
ProtocolUtils.writeVarInt(section.getOut(), !section.isSkipSection() && section.getObfuscate().contains(value) ? section.getTarget() : value);
return;
} else if (section.getBitsPerBlock() < 9) {
// Indirect (paletted) storage only present when bitsPerBlock < 9 in 1.21+
section.processPalette();
}
if (section.isSkipSection() || (!section.blockPrecise() && section.isPaletted())) {
section.skipNewDataArray(4096);
return;
}
SimpleBitStorage values = new SimpleBitStorage(section.getBitsPerBlock(), 4096, section.readNewDataArray(4096));
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int pos = (((y * 16) + z) * 16) + x;
TechHider.State test = section.test(x, y, z);
switch (test) {
case SKIP:
break;
case CHECK:
if (!section.getObfuscate().contains(values.get(pos)))
break;
case HIDE:
values.set(pos, section.getTarget());
break;
case HIDE_AIR:
default:
values.set(pos, section.getAir());
}
}
}
}
section.writeDataArray(values.getRaw());
}
private void biomes(SectionHider section) {
section.copyBitsPerBlock();
if(section.getBitsPerBlock() == 0) {
section.copyVarInt();
} else if(section.getBitsPerBlock() < 6) {
section.skipPalette();
section.skipNewDataArray(64);
} else {
// Direct (global) biome IDs no palette present
section.skipNewDataArray(64);
}
}
}
-30
View File
@@ -1,30 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
dependencies {
compileOnly(project(":CommonCore", "default"))
compileOnly(project(":SpigotCore:SpigotCore_Main", "default"))
compileOnly(libs.nms8)
compileOnly(libs.worldedit12)
}
@@ -1,106 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent;
import net.minecraft.server.v1_8_R3.ChatComponentText;
import net.minecraft.server.v1_8_R3.MathHelper;
import net.minecraft.server.v1_8_R3.PacketPlayOutChat;
import org.bukkit.Sound;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
public class BountifulWrapper8 implements BountifulWrapper.IBountifulWrapper {
@Override
public void playPling(Player player) {
player.playSound(player.getLocation(), Sound.ORB_PICKUP, 1, 1);
}
@Override
public void sendMessage(Player player, ChatMessageType type, BaseComponent... msg) {
((CraftPlayer) player).getHandle().playerConnection.sendPacket(new PacketPlayOutChat(new ChatComponentText(BaseComponent.toLegacyText(msg)), (byte)type.ordinal()));
}
@Override
public Object getDataWatcherObject(int index, Class<?> type) {
return index;
}
private static final Class<?> watchableObject = Reflection.getClass("net.minecraft.DataWatcher$WatchableObject");
private static final Reflection.Constructor watchableObjectConstructor = Reflection.getConstructor(watchableObject, int.class, int.class, Object.class);
private static final Map<Class<?>, Integer> watchableDatatypes = new HashMap<>();
static {
watchableDatatypes.put(byte.class, 0);
watchableDatatypes.put(short.class, 1);
watchableDatatypes.put(int.class, 2);
watchableDatatypes.put(float.class, 3);
watchableDatatypes.put(String.class, 4);
}
@Override
public Object getDataWatcherItem(Object dwo, Object value) {
return watchableObjectConstructor.invoke(watchableDatatypes.get(value.getClass()), dwo, value);
}
@Override
public BountifulWrapper.PositionSetter getPositionSetter(Class<?> packetClass, int fieldOffset) {
Reflection.Field<Integer> posX = Reflection.getField(packetClass, int.class, fieldOffset);
Reflection.Field<Integer> posY = Reflection.getField(packetClass, int.class, fieldOffset +1);
Reflection.Field<Integer> posZ = Reflection.getField(packetClass, int.class, fieldOffset +2);
Reflection.Field<Byte> lookYaw = Reflection.getField(packetClass, byte.class, 0);
Reflection.Field<Byte> lookPitch = Reflection.getField(packetClass, byte.class, 1);
return (packet, x, y, z, pitch, yaw) -> {
posX.set(packet, MathHelper.floor(x * 32));
posY.set(packet, MathHelper.floor(y * 32));
posZ.set(packet, MathHelper.floor(z * 32));
lookYaw.set(packet, (byte)(yaw * 256 / 360));
lookPitch.set(packet, (byte)(pitch * 256 / 360));
};
}
@Override
public BountifulWrapper.PositionSetter getRelMoveSetter(Class<?> packetClass) {
Reflection.Field<?> moveX = Reflection.getField(packetClass, "b", byte.class);
Reflection.Field<?> moveY = Reflection.getField(packetClass, "c", byte.class);
Reflection.Field<?> moveZ = Reflection.getField(packetClass, "d", byte.class);
Reflection.Field<Byte> lookYaw = Reflection.getField(packetClass, "e", byte.class);
Reflection.Field<Byte> lookPitch = Reflection.getField(packetClass, "f", byte.class);
return (packet, x, y, z, pitch, yaw) -> {
moveX.set(packet, (byte)(x*32));
moveY.set(packet, (byte)(y*32));
moveZ.set(packet, (byte)(z*32));
lookYaw.set(packet, (byte)(yaw*256/360));
lookPitch.set(packet, (byte)(pitch*256/360));
};
}
@Override
public BountifulWrapper.UUIDSetter getUUIDSetter(Class<?> packetClass) {
return (packet, uuid) -> {};
}
}
@@ -1,51 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import java.util.ArrayList;
import java.util.List;
public class ChatWrapper8 implements ChatWrapper {
private static final Reflection.Constructor chatComponentConstructor = Reflection.getConstructor(Reflection.getClass("net.minecraft.network.chat.ChatComponentText"), String.class);
@Override
public Object stringToChatComponent(String text) {
return chatComponentConstructor.invoke(text);
}
private static final Class<?> metadataPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket");
private static final Reflection.Field<Integer> metadataEntity = Reflection.getField(metadataPacket, int.class, 0);
private static final Reflection.Field<List> metadataMetadata = Reflection.getField(metadataPacket, List.class, 0);
@Override
public Object getDataWatcherPacket(int entityId, Object... dataWatcherKeyValues) {
Object packet = Reflection.newInstance(metadataPacket);
metadataEntity.set(packet, entityId);
ArrayList<Object> nativeWatchers = new ArrayList<>(1);
for(int i = 0; i < dataWatcherKeyValues.length; i+=2) {
nativeWatchers.add(BountifulWrapper.impl.getDataWatcherItem(dataWatcherKeyValues[i], dataWatcherKeyValues[i+1]));
}
metadataMetadata.set(packet, nativeWatchers);
return packet;
}
}
@@ -1,33 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import net.minecraft.server.v1_8_R3.PacketPlayOutMapChunk;
import org.bukkit.craftbukkit.v1_8_R3.CraftChunk;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
public class CraftbukkitWrapper8 implements CraftbukkitWrapper.ICraftbukkitWrapper {
@Override
public void sendChunk(Player p, int chunkX, int chunkZ) {
((CraftPlayer)p).getHandle().playerConnection.sendPacket(new PacketPlayOutMapChunk(((CraftChunk)p.getWorld().getChunkAt(chunkX, chunkZ)).getHandle(), true, 65535));
}
}
@@ -1,121 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import java.util.HashMap;
import java.util.Map;
public class FlatteningWrapper8 implements FlatteningWrapper.IFlatteningWrapper {
private static final Reflection.Field<String> scoreboardName = Reflection.getField(FlatteningWrapper.scoreboardObjective, String.class, 1);
private static final Class<?> scoreActionEnum = Reflection.getClass("net.minecraft.PacketPlayOutScoreboardScore$EnumScoreboardAction");
private static final Reflection.Field<?> scoreAction = Reflection.getField(FlatteningWrapper.scoreboardScore, scoreActionEnum, 0);
private static final Object scoreActionChange = scoreActionEnum.getEnumConstants()[0];
@Override
public void setScoreboardTitle(Object packet, String title) {
scoreboardName.set(packet, title);
}
@Override
public void setScoreAction(Object packet) {
scoreAction.set(packet, scoreActionChange);
}
@Override
public Material getMaterial(String material) {
try{
return Material.valueOf(material);
}catch(IllegalArgumentException e){
return Material.STONE;
}
}
@Override
public Material getDye(int colorCode) {
return Material.INK_SACK;
}
@Override
public ItemStack setSkullOwner(String player) {
ItemStack head = new ItemStack(Material.SKULL_ITEM, 1, (short) 3);
SkullMeta headmeta = (SkullMeta) head.getItemMeta();
headmeta.setOwner(player.startsWith(".") ? player.substring(1) : player);
headmeta.setDisplayName(player);
head.setItemMeta(headmeta);
return head;
}
@Override
public Object getPose(FlatteningWrapper.EntityPose pose) {
return Byte.valueOf((byte)(pose == FlatteningWrapper.EntityPose.SNEAKING ? 2 : 0));
}
private static final Class<?> dataWatcher = Reflection.getClass("net.minecraft.DataWatcher");
private static final Class<?> namedSpawnPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundAddPlayerPacket");
private static final Reflection.Field<?> namedSpawnDataWatcher = Reflection.getField(namedSpawnPacket, dataWatcher, 0);
private static final Class<?> entity = Reflection.getClass("net.minecraft.Entity");
private static final Reflection.Constructor dataWatcherConstructor = Reflection.getConstructor(dataWatcher, entity);
@Override
public void setNamedSpawnPacketDataWatcher(Object packet) {
namedSpawnDataWatcher.set(packet, dataWatcherConstructor.invoke((Object) null));
}
@Override
public Object formatDisplayName(String displayName) {
return displayName != null ? displayName : "";
}
private static final Reflection.Field<?> spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, int.class, Core.getVersion() > 8 ? 6 : 9);
private static final Reflection.Field<Integer> spawnLivingType = Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 1);
private static final Map<EntityType, Object> types = new HashMap<>();
static {
types.put(TrickyTrialsWrapper.impl.getTntEntityType(), 50);
types.put(EntityType.ARMOR_STAND, 30);
types.put(EntityType.ARROW, 60);
types.put(EntityType.FIREBALL, 63);
types.put(EntityType.ITEM_FRAME, 18);
types.put(EntityType.FALLING_BLOCK, 21);
}
@Override
public void setSpawnPacketType(Object packet, EntityType type) {
(type.isAlive() ? spawnLivingType : spawnType).set(packet, types.get(type));
}
@Override
public int getViewDistance(Player player) {
return 10;
}
private static final Reflection.Method save = Reflection.getMethod("org.bukkit.craftbukkit.CraftWorld", "save", boolean.class);
@Override
public void syncSave(World world) {
save.invoke(world, true);
}
}
@@ -1,113 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.InputStreamReader;
import java.util.*;
import java.util.stream.Collectors;
public class IDConverter8 {
private final Map<String, Set<String>> availibleAttributes;
private final Map<String, Map<Set<String>, BlockTypeID>> map;
public IDConverter8() {
Map<String, Map<Set<String>, BlockTypeID>> map = new HashMap<>();
YamlConfiguration legacy = YamlConfiguration.loadConfiguration(new InputStreamReader(Objects.requireNonNull(IDConverter8.class.getClassLoader().getResourceAsStream("legacy.yml"))));
for(String blockString : legacy.getKeys(false)){
String[] legacyBlockId = legacy.getString(blockString).split(":");
map.computeIfAbsent(getBlockId(blockString), bId -> {
Map<Set<String>, BlockTypeID> attributeMap = new HashMap<>();
attributeMap.put(new HashSet<>(), new BlockTypeID(legacyBlockId[0], "0"));
return attributeMap;
}).put(getAttributes(blockString), new BlockTypeID(legacyBlockId[0], legacyBlockId[1]));
}
this.map = map;
Map<String, Set<String>> availableAttributes = new HashMap<>();
for (Map.Entry<String, Map<Set<String>, BlockTypeID>> entry : map.entrySet()) {
availableAttributes.put(entry.getKey(), entry.getValue().keySet().stream().flatMap(Collection::stream).collect(Collectors.toSet()));
}
this.availibleAttributes = availableAttributes;
}
public BlockTypeID getId(String blockString) {
String blockId = getBlockId(blockString);
Map<Set<String>, IDConverter8.BlockTypeID> attributeMap = map.get(blockId);
if(attributeMap == null) { // Block nonexistent pre-flattening
return new BlockTypeID("0", "0");
}
Set<String> attributes = getAttributes(blockString);
Set<String> knownAttributes = this.availibleAttributes.get(blockId);
attributes.removeIf(attribute -> !knownAttributes.contains(attribute));
long bestMatch = -1;
BlockTypeID blockID = null;
for(Map.Entry<Set<String>, BlockTypeID> entry : attributeMap.entrySet()) {
Set<String> attrs = entry.getKey();
if(attrs.size() <= bestMatch)
continue;
long matching = attributes.stream().filter(attrs::contains).count();
if(matching > bestMatch) {
blockID = entry.getValue();
bestMatch = matching;
if(bestMatch == attributes.size())
break;
}
}
return blockID;
}
private String getBlockId(String blockString) {
return blockString.split("\\[", 2)[0];
}
private Set<String> getAttributes(String blockString) {
Set<String> attributes = new HashSet<>();
if(blockString.contains("["))
Collections.addAll(attributes, blockString.split("\\[")[1].replace("]", "").split(","));
return attributes;
}
static class BlockTypeID{
private final int blockId;
private final byte dataId;
private BlockTypeID(String blockId, String dataId) {
this.blockId = Integer.parseInt(blockId);
this.dataId = Byte.parseByte(dataId);
}
int getBlockId() {
return blockId;
}
byte getDataId() {
return dataId;
}
}
}
@@ -1,24 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
public class LocaleChangeWrapper8 implements LocaleChangeWrapper {
// Event not available in 1.8-1.10
}
@@ -1,71 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import com.mojang.authlib.GameProfile;
import org.bukkit.GameMode;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
public class ProtocolWrapper8 implements ProtocolWrapper {
private static final Reflection.Field<?> equipmentSlot;
static {
if(Core.getVersion() == 8) {
equipmentSlot = Reflection.getField(equipmentPacket, int.class, 1);
} else {
Class<?> enumItemSlot = Reflection.getClass("net.minecraft.world.entity.EnumItemSlot");
equipmentSlot = Reflection.getField(equipmentPacket, enumItemSlot, 0);
}
}
private static final Reflection.Field<?> equipmentStack = Reflection.getField(equipmentPacket, itemStack, 0);
@Override
public void setEquipmentPacketStack(Object packet, Object slot, Object stack) {
equipmentSlot.set(packet, slot);
equipmentStack.set(packet, stack);
}
private static final Class<?> playerInfoPacket = Reflection.getClass("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo");
private static final Class<?> playerInfoActionClass = Reflection.getClass("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo$EnumPlayerInfoAction");
private static final Reflection.Field<?> playerInfoAction = Reflection.getField(playerInfoPacket, playerInfoActionClass, 0);
private static final Reflection.Field<List> playerInfoData = Reflection.getField(playerInfoPacket, List.class, 0);
private static final EnumMap<PlayerInfoAction, Object> actions = new EnumMap<>(PlayerInfoAction.class);
static {
Object[] nativeActions = playerInfoActionClass.getEnumConstants();
actions.put(PlayerInfoAction.ADD, nativeActions[0]);
actions.put(PlayerInfoAction.GAMEMODE, nativeActions[1]);
actions.put(PlayerInfoAction.REMOVE, nativeActions[4]);
}
private static final Class<?> iChatBaseComponent = Reflection.getClass("net.minecraft.network.chat.Component");
private static final Reflection.Constructor playerInfoDataConstructor = Reflection.getConstructor("net.minecraft.network.protocol.game.PacketPlayOutPlayerInfo$PlayerInfoData", playerInfoPacket, GameProfile.class, int.class, enumGamemode, iChatBaseComponent);
@Override
@SuppressWarnings("deprecation")
public Object playerInfoPacketConstructor(PlayerInfoAction action, GameProfile profile, GameMode mode) {
Object packet = Reflection.newInstance(playerInfoPacket);
playerInfoAction.set(packet, actions.get(action));
playerInfoData.set(packet, Collections.singletonList(playerInfoDataConstructor.invoke(packet, profile, 0, ProtocolWrapper.getGameModeById.invoke(null, mode.getValue()), null)));
return packet;
}
}
@@ -1,24 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
public class RecipeDiscoverWrapper8 implements RecipeDiscoverWrapper {
// Event not available pre flattening
}
@@ -1,49 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import com.mojang.authlib.properties.Property;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.EntityType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
public class TrickyTrialsWrapper8 implements TrickyTrialsWrapper {
@Override
public EntityType getTntEntityType() {
return EntityType.PRIMED_TNT;
}
@Override
public Enchantment getUnbreakingEnchantment() {
return Enchantment.DURABILITY;
}
@Override
public Material getTurtleScute() {
return Material.STONE;
}
@Override
public String getValue(Property property) {
return property.getValue();
}
}
@@ -1,42 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
public class WorldEditRendererWrapper8 implements WorldEditRendererWrapper {
@Override
public void draw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) {
}
@Override
public void tick(Player player) {
}
@Override
public void hide(Player player, boolean clipboard, boolean hide) {
}
@Override
public void remove(Player player) {
}
}
@@ -1,305 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.sk89q.jnbt.*;
import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.blocks.BaseBlock;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
import com.sk89q.worldedit.extent.clipboard.io.SchematicReader;
import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.world.registry.WorldData;
import de.steamwar.sql.NodeData;
import org.bukkit.entity.Player;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class WorldEditWrapper8 implements WorldEditWrapper {
@Override
public InputStream getPlayerClipboard(Player player) {
return WorldEditWrapper.getPlayerClipboard(player, (outputStream, clipboard, clipboardHolder) ->
ClipboardFormat.SCHEMATIC.getWriter(outputStream).write(clipboard, clipboardHolder.getWorldData()));
}
@Override
public void setPlayerClipboard(Player player, Clipboard clipboard) {
WorldData world = new BukkitWorld(player.getWorld()).getWorldData();
Actor actor = WorldEditWrapper.getWorldEditPlugin().wrapCommandSender(player);
WorldEditWrapper.getWorldEditPlugin().getWorldEdit().getSessionManager().get(actor).setClipboard(new ClipboardHolder(clipboard, world));
}
@Override
public Clipboard getClipboard(NodeData data) throws IOException {
InputStream is = data.schemData(true);
return readClipboard(is, data.getNodeFormat());
}
@Override
public Clipboard getClipboard(InputStream inputStream) throws IOException {
return readClipboard(inputStream, getNativeFormat());
}
private Clipboard readClipboard(InputStream is, NodeData.SchematicFormat format) throws IOException {
switch (format) {
case MCEDIT:
return new SchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData());
case SPONGE_V2:
case SPONGE_V3:
return new SpongeSchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData());
default:
throw new IllegalArgumentException("Unsupported schematic format");
}
}
@Override
public org.bukkit.util.Vector getOrigin(Clipboard clipboard) {
return new org.bukkit.util.Vector(clipboard.getOrigin().getX(), clipboard.getOrigin().getY(), clipboard.getOrigin().getZ());
}
@Override
public org.bukkit.util.Vector getMinimum(Region region) {
return new org.bukkit.util.Vector(region.getMinimumPoint().getX(), region.getMinimumPoint().getY(), region.getMinimumPoint().getZ());
}
@Override
public org.bukkit.util.Vector getMaximum(Region region) {
return new org.bukkit.util.Vector(region.getMaximumPoint().getX(), region.getMaximumPoint().getY(), region.getMaximumPoint().getZ());
}
@Override
public org.bukkit.util.Vector applyTransform(org.bukkit.util.Vector vector, Transform transform) {
Vector v = new Vector(vector.getX(), vector.getY(), vector.getZ());
v = transform.apply(v);
return new org.bukkit.util.Vector(v.getX(), v.getY(), v.getZ());
}
@Override
public NodeData.SchematicFormat getNativeFormat() {
return NodeData.SchematicFormat.MCEDIT;
}
private static class SpongeSchematicReader implements ClipboardReader {
private final NBTInputStream inputStream;
private int schematicVersion = -1;
SpongeSchematicReader(NBTInputStream inputStream) {
Preconditions.checkNotNull(inputStream);
this.inputStream = inputStream;
}
@Override
public Clipboard read(WorldData worldData) throws IOException {
CompoundTag schematicTag = this.getBaseTag();
if (this.schematicVersion == 1) {
return this.readSchematic(schematicTag);
} else if (this.schematicVersion == 2) {
return this.readSchematic(schematicTag);
} else {
throw new IOException("This schematic version is currently not supported");
}
}
private CompoundTag getBaseTag() throws IOException {
NamedTag rootTag = this.inputStream.readNamedTag();
if (!rootTag.getName().equals("Schematic")) {
throw new IOException("Tag 'Schematic' does not exist or is not first");
} else {
CompoundTag schematicTag = (CompoundTag)rootTag.getTag();
Map<String, Tag> schematic = schematicTag.getValue();
this.schematicVersion = (requireTag(schematic, "Version", IntTag.class)).getValue();
return schematicTag;
}
}
private BlockArrayClipboard readSchematic(CompoundTag schematicTag) throws IOException {
IDConverter8 ids = new IDConverter8();
Map<String, Tag> schematic = schematicTag.getValue();
boolean v3Mode = false;
if (schematic.size() == 1) {
schematic = (requireTag(schematic, "Schematic", CompoundTag.class)).getValue();
v3Mode = true;
}
int width = (requireTag(schematic, "Width", ShortTag.class)).getValue();
int height = (requireTag(schematic, "Height", ShortTag.class)).getValue();
int length = (requireTag(schematic, "Length", ShortTag.class)).getValue();
IntArrayTag offsetTag = getTag(schematic, "Offset", IntArrayTag.class);
int[] offsetParts;
if (offsetTag != null) {
offsetParts = offsetTag.getValue();
if (offsetParts.length != 3)
throw new IOException("Invalid offset specified in schematic.");
} else {
offsetParts = new int[]{0, 0, 0};
}
BlockVector min = new BlockVector(offsetParts[0], offsetParts[1], offsetParts[2]);
CompoundTag metadataTag = getTag(schematic, "Metadata", CompoundTag.class);
Vector origin;
CuboidRegion region;
if (metadataTag != null && metadataTag.containsKey("WEOffsetX")) {
Map<String, Tag> metadata = metadataTag.getValue();
int offsetX = (requireTag(metadata, "WEOffsetX", IntTag.class)).getValue();
int offsetY = (requireTag(metadata, "WEOffsetY", IntTag.class)).getValue();
int offsetZ = (requireTag(metadata, "WEOffsetZ", IntTag.class)).getValue();
BlockVector offset = new BlockVector(offsetX, offsetY, offsetZ);
origin = min.subtract(offset);
region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector.ONE));
} else {
origin = min;
region = new CuboidRegion(min, min.add(width, height, length).subtract(BlockVector.ONE));
}
Map<String, Tag> blockContainer = null;
if (v3Mode) {
blockContainer = getTag(schematic, "Blocks", CompoundTag.class).getValue();
}
Map<String, Tag> paletteObject = requireTag(v3Mode ? blockContainer : schematic, "Palette", CompoundTag.class).getValue();
Map<Integer, BaseBlock> palette = new HashMap<>();
ParserContext parserContext = new ParserContext();
parserContext.setRestricted(false);
parserContext.setPreferringWildcard(false);
for(String palettePart : paletteObject.keySet()) {
IDConverter8.BlockTypeID blockID = ids.getId(palettePart);
palette.put(requireTag(paletteObject, palettePart, IntTag.class).getValue(), new BaseBlock(blockID.getBlockId(), blockID.getDataId()));
}
byte[] blocks = requireTag(v3Mode ? blockContainer : schematic, v3Mode ? "Data" : "BlockData", ByteArrayTag.class).getValue();
Map<BlockVector, Map<String, Tag>> tileEntitiesMap = new HashMap<>();
ListTag tileEntities = getTag(v3Mode ? blockContainer : schematic, "BlockEntities", ListTag.class);
if (tileEntities == null) {
tileEntities = getTag(v3Mode ? blockContainer : schematic, "TileEntities", ListTag.class);
}
if (tileEntities != null) {
List<Map<String, Tag>> tileEntityTags = tileEntities.getValue().stream().map((tag) ->
(CompoundTag)tag
).map(CompoundTag::getValue).collect(Collectors.toList());
BlockVector pt;
Map<String, Tag> tileEntity;
for(Iterator<Map<String, Tag>> var20 = tileEntityTags.iterator(); var20.hasNext(); tileEntitiesMap.put(pt, tileEntity)) {
tileEntity = var20.next();
int[] pos = requireTag(tileEntity, "Pos", IntArrayTag.class).getValue();
pt = new BlockVector(pos[0], pos[1], pos[2]);
Map<String, Tag> values = Maps.newHashMap(tileEntity);
values.put("x", new IntTag(pt.getBlockX()));
values.put("y", new IntTag(pt.getBlockY()));
values.put("z", new IntTag(pt.getBlockZ()));
values.put("id", values.get("Id"));
values.remove("Id");
values.remove("Pos");
tileEntity = values;
}
}
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
clipboard.setOrigin(origin);
int index = 0;
for(int i = 0; i < blocks.length; ++index) {
int value = 0;
int varintLength = 0;
while(true) {
value |= (blocks[i] & 127) << varintLength++ * 7;
if (varintLength > 5) {
throw new IOException("VarInt too big (probably corrupted data)");
}
if ((blocks[i] & 128) != 128) {
++i;
int y = index / (width * length);
int z = index % (width * length) / width;
int x = index % (width * length) % width;
BaseBlock block = palette.get(value);
BlockVector pt = new BlockVector(x, y, z);
try {
if (tileEntitiesMap.containsKey(pt)) {
block.setNbtData(new CompoundTag(tileEntitiesMap.get(pt)));
clipboard.setBlock(clipboard.getMinimumPoint().add(pt), block);
} else {
clipboard.setBlock(clipboard.getMinimumPoint().add(pt), block);
}
break;
} catch (WorldEditException var30) {
throw new IOException("Failed to load a block in the schematic");
}
}
++i;
}
}
return clipboard;
}
private static <T extends Tag> T requireTag(Map<String, Tag> items, String key, Class<T> expected) throws IOException {
if (!items.containsKey(key)) {
throw new IOException("Schematic file is missing a \"" + key + "\" tag");
} else {
Tag tag = items.get(key);
if (!expected.isInstance(tag)) {
throw new IOException(key + " tag is not of tag type " + expected.getName());
} else {
return expected.cast(tag);
}
}
}
private static <T extends Tag> T getTag(Map<String, Tag> items, String key, Class<T> expected) {
if (!items.containsKey(key)) {
return null;
} else {
Tag test = items.get(key);
return !expected.isInstance(test) ? null : expected.cast(test);
}
}
}
}
@@ -1,27 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
public class WorldIdentifier8 implements WorldIdentifier.IWorldIdentifier {
@Override
public void setResourceKey(String name) {
}
}
@@ -1,72 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core.authlib;
import com.mojang.authlib.Agent;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.GameProfileRepository;
import com.mojang.authlib.ProfileLookupCallback;
import de.steamwar.Reflection;
import de.steamwar.sql.SteamwarUser;
import java.util.ArrayList;
import java.util.List;
public class SteamwarGameProfileRepository8 extends SteamwarGameProfileRepository {
private static final GameProfileRepository fallback;
private static final Object minecraftServer;
private static final Reflection.Field<?> gameProfile;
static {
Class<?> minecraftServerClass = Reflection.getClass("net.minecraft.server.MinecraftServer");
Class<?> gpr = Reflection.getClass("com.mojang.authlib.GameProfileRepository");
gameProfile = Reflection.getField(minecraftServerClass, gpr, 0);
minecraftServer = Reflection.getTypedMethod(minecraftServerClass, "getServer", minecraftServerClass).invoke(null);
fallback = (GameProfileRepository) gameProfile.get(minecraftServer);
}
@Override
public void inject() {
gameProfile.set(minecraftServer, this);
}
@Override
public void findProfilesByNames(String[] strings, Agent agent, ProfileLookupCallback profileLookupCallback) {
if(agent == Agent.SCROLLS) {
fallback.findProfilesByNames(strings, agent, profileLookupCallback);
} else {
List<String> unknownNames = new ArrayList<>();
for (String name:strings) {
SteamwarUser user = SteamwarUser.get(name);
if(user == null) {
unknownNames.add(name);
continue;
}
profileLookupCallback.onProfileLookupSucceeded(new GameProfile(user.getUUID(), user.getUserName()));
}
if(!unknownNames.isEmpty()) {
fallback.findProfilesByNames(unknownNames.toArray(new String[0]), agent, profileLookupCallback);
}
}
}
}
@@ -1,115 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.scoreboard;
import de.steamwar.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.core.Core;
import de.steamwar.core.FlatteningWrapper;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
public class SWScoreboard8 implements SWScoreboard {
private static final Reflection.Field<String> scoreboardName = Reflection.getField(FlatteningWrapper.scoreboardObjective, String.class, 0);
private static final Reflection.Field<Integer> scoreboardAction = Reflection.getField(FlatteningWrapper.scoreboardObjective, int.class, Core.getVersion() > 15 ? 3 : 0);
private static final Class<?> scoreboardDisplayEnum = Reflection.getClass("net.minecraft.world.scores.criteria.IScoreboardCriteria$EnumScoreboardHealthDisplay");
private static final Reflection.Field<?> scoreboardDisplayType = Reflection.getField(FlatteningWrapper.scoreboardObjective, scoreboardDisplayEnum, 0);
private static final Object displayTypeIntegers = scoreboardDisplayEnum.getEnumConstants()[0];
private static final Reflection.Field<String> scoreName = Reflection.getField(FlatteningWrapper.scoreboardScore, String.class, 0);
private static final Reflection.Field<String> scoreScoreboardName = Reflection.getField(FlatteningWrapper.scoreboardScore, String.class, 1);
private static final Reflection.Field<Integer> scoreValue = Reflection.getField(FlatteningWrapper.scoreboardScore, int.class, 0);
private static final HashMap<Player, ScoreboardCallback> playerBoards = new HashMap<>(); //Object -> Scoreboard | Alle Versionen in der Map!
private static int toggle = 0; // Scoreboard 0 updates while scoreboard 1 is presenting. toggle marks the current active scoreboard
private static final String SIDEBAR = "Sidebar";
private static final Object[] DELETE_SCOREBOARD = new Object[2];
private static final Object[] DISPLAY_SIDEBAR = new Object[2];
static {
Class<?> scoreboardDisplayObjective = Reflection.getClass("net.minecraft.network.protocol.game.PacketPlayOutScoreboardDisplayObjective");
Reflection.Field<String> scoreboardDisplayName = Reflection.getField(scoreboardDisplayObjective, String.class, 0);
Reflection.Field<Integer> scoreboardDisplaySlot = Reflection.getField(scoreboardDisplayObjective, int.class, 0);
for(int id = 0; id < 2; id++) {
DELETE_SCOREBOARD[id] = Reflection.newInstance(FlatteningWrapper.scoreboardObjective);
scoreboardName.set(DELETE_SCOREBOARD[id], SIDEBAR + id);
scoreboardAction.set(DELETE_SCOREBOARD[id], 1); //1 to remove
DISPLAY_SIDEBAR[id] = Reflection.newInstance(scoreboardDisplayObjective);
scoreboardDisplayName.set(DISPLAY_SIDEBAR[id], SIDEBAR + id);
scoreboardDisplaySlot.set(DISPLAY_SIDEBAR[id], 1); // 1 = Sidebar
}
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
toggle ^= 1; // Toggle between 0 and 1
for(Map.Entry<Player, ScoreboardCallback> scoreboard : playerBoards.entrySet()) {
Player player = scoreboard.getKey();
ScoreboardCallback callback = scoreboard.getValue();
TinyProtocol.instance.sendPacket(player, DELETE_SCOREBOARD[toggle]);
TinyProtocol.instance.sendPacket(player, createSidebarPacket(callback.getTitle()));
for(Map.Entry<String, Integer> score : callback.getData().entrySet()){
TinyProtocol.instance.sendPacket(player, createScorePacket(score.getKey(), score.getValue()));
}
Bukkit.getScheduler().runTaskLater(Core.getInstance(), () -> {
if(!player.isOnline())
return;
TinyProtocol.instance.sendPacket(player, DISPLAY_SIDEBAR[toggle]);
}, 2);
}
}, 10, 5);
}
public boolean createScoreboard(Player player, ScoreboardCallback callback) {
playerBoards.put(player, callback);
return true;
}
public void removeScoreboard(Player player) {
if(playerBoards.remove(player) == null || !player.isOnline())
return;
TinyProtocol.instance.sendPacket(player, DELETE_SCOREBOARD[toggle]);
}
private static Object createSidebarPacket(String name){
Object packet = Reflection.newInstance(FlatteningWrapper.scoreboardObjective);
scoreboardName.set(packet, SIDEBAR + toggle);
scoreboardAction.set(packet, 0); //0 to create
FlatteningWrapper.impl.setScoreboardTitle(packet, name);
scoreboardDisplayType.set(packet, displayTypeIntegers);
return packet;
}
private static Object createScorePacket(String name, int value){
Object packet = Reflection.newInstance(FlatteningWrapper.scoreboardScore);
scoreName.set(packet, name);
scoreScoreboardName.set(packet, SIDEBAR + toggle);
scoreValue.set(packet, value);
FlatteningWrapper.impl.setScoreAction(packet);
return packet;
}
}
@@ -1,44 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
import org.bukkit.Material;
import java.util.Collections;
import java.util.Set;
public class BlockIds8 implements BlockIds {
@Override
public int getCombinedId(Object iBlockData) {
int id = (int) getCombinedId.invoke(null, iBlockData); // blockState << 12 | blockId
return (id & 4095) | (id >> 12);
}
@Override
@SuppressWarnings("deprecation")
public int materialToId(Material material) {
return material.getId() << 4;
}
@Override
public Set<Integer> materialToAllIds(Material material) {
return Collections.singleton(materialToId(material));
}
}
@@ -1,39 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
import de.steamwar.Reflection;
import org.bukkit.entity.Player;
import java.util.function.BiFunction;
public class ChunkHider8 implements ChunkHider {
protected static final Class<?> mapChunkPacket = Reflection.getClass("net.minecraft.PacketPlayOutMapChunk");
@Override
public Class<?> mapChunkPacket() {
return mapChunkPacket;
}
@Override
public BiFunction<Player, Object, Object> chunkHiderGenerator(TechHider techHider) {
return (player, packet) -> packet;
}
}
@@ -1,85 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
import de.steamwar.Reflection;
import org.bukkit.entity.Player;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.function.BiFunction;
public class ProtocolWrapper8 implements ProtocolWrapper {
private static final Class<?> chunkCoordinateIntPair = Reflection.getClass("net.minecraft.ChunkCoordIntPair");
private static final Reflection.Field<?> multiBlockChangeChunk = Reflection.getField(TechHider.multiBlockChangePacket, chunkCoordinateIntPair, 0);
private static final Reflection.Field<Integer> chunkCoordinateX = Reflection.getField(chunkCoordinateIntPair, int.class, 0);
private static final Reflection.Field<Integer> chunkCoordinateZ = Reflection.getField(chunkCoordinateIntPair, int.class, 1);
private static final Class<?> multiBlockChangeInfo = Reflection.getClass("net.minecraft.PacketPlayOutMultiBlockChange$MultiBlockChangeInfo");
private static final Reflection.Constructor multiBlockChangeInfoConstructor = Reflection.getConstructor(multiBlockChangeInfo, TechHider.multiBlockChangePacket, short.class, TechHider.iBlockData);
private static final Reflection.Field<?> multiBlockChangeInfoBlock = Reflection.getField(multiBlockChangeInfo, TechHider.iBlockData, 0);
private static final Reflection.Field<?> multiBlockChangeInfoPos = Reflection.getField(multiBlockChangeInfo, short.class, 0);
private static final Class<?> multiBlockChangeInfoArray = Reflection.getClass("[L" + Reflection.LEGACY_NET_MINECRAFT_SERVER + ".PacketPlayOutMultiBlockChange$MultiBlockChangeInfo;");
private static final Reflection.Field<?> multiBlockChangeInfos = Reflection.getField(TechHider.multiBlockChangePacket, multiBlockChangeInfoArray, 0);
@Override
public BiFunction<Player, Object, Object> multiBlockChangeGenerator(TechHider techHider) {
return (p, packet) -> {
TechHider.LocationEvaluator locationEvaluator = techHider.getLocationEvaluator();
Object chunkCoords = multiBlockChangeChunk.get(packet);
int chunkX = chunkCoordinateX.get(chunkCoords);
int chunkZ = chunkCoordinateZ.get(chunkCoords);
if(locationEvaluator.skipChunk(p, chunkX, chunkZ))
return packet;
packet = TechHider.multiBlockChangeCloner.apply(packet);
Object[] mbcis = (Object[]) multiBlockChangeInfos.get(packet);
ArrayList<Object> blockChangeInfos = new ArrayList<>(mbcis.length);
for(Object mbci : mbcis) {
short pos = (short) multiBlockChangeInfoPos.get(mbci);
switch(locationEvaluator.check(p, 16*chunkX + (pos >> 12 & 0xF), pos & 0xFF, 16*chunkZ + (pos >> 8 & 0xF))) {
case SKIP:
blockChangeInfos.add(mbci);
break;
case CHECK:
blockChangeInfos.add(techHider.iBlockDataHidden(multiBlockChangeInfoBlock.get(mbci)) ? multiBlockChangeInfoConstructor.invoke(packet, pos, techHider.getObfuscationTarget()) : mbci);
break;
default:
break;
}
}
if(blockChangeInfos.isEmpty())
return null;
multiBlockChangeInfos.set(packet, blockChangeInfos.toArray((Object[])Array.newInstance(multiBlockChangeInfo, 0)));
return packet;
};
}
private static final Reflection.Field<Integer> tileEntityDataAction = Reflection.getField(TechHider.tileEntityDataPacket, int.class, 0);
@Override
public boolean unfilteredTileEntityDataAction(Object packet) {
return tileEntityDataAction.get(packet) != 9;
}
@Override
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider) {
return null;
}
}
File diff suppressed because it is too large Load Diff
-30
View File
@@ -1,30 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
dependencies {
compileOnly(project(":SpigotCore:SpigotCore_Main", "default"))
compileOnly(project(":SpigotCore:SpigotCore_8", "default"))
compileOnly(libs.nms9)
compileOnly(libs.worldedit12)
}
@@ -1,110 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import java.util.UUID;
public class BountifulWrapper9 implements BountifulWrapper.IBountifulWrapper {
@Override
public void playPling(Player player) {
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1);
}
@Override
public void sendMessage(Player player, ChatMessageType type, BaseComponent... msg) {
if(type == ChatMessageType.CHAT)
type = ChatMessageType.SYSTEM;
player.spigot().sendMessage(type, msg);
}
private static final Class<?> dataWatcherObject = Reflection.getClass("net.minecraft.network.syncher.EntityDataAccessor");
private static final Class<?> dataWatcherRegistry = Reflection.getClass("net.minecraft.network.syncher.EntityDataSerializers");
private static final Class<?> dataWatcherSerializer = Reflection.getClass("net.minecraft.network.syncher.EntityDataSerializer");
private static final Reflection.Constructor dataWatcherObjectConstructor = Reflection.getConstructor(dataWatcherObject, int.class, dataWatcherSerializer);
@Override
public Object getDataWatcherObject(int index, Class<?> type) {
return dataWatcherObjectConstructor.invoke(index, Reflection.getField(dataWatcherRegistry, dataWatcherSerializer, 0, type).get(null));
}
private static final Class<?> item = Reflection.getClass("net.minecraft.network.syncher.SynchedEntityData$DataItem");
private static final Reflection.Constructor itemConstructor = Reflection.getConstructor(item, dataWatcherObject, Object.class);
@Override
public Object getDataWatcherItem(Object dwo, Object value) {
return itemConstructor.invoke(dwo, value);
}
@Override
public BountifulWrapper.PositionSetter getPositionSetter(Class<?> packetClass, int fieldOffset) {
Reflection.Field<Double> posX = Reflection.getField(packetClass, double.class, fieldOffset);
Reflection.Field<Double> posY = Reflection.getField(packetClass, double.class, fieldOffset+1);
Reflection.Field<Double> posZ = Reflection.getField(packetClass, double.class, fieldOffset+2);
boolean isByteClass = packetClass.getSimpleName().contains("PacketPlayOutEntityTeleport") || packetClass.getSimpleName().contains("PacketPlayOutNamedEntitySpawn");
Class<?> pitchYawType = isByteClass ? byte.class : int.class;
Reflection.Field<?> lookYaw = Reflection.getField(packetClass, pitchYawType, isByteClass ? 0 : 1);
Reflection.Field<?> lookPitch = Reflection.getField(packetClass, pitchYawType, isByteClass ? 1 : 2);
return (packet, x, y, z, pitch, yaw) -> {
posX.set(packet, x);
posY.set(packet, y);
posZ.set(packet, z);
if (isByteClass) {
lookYaw.set(packet, (byte) (yaw*256/360));
lookPitch.set(packet, (byte) (pitch*256/360));
} else {
lookYaw.set(packet, (int) (yaw*256/360));
lookPitch.set(packet, (int) (pitch*256/360));
}
};
}
@Override
public BountifulWrapper.PositionSetter getRelMoveSetter(Class<?> packetClass) {
Class<?> type = Core.getVersion() > 12 ? short.class : int.class;
int fieldOffset = Core.getVersion() > 12 ? 0 : 1;
Reflection.Field<?> moveX = Reflection.getField(packetClass, type, 0 + fieldOffset);
Reflection.Field<?> moveY = Reflection.getField(packetClass, type, 1 + fieldOffset);
Reflection.Field<?> moveZ = Reflection.getField(packetClass, type, 2 + fieldOffset);
Reflection.Field<Byte> moveYaw = Reflection.getField(packetClass, byte.class, 0);
Reflection.Field<Byte> movePitch = Reflection.getField(packetClass, byte.class, 1);
return (packet, x, y, z, pitch, yaw) -> {
moveX.set(packet, (short)(x*4096));
moveY.set(packet, (short)(y*4096));
moveZ.set(packet, (short)(z*4096));
moveYaw.set(packet, (byte)(yaw*256/360));
movePitch.set(packet, (byte)(pitch*256/360));
};
}
@Override
public BountifulWrapper.UUIDSetter getUUIDSetter(Class<?> packetClass) {
Reflection.Field<UUID> uuidField = Reflection.getField(packetClass, UUID.class, 0);
return uuidField::set;
}
}
@@ -1,37 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import de.steamwar.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;
import org.bukkit.entity.Player;
public class CraftbukkitWrapper9 implements CraftbukkitWrapper.ICraftbukkitWrapper {
private static final Class<?> chunk = Reflection.getClass("net.minecraft.world.level.chunk.LevelChunk");
private static final Class<?> packetPlayOutMapChunk = Reflection.getClass("net.minecraft.network.protocol.game.PacketPlayOutMapChunk");
private static final Reflection.Constructor newPacketPlayOutMapChunk = Reflection.getConstructor(packetPlayOutMapChunk, chunk, int.class);
private static final Reflection.Method getHandle = Reflection.getMethod("org.bukkit.craftbukkit.CraftChunk", "getHandle");
@Override
public void sendChunk(Player p, int chunkX, int chunkZ) {
TinyProtocol.instance.sendPacket(p, newPacketPlayOutMapChunk.invoke(getHandle.invoke(p.getWorld().getChunkAt(chunkX, chunkZ)), 65535));
}
}
@@ -1,29 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import org.bukkit.Particle;
public class TrickyParticleWrapper9 implements TrickyParticleWrapper {
@Override
public Particle getVillagerHappy() {
return Particle.VILLAGER_HAPPY;
}
}
@@ -1,158 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.techhider;
import de.steamwar.Reflection;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.bukkit.entity.Player;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
public class ChunkHider9 extends ChunkHider8 {
private static final UnaryOperator<Object> mapChunkCloner = ProtocolUtils.shallowCloneGenerator(mapChunkPacket);
private static final Reflection.Field<Integer> mapChunkX = Reflection.getField(mapChunkPacket, int.class, 0);
private static final Reflection.Field<Integer> mapChunkZ = Reflection.getField(mapChunkPacket, int.class, 1);
private static final Reflection.Field<Integer> mapChunkBitMask = Reflection.getField(mapChunkPacket, int.class, 2);
private static final Reflection.Field<List> mapChunkBlockEntities = Reflection.getField(mapChunkPacket, List.class, 0);
private static final Reflection.Field<byte[]> mapChunkData = Reflection.getField(mapChunkPacket, byte[].class, 0);
private static final Class<?> nbtTagCompound = Reflection.getClass("net.minecraft.nbt.CompoundTag");
private static final Reflection.Method nbtTagGetString = Reflection.getTypedMethod(nbtTagCompound, null, String.class, String.class);
@Override
public BiFunction<Player, Object, Object> chunkHiderGenerator(TechHider techHider) {
return (p, packet) -> {
int chunkX = mapChunkX.get(packet);
int chunkZ = mapChunkZ.get(packet);
if (techHider.getLocationEvaluator().skipChunk(p, chunkX, chunkZ))
return packet;
packet = mapChunkCloner.apply(packet);
Set<String> hiddenBlockEntities = techHider.getHiddenBlockEntities();
mapChunkBlockEntities.set(packet, ((List<?>)mapChunkBlockEntities.get(packet)).stream().filter(
nbttag -> !hiddenBlockEntities.contains((String) nbtTagGetString.invoke(nbttag, "id"))
).collect(Collectors.toList()));
int primaryBitMask = mapChunkBitMask.get(packet);
ByteBuf in = Unpooled.wrappedBuffer(mapChunkData.get(packet));
ByteBuf out = Unpooled.buffer(in.readableBytes() + 64);
for(int chunkY = 0; chunkY < p.getWorld().getMaxHeight()/16; chunkY++) {
if(((1 << chunkY) & primaryBitMask) == 0)
continue;
SectionHider section = new SectionHider(p, techHider, in, out, chunkX, chunkY, chunkZ);
dataHider(section);
}
byte[] data = new byte[out.readableBytes()];
out.readBytes(data);
mapChunkData.set(packet, data);
return packet;
};
}
protected void dataHider(SectionHider section) {
section.copyBitsPerBlock();
section.processPalette();
if(section.isSkipSection() || (!section.blockPrecise() && section.isPaletted())) { //section.getBitsPerBlock() < 9
section.skipDataArray();
} else {
processDataArray(section);
}
section.getOut().writeBytes(section.getIn(), 4096); //Skylight (Not in Nether/End!!!) 2048 + Blocklight 2048
}
protected void processDataArray(SectionHider section) {
VariableValueArray values = new VariableValueArray(section.getBitsPerBlock(), section.readDataArray());
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int pos = (((y * 16) + z) * 16) + x;
switch (section.test(x, y, z)) {
case SKIP:
break;
case CHECK:
if(!section.getObfuscate().contains(values.get(pos)))
break;
case HIDE:
values.set(pos, section.getTarget());
break;
case HIDE_AIR:
default:
values.set(pos, section.getAir());
}
}
}
}
section.writeDataArray(values.backing);
}
private static class VariableValueArray {
private final long[] backing;
private final int bitsPerValue;
private final long valueMask;
public VariableValueArray(int bitsPerEntry, long[] dataArray) {
this.bitsPerValue = bitsPerEntry;
this.valueMask = (1L << this.bitsPerValue) - 1;
this.backing = dataArray;
}
public int get(int index) {
index *= bitsPerValue;
int i0 = index >> 6;
int i1 = index & 0x3f;
long value = backing[i0] >>> i1;
// The value is divided over two long values
if (i1 + bitsPerValue > 64)
value |= backing[++i0] << 64 - i1;
return (int) (value & valueMask);
}
public void set(int index, int value) {
index *= bitsPerValue;
int i0 = index >> 6;
int i1 = index & 0x3f;
backing[i0] = backing[i0] & ~(valueMask << i1) | (value & valueMask) << i1;
int i2 = i1 + bitsPerValue;
// The value is divided over two long values
if (i2 > 64) {
i0++;
backing[i0] = backing[i0] & -(1L << i2 - 64) | value >> 64 - i1;
}
}
}
}
+21 -2
View File
@@ -25,6 +25,21 @@ tasks.compileJava {
options.isWarnings = false options.isWarnings = false
} }
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
tasks.withType<JavaCompile>().configureEach {
options.compilerArgs.addAll(listOf(
"--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"
))
}
tasks.withType<Test>().configureEach {
jvmArgs("--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED")
}
dependencies { dependencies {
compileOnly(libs.classindex) compileOnly(libs.classindex)
annotationProcessor(libs.classindex) annotationProcessor(libs.classindex)
@@ -32,11 +47,15 @@ dependencies {
compileOnly(project(":CommandFramework", "default")) compileOnly(project(":CommandFramework", "default"))
compileOnly(project(":SpigotCore:CRIUDummy", "default")) compileOnly(project(":SpigotCore:CRIUDummy", "default"))
compileOnly(libs.worldedit12) compileOnly(libs.fawe21)
compileOnly(libs.spigotapi) compileOnly(libs.paperapi21)
compileOnly(libs.nms21)
compileOnly(libs.authlib2)
compileOnly(libs.datafixer)
compileOnly(libs.netty) compileOnly(libs.netty)
compileOnly(libs.authlib) compileOnly(libs.authlib)
compileOnly(libs.brigadier)
compileOnly(libs.fastutil) compileOnly(libs.fastutil)
implementation(libs.anvilgui) implementation(libs.anvilgui)
@@ -19,28 +19,100 @@
package de.steamwar.core; package de.steamwar.core;
import de.steamwar.Reflection;
import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.BaseComponent;
import net.minecraft.world.entity.PositionMoveRotation;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Sound;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.UUID; import java.util.UUID;
public class BountifulWrapper { public class BountifulWrapper {
private BountifulWrapper() {} public static final BountifulWrapper impl = new BountifulWrapper();
public static final IBountifulWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); public void playPling(Player player) {
player.playSound(player.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1);
}
public interface IBountifulWrapper { public void sendMessage(Player player, ChatMessageType type, BaseComponent... msg) {
void playPling(Player player); if(type == ChatMessageType.CHAT)
type = ChatMessageType.SYSTEM;
void sendMessage(Player player, ChatMessageType type, BaseComponent... msg); player.spigot().sendMessage(type, msg);
}
Object getDataWatcherObject(int index, Class<?> type); private static final Class<?> dataWatcherObject = Reflection.getClass("net.minecraft.network.syncher.EntityDataAccessor");
Object getDataWatcherItem(Object dataWatcherObject, Object value); private static final Class<?> dataWatcherRegistry = Reflection.getClass("net.minecraft.network.syncher.EntityDataSerializers");
private static final Class<?> dataWatcherSerializer = Reflection.getClass("net.minecraft.network.syncher.EntityDataSerializer");
private static final Reflection.Constructor dataWatcherObjectConstructor = Reflection.getConstructor(dataWatcherObject, int.class, dataWatcherSerializer);
public Object getDataWatcherObject(int index, Class<?> type) {
return dataWatcherObjectConstructor.invoke(index, Reflection.getField(dataWatcherRegistry, dataWatcherSerializer, 0, type).get(null));
}
PositionSetter getPositionSetter(Class<?> packetClass, int fieldOffset); private static final Class<?> item = Reflection.getClass("net.minecraft.network.syncher.SynchedEntityData$DataItem");
PositionSetter getRelMoveSetter(Class<?> packetClass); private static final Reflection.Constructor itemConstructor = Reflection.getConstructor(item, dataWatcherObject, Object.class);
UUIDSetter getUUIDSetter(Class<?> packetClass); public Object getDataWatcherItem(Object dwo, Object value) {
return itemConstructor.invoke(dwo, value);
}
public BountifulWrapper.PositionSetter getPositionSetter(Class<?> packetClass, int fieldOffset) {
try {
Reflection.Field<PositionMoveRotation> field = Reflection.getField(packetClass, PositionMoveRotation.class, 0);
return (packet, x, y, z, pitch, yaw) -> {
PositionMoveRotation pos = field.get(packet);
field.set(packet, new PositionMoveRotation(new Vec3(x, y, z), pos.deltaMovement(), yaw, pitch));
};
} catch (IllegalArgumentException e) {
Reflection.Field<Double> posX = Reflection.getField(packetClass, double.class, fieldOffset);
Reflection.Field<Double> posY = Reflection.getField(packetClass, double.class, fieldOffset+1);
Reflection.Field<Double> posZ = Reflection.getField(packetClass, double.class, fieldOffset+2);
boolean isByteClass = packetClass.getSimpleName().contains("PacketPlayOutEntityTeleport") || packetClass.getSimpleName().contains("PacketPlayOutNamedEntitySpawn");
Class<?> pitchYawType = isByteClass ? byte.class : int.class;
Reflection.Field<?> lookYaw = Reflection.getField(packetClass, pitchYawType, isByteClass ? 0 : 1);
Reflection.Field<?> lookPitch = Reflection.getField(packetClass, pitchYawType, isByteClass ? 1 : 2);
return (packet, x, y, z, pitch, yaw) -> {
posX.set(packet, x);
posY.set(packet, y);
posZ.set(packet, z);
if (isByteClass) {
lookYaw.set(packet, (byte) (yaw*256/360));
lookPitch.set(packet, (byte) (pitch*256/360));
} else {
lookYaw.set(packet, (int) (yaw*256/360));
lookPitch.set(packet, (int) (pitch*256/360));
}
};
}
}
public BountifulWrapper.PositionSetter getRelMoveSetter(Class<?> packetClass) {
Class<?> type = Core.getVersion() > 12 ? short.class : int.class;
int fieldOffset = Core.getVersion() > 12 ? 0 : 1;
Reflection.Field<?> moveX = Reflection.getField(packetClass, type, 0 + fieldOffset);
Reflection.Field<?> moveY = Reflection.getField(packetClass, type, 1 + fieldOffset);
Reflection.Field<?> moveZ = Reflection.getField(packetClass, type, 2 + fieldOffset);
Reflection.Field<Byte> moveYaw = Reflection.getField(packetClass, byte.class, 0);
Reflection.Field<Byte> movePitch = Reflection.getField(packetClass, byte.class, 1);
return (packet, x, y, z, pitch, yaw) -> {
moveX.set(packet, (short)(x*4096));
moveY.set(packet, (short)(y*4096));
moveZ.set(packet, (short)(z*4096));
moveYaw.set(packet, (byte)(yaw*256/360));
movePitch.set(packet, (byte)(pitch*256/360));
};
}
public BountifulWrapper.UUIDSetter getUUIDSetter(Class<?> packetClass) {
Reflection.Field<UUID> uuidField = Reflection.getField(packetClass, UUID.class, 0);
return uuidField::set;
} }
public interface PositionSetter { public interface PositionSetter {
@@ -19,11 +19,26 @@
package de.steamwar.core; package de.steamwar.core;
public interface ChatWrapper { import net.minecraft.network.chat.MutableComponent;
ChatWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); import net.minecraft.network.chat.contents.PlainTextContents;
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
import net.minecraft.network.syncher.SynchedEntityData;
import java.util.ArrayList;
Object stringToChatComponent(String text); public class ChatWrapper {
public static final ChatWrapper impl = new ChatWrapper();
Object getDataWatcherPacket(int entityId, Object... dataWatcherKeyValues); public Object stringToChatComponent(String text) {
return MutableComponent.create(PlainTextContents.create(text));
}
public Object getDataWatcherPacket(int entityId, Object... dataWatcherKeyValues) {
ArrayList<SynchedEntityData.DataValue<?>> nativeWatchers = new ArrayList<>(1);
for(int i = 0; i < dataWatcherKeyValues.length; i+=2) {
nativeWatchers.add(((SynchedEntityData.DataItem<?>) BountifulWrapper.impl.getDataWatcherItem(dataWatcherKeyValues[i], dataWatcherKeyValues[i+1])).value());
}
return new ClientboundSetEntityDataPacket(entityId, nativeWatchers);
}
} }
@@ -19,22 +19,20 @@
package de.steamwar.core; package de.steamwar.core;
import de.steamwar.Reflection;
import lombok.experimental.UtilityClass; import lombok.experimental.UtilityClass;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.SimpleCommandMap; import org.bukkit.craftbukkit.CraftServer;
import java.util.Map; import java.util.Map;
@UtilityClass @UtilityClass
public class CommandRemover { public class CommandRemover {
private static final Reflection.Field<SimpleCommandMap> commandMap = Reflection.getField("org.bukkit.craftbukkit.CraftServer", "commandMap", SimpleCommandMap.class); private static final Map<String, Command> knownCommands = ((CraftServer) Bukkit.getServer()).getCommandMap().getKnownCommands();
private static final Reflection.Field<Map> knownCommands = Reflection.getField(SimpleCommandMap.class, "knownCommands", Map.class);
public static void removeAll(String... cmds) { public static void removeAll(String... cmds) {
Map<String, Command> knownCmds = knownCommands.get(commandMap.get(Bukkit.getServer()));
for (String cmd : cmds) { for (String cmd : cmds) {
knownCmds.remove(cmd.toLowerCase()); knownCommands.remove(cmd.toLowerCase());
} }
} }
} }
@@ -21,16 +21,11 @@ package de.steamwar.core;
import com.comphenix.tinyprotocol.TinyProtocol; import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.Reflection; import de.steamwar.Reflection;
import de.steamwar.command.*;
import de.steamwar.core.authlib.SteamwarGameProfileRepository;
import de.steamwar.core.events.AntiNocom;
import de.steamwar.core.events.ChattingEvent;
import de.steamwar.core.events.PlayerJoinedEvent;
import de.steamwar.core.events.WorldLoadEvent;
import de.steamwar.command.SWCommandUtils; import de.steamwar.command.SWCommandUtils;
import de.steamwar.command.SWTypeMapperCreator; import de.steamwar.command.SWTypeMapperCreator;
import de.steamwar.command.TabCompletionCache; import de.steamwar.command.TabCompletionCache;
import de.steamwar.command.TypeMapper; import de.steamwar.command.TypeMapper;
import de.steamwar.core.authlib.SteamwarGameProfileRepository;
import de.steamwar.linkage.AbstractLinker; import de.steamwar.linkage.AbstractLinker;
import de.steamwar.linkage.SpigotLinker; import de.steamwar.linkage.SpigotLinker;
import de.steamwar.message.Message; import de.steamwar.message.Message;
@@ -54,6 +49,7 @@ public class Core extends JavaPlugin {
public static final Message MESSAGE = new Message("SpigotCore", Core.class.getClassLoader()); public static final Message MESSAGE = new Message("SpigotCore", Core.class.getClassLoader());
@Deprecated
public static int getVersion(){ public static int getVersion(){
return Reflection.MAJOR_VERSION; return Reflection.MAJOR_VERSION;
} }
@@ -108,9 +104,8 @@ public class Core extends JavaPlugin {
return; return;
} }
Bukkit.getServer().getPluginManager().registerEvents(RecipeDiscoverWrapper.impl, this);
if(!Statement.productionDatabase()) { if(!Statement.productionDatabase()) {
getServer().getPluginManager().registerEvents(LocaleChangeWrapper.impl, this); getServer().getPluginManager().registerEvents(new LocaleChangeWrapper(), this);
} }
getServer().getMessenger().registerIncomingPluginChannel(this, "sw:bridge", new NetworkReceiver()); getServer().getMessenger().registerIncomingPluginChannel(this, "sw:bridge", new NetworkReceiver());
@@ -19,14 +19,18 @@
package de.steamwar.core; package de.steamwar.core;
import com.comphenix.tinyprotocol.TinyProtocol;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import org.bukkit.craftbukkit.CraftChunk;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
public class CraftbukkitWrapper { public class CraftbukkitWrapper {
private CraftbukkitWrapper() {} public static final CraftbukkitWrapper impl = new CraftbukkitWrapper();
public static final ICraftbukkitWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); public void sendChunk(Player p, int chunkX, int chunkZ) {
LevelChunk chunk = (LevelChunk) ((CraftChunk) p.getWorld().getChunkAt(chunkX, chunkZ)).getHandle(ChunkStatus.FULL);
public interface ICraftbukkitWrapper { TinyProtocol.instance.sendPacket(p, new ClientboundLevelChunkWithLightPacket(chunk, chunk.level.getLightEngine(), null, null, true));
void sendChunk(Player p, int chunkX, int chunkZ);
} }
} }
@@ -21,6 +21,7 @@ package de.steamwar.core;
import de.steamwar.Reflection; import de.steamwar.Reflection;
import de.steamwar.sql.SWException; import de.steamwar.sql.SWException;
import org.spigotmc.WatchdogThread;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.PrintStream; import java.io.PrintStream;
@@ -39,10 +40,8 @@ public class ErrorHandler extends Handler {
public ErrorHandler(){ public ErrorHandler(){
Logger.getLogger("").addHandler(this); Logger.getLogger("").addHandler(this);
Class<?> watchdogThread = Reflection.getClass("org.spigotmc.WatchdogThread"); Reflection.Field<WatchdogThread> getInstance = Reflection.getField(WatchdogThread.class, WatchdogThread.class, 0);
Reflection.Field<?> getInstance = Reflection.getField(watchdogThread, watchdogThread, 0); watchdogThreadId = getInstance.get(null).getId();
Thread watchdog = (Thread) getInstance.get(null);
watchdogThreadId = watchdog.getId();
} }
void unregister() { void unregister() {
@@ -19,38 +19,343 @@
package de.steamwar.core; package de.steamwar.core;
import com.destroystokyo.paper.profile.PlayerProfile;
import de.steamwar.Reflection; import de.steamwar.Reflection;
import org.bukkit.Material; import net.minecraft.network.protocol.game.ClientboundSetObjectivePacket;
import org.bukkit.World; import net.minecraft.network.protocol.game.ClientboundSetScorePacket;
import org.bukkit.*;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.SkullMeta;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class FlatteningWrapper { public class FlatteningWrapper {
private FlatteningWrapper() {} private FlatteningWrapper() {}
public static final Class<?> scoreboardObjective = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundSetObjectivePacket"); public static final FlatteningWrapper impl = new FlatteningWrapper();
public static final Class<?> scoreboardScore = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundSetScorePacket");
public static final IFlatteningWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); private static final Map<String, Material> renamedLegacy = new HashMap<>();
public interface IFlatteningWrapper { static{
void setScoreboardTitle(Object packet, String title); renamedLegacy.put("WOOD", Material.OAK_WOOD);
void setScoreAction(Object packet); renamedLegacy.put("SAPLING", Material.OAK_SAPLING);
renamedLegacy.put("STATIONARY_WATER", Material.WATER);
renamedLegacy.put("STATIONARY_LAVA", Material.LAVA);
renamedLegacy.put("LOG", Material.OAK_LOG);
renamedLegacy.put("LEAVES", Material.OAK_LEAVES);
renamedLegacy.put("BED_BLOCK", Material.RED_BED);
renamedLegacy.put("BED", Material.RED_BED);
renamedLegacy.put("PISTON_STICKY_BASE", Material.STICKY_PISTON);
renamedLegacy.put("WEB", Material.COBWEB);
renamedLegacy.put("LONG_GRASS", Material.TALL_GRASS);
renamedLegacy.put("PISTON_BASE", Material.PISTON);
renamedLegacy.put("PISTON_EXTENSION", Material.PISTON_HEAD);
renamedLegacy.put("WOOL", Material.WHITE_WOOL);
renamedLegacy.put("PISTON_MOVING_PIECE", Material.MOVING_PISTON);
renamedLegacy.put("YELLOW_FLOWER", Material.DANDELION);
renamedLegacy.put("RED_ROSE", Material.POPPY);
renamedLegacy.put("DOUBLE_STEP", Material.SMOOTH_STONE);
renamedLegacy.put("STEP", Material.SMOOTH_STONE_SLAB);
renamedLegacy.put("MOB_SPAWNER", Material.SPAWNER);
renamedLegacy.put("WOOD_STAIRS", Material.OAK_STAIRS);
renamedLegacy.put("WORKBENCH", Material.CRAFTING_TABLE);
renamedLegacy.put("CROPS", Material.WHEAT_SEEDS);
renamedLegacy.put("SEEDS", Material.WHEAT_SEEDS);
renamedLegacy.put("SOIL", Material.FARMLAND);
renamedLegacy.put("BURNING_FURNACE", Material.FURNACE);
renamedLegacy.put("SIGN_POST", Material.OAK_SIGN);
renamedLegacy.put("SIGN", Material.OAK_SIGN);
renamedLegacy.put("WOODEN_DOOR", Material.OAK_DOOR);
renamedLegacy.put("WOOD_DOOR", Material.OAK_DOOR);
renamedLegacy.put("RAILS", Material.RAIL);
renamedLegacy.put("WALL_SIGN", Material.OAK_WALL_SIGN);
renamedLegacy.put("STONE_PLATE", Material.STONE_PRESSURE_PLATE);
renamedLegacy.put("WOOD_PLATE", Material.OAK_PRESSURE_PLATE);
renamedLegacy.put("GLOWING_REDSTONE_ORE", Material.REDSTONE_ORE);
renamedLegacy.put("REDSTONE_TORCH_OFF", Material.REDSTONE_TORCH);
renamedLegacy.put("REDSTONE_TORCH_ON", Material.REDSTONE_TORCH);
renamedLegacy.put("IRON_DOOR_BLOCK", Material.IRON_DOOR);
renamedLegacy.put("SUGAR_CANE_BLOCK", Material.SUGAR_CANE);
renamedLegacy.put("CAKE_BLOCK", Material.CAKE);
renamedLegacy.put("MELON_BLOCK", Material.MELON);
renamedLegacy.put("BEETROOT_BLOCK", Material.BEETROOT);
renamedLegacy.put("FENCE", Material.OAK_FENCE);
renamedLegacy.put("PORTAL", Material.NETHER_PORTAL);
renamedLegacy.put("DIODE_BLOCK_OFF", Material.REPEATER);
renamedLegacy.put("DIODE_BLOCK_ON", Material.REPEATER);
renamedLegacy.put("DIODE", Material.REPEATER);
renamedLegacy.put("STAINED_GLASS", Material.WHITE_STAINED_GLASS);
renamedLegacy.put("TRAP_DOOR", Material.OAK_TRAPDOOR);
renamedLegacy.put("MONSTER_EGGS", Material.SKELETON_SPAWN_EGG);
renamedLegacy.put("MONSTER_EGG", Material.SKELETON_SPAWN_EGG);
renamedLegacy.put("SMOOTH_BRICK", Material.STONE_BRICKS);
renamedLegacy.put("HUGE_MUSHROOM_1", Material.MUSHROOM_STEM);
renamedLegacy.put("HUGE_MUSHROOM_2", Material.RED_MUSHROOM);
renamedLegacy.put("IRON_FENCE", Material.IRON_BARS);
renamedLegacy.put("THIN_GLASS", Material.GLASS_PANE);
renamedLegacy.put("FENCE_GATE", Material.OAK_FENCE_GATE);
renamedLegacy.put("SMOOTH_STAIRS", Material.STONE_BRICK_STAIRS);
renamedLegacy.put("MYCEL", Material.MYCELIUM);
renamedLegacy.put("WATER_LILY", Material.LILY_PAD);
renamedLegacy.put("NETHER_FENCE", Material.NETHER_BRICK_FENCE);
renamedLegacy.put("NETHER_WARTS", Material.NETHER_WART);
renamedLegacy.put("NETHER_STALK", Material.NETHER_WART);
renamedLegacy.put("ENCHANTMENT_TABLE", Material.ENCHANTING_TABLE);
renamedLegacy.put("ENDER_PORTAL", Material.END_PORTAL);
renamedLegacy.put("ENDER_PORTAL_FRAME", Material.END_PORTAL_FRAME);
renamedLegacy.put("ENDER_STONE", Material.END_STONE);
renamedLegacy.put("REDSTONE_LAMP_OFF", Material.REDSTONE_LAMP);
renamedLegacy.put("REDSTONE_LAMP_ON", Material.REDSTONE_LAMP);
renamedLegacy.put("WOOD_DOUBLE_STEP", Material.OAK_SLAB);
renamedLegacy.put("WOOD_STEP", Material.OAK_SLAB);
renamedLegacy.put("SPRUCE_WOOD_STAIRS", Material.SPRUCE_STAIRS);
renamedLegacy.put("BIRCH_WOOD_STAIRS", Material.BIRCH_STAIRS);
renamedLegacy.put("JUNGLE_WOOD_STAIRS", Material.JUNGLE_STAIRS);
renamedLegacy.put("COMMAND", Material.COMMAND_BLOCK);
renamedLegacy.put("COBBLE_WALL", Material.COBBLESTONE_WALL);
renamedLegacy.put("WOOD_BUTTON", Material.OAK_BUTTON);
renamedLegacy.put("SKULL", Material.SKELETON_SKULL);
renamedLegacy.put("SKULL_ITEM", Material.SKELETON_SKULL);
renamedLegacy.put("GOLD_PLATE", Material.LIGHT_WEIGHTED_PRESSURE_PLATE);
renamedLegacy.put("IRON_PLATE", Material.HEAVY_WEIGHTED_PRESSURE_PLATE);
renamedLegacy.put("REDSTONE_COMPARATOR_OFF", Material.COMPARATOR);
renamedLegacy.put("REDSTONE_COMPARATOR_ON", Material.COMPARATOR);
renamedLegacy.put("REDSTONE_COMPARATOR", Material.COMPARATOR);
renamedLegacy.put("QUARTZ_ORE", Material.QUARTZ);
renamedLegacy.put("STAINED_CLAY", Material.WHITE_TERRACOTTA);
renamedLegacy.put("STAINED_GLASS_PANE", Material.WHITE_STAINED_GLASS_PANE);
renamedLegacy.put("LEAVES_2", Material.ACACIA_LEAVES);
renamedLegacy.put("LOG_2", Material.ACACIA_LOG);
renamedLegacy.put("CARPET", Material.WHITE_CARPET);
renamedLegacy.put("HARD_CLAY", Material.TERRACOTTA);
renamedLegacy.put("DOUBLE_PLANT", Material.SUNFLOWER);
renamedLegacy.put("STANDING_BANNER", Material.WHITE_BANNER);
renamedLegacy.put("BANNER", Material.WHITE_BANNER);
renamedLegacy.put("WALL_BANNER", Material.WHITE_WALL_BANNER);
renamedLegacy.put("DAYLIGHT_DETECTOR_INVERTED", Material.DAYLIGHT_DETECTOR);
renamedLegacy.put("DOUBLE_STONE_SLAB2", Material.RED_SANDSTONE_SLAB);
renamedLegacy.put("STONE_SLAB2", Material.RED_SANDSTONE_SLAB);
renamedLegacy.put("PURPUR_DOUBLE_SLAB", Material.PURPUR_SLAB);
renamedLegacy.put("END_BRICKS", Material.END_STONE_BRICKS);
renamedLegacy.put("COMMAND_REPEATING", Material.REPEATING_COMMAND_BLOCK);
renamedLegacy.put("COMMAND_CHAIN", Material.CHAIN_COMMAND_BLOCK);
renamedLegacy.put("MAGMA", Material.MAGMA_BLOCK);
renamedLegacy.put("RED_NETHER_BRICK", Material.RED_NETHER_BRICKS);
renamedLegacy.put("SILVER_SHULKER_BOX", Material.LIGHT_GRAY_SHULKER_BOX);
renamedLegacy.put("SILVER_GLAZED_TERRACOTTA", Material.LIGHT_GRAY_TERRACOTTA);
renamedLegacy.put("CONCRETE", Material.WHITE_CONCRETE);
renamedLegacy.put("CONCRETE_POWDER", Material.WHITE_CONCRETE_POWDER);
renamedLegacy.put("IRON_SPADE", Material.IRON_SHOVEL);
renamedLegacy.put("WOOD_SWORD", Material.WOODEN_SWORD);
renamedLegacy.put("WOOD_SPADE", Material.WOODEN_SHOVEL);
renamedLegacy.put("WOOD_PICKAXE", Material.WOODEN_PICKAXE);
renamedLegacy.put("WOOD_AXE", Material.WOODEN_AXE);
renamedLegacy.put("STONE_SPADE", Material.STONE_SHOVEL);
renamedLegacy.put("DIAMOND_SPADE", Material.DIAMOND_SHOVEL);
renamedLegacy.put("MUSHROOM_SOUP", Material.MUSHROOM_STEW);
renamedLegacy.put("GOLD_SWORD", Material.GOLDEN_SWORD);
renamedLegacy.put("GOLD_SPADE", Material.GOLDEN_SHOVEL);
renamedLegacy.put("GOLD_PICKAXE", Material.GOLDEN_PICKAXE);
renamedLegacy.put("GOLD_AXE", Material.GOLDEN_AXE);
renamedLegacy.put("SULPHUR", Material.GUNPOWDER);
renamedLegacy.put("WOOD_HOE", Material.WOODEN_HOE);
renamedLegacy.put("GOLD_HOE", Material.GOLDEN_HOE);
renamedLegacy.put("GOLD_HELMET", Material.GOLDEN_HELMET);
renamedLegacy.put("GOLD_CHESTPLATE", Material.GOLDEN_CHESTPLATE);
renamedLegacy.put("GOLD_LEGGINGS", Material.GOLDEN_LEGGINGS);
renamedLegacy.put("GOLD_BOOTS", Material.GOLDEN_BOOTS);
renamedLegacy.put("PORK", Material.PORKCHOP);
renamedLegacy.put("GRILLED_PORK", Material.COOKED_PORKCHOP);
renamedLegacy.put("SNOW_BALL", Material.SNOWBALL);
renamedLegacy.put("BOAT", Material.OAK_BOAT);
renamedLegacy.put("CLAY_BRICK", Material.BRICKS);
renamedLegacy.put("STORAGE_MINECART", Material.CHEST_MINECART);
renamedLegacy.put("POWERED_MINECART", Material.FURNACE_MINECART);
renamedLegacy.put("WATCH", Material.CLOCK);
renamedLegacy.put("RAW_FISH", Material.SALMON);
renamedLegacy.put("COOKED_FISH", Material.COOKED_SALMON);
renamedLegacy.put("INK_SACK", Material.INK_SAC);
renamedLegacy.put("RAW_BEEF", Material.BEEF);
renamedLegacy.put("RAW_CHICKEN", Material.CHICKEN);
renamedLegacy.put("EYE_OF_ENDER", Material.ENDER_EYE);
renamedLegacy.put("SPECKLED_MELON", Material.GLISTERING_MELON_SLICE);
renamedLegacy.put("EXP_BOTTLE", Material.EXPERIENCE_BOTTLE);
renamedLegacy.put("FIREBALL", Material.FIRE_CHARGE);
renamedLegacy.put("BOOK_AND_QUILL", Material.WRITABLE_BOOK);
renamedLegacy.put("FLOWER_POT_ITEM", Material.FLOWER_POT);
renamedLegacy.put("EMPTY_MAP", Material.MAP);
renamedLegacy.put("BREWING_STAND_ITEM", Material.BREWING_STAND);
renamedLegacy.put("CAULDRON_ITEM", Material.CAULDRON);
renamedLegacy.put("CARROT_ITEM", Material.CARROT);
renamedLegacy.put("POTATO_ITEM", Material.POTATO);
renamedLegacy.put("SPRUCE_DOOR_ITEM", Material.SPRUCE_DOOR);
renamedLegacy.put("BIRCH_DOOR_ITEM", Material.BIRCH_DOOR);
renamedLegacy.put("JUNGLE_DOOR_ITEM", Material.JUNGLE_DOOR);
renamedLegacy.put("ACACIA_DOOR_ITEM", Material.ACACIA_DOOR);
renamedLegacy.put("DARK_OAK_DOOR_ITEM", Material.DARK_OAK_DOOR);
renamedLegacy.put("CARROT_STICK", Material.CARROT_ON_A_STICK);
renamedLegacy.put("FIREWORK", Material.FIREWORK_ROCKET);
renamedLegacy.put("FIREWORK_CHARGE", Material.FIREWORK_STAR);
renamedLegacy.put("NETHER_BRICK_ITEM", Material.NETHER_BRICKS);
renamedLegacy.put("EXPLOSIVE_MINECART", Material.TNT_MINECART);
renamedLegacy.put("IRON_BARDING", Material.IRON_HORSE_ARMOR);
renamedLegacy.put("GOLD_BARDING", Material.GOLDEN_HORSE_ARMOR);
renamedLegacy.put("DIAMOND_BARDING", Material.DIAMOND_HORSE_ARMOR);
renamedLegacy.put("LEASH", Material.LEAD);
renamedLegacy.put("COMMAND_MINECART", Material.COMMAND_BLOCK_MINECART);
renamedLegacy.put("CHORUS_FRUIT_POPPED", Material.POPPED_CHORUS_FRUIT);
renamedLegacy.put("DRAGONS_BREATH", Material.DRAGON_BREATH);
renamedLegacy.put("BOAT_SPRUCE", Material.SPRUCE_BOAT);
renamedLegacy.put("BOAT_BIRCH", Material.BIRCH_BOAT);
renamedLegacy.put("BOAT_JUNGLE", Material.JUNGLE_BOAT);
renamedLegacy.put("BOAT_ACACIA", Material.ACACIA_BOAT);
renamedLegacy.put("BOAT_DARK_OAK", Material.DARK_OAK_BOAT);
renamedLegacy.put("TOTEM", Material.TOTEM_OF_UNDYING);
renamedLegacy.put("GOLD_RECORD", Material.MUSIC_DISC_13);
renamedLegacy.put("GREEN_RECORD", Material.MUSIC_DISC_CAT);
renamedLegacy.put("RECORD_3", Material.MUSIC_DISC_BLOCKS);
renamedLegacy.put("RECORD_4", Material.MUSIC_DISC_CHIRP);
renamedLegacy.put("RECORD_5", Material.MUSIC_DISC_FAR);
renamedLegacy.put("RECORD_6", Material.MUSIC_DISC_MALL);
renamedLegacy.put("RECORD_7", Material.MUSIC_DISC_MELLOHI);
renamedLegacy.put("RECORD_8", Material.MUSIC_DISC_STAL);
renamedLegacy.put("RECORD_9", Material.MUSIC_DISC_STRAD);
renamedLegacy.put("RECORD_10", Material.MUSIC_DISC_WARD);
renamedLegacy.put("RECORD_11", Material.MUSIC_DISC_11);
renamedLegacy.put("RECORD_12", Material.MUSIC_DISC_WAIT);
}
Material getMaterial(String material); private static final Reflection.Field<?> scoreboardName = Reflection.getField(ClientboundSetObjectivePacket.class, Reflection.getClass("net.minecraft.network.chat.Component"), 0);
Material getDye(int colorCode); public void setScoreboardTitle(Object packet, String title) {
ItemStack setSkullOwner(String player); scoreboardName.set(packet, ChatWrapper.impl.stringToChatComponent(title));
}
Object getPose(EntityPose pose); private static final Class<?> scoreActionEnum = Core.getVersion() < 21 ? Reflection.getClass("net.minecraft.server.ServerScoreboard$Method") : null;
void setNamedSpawnPacketDataWatcher(Object packet); private static final Reflection.Field<?> scoreAction = Core.getVersion() < 21 ? Reflection.getField(ClientboundSetScorePacket.class, scoreActionEnum, 0) : null;
Object formatDisplayName(String displayName); private static final Object scoreActionChange = Core.getVersion() < 21 ? scoreActionEnum.getEnumConstants()[0] : null;
void setSpawnPacketType(Object packet, EntityType type); public void setScoreAction(Object packet) {
scoreAction.set(packet, scoreActionChange);
}
int getViewDistance(Player player); public Material getMaterial(String material) {
try{
return Material.valueOf(material);
}catch(IllegalArgumentException e){
return renamedLegacy.get(material);
}
}
void syncSave(World world); public Material getDye(int colorCode) {
switch(colorCode){
case 1:
return Material.RED_DYE;
case 2:
return Material.GREEN_DYE;
case 3:
return Material.BROWN_DYE;
case 4:
return Material.LAPIS_LAZULI;
case 5:
return Material.PURPLE_DYE;
case 6:
return Material.CYAN_DYE;
case 7:
return Material.LIGHT_GRAY_DYE;
case 8:
return Material.GRAY_DYE;
case 9:
return Material.PINK_DYE;
case 10:
return Material.LIME_DYE;
case 11:
return Material.YELLOW_DYE;
case 12:
return Material.LIGHT_BLUE_DYE;
case 13:
return Material.MAGENTA_DYE;
case 14:
return Material.ORANGE_DYE;
case 15:
return Material.WHITE_DYE;
default:
return Material.BLACK_DYE;
}
}
public ItemStack setSkullOwner(String player) {
ItemStack head = new ItemStack(Material.PLAYER_HEAD, 1);
head.editMeta(SkullMeta.class, skullMeta -> {
try {
OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(player.startsWith(".") ? player.substring(1) : player);
PlayerProfile playerProfile = offlinePlayer.getPlayerProfile();
playerProfile.complete();
skullMeta.setPlayerProfile(playerProfile);
} catch (Exception e) {
// Ignore
}
});
return head;
}
protected static final Class<?> entityPose = Reflection.getClass("net.minecraft.world.entity.Pose");
protected static final Object shooting = entityPose.getEnumConstants()[16];
protected static final Object standing = entityPose.getEnumConstants()[0];
protected static final Object swimming = entityPose.getEnumConstants()[3];
protected static final Object sneaking = entityPose.getEnumConstants()[5];
public Object getPose(FlatteningWrapper.EntityPose pose) {
switch (pose) {
case SHOOTING:
return shooting;
case SNEAKING:
return sneaking;
case SWIMMING:
return swimming;
case NORMAL:
default:
return standing;
}
}
public void setNamedSpawnPacketDataWatcher(Object packet) {
// field not present
}
public Object formatDisplayName(String displayName) {
return displayName != null ? Optional.of(ChatWrapper.impl.stringToChatComponent(displayName)) : Optional.empty();
}
private static final Class<?> registryBlocks = Reflection.getClass("net.minecraft.core.DefaultedRegistry");
private static final Class<?> entityTypes = Reflection.getClass("net.minecraft.world.entity.EntityType");
private static final Object entityTypesRegistry = Reflection.getField(Reflection.getClass(Core.getVersion() > 18 ? "net.minecraft.core.registries.BuiltInRegistries" : "net.minecraft.core.IRegistry"), registryBlocks, 0, entityTypes).get(null);
private static final Reflection.Method get = Reflection.getMethod(registryBlocks, null, Reflection.getClass("net.minecraft.resources.ResourceLocation"));
private static final Reflection.Field<?> spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, entityTypes, 0);
private static final Reflection.Field<?> spawnLivingType = Core.getVersion() > 18 ? spawnType : Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 1);
private static final Reflection.Method toMinecraft = Reflection.getMethod("org.bukkit.craftbukkit.util.CraftNamespacedKey", "toMinecraft", NamespacedKey.class);
private static final Map<EntityType, Object> types = new HashMap<>();
static {
types.put(EntityType.ARMOR_STAND, 1);
}
public void setSpawnPacketType(Object packet, EntityType type) {
if(type.isAlive()) {
spawnLivingType.set(packet, Core.getVersion() > 18 ? get.invoke(entityTypesRegistry, toMinecraft.invoke(null, type.getKey())) : types.get(type));
} else {
spawnType.set(packet, get.invoke(entityTypesRegistry, toMinecraft.invoke(null, type.getKey())));
}
}
public int getViewDistance(Player player) {
return player.getClientViewDistance();
}
private static final Reflection.Method getHandle = Reflection.getMethod("org.bukkit.craftbukkit.CraftWorld", "getHandle");
private static final Reflection.Method save = Reflection.getMethod("net.minecraft.server.level.ServerLevel", null, Reflection.getClass("net.minecraft.util.ProgressListener"), boolean.class, boolean.class);
public void syncSave(World world) {
save.invoke(getHandle.invoke(world), null, true, false);
} }
public enum EntityPose { public enum EntityPose {
@@ -19,8 +19,17 @@
package de.steamwar.core; package de.steamwar.core;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLocaleChangeEvent;
public interface LocaleChangeWrapper extends Listener { import java.util.Locale;
LocaleChangeWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
public class LocaleChangeWrapper implements Listener {
@EventHandler
private void onLocale(PlayerLocaleChangeEvent event) {
SteamwarUser.get(event.getPlayer().getUniqueId()).setLocale(Locale.forLanguageTag(event.getLocale()), false);
}
} }
@@ -19,37 +19,50 @@
package de.steamwar.core; package de.steamwar.core;
import de.steamwar.Reflection;
import com.mojang.authlib.GameProfile; import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Pair;
import de.steamwar.Reflection;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameType;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import java.util.function.LongSupplier; import java.util.Collections;
import java.util.EnumSet;
public interface ProtocolWrapper { public class ProtocolWrapper {
Class<?> itemStack = Reflection.getClass("net.minecraft.world.item.ItemStack"); public static final Class<?> itemStack = Reflection.getClass("net.minecraft.world.item.ItemStack");
Class<?> spawnPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundAddEntityPacket"); public static final Class<?> spawnPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundAddEntityPacket");
Class<?> spawnLivingPacket = Core.getVersion() > 18 ? ProtocolWrapper.spawnPacket : Reflection.getClass("net.minecraft.network.protocol.game.PacketPlayOutSpawnEntityLiving"); public static final Class<?> spawnLivingPacket = Core.getVersion() > 18 ? ProtocolWrapper.spawnPacket : Reflection.getClass("net.minecraft.network.protocol.game.PacketPlayOutSpawnEntityLiving");
Class<?> equipmentPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket"); public static final Class<?> equipmentPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket");
Class<?> enumGamemode = Reflection.getClass(Core.getVersion() > 9 ? "net.minecraft.world.level.GameType" : "net.minecraft.WorldSettings$EnumGamemode"); public static final Class<?> enumGamemode = Reflection.getClass(Core.getVersion() > 9 ? "net.minecraft.world.level.GameType" : "net.minecraft.WorldSettings$EnumGamemode");
Reflection.Method getGameModeById = Reflection.getTypedMethod(enumGamemode, null, enumGamemode, int.class); public static final Reflection.Method getGameModeById = Reflection.getTypedMethod(enumGamemode, null, enumGamemode, int.class);
// 0: hand, 1: offhand, 2: feet, 3: legs, 4: chest, 5: head // 0: hand, 1: offhand, 2: feet, 3: legs, 4: chest, 5: head
Object[] itemSlots = Core.getVersion() > 8 ? Reflection.getClass("net.minecraft.world.entity.EnumItemSlot").getEnumConstants() : new Integer[]{0, 0, 1, 2, 3, 4}; public static final Object[] itemSlots = Core.getVersion() > 8 ? Reflection.getClass("net.minecraft.world.entity.EnumItemSlot").getEnumConstants() : new Integer[]{0, 0, 1, 2, 3, 4};
ProtocolWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); public static final ProtocolWrapper impl = new ProtocolWrapper();
void setEquipmentPacketStack(Object packet, Object slot, Object stack); public void setEquipmentPacketStack(Object packet, Object slot, Object stack) {
ClientboundSetEquipmentPacket setEquipmentPacket = (ClientboundSetEquipmentPacket) packet;
Object playerInfoPacketConstructor(PlayerInfoAction action, GameProfile profile, GameMode mode); setEquipmentPacket.getSlots().add(Pair.of((EquipmentSlot) slot, (ItemStack) stack));
default void initTPSWarp(LongSupplier longSupplier) {
Class<?> systemUtils = Reflection.getClass("net.minecraft.Util");
Reflection.getField(systemUtils, LongSupplier.class, 0).set(systemUtils, (LongSupplier) () -> System.nanoTime() + longSupplier.getAsLong());
} }
enum PlayerInfoAction { public Object playerInfoPacketConstructor(PlayerInfoAction action, GameProfile profile, GameMode mode) {
if(action == PlayerInfoAction.REMOVE)
return new ClientboundPlayerInfoRemovePacket(Collections.singletonList(profile.getId()));
return new ClientboundPlayerInfoUpdatePacket(action == PlayerInfoAction.ADD ?
EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE) : EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE),
Collections.singletonList(new ClientboundPlayerInfoUpdatePacket.Entry(profile.getId(), profile, false, 0, GameType.byId(mode.getValue()), null, false, 0, null)));
}
public enum PlayerInfoAction {
ADD, ADD,
GAMEMODE, GAMEMODE,
REMOVE REMOVE
@@ -19,8 +19,15 @@
package de.steamwar.core; package de.steamwar.core;
import de.steamwar.linkage.Linked;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerRecipeDiscoverEvent;
public interface RecipeDiscoverWrapper extends Listener { @Linked
RecipeDiscoverWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); public class RecipeDiscoverWrapper implements Listener {
@EventHandler
public void onRecipeDiscover(PlayerRecipeDiscoverEvent e) {
e.setCancelled(true);
}
} }
@@ -1,52 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core;
import lombok.experimental.UtilityClass;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitTask;
@UtilityClass
public class TPSWarpUtils {
private static long nanoOffset = 0;
private static long nanoDOffset = 0;
private static BukkitTask bukkitTask = null;
static {
ProtocolWrapper.impl.initTPSWarp(() -> nanoOffset);
}
public static void warp(double tps) {
double d = 50 - (50 / (tps / 20.0));
nanoDOffset = Math.max(0, (long) (d * 1000000));
if (nanoDOffset == 0) {
if (bukkitTask == null) return;
bukkitTask.cancel();
bukkitTask = null;
} else if (bukkitTask == null) {
bukkitTask = Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> nanoOffset += nanoDOffset, 1, 1);
}
}
public static boolean isWarping() {
return nanoDOffset > 0;
}
}
@@ -21,8 +21,10 @@ package de.steamwar.core;
import org.bukkit.Particle; import org.bukkit.Particle;
public interface TrickyParticleWrapper { public class TrickyParticleWrapper {
public TrickyParticleWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); public static final TrickyParticleWrapper impl = new TrickyParticleWrapper();
Particle getVillagerHappy(); public Particle getVillagerHappy() {
return Particle.HAPPY_VILLAGER;
}
} }
@@ -24,14 +24,22 @@ import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment; import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
public interface TrickyTrialsWrapper { public class TrickyTrialsWrapper {
TrickyTrialsWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); public static final TrickyTrialsWrapper impl = new TrickyTrialsWrapper();
EntityType getTntEntityType(); public EntityType getTntEntityType() {
return EntityType.TNT;
Enchantment getUnbreakingEnchantment(); }
Material getTurtleScute(); public Enchantment getUnbreakingEnchantment() {
return Enchantment.UNBREAKING;
String getValue(Property property); }
public Material getTurtleScute() {
return Material.TURTLE_SCUTE;
}
public String getValue(Property property) {
return property.value();
}
} }
@@ -1,7 +1,7 @@
/* /*
* This file is a part of the SteamWar software. * This file is a part of the SteamWar software.
* *
* Copyright (C) 2025 SteamWar.de-Serverteam * Copyright (C) 2026 SteamWar.de-Serverteam
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@@ -23,6 +23,7 @@ import org.bukkit.plugin.Plugin;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@Deprecated
public class VersionDependent { public class VersionDependent {
private VersionDependent() {} private VersionDependent() {}
@@ -1,7 +1,7 @@
/* /*
* This file is a part of the SteamWar software. * This file is a part of the SteamWar software.
* *
* Copyright (C) 2025 SteamWar.de-Serverteam * Copyright (C) 2026 SteamWar.de-Serverteam
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by * it under the terms of the GNU Affero General Public License as published by
@@ -24,7 +24,7 @@ import org.bukkit.Particle;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
public class WorldEditRendererWrapper9 implements WorldEditRendererWrapper { public class WorldEditRendererFallback {
private static final int VIEW_DISTANCE = 64; private static final int VIEW_DISTANCE = 64;
private static final int SQ_VIEW_DISTANCE = VIEW_DISTANCE * VIEW_DISTANCE; private static final int SQ_VIEW_DISTANCE = VIEW_DISTANCE * VIEW_DISTANCE;
@@ -33,7 +33,6 @@ public class WorldEditRendererWrapper9 implements WorldEditRendererWrapper {
private static final Vector ONES = new Vector(1, 1, 1); private static final Vector ONES = new Vector(1, 1, 1);
private static final Vector STEPS = new Vector(STEP_SIZE, STEP_SIZE, STEP_SIZE); private static final Vector STEPS = new Vector(STEP_SIZE, STEP_SIZE, STEP_SIZE);
@Override
public void draw(Player player, boolean scheduled, boolean clipboard, Vector min, Vector max) { public void draw(Player player, boolean scheduled, boolean clipboard, Vector min, Vector max) {
if (!scheduled) return; if (!scheduled) return;
@@ -77,16 +76,4 @@ public class WorldEditRendererWrapper9 implements WorldEditRendererWrapper {
min.add(stepSize); min.add(stepSize);
} }
} }
@Override
public void tick(Player player) {
}
@Override
public void hide(Player player, boolean clipboard, boolean hide) {
}
@Override
public void remove(Player player) {
}
} }
@@ -19,12 +19,19 @@
package de.steamwar.core; package de.steamwar.core;
import de.steamwar.entity.CWireframe;
import de.steamwar.entity.REntityServer;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
public interface WorldEditRendererWrapper { import java.util.HashMap;
WorldEditRendererWrapper fallback = VersionDependent.getVersionImpl(Core.getInstance(), 9); import java.util.Map;
WorldEditRendererWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
public class WorldEditRendererWrapper {
public static final WorldEditRendererFallback fallback = new WorldEditRendererFallback();
public static final WorldEditRendererWrapper impl = new WorldEditRendererWrapper();
static void safeDraw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) { static void safeDraw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) {
if (PlayerVersion.isBedrock(player) || PlayerVersion.getVersion(player) < 20) { if (PlayerVersion.isBedrock(player) || PlayerVersion.getVersion(player) < 20) {
@@ -34,11 +41,83 @@ public interface WorldEditRendererWrapper {
} }
} }
void draw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2); private static final class BoxPair {
private CWireframe regionBox;
private CWireframe clipboardBox;
void tick(Player player); public CWireframe get(boolean clipboard) {
if (clipboard) {
void hide(Player player, boolean clipboard, boolean hide); return clipboardBox;
} else {
void remove(Player player); return regionBox;
}
}
public void set(boolean clipboard, CWireframe box) {
if (clipboard) {
this.clipboardBox = box;
} else {
this.regionBox = box;
}
}
public void die() {
if (clipboardBox != null) {
clipboardBox.die();
}
if (regionBox != null) {
regionBox.die();
}
}
}
private static final Map<Player, REntityServer> servers = new HashMap<>();
private static final Map<Player, BoxPair> boxes = new HashMap<>();
public void draw(Player player, boolean scheduled, boolean clipboard, Vector pos1, Vector pos2) {
REntityServer server = servers.computeIfAbsent(player, __ -> {
REntityServer entityServer = new REntityServer();
entityServer.addPlayer(player);
return entityServer;
});
WorldEditRendererCUIEditor.Type type = clipboard ? WorldEditRendererCUIEditor.Type.CLIPBOARD : WorldEditRendererCUIEditor.Type.SELECTION;
float width = type.getWidth(player).value;
Material material = type.getMaterial(player);
if (material == Material.BARRIER) {
hide(player, clipboard, true);
return;
}
BlockData block = material.createBlockData();
BoxPair boxPair = boxes.computeIfAbsent(player, __ -> new BoxPair());
CWireframe box = boxPair.get(clipboard);
if (box == null) {
box = new CWireframe(server);
boxPair.set(clipboard, box);
}
box.setPos1And2(pos1.toLocation(player.getWorld()), pos2.toLocation(player.getWorld()));
box.setWidth(width);
box.setBlock(block);
}
public void tick(Player player) {
REntityServer server = servers.get(player);
if (server != null) server.tick();
}
public void hide(Player player, boolean clipboard, boolean hide) {
BoxPair boxPair = boxes.get(player);
if (boxPair == null) return;
CWireframe box = boxPair.get(clipboard);
if (box == null) return;
box.hide(hide);
}
public void remove(Player player) {
BoxPair boxPair = boxes.remove(player);
if (boxPair != null) boxPair.die();
REntityServer server = servers.remove(player);
if (server != null) server.close();
}
} }
@@ -19,9 +19,18 @@
package de.steamwar.core; package de.steamwar.core;
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV2;
import com.fastasyncworldedit.core.extent.clipboard.io.FastSchematicReaderV3;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.worldedit.EmptyClipboardException; import com.sk89q.worldedit.EmptyClipboardException;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.*;
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV1Reader;
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV2Reader;
import com.sk89q.worldedit.extent.clipboard.io.sponge.SpongeSchematicV3Reader;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.math.transform.Transform;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.session.ClipboardHolder;
@@ -30,25 +39,140 @@ import de.steamwar.sql.NodeData;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.util.Vector; import org.bukkit.util.Vector;
import org.enginehub.linbus.stream.LinBinaryIO;
import java.io.*; import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.logging.Level; import java.util.logging.Level;
public interface WorldEditWrapper { public class WorldEditWrapper {
WorldEditWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); public static final WorldEditWrapper impl = new WorldEditWrapper();
InputStream getPlayerClipboard(Player player); public InputStream getPlayerClipboard(Player player) {
return WorldEditWrapper.getPlayerClipboard(player, (outputStream, clipboard, clipboardHolder) -> {
ClipboardWriter writer = BuiltInClipboardFormat.FAST_V3.getWriter(outputStream);
writer.write(clipboard);
writer.close();
});
}
void setPlayerClipboard(Player player, Clipboard clipboard); public void setPlayerClipboard(Player player, Clipboard clipboard) {
Clipboard getClipboard(NodeData data) throws IOException; Actor actor = WorldEditWrapper.getWorldEditPlugin().wrapCommandSender(player);
Clipboard getClipboard(InputStream inputStream) throws IOException; WorldEditWrapper.getWorldEditPlugin().getWorldEdit().getSessionManager().get(actor).setClipboard(new ClipboardHolder(clipboard));
}
Vector getOrigin(Clipboard clipboard); public Clipboard getClipboard(NodeData data) throws IOException {
Vector getMinimum(Region region); ResetableInputStream is = new ResetableInputStream(data.schemData(false));
Vector getMaximum(Region region); for (ClipboardFormat clipboardFormat : ClipboardFormats.getAll()) {
Vector applyTransform(Vector vector, Transform transform); FilterInputStream fis = new FilterInputStream(is) {
@Override
public void close() throws IOException {
// Ignore close call!
}
};
boolean canBeRead = clipboardFormat.isFormat(fis);
is.reset();
if (!canBeRead) continue;
return clipboardFormat.load(is);
}
throw new IOException("No clipboard found");
}
NodeData.SchematicFormat getNativeFormat(); private static final Function<InputStream, ClipboardReader> FastV3 = FastSchematicReaderV3::new;
@SuppressWarnings("removal")
private static final Function<InputStream, ClipboardReader> FastV2 = inputStream -> new FastSchematicReaderV2(new NBTInputStream(inputStream));
@SuppressWarnings("removal")
private static final Function<InputStream, ClipboardReader> McEdit = inputStream -> new MCEditSchematicReader(new NBTInputStream(inputStream));
private static final Function<InputStream, ClipboardReader> SpongeV3 = inputStream -> new SpongeSchematicV3Reader(LinBinaryIO.read(new DataInputStream(inputStream)));
private static final Function<InputStream, ClipboardReader> SpongeV2 = inputStream -> new SpongeSchematicV2Reader(LinBinaryIO.read(new DataInputStream(inputStream)));
private static final Function<InputStream, ClipboardReader> SpongeV1 = inputStream -> new SpongeSchematicV1Reader(LinBinaryIO.read(new DataInputStream(inputStream)));
private static final Function<InputStream, ClipboardReader>[] READERS = new Function[]{
FastV3,
FastV2,
SpongeV3,
SpongeV2,
SpongeV1,
McEdit
};
public Clipboard getClipboard(InputStream inputStream) throws IOException {
ResetableInputStream is = new ResetableInputStream(inputStream);
for (Function<InputStream, ClipboardReader> reader : READERS) {
FilterInputStream fis = new FilterInputStream(is) {
@Override
public void close() throws IOException {
// Ignore close call!
}
};
try {
return reader.apply(fis).read();
} catch (Exception e) {
is.reset();
}
}
is.close();
throw new IOException("No clipboard found");
}
private static class ResetableInputStream extends InputStream {
private InputStream inputStream;
private int pointer = 0;
private List<Integer> list = new ArrayList<>();
public ResetableInputStream(InputStream in) {
this.inputStream = in;
}
@Override
public int read() throws IOException {
if (pointer >= list.size()) {
int data = inputStream.read();
list.add(data);
pointer++;
return data;
}
int data = list.get(pointer);
pointer++;
return data;
}
@Override
public void reset() throws IOException {
pointer = 0;
}
@Override
public void close() throws IOException {
list.clear();
pointer = -1;
}
}
public org.bukkit.util.Vector getOrigin(Clipboard clipboard) {
return new org.bukkit.util.Vector(clipboard.getOrigin().x(), clipboard.getOrigin().y(), clipboard.getOrigin().z());
}
public Vector getMinimum(Region region) {
return new Vector(region.getMinimumPoint().x(), region.getMinimumPoint().y(), region.getMinimumPoint().z());
}
public Vector getMaximum(Region region) {
return new Vector(region.getMaximumPoint().x(), region.getMaximumPoint().y(), region.getMaximumPoint().z());
}
public Vector applyTransform(Vector vector, Transform transform) {
Vector3 v = Vector3.at(vector.getX(), vector.getY(), vector.getZ());
v = transform.apply(v);
return new org.bukkit.util.Vector(v.x(), v.y(), v.z());
}
public NodeData.SchematicFormat getNativeFormat() {
return NodeData.SchematicFormat.SPONGE_V3;
}
static WorldEditPlugin getWorldEditPlugin() { static WorldEditPlugin getWorldEditPlugin() {
return (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"); return (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit");
@@ -19,15 +19,56 @@
package de.steamwar.core; package de.steamwar.core;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.Reflection;
import de.steamwar.linkage.Linked;
import net.minecraft.network.protocol.game.ClientboundLoginPacket;
import net.minecraft.network.protocol.game.CommonPlayerSpawnInfo;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.Level;
@Linked
public class WorldIdentifier { public class WorldIdentifier {
private static final IWorldIdentifier impl = VersionDependent.getVersionImpl(Core.getInstance()); private static ResourceKey<Level> resourceKey = null;
private static final Class<?> resourceKeyClass = Reflection.getClass("net.minecraft.resources.ResourceKey");
private static final Class<?> minecraftKeyClass = Reflection.getClass("net.minecraft.resources.MinecraftKey");
private static final Reflection.Constructor resourceKeyConstructor = Reflection.getConstructor(resourceKeyClass, minecraftKeyClass, minecraftKeyClass);
private static final Reflection.Constructor minecraftKeyConstructor = Reflection.getConstructor(minecraftKeyClass, String.class, String.class);
public static void set(String name) { public static void set(String name) {
impl.setResourceKey(name); resourceKey = (ResourceKey<Level>) resourceKeyConstructor.invoke(minecraftKeyConstructor.invoke("minecraft", "dimension"), minecraftKeyConstructor.invoke("steamwar", name));
} }
protected interface IWorldIdentifier { public WorldIdentifier() {
void setResourceKey(String name); TinyProtocol.instance.addFilter(ClientboundLoginPacket.class, (player, o) -> {
if (resourceKey == null) return o;
ClientboundLoginPacket packet = (ClientboundLoginPacket) o;
return new ClientboundLoginPacket(packet.playerId(),
packet.hardcore(),
packet.levels(),
packet.maxPlayers(),
packet.chunkRadius(),
packet.simulationDistance(),
packet.reducedDebugInfo(),
packet.showDeathScreen(),
packet.doLimitedCrafting(),
new CommonPlayerSpawnInfo(
packet.commonPlayerSpawnInfo().dimensionType(),
resourceKey,
packet.commonPlayerSpawnInfo().seed(),
packet.commonPlayerSpawnInfo().gameType(),
packet.commonPlayerSpawnInfo().previousGameType(),
packet.commonPlayerSpawnInfo().isDebug(),
packet.commonPlayerSpawnInfo().isFlat(),
packet.commonPlayerSpawnInfo().lastDeathLocation(),
packet.commonPlayerSpawnInfo().portalCooldown(),
packet.commonPlayerSpawnInfo().seaLevel()
),
packet.enforcesSecureChat()
);
});
} }
} }
@@ -19,12 +19,56 @@
package de.steamwar.core.authlib; package de.steamwar.core.authlib;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.GameProfileRepository; import com.mojang.authlib.GameProfileRepository;
import de.steamwar.core.Core; import com.mojang.authlib.ProfileLookupCallback;
import de.steamwar.core.VersionDependent; import de.steamwar.Reflection;
import de.steamwar.sql.SteamwarUser;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.Services;
public abstract class SteamwarGameProfileRepository implements GameProfileRepository { import java.util.ArrayList;
public static final SteamwarGameProfileRepository impl = VersionDependent.getVersionImpl(Core.getInstance()); import java.util.List;
import java.util.Optional;
public abstract void inject(); public class SteamwarGameProfileRepository implements GameProfileRepository {
public static final SteamwarGameProfileRepository impl = new SteamwarGameProfileRepository();
private static final GameProfileRepository fallback;
private static final Reflection.Field<Services> field;
private static final Services current;
static {
Class<?> clazz = MinecraftServer.getServer().getClass();
field = Reflection.getField(clazz, Services.class, 0);
current = field.get(MinecraftServer.getServer());
fallback = current.profileRepository();
}
@Override
public void findProfilesByNames(String[] strings, ProfileLookupCallback profileLookupCallback) {
List<String> unknownNames = new ArrayList<>();
for (String name:strings) {
SteamwarUser user = SteamwarUser.get(name);
if(user == null) {
unknownNames.add(name);
continue;
}
profileLookupCallback.onProfileLookupSucceeded(new GameProfile(user.getUUID(), user.getUserName()));
}
if(!unknownNames.isEmpty()) {
fallback.findProfilesByNames(unknownNames.toArray(new String[0]), profileLookupCallback);
}
}
@Override
public Optional<GameProfile> findProfileByName(String s) {
return fallback.findProfileByName(s);
}
public void inject() {
Services newServices = new Services(current.sessionService(), current.servicesKeySet(), this, current.profileCache(), current.paperConfigurations());
field.set(MinecraftServer.getServer(), newServices);
}
} }
@@ -19,12 +19,35 @@
package de.steamwar.entity; package de.steamwar.entity;
import de.steamwar.core.Core; import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import de.steamwar.core.VersionDependent; import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.PositionMoveRotation;
import net.minecraft.world.phys.Vec3;
public interface PacketConstructor { import java.util.Collections;
PacketConstructor impl = VersionDependent.getVersionImpl(Core.getInstance());
Object teleportPacket(int entityId, double x, double y, double z, float yaw, float pitch); public class PacketConstructor {
Object createRPlayerSpawn(RPlayer player); public static final PacketConstructor impl = new PacketConstructor();
public Object teleportPacket(int entityId, double x, double y, double z, float yaw, float pitch) {
PositionMoveRotation rot = new PositionMoveRotation(new Vec3(x, y, z), Vec3.ZERO, pitch, yaw);
return new ClientboundTeleportEntityPacket(entityId, rot, Collections.emptySet(), false);
}
public Object createRPlayerSpawn(RPlayer player) {
return new ClientboundAddEntityPacket(
player.entityId,
player.uuid,
player.x,
player.y,
player.z,
player.yaw,
player.pitch,
EntityType.PLAYER,
0,
Vec3.ZERO,
player.headYaw
);
}
} }
@@ -21,11 +21,54 @@ package de.steamwar.scoreboard;
import de.steamwar.core.Core; import de.steamwar.core.Core;
import de.steamwar.core.VersionDependent; import de.steamwar.core.VersionDependent;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Scoreboard;
public interface SWScoreboard { import java.util.HashMap;
public static final SWScoreboard impl = VersionDependent.getVersionImpl(Core.getInstance()); import java.util.Map;
boolean createScoreboard(Player player, ScoreboardCallback callback); public class SWScoreboard {
void removeScoreboard(Player player); public static final SWScoreboard impl = new SWScoreboard();
private static final HashMap<Player, ScoreboardCallback> playerBoards = new HashMap<>();
private static final String SIDEBAR = "sw-sidebar";
static {
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
for(Map.Entry<Player, ScoreboardCallback> scoreboard : playerBoards.entrySet()) {
render(scoreboard.getKey(), scoreboard.getValue());
}
}, 10, 5);
}
private static void render(Player player, ScoreboardCallback callback) {
if (player.getScoreboard().getObjective(SIDEBAR) != null) {
player.getScoreboard().getObjective(SIDEBAR).unregister();
}
Objective objective = player.getScoreboard().registerNewObjective(SIDEBAR, "dummy", Component.text(callback.getTitle()));
objective.setAutoUpdateDisplay(true);
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
callback.getData().forEach((text, score) -> objective.getScore(text).setScore(score));
}
public boolean createScoreboard(Player player, ScoreboardCallback callback) {
Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
player.setScoreboard(scoreboard);
render(player, callback);
playerBoards.put(player, callback);
return true;
}
public void removeScoreboard(Player player) {
player.getScoreboard().getObjective(SIDEBAR).unregister();
playerBoards.remove(player);
}
} }
@@ -19,19 +19,55 @@
package de.steamwar.techhider; package de.steamwar.techhider;
import com.google.common.collect.ImmutableList;
import de.steamwar.Reflection; import de.steamwar.Reflection;
import de.steamwar.core.Core;
import de.steamwar.core.VersionDependent;
import org.bukkit.Material; import org.bukkit.Material;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
public interface BlockIds { public class BlockIds {
BlockIds impl = VersionDependent.getVersionImpl(Core.getInstance()); public static final BlockIds impl = new BlockIds();
Reflection.Method getCombinedId = Reflection.getTypedMethod(TechHider.block, null, int.class, TechHider.iBlockData); Reflection.Method getCombinedId = Reflection.getTypedMethod(TechHider.block, null, int.class, TechHider.iBlockData);
int getCombinedId(Object iBlockData); private static final Class<?> blockStateList = Reflection.getClass("net.minecraft.world.level.block.state.StateDefinition");
int materialToId(Material material); private static final Class<?> fluidTypeFlowing = Reflection.getClass("net.minecraft.world.level.material.FlowingFluid");
Set<Integer> materialToAllIds(Material material); private static final Class<?> fluid = Reflection.getClass("net.minecraft.world.level.material.FluidState");
private static final Reflection.Method getBlockData = Reflection.getTypedMethod(TechHider.block, null, TechHider.iBlockData);
public int materialToId(Material material) {
return getCombinedId(getBlockData.invoke(getBlock(material)));
}
private static final Reflection.Method getStates = Reflection.getTypedMethod(TechHider.block, null, blockStateList);
private static final Reflection.Method getStateList = Reflection.getTypedMethod(blockStateList, null, ImmutableList.class);
private static final Object water = Reflection.getTypedMethod(fluidTypeFlowing, null, fluid, boolean.class).invoke(Reflection.getField(Reflection.getClass("net.minecraft.world.level.material.Fluids"), fluidTypeFlowing, 1).get(null), false);
private static final Iterable<?> registryBlockId = (Iterable<?>) Reflection.getField(TechHider.block, Reflection.getClass("net.minecraft.core.IdMapper"), 0).get(null);
private static final Reflection.Method getFluid = Reflection.getTypedMethod(TechHider.iBlockData, null, fluid);
public Set<Integer> materialToAllIds(Material material) {
Set<Integer> ids = new HashSet<>();
for(Object data : (ImmutableList<?>) getStateList.invoke(getStates.invoke(getBlock(material)))) {
ids.add(getCombinedId(data));
}
if(material == Material.WATER) {
for(Object data : registryBlockId) {
if(getFluid.invoke(data) == water) {
ids.add(getCombinedId(data));
}
}
}
return ids;
}
private static final Reflection.Method getBlock = Reflection.getTypedMethod(TechHider.craftMagicNumbers, "getBlock", TechHider.block, Material.class);
private Object getBlock(Material material) {
return getBlock.invoke(null, material);
}
public int getCombinedId(Object blockData) {
return (int) getCombinedId.invoke(null, blockData);
}
} }
@@ -19,21 +19,147 @@
package de.steamwar.techhider; package de.steamwar.techhider;
import de.steamwar.core.Core; import de.steamwar.Reflection;
import de.steamwar.core.VersionDependent;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import lombok.Getter; import lombok.Getter;
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.util.SimpleBitStorage;
import net.minecraft.world.level.block.entity.BlockEntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
public interface ChunkHider { public class ChunkHider {
ChunkHider impl = VersionDependent.getVersionImpl(Core.getInstance()); public static final ChunkHider impl = new ChunkHider();
Class<?> mapChunkPacket(); public Class<?> mapChunkPacket() {
BiFunction<Player, Object, Object> chunkHiderGenerator(TechHider techHider); return ClientboundLevelChunkWithLightPacket.class;
}
private static final UnaryOperator<Object> chunkPacketCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkWithLightPacket.class);
private static final UnaryOperator<Object> chunkDataCloner = ProtocolUtils.shallowCloneGenerator(ClientboundLevelChunkPacketData.class);
private static final Reflection.Field<Integer> chunkXField = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 0);
private static final Reflection.Field<Integer> chunkZField = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, int.class, 1);
private static final Reflection.Field<ClientboundLevelChunkPacketData> chunkData = Reflection.getField(ClientboundLevelChunkWithLightPacket.class, ClientboundLevelChunkPacketData.class, 0);
private static final Reflection.Field<byte[]> dataField = Reflection.getField(ClientboundLevelChunkPacketData.class, byte[].class, 0);
private static final Reflection.Field<List> tileEntities = Reflection.getField(ClientboundLevelChunkPacketData.class, List.class, 0);
public BiFunction<Player, Object, Object> chunkHiderGenerator(TechHider techHider) {
return (p, packet) -> {
int chunkX = chunkXField.get(packet);
int chunkZ = chunkZField.get(packet);
if (techHider.getLocationEvaluator().skipChunk(p, chunkX, chunkZ))
return packet;
packet = chunkPacketCloner.apply(packet);
Object dataWrapper = chunkDataCloner.apply(chunkData.get(packet));
Set<String> hiddenBlockEntities = techHider.getHiddenBlockEntities();
tileEntities.set(dataWrapper, ((List<?>)tileEntities.get(dataWrapper)).stream().filter(te -> tileEntityVisible(hiddenBlockEntities, te)).collect(Collectors.toList()));
ByteBuf in = Unpooled.wrappedBuffer(dataField.get(dataWrapper));
ByteBuf out = Unpooled.buffer(in.readableBytes() + 64);
for(int yOffset = p.getWorld().getMinHeight(); yOffset < p.getWorld().getMaxHeight(); yOffset += 16) {
SectionHider section = new SectionHider(p, techHider, in, out, chunkX, yOffset/16, chunkZ);
section.copyBlockCount();
blocks(section);
biomes(section);
}
if (in.readableBytes() != 0) {
throw new IllegalStateException("ChunkHider21: Incomplete chunk data, " + in.readableBytes() + " bytes left");
}
byte[] data = new byte[out.readableBytes()];
out.readBytes(data);
dataField.set(dataWrapper, data);
chunkData.set(packet, dataWrapper);
return packet;
};
}
public static final Class<?> tileEntity = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData$BlockEntityInfo");
protected static final Reflection.Field<BlockEntityType> entityType = Reflection.getField(tileEntity, BlockEntityType.class, 0);
private static final Class<?> builtInRegestries = Reflection.getClass("net.minecraft.core.registries.BuiltInRegistries");
private static final Class<?> registry = Reflection.getClass("net.minecraft.core.Registry");
private static final Reflection.Field<?> nameField = Reflection.getField(builtInRegestries, "BLOCK_ENTITY_TYPE", registry);
private static final Class<?> resourceLocation = Reflection.getClass("net.minecraft.resources.ResourceLocation");
private static final Reflection.Method getKey = Reflection.getTypedMethod(registry, "getKey", resourceLocation, Object.class);
private static final Reflection.Method getName = Reflection.getTypedMethod(resourceLocation, "getPath", String.class);
protected boolean tileEntityVisible(Set<String> hiddenBlockEntities, Object tile) {
return !hiddenBlockEntities.contains(getName.invoke(getKey.invoke(nameField.get(null), entityType.get(tile))));
}
private void blocks(SectionHider section) {
section.copyBitsPerBlock();
boolean singleValued = section.getBitsPerBlock() == 0;
if (singleValued) {
int value = ProtocolUtils.readVarInt(section.getIn());
ProtocolUtils.writeVarInt(section.getOut(), !section.isSkipSection() && section.getObfuscate().contains(value) ? section.getTarget() : value);
return;
} else if (section.getBitsPerBlock() < 9) {
// Indirect (paletted) storage only present when bitsPerBlock < 9 in 1.21+
section.processPalette();
}
if (section.isSkipSection() || (!section.blockPrecise() && section.isPaletted())) {
section.skipNewDataArray(4096);
return;
}
SimpleBitStorage values = new SimpleBitStorage(section.getBitsPerBlock(), 4096, section.readNewDataArray(4096));
for (int y = 0; y < 16; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
int pos = (((y * 16) + z) * 16) + x;
TechHider.State test = section.test(x, y, z);
switch (test) {
case SKIP:
break;
case CHECK:
if (!section.getObfuscate().contains(values.get(pos)))
break;
case HIDE:
values.set(pos, section.getTarget());
break;
case HIDE_AIR:
default:
values.set(pos, section.getAir());
}
}
}
}
section.writeDataArray(values.getRaw());
}
private void biomes(SectionHider section) {
section.copyBitsPerBlock();
if(section.getBitsPerBlock() == 0) {
section.copyVarInt();
} else if(section.getBitsPerBlock() < 6) {
section.skipPalette();
section.skipNewDataArray(64);
} else {
// Direct (global) biome IDs no palette present
section.skipNewDataArray(64);
}
}
@Getter @Getter
class SectionHider { class SectionHider {
@@ -19,19 +19,74 @@
package de.steamwar.techhider; package de.steamwar.techhider;
import de.steamwar.core.Core; import de.steamwar.Reflection;
import de.steamwar.core.VersionDependent; import net.minecraft.core.SectionPos;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.function.BiFunction; import java.util.function.BiFunction;
public interface ProtocolWrapper { public class ProtocolWrapper {
ProtocolWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); public static final ProtocolWrapper impl = new ProtocolWrapper();
private static final Reflection.Field<SectionPos> multiBlockChangeChunk = Reflection.getField(TechHider.multiBlockChangePacket, SectionPos.class, 0);
private static final Reflection.Field<short[]> multiBlockChangePos = Reflection.getField(TechHider.multiBlockChangePacket, short[].class, 0);
private static final Reflection.Field<BlockState[]> multiBlockChangeBlocks = Reflection.getField(TechHider.multiBlockChangePacket, BlockState[].class, 0);
public BiFunction<Player, Object, Object> multiBlockChangeGenerator(TechHider techHider) {
return (p, packet) -> {
TechHider.LocationEvaluator locationEvaluator = techHider.getLocationEvaluator();
Object chunkCoords = multiBlockChangeChunk.get(packet);
int chunkX = TechHider.blockPositionX.get(chunkCoords);
int chunkY = TechHider.blockPositionY.get(chunkCoords);
int chunkZ = TechHider.blockPositionZ.get(chunkCoords);
if(locationEvaluator.skipChunkSection(p, chunkX, chunkY, chunkZ))
return packet;
boolean unfilteredTileEntityDataAction(Object packet); packet = TechHider.multiBlockChangeCloner.apply(packet);
final short[] oldPos = multiBlockChangePos.get(packet);
BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider); final BlockState[] oldBlocks = multiBlockChangeBlocks.get(packet);
ArrayList<Short> poss = new ArrayList<>(oldPos.length);
BiFunction<Player, Object, Object> multiBlockChangeGenerator(TechHider techHider); ArrayList<BlockState> blocks = new ArrayList<>(oldPos.length);
for(int i = 0; i < oldPos.length; i++) {
short pos = oldPos[i];
BlockState block = oldBlocks[i];
switch(locationEvaluator.check(p, 16*chunkX + (pos >> 8 & 0xF), 16*chunkY + (pos & 0xF), 16*chunkZ + (pos >> 4 & 0xF))) {
case SKIP:
poss.add(pos);
blocks.add(block);
break;
case CHECK:
poss.add(pos);
blocks.add(techHider.iBlockDataHidden(block) ? (BlockState) techHider.getObfuscationTarget() : block);
break;
default:
break;
}
}
if(blocks.isEmpty())
return null;
short[] newPos = new short[poss.size()];
for(int i = 0; i < newPos.length; i++)
newPos[i] = poss.get(i);
multiBlockChangePos.set(packet, newPos);
multiBlockChangeBlocks.set(packet, blocks.toArray(new BlockState[0]));
return packet;
};
}
private static final Reflection.Field<BlockEntityType> tileEntityType = Reflection.getField(TechHider.tileEntityDataPacket, BlockEntityType.class, 0);
private static final BlockEntityType<?> signType = Reflection.getField(BlockEntityType.class, BlockEntityType.class, 0, SignBlockEntity.class).get(null);
public boolean unfilteredTileEntityDataAction(Object packet) {
return tileEntityType.get(packet) != signType;
}
public BiFunction<Player, Object, Object> blockBreakHiderGenerator(Class<?> blockBreakPacket, TechHider techHider) {
return null;
}
} }
-16
View File
@@ -30,20 +30,4 @@ dependencies {
api(project(":CommonCore")) api(project(":CommonCore"))
api(project(":CommandFramework")) api(project(":CommandFramework"))
api(project(":SpigotCore:SpigotCore_Main")) api(project(":SpigotCore:SpigotCore_Main"))
implementation(project(":SpigotCore:SpigotCore_8"))
implementation(project(":SpigotCore:SpigotCore_9"))
implementation(project(":SpigotCore:SpigotCore_10"))
implementation(project(":SpigotCore:SpigotCore_12"))
implementation(project(":SpigotCore:SpigotCore_14"))
implementation(project(":SpigotCore:SpigotCore_15"))
implementation(project(":SpigotCore:SpigotCore_18"))
implementation(project(":SpigotCore:SpigotCore_19"))
implementation(project(":SpigotCore:SpigotCore_20"))
implementation(project(":SpigotCore:SpigotCore_21")) {
attributes {
// Very Hacky, but it works
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
}
}
} }
-10
View File
@@ -219,16 +219,6 @@ include("SchematicSystem")
include( include(
"SpigotCore", "SpigotCore",
"SpigotCore:CRIUDummy", "SpigotCore:CRIUDummy",
"SpigotCore:SpigotCore_8",
"SpigotCore:SpigotCore_9",
"SpigotCore:SpigotCore_10",
"SpigotCore:SpigotCore_12",
"SpigotCore:SpigotCore_14",
"SpigotCore:SpigotCore_15",
"SpigotCore:SpigotCore_18",
"SpigotCore:SpigotCore_19",
"SpigotCore:SpigotCore_20",
"SpigotCore:SpigotCore_21",
"SpigotCore:SpigotCore_Main" "SpigotCore:SpigotCore_Main"
) )