Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: basic towny integration #334

Merged
merged 28 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
74d6870
beginning work on towny support
broccolai Nov 5, 2023
e5e6e05
improve editorconfig for imports
broccolai Nov 5, 2023
64142ae
feature: add special handlers to registry, move integrations
broccolai Nov 5, 2023
f53fddb
move integration base type into common module
broccolai Nov 5, 2023
a3aef52
feature: add alliance chat for towny
broccolai Nov 5, 2023
e29bcba
add some default formatting for towny channels
broccolai Nov 5, 2023
6f04fc8
Add integration configs
jpenilla Nov 6, 2023
2a4da56
simplify special config channel registration
jpenilla Nov 7, 2023
cb18955
Fix IntegrationConfigContainer.Serializer always moving its node to t…
jpenilla Nov 8, 2023
3a94772
add CarbonPlatformModule
broccolai Nov 8, 2023
098e970
format
broccolai Nov 8, 2023
965d37f
format again
broccolai Nov 8, 2023
f6b2673
Merge branch 'trunk' into feat/towny
broccolai Nov 8, 2023
dc81d75
Merge branch 'trunk' into feat/towny
broccolai Nov 8, 2023
e6dcf95
fix: format again again
broccolai Nov 8, 2023
f978822
fix: modify how CarbonPlatformModule works
broccolai Nov 9, 2023
66a1d62
fix: specify an identifier for resident list channels
broccolai Nov 9, 2023
9528149
Merge branch 'trunk' into feat/towny
jpenilla Nov 9, 2023
2530bce
Add Towny as soft depend
jpenilla Nov 9, 2023
88232e5
Move messages to locale
jpenilla Nov 9, 2023
1bd68c4
Merge branch 'trunk' into feat/towny
jpenilla Nov 9, 2023
c28ac70
sort integration configs
jpenilla Nov 10, 2023
8612059
fix
jpenilla Nov 10, 2023
dee281f
fix 2
jpenilla Nov 10, 2023
7fd821d
adjust towny channel default formats
jpenilla Nov 10, 2023
79641ac
Add `@ConfigHeader`
jpenilla Nov 10, 2023
adb753e
fix
jpenilla Nov 10, 2023
d1cddd0
disable alliance chat by default
jpenilla Nov 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,10 @@ indent_style = space
insert_final_newline = true
max_line_length = off

[*.java]
ij_java_imports_layout = *, |, $*
ij_java_class_count_to_use_import_on_demand = 999
ij_java_names_count_to_use_import_on_demand = 999

[{*.kt,*.kts,*.yml}]
indent_size = 2
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import net.draycia.carbon.common.command.CarbonCommand;
import net.draycia.carbon.common.command.ExecutionCoordinatorHolder;
import net.draycia.carbon.common.config.ConfigManager;
import net.draycia.carbon.common.integration.Integration;
import net.draycia.carbon.common.listeners.Listener;
import net.draycia.carbon.common.messages.CarbonMessages;
import net.draycia.carbon.common.messaging.MessagingManager;
Expand Down Expand Up @@ -122,6 +123,17 @@ protected void init() {
TimeUnit.SECONDS
);

// Integration
final Set<Integration> integrations = this.injector().getInstance(Key.get(new TypeLiteral<>() {}));

for (final Integration integration : integrations) {
if (!integration.eligible()) {
continue;
}

integration.register();
}

// Load channels
this.channelRegistry().loadConfigChannels(this.carbonMessages);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* CarbonChat
*
* Copyright (c) 2023 Josua Parks (Vicarious)
* Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.draycia.carbon.common;

import com.google.inject.AbstractModule;
import com.google.inject.multibindings.Multibinder;
import net.draycia.carbon.common.integration.Integration;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;

