Merge pull request 'Add Schematic Revisions' (#93) from schematic-revisions into main

Reviewed-on: SteamWar/SteamWar#93
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
This commit is contained in:
2025-07-14 09:13:16 +02:00
22 changed files with 229 additions and 97 deletions
@@ -21,6 +21,7 @@ package de.steamwar.bausystem.features.world;
import de.steamwar.bausystem.Permission;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.NodeData;
import de.steamwar.sql.SchematicData;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
@@ -65,7 +66,8 @@ public class ClipboardListener implements Listener {
}
try {
new SchematicData(schematic).saveFromPlayer(e.getPlayer());
NodeData.get(schematic).forEach(NodeData::delete);
SchematicData.saveFromPlayer(e.getPlayer(), schematic);
} catch (Exception ex) {
if (newSchem) {
schematic.delete();
@@ -23,8 +23,13 @@ import de.steamwar.sql.internal.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import javax.swing.plaf.nimbus.State;
import java.io.*;
import java.sql.PreparedStatement;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.zip.GZIPInputStream;
@AllArgsConstructor
@@ -40,26 +45,47 @@ public class NodeData {
private static final Table<NodeData> table = new Table<>(NodeData.class);
private static final Statement updateDatabase = new Statement("INSERT INTO NodeData(NodeId, NodeFormat, SchemData) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE NodeFormat = VALUES(NodeFormat), SchemData = VALUES(SchemData)");
private static final Statement selSchemData = new Statement("SELECT SchemData FROM NodeData WHERE NodeId = ?");
private static final Statement updateDatabase = new Statement("INSERT INTO NodeData(NodeId, NodeFormat, SchemData) VALUES (?, ?, ?)", true);
private static final Statement selSchemData = new Statement("SELECT SchemData FROM NodeData WHERE NodeId = ? AND CreatedAt = ?");
private static final Statement delete = table.delete(Table.PRIMARY);
private static final SelectStatement<NodeData> get = table.select(Table.PRIMARY);
private static final SelectStatement<NodeData> get = new SelectStatement<>(table, "SELECT NodeId, CreatedAt, NodeFormat FROM NodeData WHERE NodeId = ? ORDER BY CreatedAt ");
private static final Statement getRevisions = new Statement("SELECT COUNT(DISTINCT CreatedAt) as CNT FROM NodeData WHERE NodeId = ?");
private static final SelectStatement<NodeData> getLatest = new SelectStatement<>(table, "SELECT NodeId, CreatedAt, NodeFormat FROM NodeData WHERE NodeId = ? ORDER BY CreatedAt LIMIT 1");
public static NodeData get(SchematicNode node) {
if(node.isDir())
throw new IllegalArgumentException("Node is a directory");
return get.select(rs -> {
if(rs.next()) {
return new NodeData(node.getId(), SchematicFormat.values()[rs.getInt("NodeFormat")]);
public static NodeData getLatest(SchematicNode node) {
if (node.isDir()) throw new IllegalArgumentException("Node is dir");
return Optional.ofNullable(getLatest.select(node)).orElseGet(() -> new NodeData(node.getId(), Timestamp.from(Instant.now()), SchematicFormat.MCEDIT));
}
public static List<NodeData> get(SchematicNode node) {
return get.listSelect(node);
}
public static NodeData get(SchematicNode node, int revision) {
return get.listSelect(node).get(revision - 1);
}
public static int getRevisions(SchematicNode node) {
return getRevisions.select(rs -> {
if (rs.next()) {
return rs.getInt("CNT");
} else {
return new NodeData(node.getId(), SchematicFormat.MCEDIT);
return 0;
}
}, node);
}
public static void saveFromStream(SchematicNode node, InputStream blob, SchematicFormat format) {
updateDatabase.update(node.getId(), format, blob);
}
@Field(keys = {Table.PRIMARY})
private final int nodeId;
@Field
private Timestamp createdAt;
@Field
private SchematicFormat nodeFormat;
@@ -84,15 +110,19 @@ public class NodeData {
} catch (IOException e) {
throw new SecurityException("SchemData is wrong", e);
}
}, nodeId);
}, nodeId, createdAt);
} catch (Exception e) {
throw new IOException(e);
}
}
@Deprecated
public void saveFromStream(InputStream blob, SchematicFormat newFormat) {
updateDatabase.update(nodeId, newFormat, blob);
nodeFormat = newFormat;
saveFromStream(SchematicNode.getSchematicNode(nodeId), blob, newFormat);
}
public void delete() {
delete.update(nodeId, createdAt);
}
@AllArgsConstructor
@@ -42,13 +42,13 @@ public class SchematicNode {
TAB_CACHE.clear();
}
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, Config FROM SchematicNode ";
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 update = table.update(Table.PRIMARY, "NodeName", "ParentNode", "NodeItem",
"NodeType", "NodeRank", "ReplaceColor", "AllowReplay");
"NodeType", "NodeRank", "Config");
private static final Statement delete = table.delete(Table.PRIMARY);
private static final SelectStatement<SchematicNode> byId = new SelectStatement<>(table,
@@ -66,13 +66,13 @@ public class SchematicNode {
private static final SelectStatement<SchematicNode> all = 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");
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 "
"SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config 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");
+ "? AND NM.UserId = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config 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 "
"SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, NM.ParentId AS ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config 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 = ?");
+ "? AND NM.UserId = ? AND SchematicNode.NodeName = ? UNION ALL SELECT SchematicNode.NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config 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,
@@ -81,7 +81,7 @@ public class SchematicNode {
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 = ?");
"SELECT NodeId, NodeOwner, ? AS EffectiveOwner, NodeName, ParentNode, LastUpdate, NodeItem, NodeType, NodeRank, Config 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");
@@ -108,10 +108,8 @@ public class SchematicNode {
private SchematicType nodeType;
@Field(def = "0")
private int nodeRank;
@Field(def = "1")
private boolean replaceColor;
@Field(def = "1")
private boolean allowReplay;
@Field
private int config;
private String brCache;
@@ -125,8 +123,7 @@ public class SchematicNode {
String nodeItem,
SchematicType nodeType,
int nodeRank,
boolean replaceColor,
boolean allowReplay) {
int config) {
this.nodeId = nodeId;
this.nodeOwner = nodeOwner;
this.effectiveOwner = effectiveOwner;
@@ -136,8 +133,7 @@ public class SchematicNode {
this.nodeType = nodeType;
this.lastUpdate = lastUpdate;
this.nodeRank = nodeRank;
this.replaceColor = replaceColor;
this.allowReplay = allowReplay;
this.config = config;
}
public static List<SchematicNode> getAll(SteamwarUser user) {
@@ -407,7 +403,7 @@ public class SchematicNode {
public String getFileEnding() {
if (isDir())
throw new SecurityException("Node is Directory");
return NodeData.get(this).getNodeFormat().getFileEnding();
return NodeData.getLatest(this).getNodeFormat().getFileEnding();
}
public int getRank() {
@@ -441,24 +437,45 @@ public class SchematicNode {
}
public boolean replaceColor() {
return replaceColor;
return getConfig(ConfigFlags.REPLACE_COLOR);
}
public void setReplaceColor(boolean replaceColor) {
if (isDir())
throw new SecurityException("Is Directory");
this.replaceColor = replaceColor;
updateDB();
setConfig(ConfigFlags.REPLACE_COLOR, replaceColor);
}
public boolean allowReplay() {
return allowReplay;
return getConfig(ConfigFlags.ALLOW_REPLAY);
}
public void setAllowReplay(boolean allowReplay) {
if (isDir())
throw new SecurityException("Is Directory");
this.allowReplay = allowReplay;
setConfig(ConfigFlags.ALLOW_REPLAY, allowReplay);
}
public boolean isPrepared() {
return getConfig(ConfigFlags.IS_PREPARED);
}
public void setPrepared(boolean prepared) {
if (isDir())
throw new SecurityException("Is Directory");
setConfig(ConfigFlags.IS_PREPARED, prepared);
}
public boolean getConfig(ConfigFlags flag) {
return (config & (1 << flag.ordinal())) == 1;
}
public void setConfig(ConfigFlags flag, boolean value) {
if (value) {
config |= (1 << flag.ordinal());
} else {
config &= ~(1 << flag.ordinal());
}
updateDB();
}
@@ -486,7 +503,7 @@ public class SchematicNode {
private void updateDB() {
this.lastUpdate = Timestamp.from(Instant.now());
update.update(nodeName, parentNode, nodeItem, nodeType, nodeRank, replaceColor, allowReplay, nodeId);
update.update(nodeName, parentNode, nodeItem, nodeType, nodeRank, config, nodeId);
TAB_CACHE.clear();
}
@@ -608,4 +625,10 @@ public class SchematicNode {
TAB_CACHE.computeIfAbsent(user.getId(), integer -> new HashMap<>()).putIfAbsent(cacheKey, list);
return list;
}
public static enum ConfigFlags {
REPLACE_COLOR,
ALLOW_REPLAY,
IS_PREPARED
}
}
@@ -145,6 +145,6 @@ public class WorldeditWrapper14 implements WorldeditWrapper {
throw new SecurityException(e);
}
new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), NodeData.SchematicFormat.SPONGE_V2);
SchematicData.saveFromBytes(schem, outputStream.toByteArray(), NodeData.SchematicFormat.SPONGE_V2);
}
}
@@ -140,6 +140,6 @@ public class WorldeditWrapper8 implements WorldeditWrapper {
throw new SecurityException(e);
}
new SchematicData(schem).saveFromBytes(outputStream.toByteArray(), NodeData.SchematicFormat.MCEDIT);
SchematicData.saveFromBytes(schem, outputStream.toByteArray(), NodeData.SchematicFormat.MCEDIT);
}
}
@@ -41,6 +41,7 @@ import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.fightsystem.utils.*;
import de.steamwar.fightsystem.winconditions.*;
import de.steamwar.message.Message;
import de.steamwar.sql.NodeData;
import de.steamwar.sql.SchematicNode;
import lombok.Getter;
import org.bukkit.Bukkit;
@@ -179,11 +180,8 @@ public class FightSystem extends JavaPlugin {
SchematicNode checkSchematicNode = SchematicNode.getSchematicNode(Config.CheckSchemID);
Fight.getBlueTeam().setSchem(checkSchematicNode);
if (checkSchematicNode.getName().endsWith("-prepared")) {
SchematicNode unpreparedSchematicNode = SchematicNode.getSchematicNode(checkSchematicNode.getOwner(), checkSchematicNode.getName().substring(0, checkSchematicNode.getName().length() - 9), checkSchematicNode.getParent());
if (unpreparedSchematicNode != null) {
Fight.getRedTeam().setSchem(unpreparedSchematicNode);
}
if (checkSchematicNode.isPrepared()) {
Fight.getRedTeam().setSchem(checkSchematicNode, NodeData.getRevisions(checkSchematicNode) - 1);
}
new TechareaCommand();
@@ -83,9 +83,13 @@ public class FightSchematic extends StateDependent {
}
public void setSchematic(SchematicNode schem) {
setSchematic(schem, -1);
}
public void setSchematic(SchematicNode schem, int revision) {
schematic = schem.getId();
try {
clipboard = new SchematicData(schem).load();
clipboard = new SchematicData(schem, revision).load();
if(schem.replaceColor())
replaceTeamColor(clipboard);
@@ -412,6 +412,10 @@ public class FightTeam {
}
public void setSchem(SchematicNode schematic){
setSchem(schematic, -1);
}
public void setSchem(SchematicNode schematic, int revision){
this.schematic.setSchematic(schematic);
broadcast("SCHEMATIC_CHOSEN", Config.GameName, schematic.getName());
}
@@ -83,13 +83,8 @@ public class PrepareSchem implements Listener {
return;
}
if(schemExists(schem))
return;
SchematicNode old = schem;
schem = SchematicNode.createSchematicNode(schem.getOwner(), preparedName(schem), schem.getParent(), Config.SchematicType.checkType().toDB(), schem.getItem());
schem.setReplaceColor(old.replaceColor());
schem.setAllowReplay(old.allowReplay());
schem.setSchemtype(Config.SchematicType.checkType());
schem.setPrepared(true);
try{
WorldeditWrapper.impl.saveSchem(schem, region, minY);
@@ -119,20 +114,5 @@ public class PrepareSchem implements Listener {
FightState.setFightState(FightState.PRE_SCHEM_SETUP);
FightState.setFightState(FightState.POST_SCHEM_SETUP);
}
schemExists(SchematicNode.getSchematicNode(Config.PrepareSchemID));
}
private boolean schemExists(SchematicNode schem) {
if(SchematicNode.getSchematicNode(schem.getOwner(), preparedName(schem), schem.getParent()) != null) {
FightSystem.getMessage().broadcast("PREPARE_SCHEM_EXISTS");
Bukkit.shutdown();
return true;
}
return false;
}
private String preparedName(SchematicNode schem) {
return schem.getName() + "-prepared";
}
}
@@ -283,7 +283,7 @@ public interface Recorder {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try{
copy(NodeData.get(SchematicNode.getSchematicNode(schemId)).schemData(), buffer);
copy(NodeData.getLatest(SchematicNode.getSchematicNode(schemId)).schemData(), buffer);
}catch (EOFException e) {
Bukkit.getLogger().log(Level.INFO, "EOFException ignored");
} catch (IOException e) {
@@ -53,7 +53,7 @@ public class ClipboardListener implements Listener {
}
try {
new SchematicData(schematic).saveFromPlayer(e.getPlayer());
SchematicData.saveFromPlayer(e.getPlayer(), schematic);
} catch (Exception ex) {
if (newSchem) {
schematic.delete();
@@ -26,6 +26,7 @@ CLICK_DRAG_ITEM=§7Click or drag item here
CURRENT=§7Current: {0}
CONFIRM=§aConfirm
CANCEL=§cCancel
BLANK={0}
UTIL_NAME_REQUIRED=§cFolder name required
UTIL_NAME_TOO_LONG=§cSchematic name too long
@@ -49,6 +50,7 @@ UTIL_LIST_NEXT=Page ({0}/{1}) »»
UTIL_LIST_NEXT_HOVER=§eNext page
UTIL_INFO_SCHEM=§7Schematic: §e{0}
UTIL_INFO_NAME=§7Name: §e{0}
UTIL_INFO_REVISIONS=§7Revisions: §e{0}
UTIL_INFO_OWNER=§7Owner: §e{0}
UTIL_INFO_PARENT=§7Directory: §e{0}
UTIL_INFO_UPDATED=§7Last update: §e{0}
@@ -70,6 +72,7 @@ UTIL_INFO_ACTION_TYPE_HOVER=§eChange schematic type
UTIL_INFO_ACTION_ADD_HOVER=§eAdd member
UTIL_INFO_ACTION_REMOVE_HOVER=§eRemove {0}
UTIL_INFO_ACTION_MOVE_HOVER=§eMove schematic
UTIL_INFO_ACTION_REVISIONS_HOVER=§eList revisions
UTIL_INFO_ACTION_RENAME_HOVER=§eRename schematic
UTIL_INFO_ACTION_DELETE=(Delete)
UTIL_INFO_ACTION_DELETE_HOVER=§eDelete schematic
@@ -79,6 +82,7 @@ UTIL_LOAD_DIR=§cYou cannot load folders
UTIL_LOAD_DONE=§7Schematic §e{0} loaded
UTIL_LOAD_NO_DATA=§cNo data could be found in the Schematic
UTIL_LOAD_ERROR=§cThe schematic could not be loaded
UTIL_LOAD_ILLEGAL_REVISION=§cThe schematic doesn't have {0} revisions
UTIL_DOWNLOAD_PUNISHED=§cYou are not allowed to download schematics: §f§l{0}
UTIL_DOWNLOAD_NOT_OWN=§cYou may download only your own schematics
UTIL_DOWNLOAD_LINK=Your download link:
@@ -224,6 +228,9 @@ GUI_DELETE_MEMBER_TITLE=Remove {0}
GUI_DELETE_MEMBER_DONE=Access to Schematic §e{0} §7removed
GUI_DELETE_MEMBERS_TITLE=Remove members
GUI_CHANGE_ITEM=Change item
GUI_LOAD_LATEST=§eLeft §7Click → §eLoad latest
GUI_LOAD_REVISION=§eRight §7Click → §eList Revisions
GUI_LOAD_REVISION_TITLE=Select Revision
AUTO_CHECK_RESULT_NOT_LOAD=The schematic could not be loaded
AUTO_CHECK_RESULT_TOO_WIDE=The schematic is too wide ({0} > {1})
@@ -263,4 +270,8 @@ AUTO_CHECKER_RESULT_RECORD=§7Record: §c[{0}, {1}, {2}]
AUTO_CHECKER_RESULT_TOO_MANY_DISPENSER_ITEMS=§7Dispenser: §c[{0}, {1}, {2}]§7, §c{3} §7items, Max: §e{4}
AUTO_CHECKER_RESULT_FORBIDDEN_ITEM_NBT=§7Forbidden Item NBT: [{0}, {1}, {2}] -> §c{3}
AUTO_CHECKER_RESULT_TELEPORT_HERE=§7Teleport to block
AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cThe deadline has expired: {0}
AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cThe deadline has expired: {0}
REVISIONS_TITLE=§7Revisions:
REVISIONS_REVISION_NUMBER=§7#{0}: §e{1}
REVISIONS_EMPTY=§cNo Revisions
@@ -90,6 +90,9 @@ UTIL_SUBMIT_DIRECT=§eDirekt einsenden
UTIL_SUBMIT_DIRECT_DONE=§aDie Schematic wird zeitnah überprüft
UTIL_SUBMIT_EXTEND=§eSchematic ausfahren
UTIL_SUBMIT_EXTEND_DONE=§aDer Vorbereitungsserver wird gestartet
UTIL_INFO_ACTION_REVISIONS_HOVER=§eVersionen anzeigen
UTIL_LOAD_ILLEGAL_REVISION=§cDie schematic hat nicht {0} Versionen
UTIL_INFO_REVISIONS=§7Versionen: §e{0}
COMMAND_INVALID_NODE=§cDie Schematic konnte nicht gefunden werden
COMMAND_NOT_OWN=§cDas darfst du nur bei deinen eigenen Schematics machen
@@ -204,6 +207,9 @@ GUI_DELETE_MEMBER_TITLE={0} entfernen
GUI_DELETE_MEMBER_DONE=Zugriff zu Schematic §e{0} §7entfernt
GUI_DELETE_MEMBERS_TITLE=Mitglieder entfernen
GUI_CHANGE_ITEM=Item ändern
GUI_LOAD_LATEST=§eLinks §7Klick → §eLetzte Laden
GUI_LOAD_REVISION=§eRechts §7Klick → §eVersionen anzeigen
GUI_LOAD_REVISION_TITLE=Version Laden
AUTO_CHECK_RESULT_NOT_LOAD=Die Schematic konnte nicht geladen werden
AUTO_CHECK_RESULT_TOO_WIDE=Die Schematic ist zu breit ({0} > {1})
@@ -242,4 +248,7 @@ AUTO_CHECKER_RESULT_RECORD=§7Schallplatte: §c[{0}, {1}, {2}]
AUTO_CHECKER_RESULT_TOO_MANY_DISPENSER_ITEMS=§7Dispenser: §c[{0}, {1}, {2}]§7, §c{3} §7gegenstände, Max: §e{4}
AUTO_CHECKER_RESULT_FORBIDDEN_ITEM_NBT=§7Verbotene NBT-Daten: [{0}, {1}, {2}] -> §c{3}
AUTO_CHECKER_RESULT_TELEPORT_HERE=§7Zum block teleportieren
AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cDer einsendeschluss ist bereits vorbei: {0}
AUTO_CHECKER_RESULT_AFTER_DEADLINE=§cDer einsendeschluss ist bereits vorbei: {0}
REVISIONS_TITLE=§7Versionen:
REVISIONS_EMPTY=§cKeine Versionen
@@ -43,7 +43,7 @@ public class DownloadCommand extends SWCommand {
}
try {
new SchematicData(copyNode).saveFromPlayer(player);
SchematicData.saveFromPlayer(player, copyNode);
} catch (IOException e) {
SchematicSystem.MESSAGE.send("DOWNLOAD_ERROR", player);
if (newSchem) {
@@ -95,9 +95,28 @@ public class GUI {
SteamwarUser user = getUser(player);
SWInventory inv = new SWInventory(player, 9 * 2, node.generateBreadcrumbs());
if(!node.isDir()) {
inv.setItem(0, SWItem.getMaterial("WOOD_AXE"), SchematicSystem.MESSAGE.parse("GUI_INFO_LOAD", player), click -> {
player.closeInventory();
SchematicCommandUtils.loadSchem(player, node);
inv.setItem(0, SWItem.getMaterial("WOOD_AXE"), SchematicSystem.MESSAGE.parse("GUI_INFO_LOAD", player), Arrays.asList(
SchematicSystem.MESSAGE.parse("GUI_LOAD_LATEST", player),
SchematicSystem.MESSAGE.parse("GUI_LOAD_REVISION", player)
), false, click -> {
if (click.isLeftClick()) {
player.closeInventory();
SchematicCommandUtils.loadSchem(player, node, -1);
} else if (click.isRightClick()) {
List<SWListInv.SWListEntry<Integer>> entries = new ArrayList<>();
List<NodeData> datas = NodeData.get(node);
for (int i = 0; i < datas.size(); i++) {
entries.add(new SWListInv.SWListEntry<>(new SWItem(SWItem.getMaterial(node.getItem()), "§e" + SchematicSystem.MESSAGE.parse("BLANK", player, datas.get(i).getCreatedAt())), i));
}
SWListInv<Integer> listInv = new SWListInv<>(player, SchematicSystem.MESSAGE.parse("GUI_LOAD_REVISION_TITLE", player, node.generateBreadcrumbs()), entries, (clickType, revision) -> {
if(revision == null) return;
player.closeInventory();
SchematicCommandUtils.loadSchem(player, node, revision);
});
listInv.setCallback(-999, click2 -> player.closeInventory());
listInv.open();
}
});
}
@@ -223,6 +223,11 @@ public class SchematicCommandUtils {
} else {
SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_PARENT", player, node.getParent() == null ? "/" : node.getParentNode().generateBreadcrumbs());
}
player.spigot().sendMessage(
new ComponentBuilder(SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_REVISIONS", false, player, NodeData.getRevisions(node)))
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[] {SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_REVISIONS_HOVER", false, player)}))
.event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem revisions " + node.generateBreadcrumbs()))
.create());
SchematicSystem.MESSAGE.sendPrefixless("UTIL_INFO_UPDATED", player, node.getLastUpdate());
if (!node.isDir()) {
if(node.getOwner() == user.getId()) {
@@ -357,7 +362,7 @@ public class SchematicCommandUtils {
PUBLIC_TOGGLED.remove(player);
}
public static void loadSchem(Player player, SchematicNode node) {
public static void loadSchem(Player player, SchematicNode node, int revision) {
SteamwarUser user = getUser(player);
if(BauServerInfo.isBauServer() && BauServerInfo.getOwnerId() != user.getId() &&
(Punishment.isPunished(user, Punishment.PunishmentType.NoSchemSharing, punishment ->
@@ -372,11 +377,13 @@ public class SchematicCommandUtils {
}
try {
new SchematicData(node).loadToPlayer(player);
new SchematicData(node, revision).loadToPlayer(player);
SchematicSystem.MESSAGE.send("UTIL_LOAD_DONE", player, node.getName());
Bukkit.getLogger().log(Level.INFO, "{0} has loaded Schematic {1} {2}", new Object[]{player.getName(), node.getId(), node.getName()});
} catch (NoClipboardException e) {
SchematicSystem.MESSAGE.send("UTIL_LOAD_NO_DATA", player);
} catch (IllegalArgumentException e) {
SchematicSystem.MESSAGE.send("UTIL_LOAD_ILLEGAL_REVISION", player, revision);
} catch (Exception e) {
SchematicSystem.MESSAGE.send("UTIL_LOAD_ERROR", player);
Bukkit.getLogger().log(Level.INFO, e.getMessage(), e);
@@ -421,6 +428,8 @@ public class SchematicCommandUtils {
return;
}
node.setPrepared(false);
if (type.writeable()) {
node.setSchemtype(type);
SchematicSystem.MESSAGE.send("UTIL_TYPE_DONE", player);
@@ -49,11 +49,11 @@ public class SavePart extends SWCommand {
SchematicSelector selector = new SchematicSelector(player, SchematicSelector.selectSchematicNode(), schematicNode -> {
if(schematicNode == null || schematicNode.isDir()) {
SWAnvilInv anvilInv = new SWAnvilInv(player, SchematicSystem.MESSAGE.parse("COMMAND_ENTER_NAME", player));
anvilInv.setCallback(s -> saveSchem(player, schematicNode==null?s:(schematicNode.generateBreadcrumbs() + s), true));
anvilInv.setCallback(s -> saveSchem(player, schematicNode==null?s:(schematicNode.generateBreadcrumbs() + s)));
anvilInv.setItem(Material.CAULDRON);
anvilInv.open();
} else {
saveSchem(player, schematicNode.generateBreadcrumbs(), true);
saveSchem(player, schematicNode.generateBreadcrumbs());
}
});
selector.setSingleDirOpen(false);
@@ -62,7 +62,7 @@ public class SavePart extends SWCommand {
@Register("save")
@Register("s")
public void saveSchem(Player player, @AbstractSWCommand.Mapper("stringMapper") String name, @AbstractSWCommand.StaticValue(value = {"", "-f"}, allowISE=true) @AbstractSWCommand.OptionalValue("") boolean overwrite) {
public void saveSchem(Player player, @AbstractSWCommand.Mapper("stringMapper") String name) {
SteamwarUser user = getUser(player);
if(BauServerInfo.isBauServer() && BauServerInfo.getOwnerId() != user.getId() &&
(Punishment.isPunished(user, Punishment.PunishmentType.NoSchemReceiving, punishment ->
@@ -88,9 +88,6 @@ public class SavePart extends SWCommand {
} else if (!node.getSchemtype().writeable() || node.getOwner() != user.getId()) {
SchematicSystem.MESSAGE.send("COMMAND_SAVE_NO_OVERWRITE", player);
return;
} else if(!overwrite) {
SchematicSystem.MESSAGE.send("COMMAND_SAVE_OVERWRITE_CONFIRM", player, SchematicSystem.MESSAGE.parse("COMMAND_SAVE_OVERWRITE_CONFIRM_HOVER", player), new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem s " + name + " -f"), node.generateBreadcrumbs());
return;
}
}
@@ -101,7 +98,7 @@ public class SavePart extends SWCommand {
}
try {
new SchematicData(node).saveFromPlayer(player);
SchematicData.saveFromPlayer(player, node);
} catch (NoClipboardException e) {
SchematicSystem.MESSAGE.send("COMMAND_SAVE_CLIPBOARD_EMPTY", player);
if (newSchem)
@@ -21,13 +21,23 @@ package de.steamwar.schematicsystem.commands.schematiccommand.parts;
import de.steamwar.command.AbstractSWCommand;
import de.steamwar.command.SWCommand;
import de.steamwar.schematicsystem.SchematicSystem;
import de.steamwar.schematicsystem.commands.schematiccommand.GUI;
import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils;
import de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommand;
import de.steamwar.sql.NodeData;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.entity.Player;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.List;
import static de.steamwar.schematicsystem.commands.schematiccommand.SchematicCommandUtils.*;
@AbstractSWCommand.PartOf(SchematicCommand.class)
@@ -69,6 +79,25 @@ public class ViewPart extends SWCommand {
printSchemInfo(player, node);
}
@Register("revisions")
public void revisions(Player player, @Validator("isSchemValidator") SchematicNode node) {
List<NodeData> revisions = NodeData.get(node);
if(revisions.isEmpty()) {
SchematicSystem.MESSAGE.send("REVISIONS_EMPTY", player);
return;
}
SchematicSystem.MESSAGE.send("REVISIONS_TITLE", player);
for (int j = Math.max(0, revisions.size() - 10); j < revisions.size(); j++) {
player.spigot().sendMessage(
new ComponentBuilder(SchematicSystem.MESSAGE.parseToComponent("REVISIONS_REVISION_NUMBER", false, player, j + 1, revisions.get(j).getCreatedAt()))
.event(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem load " + (node.getOwner() == 0 ? "public " : "") + node.generateBreadcrumbs() + " " + (j + 1)))
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponent[]{SchematicSystem.MESSAGE.parseToComponent("UTIL_INFO_ACTION_LOAD_HOVER", false, player)}))
.create()
);
}
}
@Register(value = "page", noTabComplete = true)
public void pageCommand(Player player, int page) {
cachedSchemList(player, page);
@@ -76,14 +105,14 @@ public class ViewPart extends SWCommand {
@Register({"l", "public"})
@Register({"load", "public"})
public void loadSchemPublic(Player player, @Validator("isSchemValidator") @Mapper("publicMapper") SchematicNode node) {
loadSchem(player, node);
public void loadSchemPublic(Player player, @Validator("isSchemValidator") @Mapper("publicMapper") SchematicNode node, @OptionalValue("-1") int revision) {
loadSchem(player, node, revision);
}
@Register("l")
@Register("load")
public void loadSchem(Player player, @Validator("isSchemValidator") SchematicNode node) {
SchematicCommandUtils.loadSchem(player, node);
public void loadSchem(Player player, @Validator("isSchemValidator") SchematicNode node, @OptionalValue("-1") int revision) {
SchematicCommandUtils.loadSchem(player, node, revision);
}
@Register("gui")
@@ -47,11 +47,25 @@ public class SchematicData {
private final NodeData data;
public SchematicData(SchematicNode node) {
this.data = NodeData.get(node);
this.data = NodeData.getLatest(node);
if(node.isDir())
throw new SecurityException("Node is Directory");
}
public SchematicData(SchematicNode node, int revision) {
if(node.isDir())
throw new SecurityException("Node is Directory");
if (revision < 1) {
this.data = NodeData.getLatest(node);
} else {
if (NodeData.getRevisions(node) < revision) {
throw new IllegalArgumentException("Revision " + revision + " does not exist");
}
this.data = NodeData.get(node, revision);
}
}
public Clipboard load() throws IOException, NoClipboardException {
return WorldEditWrapper.impl.getClipboard(data.schemData(), data.getNodeFormat());
}
@@ -60,12 +74,12 @@ public class SchematicData {
WorldEditWrapper.impl.setPlayerClipboard(player, data.schemData(), data.getNodeFormat());
}
public void saveFromPlayer(Player player) throws IOException, NoClipboardException {
data.saveFromStream(WorldEditWrapper.impl.getPlayerClipboard(player), WorldEditWrapper.impl.getNativeFormat());
public static void saveFromPlayer(Player player, SchematicNode node) throws IOException, NoClipboardException {
NodeData.saveFromStream(node, WorldEditWrapper.impl.getPlayerClipboard(player), WorldEditWrapper.impl.getNativeFormat());
}
@Deprecated
public void saveFromBytes(byte[] bytes, NodeData.SchematicFormat newFormat) {
data.saveFromStream(new ByteArrayInputStream(bytes), newFormat);
public static void saveFromBytes(SchematicNode node, byte[] bytes, NodeData.SchematicFormat newFormat) {
NodeData.saveFromStream(node, new ByteArrayInputStream(bytes), newFormat);
}
}
@@ -309,8 +309,12 @@ public class CheckCommand extends SWCommand {
private void concludeCheckSession(String reason, SchematicType type, BooleanSupplier sendMessageIsOnline) {
if(SchematicNode.getSchematicNode(schematic.getId()) != null) {
CheckedSchematic.create(schematic, checker.user().getId(), startTime, Timestamp.from(Instant.now()), reason, sendMessageIsOnline.getAsBoolean());
if(type != null)
if(type != null) {
schematic.setSchemtype(type);
if (type == SchematicType.Normal) {
schematic.setPrepared(false);
}
}
}
remove();
@@ -94,7 +94,7 @@ public class DiscordSchemUpload extends ListenerAdapter {
version = NodeData.SchematicFormat.MCEDIT;
}
NodeData.get(node).saveFromStream(new ByteArrayInputStream(bytes), version);
NodeData.saveFromStream(node, new ByteArrayInputStream(bytes), version);
sender.system("DC_SCHEMUPLOAD_SUCCESS", name);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
@@ -89,7 +89,7 @@ fun Route.configureSchematic() {
return@get
}
val data = NodeData.get(node) ?: run {
val data = NodeData.getLatest(node) ?: run {
call.respond(HttpStatusCode.InternalServerError)
return@get
}
@@ -166,8 +166,7 @@ fun Route.configureSchematic() {
} catch (_: Exception) {}
}
val data = NodeData(node.id, version)
data.saveFromStream(content.inputStream(), version)
NodeData.saveFromStream(node, content.inputStream(), version)
call.respond(ResponseSchematic(node))
} catch (e: Exception) {