001/*
002 * PlotSquared, a land and world management plugin for Minecraft.
003 * Copyright (C) IntellectualSites <https://intellectualsites.com>
004 * Copyright (C) IntellectualSites team and contributors
005 *
006 * This program is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * This program is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
018 */
019package com.plotsquared.bukkit.listener;
020
021import com.plotsquared.core.PlotSquared;
022import com.plotsquared.core.plot.world.PlotAreaManager;
023import com.plotsquared.core.plot.world.SinglePlotArea;
024import com.plotsquared.core.plot.world.SinglePlotAreaManager;
025import com.plotsquared.core.util.ReflectionUtils;
026import org.bukkit.Chunk;
027import org.bukkit.World;
028import org.bukkit.event.EventHandler;
029import org.bukkit.event.EventPriority;
030import org.bukkit.event.Listener;
031import org.bukkit.event.world.ChunkEvent;
032import org.bukkit.event.world.ChunkLoadEvent;
033
034import java.lang.reflect.Method;
035
036import static com.plotsquared.core.util.ReflectionUtils.getRefClass;
037
038public class SingleWorldListener implements Listener {
039
040    private final Method methodSetUnsaved;
041    private Method methodGetHandleChunk;
042    private Object objChunkStatusFull = null;
043
044    public SingleWorldListener() throws Exception {
045        ReflectionUtils.RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
046        ReflectionUtils.RefClass classChunkAccess = getRefClass("net.minecraft.world.level.chunk.IChunkAccess");
047        this.methodSetUnsaved = classChunkAccess.getMethod("a", boolean.class).getRealMethod();
048        try {
049            this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle").getRealMethod();
050        } catch (NoSuchMethodException ignored) {
051            try {
052                ReflectionUtils.RefClass classChunkStatus = getRefClass("net.minecraft.world.level.chunk.ChunkStatus");
053                this.objChunkStatusFull = classChunkStatus.getRealClass().getField("n").get(null);
054                this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle", classChunkStatus.getRealClass()).getRealMethod();
055            } catch (NoSuchMethodException ex) {
056                throw new RuntimeException(ex);
057            }
058        }
059    }
060
061    public void markChunkAsClean(Chunk chunk) {
062        try {
063            Object nmsChunk = objChunkStatusFull != null
064                    ? this.methodGetHandleChunk.invoke(chunk, objChunkStatusFull)
065                    : this.methodGetHandleChunk.invoke(chunk);
066            methodSetUnsaved.invoke(nmsChunk, false);
067        } catch (Throwable e) {
068            e.printStackTrace();
069        }
070    }
071
072    private void handle(ChunkEvent event) {
073        World world = event.getWorld();
074        String name = world.getName();
075        PlotAreaManager man = PlotSquared.get().getPlotAreaManager();
076        if (!(man instanceof SinglePlotAreaManager)) {
077            return;
078        }
079        if (!SinglePlotArea.isSinglePlotWorld(name)) {
080            return;
081        }
082        int x = event.getChunk().getX();
083        int z = event.getChunk().getZ();
084        if (x < 16 && x > -16 && z < 16 && z > -16) {
085            // Allow spawn to generate
086            return;
087        }
088        markChunkAsClean(event.getChunk());
089    }
090
091    //    @EventHandler
092    //    public void onPopulate(ChunkPopulateEvent event) {
093    //        handle(event);
094    //    }
095
096    @EventHandler(priority = EventPriority.LOWEST)
097    public void onChunkLoad(ChunkLoadEvent event) {
098        handle(event);
099    }
100
101}