Beiträge von Scrayos

    #push: Auch in dieser Woche ist wieder ein neuer Wochenrückblick erschienen, den ihr über diesen Link erreichen könnt. Dieses mal wurden unter anderem die baulichen Neuerungen durch die Version 1.16 thematisiert, aber auch die stetige Verbesserung unserer Code-Qualität wird aufgegriffen. Schaut wie immer gerne rein und hinterlasst uns Feedback! Auch wenn wir hier ebenfalls die Wochenrückblicke posten, könnt ihr sie auf unserer Website immer schon bereits ab Samstag 19.00 Uhr lesen!


    Wie schon angekündigt planen wir dieses Thema in Zukunft komplett zu überarbeiten. Deshalb wurden aber die Informationen im Hauptpost seit einiger Zeit nicht mehr auf den neuesten Stand gebracht. In der PDF unterhalb findet ihr jedoch stets die aktuelle Ausschreibung für Entwickler. Haltet euch daher besser an dieses Dokument bis wir den Thread überarbeitet haben.


    Wir suchen noch weitere Unterstützung im Entwicklungsbereich und bieten unseren Entwicklern eine Menge Vorteile, die unter anderem in unserer PDF unterhalb angesehen werden können. Wir wollen auch in Zukunft große Projekte realisieren und Deine sowie unsere Ideen umsetzen, weshalb wir auf Nachwuchs angewiesen sind. Schaue daher gerne unverbindlich auf unserem Teamspeak-Server unter ts.justchunks.net vorbei, oder kontaktiere uns auf unserem Discord-Server unter https://justchunks.net/discord!



    » ZUR ENTWICKLER-AUSSCHREIBUNG «

    Builder | Video-Produzent | Grafiker

    #push: Wir haben nun seit 12 Wochen jede Woche einen Rückblick auf unserer Website veröffentlicht, in dem wir resümieren, was in der jeweils vorangegangenen Woche passiert ist und welche Fortschritte wir erreichen konnten. Zudem wurden auf unserem YouTube-Channel vier Cinematics publiziert. Den aktuellen Wochenrückblick findet ihr entsprechend unter diesem Link. Er steht im Zeichen des 1.16 Updates und einer Änderung an der Art und Weise, wie wir unsere Versionen kommunizieren.


    In der letzten Zeit haben wir hier nur selten das Thema gepusht, weil wir eine komplette Überarbeitung des Threads konzipieren. Bislang haben wir auf Dev-Tek nur nach Entwicklern gesucht und auf jeweils anderen Plattformen nach z.B. Buildern. Dies wollen wir nun vereinheitlichen und mit dem Hauptthema einen möglichst guten Einblick in unser allgemeines Team, das Projekt und die Vision hinter JustChunks – losgelöst von den jeweiligen Rollen – bieten. Die einzelnen PDF-Ausschreibungen werden dort dann verlinkt und gehen genau auf die bestimmten Rollen ein.


    Wegen dieser Überarbeitung wurden aber die Informationen im Hauptthema seit einiger Zeit nicht mehr auf den neuesten Stand gebracht. In der PDF unterhalb findet ihr jedoch stets die aktuelle Ausschreibung für Entwickler (die auch erst vorgestern wieder erneuert wurde).


    Wir suchen noch weitere Unterstützung im Entwicklungsbereich und bieten unseren Entwicklern eine Menge Vorteile, die unter anderem in unserer PDF unterhalb angesehen werden können. Wir wollen auch in Zukunft große Projekte realisieren und Deine sowie unsere Ideen umsetzen, weshalb wir auf Nachwuchs angewiesen sind. Schaue daher gerne unverbindlich auf unserem Teamspeak-Server unter ts.justchunks.net vorbei, oder kontaktiere uns auf unserem Discord-Server unter https://justchunks.net/discord!



    » ZUR ENTWICKLER-AUSSCHREIBUNG «

    Builder | Video-Produzent | Grafiker

    AtariKafa Es freut mich, dass du dein Problem lösen konntest. Die Noten sind in Minecraft übrigens eines der Systeme, die m.M.n. mit am schönsten umgesetzt wurden. Die Zahlen (wie zum Beispiel deine 0.94) mögen erst einmal sehr willkürlich wirken, aber die zwei Oktaven die Minecraft abbildet, werden durch die Zahlen von 2^(-12/12) bis 2^(12/12) gebildet. Deine 0.94 sind also eigentlich 2^(-1/12) bzw. ~ 0.943874 und damit ein F. Es gibt auch (ich weiß nicht, ob es sie nur in neueren Versionen gibt, aber ich schätze die gibt es schon länger) eine ganz nette Klasse org.bukkit.Note, mit der du die Zahlenwerte ebenfalls modellieren kannst. :thumbup:


    Mehr Infomationen: https://minecraft.gamepedia.com/Note_Block#Notes

    Hallo ShiroCW,


    tatsächlich hängt der damit verbundene Aufwand bzw. die elegante Umsetzbarkeit dieses Vorhabens stark davon ab, ob du Paper (ehemals PaperSpigot) verwendest/voraussetzen kannst, oder ob du stattdessen nur Spigot (bzw. sogar Craftbukkit) nutzt oder nutzen kannst. Das hängt damit zusammen, dass Paper innerhalb einer Reihe von Patches sogenannte "PlayerProfiles" hinzugefügt hat, die ein API-Objekt zur Arbeit mit eben diesen Texturen und Metadaten der Mojang-Profile darstellen. Dadurch ersparen wir uns die mühselige und unsaubere Arbeit mit dem direkten NMS-Code (net.minecraft.server – also der direkten Server-Implementation und nicht der Schnittstelle) und können sauber auf diese Texturen zugreifen.


    Nachfolgend werde ich also beide Implementation dieser Funktionalität vorstellen, kann aber nur zu der Nutzung von Paper anraten, da neben dieser Funktionalität auch noch ein Haufen weiterer Features enthalten ist und die allgemeine Performance der von Spigot in vielerlei Hinsicht überlegen ist. Mehr Informationen hierzu gibt es auf der entsprechenden Projekt-Website. Ich setze übrigens für beide Lösungen voraus, dass du den Base64-String bereits konvertiert hast und dir den letzten Teil der URL herausgefiltert hast. Eine kurze Info dazu erhältst du unterhalb:

    1. Du hast einen Base64-String wie diesen: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWMwYTY0NTkzY2E3ZTExODNhZjE1MjMxZGI3ZGI4YWQ2YWM0ZTExMzM4ZTA5Mjg0ZGU5YzFmZTUyYTc0ZTVl
    2. Du konvertierst diesen beispielsweise mit dem Java 8 Base64 Decoder (Base64#getDecoder()#decode(byte[])) in seine ursprüngliche Form.
    3. Du hast nun beispielsweise {"textures":{"SKIN":{"url":"http://textures.minecraft.net/texture/9c0a64593ca7e1183af15231db7db8ad6ac4e11338e09284de9c1fe52a74e5e8"}}}
    4. Hiervon nimmst du den letzten Teil der URL, also 9c0a64593ca7e1183af15231db7db8ad6ac4e11338e09284de9c1fe52a74e5e8

    Lösung mit Paper

    Wie oberhalb bereits angeschnitten ist die Implementation mit Paper sehr gradlinig und sauber. Ich werde meine Implementation hier nicht gesondert für diese Antwort anpassen, aber sie sollte dennoch gut verständlich sein und im schlimmsten Fall kannst du ja noch einmal nachfragen:



    Der SkullTextureModifier modifiziert wie in der Doku beschrieben SkullMeta Objekte. Du kannst jede ItemMeta zu einer SkullMeta casten, sofern der Material-Typ dem eines Spieler-Kopfes entspricht.

    Lösung mit Spigot

    Hierzu habe ich bereits in der Vergangenheit eine Lösung auf Dev-Tek geschrieben. Der Link dazu ist: RE: Spieler-Köpfe im Inventar direkt laden


    Ich habe damals jedoch nicht den Code der Methode DataHandler#getTextureProfile(String) veröffentlicht, das hole ich hiermit nun nach (zum Glück arbeite ich seit jeher mit Git):

    Java
    public GameProfile getTextureProfile(String skinURL) {
    GameProfile profile = new GameProfile(UUID.randomUUID(), null);
    String base64encoded = org.apache.commons.codec.binary.Base64.encodeBase64String(
    ("{textures:{SKIN:{url:\"http://textures.minecraft.net/texture/" + skinURL + "\"}}}").getBytes()
    );
    Property property = new Property("textures", base64encoded);
    profile.getProperties().put("textures", property);
    return profile;
    }

    Guten Tag,

    um direkt vorweg deine eigentliche Frage zu beantworten, würde ich dir beispielsweise WinMerge nahelegen. Es existiert aber eine wahre Flut an Anwendungen, die den von dir skizzierten Usecase abdecken. Ich habe für Vergleiche – als Linux-Nutzer – beispielsweise in der Vergangenheit Meld genutzt. Das Stichwort für eine Suche bei Google hierzu wäre wohl der etablierte Begriff des "Diffs". Letzten Endes geht es dir ja genau hierum: Du möchtest die Diff(erenz) eines ursprünglichen Ordners und einer neuen Version dieses Ordners vergleichen.


    Dafür musst du zuvor natürlich noch die Jar so dekompilieren, dass sie direkt in einem Ordner abgelegt wird. Du hast bereits geschrieben, dass das Dekompilieren kein Problem sei, aber falls es dennoch Probleme mit deiner existierenden Lösung geben sollte (beispielsweise weil sie die dekompilierten Dateien nicht entsprechend exportiert), so wäre hier Fernflower, das ursprünglich als interne Komponente von IntelliJ IDEA entwickelt wurde, nun aber auch separat erhältlich ist, sicherlich eine solide Wahl. Anschließend vergleichst du dann nur noch mit dem Tool deiner Wahl die beiden Ordner.



    Wo deine eigentliche Frage nun beantwortet ist, würde ich mich aber gerne mit Nachdruck der Argumentation von Der_Maibaum anschließen wollen. Auch ich halte Git hier nicht nur für die bessere Lösung sondern – unabhängig von deinem aktuellen Problem – für eine Ergänzung eures Workflows, die ihr definitiv mal berücksichtigen solltet. Es geht dabei ja keineswegs nur um die Kollaboration und die Kontrolle von eingereichtem Code, sondern viel mehr um die Nachvollziehbarkeit von einzelnen Änderungen, der Sicherung von bestimmten Stadien der Entwicklung sowie eine Umgebung, in der das Durchführen von Experimenten als Teil des allgemeinen Workflows verstanden wird. Und ich denke umso früher ihr Git als wertvolle Bereicherung eurer Tätigkeit versteht, desto einfacher werdet ihr es auch damit haben, die von Git beabsichtigten Workflows für euch zu adaptieren.



    Zur Veranschaulichung werde ich hier mal unseren Workflow als Kurzabriss (weil ich mittelfristig hierzu noch einen umfangreichen Beitrag auf unserer Website veröffentlichen möchte) beschreiben:


    Wir arbeiten grundsätzlich mit zwei Hauptbranches (Entwicklungszweigen): master und development. Im Gegensatz zu vielen anderen Software-Projekten stellen wir an beide Branches die Anforderung, dass sie jederzeit kompilierbar sein müssen und master sich von development nur insofern unterscheidet, dass der master zusätzlich manuell getestet und bereits in der Vergangenheit Teil eines Releases war. Aber auch unsere development-Branch soll zu jedem Zeitpunkt eine weitestgehend stabile Version darstellen, die aber eben bislang nur automatisch getestet wurde.


    Auf diese beiden Branches haben nur Ich und optional ein Project-Maintainer (also der Haupt-Verantwortliche für diese Software-Komponente) Schreibzugriff. Die anderen Entwickler können also ihre Änderung nicht direkt auf die master und development Branches anwenden. So ist schon einmal gesichert, dass sie keine Änderungen veranlassen können, die unmittelbar auf den Server aufgespielt werden. Stattdessen arbeiten die Entwickler in ihren eigenen Feature- bzw. Dev-Branches. Wir verwenden dafür das Schema dev/<name-in-kebab-case> (also zum Beispiel dev/teleport-history). Die Namen dieser Branches sind aber grundsätzlich willkürlich.


    Über diese Entwicklungszweige haben die Entwickler volle Kontrolle und können hier auch frei nach Belieben verändert, gelöscht oder erstellt werden. Darin findet dann die eigentliche Entwicklung statt und der Entwickler testet diese Version auch Eigenständig auf einer eigenen Instanz des Netzwerks. Sobald sich der Entwickler sicher ist, dass das Feature soweit abgeschlossen ist und auch keine weiteren Fehler auftreten, erstellt er einen entsprechenden Merge-Request. Ein solcher Merge-Request ist im Grunde die Beantragung der Überführung der Änderungen seines Entwicklungszweigs in den allgemeinen Entwicklungszweig development. Dort erklärt er dann auch seine Absicht für diesen Commit, verlinkt den vorhergegangenen Issue (Beschreibung des Bugs oder Features) und gibt optional weitere Anmerkungen zu der Merge-Prozedur. Das ganze sieht dann beispielsweise so aus:




    Wenn mir – oder dem entsprechenden Project-Maintainer – nun etwas an dem Code auffällt und wir Änderungen anbringen wollen oder zumindest bestimmte Stellen des Codes gerne diskutieren würden, so machen wir dies über Kommentare an dem gesamten Diff (oder wie Gitlab sie nennt "Threads"). Solche Diskussionen sehen dann beispielsweise so aus:




    Und sobald nun der Code allgemeinen Konsensus gefunden hat und so entsprechend in die Codebase bei development aufgenommen werden kann, mergen Ich – oder der besagte Project-Maintainer – das Ganze und die Änderungen landen automatisch auch in der development Branch. Wir haben so also vollste Kontrolle darüber was nun auf dem Netzwerk und in unserer Codebase landet. Zusätzlich können so frühzeitig Bugs entdeckt werden und alle lernen voneinander innerhalb der entsprechenden Diskussionen innerhalb der Merge-Requests.


    Bei uns sind zudem noch Pipelines (also CI-Job-Serien) in dem Workflow enthalten und ich merge auch nur Merge-Requests für die die Pipeline vollständig erfolgreich durchläuft. Wie eine solche Pipeline bei uns aussehen kann, ist hier zu sehen (Für Fortgeschrittene: Die Commit-Meldung ist übrigens nur deshalb so ... ähem ... rustikal, weil die Commits vor dem Merge gesquashed werden und daher am Ende für die Gesamtheit der Änderungen ein gutes Betreff und eine aussagekräftige Beschreibung gesetzt werden):



    Optional kann hier auch noch das Deployen des Codes (beispielsweise in ein Docker-Cluster) vorgenommen werden. Der Ansatz führt also zu qualitativ höherwertigem Code, besserer Kollaboration, allgemein hoher Sicherheit und vor Allem: Zeitersparnis und weniger Fehlerquellen. Manuelle Tests, Prozesse und Kontrollen sind unheimlich fehleranfällig und sollten daher vermieden werden. Ich kann dir also abschließend wirklich nur noch einmal dazu raten Git ggf. doch noch eine Chance zu geben. Die Vorteile sind riesig und der wohl einzige "Nachteil" ist die Eingewöhnungsphase bzw. die geringfügig verlängerte Einlern-Zeit für neue Entwickler.


    Solltest du hierzu weitere Fragen haben, so beantwortet sie dir sicherlich auch jemand innerhalb des Forums.

    Alle Chunks innerhalb der Border

    Ich würde hier unbedingt dazu raten auch noch so viele Chunks darüber hinaus zu berechnen, wie die Sichtweite der Spieler beträgt. Sonst wird es dennoch Chunk-Generierungen geben. Leider ignoriert der Server die Chunks außerhalb der WorldBorder ja nicht einfach, so wie man es beispielsweise beim Spectator-Modus einstellen kann.

    MadeByProxxy Es freut mich, dass es nun funktioniert!


    Ich würde dennoch ungerne ein paar der von IDK_WHO_AM_I aufgeworfenen Punkte unkommentiert so stehen lassen. Dieser Post richtet sich also nicht mehr direkt an dein Problem, ist für dich und zukünftige Leser ggf. dennoch interessant und bedenkenswert. Es geht um meine allgemeine Einstellung in Bezug auf Hilfe-/Frage-Posts und um die Relevanz von Codestyle sowie verbesserter Lesbarkeit.


    IDK_WHO_AM_I Ich vermute, dass du meine Kritik falsch aufgefasst hast, bzw. ich nicht klar genug gemacht habe, was ich damit bezwecken wollte. Es ging mir überhaupt nicht darum dich auch nur im entferntesten persönlich anzugreifen oder dich darin zu kritisieren, dass du Hilfe anbietest. Im Gegenteil: Ich finde es hervorragend, dass du dir die Zeit nimmst, um jemanden mit einem Problem unentgeltlich zu helfen. Das ist definitiv nicht selbstverständlich und sollte entsprechend honoriert werden.


    Auch deinen generellen Ansatz habe ich nicht negativ kommentiert, und darin sehe ich auch keinen Grund. Der allgemeine Algorithmus und dessen Funktion stimmt ja durchaus mit dem überein, was sich der Thread-Ersteller gewünscht hat. Dennoch sind mir, wie ich oberhalb ja bereits ausgeführt habe, einige Dinge aufgefallen, die ich so für nicht gut, oder zumindest nicht uneingeschränkt optimal halte. Und insbesondere weil du dir die Zeit genommen hast, hier jemandem zu helfen und weil ich hier mit einer Antwort nicht nur dich erreichen kann, sondern auch Leute, die beispielsweise über Google auf diese Frage aufmerksam werden, habe ich mir gerne die Zeit genommen um auch darauf zu antworten und damit ggf. auch für dich einen Mehrwert zu bieten. Leider scheinst du dich davon angegriffen gefühlt zu haben, und hast dich auch innerhalb des ersten Satzes gerechtfertigt. Das wäre gar nicht nötig gewesen, es ging mir ja nicht darum dir Unvermögen oder dergleichen zu unterstellen.


    Nun aber zu meiner Meinung zu deinen Rechtfertigungen:

    Das ist einfach nur Unsinn sowas als "Verbesserung" zu sehen den Erstens gehört es so das ein "neuer Code Block" eingerückt beginnt wer das nicht macht, "Schande über dich".

    Das halte ich so für zumindest kontrovers. Codestyle und Lesbarkeit ist häufig sogar wichtiger als Mikro-Optimierungen, Feature-Überschuss oder Erweiterbarkeit. Codestyle und gute Lesbarkeit sind der Schlüssel zu guter Zusammenarbeit und Wartbarkeit. Programme werden schließlich für Menschen und nicht für den Computer geschrieben. Und auch, wenn ich deine Argumentation bezüglich des eingefügten Code-Blocks nachvollziehen kann, so stellt sich mir – insbesondere in dem konkreten Code-Beispiel – wirklich kein eigenständiger, logischer, neuer Block dar. Der innere Block besteht schließlich nur aus einer einzelnen Bedingung. Und diese Bedingung steht auch noch im direkten Zusammenhang mit der vorigen Bedingung, da du hiermit lediglich sicherstellen möchtest, dass ein fehlender Eintrag niemals größer als die 60 sein kann, die Bedingung also in diesem Fall immer falsch sein muss.


    Unnötige Einrückungen wirken sich besonders negativ auf den Lesefluss aus, wenn sie dafür sorgen, dass der darin enthaltene Code weit jenseits der (gut) lesbaren 100 Zeichen/Spalten liegt. Unter anderem deshalb gilt es, Einrückungen sinnvoll einzusetzen und eben auch zu vermeiden, wenn die Einrückung an dieser Stelle keinen Mehrwert bietet. In diesem Beispiel ist das weniger wichtig, aber grundsätzlich wirken sich separate Code-Blocks und die Aufteilung in zwei separate Bedingungen auch auf die zyklomatische Komplexität aus, was ebenfalls vermieden werden sollte.


    Was die Klammern und den Hinweis auf die AFK-Logik betrifft, so vertrete ich die Auffassung, dass die Personen die hier Hilfe anbieten so umsichtig wie möglich auf möglichst viele Leser eingehen sollten. Natürlich kann man das nicht verlangen, ist doch jeder hier freiwillig, aber wünschenswert ist es dennoch. Das Weglassen der Klammern verwirrt hier ggf. den einen oder anderen Leser und liefert ihm im Umkehrschluss keinen Vorteil. Zusätzlich können hier durch Unachtsamkeit leicht Fehler entstehen. Und auch wenn du natürlich damit recht hast, das es hier nicht um das Schreiben fertiger Plugins geht, so tut es dennoch nicht weh, hier kurz auf solche Faktoren hinzuweisen, bzw. die Klammern zu setzen. Ich glaube einfach, dass du dem Leser damit keinen gefallen tust, weil vielleicht nicht jeder so umfassend um die syntaktischen Möglichkeiten von Java informiert ist, wie du es bist.


    Dennoch möchte ich abschließend ein weiteres Mal darauf hinweisen, dass ich es grundsätzlich begrüße und loben möchte, dass du hier Leuten hilfst, und das ja auch tatsächlich nicht schlecht oder verkehrt. Aber ich hielt es für nötig mich hier zu äußern, da mir Aussagen wie "Schande über dich" trotzdem negativ aufgestoßen sind. Ich wünsche dir ungeachtet dessen einen schönen Tag und hoffe du weißt meinen Post hier richtig einzuordnen. :)

    IDK_WHO_AM_I Ich stimme mit deiner Lösung soweit überein, bis auf zwei, drei kleinere Dinge:



    private HashMap<UUID, LocalDateTime> lastMovement;

    Eine LocalDateTime ist hier definitiv der falsche Datentyp. Du willst hier einen Moment (also einen spezifischen, unverwechselbaren Zeitpunkt) vergleichen. Es sollen ja immer 60 Sekunden vergangen sein und du willst überhaupt keine für Menschen lesbare Repräsentation dieser Zeit. Du möchtest einen Instant. Sie sind untereinander vollständig kompatibel, meinen aber wie gesagt vollständig unterschiedliche Dinge. Eine hervorragende Unterscheidung der neuen Zeit-Typen kannst du HIER erhalten.


    Code
    public void handleMovement(PlayerMoveEvent e) { if (e.getFrom().getBlockX() != e.getTo().getBlockX() || e.getFrom().getBlockY() != e.getTo().getBlockY() || e.getFrom().getBlockZ() != e.getTo().getBlockZ()) if (e.getFrom().getPitch() != e.getTo().getPitch() || e.getFrom().getYaw() != e.getTo().getYaw()) lastMovement.put(e.getPlayer().getUniqueId(), LocalDateTime.now()); }

    Die Bedingungen würde ich mir hier schenken. Es wird ohnehin nur ein Move-Event ausgelöst, wenn sich die Position wenigstens irgendwie von der vorigen Position unterscheidet, und ob es nun innerhalb des Blocks war, oder Block-Grenzen übergreifend macht es nur ungenauer. Würde ein Nutzer so vorher an der Blockgrenze stehen, dürfte er sich weniger bewegen um trotzdem noch als AFK markiert zu werden, als wenn er in der Mitte des Blocks gestanden hätte.


    Durch deine Abfragen würden auch Teleports an die exakt selbe Position in einer anderen Welt nicht berücksichtigt. Wenn man unbedingt eine Bedingung haben möchte, kann man auch einfach die From- und To-Positionen mit Equals vergleichen, da bekäme man dann sogar noch die bessere Verarbeitung von Float und Double geschenkt. Aber es ist wie gesagt überhaupt keine Bedingung nötig, wenn ohnehin jede Art der Veränderung berücksichtigt werden soll.


    if (lastMovement.containsKey(player.getUniqueId()))
    if (lastMovement.get(player.getUniqueId()).plusMinutes(1).isAfter(LocalDateTime.now()))
    Bukkit.broadcastMessage(String.format("§e%s hasn't moved since 60 seconds"));
    //TODO do something

    Hier rückst du unnötig oft ein und verwendest keine Klammern, was insbesondere in Anbetracht der Tatsache, dass man da auch gerne mal mehrere Dinge anstoßen möchte, schnell zu Fehlern führen kann. Abgesehen davon, würde ich es aber so regeln:

    Java
    Bukkit.getScheduler().scheduleSyncRepeatingTask(pluginInstance, () -> {
    final Instant now = Instant.now;
    Bukkit.getOnlinePlayers().forEach(player -> {
    Instant lastMovementMoment = lastMovement.get(player.getUniqueId());
    if (lastMovementMoment != null && Duration.between(lastMovementMoment, now).getSeconds() > INACTIVITY_SECOND_TRESHOLD) {
    // afk-logic here
    }
    });
    }, 0L, 20L);

    Erstmal hole ich hier nur einmal die aktuelle Zeit. Sich den aktuellen Zeitpunkt zu beschaffen ist zwar nicht teuer, aber auch nicht gratis. Insbesondere bei der Präzision, die die neuen Time-Objekte von Java 8 anstreben, wird die präziseste, verfügbare Zeit-Ressource verwendet, um so ein Objekt zu beziehen. Das kann gerne auch mal einen Syscall beinhalten, was zwar in Ordnung ist, aber eben auch nicht so schnell/günstig wie man ggf. meinen mag. Wir brauchen den aktuellen Zeitpunkt ohnehin nur einmal, da uns die Veränderungen im Nanosekunden-Bereich während des Vergleichs egal sind.


    Eben weil uns die Präzision unter einer Sekunde nicht interessiert, habe ich den Task-Intervall übrigens auch auf 20 angehoben. Es reicht für diesen Fall sicherlich vollkommen einmal in der Sekunde nachzuprüfen, ob sich etwas neues ergeben hat.


    Dann habe ich deine beiden Bedingungen zu einer Zusammengefasst, und dabei auch das Contains durch die Nullability der Get-Methode ersetzt. Wenn das Element nicht enthalten ist, wird null zurückgegeben. Wir nutzen null niemals als echte Value, es kann also nur daher kommen. So sparen wir uns das doppelte Hashing (das aber sowieso unglaublich günstig ist) und können den Code etwas entschlacken. Der zweite Teil der Bedingung nutzt jetzt eine Konstante für den Vergleich (hier müsste also 60 zugewiesen werden) und arbeitet mit dem ermittelten Moment.


    Die Lösung ist vor Allem deshalb besser, weil sie wie gesagt nur einmal den aktuellen Vergleichs-Zeitpunkt erstellt, und weil sie generell nicht so viele Elemente erstellt. Die neue java.time-API basiert auf unveränderbaren (Immutable) Objekten. Ein Aufruf wie "plusMinutes(long)" erstellt daher extra ein neues LocalDateTime-Objekt. Wir erstellen hier jetzt zwar auch eine Duration, die wir durch den direkten Vergleich der Sekunden verhindern könnten, erhalten dafür aber eine deutlich verbesserte Lesbarkeit.


    Was aber hier noch immer nicht bedacht wurde, und was auch deine Lösung nicht abgedeckt hatte, ist der Fall, dass der Nutzer bereits als "AFK" markiert wurde. Aktuell würde also immer wieder der Teil bei "// afk-logic here" für ihn ausgeführt. Da müsste man also ggf. noch drauf achten und entsprechend filtern, um nur die neuen AFK-Nutzer zu erhalten.

    Die Lösung mit der besten Performance wäre sicherlich ein Aufruf von https://papermc.io/javadocs/pa…/Entity.html#isOnGround-- (Entity#isOnGround). Allerdings gab es zumindest in der Vergangenheit bei der Nutzung im Zusammenhang mit Spielern einige Warnungen in den Javadocs, weswegen der Aufruf der Methode beim Spieler auch als Deprecated markiert war. Hierbei war das Problem, dass der "OnGround"-Status vom Client gesendet wurde, und daher mit modifizierten Clients sehr leicht gefälscht werden konnte. Diese Hinweise gibt es in den neueren Versionen (1.12+) allerdings nicht mehr, auch wenn ich mir nicht sicher bin ob das nun bedeutet, dass der Status auch bei Spielern selbst berechnet wird, immerhin wird der Status nach wie vor vom Client als Teil des Protokolls übertragen: https://wiki.vg/Protocol#Player_Position


    Ich würde diese Methode dennoch erstmal probieren (insbesondere sofern es nicht sooo kritisch ist, wenn es mit einem manipulierten Client umgehbar wäre) und nur falls diese Methode nicht deinen Ansprüchen genügt auf diese einfache, eigene Implementation zurückgreifen. Die Performance unterscheidet sich zwar wirklich nur minimal, da hier ebenfalls ausschließlich einfache mathematische Vergleiche und sehr schnelle Lookups mit linearer Laufzeit durchgeführt werden, aber die andere Methode ist extra für diesen Fall gedacht und lässt sich deutlich besser lesen, zumindest wenn man mich fragt. Die alternative Lösung wäre eben:


    Code
    // hier muss selbstverständlich eine echte variable genutzt werden
    Player yourPlayer;
    // die unterscheidung bei .isSolid() kannst du auf deinen individuellen fall anpassen
    // ggf. möchtest du ja zum beispiel spinnenweben und co. als "auf dem boden" zählen
    return yourPlayer.getLocation().getBlock().getRelative(BlockFace.DOWN).getType().isSolid();


    Diese Abfrage packst du dann in eine eigene Methode und fragst sie beim PlayerCommandPreprocessEvent und PlayerInteractEvent ab. Sollten sie nicht "auf dem Boden" sein, so brichst du das Event ab (Event#setCancelled(Boolean)).


    #push: Lange ist es her, dass dieses Thema aktualisiert wurde. Nun wurde der erste Post an unser neues PDF-Design angepasst und die Informationen sind ebenfalls auf dem neuesten Stand. Dabei haben wir uns von einer Menge Text getrennt und versucht die Informationen weiter aufzubereiten und auf das Wichtigste herunter zu brechen. Für das Thema wurde die PDF zudem in ein Bild konvertiert. Für die optimale Ansicht empfehlen wir jedoch die PDF im Original über einen Klick auf die Grafik oder das Banner oberhalb zu öffnen. Wir wollen dieses Thema ab sofort wieder häufiger mit Neuigkeiten versorgen und freuen uns mit dem aktualisierten Thema nun den Grundstein dafür gelegt zu haben!

    Äh, ...

    auch ich scheine deiner Argumentation nicht ganz folgen zu können. Meine Verwunderung über deine Argumentationskette begründet sich vor Allem darin, dass ja von der verlinkten Hytale-News-Seite auf das Hytale-Forum von MCSEU verlinkt wird, und nicht andersherum. Entsprechend wundert mich, dass du beklagst, dass im Impressum von MCSEU nichts hierzu vermerkt ist. Aber das wäre doch auch der falsche Ort, oder nicht?

    Ich könnte durchaus verstehen, wenn du eine Ungereimtheit in dem Fehlen eines Hinweises auf das externe Forum seitens der News-Seite sehen würdest. Es erschließt sich mir allerdings nicht, welchen Fehler MCSEU hier – abgesehen von dem falschen Routing beim Hytale-Forum und dem dadurch verschuldeten Nichtvorhandensein des Impressums – gemacht haben soll. Vielleicht könntest du da die Sachlage aus deiner Perspektive noch einmal näher darlegen.

    Heyho,


    die Zielgruppe besteht hauptsächlich aus denjenigen, die bereits eine der vielen "Bukkit-Tutorial-Reihen" angeschaut haben. Es geht mir also definitiv nicht darum Bukkit geschweige denn Java neu zu vermitteln, sondern viel mehr vorhandene Fehler oder schlechte Angewohnheiten auszubügeln, die sich durch die Tutorial oder im Laufe der Zeit eingeschlichen haben. Darüber hinaus möchte ich noch einige Ebenen auf das Tutorial-Wissen drauflegen. Das sieht man zum Beispiel an den Erklärungsvideos zu den Tools (Git, Checkstyle). Es geht mir hier also darum Menschen, die schon regelmäßig im Bukkit-Kontext agieren mit Wissen darüber zu versorgen, wie sie ihren Workflow optimieren können, bzw. wie in der Software-Entwicklung außerhalb von Minecraft gearbeitet wird.


    Ich habe also nicht den Anspruch "einsteiger-freundlich" zu sein, sondern viel mehr engagierte Entwickler dazu zu verhelfen weiter besser zu werden. Für solche Einstiegstutorials kann ich da zum Beispiel die Tutorials von BiVieh empfehlen.


    Vielen Dank für dein Feedback!

    Im Zuge meiner Update-Agenda, die ich für diesen Thread angekündigt habe, poste ich mal wieder das Video dieser Woche. Neue Videos erscheinen immer Sonntags gegen 12:00:



    Vielen Dank auch noch einmal für die Aufmerksamkeit und den anhaltenden Support!

    Vielen Dank für das nette Feedback!

    Und die Alarmglocken-Sache gibt es ja leider in Bezug auf viele Praktiken in der Bukkit-Szene. Und bei den Dingen, bei denen die Alarmglocken wirklich Sturm klingeln sollten (Reflection zum Beispiel), da werden falsche Dogmen gepredigt. Und das ist ja eben auch eine der Motivationen, die ich für dieses Projekt verfolge.


    Bezüglich deines Fun-Facts scheine ich etwas auf dem Schlauch zu stehen; kannst du das näher ausführen? Ich wäre mir keines "Überschreibens statischer Methoden" bewusst. Es sei denn, du meinst das Shadowing (Überdeckung) oder Overloading (Überladung). Bei statischen Methoden ist ja wegen des fehlenden Polymorphismus' zur Laufzeit sogar bei dieser Konstellation mit keiner Überschreibung zu rechnen:


    Vermutlich meintest du eines der oberhalb genannten Szenarien, aber beschreib' gerne nochmal genauer was du damit meinst. :)

    Guten Tag liebe Dev-Tek-Community,


    ich liebäugle schon seit geraumer Zeit mit dem Gedanken eine YouTube Leitfaden-Reihe zu kreieren. Nun habe ich mich endlich dazu motivieren können diesen Gedanken in die Tat umzusetzen. Getauft habe ich das Projekt Bukkit: Done The Right Way und es wird wie geplant auf YouTube publiziert. In diesem Beitrag möchte ich euch das grundsätzliche Projekt vorstellen, ein wenig über meine Motivation, die Eckdaten und die Ideen für die Zukunft sprechen.

    Motivation

    Meine Motivation für die Videoreihe begründet sich hauptsächlich in den vielen Fragen die ich in der Vergangenheit zu IntelliJ IDEA, Maven und Bukkit erhalten habe, sowie den Eindrücken, die ich beim "durchzappen" der bereits existierenden YouTube-Bukkit-Tutorials gewinnen durfte. Deshalb wähle ich für diese Reihe häufig einen vergleichenden Ansatz, bei dem ich mich bemühe externe, weiterführende Quellen und Literatur einzubinden und Bezüge zu falschen Programmier-Paradigmen und Common-Pitfalls herzustellen. Ich beschränke mich bei diesen Tutorials größtenteils auf den Java/Bukkit-Bereich, werde allerdings versuchen hier auch den Ausblick bzw. die Brücke zu Java zu schaffen.

    Eckdaten

    Da ich nicht alle Build-Systeme, IDEs, Minecraft-Versionen, Bukkit-Forks und Java-Versionen abdecken kann, habe ich mich gleich zu Anfang auf ein Set aus Versionen und Tools festgelegt, dass ich möglichst konstant über die Video-Reihe hinweg pflegen möchte. Ich verwende als BuildSystem Maven v3, die IDE meines Vertrauens ist IntelliJ IDEA (immer auf neuester Version), es wird mit Minecraft 1.13 auf dem Bukkit-Fork PaperSpigot gearbeitet und dafür nutze ich Java 11. Sobald die Tutorials sich in Richtung weiterer Technologien wie Datenbanken, Collections oder Networking bewegen, werde ich auch hierfür Versionen festlegen, bei denen ich versuche den Grad zwischen Stabilität und Modernität abzuwägen. Gerichtet ist diese Leitfaden-Reihe primär an Personen die schon ein wenig Erfahrung mit Java haben und ggf. sogar schon ein bisschen in die Bukkit-Programmierung hineingeschnuppert haben. Dennoch ist natürlich jeder eingeladen sich die Videos anzuschauen, hier ist dann ggf. nur ein wenig eigene Recherche nötig

    Pläne für die Zukunft

    Der Plan den ich hierbei verfolge sieht es vor, besonders jene Themen zu beleuchten, die häufig ausgelassen, ignoriert oder falsch interpretiert werden. Ich hege den Anspruch an mich selbst, bei den Themen die ich anspreche ein ausgewogenes Gesamtbild zu vermitteln und damit niemanden mit der "Erklärung" abzutun: "Ja, das kopierste halt so rein. Ist nicht wichtig warum.". Denn das Warum ist das eigentlich wichtigste und ist der Grundstein für jegliches eigenständiges Lernen. Obwohl mein Ziel natürlich ist, Wissen zu vermitteln und einen offenen Dialog über die verschiedenen Technologien zu starten, habe ich dennoch kein Problem damit, wenn jemand den im Video erstellten Code einfach kopiert. Ob man hieraus etwas lernen möchte, oder einfach schnell ein Problem beheben möchte ist jedem selbst überlassen und ich würde es mir niemals anmaßen jemandem vorzuschreiben, wie er meinen Content zu konsumieren hat. Deshalb stelle ich den Code nach jeder Folge auf Github und markiere die einzelnen Episoden mit Git-Tags.


    Für die Zukunft sind Themen wie beispielsweise: Maven: Extended Cut (also mehr als Basis-Informationen), Git, IntelliJ IDEA: Poweruser (also Produktivitäts-/Setup-Kniffe), Unit-Testing, Quality Assurance mit Checkstyle, Spotbugs und PMD sowie SonarQube und weitere angedacht. Aber natürlich werden auch die Basis-Themen wie Commands, Datenbanken, Networking, etc. abgedeckt und ich werde so gut es geht versuchen zusätzliche, über den Standard hinausgehende Informationen zu vermitteln.


    Hier findet ihr die Video-Reihe auf YouTube: YouTube-Playlist
    Hier ist die Organisation auf Github: https://github.com/BukkitDTRW

    Und hier sind die ersten Videos als Einbettung:





    Solltet ihr Lob, Kritik oder einfach neutrales Feedback hierzu loswerden, meldet euch gerne in den Kommentaren. Ich freue mich bereits von euch zu hören und werde vermutlich wöchentlich neue Videos hochladen!


    Ich bedanke mich ganz herzlich für das Lesen dieser Vorstellung und wünsche euch viel Spaß beim Schauen!

    Du kannst aber auch den https://... Link nutzen der geht bei den JetBrains Produkten.

    Gut möglich, dass das als Workaround funktionieren mag, ich arbeite in IntelliJ IDEA und CLion aber mit der SSH-Referenz und es funktioniert dennoch fantastisch. Ich denke es ist daher wichtig hier klar zu stellen, dass es eben nicht ausschließlich mit den HTTP(S)-Referenzen funktioniert (sollten sie denn funktionieren), sondern dass der Fehler eine andere Ursache hat, und keine schlichte Limitation der Software ist.

    #push: Während andere nun vollends im sogenannten "Sommerloch" angekommen sind, sich in den Ferien befinden oder der Urlaubsplanung frönen, wird gerade die neue Version unseres internen Networkings, des Berechtigungssystems sowie der Nutzerstruktur fertiggestellt. Ich habe mich vor einigen Monaten dazu entschlossen diese Bereiche grundlegend zu überarbeiten, da ich möchte, dass Entwickler bei uns den Umgang mit unseren APIs als konsistent, verlässlich und einfach wahrnehmen. Und auch wenn dies schon im Vorhinein teilweise der Fall war, so mussten Entwickler bei uns dennoch noch einiges über die bloße Nutzung der API bedenken. Durch unsere nun nahezu 100% abdeckende – äußerst umfangreiche und (hoffentlich) präzise – Dokumentation und die voranschreitende, konsistentere Trennung zwischen API und Implementation dürfte das Entwickeln in Zukunft wesentlich einfacher, übersichtlicher und – aus eigener Erfahrung – spaßiger ablaufen!


    Die diesmalige Grafik – die auch ein ungewöhnliches Format mit sich bringt – ist ein Screenshot des "Structure"-Views auf IntelliJ IDEA eines Markdown-Dokuments, an dem ich gerade – wenn ich nicht selbst programmiere – erstelle, um außenstehenden sowie Bewerbern unseren Workflow, unsere Einstellung sowie unsere Tools näher zu bringen. Die Titel können sich sicher noch ändern, und es kommt noch einiges dazu, als kleine Übersicht kann es aber auch jetzt schon genommen werden.




    Ich freue mich bereits darauf in einiger Zeit das fertige Dokument präsentieren zu können. Da ich hier allerdings detailliert auf die einzelnen Bereiche, unsere Arbeitsweise und unsere Ideale eingehen möchte, kann dies sicherlich noch ein wenig dauern! Bis dahin möchte ich aber schon einmal allen ein schönes Rest-Wochenende wünschen!