001/*
002 * PlotSquared, a land and world management plugin for Minecraft.
003 * Copyright (C) IntellectualSites <https://intellectualsites.com>
004 * Copyright (C) IntellectualSites team and contributors
005 *
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
018 */
019package com.plotsquared.core.util;
020
021import com.google.common.base.Preconditions;
022import com.plotsquared.core.PlotSquared;
023import org.jetbrains.annotations.NotNull;
024
025import java.util.Arrays;
026import java.util.Comparator;
027
028/**
029 * Represents a Minecraft version. For simplicity, and compatibility with modern versions, the `1.` prefix of older versions is
030 * ignored and the minor version part becomes the major version part.
031 * <p>
032 * <ul>
033 *     <li>`1.17.0` -> `(17, 0, 0)`</li>
034 *     <li>`26.2` -> `(26, 2, 0)`</li>
035 *     <li>`26.1.2` -> `(26, 1, 2)`</li>
036 * </ul>
037 *
038 * @param major the major part of the version string. For versions pre 26 this is the minor version part
039 * @param minor the minor part of the version string. For versions pre 26 this is the patch version part
040 * @param patch the patch part of the version string. For versions pre 26 this is always {@code 0}
041 */
042public record MinecraftVersion(int major, int minor, int patch) implements Comparable<MinecraftVersion> {
043
044    /**
045     * Minecraft 1.17 release version
046     */
047    public static final MinecraftVersion CAVES_AND_CLIFFS = new MinecraftVersion(17, 0, 0);
048    /**
049     * Minecraft 1.18 release version
050     */
051    public static final MinecraftVersion CAVES_AND_CLIFFS_2 = new MinecraftVersion(18, 0, 0);
052    /**
053     * Minecraft 1.19 release version
054     */
055    public static final MinecraftVersion THE_WILD_UPDATE = new MinecraftVersion(19, 0, 0);
056    /**
057     * Minecraft 1.20 release version
058     */
059    public static final MinecraftVersion TRAILS_AND_TALES = new MinecraftVersion(20, 0, 0);
060    /**
061     * Minecraft 1.21 release version
062     */
063    public static final MinecraftVersion TRICKY_TRIALS = new MinecraftVersion(21, 0, 0);
064    /**
065     * Minecraft 26.1 release version
066     */
067    public static final MinecraftVersion TINY_TAKEOVER = new MinecraftVersion(26, 1, 0);
068    /**
069     * Minecraft 26.2 release version
070     */
071    public static final MinecraftVersion CHAOS_CUBED = new MinecraftVersion(26, 2, 0);
072
073    private static final Comparator<MinecraftVersion> COMPARATOR = Comparator
074            .comparingInt(MinecraftVersion::major)
075            .thenComparingInt(MinecraftVersion::minor)
076            .thenComparingInt(MinecraftVersion::patch);
077
078    private static MinecraftVersion current;
079
080    public static MinecraftVersion current() {
081        if (current == null) {
082            //noinspection deprecation
083            int[] parts = PlotSquared.platform().serverVersion();
084            if (parts.length < 2) {
085                throw new IllegalStateException("Version string provided by platform is malformed: " + Arrays.toString(parts));
086            }
087            // if real major version part is `1`, we are running on legacy versions
088            if (parts[0] == 1) {
089                // legacy versions don't have real patch versions (as their major part is basically a dummy)
090                current = new MinecraftVersion(parts[1], parts.length > 2 ? parts[2] : 0, 0);
091            } else {
092                // modern versions do have a optional patch version (e.g. 26.1.2)
093                current = new MinecraftVersion(parts[0], parts[1], parts.length > 2 ? parts[2] : 0);
094            }
095        }
096        return current;
097    }
098
099    public MinecraftVersion {
100        Preconditions.checkArgument(this.major() > -1, "major version part must be positive or 0");
101        Preconditions.checkArgument(this.minor() > -1, "major version part must be positive or 0");
102        Preconditions.checkArgument(this.patch() > -1, "major version part must be positive or 0");
103    }
104
105    @Override
106    public int compareTo(@NotNull final MinecraftVersion o) {
107        return COMPARATOR.compare(this, o);
108    }
109
110    public boolean isNewerOrEqualThan(MinecraftVersion other) {
111        return this.compareTo(other) >= 0;
112    }
113
114    public boolean isOlderOrEqualThan(MinecraftVersion other) {
115        return this.compareTo(other) <= 0;
116    }
117
118    public boolean isOlderThan(MinecraftVersion other) {
119        return this.compareTo(other) < 0;
120    }
121
122    public boolean isNewerOrEqualThan(int otherMajor) {
123        return this.major() >= otherMajor;
124    }
125
126    public boolean isNewerOrEqualThan(int otherMajor, int otherMinor) {
127        return this.major() > otherMajor || (this.major() == otherMajor && this.minor() >= otherMinor);
128    }
129
130    public boolean isOlderOrEqualThan(int otherMajor) {
131        return this.major() <= otherMajor;
132    }
133
134    public boolean isOlderOrEqualThan(int otherMajor, int otherMinor) {
135        return this.major() < otherMajor || (this.major() == otherMajor && this.minor() <= otherMinor);
136    }
137
138}