Use new YML format for animations
This commit is contained in:
parent
de3366a8a2
commit
016de63f93
|
@ -31,7 +31,7 @@ import me.filoghost.holographicdisplays.plugin.listener.UpdateNotificationListen
|
|||
import me.filoghost.holographicdisplays.plugin.log.PrintableErrorCollector;
|
||||
import me.filoghost.holographicdisplays.plugin.placeholder.TickClock;
|
||||
import me.filoghost.holographicdisplays.plugin.placeholder.TickingTask;
|
||||
import me.filoghost.holographicdisplays.plugin.placeholder.internal.AnimationRegistry;
|
||||
import me.filoghost.holographicdisplays.plugin.placeholder.internal.AnimationPlaceholderFactory;
|
||||
import me.filoghost.holographicdisplays.plugin.placeholder.internal.DefaultPlaceholders;
|
||||
import me.filoghost.holographicdisplays.plugin.placeholder.registry.PlaceholderRegistry;
|
||||
import me.filoghost.holographicdisplays.plugin.placeholder.tracking.PlaceholderTracker;
|
||||
|
@ -42,7 +42,6 @@ import org.bukkit.Bukkit;
|
|||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class HolographicDisplays extends FCommonsPlugin {
|
||||
|
@ -53,7 +52,6 @@ public class HolographicDisplays extends FCommonsPlugin {
|
|||
private ConfigManager configManager;
|
||||
private InternalHologramManager internalHologramManager;
|
||||
private BungeeServerTracker bungeeServerTracker;
|
||||
private AnimationRegistry animationRegistry;
|
||||
private PlaceholderRegistry placeholderRegistry;
|
||||
private LineTrackerManager lineTrackerManager;
|
||||
|
||||
|
@ -97,7 +95,6 @@ public class HolographicDisplays extends FCommonsPlugin {
|
|||
|
||||
configManager = new ConfigManager(getDataFolder().toPath());
|
||||
bungeeServerTracker = new BungeeServerTracker(this);
|
||||
animationRegistry = new AnimationRegistry();
|
||||
placeholderRegistry = new PlaceholderRegistry();
|
||||
TickClock tickClock = new TickClock();
|
||||
PlaceholderTracker placeholderTracker = new PlaceholderTracker(placeholderRegistry, tickClock);
|
||||
|
@ -160,21 +157,17 @@ public class HolographicDisplays extends FCommonsPlugin {
|
|||
}
|
||||
|
||||
public void load(boolean deferHologramsCreation, ErrorCollector errorCollector) {
|
||||
DefaultPlaceholders.resetAndRegister(this, placeholderRegistry, animationRegistry, bungeeServerTracker);
|
||||
|
||||
internalHologramManager.clearAll();
|
||||
|
||||
configManager.reloadStaticReplacements(errorCollector);
|
||||
configManager.reloadMainSettings(errorCollector);
|
||||
HologramDatabase hologramDatabase = configManager.loadHologramDatabase(errorCollector);
|
||||
try {
|
||||
animationRegistry.loadAnimations(configManager, errorCollector);
|
||||
} catch (IOException | ConfigException e) {
|
||||
errorCollector.add(e, "failed to load animation files");
|
||||
}
|
||||
|
||||
AnimationPlaceholderFactory animationPlaceholderFactory = configManager.loadAnimations(errorCollector);
|
||||
DefaultPlaceholders.resetAndRegister(this, placeholderRegistry, animationPlaceholderFactory, bungeeServerTracker);
|
||||
|
||||
bungeeServerTracker.restart(Settings.bungeeRefreshSeconds, TimeUnit.SECONDS);
|
||||
|
||||
HologramDatabase hologramDatabase = configManager.loadHologramDatabase(errorCollector);
|
||||
if (deferHologramsCreation) {
|
||||
// For the initial load: holograms are loaded later, when the worlds are ready
|
||||
Bukkit.getScheduler().runTask(this, () -> hologramDatabase.createHolograms(internalHologramManager, errorCollector));
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.plugin.config;
|
||||
|
||||
import me.filoghost.fcommons.config.mapped.MappedConfig;
|
||||
import me.filoghost.fcommons.config.mapped.Path;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class AnimationConfig implements MappedConfig {
|
||||
|
||||
@Path("interval-seconds")
|
||||
private double intervalSeconds;
|
||||
|
||||
@Path("animation-frames")
|
||||
private List<String> frames;
|
||||
|
||||
public int getIntervalTicks() {
|
||||
return Math.max((int) (intervalSeconds * 20.0), 1);
|
||||
}
|
||||
|
||||
public List<String> getFrames() {
|
||||
return frames;
|
||||
}
|
||||
|
||||
}
|
|
@ -11,12 +11,21 @@ import me.filoghost.fcommons.config.ConfigErrors;
|
|||
import me.filoghost.fcommons.config.ConfigLoader;
|
||||
import me.filoghost.fcommons.config.FileConfig;
|
||||
import me.filoghost.fcommons.config.exception.ConfigException;
|
||||
import me.filoghost.fcommons.config.exception.ConfigLoadException;
|
||||
import me.filoghost.fcommons.config.exception.ConfigSaveException;
|
||||
import me.filoghost.fcommons.config.mapped.MappedConfigLoader;
|
||||
import me.filoghost.fcommons.logging.ErrorCollector;
|
||||
import me.filoghost.fcommons.logging.Log;
|
||||
import me.filoghost.holographicdisplays.plugin.hologram.internal.InternalHologramManager;
|
||||
import me.filoghost.holographicdisplays.plugin.placeholder.internal.AnimationPlaceholder;
|
||||
import me.filoghost.holographicdisplays.plugin.placeholder.internal.AnimationPlaceholderFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ConfigManager extends BaseConfigManager {
|
||||
|
||||
|
@ -67,6 +76,45 @@ public class ConfigManager extends BaseConfigManager {
|
|||
}
|
||||
}
|
||||
|
||||
public AnimationPlaceholderFactory loadAnimations(ErrorCollector errorCollector) {
|
||||
Map<String, AnimationPlaceholder> animationsByFileName = new HashMap<>();
|
||||
Path animationsFolder = getAnimationsFolder();
|
||||
|
||||
try {
|
||||
if (!Files.isDirectory(animationsFolder)) {
|
||||
Files.createDirectories(animationsFolder);
|
||||
try {
|
||||
Path exampleAnimationFile = animationsFolder.resolve("example.yml");
|
||||
getConfigLoader(exampleAnimationFile).createDefault();
|
||||
} catch (ConfigSaveException e) {
|
||||
errorCollector.add(e, "could not add example animation file");
|
||||
}
|
||||
}
|
||||
|
||||
try (Stream<Path> animationFiles = Files.list(animationsFolder)) {
|
||||
animationFiles.filter(this::isYamlFile).forEach(file -> {
|
||||
try {
|
||||
String fileName = file.getFileName().toString();
|
||||
AnimationPlaceholder animationPlaceholder = loadAnimation(file);
|
||||
animationsByFileName.put(fileName, animationPlaceholder);
|
||||
} catch (ConfigLoadException e) {
|
||||
logConfigInitException(errorCollector, file, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (IOException e) {
|
||||
errorCollector.add(e, "error loading animation files");
|
||||
}
|
||||
|
||||
return new AnimationPlaceholderFactory(animationsByFileName);
|
||||
}
|
||||
|
||||
private AnimationPlaceholder loadAnimation(Path animationFile) throws ConfigLoadException {
|
||||
MappedConfigLoader<AnimationConfig> animationConfigLoader = getMappedConfigLoader(animationFile, AnimationConfig.class);
|
||||
AnimationConfig animationConfig = animationConfigLoader.load();
|
||||
return new AnimationPlaceholder(animationConfig.getIntervalTicks(), animationConfig.getFrames());
|
||||
}
|
||||
|
||||
public void reloadStaticReplacements(ErrorCollector errorCollector) {
|
||||
FileConfig staticReplacementsConfig;
|
||||
|
||||
|
@ -84,12 +132,16 @@ public class ConfigManager extends BaseConfigManager {
|
|||
return getRootDataFolder().resolve("animations");
|
||||
}
|
||||
|
||||
public ConfigLoader getExampleAnimationLoader() {
|
||||
return getConfigLoader(getAnimationsFolder().resolve("example.txt"));
|
||||
private boolean isYamlFile(Path file) {
|
||||
if (!Files.isRegularFile(file)) {
|
||||
return false;
|
||||
}
|
||||
String fileName = file.getFileName().toString().toLowerCase();
|
||||
return fileName.endsWith(".yml") || fileName.endsWith(".yaml");
|
||||
}
|
||||
|
||||
private void logConfigInitException(ErrorCollector errorCollector, Path file, ConfigException e) {
|
||||
errorCollector.add(e, "error while initializing config file \"" + formatPath(file) + "\"");
|
||||
errorCollector.add(e, "error while loading config file \"" + formatPath(file) + "\"");
|
||||
}
|
||||
|
||||
private String formatPath(Path path) {
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
*/
|
||||
package me.filoghost.holographicdisplays.plugin.placeholder.internal;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import me.filoghost.fcommons.Preconditions;
|
||||
import me.filoghost.holographicdisplays.api.placeholder.Placeholder;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -12,12 +14,13 @@ import java.util.List;
|
|||
public class AnimationPlaceholder implements Placeholder {
|
||||
|
||||
private final int refreshIntervalTicks;
|
||||
private final List<String> frames;
|
||||
private final ImmutableList<String> frames;
|
||||
private int currentIndex;
|
||||
|
||||
public AnimationPlaceholder(int refreshIntervalTicks, List<String> frames) {
|
||||
this.frames = frames;
|
||||
Preconditions.notEmpty(frames, "frames");
|
||||
this.refreshIntervalTicks = refreshIntervalTicks;
|
||||
this.frames = ImmutableList.copyOf(frames);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.plugin.placeholder.internal;
|
||||
|
||||
import me.filoghost.fcommons.collection.CaseInsensitiveHashMap;
|
||||
import me.filoghost.fcommons.collection.CaseInsensitiveMap;
|
||||
import me.filoghost.holographicdisplays.api.placeholder.Placeholder;
|
||||
import me.filoghost.holographicdisplays.api.placeholder.PlaceholderFactory;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class AnimationPlaceholderFactory implements PlaceholderFactory {
|
||||
|
||||
private final CaseInsensitiveMap<Placeholder> animationsByFileName;
|
||||
|
||||
public AnimationPlaceholderFactory(Map<String, AnimationPlaceholder> animationsByFileName) {
|
||||
this.animationsByFileName = new CaseInsensitiveHashMap<>();
|
||||
this.animationsByFileName.putAllString(animationsByFileName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Placeholder getPlaceholder(String fileNameArgument) {
|
||||
Placeholder placeholder = animationsByFileName.get(fileNameArgument);
|
||||
if (placeholder != null) {
|
||||
return placeholder;
|
||||
} else {
|
||||
return new StaticPlaceholder("[Animation not found: " + fileNameArgument + "]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) filoghost and contributors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
package me.filoghost.holographicdisplays.plugin.placeholder.internal;
|
||||
|
||||
import me.filoghost.fcommons.config.exception.ConfigSaveException;
|
||||
import me.filoghost.fcommons.logging.ErrorCollector;
|
||||
import me.filoghost.holographicdisplays.api.placeholder.Placeholder;
|
||||
import me.filoghost.holographicdisplays.api.placeholder.PlaceholderFactory;
|
||||
import me.filoghost.holographicdisplays.common.DebugLogger;
|
||||
import me.filoghost.holographicdisplays.plugin.config.ConfigManager;
|
||||
import me.filoghost.holographicdisplays.plugin.format.DisplayFormat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class AnimationRegistry implements PlaceholderFactory {
|
||||
|
||||
private static final String SPEED_PREFIX = "speed:";
|
||||
|
||||
private final Map<String, Placeholder> animationsByFilename = new HashMap<>();
|
||||
|
||||
public void loadAnimations(ConfigManager configManager, ErrorCollector errorCollector) throws IOException, ConfigSaveException {
|
||||
animationsByFilename.clear();
|
||||
Path animationFolder = configManager.getAnimationsFolder();
|
||||
|
||||
if (!Files.isDirectory(animationFolder)) {
|
||||
Files.createDirectories(animationFolder);
|
||||
configManager.getExampleAnimationLoader().createDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
try (Stream<Path> animationFiles = Files.list(animationFolder)) {
|
||||
animationFiles.forEach(file -> readAnimationFile(file, errorCollector));
|
||||
}
|
||||
}
|
||||
|
||||
private void readAnimationFile(Path file, ErrorCollector errorCollector) {
|
||||
String fileName = file.getFileName().toString();
|
||||
|
||||
try {
|
||||
List<String> lines = Files.readAllLines(file);
|
||||
if (lines.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
double speed = 0.5;
|
||||
boolean validSpeedFound = false;
|
||||
|
||||
String firstLine = lines.get(0).trim();
|
||||
if (firstLine.toLowerCase().startsWith(SPEED_PREFIX)) {
|
||||
// Do not consider it
|
||||
lines.remove(0);
|
||||
|
||||
firstLine = firstLine.substring(SPEED_PREFIX.length()).trim();
|
||||
|
||||
try {
|
||||
speed = Double.parseDouble(firstLine);
|
||||
validSpeedFound = true;
|
||||
} catch (NumberFormatException ignored) {}
|
||||
}
|
||||
|
||||
if (!validSpeedFound) {
|
||||
errorCollector.add("could not find a valid \"" + SPEED_PREFIX + " <number>\""
|
||||
+ " in the first line of the file \"" + fileName + "\","
|
||||
+ " default speed of 0.5 seconds will be used");
|
||||
}
|
||||
|
||||
if (lines.isEmpty()) {
|
||||
lines.add("[No lines: " + fileName + "]");
|
||||
errorCollector.add("could not find any line in \"" + fileName + "\" (excluding the speed),"
|
||||
+ " you should add at least one more line");
|
||||
}
|
||||
|
||||
// Add colors and formatting to lines
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
lines.set(i, DisplayFormat.apply(lines.get(i)));
|
||||
}
|
||||
|
||||
int refreshIntervalTicks = Math.max((int) (speed * 20.0), 1);
|
||||
animationsByFilename.put(fileName, new AnimationPlaceholder(refreshIntervalTicks, lines));
|
||||
DebugLogger.info("Successfully loaded animation \"" + fileName + "\", speed = " + speed + ".");
|
||||
|
||||
} catch (Exception e) {
|
||||
errorCollector.add(e, "couldn't load the animation file \"" + fileName + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Placeholder getPlaceholder(String fileNameArgument) {
|
||||
Placeholder placeholder = animationsByFilename.get(fileNameArgument);
|
||||
if (placeholder != null) {
|
||||
return placeholder;
|
||||
} else {
|
||||
return new StaticPlaceholder("[Animation not found: " + fileNameArgument + "]");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -26,7 +26,7 @@ public class DefaultPlaceholders {
|
|||
public static void resetAndRegister(
|
||||
Plugin plugin,
|
||||
PlaceholderRegistry placeholderRegistry,
|
||||
AnimationRegistry animationRegistry,
|
||||
AnimationPlaceholderFactory animationPlaceholderFactory,
|
||||
BungeeServerTracker bungeeServerTracker) {
|
||||
placeholderRegistry.unregisterAll(plugin);
|
||||
|
||||
|
@ -47,7 +47,7 @@ public class DefaultPlaceholders {
|
|||
return Settings.timeFormat.format(Instant.now());
|
||||
});
|
||||
|
||||
placeholderRegistry.registerGlobalPlaceholderFactory(plugin, "animation", animationRegistry);
|
||||
placeholderRegistry.registerGlobalPlaceholderFactory(plugin, "animation", animationPlaceholderFactory);
|
||||
|
||||
placeholderRegistry.registerGlobalPlaceholderFactory(plugin, "world", new WorldPlayersPlaceholderFactory());
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
Speed: 0.5
|
||||
This is an example.
|
||||
This line will change every 0.5 seconds...
|
||||
because it's an animation.
|
||||
You just have to put "{animation: example.txt}" in a hologram...
|
||||
to see this animated text.
|
|
@ -0,0 +1,7 @@
|
|||
interval-seconds: 0.5
|
||||
animation-frames:
|
||||
- "This is an example."
|
||||
- "This line will change every 0.5 seconds..."
|
||||
- "because it's an animation."
|
||||
- "You just have to put {animation: example.yml} in a hologram..."
|
||||
- "to see this animated text."
|
Loading…
Reference in New Issue