/*
* 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.profile;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import com.google.common.base.MoreObjects;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import ninja.leaping.configurate.objectmapping.Setting;
import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
import org.spongepowered.api.data.DataContainer;
import org.spongepowered.api.data.DataQuery;
import org.spongepowered.api.data.MemoryDataContainer;
import org.spongepowered.api.profile.GameProfile;
import org.spongepowered.api.profile.property.ProfileProperty;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nullable;
@ConfigSerializable
public final class LanternGameProfile implements GameProfile {
public static final UUID UNKNOWN_UUID = UUID.fromString("00000000-0000-0000-0000-000000000000");
public static final LanternGameProfile UNKNOWN = new LanternGameProfile(UNKNOWN_UUID, null);
private static final DataQuery NAME = DataQuery.of("Name");
private static final DataQuery UNIQUE_ID = DataQuery.of("UniqueId");
private static final DataQuery PROPERTIES = DataQuery.of("Properties");
private static final DataQuery VALUE = DataQuery.of("Value");
private static final DataQuery SIGNATURE = DataQuery.of("Signature");
@Setting("properties")
private Multimap<String, LanternProfileProperty> properties;
@Setting("uniqueId")
private UUID uniqueId;
@Nullable
@Setting("name")
private String name;
protected LanternGameProfile() {
this.properties = LinkedHashMultimap.create();
}
public LanternGameProfile(UUID uniqueId, @Nullable String name) {
this(uniqueId, name, LinkedHashMultimap.create());
}
@SuppressWarnings("unchecked")
public LanternGameProfile(UUID uniqueId, @Nullable String name, Multimap<String, ProfileProperty> properties) {
this.properties = (Multimap) checkNotNull(properties, "properties");
this.uniqueId = checkNotNull(uniqueId, "uniqueId");
this.name = name;
}
/**
* Creates a copy of this game profile.
*
* @return The copy
*/
public LanternGameProfile copy() {
return new LanternGameProfile(this.uniqueId, this.name, LinkedHashMultimap.create(this.properties));
}
/**
* Creates a copy of this game profile without all the properties.
*
* @return The copy
*/
public LanternGameProfile copyWithoutProperties() {
return new LanternGameProfile(this.uniqueId, this.name);
}
/**
* Creates a new game profile without all the properties.
*
* @return The new game profile
*/
public LanternGameProfile withoutProperties() {
if (this.properties.isEmpty()) {
return this;
}
return new LanternGameProfile(this.uniqueId, this.name);
}
@Override
public UUID getUniqueId() {
//noinspection ConstantConditions
checkState(this.uniqueId != null, "Invalid game profile, the unique id is null!");
return this.uniqueId;
}
@Override
public int getContentVersion() {
return 0;
}
@Override
public DataContainer toContainer() {
final DataContainer container = new MemoryDataContainer()
.set(UNIQUE_ID, this.uniqueId.toString());
if (this.name != null) {
container.set(NAME, this.name);
}
if (!this.properties.isEmpty()) {
final DataContainer propertiesMap = new MemoryDataContainer();
for (String key : this.properties.keySet()) {
final List<DataContainer> entries = Lists.newArrayList();
for (ProfileProperty property : this.properties.get(key)) {
final DataContainer entry = new MemoryDataContainer()
.set(VALUE, property.getValue());
property.getSignature().ifPresent(signature -> entry.set(SIGNATURE, signature));
entries.add(entry);
}
propertiesMap.set(DataQuery.of(key), entries);
}
container.set(PROPERTIES, propertiesMap);
}
return container;
}
@Override
public Optional<String> getName() {
return Optional.ofNullable(this.name);
}
public void setName(@Nullable String name) {
this.name = name;
}
@SuppressWarnings("unchecked")
@Override
public Multimap<String, ProfileProperty> getPropertyMap() {
return (Multimap) this.properties;
}
@Override
public boolean isFilled() {
return this.name != null;
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (other == null || other.getClass() != this.getClass()) {
return false;
}
final LanternGameProfile o = (LanternGameProfile) other;
return Objects.equals(this.name, o.name) && this.uniqueId.equals(o.uniqueId) &&
this.properties.equals(o.properties);
}
@Override
public int hashCode() {
return Objects.hash(this.uniqueId, this.name, this.properties);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.omitNullValues()
.add("uniqueId", this.uniqueId)
.add("name", this.name)
.toString();
}
/*
public static class LanternDataBuilder implements DataBuilder<GameProfile> {
// Why use both the optional and data exception?
@Override
public Optional<GameProfile> build(DataView container) throws InvalidDataException {
String uniqueId = container.getString(UNIQUE_ID).orElse(null);
if (uniqueId == null) {
throw new InvalidDataException("UniqueId is missing!");
}
UUID uniqueId0;
try {
uniqueId0 = UUID.fromString(uniqueId);
} catch (IllegalArgumentException e) {
throw new InvalidDataException("Unknown uniqueId format!", e);
}
String name = container.getString(NAME).orElse(null);
if (name == null) {
throw new InvalidDataException("Name is missing!");
}
List<DataView> views = container.getViewList(PROPERTIES).orElse(null);
List<Property> properties;
if (views != null && !views.isEmpty()) {
properties = Lists.newArrayListWithCapacity(views.size());
for (DataView view : views) {
if (view.contains(NAME) && view.contains(VALUE)) {
properties.add(new Property(view.getString(NAME).get(), view.getString(VALUE).get(),
view.getString(SIGNATURE).orElse(null)));
}
}
} else {
properties = Lists.newArrayList();
}
return Optional.of(new LanternGameProfile(uniqueId0, name, properties));
}
}*/
}