feat: integrated Glyphs library
This commit is contained in:
parent
fadc170c62
commit
e8c588b2b6
@ -10,6 +10,8 @@ import java.net.InetSocketAddress;
|
|||||||
@Log4j2
|
@Log4j2
|
||||||
public class ServerBootstrap {
|
public class ServerBootstrap {
|
||||||
|
|
||||||
|
public static final ClassLoader CLASS_LOADER = ServerBootstrap.class.getClassLoader();
|
||||||
|
|
||||||
private static final String[] LOGO = {
|
private static final String[] LOGO = {
|
||||||
"==============================================",
|
"==============================================",
|
||||||
"Minestom Server Base v3 - by ScarletRedMan",
|
"Minestom Server Base v3 - by ScarletRedMan",
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph;
|
||||||
|
|
||||||
|
public final class GlyphConstants {
|
||||||
|
|
||||||
|
public static final int CHEST_GUI_WIDTH = 176;
|
||||||
|
public static final int DEFAULT_CHAT_WIDTH = 320;
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.compile;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public interface ArbitraryCharacterFactory {
|
||||||
|
|
||||||
|
@NotNull Character nextCharacter() throws IllegalStateException;
|
||||||
|
}
|
||||||
@ -0,0 +1,51 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.compile;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class DefaultArbitraryCharacterFactory implements ArbitraryCharacterFactory {
|
||||||
|
|
||||||
|
private final static Set<Character> reservedCharacters = new HashSet<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
for (char c = 'a'; c <= 'z'; c++) reservedCharacters.add(c);
|
||||||
|
for (char c = 'A'; c <= 'Z'; c++) reservedCharacters.add(c);
|
||||||
|
for (char c = 'а'; c <= 'я'; c++) reservedCharacters.add(c);
|
||||||
|
for (char c = 'А'; c <= 'Я'; c++) reservedCharacters.add(c);
|
||||||
|
for (char c = '0'; c <= '9'; c++) reservedCharacters.add(c);
|
||||||
|
|
||||||
|
reservedCharacters.addAll(Arrays.asList(
|
||||||
|
'!', '?', ':', '$',
|
||||||
|
';', '#', '@', '%',
|
||||||
|
'^', '&', '*', '(',
|
||||||
|
')', '_', '-', '+',
|
||||||
|
'/', '\\', '№', '"',
|
||||||
|
'\'', '{', '}', '[',
|
||||||
|
']', '~', '`', '<', '>',
|
||||||
|
',', '.', '|', '\n', '\r',
|
||||||
|
'\b', '\f', '\t', ' ',
|
||||||
|
'ё', 'Ё', '=')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private char currentChar = '\uA201';
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Character nextCharacter() throws IllegalStateException {
|
||||||
|
if (currentChar == Character.MAX_VALUE) {
|
||||||
|
throw new IllegalStateException("Characters range exceeded");
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
currentChar++;
|
||||||
|
} while (!isCharacterAllowed(currentChar));
|
||||||
|
return currentChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCharacterAllowed(char c) {
|
||||||
|
return !reservedCharacters.contains(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.compile;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import team.unnamed.creative.font.Font;
|
||||||
|
import team.unnamed.creative.font.FontProvider;
|
||||||
|
import team.unnamed.creative.part.ResourcePackPart;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class DefaultGlyphCompiler implements GlyphCompiler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Collection<@NotNull ResourcePackPart> compile(@NotNull Collection<@NotNull ResourceProducer> producers) {
|
||||||
|
Set<ResourcePackPart> fileResources = new HashSet<>();
|
||||||
|
|
||||||
|
Set<Key> fontKeys = producers
|
||||||
|
.stream()
|
||||||
|
.map(ResourceProducer::fontKey)
|
||||||
|
.collect(Collectors.toUnmodifiableSet());
|
||||||
|
|
||||||
|
for (Key key : fontKeys) {
|
||||||
|
List<FontProvider> fontProviders = new ArrayList<>();
|
||||||
|
ArbitraryCharacterFactory characterFactory = new DefaultArbitraryCharacterFactory();
|
||||||
|
for (ResourceProducer producer : producers) {
|
||||||
|
if (producer.fontKey().equals(key)) {
|
||||||
|
producer.produceResources(characterFactory);
|
||||||
|
// Add font providers for current font key
|
||||||
|
fontProviders.addAll(producer.fontProviders());
|
||||||
|
// Add textures to common set with resources
|
||||||
|
fileResources.addAll(producer.textures());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileResources.add(Font.font(key, fontProviders));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
<T> Iterable<T> toIterable(final Stream<T> stream) {
|
||||||
|
return stream::iterator;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.compile;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import team.unnamed.creative.part.ResourcePackPart;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public interface GlyphCompiler {
|
||||||
|
|
||||||
|
static GlyphCompiler instance() {
|
||||||
|
return new DefaultGlyphCompiler();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull Collection<@NotNull ResourcePackPart> compile(@NotNull Collection<@NotNull ResourceProducer> resourceProducerCollection);
|
||||||
|
|
||||||
|
default @NotNull Collection<@NotNull ResourcePackPart> compile(@NotNull ResourceProducer... resourceProducer) {
|
||||||
|
return compile(Arrays.asList(resourceProducer));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.compile;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceAlreadyProducedException;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceNotProducedException;
|
||||||
|
import team.unnamed.creative.font.FontProvider;
|
||||||
|
import team.unnamed.creative.texture.Texture;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public interface ResourceProducer {
|
||||||
|
|
||||||
|
@NotNull Key fontKey();
|
||||||
|
|
||||||
|
boolean produced();
|
||||||
|
|
||||||
|
void produceResources(ArbitraryCharacterFactory characterFactory) throws ResourceAlreadyProducedException;
|
||||||
|
|
||||||
|
@NotNull Collection<@NotNull FontProvider> fontProviders() throws ResourceNotProducedException;
|
||||||
|
|
||||||
|
default @NotNull Collection<@NotNull Texture> textures() throws ResourceNotProducedException {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.font;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.ServerBootstrap;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.GlyphCompiler;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.Glyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.image.TextureProperties;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.image.multicharacter.LanguageGlyphCollection;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.space.SpacesGlyphResourceProducer;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.space.mojang.MojangSpacesGlyph;
|
||||||
|
import ru.dragonestia.msb3.api.util.ResourceFromJar;
|
||||||
|
import team.unnamed.creative.base.Writable;
|
||||||
|
import team.unnamed.creative.part.ResourcePackPart;
|
||||||
|
import team.unnamed.creative.texture.Texture;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GlyphFont {
|
||||||
|
|
||||||
|
public static final SpacesGlyphResourceProducer SPACES = MojangSpacesGlyph.create();
|
||||||
|
private static final Key MINECRAFT_FONT_KEY = Key.key(Glyph.DEFAULT_NAMESPACE, "minecraft_font");
|
||||||
|
private static final Writable MINECRAFT_FONT_IMAGE_WRITABLE = ResourceFromJar.of(ServerBootstrap.CLASS_LOADER, "glyphs/defaults/minecraft_font.png");
|
||||||
|
public static final LanguageGlyphCollection LANGUAGE_GLYPH = minecraftFontGlyphCollection(
|
||||||
|
MINECRAFT_FONT_KEY,
|
||||||
|
Key.key(MINECRAFT_FONT_KEY.asString().concat(".png")),
|
||||||
|
List.of(new TextureProperties(12,-6),
|
||||||
|
new TextureProperties(8,-24),
|
||||||
|
new TextureProperties(8,-36)));
|
||||||
|
|
||||||
|
private GlyphFont() {}
|
||||||
|
|
||||||
|
public static Collection<ResourcePackPart> compile() {
|
||||||
|
return GlyphCompiler.instance().compile(SPACES, LANGUAGE_GLYPH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static @NotNull LanguageGlyphCollection minecraftFontGlyphCollection(@NotNull Key fontKey, @NotNull Key textureKey, @NotNull List<@NotNull TextureProperties> propertiesList) {
|
||||||
|
return LanguageGlyphCollection.of(fontKey,
|
||||||
|
Texture.texture(textureKey, MINECRAFT_FONT_IMAGE_WRITABLE),
|
||||||
|
propertiesList,
|
||||||
|
List.of(" АБВГДЕЖЗИК",
|
||||||
|
"ЛМНОПРСТУФХЦЧШЩЪ",
|
||||||
|
"ЫЬЭЮЯабвгдежзикл",
|
||||||
|
"мнопрстуфхцчшщъы",
|
||||||
|
"ьэюяйЙёЁ ",
|
||||||
|
"₽!\"#$%&'()*+,-./",
|
||||||
|
"0123456789: <=>?",
|
||||||
|
"@ABCDEFGHIJKLMNO",
|
||||||
|
"PQRSTUVWXYZ[\\]^_",
|
||||||
|
"`abcdefghijklmno",
|
||||||
|
"pqrstuvwxyz{|} ")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph;
|
||||||
|
|
||||||
|
public interface AppendableGlyph extends Glyph {}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceNotProducedException;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||||
|
public class EmptyGlyph implements AppendableGlyph {
|
||||||
|
|
||||||
|
public static final EmptyGlyph INSTANCE = new EmptyGlyph();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Component toAdventure() throws ResourceNotProducedException {
|
||||||
|
return Component.text("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int width() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceNotProducedException;
|
||||||
|
|
||||||
|
public interface Glyph {
|
||||||
|
|
||||||
|
String DEFAULT_NAMESPACE = "glyphs";
|
||||||
|
|
||||||
|
Key DEFAULT_FONT_KEY = Key.key(DEFAULT_NAMESPACE, "default");
|
||||||
|
|
||||||
|
Key DEFAULT_SPACES_FONT_KEY = Key.key(DEFAULT_NAMESPACE, "spaces");
|
||||||
|
|
||||||
|
int SEPARATOR_WIDTH = 1;
|
||||||
|
|
||||||
|
@NotNull Component toAdventure() throws ResourceNotProducedException;
|
||||||
|
|
||||||
|
int width();
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.space.SpacesGlyphResourceProducer;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface GlyphComponentBuilder {
|
||||||
|
|
||||||
|
static @NotNull GlyphComponentBuilder universal(SpacesGlyphResourceProducer spacesProducer) {
|
||||||
|
return new GlyphComponentBuilderImpl(spacesProducer, 0, Component.text(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
static @NotNull GlyphComponentBuilder gui(SpacesGlyphResourceProducer spacesProducer) {
|
||||||
|
return new GlyphComponentBuilderImpl(spacesProducer, -8, Component.text("", NamedTextColor.WHITE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull GlyphComponentBuilder append(PositionType positionType, int position, @NotNull AppendableGlyph glyph);
|
||||||
|
|
||||||
|
default @NotNull GlyphComponentBuilder append(PositionType positionType, @NotNull AppendableGlyph glyph) {
|
||||||
|
return append(positionType, 0, glyph);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull GlyphComponentBuilder append(PositionType positionType, int position, @NotNull List<? extends @NotNull AppendableGlyph> glyphList);
|
||||||
|
|
||||||
|
default @NotNull GlyphComponentBuilder append(PositionType positionType, @NotNull List<? extends @NotNull AppendableGlyph> glyphList) {
|
||||||
|
return append(positionType, 0, glyphList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append with default position type
|
||||||
|
|
||||||
|
default @NotNull GlyphComponentBuilder append(int position, @NotNull AppendableGlyph glyph) {
|
||||||
|
return append(PositionType.ABSOLUTE, position, glyph);
|
||||||
|
}
|
||||||
|
|
||||||
|
default @NotNull GlyphComponentBuilder append(@NotNull AppendableGlyph glyph) {
|
||||||
|
return append(PositionType.ABSOLUTE, glyph);
|
||||||
|
}
|
||||||
|
|
||||||
|
default @NotNull GlyphComponentBuilder append(int position, @NotNull List<? extends @NotNull AppendableGlyph> glyphList) {
|
||||||
|
return append(PositionType.ABSOLUTE, position, glyphList);
|
||||||
|
}
|
||||||
|
|
||||||
|
default @NotNull GlyphComponentBuilder append(@NotNull List<? extends @NotNull AppendableGlyph> glyphList) {
|
||||||
|
return append(PositionType.ABSOLUTE, glyphList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull Component build(boolean keepInitialPosition);
|
||||||
|
|
||||||
|
default @NotNull Component build() {
|
||||||
|
return build(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PositionType {
|
||||||
|
ABSOLUTE,
|
||||||
|
RELATIVE
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,86 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.space.SpacesGlyphResourceProducer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
|
public class GlyphComponentBuilderImpl implements GlyphComponentBuilder {
|
||||||
|
|
||||||
|
private final SpacesGlyphResourceProducer spacesProducer;
|
||||||
|
private final int initialPosition;
|
||||||
|
private final Component baseComponent;
|
||||||
|
|
||||||
|
private final List<Glyph> glyphs = new ArrayList<>();
|
||||||
|
|
||||||
|
private int previousElementsWidth;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull GlyphComponentBuilder append(PositionType positionType, int position, @NotNull AppendableGlyph glyph) {
|
||||||
|
if (positionType == PositionType.ABSOLUTE && previousElementsWidth != 0) {
|
||||||
|
glyphs.add(spacesProducer.translate((-1) * previousElementsWidth));
|
||||||
|
previousElementsWidth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position != 0) {
|
||||||
|
glyphs.add(spacesProducer.translate(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
glyphs.add(glyph);
|
||||||
|
this.previousElementsWidth += position + glyph.width();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull GlyphComponentBuilder append(PositionType positionType, int position, @NotNull List<? extends @NotNull AppendableGlyph> glyphList) {
|
||||||
|
if (positionType == PositionType.ABSOLUTE && previousElementsWidth != 0) {
|
||||||
|
glyphs.add(spacesProducer.translate((-1) * previousElementsWidth));
|
||||||
|
previousElementsWidth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (position != 0) {
|
||||||
|
glyphs.add(spacesProducer.translate(position));
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = 0;
|
||||||
|
for (AppendableGlyph glyph : glyphList) {
|
||||||
|
glyphs.add(glyph);
|
||||||
|
width += glyph.width();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.previousElementsWidth += position + width;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Component build(boolean keepInitialPosition) {
|
||||||
|
if (keepInitialPosition) {
|
||||||
|
previousElementsWidth += initialPosition;
|
||||||
|
|
||||||
|
// Component should have zero width finally
|
||||||
|
if (previousElementsWidth != 0) {
|
||||||
|
glyphs.add(spacesProducer.translate((-1) * previousElementsWidth));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var component = baseComponent;
|
||||||
|
|
||||||
|
if (initialPosition != 0) {
|
||||||
|
component = component.append(spacesProducer.translate(initialPosition).toAdventure());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Glyph glyph : glyphs) {
|
||||||
|
component = component.append(glyph.toAdventure());
|
||||||
|
}
|
||||||
|
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.exception;
|
||||||
|
|
||||||
|
public class ResourceAlreadyProducedException extends RuntimeException {}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.exception;
|
||||||
|
|
||||||
|
public class ResourceNotProducedException extends RuntimeException {}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.image;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ResourceProducer;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.AppendableGlyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.Glyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceNotProducedException;
|
||||||
|
import team.unnamed.creative.texture.Texture;
|
||||||
|
|
||||||
|
public interface ImageGlyph extends AppendableGlyph, ResourceProducer {
|
||||||
|
|
||||||
|
static @NotNull ImageGlyph of(@NotNull Key key,
|
||||||
|
@NotNull Texture texture,
|
||||||
|
@NotNull TextureProperties properties) {
|
||||||
|
return new ImageGlyphImpl(key, texture, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
|
static @NotNull ImageGlyph of(@NotNull Texture texture,
|
||||||
|
@NotNull TextureProperties properties) {
|
||||||
|
return of(Glyph.DEFAULT_FONT_KEY, texture, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull Character character() throws ResourceNotProducedException;
|
||||||
|
|
||||||
|
@NotNull Texture texture();
|
||||||
|
|
||||||
|
default @NotNull Component toAdventure() throws ResourceNotProducedException {
|
||||||
|
return Component.text(character()).font(fontKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.image;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ArbitraryCharacterFactory;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.Glyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceAlreadyProducedException;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceNotProducedException;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.util.ImageUtil;
|
||||||
|
import team.unnamed.creative.font.FontProvider;
|
||||||
|
import team.unnamed.creative.texture.Texture;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
|
public class ImageGlyphImpl implements ImageGlyph {
|
||||||
|
|
||||||
|
private final Key fontKey;
|
||||||
|
private final Texture texture;
|
||||||
|
private final TextureProperties properties;
|
||||||
|
|
||||||
|
private Character character;
|
||||||
|
private Set<FontProvider> fontProviders;
|
||||||
|
|
||||||
|
private int width = -1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Key fontKey() {
|
||||||
|
return fontKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean produced() {
|
||||||
|
return fontProviders != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void produceResources(ArbitraryCharacterFactory characterFactory) throws ResourceAlreadyProducedException {
|
||||||
|
if (fontProviders != null) {
|
||||||
|
throw new ResourceAlreadyProducedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var fontProviderBuilder = FontProvider.bitMap();
|
||||||
|
|
||||||
|
this.character = characterFactory.nextCharacter();
|
||||||
|
|
||||||
|
fontProviderBuilder.characters(String.valueOf(character));
|
||||||
|
fontProviderBuilder.file(texture.key());
|
||||||
|
fontProviderBuilder.ascent(properties.ascent());
|
||||||
|
fontProviderBuilder.height(properties.height());
|
||||||
|
|
||||||
|
this.fontProviders = Collections.singleton(fontProviderBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Collection<@NotNull FontProvider> fontProviders() throws ResourceNotProducedException {
|
||||||
|
if (fontProviders == null) {
|
||||||
|
throw new ResourceNotProducedException();
|
||||||
|
}
|
||||||
|
return fontProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Collection<@NotNull Texture> textures() throws ResourceNotProducedException {
|
||||||
|
return Collections.singleton(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int width() {
|
||||||
|
if (width == -1) {
|
||||||
|
try {
|
||||||
|
BufferedImage image = ImageIO.read(new ByteArrayInputStream(texture.data().toByteArray()));
|
||||||
|
int fileHeight = image.getHeight();
|
||||||
|
width = (int) Math.ceil(
|
||||||
|
((double) properties.height() / (double) fileHeight)
|
||||||
|
* ImageUtil.calculateWidth(image)) + Glyph.SEPARATOR_WIDTH;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Character character() throws ResourceNotProducedException {
|
||||||
|
if (fontProviders == null) {
|
||||||
|
throw new ResourceNotProducedException();
|
||||||
|
}
|
||||||
|
return character;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Texture texture() {
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.image;
|
||||||
|
|
||||||
|
public record TextureProperties(int height, int ascent) {}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.image.multicharacter;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public interface ColorableGlyph {
|
||||||
|
|
||||||
|
@Nullable TextColor color();
|
||||||
|
|
||||||
|
void updateColor(@Nullable TextColor color);
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.image.multicharacter;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ResourceProducer;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.AppendableGlyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.Glyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.image.TextureProperties;
|
||||||
|
import team.unnamed.creative.texture.Texture;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface LanguageGlyphCollection extends ResourceProducer {
|
||||||
|
|
||||||
|
static @NotNull LanguageGlyphCollection of(@NotNull Key fontKey,
|
||||||
|
@NotNull Texture texture,
|
||||||
|
@NotNull List<@NotNull TextureProperties> propertiesList,
|
||||||
|
@NotNull List<@NotNull String> charactersMapping) {
|
||||||
|
return new LanguageGlyphCollectionImpl(fontKey, texture, propertiesList, charactersMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
|
static @NotNull LanguageGlyphCollection of(@NotNull Texture texture,
|
||||||
|
@NotNull List<@NotNull TextureProperties> propertiesList,
|
||||||
|
@NotNull List<@NotNull String> charactersMapping) {
|
||||||
|
return of(Glyph.DEFAULT_FONT_KEY, texture, propertiesList, charactersMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull AppendableGlyph translate(int height, int ascent, @NotNull Character character, @Nullable TextColor color) throws IllegalArgumentException;
|
||||||
|
|
||||||
|
@NotNull List<@NotNull AppendableGlyph> translate(int height, int ascent, @NotNull String text, @Nullable TextColor color) throws IllegalArgumentException;
|
||||||
|
|
||||||
|
default @NotNull AppendableGlyph translate(int height, int ascent, @NotNull Character character) throws IllegalArgumentException {
|
||||||
|
return translate(height, ascent, character, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
default @NotNull List<@NotNull AppendableGlyph> translate(int height, int ascent, @NotNull String text) throws IllegalArgumentException {
|
||||||
|
return translate(height, ascent, text, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.image.multicharacter;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ArbitraryCharacterFactory;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.AppendableGlyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceAlreadyProducedException;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceNotProducedException;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.image.TextureProperties;
|
||||||
|
import team.unnamed.creative.font.FontProvider;
|
||||||
|
import team.unnamed.creative.texture.Texture;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class LanguageGlyphCollectionImpl implements LanguageGlyphCollection {
|
||||||
|
|
||||||
|
private final Key fontKey;
|
||||||
|
private final Texture texture;
|
||||||
|
|
||||||
|
private final Map<TextureProperties, MulticharacterImageGlyphCollection> propertiesToMulticharacterMap = new HashMap<>();
|
||||||
|
|
||||||
|
private Set<FontProvider> fontProviders;
|
||||||
|
|
||||||
|
LanguageGlyphCollectionImpl(
|
||||||
|
Key fontKey,
|
||||||
|
Texture texture,
|
||||||
|
List<TextureProperties> propertiesList,
|
||||||
|
List<String> charactersMapping
|
||||||
|
) {
|
||||||
|
this.fontKey = fontKey;
|
||||||
|
this.texture = texture;
|
||||||
|
|
||||||
|
for (TextureProperties properties : propertiesList) {
|
||||||
|
propertiesToMulticharacterMap.put(properties, MulticharacterImageGlyphCollection.of(fontKey, texture, properties, charactersMapping));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Key fontKey() {
|
||||||
|
return fontKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean produced() {
|
||||||
|
return fontProviders != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void produceResources(ArbitraryCharacterFactory characterFactory) throws ResourceAlreadyProducedException {
|
||||||
|
if (fontProviders != null) {
|
||||||
|
throw new ResourceAlreadyProducedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
fontProviders = new HashSet<>();
|
||||||
|
|
||||||
|
for (var entry : propertiesToMulticharacterMap.entrySet()) {
|
||||||
|
entry.getValue().produceResources(characterFactory);
|
||||||
|
fontProviders.addAll(entry.getValue().fontProviders());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Collection<@NotNull FontProvider> fontProviders() throws ResourceNotProducedException {
|
||||||
|
return fontProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Collection<@NotNull Texture> textures() throws ResourceNotProducedException {
|
||||||
|
return Collections.singleton(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull AppendableGlyph translate(int height, int ascent, @NotNull Character character, @Nullable TextColor color) throws IllegalArgumentException {
|
||||||
|
TextureProperties properties = new TextureProperties(height, ascent);
|
||||||
|
if (!propertiesToMulticharacterMap.containsKey(properties)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
return propertiesToMulticharacterMap.get(properties).translate(character, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull List<@NotNull AppendableGlyph> translate(int height, int ascent, @NotNull String text, @Nullable TextColor color) throws IllegalArgumentException {
|
||||||
|
TextureProperties properties = new TextureProperties(height, ascent);
|
||||||
|
if (!propertiesToMulticharacterMap.containsKey(properties)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
return propertiesToMulticharacterMap.get(properties).translate(text, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.image.multicharacter;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ResourceProducer;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.AppendableGlyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.Glyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.image.TextureProperties;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.space.SpacesGlyph;
|
||||||
|
import team.unnamed.creative.texture.Texture;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface MulticharacterImageGlyphCollection extends ResourceProducer {
|
||||||
|
|
||||||
|
static @NotNull MulticharacterImageGlyphCollection of(@NotNull Key fontKey,
|
||||||
|
@NotNull Texture texture,
|
||||||
|
@NotNull TextureProperties properties,
|
||||||
|
@NotNull List<@NotNull String> charactersMapping) {
|
||||||
|
return new MulticharacterImageGlyphCollectionImpl(fontKey, texture, properties, charactersMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
|
static @NotNull MulticharacterImageGlyphCollection of(@NotNull Texture texture,
|
||||||
|
@NotNull TextureProperties properties,
|
||||||
|
@NotNull List<@NotNull String> charactersMapping) {
|
||||||
|
return of(Glyph.DEFAULT_FONT_KEY, texture, properties, charactersMapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull AppendableGlyph translate(@NotNull Character character, @Nullable TextColor color) throws IllegalArgumentException;
|
||||||
|
|
||||||
|
default @NotNull List<@NotNull AppendableGlyph> translate(@NotNull String text, @Nullable TextColor color) throws IllegalArgumentException {
|
||||||
|
List<AppendableGlyph> glyphs = new ArrayList<>();
|
||||||
|
for (char character : text.toCharArray()) {
|
||||||
|
if (character == ' ') {
|
||||||
|
glyphs.add(SpacesGlyph.DEFAULT_SPACE_GLYPH);
|
||||||
|
} else {
|
||||||
|
glyphs.add(translate(character, color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return glyphs;
|
||||||
|
}
|
||||||
|
|
||||||
|
default @NotNull AppendableGlyph translate(@NotNull Character character) throws IllegalArgumentException {
|
||||||
|
return translate(character, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
default @NotNull List<@NotNull AppendableGlyph> translate(@NotNull String text) throws IllegalArgumentException {
|
||||||
|
return translate(text, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,131 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.image.multicharacter;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ArbitraryCharacterFactory;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.Glyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceAlreadyProducedException;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceNotProducedException;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.image.TextureProperties;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.util.ImageUtil;
|
||||||
|
import team.unnamed.creative.font.FontProvider;
|
||||||
|
import team.unnamed.creative.texture.Texture;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
|
public class MulticharacterImageGlyphCollectionImpl implements MulticharacterImageGlyphCollection {
|
||||||
|
|
||||||
|
private final Key fontKey;
|
||||||
|
private final Texture texture;
|
||||||
|
private final TextureProperties properties;
|
||||||
|
private final List<String> charactersMapping;
|
||||||
|
|
||||||
|
private final Map<Character, Character> originToArbitraryCharacterMap = new HashMap<>();
|
||||||
|
|
||||||
|
private Set<FontProvider> fontProviders;
|
||||||
|
|
||||||
|
private BufferedImage image;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Key fontKey() {
|
||||||
|
return fontKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean produced() {
|
||||||
|
return fontProviders != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void produceResources(ArbitraryCharacterFactory characterFactory) throws ResourceAlreadyProducedException {
|
||||||
|
if (fontProviders != null) {
|
||||||
|
throw new ResourceAlreadyProducedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var fontProviderBuilder = FontProvider.bitMap();
|
||||||
|
fontProviderBuilder.file(texture.key());
|
||||||
|
fontProviderBuilder.ascent(properties.ascent());
|
||||||
|
fontProviderBuilder.height(properties.height());
|
||||||
|
|
||||||
|
List<String> mappingLines = new ArrayList<>();
|
||||||
|
|
||||||
|
for (String mappingLine : charactersMapping) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (char character : mappingLine.toCharArray()) {
|
||||||
|
char arbitraryCharacter = characterFactory.nextCharacter();
|
||||||
|
originToArbitraryCharacterMap.put(character, arbitraryCharacter);
|
||||||
|
builder.append(arbitraryCharacter);
|
||||||
|
}
|
||||||
|
mappingLines.add(builder.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
fontProviderBuilder.characters(mappingLines);
|
||||||
|
|
||||||
|
this.fontProviders = Collections.singleton(fontProviderBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Collection<@NotNull FontProvider> fontProviders() throws ResourceNotProducedException {
|
||||||
|
return fontProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Collection<@NotNull Texture> textures() throws ResourceNotProducedException {
|
||||||
|
return Collections.singleton(texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull PreparedImageGlyph translate(@NotNull Character character, @Nullable TextColor color) throws IllegalArgumentException {
|
||||||
|
if (!originToArbitraryCharacterMap.containsKey(character)) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
int width = 0;
|
||||||
|
for (int lineIndex = 0; lineIndex < charactersMapping.size(); lineIndex++) {
|
||||||
|
String line = charactersMapping.get(lineIndex);
|
||||||
|
for (int characterIndex = 0; characterIndex < line.toCharArray().length; characterIndex++) {
|
||||||
|
if (line.charAt(characterIndex) == character) {
|
||||||
|
if (image == null) {
|
||||||
|
cacheImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image == null) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
int filePartWidth = image.getWidth() / charactersMapping.get(0).length();
|
||||||
|
int filePartHeight = image.getHeight() / charactersMapping.size();
|
||||||
|
|
||||||
|
width = (int) Math.ceil(
|
||||||
|
((double) properties.height() / (double) filePartHeight)
|
||||||
|
* ImageUtil.calculateWidth(
|
||||||
|
image, filePartWidth * characterIndex, filePartHeight * lineIndex,
|
||||||
|
filePartWidth * (characterIndex + 1), filePartHeight * (lineIndex + 1)
|
||||||
|
)) + Glyph.SEPARATOR_WIDTH;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PreparedImageGlyph(fontKey, originToArbitraryCharacterMap.get(character), width, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cacheImage() {
|
||||||
|
try {
|
||||||
|
image = ImageIO.read(new ByteArrayInputStream(texture.data().toByteArray()));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.image.multicharacter;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
|
import net.kyori.adventure.text.format.TextColor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.AppendableGlyph;
|
||||||
|
|
||||||
|
@AllArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
|
public class PreparedImageGlyph implements AppendableGlyph, ColorableGlyph {
|
||||||
|
|
||||||
|
private final Key key;
|
||||||
|
private final Character character;
|
||||||
|
private final int width;
|
||||||
|
private @Nullable TextColor color;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Component toAdventure() {
|
||||||
|
return Component.text(character)
|
||||||
|
.font(key)
|
||||||
|
.color(color == null ? NamedTextColor.BLACK : color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int width() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable TextColor color() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateColor(@Nullable TextColor color) {
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.space;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.EmptyGlyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.Glyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceNotProducedException;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.util.ArrayUtil;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public abstract class AbstractSpacesGlyphResourceProducer implements SpacesGlyphResourceProducer {
|
||||||
|
|
||||||
|
private final Key fontKey;
|
||||||
|
|
||||||
|
protected Map<Integer, Character> mapping;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Key fontKey() {
|
||||||
|
return fontKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean produced() {
|
||||||
|
return mapping != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Glyph translate(int length) throws ResourceNotProducedException {
|
||||||
|
if (mapping == null) {
|
||||||
|
throw new ResourceNotProducedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length == 0) {
|
||||||
|
return EmptyGlyph.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sign = length > 0 ? 1 : -1;
|
||||||
|
String binaryString = Integer.toBinaryString(Math.abs(length));
|
||||||
|
|
||||||
|
List<Character> characters = new ArrayList<>();
|
||||||
|
|
||||||
|
int currentRankLength = 1;
|
||||||
|
for (int index = 0; index < binaryString.length(); index++) {
|
||||||
|
char digit = binaryString.charAt(binaryString.length() - index - 1);
|
||||||
|
if (digit == '1') {
|
||||||
|
int partLength = currentRankLength * sign;
|
||||||
|
if (!mapping.containsKey(partLength)) {
|
||||||
|
throw new IllegalArgumentException("Too much length");
|
||||||
|
}
|
||||||
|
characters.add(mapping.get(partLength));
|
||||||
|
}
|
||||||
|
currentRankLength *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SpacesGlyph(fontKey(), ArrayUtil.toCharArray(characters), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.space;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.AppendableGlyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceNotProducedException;
|
||||||
|
import team.unnamed.creative.font.Font;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
|
public class DefaultSpaceGlyph implements AppendableGlyph {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Component toAdventure() throws ResourceNotProducedException {
|
||||||
|
return Component.text(" ").font(Font.MINECRAFT_DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int width() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.space;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ArbitraryCharacterFactory;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceAlreadyProducedException;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceNotProducedException;
|
||||||
|
import team.unnamed.creative.base.Writable;
|
||||||
|
import team.unnamed.creative.font.BitMapFontProvider;
|
||||||
|
import team.unnamed.creative.font.FontProvider;
|
||||||
|
import team.unnamed.creative.texture.Texture;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class DefaultSpacesGlyphResourceProducer extends AbstractSpacesGlyphResourceProducer {
|
||||||
|
|
||||||
|
private final Key textureKey;
|
||||||
|
private final Writable writable;
|
||||||
|
|
||||||
|
private Set<Texture> textures;
|
||||||
|
private Set<FontProvider> fontProviders;
|
||||||
|
|
||||||
|
public DefaultSpacesGlyphResourceProducer(Key fontKey, Key textureKey, Writable writable) {
|
||||||
|
super(fontKey);
|
||||||
|
this.textureKey = textureKey;
|
||||||
|
this.writable = writable;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean produced() {
|
||||||
|
return textures != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void produceResources(ArbitraryCharacterFactory characterFactory) {
|
||||||
|
if (textures != null) {
|
||||||
|
throw new ResourceAlreadyProducedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mapping = new HashMap<>();
|
||||||
|
|
||||||
|
Set<FontProvider> fontProviders = new HashSet<>();
|
||||||
|
|
||||||
|
for (int length = 1; length <= 2048; length *= 2) {
|
||||||
|
fontProviders.add(prepareBuilder(characterFactory, length).build());
|
||||||
|
fontProviders.add(prepareBuilder(characterFactory, length * (-1)).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.textures = Collections.singleton(Texture.texture(textureKey, writable));
|
||||||
|
this.fontProviders = fontProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Collection<@NotNull FontProvider> fontProviders() throws ResourceNotProducedException {
|
||||||
|
if (fontProviders == null) {
|
||||||
|
throw new ResourceNotProducedException();
|
||||||
|
}
|
||||||
|
return fontProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Collection<@NotNull Texture> textures() throws ResourceNotProducedException {
|
||||||
|
if (textures == null) {
|
||||||
|
throw new ResourceNotProducedException();
|
||||||
|
}
|
||||||
|
return textures;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private BitMapFontProvider.Builder prepareBuilder(ArbitraryCharacterFactory characterFactory, int length) {
|
||||||
|
var fontProviderBuilder = FontProvider.bitMap();
|
||||||
|
|
||||||
|
char character = characterFactory.nextCharacter();
|
||||||
|
|
||||||
|
fontProviderBuilder.characters(String.valueOf(character));
|
||||||
|
fontProviderBuilder.file(textureKey);
|
||||||
|
|
||||||
|
if (length > 0) {
|
||||||
|
fontProviderBuilder.height(length - 1);
|
||||||
|
fontProviderBuilder.ascent(0);
|
||||||
|
} else {
|
||||||
|
fontProviderBuilder.height(length - 2);
|
||||||
|
fontProviderBuilder.ascent(-32768);
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping.put(length, character);
|
||||||
|
|
||||||
|
return fontProviderBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.space;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.Glyph;
|
||||||
|
import team.unnamed.creative.base.Writable;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
|
||||||
|
public class SpacesGlyph implements Glyph {
|
||||||
|
|
||||||
|
private static final Key DEFAULT_SPACE_TEXTURE_KEY = Key.key(Glyph.DEFAULT_NAMESPACE, "space");
|
||||||
|
public static final @NotNull DefaultSpaceGlyph DEFAULT_SPACE_GLYPH = new DefaultSpaceGlyph();
|
||||||
|
private final Key key;
|
||||||
|
private final char[] characters;
|
||||||
|
private final int length;
|
||||||
|
|
||||||
|
public static @NotNull SpacesGlyphResourceProducer create(@NotNull Key fontKey,
|
||||||
|
@NotNull Key textureKey,
|
||||||
|
@NotNull Writable spacesWritable) {
|
||||||
|
return new DefaultSpacesGlyphResourceProducer(fontKey, textureKey, spacesWritable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpacesGlyphResourceProducer create(@NotNull Writable spacesWritable) {
|
||||||
|
return create(Glyph.DEFAULT_SPACES_FONT_KEY, DEFAULT_SPACE_TEXTURE_KEY, spacesWritable);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Component toAdventure() {
|
||||||
|
return Component.text(new String(characters)).font(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int width() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.space;
|
||||||
|
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ResourceProducer;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.Glyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceNotProducedException;
|
||||||
|
|
||||||
|
public interface SpacesGlyphResourceProducer extends ResourceProducer {
|
||||||
|
|
||||||
|
Glyph translate(int length) throws ResourceNotProducedException;
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.space.mojang;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ResourceProducer;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.Glyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.space.SpacesGlyphResourceProducer;
|
||||||
|
|
||||||
|
public interface MojangSpacesGlyph extends Glyph, ResourceProducer {
|
||||||
|
|
||||||
|
static @NotNull SpacesGlyphResourceProducer create(@NotNull Key key) {
|
||||||
|
return new MojangSpacesGlyphResourceProducer(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SpacesGlyphResourceProducer create() {
|
||||||
|
return create(Glyph.DEFAULT_SPACES_FONT_KEY);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.glyph.space.mojang;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ArbitraryCharacterFactory;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceAlreadyProducedException;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.exception.ResourceNotProducedException;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.space.AbstractSpacesGlyphResourceProducer;
|
||||||
|
import team.unnamed.creative.font.FontProvider;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class MojangSpacesGlyphResourceProducer extends AbstractSpacesGlyphResourceProducer {
|
||||||
|
|
||||||
|
private Set<FontProvider> fontProviders;
|
||||||
|
|
||||||
|
public MojangSpacesGlyphResourceProducer(Key key) {
|
||||||
|
super(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean produced() {
|
||||||
|
return fontProviders != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void produceResources(ArbitraryCharacterFactory characterFactory) {
|
||||||
|
if (fontProviders != null) {
|
||||||
|
throw new ResourceAlreadyProducedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
mapping = new HashMap<>();
|
||||||
|
|
||||||
|
var fontProviderBuilder = FontProvider.space();
|
||||||
|
|
||||||
|
for (int length = 1; length <= 2048; length *= 2) {
|
||||||
|
fontProviderBuilder.advance(retrieveCharacter(characterFactory, length), length);
|
||||||
|
fontProviderBuilder.advance(retrieveCharacter(characterFactory, length * (-1)), length * (-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fontProviders = Collections.singleton(fontProviderBuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Collection<@NotNull FontProvider> fontProviders() throws ResourceNotProducedException {
|
||||||
|
if (fontProviders == null) {
|
||||||
|
throw new ResourceNotProducedException();
|
||||||
|
}
|
||||||
|
return fontProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Character retrieveCharacter(ArbitraryCharacterFactory characterFactory, int length) {
|
||||||
|
char character = characterFactory.nextCharacter();
|
||||||
|
mapping.put(length, character);
|
||||||
|
return character;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.pack;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import lombok.AccessLevel;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.GlyphCompiler;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ResourceProducer;
|
||||||
|
import team.unnamed.creative.part.ResourcePackPart;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
@NoArgsConstructor(access = AccessLevel.PROTECTED)
|
||||||
|
public class DefaultGlyphResourcePack implements GlyphResourcePack {
|
||||||
|
|
||||||
|
private final Map<String, ResourceProducer> raw = new HashMap<>();
|
||||||
|
private final Map<String, ResourceProducer> compiled = new HashMap<>();
|
||||||
|
|
||||||
|
private final Set<ResourcePackPart> resources = new HashSet<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Collection<@NotNull ResourcePackPart> all() {
|
||||||
|
if (!raw.isEmpty()) {
|
||||||
|
compileAll();
|
||||||
|
}
|
||||||
|
return resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void compileAll() {
|
||||||
|
var resources = GlyphCompiler.instance().compile(raw.values());
|
||||||
|
this.resources.addAll(resources);
|
||||||
|
compiled.putAll(raw);
|
||||||
|
raw.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull <T extends ResourceProducer> GlyphResourcePack with(@NotNull ResourceIdentifier<@NotNull T> id, @NotNull T producer) {
|
||||||
|
if (raw.containsKey(id.key()) || compiled.containsKey(id.key())) {
|
||||||
|
throw new IllegalArgumentException("Producer with this identifier already registered");
|
||||||
|
}
|
||||||
|
raw.put(id.key(), producer);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull GlyphResourcePack with(@NotNull ResourcePackPart resource) {
|
||||||
|
resources.add(resource);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends ResourceProducer> @NotNull T get(@NotNull ResourceIdentifier<@NotNull T> id) throws IllegalArgumentException {
|
||||||
|
if (!compiled.containsKey(id.key())) {
|
||||||
|
throw new IllegalArgumentException("Producer with that identifier is not compiled");
|
||||||
|
}
|
||||||
|
ResourceProducer producer = compiled.get(id.key());
|
||||||
|
if (!id.getType().isAssignableFrom(producer.getClass())) {
|
||||||
|
throw new IllegalArgumentException("Wrong producer type");
|
||||||
|
}
|
||||||
|
return (T) producer;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.pack;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ResourceProducer;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.space.SpacesGlyphResourceProducer;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.space.mojang.MojangSpacesGlyph;
|
||||||
|
import team.unnamed.creative.ResourcePack;
|
||||||
|
import team.unnamed.creative.part.ResourcePackPart;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public interface GlyphResourcePack {
|
||||||
|
|
||||||
|
@NotNull Collection<@NotNull ResourcePackPart> all();
|
||||||
|
|
||||||
|
void compileAll();
|
||||||
|
|
||||||
|
@Contract("_, _ -> this")
|
||||||
|
<T extends ResourceProducer> @NotNull GlyphResourcePack with(@NotNull ResourceIdentifier<@NotNull T> id, @NotNull T producer);
|
||||||
|
|
||||||
|
@Contract("_ -> this")
|
||||||
|
@NotNull GlyphResourcePack with(@NotNull ResourcePackPart resource);
|
||||||
|
|
||||||
|
@Contract("_ -> this")
|
||||||
|
default @NotNull GlyphResourcePack with(@NotNull ResourcePackPart... resources) {
|
||||||
|
for (ResourcePackPart resource : resources) {
|
||||||
|
with(resource);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract("_ -> this")
|
||||||
|
default @NotNull GlyphResourcePack with(@NotNull Collection<@NotNull ResourcePackPart> resources) {
|
||||||
|
resources.forEach(this::with);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Contract("-> this")
|
||||||
|
default @NotNull GlyphResourcePack withMojangSpaces() {
|
||||||
|
with(ResourceIdentifier.SPACES, MojangSpacesGlyph.create());
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
<T extends ResourceProducer> @NotNull T get(@NotNull ResourceIdentifier<@NotNull T> id) throws IllegalArgumentException;
|
||||||
|
|
||||||
|
default @NotNull SpacesGlyphResourceProducer spaces() {
|
||||||
|
return get(ResourceIdentifier.SPACES);
|
||||||
|
}
|
||||||
|
|
||||||
|
default void writeAll(@NotNull ResourcePack resourcePack) {
|
||||||
|
all().forEach(resourcePack::part);
|
||||||
|
}
|
||||||
|
|
||||||
|
static @NotNull GlyphResourcePack create() {
|
||||||
|
return new DefaultGlyphResourcePack();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.pack;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.image.ImageGlyph;
|
||||||
|
|
||||||
|
public interface ImageResourceIdentifier extends ResourceIdentifier<@NotNull ImageGlyph> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default @NotNull Class<@NotNull ImageGlyph> getType() {
|
||||||
|
return ImageGlyph.class;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.pack;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ResourceProducer;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.image.multicharacter.LanguageGlyphCollection;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.space.SpacesGlyphResourceProducer;
|
||||||
|
|
||||||
|
public interface ResourceIdentifier<T extends @NotNull ResourceProducer> {
|
||||||
|
|
||||||
|
@NotNull StringIdentifier<@NotNull SpacesGlyphResourceProducer> SPACES = StringIdentifier.of("spaces", SpacesGlyphResourceProducer.class);
|
||||||
|
|
||||||
|
@NotNull StringIdentifier<@NotNull LanguageGlyphCollection> MINECRAFT_FONT = StringIdentifier.of("minecraft_font", LanguageGlyphCollection.class);
|
||||||
|
|
||||||
|
String STRING_IDENTIFIER_NAMESPACE = "glyphs";
|
||||||
|
|
||||||
|
@NotNull String key();
|
||||||
|
|
||||||
|
@NotNull Class<T> getType();
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.pack;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.ResourceProducer;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.image.ImageGlyph;
|
||||||
|
|
||||||
|
public class StringIdentifier<T extends @NotNull ResourceProducer> implements ResourceIdentifier<T> {
|
||||||
|
|
||||||
|
private final @NotNull String id;
|
||||||
|
|
||||||
|
private final @NotNull Class<T> type;
|
||||||
|
|
||||||
|
protected StringIdentifier(@NotNull String id, @NotNull Class<T> type) {
|
||||||
|
this.id = id;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Class<T> getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull String key() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends @NotNull ResourceProducer> @NotNull StringIdentifier<@NotNull T> of(
|
||||||
|
@NotNull String id,
|
||||||
|
@NotNull Class<T> type) {
|
||||||
|
return new StringIdentifier<>(id, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static @NotNull StringIdentifier<@NotNull ImageGlyph> image(@NotNull String id) {
|
||||||
|
return new StringIdentifier<>(id, ImageGlyph.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.util;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class ArrayUtil {
|
||||||
|
|
||||||
|
public char[] toCharArray(@NotNull List<Character> list) {
|
||||||
|
char[] arr = new char[list.size()];
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
arr[i] = list.get(i);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package ru.dragonestia.msb3.api.glyph.util;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class ImageUtil {
|
||||||
|
|
||||||
|
public int calculateWidth(BufferedImage image, int xFrom, int yFrom, int xTo, int yTo) {
|
||||||
|
int width;
|
||||||
|
for (width = xTo - 1; width > xFrom; width--) {
|
||||||
|
for (int height = yFrom; height < yTo; height++) {
|
||||||
|
if (new Color(image.getRGB(width, height), true)
|
||||||
|
.getAlpha() == 255) {
|
||||||
|
return width - xFrom + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return width - xFrom + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int calculateWidth(BufferedImage image) {
|
||||||
|
return calculateWidth(image, 0, 0, image.getWidth(), image.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package ru.dragonestia.msb3.api.item;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.minestom.server.item.ItemStack;
|
||||||
|
import net.minestom.server.item.Material;
|
||||||
|
import ru.dragonestia.msb3.api.ServerBootstrap;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.Glyph;
|
||||||
|
import ru.dragonestia.msb3.api.util.ResourceFromJar;
|
||||||
|
import team.unnamed.creative.base.Writable;
|
||||||
|
import team.unnamed.creative.model.*;
|
||||||
|
import team.unnamed.creative.part.ResourcePackPart;
|
||||||
|
import team.unnamed.creative.texture.Texture;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
public class BlankSlotItem {
|
||||||
|
|
||||||
|
private static final Writable BLANK_SLOT_IMAGE_WRITABLE = ResourceFromJar.of(ServerBootstrap.CLASS_LOADER, "glyphs/defaults/blank_slot.png");
|
||||||
|
private static ItemStack stack;
|
||||||
|
|
||||||
|
private BlankSlotItem() {}
|
||||||
|
|
||||||
|
public synchronized static ItemStack getItem() {
|
||||||
|
if (stack == null) {
|
||||||
|
stack = ItemStack.builder(Material.PAPER)
|
||||||
|
.customModelData(1)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Collection<ResourcePackPart> compile() {
|
||||||
|
var modelKey = Key.key(Glyph.DEFAULT_NAMESPACE, "blank_slot");
|
||||||
|
var itemKey = Key.key("item/paper");
|
||||||
|
|
||||||
|
Model blankSlotModel = Model.model()
|
||||||
|
.key(modelKey)
|
||||||
|
.parent(Model.ITEM_GENERATED)
|
||||||
|
.textures(ModelTextures.builder()
|
||||||
|
.layers(ModelTexture.ofKey(modelKey))
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Model paperItemModel = Model.model()
|
||||||
|
.key(itemKey)
|
||||||
|
.parent(Model.ITEM_GENERATED)
|
||||||
|
.textures(ModelTextures.builder()
|
||||||
|
.layers(ModelTexture.ofKey(itemKey))
|
||||||
|
.build())
|
||||||
|
.overrides(ItemOverride.of(modelKey, ItemPredicate.customModelData(1)))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Texture texture = Texture.texture(Key.key("glyphs", "blank_slot.png"), BLANK_SLOT_IMAGE_WRITABLE);
|
||||||
|
return Arrays.asList(blankSlotModel, paperItemModel, texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,26 +2,79 @@ package ru.dragonestia.msb3.api.resource;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.extern.log4j.Log4j2;
|
import lombok.extern.log4j.Log4j2;
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.compile.GlyphCompiler;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.font.GlyphFont;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.pack.GlyphResourcePack;
|
||||||
|
import ru.dragonestia.msb3.api.item.BlankSlotItem;
|
||||||
|
import ru.dragonestia.msb3.api.title.BlackScreen;
|
||||||
import team.unnamed.creative.ResourcePack;
|
import team.unnamed.creative.ResourcePack;
|
||||||
|
import team.unnamed.creative.atlas.Atlas;
|
||||||
|
import team.unnamed.creative.atlas.AtlasSource;
|
||||||
import team.unnamed.creative.base.Writable;
|
import team.unnamed.creative.base.Writable;
|
||||||
|
import team.unnamed.creative.model.Model;
|
||||||
import team.unnamed.creative.serialize.minecraft.MinecraftResourcePackWriter;
|
import team.unnamed.creative.serialize.minecraft.MinecraftResourcePackWriter;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@Getter
|
||||||
@Log4j2
|
@Log4j2
|
||||||
public class ResourcePackManager {
|
public class ResourcePackManager {
|
||||||
|
|
||||||
@Getter private final ResourcePack resourcePack;
|
private final ResourcePack resourcePack;
|
||||||
|
private final GlyphResourcePack glyphResourcePack;
|
||||||
|
|
||||||
public ResourcePackManager() {
|
public ResourcePackManager() {
|
||||||
resourcePack = ResourcePack.resourcePack();
|
resourcePack = ResourcePack.resourcePack();
|
||||||
resourcePack.packMeta(34, "Dragonestia MSB3 - Resource pack");
|
resourcePack.packMeta(34, "Dragonestia MSB3 - Resource pack");
|
||||||
resourcePack.icon(Writable.resource(getClass().getClassLoader(), "logo.png"));
|
resourcePack.icon(Writable.resource(getClass().getClassLoader(), "logo.png"));
|
||||||
resourcePack.unknownFile("credits.txt", Writable.stringUtf8("dragonestia.ru"));
|
resourcePack.unknownFile("credits.txt", Writable.stringUtf8("dragonestia.ru"));
|
||||||
|
|
||||||
|
glyphResourcePack = GlyphResourcePack.create();
|
||||||
|
initDefaultGlyphs();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initDefaultGlyphs() {
|
||||||
|
glyphResourcePack.with(BlankSlotItem.compile());
|
||||||
|
glyphResourcePack.with(GlyphCompiler.instance().compile(BlackScreen.GLYPH));
|
||||||
|
glyphResourcePack.with(GlyphFont.compile());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void compile() {
|
public void compile() {
|
||||||
|
glyphResourcePack.writeAll(resourcePack);
|
||||||
|
generateAtlases();
|
||||||
MinecraftResourcePackWriter.minecraft().writeToZipFile(new File("resource-pack.zip"), resourcePack);
|
MinecraftResourcePackWriter.minecraft().writeToZipFile(new File("resource-pack.zip"), resourcePack);
|
||||||
log.info("Compiled resource pack. File: ./resource-pack.zip");
|
log.info("Compiled resource pack. File: ./resource-pack.zip");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void generateAtlases() {
|
||||||
|
Atlas.Builder atlasBuilder = Atlas.atlas();
|
||||||
|
atlasBuilder.key(Key.key("minecraft", "blocks"));
|
||||||
|
Set<String> applicableTextureKeys = new HashSet<>();
|
||||||
|
|
||||||
|
for (Model model: resourcePack.models()) {
|
||||||
|
for (var layer: model.textures().layers()) {
|
||||||
|
var key = layer.key();
|
||||||
|
if (key != null) {
|
||||||
|
applicableTextureKeys.add(key.asString().concat(".png"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var texture: model.textures().variables().values()) {
|
||||||
|
var key = texture.key();
|
||||||
|
if (key != null) {
|
||||||
|
applicableTextureKeys.add(key.asString().concat(".png"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var sources = resourcePack.textures()
|
||||||
|
.stream()
|
||||||
|
//.filter(texture -> !applicableTextureKeys.contains(texture.key().asString()))
|
||||||
|
.map(texture -> (AtlasSource) AtlasSource.single(Key.key(texture.key().toString().replace(".png", "")))).toList();
|
||||||
|
atlasBuilder.sources(sources);
|
||||||
|
resourcePack.atlas(atlasBuilder.build());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
package ru.dragonestia.msb3.api.title;
|
||||||
|
|
||||||
|
import net.kyori.adventure.key.Key;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.title.Title;
|
||||||
|
import net.minestom.server.entity.Player;
|
||||||
|
import ru.dragonestia.msb3.api.ServerBootstrap;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.Glyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.image.ImageGlyph;
|
||||||
|
import ru.dragonestia.msb3.api.glyph.glyph.image.TextureProperties;
|
||||||
|
import ru.dragonestia.msb3.api.util.ResourceFromJar;
|
||||||
|
import team.unnamed.creative.base.Writable;
|
||||||
|
import team.unnamed.creative.texture.Texture;
|
||||||
|
|
||||||
|
public class BlackScreen {
|
||||||
|
|
||||||
|
private static final Writable BACKGROUND_WRITABLE = ResourceFromJar.of(ServerBootstrap.CLASS_LOADER, "glyphs/defaults/fullscreen_background.png");
|
||||||
|
private static final Key FULLSCREEN_BACKGROUND_KEY = Key.key(Glyph.DEFAULT_NAMESPACE, "fullscreen_background.png");
|
||||||
|
public static final ImageGlyph GLYPH = fullscreenBackgroundGlyph();
|
||||||
|
|
||||||
|
private BlackScreen() {}
|
||||||
|
|
||||||
|
public static void show(Player player) {
|
||||||
|
player.showTitle(Title.title(
|
||||||
|
GLYPH.toAdventure(),
|
||||||
|
Component.empty()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ImageGlyph fullscreenBackgroundGlyph() {
|
||||||
|
return ImageGlyph.of(FULLSCREEN_BACKGROUND_KEY,
|
||||||
|
Texture.texture(FULLSCREEN_BACKGROUND_KEY, BACKGROUND_WRITABLE),
|
||||||
|
new TextureProperties(2500, 256));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
package ru.dragonestia.msb3.api.util;
|
||||||
|
|
||||||
|
import team.unnamed.creative.base.Writable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLConnection;
|
||||||
|
|
||||||
|
public interface ResourceFromJar {
|
||||||
|
|
||||||
|
static Writable of(ClassLoader classLoader, String fileName) {
|
||||||
|
return Writable.inputStream(() -> {
|
||||||
|
try {
|
||||||
|
URL url = classLoader.getResource(fileName);
|
||||||
|
|
||||||
|
if (url == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
URLConnection connection = url.openConnection();
|
||||||
|
connection.setUseCaches(false);
|
||||||
|
return connection.getInputStream();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
api/src/main/resources/glyphs/defaults/blank_slot.png
Normal file
BIN
api/src/main/resources/glyphs/defaults/blank_slot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
BIN
api/src/main/resources/glyphs/defaults/fullscreen_background.png
Normal file
BIN
api/src/main/resources/glyphs/defaults/fullscreen_background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 120 B |
BIN
api/src/main/resources/glyphs/defaults/minecraft_font.png
Normal file
BIN
api/src/main/resources/glyphs/defaults/minecraft_font.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
BIN
api/src/main/resources/glyphs/defaults/space.png
Normal file
BIN
api/src/main/resources/glyphs/defaults/space.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 120 B |
Loading…
x
Reference in New Issue
Block a user