Hub / src / main / java / com / lifeknight / relaymchub / cosmetics / PhysicalCosmetic.java
PhysicalCosmetic.java
Raw
package com.lifeknight.relaymchub.cosmetics;

import com.lifeknight.relaymchub.Main;
import com.lifeknight.relaymchub.cosmetics.types.ItemApplication;
import com.lifeknight.relaymchub.player.HubPlayer;
import com.lifeknight.relaymcutils.player.SmartItem;
import com.lifeknight.relaymcutils.utilities.SmartNPC;
import com.lifeknight.relayutils.basic.Miscellaneous;
import com.lifeknight.relayutils.player.cosmetics.Cosmetic;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.util.Vector;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class PhysicalCosmetic extends CooldownCosmetic {
    private final Map<Vector, Material> blueprint = new HashMap<>();
    private final double duration;
    private final Map<Long, Instance> instances = new HashMap<>();

    public PhysicalCosmetic(Cosmetic original, int duration) {
        super(original);
        this.duration = duration;
        this.cooldown = duration + 5;
        this.createBlueprint();
        SmartItem smartItem = new SmartItem(this.getOriginal().getRepresentative(), this.getPrettyName(), this.getDescriptionArray());
        smartItem.onPlayerClick((player, b, b2) -> this.use(HubPlayer.getHubPlayer(player), b));
        this.addApplication(new ItemApplication(1, smartItem));
    }

    public void use(HubPlayer hubPlayer, boolean rightClick) {
        if (this.hasCooldown()) {
            if (hubPlayer.enoughSecondsHaveElapsed(this.getCodeName(), this.cooldown)) {
                if (this.onUse(hubPlayer, rightClick)) {
                    hubPlayer.updateCooldown(this.getCodeName());
                }
            } else {
                hubPlayer.showCooldownWarning(this.getCodeName(), this.cooldown);
            }
        } else {
            this.onUse(hubPlayer, rightClick);
        }
    }

    public abstract void createBlueprint();

    public void put(int x, int y, int z, Material material) {
        this.clear(x, y, z);
        this.blueprint.put(new Vector(x, y, z), material);
    }

    protected void putSolid(int x1, int y1, int z1, int x2, int y2, int z2, Material material) {

        for (int x = x1; x <= x2; x++) {
            for (int y = y1; y <= y2; y++) {
                for (int z = z1; z <= z2; z++) {
                    this.put(x, y, z, material);
                }
            }
        }
    }

    protected void putPlatform(int x1, int z1, int x2, int z2, int y, Material material) {
        this.putSolid(x1, y, z1, x2, y, z2, material);
    }

    @Override
    public void tick(HubPlayer hubPlayer) {
        for (Instance value : this.instances.values()) {
            if (value.owner == hubPlayer) {
                value.ticks++;
            }
        }

        for (Instance value : instances.values()) {
            this.tickInstance(value);
        }
    }

    public void tickInstance(Instance instance) {

    }

    public boolean place(HubPlayer hubPlayer, Location location) {
        for (Vector vector : blueprint.keySet()) {
            Location prospectiveLocation = location.clone().add(vector);
            if (!(prospectiveLocation.getBlock().getType().isAir() || prospectiveLocation.getBlock().getType() == Material.LIGHT)) {
                return false;
            }
            for (SmartNPC smartNPC : SmartNPC.getSmartNPCs()) {
                if (smartNPC.getLocation().distance(location.toVector()) < 5) {
                    return false;
                }
            }
        }

        List<Block> unit = new ArrayList<>();
        for (Vector vector : this.blueprint.keySet()) {
            Location prospectiveLocation = location.clone().add(vector);
            Block block = prospectiveLocation.getBlock();
            unit.add(block);

            block.setType(this.blueprint.get(vector));
        }

        long time = System.currentTimeMillis();
        this.instances.put(time, new Instance(unit, hubPlayer, location));

        Main.scheduleSyncDelayedTask(() -> this.reset(time), this.duration);

        return true;
    }

    private void reset(long time) {
        Instance instance = this.instances.remove(time);
        if (instance != null) {
            for (int i = 0; i < instance.blocks.size(); i++) {
                 Main.scheduleSyncDelayedTask(() -> {
                     Block block = Miscellaneous.getRandomEntry(instance.blocks);
                     block.setType(Material.AIR);
                     instance.blocks.remove(block);
                 }, i / 20D);
            }
        }
    }

    protected void clear(int x, int y, int z) {
        for (Vector vector : Miscellaneous.getList(this.blueprint.keySet())) {
            if (vector.distance(new Vector(x, y, z)) == 0) {
                this.blueprint.remove(vector);
            }
        }
    }

    @Override
    public PhysicalCosmetic setCooldown(double seconds) {
        return (PhysicalCosmetic) super.setCooldown(seconds);
    }

    static class Instance {
        private final List<Block> blocks;
        public final long time;
        public int ticks = 0;
        private final HubPlayer owner;
        final Location center;
        public Instance(List<Block> blocks, HubPlayer owner, Location center) {
            this.blocks = blocks;
            this.time = System.currentTimeMillis();
            this.owner = owner;
            this.center = center;
        }
    }
}