001package net.tnemc.plugincore.sponge.impl; 002 003/* 004 * The New Plugin Core 005 * Copyright (C) 2022 - 2024 Daniel "creatorfromhell" Vidmar 006 * 007 * This program is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU Affero General Public License as published by 009 * the Free Software Foundation, either version 3 of the License, or 010 * (at your option) any later version. 011 * 012 * This program is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 015 * GNU Affero General Public License for more details. 016 * 017 * You should have received a copy of the GNU Affero General Public License 018 * along with this program. If not, see <http://www.gnu.org/licenses/>. 019 */ 020 021import net.tnemc.item.AbstractItemStack; 022import net.tnemc.plugincore.core.compatibility.CmdSource; 023import net.tnemc.plugincore.core.compatibility.LogProvider; 024import net.tnemc.plugincore.core.compatibility.PlayerProvider; 025import net.tnemc.plugincore.core.compatibility.ProxyProvider; 026import net.tnemc.plugincore.core.compatibility.ServerConnector; 027import net.tnemc.plugincore.core.compatibility.helper.CraftingRecipe; 028import net.tnemc.plugincore.core.compatibility.scheduler.SchedulerProvider; 029import net.tnemc.plugincore.sponge.SpongePluginCore; 030import net.tnemc.plugincore.sponge.impl.scheduler.SpongeScheduler; 031import net.tnemc.sponge.SpongeItemCalculationsProvider; 032import net.tnemc.sponge.SpongeItemStack; 033import org.jetbrains.annotations.NotNull; 034import org.jetbrains.annotations.Nullable; 035import org.spongepowered.api.Sponge; 036import org.spongepowered.api.entity.living.player.server.ServerPlayer; 037import org.spongepowered.api.world.DefaultWorldKeys; 038import revxrsal.commands.command.CommandActor; 039import revxrsal.commands.sponge.actor.SpongeCommandActor; 040 041import java.io.File; 042import java.io.FileOutputStream; 043import java.io.IOException; 044import java.io.InputStream; 045import java.io.OutputStream; 046import java.net.URL; 047import java.net.URLConnection; 048import java.util.Optional; 049import java.util.UUID; 050 051/** 052 * SpongeServerProvider 053 * 054 * @author creatorfromhell 055 * @since 0.1.2.0 056 */ 057public class SpongeServerProvider implements ServerConnector { 058 059 private final SpongeItemCalculationsProvider calc = new SpongeItemCalculationsProvider(); 060 private final SpongeProxyProvider proxy = new SpongeProxyProvider(); 061 062 private final SpongeScheduler scheduler; 063 064 protected String world = null; 065 066 public SpongeServerProvider() { 067 this.scheduler = new SpongeScheduler(); 068 } 069 070 @Override 071 public String name() { 072 return "sponge"; 073 } 074 075 /** 076 * Used to replace placeholders from a string. 077 * 078 * @param player The player to use for the placeholder replacement. 079 * @param message The message to replace placeholders in. 080 * 081 * @return The string after placeholders have been replaced. 082 */ 083 @Override 084 public String replacePlaceholder(final UUID player, final String message) { 085 return message; 086 } 087 088 /** 089 * The proxy provider to use for this implementation. 090 * 091 * @return The proxy provider to use for this implementation. 092 */ 093 @Override 094 public ProxyProvider proxy() { 095 return proxy; 096 } 097 098 /** 099 * Used to convert an {@link CommandActor} to a {@link CmdSource}. 100 * 101 * @param actor The command actor. 102 * 103 * @return The {@link CmdSource} for this actor. 104 */ 105 @Override 106 public CmdSource<?> source(@NotNull final CommandActor actor) { 107 return new SpongeCMDSource((SpongeCommandActor)actor); 108 } 109 110 /** 111 * Used to get the amount of online players. 112 * 113 * @return The amount of online players. 114 */ 115 @Override 116 public int onlinePlayers() { 117 return Sponge.server().onlinePlayers().size(); 118 } 119 120 /** 121 * Attempts to find a {@link PlayerProvider player} based on an {@link UUID identifier}. 122 * 123 * @param identifier The identifier 124 * 125 * @return An Optional containing the located {@link PlayerProvider player}, or an empty 126 * Optional if no player is located. 127 */ 128 @Override 129 public Optional<PlayerProvider> findPlayer(@NotNull final UUID identifier) { 130 final Optional<ServerPlayer> player = Sponge.server().player(identifier); 131 return player.map(value->new SpongePlayerProvider(value.user(), SpongePluginCore.instance().getContainer())); 132 } 133 134 /** 135 * This is used to return an instance of an {@link PlayerProvider player} based on the provided 136 * instance's player object. 137 * 138 * @param player The instance of the player. 139 * 140 * @return The initialized {@link PlayerProvider player object}. 141 */ 142 @Override 143 public PlayerProvider initializePlayer(@NotNull final Object player) { 144 if(player instanceof final ServerPlayer playerObj) { 145 return new SpongePlayerProvider(playerObj.user(), SpongePluginCore.instance().getContainer()); 146 } 147 return null; 148 } 149 150 /** 151 * Used to determine if this player has played on this server before. 152 * 153 * @param identifier The {@link UUID} that is associated with the player. 154 * 155 * @return True if the player has played on the server before, otherwise false. 156 */ 157 @Override 158 public boolean playedBefore(final UUID identifier) { 159 final Optional<ServerPlayer> player = Sponge.server().player(identifier); 160 return player.map(ServerPlayer::hasPlayedBefore).orElse(false); 161 } 162 163 /** 164 * Used to determine if a player with the specified username has played 165 * before. 166 * 167 * @param name The username to search for. 168 * 169 * @return True if someone with the specified username has played before, 170 * otherwise false. 171 */ 172 @Override 173 public boolean playedBefore(final String name) { 174 final Optional<ServerPlayer> player = Sponge.server().player(name); 175 return player.map(ServerPlayer::hasPlayedBefore).orElse(false); 176 } 177 178 /** 179 * Used to determine if a player with the specified username is online. 180 * 181 * @param name The username to search for. 182 * 183 * @return True if someone with the specified username is online. 184 */ 185 @Override 186 public boolean online(final String name) { 187 try { 188 189 final Optional<ServerPlayer> player = Sponge.server().player(UUID.fromString(name)); 190 return player.map(ServerPlayer::isOnline).orElse(false); 191 } catch (final Exception e) { 192 193 final Optional<ServerPlayer> player = Sponge.server().player(name); 194 return player.map(ServerPlayer::isOnline).orElse(false); 195 } 196 } 197 198 @Override 199 public Optional<UUID> fromName(final String name) { 200 return Optional.empty(); 201 } 202 203 /** 204 * Used to locate a username for a specific name. This could be called from either a primary or 205 * secondary thread, and should not call back to the Mojang API ever. 206 * 207 * @param id The {@link UUID} to use for the search. 208 * 209 * @return An optional containing the name if exists, otherwise false. 210 */ 211 @Override 212 public Optional<String> fromID(final UUID id) { 213 return Optional.empty(); 214 } 215 216 /** 217 * Returns the name of the default world. 218 * 219 * @return The name of the default world. 220 */ 221 @Override 222 public String defaultWorld() { 223 if(world == null) { 224 world = Sponge.server().worldManager().world(DefaultWorldKeys.DEFAULT).get().key().asString(); 225 } 226 return world; 227 } 228 229 /** 230 * Used to replace colour codes in a string. 231 * @param string The string to format. 232 * @param strip If true, the color codes are striped from the string. 233 * @return The formatted string. 234 */ 235 @Override 236 public String replaceColours(final String string, final boolean strip) { 237 return string; 238 } 239 240 @Override 241 public AbstractItemStack<?> stackBuilder() { 242 return new SpongeItemStack(); 243 } 244 245 @Override 246 public void saveResource(String resourcePath, final boolean replace) { 247 if (resourcePath != null && ! resourcePath.isEmpty()) { 248 249 resourcePath = resourcePath.replace('\\', '/'); 250 251 final LogProvider logger = SpongePluginCore.log(); 252 final InputStream in = this.getResource(resourcePath); 253 if (in == null) { 254 255 throw new IllegalArgumentException("The embedded resource '" + resourcePath + "' cannot be found in the jar."); 256 } else { 257 258 final File outFile = new File(SpongePluginCore.directory(), resourcePath); 259 final int lastIndex = resourcePath.lastIndexOf(47); 260 final File outDir = new File(SpongePluginCore.directory(), resourcePath.substring(0, Math.max(lastIndex, 0))); 261 if (!outDir.exists()) { 262 outDir.mkdirs(); 263 } 264 265 try { 266 if (outFile.exists() && !replace) { 267 } else { 268 269 final OutputStream out = new FileOutputStream(outFile); 270 final byte[] buf = new byte[1024]; 271 272 int len; 273 while((len = in.read(buf)) > 0) { 274 out.write(buf, 0, len); 275 } 276 277 out.close(); 278 in.close(); 279 } 280 } catch (final IOException ignore) { 281 logger.error("Could not save " + outFile.getName() + " to " + outFile); 282 } 283 284 } 285 } else { 286 throw new IllegalArgumentException("ResourcePath cannot be null or empty"); 287 } 288 } 289 290 /** 291 * Provides this implementation's {@link SchedulerProvider scheduler}. 292 * 293 * @return The scheduler for this implementation. 294 */ 295 @Override 296 public SpongeScheduler scheduler() { 297 return scheduler; 298 } 299 300 /** 301 * Used to register a crafting recipe to the server. 302 * 303 * @param key The key for the crafting recipe to be registered. 304 * @param recipe The crafting recipe to register. 305 * 306 * @see CraftingRecipe 307 */ 308 @Override 309 public void registerCrafting(@NotNull final String key, @NotNull final CraftingRecipe recipe) { 310 //TODO: Sponge Register crafting 311 } 312 313 @Override 314 public SpongeItemCalculationsProvider calculations() { 315 return calc; 316 } 317 318 @Override 319 public @Nullable InputStream getResource(@NotNull final String filename) { 320 try { 321 final URL url = this.getClass().getClassLoader().getResource(filename); 322 if (url == null) { 323 return null; 324 } else { 325 final URLConnection connection = url.openConnection(); 326 connection.setUseCaches(false); 327 return connection.getInputStream(); 328 } 329 } catch (final IOException var4) { 330 return null; 331 } 332 } 333}