Merge branch 'master' into 1.19.3
Dieser Commit ist enthalten in:
Commit
3a777970d0
@ -1 +1 @@
|
|||||||
Subproject commit 9ea02ebcd4620e7baa6980cd88e1a4dabd59e50c
|
Subproject commit 38457db0141d34e6f9f133e70bc3061b8a3d3e5a
|
@ -22,6 +22,7 @@ package de.steamwar.core;
|
|||||||
import com.comphenix.tinyprotocol.Reflection;
|
import com.comphenix.tinyprotocol.Reflection;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
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;
|
||||||
@ -325,9 +326,13 @@ public class FlatteningWrapper14 implements FlatteningWrapper.IFlatteningWrapper
|
|||||||
return displayName != null ? Optional.of(ChatWrapper.impl.stringToChatComponent(displayName)) : Optional.empty();
|
return displayName != null ? Optional.of(ChatWrapper.impl.stringToChatComponent(displayName)) : Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Reflection.FieldAccessor<?> spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, Reflection.getClass("{nms.world.entity}.EntityTypes"), 0);
|
private static final Class<?> registryBlocks = Reflection.getClass("{nms.core}.RegistryBlocks");
|
||||||
private static final Reflection.FieldAccessor<?> spawnLivingType = Core.getVersion() > 19 ? spawnType : Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 1);
|
private static final Class<?> entityTypes = Reflection.getClass("{nms.world.entity}.EntityTypes");
|
||||||
private static final Reflection.MethodInvoker getEntityTypes = Reflection.getMethod("{obc}.util.CraftMagicNumbers", "getEntityTypes", EntityType.class);
|
private static final Object entityTypesRegistry = Reflection.getField(Reflection.getClass("{nms.core}.IRegistry"), registryBlocks, 0, entityTypes).get(null);
|
||||||
|
private static final Reflection.MethodInvoker get = Reflection.getMethod(registryBlocks, null, Reflection.getClass("{nms.resources}.MinecraftKey"));
|
||||||
|
private static final Reflection.FieldAccessor<?> spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, entityTypes, 0);
|
||||||
|
private static final Reflection.FieldAccessor<?> spawnLivingType = Core.getVersion() > 18 ? spawnType : Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 1);
|
||||||
|
private static final Reflection.MethodInvoker toMinecraft = Reflection.getMethod("{obc}.util.CraftNamespacedKey", "toMinecraft", NamespacedKey.class);
|
||||||
private static final Map<EntityType, Object> types = new HashMap<>();
|
private static final Map<EntityType, Object> types = new HashMap<>();
|
||||||
static {
|
static {
|
||||||
types.put(EntityType.ARMOR_STAND, 1);
|
types.put(EntityType.ARMOR_STAND, 1);
|
||||||
@ -335,9 +340,9 @@ public class FlatteningWrapper14 implements FlatteningWrapper.IFlatteningWrapper
|
|||||||
@Override
|
@Override
|
||||||
public void setSpawnPacketType(Object packet, EntityType type) {
|
public void setSpawnPacketType(Object packet, EntityType type) {
|
||||||
if(type.isAlive()) {
|
if(type.isAlive()) {
|
||||||
spawnLivingType.set(packet, Core.getVersion() > 18 ? getEntityTypes.invoke(null, type) : types.get(type));
|
spawnLivingType.set(packet, Core.getVersion() > 18 ? get.invoke(entityTypesRegistry, toMinecraft.invoke(null, type.getKey())) : types.get(type));
|
||||||
} else {
|
} else {
|
||||||
spawnType.set(packet, getEntityTypes.invoke(null, type));
|
spawnType.set(packet, get.invoke(entityTypesRegistry, toMinecraft.invoke(null, type.getKey())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
30
SpigotCore_14/src/de/steamwar/core/RecipeDiscoverWrapper14.java
Normale Datei
30
SpigotCore_14/src/de/steamwar/core/RecipeDiscoverWrapper14.java
Normale Datei
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
24
SpigotCore_8/src/de/steamwar/core/RecipeDiscoverWrapper8.java
Normale Datei
24
SpigotCore_8/src/de/steamwar/core/RecipeDiscoverWrapper8.java
Normale Datei
@ -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
|
||||||
|
}
|
@ -43,6 +43,8 @@ sourceSets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
compileOnly 'com.viaversion:viaversion-api:4.3.1'
|
||||||
|
|
||||||
compileOnly project(":SpigotCore_Main")
|
compileOnly project(":SpigotCore_Main")
|
||||||
compileOnly project(":SpigotCore_8")
|
compileOnly project(":SpigotCore_8")
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
package de.steamwar.core;
|
package de.steamwar.core;
|
||||||
|
|
||||||
import com.comphenix.tinyprotocol.Reflection;
|
import com.comphenix.tinyprotocol.Reflection;
|
||||||
|
import com.viaversion.viaversion.api.Via;
|
||||||
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 org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
@ -36,6 +37,9 @@ public class BountifulWrapper9 implements BountifulWrapper.IBountifulWrapper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendMessage(Player player, ChatMessageType type, BaseComponent... msg) {
|
public void sendMessage(Player player, ChatMessageType type, BaseComponent... msg) {
|
||||||
|
if(type == ChatMessageType.CHAT && Via.getAPI().getPlayerVersion(player.getUniqueId()) >= 759)
|
||||||
|
type = ChatMessageType.SYSTEM;
|
||||||
|
|
||||||
player.spigot().sendMessage(type, msg);
|
player.spigot().sendMessage(type, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ public final class Reflection {
|
|||||||
|
|
||||||
// Search in every superclass
|
// Search in every superclass
|
||||||
if (clazz.getSuperclass() != null)
|
if (clazz.getSuperclass() != null)
|
||||||
return getMethod(clazz.getSuperclass(), methodName, params);
|
return getTypedMethod(clazz.getSuperclass(), methodName, returnType, params);
|
||||||
|
|
||||||
throw new IllegalStateException(String.format("Unable to find method %s (%s).", methodName, Arrays.asList(params)));
|
throw new IllegalStateException(String.format("Unable to find method %s (%s).", methodName, Arrays.asList(params)));
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,7 @@ package de.steamwar.core;
|
|||||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||||
import de.steamwar.command.*;
|
import de.steamwar.command.*;
|
||||||
import de.steamwar.core.authlib.AuthlibInjector;
|
import de.steamwar.core.authlib.AuthlibInjector;
|
||||||
import de.steamwar.core.events.ChattingEvent;
|
import de.steamwar.core.events.*;
|
||||||
import de.steamwar.core.events.PartialChunkFixer;
|
|
||||||
import de.steamwar.core.events.PlayerJoinedEvent;
|
|
||||||
import de.steamwar.core.events.WorldLoadEvent;
|
|
||||||
import de.steamwar.message.Message;
|
import de.steamwar.message.Message;
|
||||||
import de.steamwar.network.NetworkReceiver;
|
import de.steamwar.network.NetworkReceiver;
|
||||||
import de.steamwar.network.handlers.ServerDataHandler;
|
import de.steamwar.network.handlers.ServerDataHandler;
|
||||||
@ -34,6 +31,7 @@ import de.steamwar.sql.SteamwarUser;
|
|||||||
import de.steamwar.sql.internal.Statement;
|
import de.steamwar.sql.internal.Statement;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
@ -84,30 +82,33 @@ public class Core extends JavaPlugin{
|
|||||||
return tabCompleter.apply(sender, s);
|
return tabCompleter.apply(sender, s);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Bukkit.getScheduler().runTaskTimer(this, TabCompletionCache::invalidateOldEntries, 20, 20);
|
|
||||||
Bukkit.getPluginManager().registerEvents(new CaseInsensitiveCommandsListener(), this);
|
|
||||||
|
|
||||||
Bukkit.getPluginManager().registerEvents(new PlayerJoinedEvent(), this);
|
for(Listener listener : new Listener[]{new CaseInsensitiveCommandsListener(), new PlayerJoinedEvent(), new ChattingEvent(), new WorldLoadEvent(), RecipeDiscoverWrapper.impl}) {
|
||||||
Bukkit.getPluginManager().registerEvents(new ChattingEvent(), this);
|
getServer().getPluginManager().registerEvents(listener, this);
|
||||||
Bukkit.getPluginManager().registerEvents(new WorldLoadEvent(), this);
|
|
||||||
if(!Statement.productionDatabase()) {
|
|
||||||
Bukkit.getPluginManager().registerEvents(LocaleChangeWrapper.impl, this);
|
|
||||||
}
|
}
|
||||||
|
if(!Statement.productionDatabase()) {
|
||||||
|
getServer().getPluginManager().registerEvents(LocaleChangeWrapper.impl, this);
|
||||||
|
}
|
||||||
|
|
||||||
getServer().getMessenger().registerIncomingPluginChannel(this, "sw:bridge", new NetworkReceiver());
|
getServer().getMessenger().registerIncomingPluginChannel(this, "sw:bridge", new NetworkReceiver());
|
||||||
getServer().getMessenger().registerOutgoingPluginChannel(this, "sw:bridge");
|
getServer().getMessenger().registerOutgoingPluginChannel(this, "sw:bridge");
|
||||||
|
|
||||||
if(Core.getVersion() < 19)
|
if(Core.getVersion() < 19)
|
||||||
AuthlibInjector.inject();
|
AuthlibInjector.inject();
|
||||||
|
|
||||||
TinyProtocol.init();
|
TinyProtocol.init();
|
||||||
|
new AntiNocom();
|
||||||
|
|
||||||
if(Core.getVersion() < 17 && Bukkit.getPluginManager().getPlugin("ViaVersion") != null)
|
if(Core.getVersion() < 17 && Bukkit.getPluginManager().getPlugin("ViaVersion") != null)
|
||||||
new PartialChunkFixer();
|
new PartialChunkFixer();
|
||||||
|
|
||||||
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SteamwarUser::clear, 72000, 72000);
|
|
||||||
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SchematicNode::clear, 20L * 30, 20L * 30);
|
|
||||||
|
|
||||||
if(Core.getVersion() >= 19)
|
if(Core.getVersion() >= 19)
|
||||||
new ServerDataHandler();
|
new ServerDataHandler();
|
||||||
|
|
||||||
|
Bukkit.getScheduler().runTaskTimer(this, TabCompletionCache::invalidateOldEntries, 20, 20);
|
||||||
|
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SteamwarUser::clear, 72000, 72000);
|
||||||
|
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), SchematicNode::clear, 20L * 30, 20L * 30);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
getLogger().log(Level.INFO, "Running on: " + new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream())).readLine());
|
getLogger().log(Level.INFO, "Running on: " + new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream())).readLine());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
26
SpigotCore_Main/src/de/steamwar/core/RecipeDiscoverWrapper.java
Normale Datei
26
SpigotCore_Main/src/de/steamwar/core/RecipeDiscoverWrapper.java
Normale Datei
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
|
||||||
|
public interface RecipeDiscoverWrapper extends Listener {
|
||||||
|
RecipeDiscoverWrapper impl = VersionDependent.getVersionImpl(Core.getInstance());
|
||||||
|
}
|
85
SpigotCore_Main/src/de/steamwar/core/events/AntiNocom.java
Normale Datei
85
SpigotCore_Main/src/de/steamwar/core/events/AntiNocom.java
Normale Datei
@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* 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.events;
|
||||||
|
|
||||||
|
import com.comphenix.tinyprotocol.Reflection;
|
||||||
|
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||||
|
import de.steamwar.core.Core;
|
||||||
|
import de.steamwar.sql.SWException;
|
||||||
|
import de.steamwar.techhider.ProtocolUtils;
|
||||||
|
import de.steamwar.techhider.TechHider;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
public class AntiNocom {
|
||||||
|
|
||||||
|
public AntiNocom() {
|
||||||
|
TinyProtocol.instance.addFilter(blockDig, this::onDig);
|
||||||
|
|
||||||
|
if(Core.getVersion() > 8) {
|
||||||
|
registerUseItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerUseItem() {
|
||||||
|
Class<?> useItem = Reflection.getClass("{nms.network.protocol.game}.PacketPlayInUseItem");
|
||||||
|
|
||||||
|
Function<Object, Object> getPosition;
|
||||||
|
if(Core.getVersion() > 12) {
|
||||||
|
Class<?> movingObjectPositionBlock = Reflection.getClass("{nms.world.phys}.MovingObjectPositionBlock");
|
||||||
|
Reflection.FieldAccessor<?> useItemPosition = Reflection.getField(useItem, movingObjectPositionBlock, 0);
|
||||||
|
Reflection.FieldAccessor<?> movingBlockPosition = Reflection.getField(movingObjectPositionBlock, TechHider.blockPosition, 0);
|
||||||
|
|
||||||
|
getPosition = (packet) -> movingBlockPosition.get(useItemPosition.get(packet));
|
||||||
|
} else {
|
||||||
|
getPosition = Reflection.getField(useItem, TechHider.blockPosition, 0)::get;
|
||||||
|
}
|
||||||
|
|
||||||
|
TinyProtocol.instance.addFilter(useItem, (player, packet) -> {
|
||||||
|
Object pos = getPosition.apply(packet);
|
||||||
|
int x = TechHider.blockPositionX.get(pos);
|
||||||
|
int z = TechHider.blockPositionZ.get(pos);
|
||||||
|
|
||||||
|
if(!player.getWorld().isChunkLoaded(ProtocolUtils.posToChunk(x), ProtocolUtils.posToChunk(z))) {
|
||||||
|
Bukkit.getScheduler().runTask(Core.getInstance(), () -> player.kickPlayer(null));
|
||||||
|
SWException.log(player.getName() + " kicked for using item on unloaded block (potential NoCom-DOS attack)", x + " " + z);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Class<?> blockDig = Reflection.getClass("{nms.network.protocol.game}.PacketPlayInBlockDig");
|
||||||
|
private static final Reflection.FieldAccessor<?> digPosition = Reflection.getField(blockDig, TechHider.blockPosition, 0);
|
||||||
|
private Object onDig(Player player, Object packet) {
|
||||||
|
Object pos = digPosition.get(packet);
|
||||||
|
int x = TechHider.blockPositionX.get(pos);
|
||||||
|
int z = TechHider.blockPositionZ.get(pos);
|
||||||
|
if((x != 0 || z != 0) && !player.getWorld().isChunkLoaded(ProtocolUtils.posToChunk(x), ProtocolUtils.posToChunk(z))) {
|
||||||
|
Bukkit.getScheduler().runTask(Core.getInstance(), () -> player.kickPlayer(null));
|
||||||
|
SWException.log(player.getName() + " kicked for digging an unloaded block (potential NoCom-DOS attack)", x + " " + z);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
}
|
@ -35,10 +35,7 @@ public class PlayerJoinedEvent implements Listener{
|
|||||||
@EventHandler(priority = EventPriority.LOWEST)
|
@EventHandler(priority = EventPriority.LOWEST)
|
||||||
private void onJoin(PlayerJoinEvent event) {
|
private void onJoin(PlayerJoinEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
if(!Statement.productionDatabase()) {
|
SteamwarUser user = Statement.productionDatabase() ? SteamwarUser.get(player.getUniqueId()) : SteamwarUser.getOrCreate(player.getUniqueId(), player.getName(), uuid -> {}, (oldName, newName) -> {});
|
||||||
SteamwarUser.createOrUpdateUsername(player.getUniqueId(), player.getName());
|
|
||||||
}
|
|
||||||
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
|
|
||||||
|
|
||||||
if(user.getUserGroup() != UserGroup.Member) {
|
if(user.getUserGroup() != UserGroup.Member) {
|
||||||
UserGroup group = user.getUserGroup();
|
UserGroup group = user.getUserGroup();
|
||||||
|
@ -52,8 +52,9 @@ public class RArmorStand extends REntity {
|
|||||||
private final Size size;
|
private final Size size;
|
||||||
|
|
||||||
public RArmorStand(REntityServer server, Location location, Size size) {
|
public RArmorStand(REntityServer server, Location location, Size size) {
|
||||||
super(server, EntityType.ARMOR_STAND, location);
|
super(server, EntityType.ARMOR_STAND, location, 0);
|
||||||
this.size = size;
|
this.size = size;
|
||||||
|
server.addEntity(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,7 +20,10 @@
|
|||||||
package de.steamwar.entity;
|
package de.steamwar.entity;
|
||||||
|
|
||||||
import com.comphenix.tinyprotocol.Reflection;
|
import com.comphenix.tinyprotocol.Reflection;
|
||||||
import de.steamwar.core.*;
|
import de.steamwar.core.BountifulWrapper;
|
||||||
|
import de.steamwar.core.Core;
|
||||||
|
import de.steamwar.core.FlatteningWrapper;
|
||||||
|
import de.steamwar.core.ProtocolWrapper;
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
import it.unimi.dsi.fastutil.ints.IntList;
|
import it.unimi.dsi.fastutil.ints.IntList;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@ -73,6 +76,7 @@ public class REntity {
|
|||||||
|
|
||||||
public REntity(REntityServer server, EntityType entityType, Location location) {
|
public REntity(REntityServer server, EntityType entityType, Location location) {
|
||||||
this(server,entityType,location,0);
|
this(server,entityType,location,0);
|
||||||
|
server.addEntity(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected REntity(REntityServer server, EntityType entityType, Location location,int objectData) {
|
protected REntity(REntityServer server, EntityType entityType, Location location,int objectData) {
|
||||||
@ -97,8 +101,6 @@ public class REntity {
|
|||||||
this.isGlowing = false;
|
this.isGlowing = false;
|
||||||
|
|
||||||
this.objectData = objectData;
|
this.objectData = objectData;
|
||||||
|
|
||||||
server.addEntity(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void move(Location location) {
|
public void move(Location location) {
|
||||||
@ -214,6 +216,18 @@ public class REntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getZ() {
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
private static int spawnPacketOffset() {
|
private static int spawnPacketOffset() {
|
||||||
switch (Core.getVersion()) {
|
switch (Core.getVersion()) {
|
||||||
case 8:
|
case 8:
|
||||||
|
@ -19,9 +19,11 @@
|
|||||||
|
|
||||||
package de.steamwar.entity;
|
package de.steamwar.entity;
|
||||||
|
|
||||||
|
import com.comphenix.tinyprotocol.Reflection;
|
||||||
import com.comphenix.tinyprotocol.TinyProtocol;
|
import com.comphenix.tinyprotocol.TinyProtocol;
|
||||||
import de.steamwar.core.Core;
|
import de.steamwar.core.Core;
|
||||||
import de.steamwar.core.FlatteningWrapper;
|
import de.steamwar.core.FlatteningWrapper;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
@ -31,11 +33,15 @@ import org.bukkit.event.Listener;
|
|||||||
import org.bukkit.event.player.PlayerMoveEvent;
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
|
||||||
public class REntityServer implements Listener {
|
public class REntityServer implements Listener {
|
||||||
@ -43,15 +49,58 @@ public class REntityServer implements Listener {
|
|||||||
private static final HashSet<REntity> emptyEntities = new HashSet<>(0);
|
private static final HashSet<REntity> emptyEntities = new HashSet<>(0);
|
||||||
private static final HashSet<Player> emptyPlayers = new HashSet<>(0);
|
private static final HashSet<Player> emptyPlayers = new HashSet<>(0);
|
||||||
|
|
||||||
|
private static final Class<?> useEntity = Reflection.getClass("{nms.network.protocol.game}.PacketPlayInUseEntity");
|
||||||
|
private static final Reflection.FieldAccessor<Integer> useEntityTarget = Reflection.getField(useEntity, int.class, 0);
|
||||||
|
private static final Class<?> useEntityEnumAction = Reflection.getClass("{nms.network.protocol.game}.PacketPlayInUseEntity$EnumEntityUseAction");
|
||||||
|
private static final Reflection.FieldAccessor<?> useEntityAction = Reflection.getField(useEntity, useEntityEnumAction, 0);
|
||||||
|
private static final Function<Object, Integer> getEntityAction;
|
||||||
|
static {
|
||||||
|
if(Core.getVersion() > 15) {
|
||||||
|
Reflection.MethodInvoker useEntityGetAction = Reflection.getMethod(useEntityEnumAction, "a");
|
||||||
|
getEntityAction = value -> ((Enum<?>) useEntityGetAction.invoke(value)).ordinal();
|
||||||
|
} else {
|
||||||
|
getEntityAction = value -> ((Enum<?>) value).ordinal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<Integer, REntity> entityMap = new ConcurrentHashMap<>();
|
||||||
private final HashMap<Long, HashSet<REntity>> entities = new HashMap<>();
|
private final HashMap<Long, HashSet<REntity>> entities = new HashMap<>();
|
||||||
private final HashMap<Long, Set<Player>> players = new HashMap<>();
|
private final HashMap<Long, Set<Player>> players = new HashMap<>();
|
||||||
private final HashMap<Player, Location> lastLocation = new HashMap<>();
|
private final HashMap<Player, Location> lastLocation = new HashMap<>();
|
||||||
private final HashMap<Player, Integer> viewDistance = new HashMap<>();
|
private final HashMap<Player, Integer> viewDistance = new HashMap<>();
|
||||||
|
|
||||||
|
private EntityActionListener callback = null;
|
||||||
|
private final Set<Player> playersThatClicked = Collections.synchronizedSet(new HashSet<>());
|
||||||
|
|
||||||
|
private final BiFunction<Player, Object, Object> filter = (player, packet) -> {
|
||||||
|
REntity entity = entityMap.get(useEntityTarget.get(packet));
|
||||||
|
if (entity == null)
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
if (playersThatClicked.contains(player))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
playersThatClicked.add(player);
|
||||||
|
EntityAction action = getEntityAction.apply(useEntityAction.get(packet)) == 1 ? EntityAction.ATTACK : EntityAction.INTERACT;
|
||||||
|
Bukkit.getScheduler().runTask(Core.getInstance(), () -> {
|
||||||
|
playersThatClicked.remove(player);
|
||||||
|
callback.onAction(player, entity, action);
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
public REntityServer() {
|
public REntityServer() {
|
||||||
Core.getInstance().getServer().getPluginManager().registerEvents(this, Core.getInstance());
|
Core.getInstance().getServer().getPluginManager().registerEvents(this, Core.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCallback(EntityActionListener callback) {
|
||||||
|
boolean uninitialized = this.callback == null;
|
||||||
|
this.callback = callback;
|
||||||
|
|
||||||
|
if(uninitialized)
|
||||||
|
TinyProtocol.instance.addFilter(useEntity, filter);
|
||||||
|
}
|
||||||
|
|
||||||
public void addPlayer(Player player) {
|
public void addPlayer(Player player) {
|
||||||
Location location = player.getLocation();
|
Location location = player.getLocation();
|
||||||
lastLocation.put(player, location);
|
lastLocation.put(player, location);
|
||||||
@ -65,6 +114,7 @@ public class REntityServer implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
|
TinyProtocol.instance.removeFilter(useEntity, filter);
|
||||||
for(Player player : lastLocation.keySet().toArray(new Player[0])) {
|
for(Player player : lastLocation.keySet().toArray(new Player[0])) {
|
||||||
removePlayer(player);
|
removePlayer(player);
|
||||||
}
|
}
|
||||||
@ -72,6 +122,7 @@ public class REntityServer implements Listener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addEntity(REntity entity) {
|
void addEntity(REntity entity) {
|
||||||
|
entityMap.put(entity.entityId, entity);
|
||||||
addEntityToChunk(entity);
|
addEntityToChunk(entity);
|
||||||
entity.spawn(packet -> updateEntity(entity, packet));
|
entity.spawn(packet -> updateEntity(entity, packet));
|
||||||
}
|
}
|
||||||
@ -105,6 +156,7 @@ public class REntityServer implements Listener {
|
|||||||
void removeEntity(REntity entity) {
|
void removeEntity(REntity entity) {
|
||||||
entity.despawn(packet -> updateEntity(entity, packet));
|
entity.despawn(packet -> updateEntity(entity, packet));
|
||||||
removeEntityFromChunk(entity);
|
removeEntityFromChunk(entity);
|
||||||
|
entityMap.remove(entity.entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addEntityToChunk(REntity entity) {
|
private void addEntityToChunk(REntity entity) {
|
||||||
@ -158,7 +210,14 @@ public class REntityServer implements Listener {
|
|||||||
if(location == null)
|
if(location == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
forChunkInView(player, location, (x, z) -> players.get(chunkToId(x, z)).remove(player));
|
forChunkInView(player, location, (x, z) -> {
|
||||||
|
long id = chunkToId(x, z);
|
||||||
|
Set<Player> playersInChunk = players.get(id);
|
||||||
|
playersInChunk.remove(player);
|
||||||
|
if(playersInChunk.isEmpty())
|
||||||
|
players.remove(id);
|
||||||
|
});
|
||||||
|
viewDistance.remove(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onMissing(Set<Player> of, Set<Player> in, Consumer<Consumer<Object>> packetProvider) {
|
private void onMissing(Set<Player> of, Set<Player> in, Consumer<Consumer<Object>> packetProvider) {
|
||||||
@ -194,7 +253,12 @@ public class REntityServer implements Listener {
|
|||||||
|
|
||||||
private void removePlayerFromChunk(Player player, int x, int z) {
|
private void removePlayerFromChunk(Player player, int x, int z) {
|
||||||
long id = chunkToId(x, z);
|
long id = chunkToId(x, z);
|
||||||
players.get(id).remove(player);
|
|
||||||
|
Set<Player> playersInChunk = players.get(id);
|
||||||
|
playersInChunk.remove(player);
|
||||||
|
if(playersInChunk.isEmpty())
|
||||||
|
players.remove(id);
|
||||||
|
|
||||||
for(REntity entity : entities.getOrDefault(id, emptyEntities)) {
|
for(REntity entity : entities.getOrDefault(id, emptyEntities)) {
|
||||||
entity.despawn(packet -> TinyProtocol.instance.sendPacket(player, packet));
|
entity.despawn(packet -> TinyProtocol.instance.sendPacket(player, packet));
|
||||||
}
|
}
|
||||||
@ -227,4 +291,13 @@ public class REntityServer implements Listener {
|
|||||||
private long chunkToId(int x, int z) {
|
private long chunkToId(int x, int z) {
|
||||||
return ((long) x << 32) + z;
|
return ((long) x << 32) + z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum EntityAction {
|
||||||
|
INTERACT,
|
||||||
|
ATTACK,
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface EntityActionListener {
|
||||||
|
void onAction(Player player, REntity entity, EntityAction action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,5 +29,6 @@ public class RFallingBlockEntity extends REntity{
|
|||||||
|
|
||||||
public RFallingBlockEntity(REntityServer server, Location location, Material material) {
|
public RFallingBlockEntity(REntityServer server, Location location, Material material) {
|
||||||
super(server, EntityType.FALLING_BLOCK, location, BlockIds.impl.materialToId(material) >> (Core.getVersion() <= 12 ? 4 : 0));
|
super(server, EntityType.FALLING_BLOCK, location, BlockIds.impl.materialToId(material) >> (Core.getVersion() <= 12 ? 4 : 0));
|
||||||
|
server.addEntity(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@ public class RPlayer extends REntity {
|
|||||||
super(server, EntityType.PLAYER, uuid, location,0);
|
super(server, EntityType.PLAYER, uuid, location,0);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
//team.addEntry(name);
|
//team.addEntry(name);
|
||||||
|
server.addEntity(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -163,7 +163,7 @@ public class SchematicSelector {
|
|||||||
}
|
}
|
||||||
if(!singleDirOpen) {
|
if(!singleDirOpen) {
|
||||||
if(NodeMember.getNodeMember(parent.getId(), user.getId()) != null) {
|
if(NodeMember.getNodeMember(parent.getId(), user.getId()) != null) {
|
||||||
return Optional.ofNullable(SchematicNode.byIdAndUser(user, parent.getId())).flatMap(SchematicNode::getOptionalParent).map(integer -> SchematicNode.byIdAndUser(user, integer)).orElse(null);
|
return NodeMember.getNodeMember(parent.getId(), user.getId()).getParent().map(integer -> SchematicNode.byIdAndUser(user, integer)).orElse(null);
|
||||||
} else {
|
} else {
|
||||||
return getParent(parent).orElse(null);
|
return getParent(parent).orElse(null);
|
||||||
}
|
}
|
||||||
|
@ -36,11 +36,6 @@ import java.util.zip.GZIPInputStream;
|
|||||||
|
|
||||||
public class SchematicData {
|
public class SchematicData {
|
||||||
|
|
||||||
static {
|
|
||||||
new SqlTypeMapper<>(PipedInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("PipedInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
|
|
||||||
new SqlTypeMapper<>(ByteArrayInputStream.class, "BLOB", (rs, identifier) -> { throw new SecurityException("ByteArrayInputStream is write only datatype"); }, PreparedStatement::setBinaryStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Clipboard clipboardFromStream(InputStream is, boolean schemFormat) {
|
public static Clipboard clipboardFromStream(InputStream is, boolean schemFormat) {
|
||||||
try {
|
try {
|
||||||
return WorldEditWrapper.impl.getClipboard(is, schemFormat);
|
return WorldEditWrapper.impl.getClipboard(is, schemFormat);
|
||||||
@ -49,42 +44,20 @@ public class SchematicData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Statement updateDatabase = new Statement("UPDATE SchematicNode SET NodeData = ?, NodeFormat = ? WHERE NodeId = ?");
|
private final NodeData data;
|
||||||
private static final Statement selSchemData = new Statement("SELECT NodeData FROM SchematicNode WHERE NodeId = ?");
|
|
||||||
|
|
||||||
private final SchematicNode node;
|
|
||||||
|
|
||||||
public SchematicData(SchematicNode node) {
|
public SchematicData(SchematicNode node) {
|
||||||
this.node = node;
|
this.data = NodeData.get(node);
|
||||||
if(node.isDir())
|
if(node.isDir())
|
||||||
throw new SecurityException("Node is Directory");
|
throw new SecurityException("Node is Directory");
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputStream schemData() throws IOException {
|
|
||||||
try {
|
|
||||||
return selSchemData.select(rs -> {
|
|
||||||
rs.next();
|
|
||||||
Blob schemData = rs.getBlob("NodeData");
|
|
||||||
if(schemData == null) {
|
|
||||||
throw new SecurityException("SchemData is null");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return new GZIPInputStream(schemData.getBinaryStream());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new SecurityException("SchemData is wrong", e);
|
|
||||||
}
|
|
||||||
}, node.getId());
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new IOException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Clipboard load() throws IOException, NoClipboardException {
|
public Clipboard load() throws IOException, NoClipboardException {
|
||||||
return WorldEditWrapper.impl.getClipboard(schemData(), node.getSchemFormat());
|
return WorldEditWrapper.impl.getClipboard(data.schemData(), data.getNodeFormat());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadToPlayer(Player player) throws IOException, NoClipboardException {
|
public void loadToPlayer(Player player) throws IOException, NoClipboardException {
|
||||||
WorldEditWrapper.impl.setPlayerClipboard(player, schemData(), node.getSchemFormat());
|
WorldEditWrapper.impl.setPlayerClipboard(player, data.schemData(), data.getNodeFormat());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveFromPlayer(Player player) throws IOException, NoClipboardException {
|
public void saveFromPlayer(Player player) throws IOException, NoClipboardException {
|
||||||
@ -92,16 +65,11 @@ public class SchematicData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void saveFromPlayer(Player player, boolean newFormat) throws IOException, NoClipboardException {
|
public void saveFromPlayer(Player player, boolean newFormat) throws IOException, NoClipboardException {
|
||||||
saveFromStream(WorldEditWrapper.impl.getPlayerClipboard(player, newFormat), newFormat);
|
data.saveFromStream(WorldEditWrapper.impl.getPlayerClipboard(player, newFormat), newFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void saveFromBytes(byte[] bytes, boolean newFormat) {
|
public void saveFromBytes(byte[] bytes, boolean newFormat) {
|
||||||
saveFromStream(new ByteArrayInputStream(bytes), newFormat);
|
data.saveFromStream(new ByteArrayInputStream(bytes), newFormat);
|
||||||
}
|
|
||||||
|
|
||||||
public void saveFromStream(InputStream blob, boolean newFormat) {
|
|
||||||
updateDatabase.update(blob, newFormat, node.getId());
|
|
||||||
node.setNodeFormat(newFormat);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren