diff --git a/CommonCore b/CommonCore index 9ea02eb..38457db 160000 --- a/CommonCore +++ b/CommonCore @@ -1 +1 @@ -Subproject commit 9ea02ebcd4620e7baa6980cd88e1a4dabd59e50c +Subproject commit 38457db0141d34e6f9f133e70bc3061b8a3d3e5a diff --git a/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java b/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java index e650a29..e0eb2ea 100644 --- a/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java +++ b/SpigotCore_14/src/de/steamwar/core/FlatteningWrapper14.java @@ -22,6 +22,7 @@ package de.steamwar.core; import com.comphenix.tinyprotocol.Reflection; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; 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(); } - private static final Reflection.FieldAccessor spawnType = Reflection.getField(ProtocolWrapper.spawnPacket, Reflection.getClass("{nms.world.entity}.EntityTypes"), 0); - private static final Reflection.FieldAccessor spawnLivingType = Core.getVersion() > 19 ? spawnType : Reflection.getField(ProtocolWrapper.spawnLivingPacket, int.class, 1); - private static final Reflection.MethodInvoker getEntityTypes = Reflection.getMethod("{obc}.util.CraftMagicNumbers", "getEntityTypes", EntityType.class); + private static final Class registryBlocks = Reflection.getClass("{nms.core}.RegistryBlocks"); + private static final Class entityTypes = Reflection.getClass("{nms.world.entity}.EntityTypes"); + 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 types = new HashMap<>(); static { types.put(EntityType.ARMOR_STAND, 1); @@ -335,9 +340,9 @@ public class FlatteningWrapper14 implements FlatteningWrapper.IFlatteningWrapper @Override public void setSpawnPacketType(Object packet, EntityType type) { 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 { - spawnType.set(packet, getEntityTypes.invoke(null, type)); + spawnType.set(packet, get.invoke(entityTypesRegistry, toMinecraft.invoke(null, type.getKey()))); } } diff --git a/SpigotCore_14/src/de/steamwar/core/RecipeDiscoverWrapper14.java b/SpigotCore_14/src/de/steamwar/core/RecipeDiscoverWrapper14.java new file mode 100644 index 0000000..93e050d --- /dev/null +++ b/SpigotCore_14/src/de/steamwar/core/RecipeDiscoverWrapper14.java @@ -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 . + */ + +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); + } +} diff --git a/SpigotCore_8/src/de/steamwar/core/RecipeDiscoverWrapper8.java b/SpigotCore_8/src/de/steamwar/core/RecipeDiscoverWrapper8.java new file mode 100644 index 0000000..59faa4c --- /dev/null +++ b/SpigotCore_8/src/de/steamwar/core/RecipeDiscoverWrapper8.java @@ -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 . + */ + +package de.steamwar.core; + +public class RecipeDiscoverWrapper8 implements RecipeDiscoverWrapper { + // Event not available pre flattening +} diff --git a/SpigotCore_9/build.gradle b/SpigotCore_9/build.gradle index 4585a01..8e81844 100644 --- a/SpigotCore_9/build.gradle +++ b/SpigotCore_9/build.gradle @@ -43,6 +43,8 @@ sourceSets { } dependencies { + compileOnly 'com.viaversion:viaversion-api:4.3.1' + compileOnly project(":SpigotCore_Main") compileOnly project(":SpigotCore_8") diff --git a/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java b/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java index 97fe828..5602d9a 100644 --- a/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java +++ b/SpigotCore_9/src/de/steamwar/core/BountifulWrapper9.java @@ -20,6 +20,7 @@ package de.steamwar.core; import com.comphenix.tinyprotocol.Reflection; +import com.viaversion.viaversion.api.Via; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.BaseComponent; import org.bukkit.Sound; @@ -36,6 +37,9 @@ public class BountifulWrapper9 implements BountifulWrapper.IBountifulWrapper { @Override 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); } diff --git a/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java b/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java index c3100b2..fc1e8c1 100644 --- a/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java +++ b/SpigotCore_Main/src/com/comphenix/tinyprotocol/Reflection.java @@ -251,7 +251,7 @@ public final class Reflection { // Search in every superclass 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))); } diff --git a/SpigotCore_Main/src/de/steamwar/core/Core.java b/SpigotCore_Main/src/de/steamwar/core/Core.java index ff0d555..7d3a30d 100644 --- a/SpigotCore_Main/src/de/steamwar/core/Core.java +++ b/SpigotCore_Main/src/de/steamwar/core/Core.java @@ -22,10 +22,7 @@ package de.steamwar.core; import com.comphenix.tinyprotocol.TinyProtocol; import de.steamwar.command.*; import de.steamwar.core.authlib.AuthlibInjector; -import de.steamwar.core.events.ChattingEvent; -import de.steamwar.core.events.PartialChunkFixer; -import de.steamwar.core.events.PlayerJoinedEvent; -import de.steamwar.core.events.WorldLoadEvent; +import de.steamwar.core.events.*; import de.steamwar.message.Message; import de.steamwar.network.NetworkReceiver; import de.steamwar.network.handlers.ServerDataHandler; @@ -34,6 +31,7 @@ import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.internal.Statement; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; +import org.bukkit.event.Listener; import org.bukkit.plugin.java.JavaPlugin; import java.io.BufferedReader; @@ -84,30 +82,33 @@ public class Core extends JavaPlugin{ 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); - Bukkit.getPluginManager().registerEvents(new ChattingEvent(), this); - Bukkit.getPluginManager().registerEvents(new WorldLoadEvent(), this); - if(!Statement.productionDatabase()) { - Bukkit.getPluginManager().registerEvents(LocaleChangeWrapper.impl, this); + for(Listener listener : new Listener[]{new CaseInsensitiveCommandsListener(), new PlayerJoinedEvent(), new ChattingEvent(), new WorldLoadEvent(), RecipeDiscoverWrapper.impl}) { + getServer().getPluginManager().registerEvents(listener, this); } + if(!Statement.productionDatabase()) { + getServer().getPluginManager().registerEvents(LocaleChangeWrapper.impl, this); + } + getServer().getMessenger().registerIncomingPluginChannel(this, "sw:bridge", new NetworkReceiver()); getServer().getMessenger().registerOutgoingPluginChannel(this, "sw:bridge"); + if(Core.getVersion() < 19) AuthlibInjector.inject(); + TinyProtocol.init(); + new AntiNocom(); if(Core.getVersion() < 17 && Bukkit.getPluginManager().getPlugin("ViaVersion") != null) 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) 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 { getLogger().log(Level.INFO, "Running on: " + new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("hostname").getInputStream())).readLine()); } catch (IOException e) { diff --git a/SpigotCore_Main/src/de/steamwar/core/RecipeDiscoverWrapper.java b/SpigotCore_Main/src/de/steamwar/core/RecipeDiscoverWrapper.java new file mode 100644 index 0000000..0d6b9da --- /dev/null +++ b/SpigotCore_Main/src/de/steamwar/core/RecipeDiscoverWrapper.java @@ -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 . + */ + +package de.steamwar.core; + +import org.bukkit.event.Listener; + +public interface RecipeDiscoverWrapper extends Listener { + RecipeDiscoverWrapper impl = VersionDependent.getVersionImpl(Core.getInstance()); +} diff --git a/SpigotCore_Main/src/de/steamwar/core/events/AntiNocom.java b/SpigotCore_Main/src/de/steamwar/core/events/AntiNocom.java new file mode 100644 index 0000000..0799523 --- /dev/null +++ b/SpigotCore_Main/src/de/steamwar/core/events/AntiNocom.java @@ -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 . + */ + +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 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; + } +} diff --git a/SpigotCore_Main/src/de/steamwar/core/events/PlayerJoinedEvent.java b/SpigotCore_Main/src/de/steamwar/core/events/PlayerJoinedEvent.java index aae2000..fe342bd 100644 --- a/SpigotCore_Main/src/de/steamwar/core/events/PlayerJoinedEvent.java +++ b/SpigotCore_Main/src/de/steamwar/core/events/PlayerJoinedEvent.java @@ -35,10 +35,7 @@ public class PlayerJoinedEvent implements Listener{ @EventHandler(priority = EventPriority.LOWEST) private void onJoin(PlayerJoinEvent event) { Player player = event.getPlayer(); - if(!Statement.productionDatabase()) { - SteamwarUser.createOrUpdateUsername(player.getUniqueId(), player.getName()); - } - SteamwarUser user = SteamwarUser.get(player.getUniqueId()); + SteamwarUser user = Statement.productionDatabase() ? SteamwarUser.get(player.getUniqueId()) : SteamwarUser.getOrCreate(player.getUniqueId(), player.getName(), uuid -> {}, (oldName, newName) -> {}); if(user.getUserGroup() != UserGroup.Member) { UserGroup group = user.getUserGroup(); diff --git a/SpigotCore_Main/src/de/steamwar/entity/RArmorStand.java b/SpigotCore_Main/src/de/steamwar/entity/RArmorStand.java index 5513d2b..369754a 100644 --- a/SpigotCore_Main/src/de/steamwar/entity/RArmorStand.java +++ b/SpigotCore_Main/src/de/steamwar/entity/RArmorStand.java @@ -52,8 +52,9 @@ public class RArmorStand extends REntity { private final 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; + server.addEntity(this); } @Override diff --git a/SpigotCore_Main/src/de/steamwar/entity/REntity.java b/SpigotCore_Main/src/de/steamwar/entity/REntity.java index bc7736e..83dc391 100644 --- a/SpigotCore_Main/src/de/steamwar/entity/REntity.java +++ b/SpigotCore_Main/src/de/steamwar/entity/REntity.java @@ -20,7 +20,10 @@ package de.steamwar.entity; 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.IntList; import lombok.Getter; @@ -73,6 +76,7 @@ public class REntity { public REntity(REntityServer server, EntityType entityType, Location location) { this(server,entityType,location,0); + server.addEntity(this); } protected REntity(REntityServer server, EntityType entityType, Location location,int objectData) { @@ -97,8 +101,6 @@ public class REntity { this.isGlowing = false; this.objectData = objectData; - - server.addEntity(this); } 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() { switch (Core.getVersion()) { case 8: diff --git a/SpigotCore_Main/src/de/steamwar/entity/REntityServer.java b/SpigotCore_Main/src/de/steamwar/entity/REntityServer.java index 1b85252..667bcce 100644 --- a/SpigotCore_Main/src/de/steamwar/entity/REntityServer.java +++ b/SpigotCore_Main/src/de/steamwar/entity/REntityServer.java @@ -19,9 +19,11 @@ package de.steamwar.entity; +import com.comphenix.tinyprotocol.Reflection; import com.comphenix.tinyprotocol.TinyProtocol; import de.steamwar.core.Core; import de.steamwar.core.FlatteningWrapper; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; 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.PlayerQuitEvent; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; +import java.util.function.BiFunction; import java.util.function.Consumer; +import java.util.function.Function; public class REntityServer implements Listener { @@ -43,15 +49,58 @@ public class REntityServer implements Listener { private static final HashSet emptyEntities = new HashSet<>(0); private static final HashSet emptyPlayers = new HashSet<>(0); + private static final Class useEntity = Reflection.getClass("{nms.network.protocol.game}.PacketPlayInUseEntity"); + private static final Reflection.FieldAccessor 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 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 entityMap = new ConcurrentHashMap<>(); private final HashMap> entities = new HashMap<>(); private final HashMap> players = new HashMap<>(); private final HashMap lastLocation = new HashMap<>(); private final HashMap viewDistance = new HashMap<>(); + private EntityActionListener callback = null; + private final Set playersThatClicked = Collections.synchronizedSet(new HashSet<>()); + + private final BiFunction 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() { 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) { Location location = player.getLocation(); lastLocation.put(player, location); @@ -65,6 +114,7 @@ public class REntityServer implements Listener { } public void close() { + TinyProtocol.instance.removeFilter(useEntity, filter); for(Player player : lastLocation.keySet().toArray(new Player[0])) { removePlayer(player); } @@ -72,6 +122,7 @@ public class REntityServer implements Listener { } void addEntity(REntity entity) { + entityMap.put(entity.entityId, entity); addEntityToChunk(entity); entity.spawn(packet -> updateEntity(entity, packet)); } @@ -105,6 +156,7 @@ public class REntityServer implements Listener { void removeEntity(REntity entity) { entity.despawn(packet -> updateEntity(entity, packet)); removeEntityFromChunk(entity); + entityMap.remove(entity.entityId); } private void addEntityToChunk(REntity entity) { @@ -158,7 +210,14 @@ public class REntityServer implements Listener { if(location == null) return; - forChunkInView(player, location, (x, z) -> players.get(chunkToId(x, z)).remove(player)); + forChunkInView(player, location, (x, z) -> { + long id = chunkToId(x, z); + Set playersInChunk = players.get(id); + playersInChunk.remove(player); + if(playersInChunk.isEmpty()) + players.remove(id); + }); + viewDistance.remove(player); } private void onMissing(Set of, Set in, Consumer> packetProvider) { @@ -194,7 +253,12 @@ public class REntityServer implements Listener { private void removePlayerFromChunk(Player player, int x, int z) { long id = chunkToId(x, z); - players.get(id).remove(player); + + Set playersInChunk = players.get(id); + playersInChunk.remove(player); + if(playersInChunk.isEmpty()) + players.remove(id); + for(REntity entity : entities.getOrDefault(id, emptyEntities)) { entity.despawn(packet -> TinyProtocol.instance.sendPacket(player, packet)); } @@ -227,4 +291,13 @@ public class REntityServer implements Listener { private long chunkToId(int x, int z) { return ((long) x << 32) + z; } + + public enum EntityAction { + INTERACT, + ATTACK, + } + + public interface EntityActionListener { + void onAction(Player player, REntity entity, EntityAction action); + } } diff --git a/SpigotCore_Main/src/de/steamwar/entity/RFallingBlockEntity.java b/SpigotCore_Main/src/de/steamwar/entity/RFallingBlockEntity.java index b436997..b17fefa 100644 --- a/SpigotCore_Main/src/de/steamwar/entity/RFallingBlockEntity.java +++ b/SpigotCore_Main/src/de/steamwar/entity/RFallingBlockEntity.java @@ -29,5 +29,6 @@ public class RFallingBlockEntity extends REntity{ public RFallingBlockEntity(REntityServer server, Location location, Material material) { super(server, EntityType.FALLING_BLOCK, location, BlockIds.impl.materialToId(material) >> (Core.getVersion() <= 12 ? 4 : 0)); + server.addEntity(this); } } diff --git a/SpigotCore_Main/src/de/steamwar/entity/RPlayer.java b/SpigotCore_Main/src/de/steamwar/entity/RPlayer.java index 013642d..dde86cb 100644 --- a/SpigotCore_Main/src/de/steamwar/entity/RPlayer.java +++ b/SpigotCore_Main/src/de/steamwar/entity/RPlayer.java @@ -78,6 +78,7 @@ public class RPlayer extends REntity { super(server, EntityType.PLAYER, uuid, location,0); this.name = name; //team.addEntry(name); + server.addEntity(this); } @Override diff --git a/SpigotCore_Main/src/de/steamwar/inventory/SchematicSelector.java b/SpigotCore_Main/src/de/steamwar/inventory/SchematicSelector.java index e57ef68..ed3f856 100644 --- a/SpigotCore_Main/src/de/steamwar/inventory/SchematicSelector.java +++ b/SpigotCore_Main/src/de/steamwar/inventory/SchematicSelector.java @@ -163,7 +163,7 @@ public class SchematicSelector { } if(!singleDirOpen) { 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 { return getParent(parent).orElse(null); } diff --git a/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java b/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java index 87b6708..ecbf86a 100644 --- a/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java +++ b/SpigotCore_Main/src/de/steamwar/sql/SchematicData.java @@ -36,11 +36,6 @@ import java.util.zip.GZIPInputStream; 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) { try { 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 static final Statement selSchemData = new Statement("SELECT NodeData FROM SchematicNode WHERE NodeId = ?"); - - private final SchematicNode node; + private final NodeData data; public SchematicData(SchematicNode node) { - this.node = node; + this.data = NodeData.get(node); if(node.isDir()) 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 { - return WorldEditWrapper.impl.getClipboard(schemData(), node.getSchemFormat()); + return WorldEditWrapper.impl.getClipboard(data.schemData(), data.getNodeFormat()); } 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 { @@ -92,16 +65,11 @@ public class SchematicData { } 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 public void saveFromBytes(byte[] bytes, boolean newFormat) { - saveFromStream(new ByteArrayInputStream(bytes), newFormat); - } - - public void saveFromStream(InputStream blob, boolean newFormat) { - updateDatabase.update(blob, newFormat, node.getId()); - node.setNodeFormat(newFormat); + data.saveFromStream(new ByteArrayInputStream(bytes), newFormat); } }