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.util; 020 021import com.google.common.collect.Maps; 022import com.plotsquared.core.location.World; 023import org.bukkit.Bukkit; 024import org.checkerframework.checker.nullness.qual.NonNull; 025 026import java.lang.ref.SoftReference; 027import java.lang.ref.WeakReference; 028import java.util.Map; 029 030public class BukkitWorld implements World<org.bukkit.World> { 031 032 // Upon world unload we should probably have the P2 BukkitWorld be GCed relatively eagerly, thus freeing the bukkit world. 033 // We also want to avoid circumstances where a bukkit world has been GCed, but a P2 BukkitWorld has not 034 private static final Map<String, WeakReference<BukkitWorld>> worldMap = Maps.newHashMap(); 035 private static final boolean HAS_MIN_Y; 036 037 static { 038 boolean temp; 039 try { 040 org.bukkit.World.class.getMethod("getMinHeight"); 041 temp = true; 042 } catch (NoSuchMethodException e) { 043 temp = false; 044 } 045 HAS_MIN_Y = temp; 046 } 047 048 // We want to allow GC to remove bukkit worlds, but not too eagerly 049 private final SoftReference<org.bukkit.World> world; 050 051 private BukkitWorld(final org.bukkit.World world) { 052 this.world = new SoftReference<>(world); 053 } 054 055 /** 056 * Get a new {@link BukkitWorld} from a world name 057 * 058 * @param worldName World name 059 * @return World instance 060 */ 061 public static @NonNull BukkitWorld of(final @NonNull String worldName) { 062 final org.bukkit.World bukkitWorld = Bukkit.getWorld(worldName); 063 if (bukkitWorld == null) { 064 throw new IllegalArgumentException(String.format("There is no world with the name '%s'", worldName)); 065 } 066 return of(bukkitWorld); 067 } 068 069 /** 070 * Get a new {@link BukkitWorld} from a Bukkit world 071 * 072 * @param world Bukkit world 073 * @return World instance 074 */ 075 public static @NonNull BukkitWorld of(final org.bukkit.World world) { 076 WeakReference<BukkitWorld> bukkitWorldRef = worldMap.get(world.getName()); 077 BukkitWorld bukkitWorld; 078 if (bukkitWorldRef != null && (bukkitWorld = bukkitWorldRef.get()) != null && world.equals(bukkitWorld.world.get())) { 079 return bukkitWorld; 080 } 081 bukkitWorld = new BukkitWorld(world); 082 worldMap.put(world.getName(), new WeakReference<>(bukkitWorld)); 083 return bukkitWorld; 084 } 085 086 /** 087 * Get the min world height from a Bukkit {@link org.bukkit.World}. Inclusive 088 * 089 * @since 6.6.0 090 */ 091 public static int getMinWorldHeight(org.bukkit.World world) { 092 return HAS_MIN_Y ? world.getMinHeight() : 0; 093 } 094 095 /** 096 * Get the max world height from a Bukkit {@link org.bukkit.World}. Exclusive 097 * 098 * @since 6.6.0 099 */ 100 public static int getMaxWorldHeight(org.bukkit.World world) { 101 return HAS_MIN_Y ? world.getMaxHeight() : 256; 102 } 103 104 @Override 105 public org.bukkit.World getPlatformWorld() { 106 org.bukkit.World world = this.world.get(); 107 if (world == null) { 108 throw new IllegalStateException("Bukkit platform world was unloaded from memory"); 109 } 110 return world; 111 } 112 113 @Override 114 public @NonNull String getName() { 115 return this.getPlatformWorld().getName(); 116 } 117 118 @Override 119 public int getMinHeight() { 120 return getMinWorldHeight(getPlatformWorld()); 121 } 122 123 @Override 124 public int getMaxHeight() { 125 return getMaxWorldHeight(getPlatformWorld()) - 1; 126 } 127 128 @Override 129 public boolean equals(final Object o) { 130 if (this == o) { 131 return true; 132 } 133 if (o == null || getClass() != o.getClass()) { 134 return false; 135 } 136 final BukkitWorld that = (BukkitWorld) o; 137 return world.equals(that.world); 138 } 139 140 @Override 141 public int hashCode() { 142 return world.hashCode(); 143 } 144 145 public String toString() { 146 return "BukkitWorld(world=" + this.world + ")"; 147 } 148 149}