forked from SteamWar/SteamWar
Add SpigotCore module
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2024 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 {
|
||||
id("java")
|
||||
id("base")
|
||||
}
|
||||
|
||||
group = "de.steamwar"
|
||||
version = ""
|
||||
|
||||
tasks.compileJava {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDirs("src/")
|
||||
}
|
||||
resources {
|
||||
srcDirs("src/")
|
||||
exclude("**/*.java", "**/*.kt")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("org.projectlombok:lombok:1.18.32")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.32")
|
||||
|
||||
compileOnly(project(":SpigotCore:SpigotCore_Main"))
|
||||
compileOnly(project(":CommonCore"))
|
||||
|
||||
compileOnly("de.steamwar:spigot:1.8")
|
||||
compileOnly("de.steamwar:worldedit:1.12")
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 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.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("{nms}.DataWatcher$WatchableObject");
|
||||
private static final Reflection.ConstructorInvoker 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.FieldAccessor<Integer> posX = Reflection.getField(packetClass, int.class, fieldOffset);
|
||||
Reflection.FieldAccessor<Integer> posY = Reflection.getField(packetClass, int.class, fieldOffset +1);
|
||||
Reflection.FieldAccessor<Integer> posZ = Reflection.getField(packetClass, int.class, fieldOffset +2);
|
||||
|
||||
return (packet, x, y, z) -> {
|
||||
posX.set(packet, MathHelper.floor(x * 32));
|
||||
posY.set(packet, MathHelper.floor(y * 32));
|
||||
posZ.set(packet, MathHelper.floor(z * 32));
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public BountifulWrapper.PositionSetter getRelMoveSetter(Class<?> packetClass) {
|
||||
Reflection.FieldAccessor<?> moveX = Reflection.getField(packetClass, "b", byte.class);
|
||||
Reflection.FieldAccessor<?> moveY = Reflection.getField(packetClass, "c", byte.class);
|
||||
Reflection.FieldAccessor<?> moveZ = Reflection.getField(packetClass, "d", byte.class);
|
||||
|
||||
return (packet, x, y, z) -> {
|
||||
moveX.set(packet, (byte)(x*32));
|
||||
moveY.set(packet, (byte)(y*32));
|
||||
moveZ.set(packet, (byte)(z*32));
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public BountifulWrapper.UUIDSetter getUUIDSetter(Class<?> packetClass) {
|
||||
return (packet, uuid) -> {};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2022 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.Reflection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ChatWrapper8 implements ChatWrapper {
|
||||
|
||||
private static final Reflection.ConstructorInvoker chatComponentConstructor = Reflection.getConstructor(Reflection.getClass("{nms.network.chat}.ChatComponentText"), String.class);
|
||||
@Override
|
||||
public Object stringToChatComponent(String text) {
|
||||
return chatComponentConstructor.invoke(text);
|
||||
}
|
||||
|
||||
private static final Class<?> metadataPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutEntityMetadata");
|
||||
private static final Reflection.FieldAccessor<Integer> metadataEntity = Reflection.getField(metadataPacket, int.class, 0);
|
||||
private static final Reflection.FieldAccessor<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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 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.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.FieldAccessor<String> scoreboardName = Reflection.getField(FlatteningWrapper.scoreboardObjective, String.class, 1);
|
||||
private static final Class<?> scoreActionEnum = Reflection.getClass("{nms}.PacketPlayOutScoreboardScore$EnumScoreboardAction");
|
||||
private static final Reflection.FieldAccessor<?> 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("{nms}.DataWatcher");
|
||||
private static final Class<?> namedSpawnPacket = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutNamedEntitySpawn");
|
||||
private static final Reflection.FieldAccessor<?> namedSpawnDataWatcher = Reflection.getField(namedSpawnPacket, dataWatcher, 0);
|
||||
private static final Class<?> entity = Reflection.getClass("{nms}.Entity");
|
||||
private static final Reflection.ConstructorInvoker 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.FieldAccessor<?> spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, int.class, Core.getVersion() > 8 ? 6 : 9);
|
||||
private static final Reflection.FieldAccessor<Integer> spawnLivingType = Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 1);
|
||||
private static final Map<EntityType, Object> types = new HashMap<>();
|
||||
static {
|
||||
types.put(EntityType.PRIMED_TNT, 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.MethodInvoker save = Reflection.getMethod("{obc}.CraftWorld", "save", boolean.class);
|
||||
@Override
|
||||
public void syncSave(World world) {
|
||||
save.invoke(world, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2020 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 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
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2022 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.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.FieldAccessor<?> equipmentSlot;
|
||||
static {
|
||||
if(Core.getVersion() == 8) {
|
||||
equipmentSlot = Reflection.getField(equipmentPacket, int.class, 1);
|
||||
} else {
|
||||
Class<?> enumItemSlot = Reflection.getClass("{nms.world.entity}.EnumItemSlot");
|
||||
equipmentSlot = Reflection.getField(equipmentPacket, enumItemSlot, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Reflection.FieldAccessor<?> 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("{nms.network.protocol.game}.PacketPlayOutPlayerInfo");
|
||||
private static final Class<?> playerInfoActionClass = Reflection.getClass("{nms.network.protocol.game}.PacketPlayOutPlayerInfo$EnumPlayerInfoAction");
|
||||
private static final Reflection.FieldAccessor<?> playerInfoAction = Reflection.getField(playerInfoPacket, playerInfoActionClass, 0);
|
||||
private static final Reflection.FieldAccessor<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("{nms.network.chat}.IChatBaseComponent");
|
||||
private static final Reflection.ConstructorInvoker playerInfoDataConstructor = Reflection.getConstructor("{nms.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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 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
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
package de.steamwar.core;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.sk89q.jnbt.*;
|
||||
import com.sk89q.worldedit.*;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
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.regions.CuboidRegion;
|
||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.world.registry.WorldData;
|
||||
import de.steamwar.sql.NoClipboardException;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class WorldEditWrapper8 implements WorldEditWrapper.IWorldEditWrapper {
|
||||
|
||||
@Override
|
||||
public InputStream getPlayerClipboard(Player player, boolean schemFormat) {
|
||||
ClipboardHolder clipboardHolder;
|
||||
try {
|
||||
clipboardHolder = WorldEditWrapper.getWorldEditPlugin().getSession(player).getClipboard();
|
||||
} catch (EmptyClipboardException e) {
|
||||
throw new NoClipboardException();
|
||||
}
|
||||
|
||||
Clipboard clipboard = clipboardHolder.getClipboard();
|
||||
if(clipboard == null)
|
||||
throw new NoClipboardException();
|
||||
|
||||
PipedOutputStream outputStream = new PipedOutputStream();
|
||||
PipedInputStream inputStream;
|
||||
try {
|
||||
inputStream = new PipedInputStream(outputStream, 4096);
|
||||
} catch (IOException e) {
|
||||
throw new SecurityException("Could not init piped input stream", e);
|
||||
}
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
ClipboardFormat.SCHEMATIC.getWriter(outputStream).write(clipboard, clipboardHolder.getWorldData());
|
||||
} catch (IOException e) {
|
||||
Core.getInstance().getLogger().log(Level.SEVERE, "Could not write schematic", e);
|
||||
}
|
||||
try {
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
Core.getInstance().getLogger().log(Level.SEVERE, "Could not close schem writer", e);
|
||||
}
|
||||
}, "SchemWriter").start();
|
||||
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerClipboard(Player player, InputStream is, boolean schemFormat) {
|
||||
WorldData world = new BukkitWorld(player.getWorld()).getWorldData();
|
||||
Clipboard clipboard;
|
||||
try {
|
||||
clipboard = getClipboard(is, schemFormat);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Actor actor = WorldEditWrapper.getWorldEditPlugin().wrapCommandSender(player);
|
||||
WorldEditWrapper.getWorldEditPlugin().getWorldEdit().getSessionManager().get(actor).setClipboard(new ClipboardHolder(clipboard, world));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Clipboard getClipboard(InputStream is, boolean schemFormat) throws IOException {
|
||||
if(schemFormat)
|
||||
return new SpongeSchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData());
|
||||
else
|
||||
return new SchematicReader(new NBTInputStream(is)).read(WorldEdit.getInstance().getServer().getWorlds().get(0).getWorldData());
|
||||
}
|
||||
|
||||
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();
|
||||
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));
|
||||
}
|
||||
|
||||
IntTag paletteMaxTag = getTag(schematic, "PaletteMax", IntTag.class);
|
||||
Map<String, Tag> paletteObject = requireTag(schematic, "Palette", CompoundTag.class).getValue();
|
||||
if (paletteMaxTag != null && paletteObject.size() != paletteMaxTag.getValue())
|
||||
throw new IOException("Block palette size does not match expected size.");
|
||||
|
||||
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(schematic, "BlockData", ByteArrayTag.class).getValue();
|
||||
Map<BlockVector, Map<String, Tag>> tileEntitiesMap = new HashMap<>();
|
||||
ListTag tileEntities = getTag(schematic, "BlockEntities", ListTag.class);
|
||||
if (tileEntities == null) {
|
||||
tileEntities = getTag(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2021 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
|
||||
@SuppressWarnings("deprecation")
|
||||
public int materialToId(Material material) {
|
||||
return material.getId() << 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> materialToAllIds(Material material) {
|
||||
return Collections.singleton(materialToId(material));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2021 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 com.comphenix.tinyprotocol.Reflection;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class ChunkHider8 implements ChunkHider {
|
||||
|
||||
protected static final Class<?> mapChunkPacket = Reflection.getClass("{nms}.PacketPlayOutMapChunk");
|
||||
@Override
|
||||
public Class<?> mapChunkPacket() {
|
||||
return mapChunkPacket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiFunction<Player, Object, Object> chunkHiderGenerator(TechHider.LocationEvaluator locationEvaluator, int obfuscationTarget, Set<Integer> obfuscate, Set<String> hiddenBlockEntities) {
|
||||
return (player, packet) -> packet;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
This file is a part of the SteamWar software.
|
||||
|
||||
Copyright (C) 2021 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 com.comphenix.tinyprotocol.Reflection;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
public class ProtocolWrapper8 implements ProtocolWrapper {
|
||||
private static final Class<?> chunkCoordinateIntPair = Reflection.getClass("{nms}.ChunkCoordIntPair");
|
||||
private static final Reflection.FieldAccessor<?> multiBlockChangeChunk = Reflection.getField(TechHider.multiBlockChangePacket, chunkCoordinateIntPair, 0);
|
||||
private static final Reflection.FieldAccessor<Integer> chunkCoordinateX = Reflection.getField(chunkCoordinateIntPair, int.class, 0);
|
||||
private static final Reflection.FieldAccessor<Integer> chunkCoordinateZ = Reflection.getField(chunkCoordinateIntPair, int.class, 1);
|
||||
private static final Class<?> multiBlockChangeInfo = Reflection.getClass("{nms}.PacketPlayOutMultiBlockChange$MultiBlockChangeInfo");
|
||||
private static final Reflection.ConstructorInvoker multiBlockChangeInfoConstructor = Reflection.getConstructor(multiBlockChangeInfo, TechHider.multiBlockChangePacket, short.class, TechHider.iBlockData);
|
||||
private static final Reflection.FieldAccessor<?> multiBlockChangeInfoBlock = Reflection.getField(multiBlockChangeInfo, TechHider.iBlockData, 0);
|
||||
private static final Reflection.FieldAccessor<?> multiBlockChangeInfoPos = Reflection.getField(multiBlockChangeInfo, short.class, 0);
|
||||
private static final Class<?> multiBlockChangeInfoArray = Reflection.getClass("[L{nms}.PacketPlayOutMultiBlockChange$MultiBlockChangeInfo;");
|
||||
private static final Reflection.FieldAccessor<?> multiBlockChangeInfos = Reflection.getField(TechHider.multiBlockChangePacket, multiBlockChangeInfoArray, 0);
|
||||
@Override
|
||||
public BiFunction<Player, Object, Object> multiBlockChangeGenerator(Object obfuscationTarget, Set<Material> obfuscate, TechHider.LocationEvaluator locationEvaluator) {
|
||||
return (p, packet) -> {
|
||||
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(obfuscate, multiBlockChangeInfoBlock.get(mbci)) ? multiBlockChangeInfoConstructor.invoke(packet, pos, obfuscationTarget) : 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.FieldAccessor<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, Object obfuscationTarget, Set<Material> obfuscate, TechHider.LocationEvaluator bypass) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user