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.Field;
035import java.lang.reflect.Method;
036
037import static com.plotsquared.core.util.ReflectionUtils.getRefClass;
038
039public class SingleWorldListener implements Listener {
040
041    private final Method methodGetHandleChunk;
042    private Field shouldSave = null;
043
044    public SingleWorldListener() throws Exception {
045        ReflectionUtils.RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
046        this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle").getRealMethod();
047        try {
048            if (PlotSquared.platform().serverVersion()[1] < 17) {
049                ReflectionUtils.RefClass classChunk = getRefClass("{nms}.Chunk");
050                if (PlotSquared.platform().serverVersion()[1] == 13) {
051                    this.shouldSave = classChunk.getField("mustSave").getRealField();
052                } else {
053                    this.shouldSave = classChunk.getField("s").getRealField();
054                }
055            } else if (PlotSquared.platform().serverVersion()[1] == 17) {
056                ReflectionUtils.RefClass classChunk = getRefClass("net.minecraft.world.level.chunk.Chunk");
057                this.shouldSave = classChunk.getField("r").getRealField();
058            } else if (PlotSquared.platform().serverVersion()[1] == 18) {
059                ReflectionUtils.RefClass classChunk = getRefClass("net.minecraft.world.level.chunk.IChunkAccess");
060                this.shouldSave = classChunk.getField("b").getRealField();
061            }
062        } catch (NoSuchFieldException e) {
063            e.printStackTrace();
064        }
065    }
066
067    public void markChunkAsClean(Chunk chunk) {
068        try {
069            Object nmsChunk = methodGetHandleChunk.invoke(chunk);
070            if (shouldSave != null) {
071                this.shouldSave.set(nmsChunk, false);
072            }
073        } catch (Throwable e) {
074            e.printStackTrace();
075        }
076    }
077
078    private void handle(ChunkEvent event) {
079        World world = event.getWorld();
080        String name = world.getName();
081        PlotAreaManager man = PlotSquared.get().getPlotAreaManager();
082        if (!(man instanceof SinglePlotAreaManager)) {
083            return;
084        }
085        if (!SinglePlotArea.isSinglePlotWorld(name)) {
086            return;
087        }
088
089        markChunkAsClean(event.getChunk());
090    }
091
092    //    @EventHandler
093    //    public void onPopulate(ChunkPopulateEvent event) {
094    //        handle(event);
095    //    }
096
097    @EventHandler(priority = EventPriority.LOWEST)
098    public void onChunkLoad(ChunkLoadEvent event) {
099        handle(event);
100    }
101
102}