de.craftolution.craftoplugin4.services.playerstorage.DatabaseStoredPlayer.java Source code

Java tutorial

Introduction

Here is the source code for de.craftolution.craftoplugin4.services.playerstorage.DatabaseStoredPlayer.java

Source

/*
 * This file is part of CraftoPlugin, licensed under the MIT License (MIT).
 *
 * Copyright (c) 2017 CraftolutionDE <https://craftolution.de>
 *
 * 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.
 *
 * Website: http://craftolution.de/
 * Contact: support@craftolution.de
 */
package de.craftolution.craftoplugin4.services.playerstorage;

import java.io.Serializable;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

import de.craftolution.craftodb.query.Query;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.PlayerInventory;

import com.google.common.collect.Lists;
import com.google.common.util.concurrent.AtomicDouble;

import de.craftolution.craftoapi.element.exceptions.UnavailableException;
import de.craftolution.craftolibrary.Blocking;
import de.craftolution.craftolibrary.Check;
import de.craftolution.craftolibrary.Scheduled;
import de.craftolution.craftolibrary.ToStringable;
import de.craftolution.craftolibrary.change.ChangeRecorder;
import de.craftolution.craftoplugin.core.structs.Language;
import de.craftolution.craftoplugin4.services.database.DatabaseService;

/**
 * TODO: File description for DatabaseStoredPlayer.java
 *
 * @author Fear837, Pingebam
 * @since 04.01.2017
 * @see <a href="https://github.com/Craftolution">Craftolution on Github</a>
 */
public class DatabaseStoredPlayer implements StoredPlayer, Serializable, ToStringable, Comparable<StoredPlayer> {

    private static final long serialVersionUID = 7060769784491101192L;

    private int id = Integer.MIN_VALUE;
    private String name;
    private String currentAddress;
    private Instant firstJoin;
    private Instant lastJoin;
    private final AtomicReference<Duration> playtime;
    private final AtomicDouble money;
    private final AtomicBoolean muted;
    private final AtomicBoolean frozen;
    private final AtomicBoolean vanished;
    private Locale locale;
    private UUID uniqueId;
    private final List<String> names = Lists.newArrayListWithCapacity(1);
    private final List<StoredPlayer> friends = Lists.newArrayListWithCapacity(0);

    private final ChangeRecorder recorder = new ChangeRecorder();

    DatabaseStoredPlayer(final int id, final UUID uniqueId) {
        this.id = id;
        this.uniqueId = uniqueId;
        this.playtime = new AtomicReference<>();
        this.playtime.set(Duration.ZERO);
        this.money = new AtomicDouble();
        this.muted = new AtomicBoolean();
        this.frozen = new AtomicBoolean();
        this.vanished = new AtomicBoolean();
    }

    /** TODO: Documentation */
    void setId(final int id) {
        if (this.id == Integer.MIN_VALUE) {
            this.id = id;
        }
    }

    /** TODO: Documentation */
    void setName(final String name) {
        Check.notNullNotEmpty(name, "The name must neither be null nor empty!");

        this.recorder.recordIfNotEqual("name", name, this.getName());
        this.name = name;
    }

    /** TODO: Documentation */
    void setCurrentAddress(String address) {
        Check.notNullNotEmpty(address, "The address must neither be null nor empty!");
        address = address.replace("/", "");

        this.recorder.recordIfNotEqual("ip", address, this.getCurrentAddress());
        this.currentAddress = address;
    }

    /** TODO: Documentation */
    void setFirstJoin(final Instant firstJoin) {
        Check.notNull(firstJoin, "The firstJoin must not be null!");

        this.recorder.recordIfNotEqual("first_joined", firstJoin, this.getFirstJoin());
        this.firstJoin = firstJoin;
    }

    /** TODO: Documentation */
    void setLastJoin(final Instant lastJoin) {
        Check.notNull(lastJoin, "The lastJoin cannot be null!");

        this.recorder.recordIfNotEqual("last_joined", lastJoin, this.getLastJoin());
        this.lastJoin = lastJoin;
    }

    /** TODO: Documentation */
    void setLocale(final Locale locale) {
        this.locale = Check.notNull(locale, "The locale cannot be null!");
    }

    /** TODO: Documentation */
    void setUniqueId(final UUID uuid) {
        this.uniqueId = Check.notNull(uuid, "The uuid cannot be null!");
    }

