/*
* 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.gson;
import static org.lanternpowered.server.text.gson.TextConstants.*;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import org.lanternpowered.server.scoreboard.LanternScore;
import org.lanternpowered.server.text.LanternTexts;
import org.spongepowered.api.scoreboard.Score;
import org.spongepowered.api.scoreboard.objective.Objective;
import org.spongepowered.api.text.ScoreText;
import org.spongepowered.api.text.Text;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Optional;
import java.util.Set;
final class JsonTextScoreSerializer extends JsonTextBaseSerializer implements JsonSerializer<ScoreText>, JsonDeserializer<ScoreText> {
private final boolean networkingFormat;
JsonTextScoreSerializer(boolean networkingFormat) {
this.networkingFormat = networkingFormat;
}
@Override
public ScoreText deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
final JsonObject obj = element.getAsJsonObject();
final Text name = LanternTexts.fromLegacy(obj.get(SCORE_NAME).getAsString());
// Try to parse the value
int value = 0;
try {
value = Integer.parseInt(obj.get(SCORE_VALUE).getAsString());
} catch (NumberFormatException ignored) {
}
final String baseObjective = obj.get(SCORE_MAIN_OBJECTIVE).getAsString();
final Set<Objective> objectives = new HashSet<>();
if (!baseObjective.isEmpty()) {
this.tryAddObjective(baseObjective, objectives);
}
if ((element = obj.get(SCORE_EXTRA_OBJECTIVES)) != null) {
final JsonArray array = element.getAsJsonArray();
for (JsonElement jsonElement : array) {
this.tryAddObjective(jsonElement.getAsString(), objectives);
}
}
String override = null;
if ((element = obj.get(SCORE_OVERRIDE)) != null) {
override = element.getAsString();
}
final Score score = new LanternScore(name);
// TODO: How to handle the objectives?
// We cannot add them to the score without attaching the
// score to the objective
score.setScore(value);
final ScoreText.Builder builder = Text.builder(score).override(override);
deserialize(obj, builder, context);
return builder.build();
}
private void tryAddObjective(String objectiveName, Set<Objective> objectives) {
// TODO: Search all the world scoreboards for objectives
}
@Override
public JsonElement serialize(ScoreText src, Type typeOfSrc, JsonSerializationContext context) {
// Lantern:
// This is a field added by sponge to be able to override
// the text provided by this component.
final Optional<String> override = src.getOverride();
// If we are using the networking format and there is an override present, just use
// the override as a literal text object
if (this.networkingFormat && override.isPresent()) {
return new JsonPrimitive(override.get());
}
// There are here some extra fields to represent the (lantern/sponge) score text object,
// while they are not supported by sponge itself, it seems worth it to provide this
// This will still remain compatible with vanilla.
final JsonObject obj = new JsonObject();
final Score score = src.getScore();
obj.addProperty(SCORE_NAME, LanternTexts.toLegacy(score.getName()));
final Iterator<Objective> it = score.getObjectives().iterator();
if (it.hasNext()) {
obj.addProperty(SCORE_MAIN_OBJECTIVE, it.next().getName());
// Lantern:
// Provide a list with all the extra objectives that
// are attached to the score.
// There is no need to send this to the client.
if (!this.networkingFormat) {
if (it.hasNext()) {
final JsonArray array = new JsonArray();
while (it.hasNext()) {
array.add(new JsonPrimitive(it.next().getName()));
}
obj.add(SCORE_EXTRA_OBJECTIVES, array);
}
}
} else {
// This field must always be specified to be valid score json,
// making it empty will prevent issues
obj.addProperty(SCORE_MAIN_OBJECTIVE, "");
}
override.ifPresent(v -> obj.addProperty(SCORE_OVERRIDE, override.get()));
obj.addProperty(SCORE_VALUE, Integer.toString(score.getScore()));
serialize(obj, src, context);
return obj;
}
}