Minecraft MapReset erstellen

Dieses Thema im Forum "Tutorials" wurde erstellt von McWizzardDev, 17. Januar 2016.

  1. McWizzardDev
    Offline

    McWizzardDev

    Registriert seit:
    7. Oktober 2015
    Beiträge:
    58
    Guten Tag,

    ich habe mich nun mit dem Thema MapReset beschäftigt und habe nun eine Klasse für euch geschrieben, wo ihr eure Welt ganz Simple Reseten könnt

    # Tutorial unter der Klasse ;)
    # Bitte lasst doch ein Abbo bei dem YTChannel https://www.youtube.com/channel/UCdnQodr6VDSv8i1X_Urxs5w da
    # Bitte kommt nicht mit Sachen, wie das kann man auch Kürzer schreiben, es gibt 1000sende Möglichkeiten ;D

    Code (Text):
    1. public class MapReset
    2. {
    3.   private static File cfgFile = new File("plugins/WorldReset", "config.yml");
    4.   private static FileConfiguration cfg = YamlConfiguration.loadConfiguration(cfgFile);
    5.  
    6.   public static void kickPlayers(World world, String kickMessage)
    7.   {
    8.     if ((Bukkit.getOnlinePlayers() != null) && (Bukkit.getOnlinePlayers().size() != 0))
    9.       for (Player p : Bukkit.getOnlinePlayers())
    10.         if (p.getWorld().getName().equals(world.getName())) {
    11.           p.saveData();
    12.           p.kickPlayer(kickMessage);
    13.         }
    14.   }
    15.  
    16.   public static void kickPlayers(String worldName, String kickMessage)
    17.   {
    18.     World world = Bukkit.getWorld(worldName);
    19.     kickPlayers(world, kickMessage);
    20.   }
    21.  
    22.   public static Boolean worldSaved(String worldName) {
    23.     File worldFolder = new File("plugins/WorldReset/WorldSaves/" + worldName);
    24.     if (worldFolder.exists()) {
    25.       return Boolean.valueOf(true);
    26.     }
    27.     return Boolean.valueOf(false);
    28.   }
    29.  
    30.   public static void deleteWorldSave(String worldName) {
    31.     File worldFolder = new File("plugins/WorldReset/WorldSaves/" + worldName);
    32.     if (worldFolder.exists())
    33.       deleteFolder(worldFolder);
    34.   }
    35.  
    36.   public static void saveWorld(World world)
    37.   {
    38.     if (world != null) {
    39.       world.save();
    40.       File worldFolder = new File("plugins/WorldReset/WorldSaves/" + world.getName());
    41.       File srcWorldFolder = new File(world.getName());
    42.       if (worldFolder.exists()) {
    43.         deleteFolder(worldFolder);
    44.       }
    45.       copyWorldFolder(srcWorldFolder, worldFolder);
    46.       FileConfiguration settings = YamlConfiguration.loadConfiguration(new File(worldFolder, "WorldSettings.yml"));
    47.       settings.set("World.Seed", Long.valueOf(world.getSeed()));
    48.       settings.set("World.Environment", world.getEnvironment().toString());
    49.       settings.set("World.Structures", Boolean.valueOf(world.canGenerateStructures()));
    50.       settings.set("World.Generator", getChunkGeneratorAsName(world));
    51.       settings.set("World.Type", world.getWorldType().toString());
    52.       try {
    53.         settings.save(new File(worldFolder, "WorldSettings.yml"));
    54.       } catch (Exception e) {
    55.         e.printStackTrace();
    56.         System.out.println("[WorldReset] Couldn't create a WorldSettings file!");
    57.       }
    58.     }
    59.   }
    60.  
    61.   public static void saveWorld(String worldName) {
    62.     World world = Bukkit.getWorld(worldName);
    63.     saveWorld(world);
    64.   }
    65.  
    66.   public static void resetWorld(String worldName) {
    67.     World world = Bukkit.getWorld(worldName);
    68.     resetWorld(world);
    69.   }
    70.  
    71.   @SuppressWarnings("unused")
    72. public static void resetWorld(World world) {
    73.     File srcWorldFolder = new File("plugins/WorldReset/WorldSaves/" + world.getName());
    74.     File worldFolder = new File(world.getName());
    75.     if ((srcWorldFolder.exists()) &&
    76.       (worldFolder.exists()))
    77.       if (world.getName().equals("world")) {
    78.         System.out.println("[WorldReset] The world 'world' is the main world and can't be resetted!");
    79.       } else {
    80.         String worldName = world.getName();
    81.         Boolean saveSett = Boolean.valueOf(false);
    82.         kickPlayers(world, ChatColor.translateAlternateColorCodes('&', cfg.getString("Config.playerKickMessage")));
    83.         Long seed = null;
    84.         World.Environment environment = null;
    85.         Boolean structures = null;
    86.         String generator = null;
    87.         WorldType worldType = null;
    88.         File settingsFile = new File(srcWorldFolder, "WorldSettings.yml");
    89.         FileConfiguration settings = YamlConfiguration.loadConfiguration(settingsFile);
    90.         if ((settingsFile.exists()) && (settings.get("World.Seed") != null)) {
    91.           seed = Long.valueOf(settings.getLong("World.Seed"));
    92.           environment = World.Environment.valueOf(settings.getString("World.Environment"));
    93.           structures = Boolean.valueOf(settings.getBoolean("World.Structures"));
    94.           generator = settings.getString("World.Generator");
    95.           worldType = WorldType.valueOf(settings.getString("World.Type"));
    96.         } else {
    97.           seed = Long.valueOf(world.getSeed());
    98.           environment = world.getEnvironment();
    99.           structures = Boolean.valueOf(world.canGenerateStructures());
    100.           generator = getChunkGeneratorAsName(world);
    101.           worldType = world.getWorldType();
    102.           settings.set("World.Seed", Long.valueOf(world.getSeed()));
    103.           settings.set("World.Environment", world.getEnvironment().toString());
    104.           settings.set("World.Structures", Boolean.valueOf(world.canGenerateStructures()));
    105.           settings.set("World.Generator", getChunkGeneratorAsName(world));
    106.           settings.set("World.Type", world.getWorldType().toString());
    107.           saveSett = Boolean.valueOf(true);
    108.         }
    109.  
    110.         Bukkit.getServer().unloadWorld(world, true);
    111.  
    112.         WorldCreator w = new WorldCreator(world.getName());
    113.         deleteFolder(worldFolder);
    114.         copyWorldFolder(srcWorldFolder, worldFolder);
    115.         if (saveSett.booleanValue()) {
    116.           try {
    117.             settings.save(settingsFile);
    118.           } catch (Exception e) {
    119.             e.printStackTrace();
    120.             System.out.println("[WorldReset] Couldn't save the WorldSettings file!");
    121.           }
    122.         }
    123.         w.seed(seed.longValue());
    124.         w.environment(environment);
    125.         w.generateStructures(structures.booleanValue());
    126.         w.generator(generator);
    127.         w.type(worldType);
    128.       }
    129.   }
    130.  
    131.   private static void deleteFolder(File folder)
    132.   {
    133.     File[] files = folder.listFiles();
    134.     if (files != null) {
    135.       for (File file : files) {
    136.         if (file.isDirectory())
    137.           deleteFolder(file);
    138.         else {
    139.           file.delete();
    140.         }
    141.       }
    142.     }
    143.     folder.delete();
    144.   }
    145.  
    146.   private static String getChunkGeneratorAsName(World world) {
    147.     String generator = null;
    148.     for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
    149.       WorldCreator wc = new WorldCreator("ThisMapWillNeverBeCreated");
    150.       wc.generator(plugin.getName());
    151.       if ((wc.generator() != null) && (world.getGenerator() != null) && (wc.generator().getClass().getName().equals(world.getGenerator().getClass().getName()))) {
    152.         generator = plugin.getName();
    153.       }
    154.     }
    155.     return generator;
    156.   }
    157.  
    158. private static void copyWorldFolder(File from, File to) {
    159.     try {
    160.       ArrayList<String> ignore = new ArrayList<>();
    161.       ignore.add("session.dat");
    162.       ignore.add("session.lock");
    163.       ignore.add("WorldSettings.yml");
    164.       if (!ignore.contains(from.getName()))
    165.         if (from.isDirectory()) {
    166.           if (!to.exists()) {
    167.             to.mkdirs();
    168.           }
    169.           String[] files = from.list();
    170.           for (String file : files) {
    171.             File srcFile = new File(from, file);
    172.             File destFile = new File(to, file);
    173.             copyWorldFolder(srcFile, destFile);
    174.           }
    175.         } else {
    176.           Files.copy(from, to);
    177.         }
    178.     }
    179.     catch (Exception e) {
    180.       e.printStackTrace();
    181.     }
    182.   }
    183. }

    Anleitung:

    Mit dieser API (Klasse) kannst du eine Welt reseten (Bitte Multiverse Core implementieren {Das ist da, wo auch die spigot.yml eingefügt ist})

    Als erstes musst du die Map saven, dies machst du am besten am Anfang des Spieles (oder Server start)

    z.B

    @Override
    public void onEnable() {
    MapReset.saveWorld("test"); //"test" ist der WeltenName (die Map "world" darf nicht resetet werden)
    }

    Um sie zu reseten, z.B am Ende des Spieles (oder ServerStopp) folgendes ausführen

    z.B

    @Override
    public void onDisable() {
    MapReset.resetWorld("test");
    }



    Folgende Methoden sind ebenfalls vorhanden:

    - MapReset.deleteWorldSave(worldName); (Löscht die gespeicherte map {kein mapreset mehr möglich bis zum nächsten Speichern der Welt})

    - MapReset.kickPlayers(worldName, kickMessage); (Spieler aus einer Welt kicken)

    - MapReset.worldSaved(worldName); (Checken ob eine Welt gespeichert wurde)




    *Du brauchst eigentlich nur die Welt Save Methode und die Reset Methode ;)
     
    #1
  2. Asgarioth
    Offline

    Asgarioth

    Registriert seit:
    17. Juli 2014
    Beiträge:
    51
    Ort:
    Hessen
    Minecraft:
    Asgarioth
    Hallo MCWizzardDev,

    Ich habe mir das Tutorial den Code mal angesehen, um zu verstehen was der Plan ist. Ich ging ursprünglich davon aus, dass wir vom Neuerzeugen einer Map sprechen (sorry dafür. :), in meinem Sprachgebrauch ist Map Reset = Welt neu erzeugen) und war irritiert, warum Du das nicht einfach mittels der MV API tust. Vielleicht kannst Du das für Doofe wie mich verdeutlichen. :D

    Okay. :) Dann erspare ich mir dazu weitere Ausführungen, wie es anders, einfacher, was auch immer geht... und bleibe strikt bei deinem vorgestellten Code und Deinem Ansatz (mit der Annahme, dass er soweit lauffähig ist nachdem man ihn eingebunden hat):

    Der I/O
    Solange die Methoden beim Serverstart bzw. Stopp ausgeführt werden geht es vermutlich gut. Sollte jemand die Methoden aber im laufenden Betrieb verwenden könnte ein Problem entstehen:

    Der ganze Kopiervorgang ist synchron, d.h. er wird im Zweifel den Server solange blockieren, bis der Kopiervorgang abgeschlossen ist oder der Server sich formlos abmeldet, da das Plugin nicht mehr reagiert. Für kleine Welten mag das funktionieren, je nach Hardware wird es bei größeren Welten schonmal eng. Evtl. externe Einflüsse, die in I/O-Waits münden und das Plugin zum Nichtstun verdammen gar nicht mal berücksichtigt.

    Für die reine Kopieroperation (und wirklich nur(!) dafür, da Bukkit-Methoden grundsätzlich als nicht thread-sicher anzusehen sind) bietet es sich an, einen asynchronen Task zu nutzen und so die Kopieroperation "abzukoppeln". In dem Fall muss natürlich die Beendigung des Tasks entsprechend erkannt und bei der weiteren Verarbeitung berücksichtigt werden. Besonders beim Stoppen und damit dem Aufrauf von onDisable() muss das berücksichtigt werden.

    Nutzung ohne Restart (Reload)
    Dem Code fehlt die Möglichkeit (zumindest sehe ich sie nicht), die Welt eigenständig (d.h. nicht über einen Restart) neu zu laden. Darauf solltest Du hinweisen. Der Hinweis "z.B. am Endes des Spiels", also im Zweifelsfall zu einem beliebigen Zeitpunkt während der Server läuft, funktioniert nicht. Ein saveWorld() wird nicht funktionieren, da die Welt entladen ist ohne dass sie zu einem späteren Zeitpunkt neu geladen werden würde.

    Speicherort der Welt:
    41: File srcWorldFolder = new File(world.getName());

    Die Welten werden grundsätzlich im Wurzelverzeichnis des Servers erwartet. Liegen die dort nicht (z.B. weil die world-container Option in der bukkit.yml verwendet wird), geht es schief. Stattdessen sollte die Methode getWorldFolder() verwendet werden, um den Speicherort der Welt zu bestimmen.

    Am Rande
    Die Speicherung & Abfrage der Parameter sowie die Speicherung in der WorldSettings ist redundant im Code vorhanden (ob sie überhaupt erforderlich ist wäer die nächste Frage). Identischer Code an mehreren Stellen ist nicht hübsch und wenn da was geändert werden soll ist es unnötiger Aufwand. Zumindest da ist ein Hinweis a là "Es geht einfacher" hoffentlich erlaubt. Es erhöht sicher die Lesbarkeit.

    Die Methode worldSaved() prüft eigentlich nur, ob das Verzeichnis existiert. Ob sich darin auch etwas (sinnvolles) befindet bleibt offen.

    Schlusswort
    Ich finde den Beitrag als Tutorial etwas knapp, da man relativ genau schauen muss. Ich glaube, es würde wesentlich hilfreicher werden, wenn Du anhand des Quellcodes auch die wesentlichen Schritte sowie die Gedanken dahinter beschreibst.

    Damit gibst Du mehr Leuten eine Chance den Beitrag zu verstehen, sich neues Wissen zu erschließen und sich weiterzuentwickeln. Nicht zuletzt kannst Du auch selber profitieren, sei es durch Anmerkungen und Vorschläge zu Deinem Beitrag oder auch dadurch, dass Du aus dem Feedback erkennst wie der Beitrag auf den Leser wirkt.

    LG
    ~Asgarioth
     
    #2
    jensIO gefällt das.