Compare commits

..

18 Commits

Author SHA1 Message Date
5a46f10f8b First fix REntity for 1.21
All checks were successful
SteamWarCI Build successful
2025-04-16 10:10:32 +02:00
0b14a216d9 Fix SmartPlaceListener updating block under repeater/comparator
All checks were successful
SteamWarCI Build successful
2025-04-14 10:04:57 +02:00
b2853b9dec Fix RCommand being able to send offline players
All checks were successful
SteamWarCI Build successful
2025-04-14 10:01:50 +02:00
df5c363fb7 Fix FreezeListener
All checks were successful
SteamWarCI Build successful
2025-04-14 09:57:31 +02:00
c9e4b57f12 Fix: Explicitly cast null to Integer in DownloadCommand
All checks were successful
SteamWarCI Build successful
2025-04-12 19:10:18 +02:00
fdcd248ba6 Merge branch 'main' of https://git.steamwar.de/SteamWar/SteamWar
Some checks failed
SteamWarCI Build failed
2025-04-12 19:04:11 +02:00
f573771355 Hotfix: Double Creation of //copy Schematics in //download command 2025-04-12 19:03:32 +02:00
80078cd8e2 Merge pull request 'Fix spectator handling' (#38) from spectator-improvements into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #38
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2025-04-12 14:46:41 +02:00
76fc468d89 Merge pull request 'Refactors SchematicNode queries for efficiency' (#39) from improve-search-querry into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #39
Reviewed-by: Lixfel <lixfel@noreply.localhost>
2025-04-12 14:40:34 +02:00
1304048509 Refactors SchematicNode queries for efficiency
All checks were successful
SteamWarCI Build successful
2025-04-11 00:07:53 +02:00
Lixfel
cf4ac95c2f Bugfix after testing
All checks were successful
SteamWarCI Build successful
2025-04-09 21:04:28 +02:00
Lixfel
f2d8c9c02b Only AntiTest
All checks were successful
SteamWarCI Build successful
2025-04-08 21:34:41 +02:00
Lixfel
2405c5e620 Fix spectator handling
All checks were successful
SteamWarCI Build successful
2025-04-08 21:31:47 +02:00
d9493c7474 Dont show bedrock players and send an error for getting your own skull as a bedrock player
All checks were successful
SteamWarCI Build successful
2025-04-08 20:58:23 +02:00
2ccb240ef5 Merge remote-tracking branch 'origin/main'
All checks were successful
SteamWarCI Build successful
2025-04-08 20:54:54 +02:00
d1d1679c0a Add /skull shorthand for own skull 2025-04-08 20:54:48 +02:00
62002e44d7 Merge pull request 'Add techhiderbug command.' (#36) from FightSystem/techhiderbug into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #36
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2025-04-07 21:22:39 +02:00
Lixfel
9c3f7526ff Add techhiderbug command.
All checks were successful
SteamWarCI Build successful
2025-04-07 19:37:23 +02:00
25 changed files with 365 additions and 142 deletions

View File

@@ -113,8 +113,8 @@ public class FreezeListener implements Listener, ScoreboardElement {
if (Core.getVersion() < 19) return; if (Core.getVersion() < 19) return;
if (e.getPlayer().getInventory().getItemInMainHand().getType() == Material.DEBUG_STICK) return; if (e.getPlayer().getInventory().getItemInMainHand().getType() == Material.DEBUG_STICK) return;
if (Region.getRegion(e.getBlock().getLocation()).get(Flag.FREEZE) == FreezeMode.ACTIVE) { if (Region.getRegion(e.getBlock().getLocation()).get(Flag.FREEZE) == FreezeMode.ACTIVE) {
if (e.isCancelled()) return;
e.setCancelled(true); e.setCancelled(true);
e.getBlock().setType(Material.BARRIER, false);
e.getBlock().setType(Material.AIR, false); e.getBlock().setType(Material.AIR, false);
} }
} }

View File

@@ -223,7 +223,7 @@ public class SmartPlaceListener implements Listener {
Block block = event.getBlock().getRelative(BlockFace.DOWN); Block block = event.getBlock().getRelative(BlockFace.DOWN);
BlockState old = block.getState(); BlockState old = block.getState();
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> { Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
block.setType(Material.GLASS); block.setType(Material.GLASS, false);
old.update(true, false); old.update(true, false);
}, 1); }, 1);
} }

View File

@@ -42,6 +42,15 @@ public class SkullCommand extends SWCommand {
super("skull", "head"); super("skull", "head");
} }
@Register
public void giveCommand(@Validator Player p) {
if (p.getName().startsWith(".")) {
BauSystem.MESSAGE.send("SKULL_INVALID", p);
return;
}
giveCommand(p, p.getName());
}
@Register(description = "SKULL_HELP") @Register(description = "SKULL_HELP")
public void giveCommand(@Validator Player p, @Mapper("player") @ErrorMessage("SKULL_INVALID") String skull) { public void giveCommand(@Validator Player p, @Mapper("player") @ErrorMessage("SKULL_INVALID") String skull) {
ItemStack is = SWItem.getPlayerSkull(skull).getItemStack(); ItemStack is = SWItem.getPlayerSkull(skull).getItemStack();
@@ -63,7 +72,7 @@ public class SkullCommand extends SWCommand {
@Override @Override
public List<String> tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) { public List<String> tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) {
return Bukkit.getOnlinePlayers().stream().map(Player::getName).filter(s1 -> !s1.endsWith("")).collect(Collectors.toList()); return Bukkit.getOnlinePlayers().stream().map(Player::getName).filter(s1 -> !s1.startsWith(".")).collect(Collectors.toList());
} }
}; };
} }

View File

