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                String chunkStatus = PlotSquared.platform().serverVersion()[1] < 21
053                        ? "net.minecraft.world.level.chunk" + ".ChunkStatus"
054                        : "net.minecraft.world.level.chunk.status.ChunkStatus";
055                ReflectionUtils.RefClass classChunkStatus = getRefClass(chunkStatus);
056                this.objChunkStatusFull = classChunkStatus.getRealClass().getField("n").get(null);
057                this.methodGetHandleChunk = classCraftChunk
058                        .getMethod("getHandle", classChunkStatus.getRealClass())
059                        .getRealMethod();
060            } catch (NoSuchMethodException ex) {
061                throw new RuntimeException(ex);
062            }
063        }
064    }
065
066    public void markChunkAsClean(Chunk chunk) {
067        try {
068            Object nmsChunk = objChunkStatusFull != null
069                    ? this.methodGetHandleChunk.invoke(chunk, objChunkStatusFull)
070                    : this.methodGetHandleChunk.invoke(chunk);
071            methodSetUnsaved.invoke(nmsChunk, false);
072        } catch (Throwable e) {
073            e.printStackTrace();
074        }
075    }
076
077    private void handle(ChunkEvent event) {
078        World world = event.getWorld();
079        String name = world.getName();
080        PlotAreaManager man = PlotSquared.get().getPlotAreaManager();
081        if (!(man instanceof SinglePlotAreaManager)) {
082            return;
083        }
084        if (!SinglePlotArea.isSinglePlotWorld(name)) {
085            return;
086        }
087        int x = event.getChunk().getX();
088        int z = event.getChunk().getZ();
089        if (x < 16 && x > -16 && z < 16 && z > -16) {
090            // Allow spawn to generate
091            return;
092        }
093        markChunkAsClean(event.getChunk());
094    }
095
096    //    @EventHandler
097    //    public void onPopulate(ChunkPopulateEvent event) {
098    //        handle(event);
099    //    }
100
101    @EventHandler(priority = EventPriority.LOWEST)
102    public void onChunkLoad(ChunkLoadEvent event) {
103        // disable this for now, should address https://github.com/IntellectualSites/PlotSquared/issues/4413
104        // handle(event);
105    }
106
107}