Compare commits
No commits in common. "0e5e8415272c06311400b5f7bd99ee09b06c8d72" and "ea5279dd82b52643b7b6f36d98b4e5d21af353a9" have entirely different histories.
0e5e841527
...
ea5279dd82
@ -33,7 +33,6 @@ public class Settings extends Appliance {
|
|||||||
ChatMentions,
|
ChatMentions,
|
||||||
DoubleDoors,
|
DoubleDoors,
|
||||||
KnockDoors,
|
KnockDoors,
|
||||||
BorderWarning
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Settings instance() {
|
public static Settings instance() {
|
||||||
@ -143,9 +142,9 @@ public class Settings extends Appliance {
|
|||||||
int countOfUncategorized = (int) settings.stream()
|
int countOfUncategorized = (int) settings.stream()
|
||||||
.filter(setting -> !(setting instanceof CategorizedSetting))
|
.filter(setting -> !(setting instanceof CategorizedSetting))
|
||||||
.count();
|
.count();
|
||||||
int invSizeForUncategorized = (int) Math.ceil((double) countOfUncategorized / 9) * 9;
|
int rowsOfUncategorized = (int) Math.ceil((double) countOfUncategorized / 9);
|
||||||
|
|
||||||
int invSizeForCategorized = Arrays.stream(SettingCategory.values())
|
int rowsOfCategorized = Arrays.stream(SettingCategory.values())
|
||||||
.map(settingCategory -> settings.stream()
|
.map(settingCategory -> settings.stream()
|
||||||
.filter(setting -> setting instanceof CategorizedSetting)
|
.filter(setting -> setting instanceof CategorizedSetting)
|
||||||
.map(setting -> (CategorizedSetting) setting)
|
.map(setting -> (CategorizedSetting) setting)
|
||||||
@ -155,11 +154,11 @@ public class Settings extends Appliance {
|
|||||||
.reduce(Integer::sum)
|
.reduce(Integer::sum)
|
||||||
.orElse(1) * 9;
|
.orElse(1) * 9;
|
||||||
|
|
||||||
int invSize = invSizeForUncategorized + invSizeForCategorized;
|
int rows = rowsOfUncategorized + rowsOfCategorized;
|
||||||
if(invSize % 9 != 0) throw new IllegalStateException(
|
if(rows % 9 != 0) throw new IllegalStateException(
|
||||||
String.format("Failed to calculate settings inventory size. %d is not an multiple of 9", invSize)
|
String.format("Failed to calculate settings inventory size. %d is not an multiple of 9", rows)
|
||||||
);
|
);
|
||||||
return invSize;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onSettingsClose(Player player) {
|
public void onSettingsClose(Player player) {
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.datatypes;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.inventory.ClickType;
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.IntStream;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public abstract class IntegerSetting extends Setting<Integer> {
|
|
||||||
private final List<Integer> options;
|
|
||||||
|
|
||||||
public IntegerSetting(Settings.Key key, int minimum, int maximum) {
|
|
||||||
this(key, IntStream.range(minimum, maximum+1).boxed().toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
public IntegerSetting(Settings.Key key, List<Integer> options) {
|
|
||||||
super(key);
|
|
||||||
this.options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ItemMeta buildMeta(ItemMeta meta) {
|
|
||||||
Component componentBefore = Component.text(" " + this.fillWithSpaces(this.options.getLast()));
|
|
||||||
Component componentAfter = Component.text(" " + this.fillWithSpaces(this.options.getFirst()));
|
|
||||||
int listIndex = this.options.indexOf(this.state);
|
|
||||||
if(listIndex > 0) componentBefore = Component.text(" " + this.fillWithSpaces(this.options.get(listIndex-1)));
|
|
||||||
if(listIndex < this.options.size()-1) componentAfter = Component.text(" " + this.fillWithSpaces(this.options.get(listIndex+1)));
|
|
||||||
|
|
||||||
meta.displayName(Component.text(this.title(), NamedTextColor.WHITE));
|
|
||||||
List<Component> lore = new ArrayList<>(Stream.of(
|
|
||||||
Component.empty()
|
|
||||||
.append(Component.text("Wert: ", NamedTextColor.DARK_GRAY)),
|
|
||||||
Component.empty()
|
|
||||||
.append(componentBefore.color(NamedTextColor.DARK_GRAY))
|
|
||||||
.append(Component.text(" " + this.fillWithSpaces(this.state), NamedTextColor.GREEN))
|
|
||||||
.append(componentAfter.color(NamedTextColor.DARK_GRAY)),
|
|
||||||
Component.empty()
|
|
||||||
).toList());
|
|
||||||
lore.addAll(this.buildDescription(this.description()));
|
|
||||||
meta.lore(lore);
|
|
||||||
return meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String fillWithSpaces(Integer option) {
|
|
||||||
String optionString = option.toString();
|
|
||||||
int optionLength = optionString.length();
|
|
||||||
int maxInteger = this.options.stream().mapToInt(value -> value).max().orElse(0);
|
|
||||||
int maxLength = String.valueOf(maxInteger).length();
|
|
||||||
int padding = maxLength - optionLength;
|
|
||||||
|
|
||||||
int padEnd = padding / 2;
|
|
||||||
int padStart = padding - padEnd;
|
|
||||||
|
|
||||||
optionString = " ".repeat(padStart) + optionString + " ".repeat(padEnd);
|
|
||||||
return optionString;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void change(Player player, ClickType clickType) {
|
|
||||||
int elementBefore = this.options.getLast();
|
|
||||||
int elementAfter = this.options.getFirst();
|
|
||||||
int listIndex = this.options.indexOf(this.state);
|
|
||||||
if(listIndex > 0) elementBefore = this.options.get(listIndex-1);
|
|
||||||
if(listIndex < this.options.size()-1) elementAfter = this.options.get(listIndex+1);
|
|
||||||
|
|
||||||
if(clickType.equals(ClickType.LEFT)) this.state = elementBefore;
|
|
||||||
if(clickType.equals(ClickType.RIGHT)) this.state = elementAfter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void fromStorage(PersistentDataContainer container) {
|
|
||||||
this.state = container.has(this.getNamespacedKey())
|
|
||||||
? Integer.valueOf(Objects.requireNonNull(container.get(this.getNamespacedKey(), PersistentDataType.STRING)))
|
|
||||||
: this.defaultValue();
|
|
||||||
|
|
||||||
if(!this.options.contains(this.state)) this.state = this.defaultValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void toStorage(PersistentDataContainer container, Integer value) {
|
|
||||||
container.set(this.getNamespacedKey(), PersistentDataType.STRING, new Gson().toJson(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> dataType() {
|
|
||||||
return Integer.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer state() {
|
|
||||||
return this.state;
|
|
||||||
}
|
|
||||||
}
|
|
@ -17,7 +17,7 @@ import org.bukkit.persistence.PersistentDataContainer;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public abstract class Setting<TDataType> {
|
public abstract class Setting<TDataType> {
|
||||||
protected TDataType state;
|
TDataType state;
|
||||||
private final Settings.Key key;
|
private final Settings.Key key;
|
||||||
|
|
||||||
public Setting(Settings.Key key) {
|
public Setting(Settings.Key key) {
|
||||||
|
@ -73,7 +73,3 @@ endPrevent:
|
|||||||
endDisabled: true
|
endDisabled: true
|
||||||
|
|
||||||
spawnpoint:
|
spawnpoint:
|
||||||
shrinkingBorder:
|
|
||||||
minimumSize: 10
|
|
||||||
shrinkPerDay: 10
|
|
||||||
shrinkTime: 03:00
|
|
||||||
|
@ -1,109 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.shrinkingBorder;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.core.Main;
|
|
||||||
import eu.mhsl.craftattack.core.appliance.Appliance;
|
|
||||||
import eu.mhsl.craftattack.core.appliance.ApplianceCommand;
|
|
||||||
import eu.mhsl.craftattack.core.config.Configuration;
|
|
||||||
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.WorldBorder;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.time.LocalTime;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class ShrinkingBorder extends Appliance {
|
|
||||||
private final String shrinkPerDayKey = "shrinkPerDay";
|
|
||||||
private final String shrinkTimeKey = "shrinkTime";
|
|
||||||
private final String minimumSizeKey = "minimumSize";
|
|
||||||
public int shrinkPerDay;
|
|
||||||
public LocalTime shrinkTime;
|
|
||||||
public int minimumSize;
|
|
||||||
private final Timer timer = new Timer();
|
|
||||||
private final Calendar calendar = Calendar.getInstance(TimeZone.getDefault());
|
|
||||||
|
|
||||||
private final WorldBorder overworldBorder = Bukkit.getWorlds().stream()
|
|
||||||
.filter(world -> world.getEnvironment().equals(World.Environment.NORMAL))
|
|
||||||
.findFirst().orElseThrow().getWorldBorder();
|
|
||||||
private final WorldBorder netherBorder = Bukkit.getWorlds().stream()
|
|
||||||
.filter(world -> world.getEnvironment().equals(World.Environment.NETHER))
|
|
||||||
.findFirst().orElseThrow().getWorldBorder();
|
|
||||||
|
|
||||||
private class ShrinkBorderTask extends TimerTask {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Bukkit.getScheduler().runTask(Main.instance(), ShrinkingBorder.this::shrinkBorder);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onEnable() {
|
|
||||||
Settings.instance().declareSetting(ShrinkingBorderSetting.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShrinkingBorder() {
|
|
||||||
super("shrinkingBorder");
|
|
||||||
this.shrinkPerDay = this.localConfig().getInt(this.shrinkPerDayKey, 10);
|
|
||||||
this.shrinkTime = LocalTime.parse(this.localConfig().getString(this.shrinkTimeKey, LocalTime.of(3, 0, 0).toString()));
|
|
||||||
this.minimumSize = this.localConfig().getInt(this.minimumSizeKey, 10);
|
|
||||||
|
|
||||||
this.calendar.set(Calendar.HOUR_OF_DAY, this.shrinkTime.getHour());
|
|
||||||
this.calendar.set(Calendar.MINUTE, this.shrinkTime.getMinute());
|
|
||||||
this.calendar.set(Calendar.SECOND, this.shrinkTime.getSecond());
|
|
||||||
|
|
||||||
if(this.calendar.getTime().before(new Date(System.currentTimeMillis()))) {
|
|
||||||
this.calendar.add(Calendar.DAY_OF_MONTH, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.timer.schedule(new ShrinkBorderTask(), this.calendar.getTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void shrinkBorder() {
|
|
||||||
this.overworldBorder.setSize(Math.max(this.overworldBorder.getSize()-this.shrinkPerDay, this.minimumSize));
|
|
||||||
this.netherBorder.setSize(Math.max(this.netherBorder.getSize()-this.shrinkPerDay, this.minimumSize));
|
|
||||||
|
|
||||||
this.calendar.add(Calendar.DAY_OF_MONTH, 1);
|
|
||||||
this.timer.schedule(new ShrinkBorderTask(), this.calendar.getTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void changeOption(ShrinkingBorderCommand.Argument option, int value) {
|
|
||||||
switch (option) {
|
|
||||||
case MINIMUM_SIZE -> {
|
|
||||||
this.minimumSize = value;
|
|
||||||
this.localConfig().set(this.minimumSizeKey, value);
|
|
||||||
}
|
|
||||||
case SHRINK_PER_DAY -> {
|
|
||||||
this.shrinkPerDay = value;
|
|
||||||
this.localConfig().set(this.shrinkPerDayKey, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Configuration.saveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getOption(ShrinkingBorderCommand.Argument option) {
|
|
||||||
switch (option) {
|
|
||||||
case MINIMUM_SIZE -> {
|
|
||||||
return this.minimumSize;
|
|
||||||
}
|
|
||||||
case SHRINK_PER_DAY -> {
|
|
||||||
return this.shrinkPerDay;
|
|
||||||
}
|
|
||||||
default -> {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected @NotNull List<ApplianceCommand<?>> commands() {
|
|
||||||
return List.of(new ShrinkingBorderCommand());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected @NotNull List<Listener> listeners() {
|
|
||||||
return List.of(new ShrinkingBorderListener());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.shrinkingBorder;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.core.appliance.ApplianceCommand;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ShrinkingBorderCommand extends ApplianceCommand<ShrinkingBorder> {
|
|
||||||
public enum Argument {
|
|
||||||
SHRINK_PER_DAY("shrinkPerDay"),
|
|
||||||
MINIMUM_SIZE("minimumSize");
|
|
||||||
|
|
||||||
public final String name;
|
|
||||||
|
|
||||||
Argument(String friendlyName) {
|
|
||||||
this.name = friendlyName;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Argument fromString(String argument) {
|
|
||||||
return Arrays.stream(values()).filter(argument1 -> argument1.name.equals(argument)).findFirst().orElseThrow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ShrinkingBorderCommand() {
|
|
||||||
super("shrinkingBorder");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void execute(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
|
||||||
if(args.length < 1 || args.length > 2) throw new Error("shrinkingBorder command needs one or two arguments");
|
|
||||||
if(Arrays.stream(Argument.values()).noneMatch(argument -> argument.name.equals(args[0]))) throw new Error(String.format("argument %s does not exist", args[0]));
|
|
||||||
Argument option = Argument.fromString(args[0]);
|
|
||||||
|
|
||||||
switch (args.length) {
|
|
||||||
case 1:
|
|
||||||
sender.sendMessage(String.format("%s is currently set to %d", args[0], this.getAppliance().getOption(option)));
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
try {
|
|
||||||
int value = Integer.parseInt(args[1]);
|
|
||||||
this.getAppliance().changeOption(option, value);
|
|
||||||
sender.sendMessage(String.format("%s is now set to %d", args[0], this.getAppliance().getOption(option)));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
throw new Error("second argument has to be an integer");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error("shrinkingBorder command needs one or two arguments");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
|
||||||
if(args.length > 1) return List.of();
|
|
||||||
return Arrays.stream(Argument.values()).map(argument -> argument.name).toList();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.shrinkingBorder;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.core.appliance.ApplianceListener;
|
|
||||||
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.format.TextColor;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.WorldBorder;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.player.PlayerMoveEvent;
|
|
||||||
|
|
||||||
public class ShrinkingBorderListener extends ApplianceListener<ShrinkingBorder> {
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerMove(PlayerMoveEvent event) {
|
|
||||||
if(!event.hasChangedPosition()) return;
|
|
||||||
if(event.getTo().getWorld().getEnvironment().equals(World.Environment.THE_END)) return;
|
|
||||||
if(this.isSave(event.getTo())) return;
|
|
||||||
int remainingDays = this.daysUntilBorder(event.getTo());
|
|
||||||
|
|
||||||
int maxDaysShown = Settings.instance().getSetting(event.getPlayer(), Settings.Key.BorderWarning, Integer.class);
|
|
||||||
|
|
||||||
if(remainingDays > maxDaysShown) return;
|
|
||||||
|
|
||||||
String actionBarText;
|
|
||||||
if(remainingDays <= 0) {
|
|
||||||
actionBarText = "Du befindest dich in der Worldborder!";
|
|
||||||
} else {
|
|
||||||
actionBarText = String.format("In %d Tagen ist die Worldborder hier!", remainingDays);
|
|
||||||
}
|
|
||||||
|
|
||||||
event.getPlayer().sendActionBar(Component.text(
|
|
||||||
actionBarText,
|
|
||||||
TextColor.color(255, 0, 0)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
private int daysUntilBorder(Location playerLocation) {
|
|
||||||
WorldBorder worldBorder = playerLocation.getWorld().getWorldBorder();
|
|
||||||
Location relativeLocation = playerLocation.clone().subtract(worldBorder.getCenter());
|
|
||||||
double playerBorderDistanceX = worldBorder.getSize()/2 - Math.abs(relativeLocation.getX());
|
|
||||||
double playerBorderDistanceZ = worldBorder.getSize()/2 - Math.abs(relativeLocation.getZ());
|
|
||||||
int xSteps = (int) Math.ceil(playerBorderDistanceX / this.getAppliance().getOption(ShrinkingBorderCommand.Argument.SHRINK_PER_DAY));
|
|
||||||
int zSteps = (int) Math.ceil(playerBorderDistanceZ / this.getAppliance().getOption(ShrinkingBorderCommand.Argument.SHRINK_PER_DAY));
|
|
||||||
return Math.min(xSteps, zSteps);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isSave(Location playerLocation) {
|
|
||||||
WorldBorder worldBorder = playerLocation.getWorld().getWorldBorder();
|
|
||||||
Location relativeLocation = playerLocation.clone().subtract(worldBorder.getCenter());
|
|
||||||
if(Math.abs(relativeLocation.getX()) > this.getAppliance().getOption(ShrinkingBorderCommand.Argument.MINIMUM_SIZE)) return false;
|
|
||||||
if(Math.abs(relativeLocation.getZ()) > this.getAppliance().getOption(ShrinkingBorderCommand.Argument.MINIMUM_SIZE)) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
package eu.mhsl.craftattack.spawn.varo.appliances.metaGameplay.shrinkingBorder;
|
|
||||||
|
|
||||||
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.CategorizedSetting;
|
|
||||||
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.SettingCategory;
|
|
||||||
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.Settings;
|
|
||||||
import eu.mhsl.craftattack.spawn.common.appliances.metaGameplay.settings.datatypes.IntegerSetting;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ShrinkingBorderSetting extends IntegerSetting implements CategorizedSetting {
|
|
||||||
public ShrinkingBorderSetting() {
|
|
||||||
super(
|
|
||||||
Settings.Key.BorderWarning,
|
|
||||||
List.of(0, 1, 2, 3)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SettingCategory category() {
|
|
||||||
return SettingCategory.Gameplay;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String title() {
|
|
||||||
return "Warnung vor der Worldborder";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String description() {
|
|
||||||
return "Warnt vor der Worldborder";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Material icon() {
|
|
||||||
return Material.BARRIER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Integer defaultValue() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user