    @Override
    public int getId() {
        return this.id;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public String getCurrentAddress() {
        return this.currentAddress;
    }

    @Override
    public Instant getFirstJoin() {
        return this.firstJoin;
    }

    @Override
    public Instant getLastJoin() {
        return this.lastJoin;
    }

    @Override
    public Duration getPlaytime() {
        return this.playtime.get();
    }

    @Override
    public double getMoney() {
        return this.money.get();
    }

    @Override
    public boolean isMuted() {
        return this.muted.get();
    }

    @Override
    public boolean isFrozen() {
        return this.frozen.get();
    }

    @Override
    public boolean isVanished() {
        return this.vanished.get();
    }

    @Override
    public Language getLanguage() {
        return Language.getDefault();
    }

    @Override
    public Locale getLocale() {
        return this.locale;
    }

    @Override
    public UUID getUniqueId() {
        return this.uniqueId;
    }

    @Override
    public List<String> getNames() {
        return this.names;
    }

    @Override
    public List<StoredPlayer> getFriends() {
        return this.friends;
    }

    @Override
    public Optional<Player> getPlayer() {
        return Optional.ofNullable(Bukkit.getServer().getPlayer(this.uniqueId));
    }

    @Override
    public Optional<OfflinePlayer> getOfflinePlayer() {
        return Optional.ofNullable(Bukkit.getServer().getOfflinePlayer(this.uniqueId));
    }

    @Override
    public Optional<PlayerInventory> getInventory() {
        final Optional<Player> player = this.getPlayer();
        return player.isPresent() ? Optional.of(player.get().getInventory()) : Optional.empty();
    }

    @Override
    public Optional<Location> getLocation() {
        final Optional<Player> player = this.getPlayer();
        return player.isPresent() ? Optional.of(player.get().getLocation()) : Optional.empty();
    }

    @Override
    public boolean isOnline() {
        final Optional<Player> player = this.getPlayer();
        return player.isPresent() ? player.get().isOnline() : false;
    }

    @Override
    public boolean isAlive() {
        final Optional<Player> player = this.getPlayer();
        return player.isPresent() ? !player.get().isDead() : false;
    }

    @Override
    public void setPlaytime(final Duration duration) {
        Check.notNull(duration, "The duration cannot be null!");
        synchronized (this.playtime) {
            this.playtime.set(duration);
        }
        this.recorder.record("playtime", this.getPlaytime().toMinutes());
    }

    @Override
    public void addPlaytime(final Duration duration) {
        Check.notNull(duration, "The duration cannot be null!");
        synchronized (this.playtime) {
            this.playtime.set(this.playtime.get().plus(duration));
        }
        this.recorder.record("playtime", this.getPlaytime().toMinutes());
    }

    @Override
    public void setMoney(final double money) {
        synchronized (this.money) {
            this.money.set(money);
        }
        this.recorder.record("money", this.getMoney());
    }

    @Override
    public void setMuted(final boolean muted) {
        synchronized (this.muted) {
            this.muted.set(muted);
        }
        this.recorder.record("silented", this.isMuted());
    }

    @Override
    public void setFrozen(final boolean frozen) {
        synchronized (this.frozen) {
            this.frozen.set(frozen);
        }
        this.recorder.record("blocked", this.isFrozen());
    }

    @Override
    public void setVanished(final boolean vanished) {
        synchronized (this.vanished) {
            this.vanished.set(vanished);
        }
        this.recorder.record("vanished", this.isVanished());
    }

    @Override
    @Blocking
    public boolean addFriend(final StoredPlayer friend) throws UnavailableException {
        Check.notNull(friend, "The friend cannot be null!");

        final DatabaseService db = DatabaseService.instance().get();

        if (!this.friends.contains(friend)) {
            synchronized (this.friends) {
                final Query query = Query.insert("cp_friends").columns("playerid", "friend")
                        .values(String.valueOf(this.id), String.valueOf(friend.getId())).onDuplicateKey("id=id");

                db.execute(query).andClose();

                return this.friends.add(friend);
            }
        }
        return false;
    }

    @Override
    @Blocking
    public boolean removeFriend(final StoredPlayer friend) {
        Check.notNull(friend, "The friend cannot be null!");

        final DatabaseService db = DatabaseService.instance().get();

        if (this.friends.contains(friend)) {
            synchronized (this.friends) {
                final Query query = Query.delete("cp_friends").where("`playerid` = " + this.id,
                        "`friend` = " + friend.getId());

                db.execute(query).andClose();

                return this.friends.remove(friend);
            }
        }
        return false;
    }

    // TODO: Reimplement once RecordModule is ported over
    //   @Override
    //   public Scheduled<Result<Record>> registerRecord(final int rating, final String text, final @Nullable StoredPlayer creator, final @Nullable Location loc) {
    //      Check.notNull(text, "The text cannot be null!");
    //      
    //      return new Scheduled<Result<Record>>(Duration.ZERO, true, () -> {
    //         final StoredPlayer realCreator = creator == null ? StoredPlayer.getCraftobot() : creator;
    //         final Location realLoc = loc == null ? new Location(Utility.getMainWorld(), 0, 70, 0) : loc;
    //
    //         Optional<RecordModule> recordModule = CraftoPlugin.instance().getModules().getModule(RecordModule.class);
    //         if (!recordModule.isPresent()) { return Result.completeFailure(); }
    //
    //         try {
    //            Record r = null; // recordModule.get().createRecord(this, rating, realLoc, text, realCreator); TODO: Reimplement registerRecord() once modules are working again
    //            return Result.of(r);
    //         }
    //         catch (Exception e) { return Result.ofException(e); }
    //      });
    //      
    //      return new Scheduled<Result<Record>>(Duration.ZERO, true, () -> {
    //         Optional<RecordModule> recordModule = CraftoPlugin.instance().getModules().getModule(RecordModule.class);
    //         if (!recordModule.isPresent()) { return Optional.empty(); }
    //
    //         try {
    //            Record r = recordModule.get().createRecord(this, rating, loc, text, creator);
    //            return Result.of(r);
    //         }
    //         catch (Exception e) { return Result.ofException(e); }
    //
    //         
    //      });
    //      Check.nonNulls("The type/text cannot be null!", type, text);
    //      return new Scheduled<>(Duration.ZERO, true, () -> {
    //         final Timestamp now = new Timestamp(System.currentTimeMillis());
    //         final InsertQuery insertQuery = Query.insert("cp_history")
    //               .insert("playerid", String.valueOf(this.getId()))
    //               .insert("type", type.name())
    //               .insert("text", text);
    //
    //         if (loc != null) {
    //            insertQuery.insert("loc_x", String.valueOf(loc.getBlockX()))
    //            .insert("loc_y", String.valueOf(loc.getBlockY()))
    //            .insert("loc_z", String.valueOf(loc.getBlockZ()))
    //            .insert("loc_yaw", String.valueOf(loc.getYaw()))
    //            .insert("loc_pitch", String.valueOf(loc.getPitch()));
    //         }
    //
    //         if (creator != null) {
    //            insertQuery.insert("created_by", String.valueOf(creator.getId()));
    //         }
    //
    //         final QueryResult result = this.plugin.getDB().execute(insertQuery);
    //         if (result.wasSuccess() && !result.getGeneratedKeys().isEmpty()) {
    //            final int id = result.getGeneratedKeys().get(0);
    //            final Record record = new Record(id, this, type, text, loc, creator, now);
    //            synchronized (this.records) { this.records.add(record); }
    //            return Optional.of(record);
    //         }
    //
    //         return Optional.empty();
    //      });
    //   }

    @Override
    public boolean save() { // Keep in mind, when reimplementing save(), some changes contain values that are Instant instances
        //      if (this.recorder.hasChanges()) {
        //         DatabaseService db = DatabaseService.instance().get();
        //         
        //         final UpdateQuery query = Query.update("cp_players").where("`id` = " + this.getId());
        //         
        //         for (Change change : this.recorder.getChanges()) {
        //            query.column(change.getKey(), change.getValue());
        //         }
        //         
        //         return db.execute(query).ifExceptionThrow("Failed to save changes of StoredPlayer with id '" + this.id + "'").wasSuccess();
        //      }
        //      if (!this.changes.isEmpty()) {
        //
        //         synchronized (this.changes) {
        //            for (final String change : this.changes) {
        //               query.columns(change);
        //            }
        //            this.changes.clear();
        //         }
        //
        //         final QueryResult result = this.plugin.getDB().execute(query).ifException(r -> CraftoMessenger.report(this.getClass(), "Failed to sav craftoplayer", r));
        //         return result.wasSuccess();
        //      }
        return false;
    }

    @Override
    public Scheduled<Boolean> saveAsync() {
        return new Scheduled<>(Duration.ZERO, true, this::save);
    }

    @Override
    public int compareTo(final StoredPlayer player) {
        return this.getLastJoin().isAfter(player.getLastJoin()) ? 1 : 0;
    }

    @Override
    public String toString() {
        return "DatabaseStoredPlayer{" + "id=" + id + ", name='" + name + '\'' + '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        DatabaseStoredPlayer that = (DatabaseStoredPlayer) o;
        return Objects.equals(uniqueId, that.uniqueId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(uniqueId);
    }

}