Skip to content

Create Configurations

Eric Lam edited this page Jun 13, 2022 · 3 revisions

Create A Single Configuration

ELDependenci using ORM to create the configuration, (no more getType)!

name: "hello world"
number: 12
bool: true
box:
  name: "box abc"
  size: 20
  color: RED

can be mapped with

@Resource(locate = "config.yml") // locate your file
public class TestConfig extends Configuration {
    public String name;
    public int number;
    public boolean bool;
    public Box box;

    public static class Box {
        public String name;
        public int size;
        public ChatColor color;
   }
}

then, register in your main class:

    @Override
    public void bindServices(ServiceCollection serviceCollection) {
        serviceCollection.addConfiguration(TestConfig.class); // register config
    }

How to get it?

you can inject it into any of your commands, listeners, or any registered singleton and services

examples:

@Commander(
        name = "edit",
        description = "config edit command"
)
public class TestConfigEditCommand  implements CommandNode {

    private final Random random = new Random();

    @Inject //inject
    private TestConfig config;

    @Override
    public void execute(CommandSender commandSender) {
        config.bool = random.nextBoolean();
        config.name = UUID.randomUUID().toString();
        config.number = random.nextInt();
        config.box = new TestConfig.Box();
        config.box.color = ChatColor.values()[random.nextInt(ChatColor.values().length)];
        config.box.name = UUID.randomUUID().toString()+" box";
        config.box.size = random.nextInt();

        try {
            config.getController().save();
            commandSender.sendMessage("save completed");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
public class TestListeners implements Listener {

    @Inject //inject!
    private TestConfig config;

    @EventHandler
    public void onPlayerChat(AsyncPlayerChatEvent e) {
        if (e.getMessage().equals("config")) {
            e.getPlayer().sendMessage(config.toString());
        }
    }
}

Reload Or Save Your Configuration

the config instance will have a getController() method, so that you can use the save() and reload() method.

Create A Message Configuration

to create a configuration that only contains messages, creates a class, and extends LangConfiguration.

assume you have lang.yml

prefix: "&a[Plugin]&r"
hello: "&ahello world!"
bye: "&7good bye!"

then the class will be like:

@Prefix(path = "prefix")
@Resource(locate = "lang.yml")
public class LangConfig extends LangConfiguration {
}

and then register:

    @Override
    public void bindServices(ServiceCollection serviceCollection) {
        serviceCollection.addConfiguration(LangConfig.class);
    }

still simple

How to use it?

same as you do in config, inject it.

but instead of using those properties, just calling getLang()

then you will have those methods

/** 
 * ends with F -> String.format, else, it uses MessageFormat.format
 */
public interface LangController {

    String get(String node);

    String get(String node, Object... args);

    String getF(String node, Object... args);

    String getPure(String node);

    String getPure(String node, Object... args);

    String getPureF(String node, Object... args);

    List<String> getList(String node);

    List<String> getPureList(String node);

    String getPrefix();

}

all have been translated color code automatically.

Create A Group Configuration

assume you have a folder structure like this.

YourPlugin/
  |- Books
      |- normal.yml
      |- test.yml

then you can do like this

@GroupResource(folder = "Books")
public class Book extends GroupConfiguration {

    public String title;
    public String author;
    public String description;
    public int pages;
    public List<String> contents;

}

to copy all resources inside jar into the plugin folder when server starts:

@GroupResource(
     folder = "Books",
     preloads = { "normal", "test" }
)
public class Book extends GroupConfiguration {

    public String title;
    public String author;
    public String description;
    public int pages;
    public List<String> contents;

}

the format of the yaml inside that folder must be united:

title: "正常的書名"
author: "正常的作者"
description: "真的很正常的一本書"
pages: 666
contents:
    - "這是一本很正常的書本"
    - "為什麼我會說很正常呢"
    - "因為真的很正常"
    - "正常到你察覺不了他的存在"
    - "oh 當你看到這則訊息的時候代表他重載得很正常。"
title: "測試書本"
author: "愛測試的作者"
description: "這是一本測試的書"
pages: 9999
contents:
    - "測試的重點"
    - "就是必須被測試"
    - "否則就無法測試"
    - "有測試才有實踐"

then register like this in main class:

    @Override
    public void bindServices(ServiceCollection serviceCollection) {
        serviceCollection.addGroupConfiguration(Book.class); //register
    }

How to use it?

instead of using @Inject you need to use @InjectPool for the group config.

@Commander(
        name = "check",
        description = "book chceck command"
)
public class TestBookCheckCommand implements CommandNode {

    @InjectPool // 使用 @InjectPool 而不是 @Inject
    private GroupConfig<Book> bookGroupConfig; // 注入

    @CommandArg(order = 0)
    private String book;

    @Override
    public void execute(CommandSender commandSender) {
        Optional<Book> gp = bookGroupConfig.findById(book);
        if (gp.isEmpty()){
            commandSender.sendMessage("book "+book+" is not exist.");
            return;
        }
        var bookContent = gp.get();
        commandSender.sendMessage("id: "+bookContent.getId());
        commandSender.sendMessage("title: "+ bookContent.title);
        commandSender.sendMessage("author: "+bookContent.author);
        commandSender.sendMessage("description: "+bookContent.description);
        commandSender.sendMessage("total pages: "+bookContent.pages);
        commandSender.sendMessage("content: ");
        for (int i = 0; i < bookContent.contents.size(); i++) {
            commandSender.sendMessage(i+1+": "+bookContent.contents.get(i));
        }
    }
}

here is the source code for GroupConfig<T>

public interface GroupConfig<T extends GroupConfiguration> {

    List<T> findAll();

    List<T> findAll(Predicate<Path> filter);

    Page<T> findAll(PageRequest pageRequest);

    Optional<T> findById(String id);

    void save(T config);

    boolean deleteById(String id);

    long totalSize();

    boolean delete(T config);

    // like reload (clear cache)
    void fetch();

    // like reload (clear cache)
    void fetchById(String id);

}

you can also create a configuration data at runtime:

@Commander(
        name = "add",
        description = "add book"
)
public class TestBookAddCommand implements CommandNode {


    @InjectPool
    private GroupConfig<Book> groupConfig;

    @Inject
    private ScheduleService scheduleService; // 如需使用異步,請自行實現

    @Inject
    private ELDTester plugin;

    @CommandArg(order = 1)
    private String id;

    @CommandArg(order = 1, optional = true)
    private String author = "unknown";

    @Override
    public void execute(CommandSender sender) {
        Book book = new Book();
        book.setId(id); // must set the id
        book.title = "This is a title with id "+id;
        book.author = author;
        book.description = "book with id "+id;
        book.contents = Arrays.asList("this", "is", "a", "content");

        scheduleService
                .runAsync(plugin, () -> groupConfig.save(book))
                .thenRunSync(v -> sender.sendMessage("save completed")).join();
    }
}

and also do the pagination

@Commander(
        name = "page",
        description = "pagination test for books"
)
public class TestBookPageCommand implements CommandNode {

    // custom filter
    private static final Predicate<Path> NO_START_WITH_B = path -> !path.getFileName().toString().startsWith("b");
    private static final Predicate<Path> NO_START_WITH_A = path -> !path.getFileName().toString().startsWith("a");

    @InjectPool
    private GroupConfig<Book> groupConfig;

    @Inject
    private ScheduleService scheduleService;

    @Inject
    private ELDTester plugin;

    @CommandArg(order = 1)
    private int page;

    @CommandArg(order = 2, optional = true)
    private boolean showContent = false;

    @CommandArg(order = 3, optional = true)
    private int size = 10;

    @Override
    public void execute(CommandSender commandSender) {
        int index = Math.max(0, page - 1);
        groupConfig.fetch(); // reload folders
        scheduleService.callAsync(plugin, () -> groupConfig.findAll(PageRequest.of(index, size, NO_START_WITH_B))) // 異步仍然需要自己實現
                .thenRunSync(page -> {
                    commandSender.sendMessage("page size: "+page.getContent().size());
                    page.getContent().forEach(book -> commandSender.sendMessage(showContent ? book.toString() : book.getId()));
                    // get the properties below via Page<T>
                    commandSender.sendMessage(MessageFormat.format("page {0} / {1}, Total Elements: {2}", page.getCurrentPage()+1, page.getTotalPages(), page.getTotalElements()));
                }).join();
    }
}

Multi-Language Configuration

assume you have two languages support

Langs/en-us.yml

prefix: "[ELD] "
first: "This is the first message"
second: "This is the second message"
third: "This is the third message"

Langs/zh-tw.yml

prefix: "[ELD] "
first: "這是第一則信息"
second: "這是第二則訊息"
third: "這是第三則信息"

then you can use it like this

@GroupResource(
        folder = "Langs", // 語言文件的文件夾
        preloads = {"en-us", "zh-tw"} // 複製這兩個文件從 jar 內到 插件資料夾
)
@DefaultLanguage("en-us") // 定義默認語言
@Prefix(path = "prefix") // 定義prefix路徑
public class TesterMultiLang extends GroupLangConfiguration {
}

and register in the main class

    @Override
    public void bindServices(ServiceCollection serviceCollection) {
        serviceCollection.addMultipleLanguages(TesterMultiLang.class); // register multi languages
    }

How to Use It?

instead of using GroupConfig<T> from GroupConfiguration, here you will need to use GroupLang<T> to declare.

@Commander(
        name = "lang",
        description = "test language command"
)
public class TestLanguageCommand implements CommandNode {

    @InjectPool
    private GroupLang<TesterMultiLang> multiLangGroupLang;

    @CommandArg(order = 1)
    private String language;

    @Override
    public void execute(CommandSender commandSender) {
        Optional<TesterMultiLang> multiLangOpt = multiLangGroupLang.getByLocale(language);
        if (multiLangOpt.isEmpty()){
            commandSender.sendMessage("unknown language");
            return;
        }
        var multiLang = multiLangOpt.get();
        commandSender.sendMessage(multiLang.getLang().get("first"));
        commandSender.sendMessage(multiLang.getLang().get("second"));
        commandSender.sendMessage(multiLang.getLang().get("third"));
    }
}

the source code for GroupLang<T> for reference

public interface GroupLang<T extends GroupLangConfiguration> {

    Optional<T> getByLocale(String locale);

    T getDefault();

    void fetchById(String locale);

    void fetch();

}