diff --git a/src/de/steamwar/bungeecore/commands/ReplayCommand.java b/src/de/steamwar/bungeecore/commands/ReplayCommand.java
index a999d72..9ca94b4 100644
--- a/src/de/steamwar/bungeecore/commands/ReplayCommand.java
+++ b/src/de/steamwar/bungeecore/commands/ReplayCommand.java
@@ -1,3 +1,22 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
package de.steamwar.bungeecore.commands;
import de.steamwar.bungeecore.ArenaMode;
diff --git a/src/de/steamwar/bungeecore/commands/TutorialCommand.java b/src/de/steamwar/bungeecore/commands/TutorialCommand.java
new file mode 100644
index 0000000..253d889
--- /dev/null
+++ b/src/de/steamwar/bungeecore/commands/TutorialCommand.java
@@ -0,0 +1,67 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.bungeecore.commands;
+
+import de.steamwar.bungeecore.Message;
+import de.steamwar.bungeecore.inventory.SWItem;
+import de.steamwar.bungeecore.inventory.SWListInv;
+import de.steamwar.bungeecore.inventory.SWStreamInv;
+import de.steamwar.bungeecore.sql.Tutorial;
+import net.md_5.bungee.api.CommandSender;
+import net.md_5.bungee.api.connection.ProxiedPlayer;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class TutorialCommand extends BasicCommand {
+
+ public TutorialCommand() {
+ super("tutorial", null);
+ }
+
+ @Override
+ public void execute(CommandSender sender, String[] args) {
+ if(!(sender instanceof ProxiedPlayer))
+ return;
+ ProxiedPlayer player = (ProxiedPlayer) sender;
+
+ //TODO: Tutorial rating
+ //TODO: Tutorial creation
+
+ new SWStreamInv<>(player, Message.parse("TUTORIAL_TITLE", player), (click, tutorial) -> {
+ //TODO: Tutorial start
+ }, page -> Tutorial.getPage(page, 45).stream().map(tutorial -> new SWListInv.SWListEntry<>(getTutorialItem(player, tutorial), tutorial)).collect(Collectors.toList())).open();
+ }
+
+ private SWItem getTutorialItem(ProxiedPlayer player, Tutorial tutorial) {
+ SWItem item = new SWItem(tutorial.item(), Message.parse("TUTORIAL_NAME", player, tutorial.name()));
+
+ List lore = new ArrayList<>();
+ lore.add(Message.parse("TUTORIAL_BY", player, tutorial.creator().getUserName()));
+ lore.add("");
+ lore.add(Message.parse("TUTORIAL_BASED_ON", player));
+ lore.add(Message.parse("TUTORIAL_NAME", player, tutorial.parent().name()));
+ lore.add(Message.parse("TUTORIAL_BY", player, tutorial.parent().creator().getUserName()));
+ item.setLore(lore);
+
+ return item;
+ }
+}
diff --git a/src/de/steamwar/bungeecore/sql/Tutorial.java b/src/de/steamwar/bungeecore/sql/Tutorial.java
new file mode 100644
index 0000000..f9b49f1
--- /dev/null
+++ b/src/de/steamwar/bungeecore/sql/Tutorial.java
@@ -0,0 +1,98 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2022 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.bungeecore.sql;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class Tutorial {
+
+ private static final Statement by_popularity = new Statement("SELECT t.TutorialID, t.Creator, t.Name, t.Item, AVG(r.Stars) AS Stars, p.TutorialID AS ParentID, p.Creator AS ParentCreator, p.Name AS ParentName FROM Tutorial t INNER JOIN Tutorial p ON t.Parent = p.TutorialID LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID GROUP BY t.TutorialID ORDER BY SUM(r.Stars) DESC LIMIT ?, ?");
+ private static final Statement rate = new Statement("INSERT INTO TutorialRating (TutorialID, UserID, Stars) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Stars = VALUES(Stars)");
+ private static final Statement create = new Statement("INSERT INTO Tutorial (Creator, Name, Item, Parent) VALUES (?, ?, ?, ?)");
+
+ public static List getPage(int page, int elementsPerPage) {
+ List tutorials = by_popularity.select(rs -> {
+ List t = new ArrayList<>();
+ while(rs.next())
+ t.add(new Tutorial(rs));
+ return t;
+ }, page * elementsPerPage, elementsPerPage);
+
+ SteamwarUser.batchCache(tutorials.stream().flatMap(tutorial -> Stream.of(tutorial.creator, tutorial.parent.creator)).collect(Collectors.toSet()));
+ return tutorials;
+ }
+
+ public static void create(SteamwarUser creator, String name, Tutorial parent) {
+ create.update(creator.getId(), name, parent.id);
+ }
+
+ private final int id;
+ private final int creator;
+ private final String name;
+ private final String item;
+ private Tutorial parent;
+ private final int stars;
+
+ public Tutorial(ResultSet rs) throws SQLException {
+ this(rs.getInt("TutorialID"), rs.getInt("Creator"), rs.getString("Name"), rs.getString("Item"), rs.getInt("Stars"));
+ parent = new Tutorial(rs.getInt("ParentID"), rs.getInt("ParentCreator"), rs.getString("ParentName"), "", 0);
+ }
+
+ private Tutorial(int id, int creator, String name, String item, int stars) {
+ this.id = id;
+ this.creator = creator;
+ this.name = name;
+ this.item = item;
+ this.stars = stars;
+ }
+
+ public SteamwarUser creator() {
+ return SteamwarUser.get(creator);
+ }
+
+ public Tutorial parent() {
+ return parent;
+ }
+
+ public int stars() {
+ return stars;
+ }
+
+ public int id() {
+ return id;
+ }
+
+ public String name() {
+ return name;
+ }
+
+ public String item() {
+ return item;
+ }
+
+ public void rate(SteamwarUser user, int rating) {
+ rate.update(id, user.getId(), rating);
+ }
+}
diff --git a/src/de/steamwar/messages/BungeeCore.properties b/src/de/steamwar/messages/BungeeCore.properties
index e711650..60b69c3 100644
--- a/src/de/steamwar/messages/BungeeCore.properties
+++ b/src/de/steamwar/messages/BungeeCore.properties
@@ -333,6 +333,12 @@ REPLAY_LOSER=§e{0} §7+§e{1}
REPLAY_TIME=§7{0}
REPLAY_SERVER=§7{0}
+#TutorialCommand
+TUTORIAL_TITLE=Tutorials
+TUTORIAL_NAME=§e{0}
+TUTORIAL_BY=§8von §7{0}
+TUTORIAL_BASED_ON=§8Basierend auf
+
#ServerTeamchatCommand
STC_USAGE=§8/§7stc §8[§eNachricht an das Team§8]
STC_FORMAT=§8STC §e{0}» §r{1}