@DefaultQualifier(NonNull.class)
public abstract class CarbonPlatformModule extends AbstractModule {

@Override
protected void configure() {
this.configurePlatform();

this.configureIntegrations(
Multibinder.newSetBinder(this.binder(), Integration.class),
Multibinder.newSetBinder(this.binder(), Integration.ConfigMeta.class)
);
}

protected abstract void configurePlatform();

protected void configureIntegrations(
final Multibinder<Integration> integrations,
final Multibinder<Integration.ConfigMeta> configs
) {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Supplier;
import net.draycia.carbon.api.channels.ChannelRegistry;
import net.draycia.carbon.api.channels.ChatChannel;
import net.draycia.carbon.api.event.CarbonEventHandler;
Expand Down Expand Up @@ -74,15 +77,20 @@
@DefaultQualifier(NonNull.class)
public class CarbonChannelRegistry extends ChatListenerInternal implements ChannelRegistry {

private static final String PARTYCHAT_CONF = "partychat.conf";

private final Path configChannelDir;
private final Injector injector;
private final Logger logger;
private final ConfigManager config;
private @MonotonicNonNull Key defaultKey;
private final CarbonMessages carbonMessages;
private final CarbonEventHandler eventHandler;
private final Map<String, SpecialHandler<?>> handlers = new HashMap<>();

private record SpecialHandler<T extends ConfigChatChannel>(Class<T> cls, Supplier<T> defaultSupplier) {}

public <T extends ConfigChatChannel> void registerSpecialConfigChannel(final String fileName, final Class<T> type) {
this.handlers.put(fileName, new SpecialHandler<>(type, () -> this.injector.getInstance(type)));
}

private volatile Registry<Key, ChatChannel> channelRegistry = Registry.create();
private final Set<Key> configChannels = ConcurrentHashMap.newKeySet();
Expand All @@ -106,6 +114,10 @@ public CarbonChannelRegistry(
this.carbonMessages = carbonMessages;
this.eventHandler = events;

if (config.primaryConfig().partyChat().enabled) {
this.registerSpecialConfigChannel(PartyChatChannel.FILE_NAME, PartyChatChannel.class);
}

events.subscribe(CarbonReloadEvent.class, -99, true, event -> this.reloadConfigChannels());
}

Expand Down Expand Up @@ -204,14 +216,10 @@ private void loadConfigChannels_(final CarbonMessages messages) {
this.logger.info("Loading config channels...");
this.defaultKey = this.config.primaryConfig().defaultChannel();

final boolean party = this.config.primaryConfig().partyChat().enabled;
if (party) {
this.saveDefaultPartyConfig();
}
this.saveSpecialDefaults();

List<Path> channelConfigs = FileUtil.listDirectoryEntries(this.configChannelDir, "*.conf");
if (channelConfigs.isEmpty() ||
party && channelConfigs.size() == 1 && channelConfigs.get(0).getFileName().toString().equals(PARTYCHAT_CONF)) {
if (channelConfigs.size() == this.handlers.size()) {
this.saveDefaultChannelConfig();
channelConfigs = FileUtil.listDirectoryEntries(this.configChannelDir, "*.conf");
}
Expand Down Expand Up @@ -251,11 +259,29 @@ private void loadConfigChannels_(final CarbonMessages messages) {
this.logger.info("Registered channels: [" + channels + "]");
}

private void saveSpecialDefaults() {
for (final Map.Entry<String, SpecialHandler<?>> e : this.handlers.entrySet()) {
final Path configFile = this.configChannelDir.resolve(e.getKey());
if (Files.isRegularFile(configFile)) {
continue;
}
try {
final ConfigChatChannel configChannel = e.getValue().defaultSupplier().get();
final ConfigurationLoader<?> loader = this.config.configurationLoader(FileUtil.mkParentDirs(configFile), ConfigManager.extractHeader(e.getValue().cls()));
final ConfigurationNode node = loader.createNode();
node.set(e.getValue().cls(), configChannel);
loader.save(node);
} catch (final IOException exception) {
throw Exceptions.rethrow(exception);
}
}
}

private void saveDefaultChannelConfig() {
try {
final Path configFile = this.configChannelDir.resolve("global.conf");
final ConfigChatChannel configChannel = this.injector.getInstance(ConfigChatChannel.class);
final ConfigurationLoader<?> loader = this.config.configurationLoader(FileUtil.mkParentDirs(configFile));
final ConfigurationLoader<?> loader = this.config.configurationLoader(FileUtil.mkParentDirs(configFile), ConfigManager.extractHeader(ConfigChatChannel.class));
final ConfigurationNode node = loader.createNode();
node.set(ConfigChatChannel.class, configChannel);
loader.save(node);
Expand All @@ -264,30 +290,12 @@ private void saveDefaultChannelConfig() {
}
}

private void saveDefaultPartyConfig() {
final Path configFile = this.configChannelDir.resolve(PARTYCHAT_CONF);
if (Files.isRegularFile(configFile)) {
return;
}
try {
final ConfigChatChannel configChannel = this.injector.getInstance(PartyChatChannel.class);
final ConfigurationLoader<?> loader = this.config.configurationLoader(FileUtil.mkParentDirs(configFile));
final ConfigurationNode node = loader.createNode();
node.set(PartyChatChannel.class, configChannel);
loader.save(node);
} catch (final IOException exception) {
throw Exceptions.rethrow(exception);
}
}

private @Nullable ChatChannel loadChannel(final Path channelFile) {
final ConfigurationLoader<?> loader = this.config.configurationLoader(channelFile);

try {
final Class<? extends ConfigChatChannel> type = this.config.primaryConfig().partyChat().enabled && channelFile.getFileName().toString().equals(PARTYCHAT_CONF)
? PartyChatChannel.class
: ConfigChatChannel.class;
final @Nullable SpecialHandler<?> special = this.handlers.get(channelFile.getFileName().toString());
final Class<? extends ConfigChatChannel> type = special == null ? ConfigChatChannel.class : special.cls();

final ConfigurationLoader<?> loader = this.config.configurationLoader(channelFile, ConfigManager.extractHeader(type));
final ConfigurationNode loaded = updateNode(loader.load());
final @Nullable ConfigChatChannel channel = loaded.get(type);
if (channel == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
@DefaultQualifier(NonNull.class)
public class ConfigChatChannel implements ChatChannel {

private transient @MonotonicNonNull @Inject CarbonServer server;
protected transient @MonotonicNonNull @Inject CarbonServer server;
private transient @MonotonicNonNull @Inject CarbonMessageRenderer renderer;

@Comment("""
Expand Down Expand Up @@ -96,7 +96,7 @@ public class ConfigChatChannel implements ChatChannel {

private @Nullable String commandName = null;

private @Nullable List<String> commandAliases = Collections.emptyList();
protected @Nullable List<String> commandAliases = Collections.emptyList();

private transient @Nullable ConfigChannelMessages carbonMessages = null;

Expand Down Expand Up @@ -125,7 +125,6 @@ public class ConfigChatChannel implements ChatChannel {
@Override
public boolean shouldRegisterCommands() {
return Objects.requireNonNullElse(this.shouldRegisterCommands, true);

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
@DefaultQualifier(NonNull.class)
public class PartyChatChannel extends ConfigChatChannel {

public static final String FILE_NAME = "partychat.conf";

private transient @MonotonicNonNull @Inject CarbonMessages messages;

public PartyChatChannel() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* CarbonChat
*
* Copyright (c) 2023 Josua Parks (Vicarious)
* Contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package net.draycia.carbon.common.config;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Tells Carbon's config loading logic to use {@link #value()}
* as the header in {@link org.spongepowered.configurate.ConfigurationOptions}
* when loading/saving this type as the root node of a document.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ConfigHeader {
String value();
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,18 @@

import com.google.inject.Inject;
import com.google.inject.Singleton;
import io.leangen.geantyref.GenericTypeReflector;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.file.Path;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import net.draycia.carbon.api.event.CarbonEventHandler;
import net.draycia.carbon.common.DataDirectory;
import net.draycia.carbon.common.command.CommandSettings;
import net.draycia.carbon.common.event.events.CarbonReloadEvent;
import net.draycia.carbon.common.integration.Integration;
import net.draycia.carbon.common.serialisation.gson.LocaleSerializerConfigurate;
import net.draycia.carbon.common.util.FileUtil;
import net.kyori.adventure.key.Key;
Expand Down Expand Up @@ -57,6 +61,7 @@ public final class ConfigManager {
private final Path dataDirectory;
private final LocaleSerializerConfigurate locale;
private final Logger logger;
private final Set<Integration.ConfigMeta> integrations;

private volatile @MonotonicNonNull PrimaryConfig primaryConfig = null;

Expand All @@ -65,15 +70,29 @@ private ConfigManager(
final CarbonEventHandler events,
@DataDirectory final Path dataDirectory,
final LocaleSerializerConfigurate locale,
final Logger logger
final Logger logger,
final Set<Integration.ConfigMeta> integrations
) {
this.dataDirectory = dataDirectory;
this.locale = locale;
this.logger = logger;
this.integrations = integrations;

events.subscribe(CarbonReloadEvent.class, -100, true, event -> this.reloadPrimaryConfig());
}

public static @Nullable String extractHeader(final Type type) {
if (type instanceof Class<?> cls) {
final @Nullable ConfigHeader h = cls.getAnnotation(ConfigHeader.class);
if (h == null) {
return null;
}
return h.value();
} else {
return extractHeader(GenericTypeReflector.erase(type));
}
}

public void reloadPrimaryConfig() {
this.logger.info("Reloading configuration....");
final @Nullable PrimaryConfig load = this.load(PrimaryConfig.class, PRIMARY_CONFIG_FILE_NAME);
Expand Down Expand Up @@ -109,17 +128,19 @@ public Map<Key, CommandSettings> loadCommandSettings() {
return load.settings();
}

public ConfigurationLoader<?> configurationLoader(final Path file) {
public ConfigurationLoader<?> configurationLoader(final Path file, final @Nullable String header) {
return HoconConfigurationLoader.builder()
.prettyPrinting(true)
.defaultOptions(opts -> {
final ConfigurateComponentSerializer serializer =
ConfigurateComponentSerializer.configurate();

return opts.shouldCopyDefaults(true)
.header(header)
.serializers(serializerBuilder ->
serializerBuilder.registerAll(serializer.serializers())
.register(Locale.class, this.locale)
.register(IntegrationConfigContainer.class, new IntegrationConfigContainer.Serializer(this.integrations))
.registerAnnotatedObjects(ObjectMapper.factoryBuilder()
.addProcessor(Comment.class, overrideComments())
.build()));
Expand All @@ -145,7 +166,7 @@ private static Processor.Factory<Comment, Object> overrideComments() {
return null;
}

final var loader = this.configurationLoader(file);
final var loader = this.configurationLoader(file, extractHeader(clazz));

try {
final var node = loader.load();
Expand Down