/*
* This file is part of LanternServer, licensed under the MIT License (MIT).
*
* Copyright (c) LanternPowered <https://www.lanternpowered.org>
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the Software), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.lanternpowered.server.text;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.lanternpowered.server.data.translator.JsonTranslator;
import org.lanternpowered.server.entity.LanternEntityType;
import org.lanternpowered.server.text.action.LanternClickActionCallbacks;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.data.DataContainer;
import org.spongepowered.api.data.DataQuery;
import org.spongepowered.api.data.DataView;
import org.spongepowered.api.data.MemoryDataContainer;
import org.spongepowered.api.entity.EntityType;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.text.action.ClickAction;
import org.spongepowered.api.text.action.HoverAction;
import org.spongepowered.api.text.action.TextActions;
import org.spongepowered.api.text.serializer.TextSerializers;
import org.spongepowered.api.util.Coerce;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Optional;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import javax.annotation.Nullable;
public final class LanternTextHelper {
private static final Gson GSON = new Gson();
private static final DataQuery SHOW_ENTITY_ID = DataQuery.of("id");
private static final DataQuery SHOW_ENTITY_TYPE = DataQuery.of("type");
private static final DataQuery SHOW_ENTITY_NAME = DataQuery.of("name");
public static ClickAction<?> parseClickAction(String action, String value) {
switch (action) {
case "open_url":
case "open_file":
URI uri = null;
if (action.equals("open_url")) {
try {
uri = new URI(value);
} catch (URISyntaxException ignored) {
}
} else {
uri = new File(value).toURI();
}
if (uri != null) {
try {
return TextActions.openUrl(uri.toURL());
} catch (MalformedURLException ignored) {
}
}
break;
case "run_command":
// Check for a valid click action callback
Matcher matcher = LanternClickActionCallbacks.COMMAND_PATTERN.matcher(value.trim().toLowerCase());
if (matcher.matches()) {
UUID uniqueId = UUID.fromString(matcher.group(1));
Optional<Consumer<CommandSource>> callback = LanternClickActionCallbacks.getInstance().getCallbackForUUID(uniqueId);
if (callback.isPresent()) {
return TextActions.executeCallback(callback.get());
}
}
return TextActions.runCommand(value);
case "suggest_command":
return TextActions.suggestCommand(value);
case "change_page":
Optional<Integer> page = Coerce.asInteger(value);
if (page.isPresent()) {
return TextActions.changePage(page.get());
}
break;
default:
throw new IllegalArgumentException("Unknown click action type: " + action);
}
return null;
}
@SuppressWarnings("deprecation")
public static HoverAction<?> parseHoverAction(String action, String value) {
switch (action) {
case "show_text":
return TextActions.showText(TextSerializers.LEGACY_FORMATTING_CODE.deserializeUnchecked(value));
case "show_achievement":
return null; // TODO
case "show_item":
return null; // TODO
case "show_entity":
DataView dataView = JsonTranslator.instance().translate(GSON.fromJson(value, JsonObject.class));
UUID uuid = UUID.fromString(dataView.getString(SHOW_ENTITY_ID).get());
String name = dataView.getString(SHOW_ENTITY_NAME).get();
EntityType entityType = null;
if (dataView.contains(SHOW_ENTITY_TYPE)) {
entityType = Sponge.getRegistry().getType(EntityType.class, dataView.getString(SHOW_ENTITY_TYPE).get()).orElse(null);
}
return TextActions.showEntity(uuid, name, entityType);
default:
throw new IllegalArgumentException("Unknown hover action type: " + action);
}
}
public static RawAction raw(ClickAction<?> clickAction) {
if (clickAction instanceof ClickAction.ChangePage) {
return new RawAction("change_page", ((ClickAction.ChangePage) clickAction).getResult().toString());
} else if (clickAction instanceof ClickAction.OpenUrl) {
URL url = ((ClickAction.OpenUrl) clickAction).getResult();
String scheme = url.getProtocol();
String host = url.getProtocol();
if ("file".equalsIgnoreCase(scheme) && (host == null || host.equals(""))) {
return new RawAction("open_file", url.getFile());
} else {
return new RawAction("open_url", url.toExternalForm());
}
} else if (clickAction instanceof ClickAction.ExecuteCallback) {
final UUID uniqueId = LanternClickActionCallbacks.getInstance().getOrCreateIdForCallback(
((ClickAction.ExecuteCallback) clickAction).getResult());
return new RawAction("run_command", LanternClickActionCallbacks.COMMAND_BASE + uniqueId.toString());
} else if (clickAction instanceof ClickAction.RunCommand) {
return new RawAction("run_command", ((ClickAction.RunCommand) clickAction).getResult());
} else if (clickAction instanceof ClickAction.SuggestCommand) {
return new RawAction("suggest_command", ((ClickAction.SuggestCommand) clickAction).getResult());
} else {
throw new IllegalArgumentException("Unknown click action type: " + clickAction.getClass().getName());
}
}
public static RawAction raw(HoverAction<?> hoverAction) {
if (hoverAction instanceof HoverAction.ShowText) {
return new RawAction("show_text", ((HoverAction.ShowText) hoverAction).getResult());
} else if (hoverAction instanceof HoverAction.ShowAchievement) {
return new RawAction("show_achievement", ((HoverAction.ShowAchievement) hoverAction).getResult().getId());
} else if (hoverAction instanceof HoverAction.ShowEntity) {
HoverAction.ShowEntity.Ref ref = ((HoverAction.ShowEntity) hoverAction).getResult();
DataContainer dataContainer = new MemoryDataContainer();
dataContainer.set(SHOW_ENTITY_ID, ref.getUniqueId().toString());
dataContainer.set(SHOW_ENTITY_NAME, ref.getName());
// TODO
// ref.getType().ifPresent(type -> dataContainer.set(SHOW_ENTITY_TYPE, ((LanternEntityType) type).getMinecraftId()));
return new RawAction("show_entity", GSON.toJson(JsonTranslator.instance().translate(dataContainer)));
} else if (hoverAction instanceof HoverAction.ShowItem) {
return null; // TODO
} else {
throw new IllegalArgumentException("Unknown hover action type: " + hoverAction.getClass().getName());
}
}
public static class RawAction {
private final String action;
@Nullable private String value;
@Nullable private Text text;
public RawAction(String action, String value) {
this.action = action;
this.value = value;
}
public RawAction(String action, Text value) {
this.action = action;
this.text = value;
}
public String getAction() {
return this.action;
}
@SuppressWarnings("deprecation")
public String getValueAsString() {
if (this.value != null) {
return this.value;
}
return this.value = LanternTexts.toLegacy(this.text);
}
@SuppressWarnings("deprecation")
public Text getValueAsText() {
if (this.text != null) {
return this.text;
}
return this.text = LanternTexts.fromLegacy(this.value);
}
}
private LanternTextHelper() {
}
}