@@ -31,10 +31,13 @@ public class SchematicNode {
static { static {
SchematicType.Normal.name(); // Ensure SchematicType is loaded. SchematicType.Normal.name(); // Ensure SchematicType is loaded.
new SqlTypeMapper<>(SchematicNode.class, null, (rs, identifier) -> { throw new SecurityException("SchematicNode cannot be used as type (recursive select)"); }, (st, index, value) -> st.setInt(index, value.nodeId)); new SqlTypeMapper<>(SchematicNode.class, null, (rs, identifier) -> {
throw new SecurityException("SchematicNode cannot be used as type (recursive select)");
}, (st, index, value) -> st.setInt(index, value.nodeId));
} }
private static final Map<Integer, Map<String, List<String>>> TAB_CACHE = new HashMap<>(); private static final Map<Integer, Map<String, List<String>>> TAB_CACHE = new HashMap<>();
public static void clear() { public static void clear() {
TAB_CACHE.clear(); TAB_CACHE.clear();
} }
@@ -42,39 +45,60 @@ public class SchematicNode {
private static final String nodeSelector = "SELECT NodeId, NodeOwner, NodeOwner AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode "; private static final String nodeSelector = "SELECT NodeId, NodeOwner, NodeOwner AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode ";
private static final Table<SchematicNode> table = new Table<>(SchematicNode.class); private static final Table<SchematicNode> table = new Table<>(SchematicNode.class);
private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem", "NodeType"); private static final Statement create = table.insertFields(true, "NodeOwner", "NodeName", "ParentNode", "NodeItem",
private static final Statement update = table.update(Table.PRIMARY, "NodeName", "ParentNode", "NodeItem", "NodeType", "NodeRank", "ReplaceColor", "AllowReplay"); "NodeType");
private static final Statement update = table.update(Table.PRIMARY, "NodeName", "ParentNode", "NodeItem",
"NodeType", "NodeRank", "ReplaceColor", "AllowReplay");
private static final Statement delete = table.delete(Table.PRIMARY); private static final Statement delete = table.delete(Table.PRIMARY);
private static final SelectStatement<SchematicNode> byId = new SelectStatement<>(table, nodeSelector + "WHERE NodeId = ?"); private static final SelectStatement<SchematicNode> byId = new SelectStatement<>(table,
private static final SelectStatement<SchematicNode> byOwnerNameParent = new SelectStatement<>(table, nodeSelector + "WHERE NodeOwner = ? AND NodeName = ? AND ParentNode " + Statement.NULL_SAFE_EQUALS + "?"); nodeSelector + "WHERE NodeId = ?");
private static final SelectStatement<SchematicNode> byParent = new SelectStatement<>(table, nodeSelector + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName"); private static final SelectStatement<SchematicNode> byOwnerNameParent = new SelectStatement<>(table,
private static final SelectStatement<SchematicNode> dirsByParent = new SelectStatement<>(table, nodeSelector + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? AND NodeType is NULL ORDER BY NodeName"); nodeSelector + "WHERE NodeOwner = ? AND NodeName = ? AND ParentNode " + Statement.NULL_SAFE_EQUALS + "?");
private static final SelectStatement<SchematicNode> byOwnerType = new SelectStatement<>(table, nodeSelector + "WHERE NodeOwner = ? AND NodeType = ? ORDER BY NodeName"); private static final SelectStatement<SchematicNode> byParent = new SelectStatement<>(table,
private static final SelectStatement<SchematicNode> byType = new SelectStatement<>(table, nodeSelector + "WHERE NodeType = ? ORDER BY NodeName"); nodeSelector + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> all = new SelectStatement<>(table, "SELECT * FROM EffectiveSchematicNode WHERE EffectiveOwner = ? ORDER BY NodeName"); private static final SelectStatement<SchematicNode> dirsByParent = new SelectStatement<>(table, nodeSelector
private static final SelectStatement<SchematicNode> list = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName"); + "WHERE ParentNode" + Statement.NULL_SAFE_EQUALS + "? AND NodeType is NULL ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byParentName = new SelectStatement<>(table, "SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId " + Statement.NULL_SAFE_EQUALS + "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?"); private static final SelectStatement<SchematicNode> byOwnerType = new SelectStatement<>(table,
private static final SelectStatement<SchematicNode> schematicAccessibleForUser = new SelectStatement<>(table, "SELECT COUNT(DISTINCT NodeId) FROM EffectiveSchematicNode WHERE EffectiveOwner = ? AND NodeId = ?"); nodeSelector + "WHERE NodeOwner = ? AND NodeType = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> accessibleByUserTypeInParent = new SelectStatement<>(table, "WITH RECURSIVE RSASN AS(WITH RECURSIVE RSAN AS (WITH RSANH AS (WITH RECURSIVE RSA AS (SELECT SN.NodeId, NM.ParentId FROM SchematicNode SN LEFT JOIN NodeMember NM on SN.NodeId = NM.NodeId WHERE NM.UserId = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN INNER JOIN RSA ON RSA.NodeId = SN.ParentNode) SELECT * FROM RSA UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?) SELECT * FROM RSANH UNION SELECT SN.NodeId, SN.ParentNode FROM RSANH JOIN SchematicNode SN ON SN.ParentNode = RSANH.NodeId) SELECT RSAN.NodeId, RSAN.ParentId FROM RSAN JOIN SchematicNode SN ON SN.NodeId = RSAN.NodeId WHERE NodeType = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN JOIN RSASN ON SN.NodeId = RSASN.ParentId) SELECT SN.*, ? as EffectiveOwner, RSASN.ParentId AS ParentNode FROM RSASN JOIN SchematicNode SN ON SN.NodeId = RSASN.NodeId WHERE RSASN.ParentId" + Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName"); private static final SelectStatement<SchematicNode> byType = new SelectStatement<>(table,
private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table, "WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeType = ?"); nodeSelector + "WHERE NodeType = ? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byIdAndUser = new SelectStatement<>(table, "SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE NodeId = ?"); private static final SelectStatement<SchematicNode> all = new SelectStatement<>(table,
private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table, "WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? AND EffectiveOwner = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId"); "WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId");
private static final SelectStatement<SchematicNode> list = new SelectStatement<>(table,
"SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId "
+ Statement.NULL_SAFE_EQUALS
+ "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE (? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?) ORDER BY NodeName");
private static final SelectStatement<SchematicNode> byParentName = new SelectStatement<>(table,
"SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode INNER JOIN NodeMember NM on SchematicNode.NodeId = NM.NodeId WHERE NM.ParentId "
+ Statement.NULL_SAFE_EQUALS
+ "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE ((? IS NULL AND ParentNode IS NULL AND NodeOwner = ?) OR (? IS NOT NULL AND ParentNode = ?)) AND NodeName = ?");
private static final SelectStatement<SchematicNode> schematicAccessibleForUser = new SelectStatement<>(table,
"WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeId = ?");
private static final SelectStatement<SchematicNode> accessibleByUserTypeInParent = new SelectStatement<>(table,
"WITH RECURSIVE RSASN AS(WITH RECURSIVE RSAN AS (WITH RSANH AS (WITH RECURSIVE RSA AS (SELECT SN.NodeId, NM.ParentId FROM SchematicNode SN LEFT JOIN NodeMember NM on SN.NodeId = NM.NodeId WHERE NM.UserId = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN INNER JOIN RSA ON RSA.NodeId = SN.ParentNode) SELECT * FROM RSA UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?) SELECT * FROM RSANH UNION SELECT SN.NodeId, SN.ParentNode FROM RSANH JOIN SchematicNode SN ON SN.ParentNode = RSANH.NodeId) SELECT RSAN.NodeId, RSAN.ParentId FROM RSAN JOIN SchematicNode SN ON SN.NodeId = RSAN.NodeId WHERE NodeType = ? UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN JOIN RSASN ON SN.NodeId = RSASN.ParentId) SELECT SN.*, ? as EffectiveOwner, RSASN.ParentId AS ParentNode FROM RSASN JOIN SchematicNode SN ON SN.NodeId = RSASN.NodeId WHERE RSASN.ParentId"
+ Statement.NULL_SAFE_EQUALS + "? ORDER BY NodeName");
private static final SelectStatement<SchematicNode> accessibleByUserType = new SelectStatement<>(table,
"WITH RECURSIVE Nodes AS (SELECT NodeId, ParentId as ParentNode FROM NodeMember WHERE UserId = ? UNION SELECT NodeId, ParentNode FROM SchematicNode WHERE NodeOwner = ?), RSN AS ( SELECT NodeId, ParentNode FROM Nodes UNION SELECT SN.NodeId, SN.ParentNode FROM SchematicNode SN, RSN WHERE SN.ParentNode = RSN.NodeId ) SELECT SN.*, ? AS EffectiveOwner FROM RSN INNER JOIN SchematicNode SN ON RSN.NodeId = SN.NodeId WHERE NodeType = ?");
private static final SelectStatement<SchematicNode> byIdAndUser = new SelectStatement<>(table,
"SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, ReplaceColor, AllowReplay FROM SchematicNode WHERE NodeId = ?");
private static final SelectStatement<SchematicNode> allParentsOfNode = new SelectStatement<>(table,
"WITH RECURSIVE R AS (SELECT NodeId, ParentNode FROM EffectiveSchematicNode WHERE NodeId = ? AND EffectiveOwner = ? UNION SELECT E.NodeId, E.ParentNode FROM R, EffectiveSchematicNode E WHERE R.ParentNode = E.NodeId AND E.EffectiveOwner = ?) SELECT SN.NodeId, SN.NodeOwner, ? AS EffectiveOwner, SN.NodeName, R.ParentNode, SN.LastUpdate, SN.NodeItem, SN.NodeType, SN.NodeRank, SN.ReplaceColor, SN.AllowReplay FROM R INNER JOIN SchematicNode SN ON SN.NodeId = R.NodeId");
static { static {
NodeMember.init(); NodeMember.init();
} }
@Field(keys = {Table.PRIMARY}, autoincrement = true) @Field(keys = { Table.PRIMARY }, autoincrement = true)
private final int nodeId; private final int nodeId;
@Field(keys = {"OwnerNameParent"}) @Field(keys = { "OwnerNameParent" })
private final int nodeOwner; private final int nodeOwner;
@Field(def = "0") @Field(def = "0")
@Getter @Getter
private final int effectiveOwner; private final int effectiveOwner;
@Field(keys = {"OwnerNameParent"}) @Field(keys = { "OwnerNameParent" })
private String nodeName; private String nodeName;
@Field(keys = {"OwnerNameParent"}, nullable = true) @Field(keys = { "OwnerNameParent" }, nullable = true)
private Integer parentNode; private Integer parentNode;
@Field(def = "CURRENT_TIMESTAMP") @Field(def = "CURRENT_TIMESTAMP")
private Timestamp lastUpdate; private Timestamp lastUpdate;
@@ -102,8 +126,7 @@ public class SchematicNode {
SchematicType nodeType, SchematicType nodeType,
int nodeRank, int nodeRank,
boolean replaceColor, boolean replaceColor,
boolean allowReplay boolean allowReplay) {
) {
this.nodeId = nodeId; this.nodeId = nodeId;
this.nodeOwner = nodeOwner; this.nodeOwner = nodeOwner;
this.effectiveOwner = effectiveOwner; this.effectiveOwner = effectiveOwner;
@@ -118,7 +141,7 @@ public class SchematicNode {
} }
public static List<SchematicNode> getAll(SteamwarUser user) { public static List<SchematicNode> getAll(SteamwarUser user) {
return all.listSelect(user); return all.listSelect(user, user, user);
} }
public static Map<Integer, List<SchematicNode>> getAllMap(SteamwarUser user) { public static Map<Integer, List<SchematicNode>> getAllMap(SteamwarUser user) {
@@ -130,7 +153,8 @@ public class SchematicNode {
} }
public static SchematicNode byParentName(SteamwarUser user, Integer schematicId, String name) { public static SchematicNode byParentName(SteamwarUser user, Integer schematicId, String name) {
return byParentName.select(user, schematicId, user, name, user, schematicId, user, schematicId, schematicId, name); return byParentName.select(user, schematicId, user, name, user, schematicId, user, schematicId, schematicId,
name);
} }
public static List<SchematicNode> accessibleByUserType(SteamwarUser user, SchematicType type) { public static List<SchematicNode> accessibleByUserType(SteamwarUser user, SchematicType type) {
@@ -142,10 +166,11 @@ public class SchematicNode {
} }
public static boolean schematicAccessibleForUser(SteamwarUser user, Integer schematicId) { public static boolean schematicAccessibleForUser(SteamwarUser user, Integer schematicId) {
return schematicAccessibleForUser.select(user, schematicId) != null; return schematicAccessibleForUser.select(user, user, user, schematicId) != null;
} }
public static List<SchematicNode> accessibleByUserTypeParent(SteamwarUser user, SchematicType type, Integer parentId) { public static List<SchematicNode> accessibleByUserTypeParent(SteamwarUser user, SchematicType type,
Integer parentId) {
return accessibleByUserTypeInParent.listSelect(user, user, type, user, parentId); return accessibleByUserTypeInParent.listSelect(user, user, type, user, parentId);
} }
@@ -160,7 +185,8 @@ public class SchematicNode {
private static Map<Integer, List<SchematicNode>> map(List<SchematicNode> in) { private static Map<Integer, List<SchematicNode>> map(List<SchematicNode> in) {
Map<Integer, List<SchematicNode>> map = new HashMap<>(); Map<Integer, List<SchematicNode>> map = new HashMap<>();
for (SchematicNode effectiveSchematicNode : in) { for (SchematicNode effectiveSchematicNode : in) {
map.computeIfAbsent(effectiveSchematicNode.getOptionalParent().orElse(0), k -> new ArrayList<>()).add(effectiveSchematicNode); map.computeIfAbsent(effectiveSchematicNode.getOptionalParent().orElse(0), k -> new ArrayList<>())
.add(effectiveSchematicNode);
} }
return map; return map;
} }
@@ -218,7 +244,8 @@ public class SchematicNode {
return byId.select(id); return byId.select(id);
} }
public static List<SchematicNode> getAccessibleSchematicsOfTypeInParent(int owner, String schemType, Integer parent) { public static List<SchematicNode> getAccessibleSchematicsOfTypeInParent(int owner, String schemType,
Integer parent) {
return accessibleByUserTypeParent(SteamwarUser.get(owner), SchematicType.fromDB(schemType), parent); return accessibleByUserTypeParent(SteamwarUser.get(owner), SchematicType.fromDB(schemType), parent);
} }
@@ -283,10 +310,12 @@ public class SchematicNode {
} }
if (s.contains("/")) { if (s.contains("/")) {
String[] layers = s.split("/"); String[] layers = s.split("/");
Optional<SchematicNode> currentNode = Optional.ofNullable(SchematicNode.byParentName(user, null, layers[0])); Optional<SchematicNode> currentNode = Optional
.ofNullable(SchematicNode.byParentName(user, null, layers[0]));
for (int i = 1; i < layers.length; i++) { for (int i = 1; i < layers.length; i++) {
int finalI = i; int finalI = i;
Optional<SchematicNode> node = currentNode.map(effectiveSchematicNode -> SchematicNode.byParentName(user, effectiveSchematicNode.getId(), layers[finalI])); Optional<SchematicNode> node = currentNode.map(effectiveSchematicNode -> SchematicNode
.byParentName(user, effectiveSchematicNode.getId(), layers[finalI]));
if (!node.isPresent()) { if (!node.isPresent()) {
return null; return null;
} else { } else {
@@ -365,7 +394,7 @@ public class SchematicNode {
@Deprecated @Deprecated
public void setType(String type) { public void setType(String type) {
if(isDir()) if (isDir())
throw new SecurityException("Node is Directory"); throw new SecurityException("Node is Directory");
this.nodeType = SchematicType.fromDB(type); this.nodeType = SchematicType.fromDB(type);
updateDB(); updateDB();
@@ -376,13 +405,13 @@ public class SchematicNode {
} }
public String getFileEnding() { public String getFileEnding() {
if(isDir()) if (isDir())
throw new SecurityException("Node is Directory"); throw new SecurityException("Node is Directory");
return NodeData.get(this).getNodeFormat().getFileEnding(); return NodeData.get(this).getNodeFormat().getFileEnding();
} }
public int getRank() { public int getRank() {
if(isDir()) if (isDir())
throw new SecurityException("Node is Directory"); throw new SecurityException("Node is Directory");
return nodeRank; return nodeRank;
} }
@@ -393,19 +422,19 @@ public class SchematicNode {
} }
public void setRank(int rank) { public void setRank(int rank) {
if(isDir()) if (isDir())
throw new SecurityException("Node is Directory"); throw new SecurityException("Node is Directory");
this.nodeRank = rank; this.nodeRank = rank;
} }
public SchematicType getSchemtype() { public SchematicType getSchemtype() {
if(isDir()) if (isDir())
throw new SecurityException("Is Directory"); throw new SecurityException("Is Directory");
return nodeType; return nodeType;
} }
public void setSchemtype(SchematicType type) { public void setSchemtype(SchematicType type) {
if(isDir()) if (isDir())
throw new SecurityException("Is Directory"); throw new SecurityException("Is Directory");
this.nodeType = type; this.nodeType = type;
updateDB(); updateDB();
@@ -416,7 +445,7 @@ public class SchematicNode {
} }
public void setReplaceColor(boolean replaceColor) { public void setReplaceColor(boolean replaceColor) {
if(isDir()) if (isDir())
throw new SecurityException("Is Directory"); throw new SecurityException("Is Directory");
this.replaceColor = replaceColor; this.replaceColor = replaceColor;
updateDB(); updateDB();
@@ -427,14 +456,15 @@ public class SchematicNode {
} }
public void setAllowReplay(boolean allowReplay) { public void setAllowReplay(boolean allowReplay) {
if(isDir()) if (isDir())
throw new SecurityException("Is Directory"); throw new SecurityException("Is Directory");
this.allowReplay = allowReplay; this.allowReplay = allowReplay;
updateDB(); updateDB();
} }
public SchematicNode getParentNode() { public SchematicNode getParentNode() {
if(parentNode == null) return null; if (parentNode == null)
return null;
return SchematicNode.getSchematicNode(parentNode); return SchematicNode.getSchematicNode(parentNode);
} }
@@ -486,7 +516,7 @@ public class SchematicNode {
} }
public String generateBreadcrumbs() { public String generateBreadcrumbs() {
if(brCache == null) { if (brCache == null) {
brCache = generateBreadcrumbs("/"); brCache = generateBreadcrumbs("/");
} }
return brCache; return brCache;
@@ -495,11 +525,15 @@ public class SchematicNode {
public String generateBreadcrumbs(String split) { public String generateBreadcrumbs(String split) {
StringBuilder builder = new StringBuilder(getName()); StringBuilder builder = new StringBuilder(getName());
Optional<SchematicNode> currentNode = Optional.of(this); Optional<SchematicNode> currentNode = Optional.of(this);
if(currentNode.map(SchematicNode::isDir).orElse(false)) { if (currentNode.map(SchematicNode::isDir).orElse(false)) {
builder.append(split); builder.append(split);
} }
while (currentNode.isPresent()) { while (currentNode.isPresent()) {
currentNode = currentNode.flatMap(schematicNode -> Optional.ofNullable(NodeMember.getNodeMember(schematicNode.getId(), effectiveOwner)).map(NodeMember::getParent).orElse(schematicNode.getOptionalParent())).map(SchematicNode::getSchematicNode); currentNode = currentNode
.flatMap(schematicNode -> Optional
.ofNullable(NodeMember.getNodeMember(schematicNode.getId(), effectiveOwner))
.map(NodeMember::getParent).orElse(schematicNode.getOptionalParent()))
.map(SchematicNode::getSchematicNode);
currentNode.ifPresent(node -> builder.insert(0, split).insert(0, node.getName())); currentNode.ifPresent(node -> builder.insert(0, split).insert(0, node.getName()));
} }
return builder.toString(); return builder.toString();
@@ -508,17 +542,22 @@ public class SchematicNode {
public List<Map.Entry<String, Integer>> generateBreadcrumbsMap(SteamwarUser user) { public List<Map.Entry<String, Integer>> generateBreadcrumbsMap(SteamwarUser user) {
List<Map.Entry<String, Integer>> map = new ArrayList<>(); List<Map.Entry<String, Integer>> map = new ArrayList<>();
Optional<SchematicNode> currentNode = Optional.of(this); Optional<SchematicNode> currentNode = Optional.of(this);
if(currentNode.map(SchematicNode::isDir).orElse(false)) { if (currentNode.map(SchematicNode::isDir).orElse(false)) {
map.add(new AbstractMap.SimpleEntry<>(getName(), getId())); map.add(new AbstractMap.SimpleEntry<>(getName(), getId()));
} }
while (currentNode.isPresent()) { while (currentNode.isPresent()) {
currentNode = currentNode.flatMap(schematicNode -> Optional.ofNullable(NodeMember.getNodeMember(schematicNode.getId(), effectiveOwner)).map(NodeMember::getParent).orElse(schematicNode.getOptionalParent())).map(SchematicNode::getSchematicNode); currentNode = currentNode
.flatMap(schematicNode -> Optional
.ofNullable(NodeMember.getNodeMember(schematicNode.getId(), effectiveOwner))
.map(NodeMember::getParent).orElse(schematicNode.getOptionalParent()))
.map(SchematicNode::getSchematicNode);
currentNode.ifPresent(node -> map.add(0, new AbstractMap.SimpleEntry<>(node.getName(), node.getId()))); currentNode.ifPresent(node -> map.add(0, new AbstractMap.SimpleEntry<>(node.getName(), node.getId())));
} }
return map; return map;
} }
private static final List<String> FORBIDDEN_NAMES = Collections.unmodifiableList(Arrays.asList("public")); private static final List<String> FORBIDDEN_NAMES = Collections.unmodifiableList(Arrays.asList("public"));
public static boolean invalidSchemName(String[] layers) { public static boolean invalidSchemName(String[] layers) {
for (String layer : layers) { for (String layer : layers) {
if (layer.isEmpty()) { if (layer.isEmpty()) {
@@ -535,7 +574,7 @@ public class SchematicNode {
layer.contains(" ")) { layer.contains(" ")) {
return true; return true;
} }
if(FORBIDDEN_NAMES.contains(layer.toLowerCase())) { if (FORBIDDEN_NAMES.contains(layer.toLowerCase())) {
return true; return true;
} }
} }
@@ -549,14 +588,15 @@ public class SchematicNode {
} }
int index = s.lastIndexOf("/"); int index = s.lastIndexOf("/");
String cacheKey = index == -1 ? "" : s.substring(0, index); String cacheKey = index == -1 ? "" : s.substring(0, index);
if(TAB_CACHE.containsKey(user.getId()) && TAB_CACHE.get(user.getId()).containsKey(cacheKey)) { if (TAB_CACHE.containsKey(user.getId()) && TAB_CACHE.get(user.getId()).containsKey(cacheKey)) {
return new ArrayList<>(TAB_CACHE.get(user.getId()).get(cacheKey)); return new ArrayList<>(TAB_CACHE.get(user.getId()).get(cacheKey));
} }
List<String> list = new ArrayList<>(); List<String> list = new ArrayList<>();
if (s.contains("/")) { if (s.contains("/")) {
String preTab = s.substring(0, s.lastIndexOf("/") + 1); String preTab = s.substring(0, s.lastIndexOf("/") + 1);
SchematicNode pa = SchematicNode.getNodeFromPath(user, preTab); SchematicNode pa = SchematicNode.getNodeFromPath(user, preTab);
if (pa == null) return new ArrayList<>(); if (pa == null)
return new ArrayList<>();
List<SchematicNode> nodes = SchematicNode.list(user, pa.getId()); List<SchematicNode> nodes = SchematicNode.list(user, pa.getId());
String br = pa.generateBreadcrumbs(); String br = pa.generateBreadcrumbs();
nodes.forEach(node -> list.add((sws ? "/" : "") + br + node.getName() + (node.isDir() ? "/" : ""))); nodes.forEach(node -> list.add((sws ? "/" : "") + br + node.getName() + (node.isDir() ? "/" : "")));

View File

@@ -29,4 +29,5 @@ dependencies {
compileOnly(libs.worldedit15) compileOnly(libs.worldedit15)
compileOnly(libs.fastutil) compileOnly(libs.fastutil)
compileOnly(libs.authlib) compileOnly(libs.authlib)
compileOnly(libs.netty)
} }

View File

@@ -97,6 +97,7 @@ public class FightSystem extends JavaPlugin {
new PrepareSchem(); new PrepareSchem();
new TestJoin(); new TestJoin();
new NormalJoin(); new NormalJoin();
new Spectator();
new RunningWorldInteraction(); new RunningWorldInteraction();
new PersonalKitCreator(); new PersonalKitCreator();
new ArrowStopper(); new ArrowStopper();
@@ -156,6 +157,7 @@ public class FightSystem extends JavaPlugin {
new LockschemCommand(); new LockschemCommand();
new StateCommand(); new StateCommand();
new SkipCommand(); new SkipCommand();
new TechhiderbugCommand();
new TPSWarpCommand(); new TPSWarpCommand();
new UnrankCommand(); new UnrankCommand();
new WinCommand(); new WinCommand();

View File

@@ -0,0 +1,71 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.fightsystem.commands;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.sql.SWException;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import java.io.StringWriter;
import java.util.Arrays;
public class TechhiderbugCommand implements CommandExecutor {
public TechhiderbugCommand() {
new StateDependentCommand(ArenaMode.All, FightState.All, "techhiderbug", this);
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String alias, String[] args) {
StringWriter writer = new StringWriter();
writer.append("ArenaMode: ").append(Config.mode.name()).append('\n');
writer.append("FightState: ").append(FightState.getFightState().name()).append('\n');
writer.append("TechHider enabled: ").append(FightState.getStateDependentFeatures().get(FightSystem.getTechHider()).toString()).append('\n');
writer.append("Arena region: ").append(Config.ArenaRegion.toString()).append('\n');
writer.append("Team regions: ");
Fight.teams().forEach(t -> writer.append(t.getName()).append(':').append(t.getExtendRegion().toString()).append(' '));
writer.append('\n');
writer.append("HullHider regions: ");
FightSystem.getHullHider().getHullMap().forEach((t, h) -> writer.append(t.getName()).append(':').append(h.getRegion().toString()).append(' '));
writer.append('\n');
writer.append("Hidden regions: ");
FightSystem.getTechHider().getHiddenRegion().forEach((p, r) -> writer.append(p.getName()).append(':').append(r.toString()).append(' '));
writer.append('\n');
writer.append('\n').append("Netty pipelines:\n");
Bukkit.getOnlinePlayers().forEach(p -> writer.append(p.getName()).append(": ").append(String.join(" ", TinyProtocol.instance.getPlayerInterceptors().get(p).getChannel().pipeline().names())).append('\n'));
SWException.log("Techhider-Bug reported by " + sender.getName() + ": " + Arrays.toString(args), writer.toString());
return false;
}
}

View File

@@ -104,40 +104,6 @@ public class Fight {
return null; return null;
} }
@SuppressWarnings("deprecation")
public static void setPlayerGamemode(Player player, GameMode gameMode) {
player.setGameMode(gameMode);
if(gameMode == GameMode.SPECTATOR) {
for(Player currentPlayer : Bukkit.getServer().getOnlinePlayers()) {
if(currentPlayer.getUniqueId() != player.getUniqueId() && currentPlayer.getGameMode() == GameMode.SPECTATOR) {
currentPlayer.hidePlayer(player);
player.hidePlayer(currentPlayer);
}
}
if(Config.test() || Config.isReferee(player))
return;
Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> {
if(!player.isOnline())
return;
pseudoSpectator(player, true);
}, 1);
}else if(gameMode == GameMode.SURVIVAL) {
for(Player currentPlayer : Bukkit.getServer().getOnlinePlayers()) {
if(currentPlayer.getUniqueId() != player.getUniqueId() && currentPlayer.getGameMode() == GameMode.SPECTATOR) {
currentPlayer.showPlayer(player);
player.showPlayer(currentPlayer);
}
}
}
}
public static void pseudoSpectator(Player player, boolean enable) {
TinyProtocol.instance.sendPacket(player, ProtocolWrapper.impl.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.GAMEMODE, new GameProfile(player.getUniqueId(), player.getName()), enable ? GameMode.CREATIVE : GameMode.SPECTATOR));
}
public static boolean publicOnly() { public static boolean publicOnly() {
if (Config.OnlyPublicSchematics) { if (Config.OnlyPublicSchematics) {
return true; return true;

View File

@@ -282,9 +282,9 @@ public class FightTeam {
FightSystem.getHullHider().updatePlayer(player); FightSystem.getHullHider().updatePlayer(player);
if(FightState.Spectate.contains(FightState.getFightState())) { if(FightState.Spectate.contains(FightState.getFightState())) {
Fight.setPlayerGamemode(player, GameMode.SPECTATOR); player.setGameMode(GameMode.SPECTATOR);
} else { } else {
Fight.setPlayerGamemode(player, GameMode.SURVIVAL); player.setGameMode(GameMode.SURVIVAL);
(FightState.ingame() ? fightPlayer.getKit() : memberKit).loadToPlayer(player); (FightState.ingame() ? fightPlayer.getKit() : memberKit).loadToPlayer(player);
} }
}); });
@@ -317,7 +317,7 @@ public class FightTeam {
entity.teleport(Config.SpecSpawn); entity.teleport(Config.SpecSpawn);
fightPlayer.ifPlayer(player -> { fightPlayer.ifPlayer(player -> {
Fight.setPlayerGamemode(player, GameMode.SPECTATOR); player.setGameMode(GameMode.SPECTATOR);
player.getInventory().clear(); player.getInventory().clear();
if(player.isOnline()){ if(player.isOnline()){
@@ -517,14 +517,14 @@ public class FightTeam {
@Override @Override
public void enable() { public void enable() {
players.values().forEach(fightPlayer -> { players.values().forEach(fightPlayer -> {
fightPlayer.ifPlayer(player -> Fight.setPlayerGamemode(player, GameMode.SPECTATOR)); fightPlayer.ifPlayer(player -> player.setGameMode(GameMode.SPECTATOR));
fightPlayer.getEntity().teleport(FightTeam.this.spawn); fightPlayer.getEntity().teleport(FightTeam.this.spawn);
}); });
} }
@Override @Override
public void disable() { public void disable() {
players.values().forEach(fightPlayer -> fightPlayer.ifPlayer(player -> Fight.setPlayerGamemode(player, GameMode.SURVIVAL))); players.values().forEach(fightPlayer -> fightPlayer.ifPlayer(player -> player.setGameMode(GameMode.SURVIVAL)));
} }
} }
} }

View File

@@ -84,6 +84,6 @@ public class LeaveableArena implements Listener {
private void markInArena(Player player) { private void markInArena(Player player) {
spectatorsInArena.put(player, player.getGameMode()); spectatorsInArena.put(player, player.getGameMode());
Fight.setPlayerGamemode(player, GameMode.SPECTATOR); player.setGameMode(GameMode.SPECTATOR);
} }
} }

View File

@@ -74,7 +74,7 @@ public class Permanent implements Listener {
public void handlePlayerRespawn(PlayerRespawnEvent event){ public void handlePlayerRespawn(PlayerRespawnEvent event){
Player player = event.getPlayer(); Player player = event.getPlayer();
if(Fight.fighting(player)) { if(Fight.fighting(player)) {
Fight.setPlayerGamemode(player, GameMode.SPECTATOR); player.setGameMode(GameMode.SPECTATOR);
FightTeam team = Fight.getPlayerTeam(player); FightTeam team = Fight.getPlayerTeam(player);
event.setRespawnLocation(team == null ? Config.SpecSpawn : team.getSpawn()); event.setRespawnLocation(team == null ? Config.SpecSpawn : team.getSpawn());
@@ -98,11 +98,11 @@ public class Permanent implements Listener {
FightPlayer fp = Fight.getFightPlayer(player); FightPlayer fp = Fight.getFightPlayer(player);
if (!Config.ArenaLeaveable && fp == null) { if (!Config.ArenaLeaveable && fp == null) {
Fight.setPlayerGamemode(player, GameMode.SPECTATOR); player.setGameMode(GameMode.SPECTATOR);
spectatorTeam.addEntry(player.getName()); spectatorTeam.addEntry(player.getName());
player.teleport(Config.SpecSpawn); player.teleport(Config.SpecSpawn);
} else if(fp != null && !fp.isLiving()) { } else if(fp != null && !fp.isLiving()) {
Fight.setPlayerGamemode(player, GameMode.SPECTATOR); player.setGameMode(GameMode.SPECTATOR);
player.teleport(fp.getTeam().getSpawn()); player.teleport(fp.getTeam().getSpawn());
} }
} }

View File

@@ -0,0 +1,114 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.fightsystem.listener;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerGameModeChangeEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import com.comphenix.tinyprotocol.TinyProtocol;
import com.mojang.authlib.GameProfile;
import de.steamwar.core.ProtocolWrapper;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightPlayer;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.states.StateDependentTask;
public class Spectator implements Listener {
private final Set<Player> pseudoSpectator = new HashSet<>();
public Spectator() {
new StateDependentListener(ArenaMode.AntiTest, FightState.All, this);
new StateDependentTask(ArenaMode.AntiTest, FightState.All, this::pseudoSpectatorCheck, 1, 1);
}
@EventHandler(priority = EventPriority.MONITOR)
public void handlePlayerJoin(PlayerJoinEvent e) {
Player player = e.getPlayer();
if(player.getGameMode() == GameMode.SPECTATOR)
gameModeChange(player, GameMode.SPECTATOR);
}
@EventHandler
public void onGameModeChange(PlayerGameModeChangeEvent e) {
gameModeChange(e.getPlayer(), e.getNewGameMode());
}
@SuppressWarnings("deprecation")
private void gameModeChange(Player player, GameMode gameMode) {
if (gameMode == GameMode.SPECTATOR) {
for(Player p : Bukkit.getServer().getOnlinePlayers()) {
if(p.getUniqueId() != player.getUniqueId())
p.hidePlayer(player);
}
} else {
for(Player p : Bukkit.getServer().getOnlinePlayers()) {
if(p.getUniqueId() != player.getUniqueId())
p.showPlayer(player);
}
}
}
@EventHandler
public void playerQuit(PlayerQuitEvent e) {
pseudoSpectator.remove(e.getPlayer());
}
private void pseudoSpectatorCheck() {
for (Player player : Bukkit.getOnlinePlayers()) {
if (player.getGameMode() != GameMode.SPECTATOR) {
pseudoSpectator.remove(player);
continue;
}
if (Config.isReferee(player))
continue;
FightPlayer fightPlayer = Fight.getFightPlayer(player);
if (fightPlayer == null || !fightPlayer.getTeam().getExtendRegion().playerInRegion(player.getLocation())) {
if (pseudoSpectator.add(player))
pseudoSpectator(player, true);
} else {
if (pseudoSpectator.remove(player))
pseudoSpectator(player, false);
}
}
}
private static void pseudoSpectator(Player player, boolean enable) {
TinyProtocol.instance.sendPacket(player, ProtocolWrapper.impl.playerInfoPacketConstructor(ProtocolWrapper.PlayerInfoAction.GAMEMODE, new GameProfile(player.getUniqueId(), player.getName()), enable ? GameMode.CREATIVE : GameMode.SPECTATOR));
}
}

View File

@@ -19,9 +19,14 @@
package de.steamwar.fightsystem.listener; package de.steamwar.fightsystem.listener;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import de.steamwar.fightsystem.ArenaMode; import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config; import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.events.BoardingEvent; import de.steamwar.fightsystem.events.BoardingEvent;
import de.steamwar.fightsystem.events.TeamDeathEvent; import de.steamwar.fightsystem.events.TeamDeathEvent;
import de.steamwar.fightsystem.events.TeamLeaveEvent; import de.steamwar.fightsystem.events.TeamLeaveEvent;
@@ -32,23 +37,12 @@ import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.states.FightState; import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.OneShotStateDependent; import de.steamwar.fightsystem.states.OneShotStateDependent;
import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.states.StateDependentTask;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashSet;
import java.util.Set;
public class TeamArea implements Listener { public class TeamArea implements Listener {
private final FightTeam team; private final FightTeam team;
private final Border spectatorBorder; private final Border spectatorBorder;
private final Border bordingBorder; private final Border bordingBorder;
private final Set<Player> realSpectator = new HashSet<>();
public TeamArea(FightTeam team) { public TeamArea(FightTeam team) {
this.team = team; this.team = team;
@@ -56,7 +50,6 @@ public class TeamArea implements Listener {
this.bordingBorder = new Border(team.getExtendRegion().to2d(), true, 1, "NO_ENTERN", team.getName() + ".boardingBorder"); this.bordingBorder = new Border(team.getExtendRegion().to2d(), true, 1, "NO_ENTERN", team.getName() + ".boardingBorder");
new StateDependentListener(ArenaMode.AntiTest, FightState.All, this); new StateDependentListener(ArenaMode.AntiTest, FightState.All, this);
new StateDependentTask(ArenaMode.AntiTest, FightState.TeamFix, this::realSpectatorCheck, 1, 1);
new OneShotStateDependent(ArenaMode.AntiTest, FightState.Spectate, () -> Fight.teams().forEach(t -> t.getPlayers().forEach(this::teamSpectator))); new OneShotStateDependent(ArenaMode.AntiTest, FightState.Spectate, () -> Fight.teams().forEach(t -> t.getPlayers().forEach(this::teamSpectator)));
} }
@@ -114,30 +107,5 @@ public class TeamArea implements Listener {
Player player = e.getPlayer(); Player player = e.getPlayer();
spectatorBorder.removePlayer(player); spectatorBorder.removePlayer(player);
bordingBorder.removePlayer(player); bordingBorder.removePlayer(player);
realSpectator.remove(player);
}
private void realSpectatorCheck() {
for(FightPlayer fightPlayer : team.getPlayers()) {
if(fightPlayer.isLiving())
continue;
fightPlayer.ifPlayer(player -> {
boolean inRegion = team.getExtendRegion().playerInRegion(player.getLocation());
if(inRegion && !realSpectator.contains(player)) {
realSpectator.add(player);
//Later to prevent race condition with Fight.setSpecatator() during respawn
Bukkit.getScheduler().runTaskLater(FightSystem.getPlugin(), () -> {
if(!player.isOnline())
return;
Fight.pseudoSpectator(player, false);
}, 2);
}else if(!inRegion && realSpectator.contains(player)) {
Fight.pseudoSpectator(player, true);
realSpectator.remove(player);
}
});
}
} }
} }

View File

@@ -49,6 +49,7 @@ public enum FightState {
public static final Set<FightState> AntiIngame = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(PRE_RUNNING, RUNNING))); public static final Set<FightState> AntiIngame = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(PRE_RUNNING, RUNNING)));
public static final Set<FightState> AntiSpectate = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(SPECTATE))); public static final Set<FightState> AntiSpectate = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(SPECTATE)));
@Getter
private static final Map<IStateDependent, Boolean> stateDependentFeatures = new HashMap<>(); private static final Map<IStateDependent, Boolean> stateDependentFeatures = new HashMap<>();
@Getter @Getter
private static FightState fightState = PRE_LEADER_SETUP; private static FightState fightState = PRE_LEADER_SETUP;

View File

@@ -45,6 +45,7 @@ public class Hull {
return material.isOccluding() || Config.HiddenBlocks.contains(material); return material.isOccluding() || Config.HiddenBlocks.contains(material);
} }
@Getter
private final Region region; private final Region region;
private final boolean groundVisible; private final boolean groundVisible;
private final IntVector[] directions; private final IntVector[] directions;

View File

@@ -33,6 +33,7 @@ import de.steamwar.fightsystem.states.StateDependent;
import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.states.StateDependentTask; import de.steamwar.fightsystem.states.StateDependentTask;
import de.steamwar.techhider.TechHider; import de.steamwar.techhider.TechHider;
import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
@@ -56,6 +57,7 @@ import java.util.function.Function;
public class HullHider implements Listener { public class HullHider implements Listener {
@Getter
private final Map<FightTeam, Hull> hullMap = new HashMap<>(); private final Map<FightTeam, Hull> hullMap = new HashMap<>();
private final Hull[] hulls; private final Hull[] hulls;
private final Map<Class<?>, BiFunction<Player, Object, Object>> packetHiders = new HashMap<>(); private final Map<Class<?>, BiFunction<Player, Object, Object>> packetHiders = new HashMap<>();

View File

@@ -159,4 +159,9 @@ public class Region {
public interface TriConsumer<T, V, U>{ public interface TriConsumer<T, V, U>{
void accept(T x, V y, U z); void accept(T x, V y, U z);
} }
@Override
public String toString() {
return minX + "," + minY + "," + minZ + "->" + maxX + "," + maxY + "," + maxZ;
}
} }

View File

@@ -32,6 +32,7 @@ import de.steamwar.fightsystem.states.StateDependent;
import de.steamwar.fightsystem.states.StateDependentListener; import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.SteamwarUser;
import de.steamwar.techhider.TechHider; import de.steamwar.techhider.TechHider;
import lombok.Getter;
import org.bukkit.GameMode; import org.bukkit.GameMode;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@@ -51,6 +52,7 @@ public class TechHiderWrapper extends StateDependent implements TechHider.Locati
public static final boolean ENABLED = !Config.OnlyPublicSchematics && !Config.test() && Config.TechhiderActive; public static final boolean ENABLED = !Config.OnlyPublicSchematics && !Config.test() && Config.TechhiderActive;
@Getter
private final ConcurrentHashMap<Player, Region> hiddenRegion = new ConcurrentHashMap<>(); private final ConcurrentHashMap<Player, Region> hiddenRegion = new ConcurrentHashMap<>();
private final ConcurrentHashMap<Player, Long> patterns = new ConcurrentHashMap<>(); private final ConcurrentHashMap<Player, Long> patterns = new ConcurrentHashMap<>();
private final TechHider techHider; private final TechHider techHider;

View File

@@ -27,4 +27,5 @@ commands:
resettb: resettb:
tpslimit: tpslimit:
tpswarp: tpswarp:
techhiderbug:
unrank: unrank:

View File

@@ -35,10 +35,10 @@ public class DownloadCommand extends SWCommand {
@Register(help = true) @Register(help = true)
public void genericCommand(Player player, String... args) { public void genericCommand(Player player, String... args) {
SteamwarUser user = SteamwarUser.get(player.getUniqueId()); SteamwarUser user = SteamwarUser.get(player.getUniqueId());
SchematicNode copyNode = SchematicNode.getSchematicNode(user.getId(), "//copy", 0); SchematicNode copyNode = SchematicNode.getSchematicNode(user.getId(), "//copy", (Integer) null);
boolean newSchem = false; boolean newSchem = false;
if(copyNode == null) { if (copyNode == null) {
copyNode = SchematicNode.createSchematicNode(user.getId(), "//copy", 0, SchematicType.Normal.toDB(), ""); copyNode = SchematicNode.createSchematicNode(user.getId(), "//copy", null, SchematicType.Normal.toDB(), "");
newSchem = true; newSchem = true;
} }
@@ -46,13 +46,13 @@ public class DownloadCommand extends SWCommand {
new SchematicData(copyNode).saveFromPlayer(player); new SchematicData(copyNode).saveFromPlayer(player);
} catch (IOException e) { } catch (IOException e) {
SchematicSystem.MESSAGE.send("DOWNLOAD_ERROR", player); SchematicSystem.MESSAGE.send("DOWNLOAD_ERROR", player);
if(newSchem) { if (newSchem) {
copyNode.delete(); copyNode.delete();
} }
throw new SecurityException(e); throw new SecurityException(e);
} catch (NoClipboardException e) { } catch (NoClipboardException e) {
SchematicSystem.MESSAGE.send("COMMAND_SAVE_CLIPBOARD_EMPTY", player); SchematicSystem.MESSAGE.send("COMMAND_SAVE_CLIPBOARD_EMPTY", player);
if(newSchem) { if (newSchem) {
copyNode.delete(); copyNode.delete();
} }
return; return;

View File

@@ -33,7 +33,7 @@ public class BountifulWrapper21 extends BountifulWrapper9 {
return (packet, x, y, z, pitch, yaw) -> { return (packet, x, y, z, pitch, yaw) -> {
PositionMoveRotation pos = field.get(packet); PositionMoveRotation pos = field.get(packet);
field.set(packet, new PositionMoveRotation(new Vec3D(x, y, z), pos.b(), yaw, pitch)); field.set(packet, new PositionMoveRotation(new Vec3D(x, y, z), pos == null ? new Vec3D(0, 0, 0) : pos.b(), yaw, pitch));
}; };
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
return super.getPositionSetter(packetClass, fieldOffset); return super.getPositionSetter(packetClass, fieldOffset);

View File

@@ -23,6 +23,7 @@ import de.steamwar.Reflection;
import de.steamwar.Reflection.Field; import de.steamwar.Reflection.Field;
import de.steamwar.core.Core; import de.steamwar.core.Core;
import io.netty.channel.*; import io.netty.channel.*;
import lombok.Getter;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
@@ -67,6 +68,7 @@ public class TinyProtocol implements Listener {
private boolean closed; private boolean closed;
private final Map<Class<?>, List<BiFunction<Player, Object, Object>>> packetFilters = new HashMap<>(); private final Map<Class<?>, List<BiFunction<Player, Object, Object>>> packetFilters = new HashMap<>();
@Getter
private final Map<Player, PacketInterceptor> playerInterceptors = new HashMap<>(); private final Map<Player, PacketInterceptor> playerInterceptors = new HashMap<>();
private TinyProtocol(final Plugin plugin) { private TinyProtocol(final Plugin plugin) {
@@ -136,8 +138,9 @@ public class TinyProtocol implements Listener {
private static final Field<Channel> getChannel = Reflection.getField(networkManager, Channel.class, 0); private static final Field<Channel> getChannel = Reflection.getField(networkManager, Channel.class, 0);
private static final Field<UUID> getUUID = Reflection.getField(networkManager, UUID.class, 0); private static final Field<UUID> getUUID = Reflection.getField(networkManager, UUID.class, 0);
private final class PacketInterceptor extends ChannelDuplexHandler { public final class PacketInterceptor extends ChannelDuplexHandler {
private final Player player; private final Player player;
@Getter
private final Channel channel; private final Channel channel;
private PacketInterceptor(Player player) { private PacketInterceptor(Player player) {

View File

@@ -177,9 +177,30 @@ public final class Reflection {
} }
public void set(Object target, Object value) { public void set(Object target, Object value) {
// This now works for Fields in records!
try { try {
f.set(target, value); long offset = Unsafe.getUnsafe().objectFieldOffset(f);
} catch (IllegalAccessException e) { Class<?> type = f.getType();
if (type == int.class) {
Unsafe.getUnsafe().putInt(target, offset, (Integer) value);
} else if (type == float.class) {
Unsafe.getUnsafe().putFloat(target, offset, (Float) value);
} else if (type == double.class) {
Unsafe.getUnsafe().putDouble(target, offset, (Double) value);
} else if (type == boolean.class) {
Unsafe.getUnsafe().putBoolean(target, offset, (Boolean) value);
} else if (type == byte.class) {
Unsafe.getUnsafe().putByte(target, offset, (Byte) value);
} else if (type == char.class) {
Unsafe.getUnsafe().putChar(target, offset, (Character) value);
} else if (type == short.class) {
Unsafe.getUnsafe().putShort(target, offset, (Short) value);
} else if (type == long.class) {
Unsafe.getUnsafe().putLong(target, offset, (Long) value);
} else {
Unsafe.getUnsafe().putReference(target, offset, value);
}
} catch (Exception e) {
throw new IllegalArgumentException("Cannot write field", e); throw new IllegalArgumentException("Cannot write field", e);
} }
} }

View File

@@ -396,10 +396,26 @@ public class REntity {
public static final Class<?> teleportPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket"); public static final Class<?> teleportPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket");
public static final Reflection.Field<Integer> teleportEntity = Reflection.getField(teleportPacket, int.class, 0); public static final Reflection.Field<Integer> teleportEntity = Reflection.getField(teleportPacket, int.class, 0);
public static final BountifulWrapper.PositionSetter teleportPosition = BountifulWrapper.impl.getPositionSetter(teleportPacket, Core.getVersion() == 8 ? 1 : 0); public static final BountifulWrapper.PositionSetter teleportPosition = BountifulWrapper.impl.getPositionSetter(teleportPacket, Core.getVersion() == 8 ? 1 : 0);
public static final Class<?> relative;
public static final Reflection.Field<Set> relatives;
static {
if (Core.getVersion() >= 21) {
relative = Reflection.getClass("net.minecraft.world.entity.Relative");
relatives = Reflection.getField(teleportPacket, Set.class, 0);
} else {
relative = null;
relatives = null;
}
}
private Object getTeleportPacket(){ private Object getTeleportPacket(){
Object packet = Reflection.newInstance(teleportPacket); Object packet = Reflection.newInstance(teleportPacket);
teleportEntity.set(packet, entityId); teleportEntity.set(packet, entityId);
teleportPosition.set(packet, x, y, z, pitch, yaw); teleportPosition.set(packet, x, y, z, pitch, yaw);
if (Core.getVersion() >= 21) {
// https://mappings.dev/1.21.3/net/minecraft/world/entity/Relative.html
Object[] constants = relative.getEnumConstants();
relatives.set(packet, new HashSet<>(Arrays.asList(constants[0], constants[1], constants[2], constants[3], constants[4], constants[5])));
}
return packet; return packet;
} }

View File

@@ -41,7 +41,7 @@ public class MsgCommand extends SWCommand {
} }
public static void msg(PlayerChatter sender, Player target, String[] args) { public static void msg(PlayerChatter sender, Player target, String[] args) {
if(target == null) { if(target == null || target.getCurrentServer().isEmpty()) {
sender.system("MSG_OFFLINE"); sender.system("MSG_OFFLINE");
return; return;
} }