PageRenderTime 58ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/forge-1.13.2/src/main/java/org/dynmap/forge_1_13_2/DynmapPlugin.java

http://github.com/webbukkit/dynmap
Java | 2133 lines | 1653 code | 164 blank | 316 comment | 293 complexity | 2b0108a84a709acdbb624dfbe628957a MD5 | raw file
Possible License(s): Apache-2.0
  1. package org.dynmap.forge_1_13_2;
  2. import java.io.File;
  3. import java.io.InputStream;
  4. import java.lang.reflect.Field;
  5. import java.net.InetSocketAddress;
  6. import java.net.SocketAddress;
  7. import java.util.ArrayList;
  8. import java.util.Arrays;
  9. import java.util.Collections;
  10. import java.util.HashMap;
  11. import java.util.HashSet;
  12. import java.util.Iterator;
  13. import java.util.List;
  14. import java.util.Map;
  15. import java.util.Map.Entry;
  16. import java.util.Optional;
  17. import java.util.PriorityQueue;
  18. import java.util.Set;
  19. import java.util.UUID;
  20. import java.util.concurrent.Callable;
  21. import java.util.concurrent.CancellationException;
  22. import java.util.concurrent.ConcurrentLinkedQueue;
  23. import java.util.concurrent.ExecutionException;
  24. import java.util.concurrent.Future;
  25. import java.util.concurrent.FutureTask;
  26. import java.util.regex.Pattern;
  27. import net.minecraft.block.Block;
  28. import net.minecraft.block.BlockFlowingFluid;
  29. import net.minecraft.block.material.Material;
  30. import net.minecraft.block.state.IBlockState;
  31. import net.minecraft.command.CommandException;
  32. import net.minecraft.command.CommandSource;
  33. import net.minecraft.command.Commands;
  34. import net.minecraft.entity.Entity;
  35. import net.minecraft.entity.player.EntityPlayer;
  36. import net.minecraft.entity.player.EntityPlayerMP;
  37. import net.minecraft.fluid.IFluidState;
  38. import net.minecraft.init.Blocks;
  39. import net.minecraft.item.Item;
  40. import net.minecraft.network.NetHandlerPlayServer;
  41. import net.minecraft.network.NetworkManager;
  42. import net.minecraft.network.play.server.SPacketTitle;
  43. import net.minecraft.particles.IParticleData;
  44. import net.minecraft.server.MinecraftServer;
  45. import net.minecraft.server.management.UserListBans;
  46. import net.minecraft.server.management.UserListIPBans;
  47. import net.minecraft.server.management.UserListOps;
  48. import net.minecraft.server.management.PlayerProfileCache;
  49. import net.minecraft.util.ObjectIntIdentityMap;
  50. import net.minecraft.util.ResourceLocation;
  51. import net.minecraft.util.SoundCategory;
  52. import net.minecraft.util.SoundEvent;
  53. import net.minecraft.util.math.BlockPos;
  54. import net.minecraft.util.math.ChunkPos;
  55. import net.minecraft.util.registry.IRegistry;
  56. import net.minecraft.util.registry.RegistryNamespaced;
  57. import net.minecraft.util.text.ITextComponent;
  58. import net.minecraft.util.text.TextComponentString;
  59. import net.minecraft.world.IBlockReader;
  60. import net.minecraft.world.IWorld;
  61. import net.minecraft.world.IWorldEventListener;
  62. import net.minecraft.world.World;
  63. import net.minecraft.world.WorldServer;
  64. import net.minecraft.world.biome.Biome;
  65. import net.minecraft.world.chunk.Chunk;
  66. import net.minecraft.world.chunk.ChunkSection;
  67. import net.minecraft.world.chunk.IChunk;
  68. import net.minecraftforge.common.MinecraftForge;
  69. import net.minecraftforge.event.ServerChatEvent;
  70. import net.minecraftforge.event.world.ChunkEvent;
  71. import net.minecraftforge.event.world.WorldEvent;
  72. import net.minecraftforge.fml.ModList;
  73. import net.minecraftforge.fml.ModContainer;
  74. import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerChangedDimensionEvent;
  75. import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
  76. import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent;
  77. import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerRespawnEvent;
  78. import net.minecraftforge.registries.ForgeRegistries;
  79. import net.minecraftforge.registries.ForgeRegistry;
  80. import net.minecraftforge.registries.RegistryManager;
  81. import net.minecraftforge.fml.common.gameevent.TickEvent;
  82. import net.minecraftforge.fml.common.registry.GameRegistry;
  83. import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
  84. import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
  85. import net.minecraftforge.forgespi.language.IModInfo;
  86. import org.apache.commons.codec.Charsets;
  87. import org.apache.commons.codec.binary.Base64;
  88. import org.apache.logging.log4j.LogManager;
  89. import org.apache.logging.log4j.Logger;
  90. import org.apache.maven.artifact.versioning.ArtifactVersion;
  91. import org.dynmap.ConfigurationNode;
  92. import org.dynmap.DynmapChunk;
  93. import org.dynmap.DynmapCommonAPIListener;
  94. import org.dynmap.DynmapCore;
  95. import org.dynmap.DynmapLocation;
  96. import org.dynmap.DynmapWorld;
  97. import org.dynmap.Log;
  98. import org.dynmap.MapManager;
  99. import org.dynmap.PlayerList;
  100. import org.dynmap.common.BiomeMap;
  101. import org.dynmap.common.DynmapCommandSender;
  102. import org.dynmap.common.DynmapPlayer;
  103. import org.dynmap.common.DynmapServerInterface;
  104. import org.dynmap.common.DynmapListenerManager.EventType;
  105. import org.dynmap.debug.Debug;
  106. import org.dynmap.forge_1_13_2.DmapCommand;
  107. import org.dynmap.forge_1_13_2.DmarkerCommand;
  108. import org.dynmap.forge_1_13_2.DynmapCommand;
  109. import org.dynmap.forge_1_13_2.DynmapMod;
  110. import org.dynmap.forge_1_13_2.permissions.FilePermissions;
  111. import org.dynmap.forge_1_13_2.permissions.OpPermissions;
  112. import org.dynmap.forge_1_13_2.permissions.PermissionProvider;
  113. import org.dynmap.permissions.PermissionsHandler;
  114. import org.dynmap.renderer.DynmapBlockState;
  115. import org.dynmap.utils.DynIntHashMap;
  116. import org.dynmap.utils.DynmapLogger;
  117. import org.dynmap.utils.MapChunkCache;
  118. import org.dynmap.utils.VisibilityLimit;
  119. import com.google.common.collect.Iterables;
  120. import com.google.gson.Gson;
  121. import com.google.gson.GsonBuilder;
  122. import com.google.gson.JsonParseException;
  123. import com.mojang.authlib.GameProfile;
  124. import com.mojang.authlib.properties.Property;
  125. import com.mojang.brigadier.CommandDispatcher;
  126. import com.mojang.brigadier.arguments.StringArgumentType;
  127. import com.mojang.brigadier.builder.LiteralArgumentBuilder;
  128. import com.mojang.brigadier.builder.RequiredArgumentBuilder;
  129. import com.mojang.brigadier.exceptions.CommandSyntaxException;
  130. import net.minecraft.state.IProperty;
  131. import net.minecraftforge.eventbus.api.SubscribeEvent;
  132. public class DynmapPlugin
  133. {
  134. private DynmapCore core;
  135. private PermissionProvider permissions;
  136. private boolean core_enabled;
  137. public SnapshotCache sscache;
  138. public PlayerList playerList;
  139. private MapManager mapManager;
  140. private net.minecraft.server.MinecraftServer server;
  141. public static DynmapPlugin plugin;
  142. private ChatHandler chathandler;
  143. private HashMap<String, Integer> sortWeights = new HashMap<String, Integer>();
  144. // Drop world load ticket after 30 seconds
  145. private long worldIdleTimeoutNS = 30 * 1000000000L;
  146. private HashMap<String, ForgeWorld> worlds = new HashMap<String, ForgeWorld>();
  147. private IWorld last_world;
  148. private ForgeWorld last_fworld;
  149. private Map<String, ForgePlayer> players = new HashMap<String, ForgePlayer>();
  150. //TODO private ForgeMetrics metrics;
  151. private HashSet<String> modsused = new HashSet<String>();
  152. private ForgeServer fserver = new ForgeServer();
  153. private boolean tickregistered = false;
  154. // TPS calculator
  155. private double tps;
  156. private long lasttick;
  157. private long avgticklen;
  158. // Per tick limit, in nsec
  159. private long perTickLimit = (50000000); // 50 ms
  160. private boolean isMCPC = false;
  161. private boolean useSaveFolder = true;
  162. private static final int SIGNPOST_ID = 63;
  163. private static final int WALLSIGN_ID = 68;
  164. private static final String[] TRIGGER_DEFAULTS = { "blockupdate", "chunkpopulate", "chunkgenerate" };
  165. private static final Pattern patternControlCode = Pattern.compile("(?i)\\u00A7[0-9A-FK-OR]");
  166. public static class BlockUpdateRec {
  167. IWorld w;
  168. String wid;
  169. int x, y, z;
  170. }
  171. ConcurrentLinkedQueue<BlockUpdateRec> blockupdatequeue = new ConcurrentLinkedQueue<BlockUpdateRec>();
  172. public static DynmapBlockState[] stateByID;
  173. /**
  174. * Initialize block states (org.dynmap.blockstate.DynmapBlockState)
  175. */
  176. public void initializeBlockStates() {
  177. stateByID = new DynmapBlockState[512*32]; // Simple map - scale as needed
  178. Arrays.fill(stateByID, DynmapBlockState.AIR); // Default to air
  179. ObjectIntIdentityMap<IBlockState> bsids = Block.BLOCK_STATE_IDS;
  180. DynmapBlockState basebs = null;
  181. Block baseb = null;
  182. int baseidx = 0;
  183. Iterator<IBlockState> iter = bsids.iterator();
  184. while (iter.hasNext()) {
  185. IBlockState bs = iter.next();
  186. int idx = bsids.get(bs);
  187. if (idx >= stateByID.length) {
  188. int plen = stateByID.length;
  189. stateByID = Arrays.copyOf(stateByID, idx*11/10); // grow array by 10%
  190. Arrays.fill(stateByID, plen, stateByID.length, DynmapBlockState.AIR);
  191. }
  192. Block b = bs.getBlock();
  193. // If this is new block vs last, it's the base block state
  194. if (b != baseb) {
  195. basebs = null;
  196. baseidx = idx;
  197. baseb = b;
  198. }
  199. ResourceLocation ui = b.getRegistryName();
  200. if (ui == null) {
  201. continue;
  202. }
  203. String bn = ui.getNamespace() + ":" + ui.getPath();
  204. // Only do defined names, and not "air"
  205. if (!bn.equals(DynmapBlockState.AIR_BLOCK)) {
  206. Material mat = bs.getMaterial();
  207. String statename = "";
  208. for(IProperty p : bs.getProperties()) {
  209. if (statename.length() > 0) {
  210. statename += ",";
  211. }
  212. statename += p.getName() + "=" + bs.get(p).toString();
  213. }
  214. //Log.info("bn=" + bn + ", statenme=" + statename + ",idx=" + idx + ",baseidx=" + baseidx);
  215. DynmapBlockState dbs = new DynmapBlockState(basebs, idx - baseidx, bn, statename, mat.toString(), idx);
  216. stateByID[idx] = dbs;
  217. if (basebs == null) { basebs = dbs; }
  218. if (mat.isSolid()) {
  219. dbs.setSolid();
  220. }
  221. if (mat == Material.AIR) {
  222. dbs.setAir();
  223. }
  224. if (mat == Material.WOOD) {
  225. dbs.setLog();
  226. }
  227. if (mat == Material.LEAVES) {
  228. dbs.setLeaves();
  229. }
  230. if ((!bs.getFluidState().isEmpty()) && !(bs.getBlock() instanceof BlockFlowingFluid)) {
  231. dbs.setWaterlogged();
  232. }
  233. }
  234. }
  235. for (int gidx = 0; gidx < DynmapBlockState.getGlobalIndexMax(); gidx++) {
  236. DynmapBlockState bs = DynmapBlockState.getStateByGlobalIndex(gidx);
  237. //Log.info(gidx + ":" + bs.toString() + ", gidx=" + bs.globalStateIndex + ", sidx=" + bs.stateIndex);
  238. }
  239. }
  240. public static final Item getItemByID(int id) {
  241. return Item.getItemById(id);
  242. }
  243. public static final String getBlockUnlocalizedName(Block b) {
  244. return b.getNameTextComponent().getString();
  245. }
  246. private static Biome[] biomelist = null;
  247. public static final Biome[] getBiomeList() {
  248. if (biomelist == null) {
  249. biomelist = new Biome[256];
  250. Iterator<Biome> iter = ForgeRegistries.BIOMES.iterator();
  251. while (iter.hasNext()) {
  252. Biome b = iter.next();
  253. int bidx = RegistryNamespaced.BIOME.getId(b);
  254. if (bidx >= biomelist.length) {
  255. biomelist = Arrays.copyOf(biomelist, bidx + biomelist.length);
  256. }
  257. biomelist[bidx] = b;
  258. }
  259. }
  260. return biomelist;
  261. }
  262. public static final NetworkManager getNetworkManager(NetHandlerPlayServer nh) {
  263. return nh.netManager;
  264. }
  265. private ForgePlayer getOrAddPlayer(EntityPlayer p) {
  266. String name = p.getEntity().getName().getString();
  267. ForgePlayer fp = players.get(name);
  268. if(fp != null) {
  269. fp.player = p;
  270. }
  271. else {
  272. fp = new ForgePlayer(p);
  273. players.put(name, fp);
  274. }
  275. return fp;
  276. }
  277. private static class TaskRecord implements Comparable<Object>
  278. {
  279. private long ticktorun;
  280. private long id;
  281. private FutureTask<?> future;
  282. @Override
  283. public int compareTo(Object o)
  284. {
  285. TaskRecord tr = (TaskRecord)o;
  286. if (this.ticktorun < tr.ticktorun)
  287. {
  288. return -1;
  289. }
  290. else if (this.ticktorun > tr.ticktorun)
  291. {
  292. return 1;
  293. }
  294. else if (this.id < tr.id)
  295. {
  296. return -1;
  297. }
  298. else if (this.id > tr.id)
  299. {
  300. return 1;
  301. }
  302. else
  303. {
  304. return 0;
  305. }
  306. }
  307. }
  308. private class ChatMessage {
  309. String message;
  310. EntityPlayer sender;
  311. }
  312. private ConcurrentLinkedQueue<ChatMessage> msgqueue = new ConcurrentLinkedQueue<ChatMessage>();
  313. public class ChatHandler {
  314. @SubscribeEvent
  315. public void handleChat(ServerChatEvent event) {
  316. String msg = event.getMessage();
  317. if(!msg.startsWith("/")) {
  318. ChatMessage cm = new ChatMessage();
  319. cm.message = msg;
  320. cm.sender = event.getPlayer();
  321. msgqueue.add(cm);
  322. }
  323. }
  324. }
  325. /** TODO: depends on forge chunk manager
  326. private static class WorldBusyRecord {
  327. long last_ts;
  328. Ticket ticket;
  329. }
  330. private static HashMap<Integer, WorldBusyRecord> busy_worlds = new HashMap<Integer, WorldBusyRecord>();
  331. private void setBusy(World w) {
  332. setBusy(w, null);
  333. }
  334. static void setBusy(World w, Ticket t) {
  335. if(w == null) return;
  336. if (!DynmapMod.useforcedchunks) return;
  337. WorldBusyRecord wbr = busy_worlds.get(w.provider.getDimension());
  338. if(wbr == null) { // Not busy, make ticket and keep spawn loaded
  339. Debug.debug("World " + w.getWorldInfo().getWorldName() + "/"+ w.provider.getDimensionType().getName() + " is busy");
  340. wbr = new WorldBusyRecord();
  341. if(t != null)
  342. wbr.ticket = t;
  343. else
  344. wbr.ticket = ForgeChunkManager.requestTicket(DynmapMod.instance, w, ForgeChunkManager.Type.NORMAL);
  345. if(wbr.ticket != null) {
  346. BlockPos cc = w.getSpawnPoint();
  347. ChunkPos ccip = new ChunkPos(cc.getX() >> 4, cc.getZ() >> 4);
  348. ForgeChunkManager.forceChunk(wbr.ticket, ccip);
  349. busy_worlds.put(w.provider.getDimension(), wbr); // Add to busy list
  350. }
  351. }
  352. wbr.last_ts = System.nanoTime();
  353. }
  354. private void doIdleOutOfWorlds() {
  355. if (!DynmapMod.useforcedchunks) return;
  356. long ts = System.nanoTime() - worldIdleTimeoutNS;
  357. for(Iterator<WorldBusyRecord> itr = busy_worlds.values().iterator(); itr.hasNext();) {
  358. WorldBusyRecord wbr = itr.next();
  359. if(wbr.last_ts < ts) {
  360. World w = wbr.ticket.world;
  361. Debug.debug("World " + w.getWorldInfo().getWorldName() + "/" + wbr.ticket.world.provider.getDimensionType().getName() + " is idle");
  362. if (wbr.ticket != null)
  363. ForgeChunkManager.releaseTicket(wbr.ticket); // Release hold on world
  364. itr.remove();
  365. }
  366. }
  367. }
  368. */
  369. public static class OurLog implements DynmapLogger {
  370. Logger log;
  371. public static final String DM = "[Dynmap] ";
  372. OurLog() {
  373. log = LogManager.getLogger("Dynmap");
  374. }
  375. @Override
  376. public void info(String s) {
  377. log.info(DM + s);
  378. }
  379. @Override
  380. public void severe(Throwable t) {
  381. log.fatal(t);
  382. }
  383. @Override
  384. public void severe(String s) {
  385. log.fatal(DM + s);
  386. }
  387. @Override
  388. public void severe(String s, Throwable t) {
  389. log.fatal(DM + s, t);
  390. }
  391. @Override
  392. public void verboseinfo(String s) {
  393. log.info(DM + s);
  394. }
  395. @Override
  396. public void warning(String s) {
  397. log.warn(DM + s);
  398. }
  399. @Override
  400. public void warning(String s, Throwable t) {
  401. log.warn(DM + s, t);
  402. }
  403. }
  404. public DynmapPlugin(MinecraftServer srv)
  405. {
  406. plugin = this;
  407. this.server = srv;
  408. }
  409. public boolean isOp(String player) {
  410. String[] ops = server.getPlayerList().getOppedPlayers().getKeys();
  411. for (String op : ops) {
  412. if (op.equalsIgnoreCase(player)) {
  413. return true;
  414. }
  415. }
  416. return (server.isSinglePlayer() && player.equalsIgnoreCase(server.getServerOwner()));
  417. }
  418. private boolean hasPerm(EntityPlayer psender, String permission) {
  419. PermissionsHandler ph = PermissionsHandler.getHandler();
  420. if((psender != null) && (ph != null) && ph.hasPermission(psender.getEntity().getName().getString(), permission)) {
  421. return true;
  422. }
  423. return permissions.has(psender, permission);
  424. }
  425. private boolean hasPermNode(EntityPlayer psender, String permission) {
  426. PermissionsHandler ph = PermissionsHandler.getHandler();
  427. if((psender != null) && (ph != null) && ph.hasPermissionNode(psender.getEntity().getName().getString(), permission)) {
  428. return true;
  429. }
  430. return permissions.hasPermissionNode(psender, permission);
  431. }
  432. private Set<String> hasOfflinePermissions(String player, Set<String> perms) {
  433. Set<String> rslt = null;
  434. PermissionsHandler ph = PermissionsHandler.getHandler();
  435. if(ph != null) {
  436. rslt = ph.hasOfflinePermissions(player, perms);
  437. }
  438. Set<String> rslt2 = hasOfflinePermissions(player, perms);
  439. if((rslt != null) && (rslt2 != null)) {
  440. Set<String> newrslt = new HashSet<String>(rslt);
  441. newrslt.addAll(rslt2);
  442. rslt = newrslt;
  443. }
  444. else if(rslt2 != null) {
  445. rslt = rslt2;
  446. }
  447. return rslt;
  448. }
  449. private boolean hasOfflinePermission(String player, String perm) {
  450. PermissionsHandler ph = PermissionsHandler.getHandler();
  451. if(ph != null) {
  452. if(ph.hasOfflinePermission(player, perm)) {
  453. return true;
  454. }
  455. }
  456. return permissions.hasOfflinePermission(player, perm);
  457. }
  458. /**
  459. * Server access abstraction class
  460. */
  461. public class ForgeServer extends DynmapServerInterface
  462. {
  463. /* Server thread scheduler */
  464. private Object schedlock = new Object();
  465. private long cur_tick;
  466. private long next_id;
  467. private long cur_tick_starttime;
  468. private PriorityQueue<TaskRecord> runqueue = new PriorityQueue<TaskRecord>();
  469. public ForgeServer() {
  470. }
  471. private GameProfile getProfileByName(String player) {
  472. PlayerProfileCache cache = server.getPlayerProfileCache();
  473. return cache.getGameProfileForUsername(player);
  474. }
  475. @Override
  476. public int getBlockIDAt(String wname, int x, int y, int z) {
  477. return -1;
  478. }
  479. @Override
  480. public int isSignAt(String wname, int x, int y, int z) {
  481. return -1;
  482. }
  483. @Override
  484. public void scheduleServerTask(Runnable run, long delay)
  485. {
  486. TaskRecord tr = new TaskRecord();
  487. tr.future = new FutureTask<Object>(run, null);
  488. /* Add task record to queue */
  489. synchronized (schedlock)
  490. {
  491. tr.id = next_id++;
  492. tr.ticktorun = cur_tick + delay;
  493. runqueue.add(tr);
  494. }
  495. }
  496. @Override
  497. public DynmapPlayer[] getOnlinePlayers()
  498. {
  499. if(server.getPlayerList() == null)
  500. return new DynmapPlayer[0];
  501. List<?> playlist = server.getPlayerList().getPlayers();
  502. int pcnt = playlist.size();
  503. DynmapPlayer[] dplay = new DynmapPlayer[pcnt];
  504. for (int i = 0; i < pcnt; i++)
  505. {
  506. EntityPlayer p = (EntityPlayer)playlist.get(i);
  507. dplay[i] = getOrAddPlayer(p);
  508. }
  509. return dplay;
  510. }
  511. @Override
  512. public void reload()
  513. {
  514. plugin.onDisable();
  515. plugin.onEnable();
  516. plugin.onStart();
  517. }
  518. @Override
  519. public DynmapPlayer getPlayer(String name)
  520. {
  521. List<?> players = server.getPlayerList().getPlayers();
  522. for (Object o : players)
  523. {
  524. EntityPlayer p = (EntityPlayer)o;
  525. if (p.getEntity().getName().getString().equalsIgnoreCase(name))
  526. {
  527. return getOrAddPlayer(p);
  528. }
  529. }
  530. return null;
  531. }
  532. @Override
  533. public Set<String> getIPBans()
  534. {
  535. UserListIPBans bl = server.getPlayerList().getBannedIPs();
  536. Set<String> ips = new HashSet<String>();
  537. for (String s : bl.getKeys()) {
  538. ips.add(s);
  539. }
  540. return ips;
  541. }
  542. @Override
  543. public <T> Future<T> callSyncMethod(Callable<T> task) {
  544. return callSyncMethod(task, 0);
  545. }
  546. public <T> Future<T> callSyncMethod(Callable<T> task, long delay)
  547. {
  548. TaskRecord tr = new TaskRecord();
  549. FutureTask<T> ft = new FutureTask<T>(task);
  550. tr.future = ft;
  551. /* Add task record to queue */
  552. synchronized (schedlock)
  553. {
  554. tr.id = next_id++;
  555. tr.ticktorun = cur_tick + delay;
  556. runqueue.add(tr);
  557. }
  558. return ft;
  559. }
  560. @Override
  561. public String getServerName()
  562. {
  563. String sn;
  564. if (server.isSinglePlayer())
  565. sn = "Integrated";
  566. else
  567. sn = server.getServerHostname();
  568. if(sn == null) sn = "Unknown Server";
  569. return sn;
  570. }
  571. @Override
  572. public boolean isPlayerBanned(String pid)
  573. {
  574. UserListBans bl = server.getPlayerList().getBannedPlayers();
  575. return bl.isBanned(getProfileByName(pid));
  576. }
  577. @Override
  578. public String stripChatColor(String s)
  579. {
  580. return patternControlCode.matcher(s).replaceAll("");
  581. }
  582. private Set<EventType> registered = new HashSet<EventType>();
  583. @Override
  584. public boolean requestEventNotification(EventType type)
  585. {
  586. if (registered.contains(type))
  587. {
  588. return true;
  589. }
  590. switch (type)
  591. {
  592. case WORLD_LOAD:
  593. case WORLD_UNLOAD:
  594. /* Already called for normal world activation/deactivation */
  595. break;
  596. case WORLD_SPAWN_CHANGE:
  597. /*TODO
  598. pm.registerEvents(new Listener() {
  599. @EventHandler(priority=EventPriority.MONITOR)
  600. public void onSpawnChange(SpawnChangeEvent evt) {
  601. DynmapWorld w = new BukkitWorld(evt.getWorld());
  602. core.listenerManager.processWorldEvent(EventType.WORLD_SPAWN_CHANGE, w);
  603. }
  604. }, DynmapPlugin.this);
  605. */
  606. break;
  607. case PLAYER_JOIN:
  608. case PLAYER_QUIT:
  609. /* Already handled */
  610. break;
  611. case PLAYER_BED_LEAVE:
  612. /*TODO
  613. pm.registerEvents(new Listener() {
  614. @EventHandler(priority=EventPriority.MONITOR)
  615. public void onPlayerBedLeave(PlayerBedLeaveEvent evt) {
  616. DynmapPlayer p = new BukkitPlayer(evt.getPlayer());
  617. core.listenerManager.processPlayerEvent(EventType.PLAYER_BED_LEAVE, p);
  618. }
  619. }, DynmapPlugin.this);
  620. */
  621. break;
  622. case PLAYER_CHAT:
  623. if (chathandler == null) {
  624. chathandler = new ChatHandler();
  625. MinecraftForge.EVENT_BUS.register(chathandler);
  626. }
  627. break;
  628. case BLOCK_BREAK:
  629. /*TODO
  630. pm.registerEvents(new Listener() {
  631. @EventHandler(priority=EventPriority.MONITOR)
  632. public void onBlockBreak(BlockBreakEvent evt) {
  633. if(evt.isCancelled()) return;
  634. Block b = evt.getBlock();
  635. if(b == null) return;
  636. Location l = b.getLocation();
  637. core.listenerManager.processBlockEvent(EventType.BLOCK_BREAK, b.getType().getId(),
  638. BukkitWorld.normalizeWorldName(l.getWorld().getName()), l.getBlockX(), l.getBlockY(), l.getBlockZ());
  639. }
  640. }, DynmapPlugin.this);
  641. */
  642. break;
  643. case SIGN_CHANGE:
  644. /*TODO
  645. pm.registerEvents(new Listener() {
  646. @EventHandler(priority=EventPriority.MONITOR)
  647. public void onSignChange(SignChangeEvent evt) {
  648. if(evt.isCancelled()) return;
  649. Block b = evt.getBlock();
  650. Location l = b.getLocation();
  651. String[] lines = evt.getLines();
  652. DynmapPlayer dp = null;
  653. Player p = evt.getPlayer();
  654. if(p != null) dp = new BukkitPlayer(p);
  655. core.listenerManager.processSignChangeEvent(EventType.SIGN_CHANGE, b.getType().getId(),
  656. BukkitWorld.normalizeWorldName(l.getWorld().getName()), l.getBlockX(), l.getBlockY(), l.getBlockZ(), lines, dp);
  657. }
  658. }, DynmapPlugin.this);
  659. */
  660. break;
  661. default:
  662. Log.severe("Unhandled event type: " + type);
  663. return false;
  664. }
  665. registered.add(type);
  666. return true;
  667. }
  668. @Override
  669. public boolean sendWebChatEvent(String source, String name, String msg)
  670. {
  671. return DynmapCommonAPIListener.fireWebChatEvent(source, name, msg);
  672. }
  673. @Override
  674. public void broadcastMessage(String msg)
  675. {
  676. ITextComponent component = new TextComponentString(msg);
  677. server.getPlayerList().sendMessage(component);
  678. Log.info(stripChatColor(msg));
  679. }
  680. @Override
  681. public String[] getBiomeIDs()
  682. {
  683. BiomeMap[] b = BiomeMap.values();
  684. String[] bname = new String[b.length];
  685. for (int i = 0; i < bname.length; i++)
  686. {
  687. bname[i] = b[i].toString();
  688. }
  689. return bname;
  690. }
  691. @Override
  692. public double getCacheHitRate()
  693. {
  694. if(sscache != null)
  695. return sscache.getHitRate();
  696. return 0.0;
  697. }
  698. @Override
  699. public void resetCacheStats()
  700. {
  701. if(sscache != null)
  702. sscache.resetStats();
  703. }
  704. @Override
  705. public DynmapWorld getWorldByName(String wname)
  706. {
  707. return DynmapPlugin.this.getWorldByName(wname);
  708. }
  709. @Override
  710. public DynmapPlayer getOfflinePlayer(String name)
  711. {
  712. /*
  713. OfflinePlayer op = getServer().getOfflinePlayer(name);
  714. if(op != null) {
  715. return new BukkitPlayer(op);
  716. }
  717. */
  718. return null;
  719. }
  720. @Override
  721. public Set<String> checkPlayerPermissions(String player, Set<String> perms)
  722. {
  723. net.minecraft.server.management.PlayerList scm = server.getPlayerList();
  724. if (scm == null) return Collections.emptySet();
  725. UserListBans bl = scm.getBannedPlayers();
  726. if (bl == null) return Collections.emptySet();
  727. if(bl.isBanned(getProfileByName(player))) {
  728. return Collections.emptySet();
  729. }
  730. Set<String> rslt = hasOfflinePermissions(player, perms);
  731. if (rslt == null) {
  732. rslt = new HashSet<String>();
  733. if(plugin.isOp(player)) {
  734. rslt.addAll(perms);
  735. }
  736. }
  737. return rslt;
  738. }
  739. @Override
  740. public boolean checkPlayerPermission(String player, String perm)
  741. {
  742. net.minecraft.server.management.PlayerList scm = server.getPlayerList();
  743. if (scm == null) return false;
  744. UserListBans bl = scm.getBannedPlayers();
  745. if (bl == null) return false;
  746. if(bl.isBanned(getProfileByName(player))) {
  747. return false;
  748. }
  749. return hasOfflinePermission(player, perm);
  750. }
  751. /**
  752. * Render processor helper - used by code running on render threads to request chunk snapshot cache from server/sync thread
  753. */
  754. @Override
  755. public MapChunkCache createMapChunkCache(DynmapWorld w, List<DynmapChunk> chunks,
  756. boolean blockdata, boolean highesty, boolean biome, boolean rawbiome)
  757. {
  758. ForgeMapChunkCache c = (ForgeMapChunkCache) w.getChunkCache(chunks);
  759. if(c == null) {
  760. return null;
  761. }
  762. if (w.visibility_limits != null)
  763. {
  764. for (VisibilityLimit limit: w.visibility_limits)
  765. {
  766. c.setVisibleRange(limit);
  767. }
  768. c.setHiddenFillStyle(w.hiddenchunkstyle);
  769. }
  770. if (w.hidden_limits != null)
  771. {
  772. for (VisibilityLimit limit: w.hidden_limits)
  773. {
  774. c.setHiddenRange(limit);
  775. }
  776. c.setHiddenFillStyle(w.hiddenchunkstyle);
  777. }
  778. if (c.setChunkDataTypes(blockdata, biome, highesty, rawbiome) == false)
  779. {
  780. Log.severe("CraftBukkit build does not support biome APIs");
  781. }
  782. if (chunks.size() == 0) /* No chunks to get? */
  783. {
  784. c.loadChunks(0);
  785. return c;
  786. }
  787. //Now handle any chunks in server thread that are already loaded (on server thread)
  788. final ForgeMapChunkCache cc = c;
  789. Future<Boolean> f = this.callSyncMethod(new Callable<Boolean>() {
  790. public Boolean call() throws Exception {
  791. // Update busy state on world
  792. ForgeWorld fw = (ForgeWorld)cc.getWorld();
  793. //TODO
  794. //setBusy(fw.getWorld());
  795. cc.getLoadedChunks();
  796. return true;
  797. }
  798. }, 0);
  799. try {
  800. f.get();
  801. }
  802. catch (CancellationException cx) {
  803. return null;
  804. }
  805. catch (ExecutionException xx) {
  806. Log.severe("Exception while loading chunks", xx.getCause());
  807. return null;
  808. }
  809. catch (Exception ix) {
  810. Log.severe(ix);
  811. return null;
  812. }
  813. if(w.isLoaded() == false) {
  814. return null;
  815. }
  816. // Now, do rest of chunk reading from calling thread
  817. c.readChunks(chunks.size());
  818. return c;
  819. }
  820. @Override
  821. public int getMaxPlayers()
  822. {
  823. return server.getMaxPlayers();
  824. }
  825. @Override
  826. public int getCurrentPlayers()
  827. {
  828. return server.getPlayerList().getCurrentPlayerCount();
  829. }
  830. @SubscribeEvent
  831. public void tickEvent(TickEvent.ServerTickEvent event) {
  832. if (event.phase == TickEvent.Phase.START) {
  833. return;
  834. }
  835. cur_tick_starttime = System.nanoTime();
  836. long elapsed = cur_tick_starttime - lasttick;
  837. lasttick = cur_tick_starttime;
  838. avgticklen = ((avgticklen * 99) / 100) + (elapsed / 100);
  839. tps = (double)1E9 / (double)avgticklen;
  840. // Tick core
  841. if (core != null) {
  842. core.serverTick(tps);
  843. }
  844. boolean done = false;
  845. TaskRecord tr = null;
  846. while(!blockupdatequeue.isEmpty()) {
  847. BlockUpdateRec r = blockupdatequeue.remove();
  848. IBlockState bs = r.w.getBlockState(new BlockPos(r.x, r.y, r.z));
  849. int idx = Block.BLOCK_STATE_IDS.get(bs);
  850. if(!org.dynmap.hdmap.HDBlockModels.isChangeIgnoredBlock(stateByID[idx])) {
  851. if(onblockchange_with_id)
  852. mapManager.touch(r.wid, r.x, r.y, r.z, "blockchange[" + idx + "]");
  853. else
  854. mapManager.touch(r.wid, r.x, r.y, r.z, "blockchange");
  855. }
  856. }
  857. long now;
  858. synchronized(schedlock) {
  859. cur_tick++;
  860. now = System.nanoTime();
  861. tr = runqueue.peek();
  862. /* Nothing due to run */
  863. if((tr == null) || (tr.ticktorun > cur_tick) || ((now - cur_tick_starttime) > perTickLimit)) {
  864. done = true;
  865. }
  866. else {
  867. tr = runqueue.poll();
  868. }
  869. }
  870. while (!done) {
  871. tr.future.run();
  872. synchronized(schedlock) {
  873. tr = runqueue.peek();
  874. now = System.nanoTime();
  875. /* Nothing due to run */
  876. if((tr == null) || (tr.ticktorun > cur_tick) || ((now - cur_tick_starttime) > perTickLimit)) {
  877. done = true;
  878. }
  879. else {
  880. tr = runqueue.poll();
  881. }
  882. }
  883. }
  884. while(!msgqueue.isEmpty()) {
  885. ChatMessage cm = msgqueue.poll();
  886. DynmapPlayer dp = null;
  887. if(cm.sender != null)
  888. dp = getOrAddPlayer(cm.sender);
  889. else
  890. dp = new ForgePlayer(null);
  891. core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, dp, cm.message);
  892. }
  893. /* Check for idle worlds */
  894. if((cur_tick % 20) == 0) {
  895. //TODO
  896. //doIdleOutOfWorlds();
  897. }
  898. }
  899. @Override
  900. public boolean isModLoaded(String name) {
  901. boolean loaded = ModList.get().isLoaded(name);
  902. if (loaded) {
  903. modsused.add(name);
  904. }
  905. return loaded;
  906. }
  907. @Override
  908. public String getModVersion(String name) {
  909. Optional<? extends ModContainer> mod = ModList.get().getModContainerById(name); // Try case sensitive lookup
  910. if (mod.isPresent()) {
  911. ArtifactVersion vi = mod.get().getModInfo().getVersion();
  912. return vi.getMajorVersion() + "." + vi.getMinorVersion() + "." + vi.getIncrementalVersion();
  913. }
  914. return null;
  915. }
  916. @Override
  917. public double getServerTPS() {
  918. return tps;
  919. }
  920. @Override
  921. public String getServerIP() {
  922. if (server.isSinglePlayer())
  923. return "0.0.0.0";
  924. else
  925. return server.getServerHostname();
  926. }
  927. @Override
  928. public File getModContainerFile(String name) {
  929. ModFileInfo mfi = ModList.get().getModFileById(name); // Try case sensitive lookup
  930. if (mfi != null) {
  931. File f = mfi.getFile().getFilePath().toFile();
  932. return f;
  933. }
  934. return null;
  935. }
  936. @Override
  937. public List<String> getModList() {
  938. List<ModInfo> mil = ModList.get().getMods();
  939. List<String> lst = new ArrayList<String>();
  940. for (ModInfo mi : mil) {
  941. lst.add(mi.getModId());
  942. }
  943. return lst;
  944. }
  945. @Override
  946. public Map<Integer, String> getBlockIDMap() {
  947. Map<Integer, String> map = new HashMap<Integer, String>();
  948. return map;
  949. }
  950. @Override
  951. public InputStream openResource(String modid, String rname) {
  952. if (modid != null) {
  953. Optional<? extends ModContainer> mc = ModList.get().getModContainerById(modid);
  954. Object mod = (mc.isPresent()) ? mc.get().getMod() : null;
  955. if (mod != null) {
  956. InputStream is = mod.getClass().getClassLoader().getResourceAsStream(rname);
  957. if (is != null) {
  958. return is;
  959. }
  960. }
  961. }
  962. List<ModInfo> mcl = ModList.get().getMods();
  963. for (ModInfo mci : mcl) {
  964. Optional<? extends ModContainer> mc = ModList.get().getModContainerById(mci.getModId());
  965. Object mod = (mc.isPresent()) ? mc.get().getMod() : null;
  966. if (mod == null) continue;
  967. InputStream is = mod.getClass().getClassLoader().getResourceAsStream(rname);
  968. if (is != null) {
  969. return is;
  970. }
  971. }
  972. return null;
  973. }
  974. /**
  975. * Get block unique ID map (module:blockid)
  976. */
  977. @Override
  978. public Map<String, Integer> getBlockUniqueIDMap() {
  979. HashMap<String, Integer> map = new HashMap<String, Integer>();
  980. return map;
  981. }
  982. /**
  983. * Get item unique ID map (module:itemid)
  984. */
  985. @Override
  986. public Map<String, Integer> getItemUniqueIDMap() {
  987. HashMap<String, Integer> map = new HashMap<String, Integer>();
  988. return map;
  989. }
  990. }
  991. private static final Gson gson = new GsonBuilder().create();
  992. public class TexturesPayload {
  993. public long timestamp;
  994. public String profileId;
  995. public String profileName;
  996. public boolean isPublic;
  997. public Map<String, ProfileTexture> textures;
  998. }
  999. public class ProfileTexture {
  1000. public String url;
  1001. }
  1002. /**
  1003. * Player access abstraction class
  1004. */
  1005. public class ForgePlayer extends ForgeCommandSender implements DynmapPlayer
  1006. {
  1007. private EntityPlayer player;
  1008. private final String skinurl;
  1009. private final UUID uuid;
  1010. public ForgePlayer(EntityPlayer p)
  1011. {
  1012. player = p;
  1013. String url = null;
  1014. if (player != null) {
  1015. uuid = player.getUniqueID();
  1016. GameProfile prof = player.getGameProfile();
  1017. if (prof != null) {
  1018. Property textureProperty = Iterables.getFirst(prof.getProperties().get("textures"), null);
  1019. if (textureProperty != null) {
  1020. TexturesPayload result = null;
  1021. try {
  1022. String json = new String(Base64.decodeBase64(textureProperty.getValue()), Charsets.UTF_8);
  1023. result = gson.fromJson(json, TexturesPayload.class);
  1024. } catch (JsonParseException e) {
  1025. }
  1026. if ((result != null) && (result.textures != null) && (result.textures.containsKey("SKIN"))) {
  1027. url = result.textures.get("SKIN").url;
  1028. }
  1029. }
  1030. }
  1031. }
  1032. else {
  1033. uuid = null;
  1034. }
  1035. skinurl = url;
  1036. }
  1037. @Override
  1038. public boolean isConnected()
  1039. {
  1040. return true;
  1041. }
  1042. @Override
  1043. public String getName()
  1044. {
  1045. if(player != null) {
  1046. String n = player.getEntity().getName().getString();;
  1047. return n;
  1048. }
  1049. else
  1050. return "[Server]";
  1051. }
  1052. @Override
  1053. public String getDisplayName()
  1054. {
  1055. if(player != null) {
  1056. String n = player.getDisplayName().getString();
  1057. return n;
  1058. }
  1059. else
  1060. return "[Server]";
  1061. }
  1062. @Override
  1063. public boolean isOnline()
  1064. {
  1065. return true;
  1066. }
  1067. @Override
  1068. public DynmapLocation getLocation()
  1069. {
  1070. if (player == null)
  1071. {
  1072. return null;
  1073. }
  1074. return toLoc(player.world, player.posX, player.posY, player.posZ);
  1075. }
  1076. @Override
  1077. public String getWorld()
  1078. {
  1079. if (player == null)
  1080. {
  1081. return null;
  1082. }
  1083. if (player.world != null)
  1084. {
  1085. return DynmapPlugin.this.getWorld(player.world).getName();
  1086. }
  1087. return null;
  1088. }
  1089. @Override
  1090. public InetSocketAddress getAddress()
  1091. {
  1092. if((player != null) && (player instanceof EntityPlayerMP)) {
  1093. NetHandlerPlayServer nsh = ((EntityPlayerMP)player).connection;
  1094. if((nsh != null) && (getNetworkManager(nsh) != null)) {
  1095. SocketAddress sa = getNetworkManager(nsh).getRemoteAddress();
  1096. if(sa instanceof InetSocketAddress) {
  1097. return (InetSocketAddress)sa;
  1098. }
  1099. }
  1100. }
  1101. return null;
  1102. }
  1103. @Override
  1104. public boolean isSneaking()
  1105. {
  1106. if (player != null)
  1107. {
  1108. return player.isSneaking();
  1109. }
  1110. return false;
  1111. }
  1112. @Override
  1113. public double getHealth()
  1114. {
  1115. if (player != null)
  1116. {
  1117. double h = player.getHealth();
  1118. if(h > 20) h = 20;
  1119. return h; // Scale to 20 range
  1120. }
  1121. else
  1122. {
  1123. return 0;
  1124. }
  1125. }
  1126. @Override
  1127. public int getArmorPoints()
  1128. {
  1129. if (player != null)
  1130. {
  1131. return player.getTotalArmorValue();
  1132. }
  1133. else
  1134. {
  1135. return 0;
  1136. }
  1137. }
  1138. @Override
  1139. public DynmapLocation getBedSpawnLocation()
  1140. {
  1141. return null;
  1142. }
  1143. @Override
  1144. public long getLastLoginTime()
  1145. {
  1146. return 0;
  1147. }
  1148. @Override
  1149. public long getFirstLoginTime()
  1150. {
  1151. return 0;
  1152. }
  1153. @Override
  1154. public boolean hasPrivilege(String privid)
  1155. {
  1156. if(player != null)
  1157. return hasPerm(player, privid);
  1158. return false;
  1159. }
  1160. @Override
  1161. public boolean isOp()
  1162. {
  1163. return DynmapPlugin.this.isOp(player.getEntity().getName().getString());
  1164. }
  1165. @Override
  1166. public void sendMessage(String msg)
  1167. {
  1168. ITextComponent ichatcomponent = new TextComponentString(msg);
  1169. player.sendMessage(ichatcomponent);
  1170. }
  1171. @Override
  1172. public boolean isInvisible() {
  1173. if(player != null) {
  1174. return player.isInvisible();
  1175. }
  1176. return false;
  1177. }
  1178. @Override
  1179. public int getSortWeight() {
  1180. Integer wt = sortWeights.get(getName());
  1181. if (wt != null)
  1182. return wt;
  1183. return 0;
  1184. }
  1185. @Override
  1186. public void setSortWeight(int wt) {
  1187. if (wt == 0) {
  1188. sortWeights.remove(getName());
  1189. }
  1190. else {
  1191. sortWeights.put(getName(), wt);
  1192. }
  1193. }
  1194. @Override
  1195. public boolean hasPermissionNode(String node) {
  1196. if(player != null)
  1197. return hasPermNode(player, node);
  1198. return false;
  1199. }
  1200. @Override
  1201. public String getSkinURL() {
  1202. return skinurl;
  1203. }
  1204. @Override
  1205. public UUID getUUID() {
  1206. return uuid;
  1207. }
  1208. /**
  1209. * Send title and subtitle text (called from server thread)
  1210. */
  1211. @Override
  1212. public void sendTitleText(String title, String subtitle, int fadeInTicks, int stayTicks, int fadeOutTicks) {
  1213. if (player instanceof EntityPlayerMP) {
  1214. EntityPlayerMP mp = (EntityPlayerMP) player;
  1215. SPacketTitle times = new SPacketTitle(fadeInTicks, stayTicks, fadeOutTicks);
  1216. mp.connection.sendPacket(times);
  1217. if (title != null) {
  1218. SPacketTitle titlepkt = new SPacketTitle(SPacketTitle.Type.TITLE, new TextComponentString(title));
  1219. mp.connection.sendPacket(titlepkt);
  1220. }
  1221. if (subtitle != null) {
  1222. SPacketTitle subtitlepkt = new SPacketTitle(SPacketTitle.Type.SUBTITLE, new TextComponentString(subtitle));
  1223. mp.connection.sendPacket(subtitlepkt);
  1224. }
  1225. }
  1226. }
  1227. }
  1228. /* Handler for generic console command sender */
  1229. public class ForgeCommandSender implements DynmapCommandSender
  1230. {
  1231. private CommandSource sender;
  1232. protected ForgeCommandSender() {
  1233. sender = null;
  1234. }
  1235. public ForgeCommandSender(CommandSource send)
  1236. {
  1237. sender = send;
  1238. }
  1239. @Override
  1240. public boolean hasPrivilege(String privid)
  1241. {
  1242. return true;
  1243. }
  1244. @Override
  1245. public void sendMessage(String msg)
  1246. {
  1247. if(sender != null) {
  1248. ITextComponent ichatcomponent = new TextComponentString(msg);
  1249. sender.sendFeedback(ichatcomponent, false);
  1250. }
  1251. }
  1252. @Override
  1253. public boolean isConnected()
  1254. {
  1255. return false;
  1256. }
  1257. @Override
  1258. public boolean isOp()
  1259. {
  1260. return true;
  1261. }
  1262. @Override
  1263. public boolean hasPermissionNode(String node) {
  1264. return true;
  1265. }
  1266. }
  1267. public void loadExtraBiomes(String mcver) {
  1268. int cnt = 0;
  1269. BiomeMap.loadWellKnownByVersion(mcver);
  1270. Biome[] list = getBiomeList();
  1271. for(int i = 0; i < list.length; i++) {
  1272. Biome bb = list[i];
  1273. if(bb != null) {
  1274. String id = bb.getRegistryName().getPath();
  1275. float tmp = bb.getDefaultTemperature(), hum = bb.getDownfall();
  1276. int watermult = bb.getWaterColor();
  1277. Log.verboseinfo("biome[" + i + "]: hum=" + hum + ", tmp=" + tmp + ", mult=" + Integer.toHexString(watermult));
  1278. BiomeMap bmap = BiomeMap.byBiomeID(i);
  1279. if (bmap.isDefault()) {
  1280. bmap = new BiomeMap(i, id, tmp, hum);
  1281. Log.verboseinfo("Add custom biome [" + bmap.toString() + "] (" + i + ")");
  1282. cnt++;
  1283. }
  1284. else {
  1285. bmap.setTemperature(tmp);
  1286. bmap.setRainfall(hum);
  1287. }
  1288. if (watermult != -1) {
  1289. bmap.setWaterColorMultiplier(watermult);
  1290. Log.verboseinfo("Set watercolormult for " + bmap.toString() + " (" + i + ") to " + Integer.toHexString(watermult));
  1291. }
  1292. }
  1293. }
  1294. if(cnt > 0)
  1295. Log.info("Added " + cnt + " custom biome mappings");
  1296. }
  1297. private String[] getBiomeNames() {
  1298. Biome[] list = getBiomeList();
  1299. String[] lst = new String[list.length];
  1300. for(int i = 0; i < list.length; i++) {
  1301. Biome bb = list[i];
  1302. if (bb != null) {
  1303. lst[i] = bb.getRegistryName().getPath();
  1304. }
  1305. }
  1306. return lst;
  1307. }
  1308. public void onEnable()
  1309. {
  1310. /* Get MC version */
  1311. String mcver = server.getMinecraftVersion();
  1312. /* Load extra biomes */
  1313. loadExtraBiomes(mcver);
  1314. /* Set up player login/quit event handler */
  1315. registerPlayerLoginListener();
  1316. /* Initialize permissions handler */
  1317. permissions = FilePermissions.create();
  1318. if(permissions == null) {
  1319. permissions = new OpPermissions(new String[] { "webchat", "marker.icons", "marker.list", "webregister", "stats", "hide.self", "show.self" });
  1320. }
  1321. /* Get and initialize data folder */
  1322. File dataDirectory = new File("dynmap");
  1323. if (dataDirectory.exists() == false)
  1324. {
  1325. dataDirectory.mkdirs();
  1326. }
  1327. /* Instantiate core */
  1328. if (core == null)
  1329. {
  1330. core = new DynmapCore();
  1331. }
  1332. /* Inject dependencies */
  1333. core.setPluginJarFile(DynmapMod.jarfile);
  1334. core.setPluginVersion(DynmapMod.ver);
  1335. core.setMinecraftVersion(mcver);
  1336. core.setDataFolder(dataDirectory);
  1337. core.setServer(fserver);
  1338. ForgeMapChunkCache.init();
  1339. core.setTriggerDefault(TRIGGER_DEFAULTS);
  1340. core.setBiomeNames(getBiomeNames());
  1341. if(!core.initConfiguration(null))
  1342. {
  1343. return;
  1344. }
  1345. // Extract default permission example, if needed
  1346. File filepermexample = new File(core.getDataFolder(), "permissions.yml.example");
  1347. core.createDefaultFileFromResource("/permissions.yml.example", filepermexample);
  1348. DynmapCommonAPIListener.apiInitialized(core);
  1349. }
  1350. private static int test(CommandSource source) throws CommandSyntaxException
  1351. {
  1352. System.out.println(source.toString());
  1353. return 1;
  1354. }
  1355. private DynmapCommand dynmapCmd;
  1356. private DmapCommand dmapCmd;
  1357. private DmarkerCommand dmarkerCmd;
  1358. private DynmapExpCommand dynmapexpCmd;
  1359. public void onStarting(CommandDispatcher<CommandSource> cd) {
  1360. /* Register command hander */
  1361. dynmapCmd = new DynmapCommand(this);
  1362. dmapCmd = new DmapCommand(this);
  1363. dmarkerCmd = new DmarkerCommand(this);
  1364. dynmapexpCmd = new DynmapExpCommand(this);
  1365. dynmapCmd.register(cd);
  1366. dmapCmd.register(cd);
  1367. dmarkerCmd.register(cd);
  1368. dynmapexpCmd.register(cd);
  1369. Log.info("Register commands");
  1370. }
  1371. public void onStart() {
  1372. initializeBlockStates();
  1373. /* Enable core */
  1374. if (!core.enableCore(null))
  1375. {
  1376. return;
  1377. }
  1378. core_enabled = true;
  1379. VersionCheck.runCheck(core);
  1380. // Get per tick time limit
  1381. perTickLimit = core.getMaxTickUseMS() * 1000000;
  1382. // Prep TPS
  1383. lasttick = System.nanoTime();
  1384. tps = 20.0;
  1385. /* Register tick handler */
  1386. if(!tickregistered) {
  1387. MinecraftForge.EVENT_BUS.register(fserver);
  1388. tickregistered = true;
  1389. }
  1390. playerList = core.playerList;
  1391. sscache = new SnapshotCache(core.getSnapShotCacheSize(), core.useSoftRefInSnapShotCache());
  1392. /* Get map manager from core */
  1393. mapManager = core.getMapManager();
  1394. /* Load saved world definitions */
  1395. loadWorlds();
  1396. /* Initialized the currently loaded worlds */
  1397. if(server.getWorlds() != null) {
  1398. for (WorldServer world : server.getWorlds()) {
  1399. ForgeWorld w = this.getWorld(world);
  1400. /*NOTYET - need rest of forge
  1401. if(DimensionManager.getWorld(world.provider.getDimensionId()) == null) { // If not loaded
  1402. w.setWorldUnloaded();
  1403. }
  1404. */
  1405. }
  1406. }
  1407. for(ForgeWorld w : worlds.values()) {
  1408. if (core.processWorldLoad(w)) { /* Have core process load first - fire event listeners if good load after */
  1409. if(w.isLoaded()) {
  1410. core.listenerManager.processWorldEvent(EventType.WORLD_LOAD, w);
  1411. }
  1412. }
  1413. }
  1414. core.updateConfigHashcode();
  1415. /* Register our update trigger events */
  1416. registerEvents();
  1417. Log.info("Register events");
  1418. /* Submit metrics to mcstats.org */
  1419. initMetrics();
  1420. //DynmapCommonAPIListener.apiInitialized(core);
  1421. Log.info("Enabled");
  1422. }
  1423. public void onDisable()
  1424. {
  1425. DynmapCommonAPIListener.apiTerminated();
  1426. //if (metrics != null) {
  1427. // metrics.stop();
  1428. // metrics = null;
  1429. //}
  1430. /* Save worlds */
  1431. saveWorlds();
  1432. /* Purge tick queue */
  1433. fserver.runqueue.clear();
  1434. /* Disable core */
  1435. core.disableCore();
  1436. core_enabled = false;
  1437. if (sscache != null)
  1438. {
  1439. sscache.cleanup();
  1440. sscache = null;
  1441. }
  1442. Log.info("Disabled");
  1443. }
  1444. void onCommand(CommandSource sender, String cmd, String[] args)
  1445. {
  1446. DynmapCommandSender dsender;
  1447. EntityPlayer psender;
  1448. try {
  1449. psender = sender.asPlayer();
  1450. } catch (com.mojang.brigadier.exceptions.CommandSyntaxException x) {
  1451. psender = null;
  1452. }
  1453. if (psender != null)
  1454. {
  1455. dsender = new ForgePlayer(psender);
  1456. }
  1457. else
  1458. {
  1459. dsender = new ForgeCommandSender(sender);
  1460. }
  1461. try {
  1462. core.processCommand(dsender, cmd, cmd, args);
  1463. } catch (Exception x) {
  1464. dsender.sendMessage("Command internal error: " + x.getMessage());
  1465. Log.severe("Error with command: " + cmd + Arrays.deepToString(args), x);
  1466. }
  1467. }
  1468. private DynmapLocation toLoc(World worldObj, double x, double y, double z)
  1469. {
  1470. return new DynmapLocation(DynmapPlugin.this.getWorld(worldObj).getName(), x, y, z);
  1471. }
  1472. public class PlayerTracker {
  1473. @SubscribeEvent
  1474. public void onPlayerLogin(PlayerLoggedInEvent event) {
  1475. if(!core_enabled) return;
  1476. final DynmapPlayer dp = getOrAddPlayer(event.getPlayer());
  1477. /* This event can be called from off server thread, so push processing there */
  1478. core.getServer().scheduleServerTask(new Runnable() {
  1479. public void run() {
  1480. core.listenerManager.processPlayerEvent(EventType.PLAYER_JOIN, dp);
  1481. }
  1482. }, 2);
  1483. }
  1484. @SubscribeEvent
  1485. public void onPlayerLogout(PlayerLoggedOutEvent event) {
  1486. if(!core_enabled) return;
  1487. final DynmapPlayer dp = getOrAddPlayer(event.getPlayer());
  1488. final String name = event.getPlayer().getEntity().getName().getString();
  1489. /* This event can be called from off server thread, so push processing there */
  1490. core.getServer().scheduleServerTask(new Runnable() {
  1491. public void run() {
  1492. core.listenerManager.processPlayerEvent(EventType.PLAYER_QUIT, dp);
  1493. players.remove(name);
  1494. }
  1495. }, 0);
  1496. }
  1497. @SubscribeEvent
  1498. public void onPlayerChangedDimension(PlayerChangedDimensionEvent event) {
  1499. if(!core_enabled) return;
  1500. getOrAddPlayer(event.getPlayer()); // Freshen player object reference
  1501. }
  1502. @SubscribeEvent
  1503. public void onPlayerRespawn(PlayerRespawnEvent event) {
  1504. if(!core_enabled) return;
  1505. getOrAddPlayer(event.getPlayer()); // Freshen player object reference
  1506. }
  1507. }
  1508. private PlayerTracker playerTracker = null;
  1509. private void registerPlayerLoginListener()
  1510. {
  1511. if (playerTracker == null) {
  1512. playerTracker = new PlayerTracker();
  1513. MinecraftForge.EVENT_BUS.register(playerTracker);
  1514. }
  1515. }
  1516. public class WorldTracker {
  1517. @SubscribeEvent
  1518. public void handleWorldLoad(WorldEvent.Load event) {
  1519. if(!core_enabled) return;
  1520. IWorld w = event.getWorld();
  1521. if(!(w instanceof WorldServer)) return;
  1522. final ForgeWorld fw = getWorld(w);
  1523. if (fw == null) return;
  1524. // This event can be called from off server thread, so push processing there
  1525. core.getServer().scheduleServerTask(new Runnable() {
  1526. public void run() {
  1527. if(core.processWorldLoad(fw)) // Have core process load first - fire event listeners if good load after
  1528. core.listenerManager.processWorldEvent(EventType.WORLD_LOAD, fw);
  1529. }
  1530. }, 0);
  1531. }
  1532. @SubscribeEvent
  1533. public void handleWorldUnload(WorldEvent.Unload event) {
  1534. if(!core_enabled) return;
  1535. IWorld w = event.getWorld();
  1536. if(!(w instanceof WorldServer)) return;
  1537. final ForgeWorld fw = getWorld(w);
  1538. if(fw != null) {
  1539. // This event can be called from off server thread, so push processing there
  1540. core.getServer().scheduleServerTask(new Runnable() {
  1541. public void run() {
  1542. core.listenerManager.processWorldEvent(EventType.WORLD_UNLOAD, fw);
  1543. core.processWorldUnload(fw);
  1544. }
  1545. }, 0);
  1546. // Set world unloaded (needs to be immediate, since it may be invalid after event)
  1547. fw.setWorldUnloaded();
  1548. // Clean up tracker
  1549. WorldUpdateTracker wut = updateTrackers.remove(fw.getName());
  1550. if(wut != null) wut.world = null;
  1551. }
  1552. }
  1553. @SubscribeEvent
  1554. public void handleChunkLoad(ChunkEvent.Load event) {
  1555. if(!core_enabled) return;
  1556. if(!onchunkgenerate) return;
  1557. IWorld w = event.getWorld();
  1558. if(!(w instanceof WorldServer)) return;
  1559. IChunk c = event.getChunk();
  1560. if((c != null) /*TODO && (!c.isTerrainPopulated())*/) { // If new chunk?
  1561. ForgeWorld fw = getWorld(w, false);
  1562. if(fw == null) {
  1563. return;
  1564. }
  1565. int ymax = 0;
  1566. ChunkSection[] sections = c.getSections();
  1567. for(int i = 0; i < sections.length; i++) {
  1568. if((sections[i] != null) && (sections[i].isEmpty() == false)) {
  1569. ymax = 16*(i+1);
  1570. }
  1571. }
  1572. ChunkPos cp = c.getPos();
  1573. int x = cp.x << 4;
  1574. int z = cp.z << 4;
  1575. if(ymax > 0) {
  1576. mapManager.touchVolume(fw.getName(), x, 0, z, x+15, ymax, z+16, "chunkgenerate");
  1577. }
  1578. }
  1579. }
  1580. /*TODO
  1581. @SubscribeEvent
  1582. public void handleChunkPopulate(PopulateChunkEvent.Post event) {
  1583. if(!core_enabled) return;
  1584. if(!onchunkpopulate) return;
  1585. World w = event.getWorld();
  1586. if(!(w instanceof WorldServer)) return;
  1587. Chunk c = w.getChunkFromChunkCoords(event.getChunkX(), event.getChunkZ());
  1588. int ymin = 0, ymax = 0;
  1589. if(c != null) {
  1590. ForgeWorld fw = getWorld(event.getWorld(), false);
  1591. if (fw == null) return;
  1592. ExtendedBlockStorage[] sections = c.getBlockStorageArray();
  1593. for(int i = 0; i < sections.length; i++) {
  1594. if((sections[i] != null) && (sections[i].isEmpty() == false)) {
  1595. ymax = 16*(i+1);
  1596. }
  1597. }
  1598. int x = c.x << 4;
  1599. int z = c.z << 4;
  1600. if(ymax > 0)
  1601. mapManager.touchVolume(fw.getName(), x, ymin, z, x+15, ymax, z+16, "chunkpopulate");
  1602. }
  1603. }
  1604. */
  1605. }
  1606. private boolean onblockchange = false;
  1607. private boolean onlightingchange = false;
  1608. private boolean onchunkpopulate = false;
  1609. private boolean onchunkgenerate = false;
  1610. private boolean onblockchange_with_id = false;
  1611. public class WorldUpdateTracker implements IWorldEventListener {
  1612. String worldid;
  1613. IWorld world;
  1614. @Override
  1615. public void notifyLightSet(BlockPos pos) {
  1616. if(sscache != null)
  1617. sscache.invalidateSnapshot(worldid, pos.getX(), pos.getY(), pos.getZ());
  1618. if(onlightingchange) {
  1619. mapManager.touch(worldid, pos.getX(), pos.getY(), pos.getZ(), "lightingchange");
  1620. }
  1621. }
  1622. @Override
  1623. public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2) {
  1624. }
  1625. @Override
  1626. public void onEntityAdded(Entity entityIn) {
  1627. }
  1628. @Override
  1629. public void onEntityRemoved(Entity entityIn) {
  1630. }
  1631. @Override
  1632. public void sendBlockBreakProgress(int breakerId, BlockPos pos,
  1633. int progress) {
  1634. }
  1635. @Override
  1636. public void broadcastSound(int p_180440_1_, BlockPos p_180440_2_,
  1637. int p_180440_3_) {
  1638. }
  1639. @Override
  1640. public void playSoundToAllNearExcept(EntityPlayer player,
  1641. SoundEvent soundIn, SoundCategory category, double x, double y,
  1642. double z, float volume, float pitch) {
  1643. }
  1644. @Override
  1645. public void playRecord(SoundEvent soundIn, BlockPos pos) {
  1646. }
  1647. @Override
  1648. public void playEvent(EntityPlayer arg0, int arg1, BlockPos arg2, int arg3) {
  1649. }
  1650. @Override
  1651. public void notifyBlockUpdate(IBlockReader worldIn, BlockPos pos, IBlockState oldState, IBlockState newState,
  1652. int flags) {
  1653. if(sscache != null)
  1654. sscache.invalidateSnapshot(worldid, pos.getX(), pos.getY(), pos.getZ());
  1655. if(onblockchange) {
  1656. BlockUpdateRec r = new BlockUpdateRec();
  1657. r.w = world;
  1658. r.wid = worldid;
  1659. r.x = pos.getX(); r.y = pos.getY(); r.z = pos.getZ();
  1660. blockupdatequeue.add(r);
  1661. }
  1662. }
  1663. @Override
  1664. public void addParticle(IParticleData particleData, boolean alwaysRender, double x, double y, double z,
  1665. double xSpeed, double ySpeed, double zSpeed) {
  1666. // TODO Auto-generated method stub
  1667. }
  1668. @Override
  1669. public void addParticle(IParticleData particleData, boolean ignoreRange, boolean minimizeLevel, double x,
  1670. double y, double z, double xSpeed, double ySpeed, double zSpeed) {
  1671. // TODO Auto-generated method stub
  1672. }
  1673. }
  1674. private WorldTracker worldTracker = null;
  1675. private HashMap<String, WorldUpdateTracker> updateTrackers = new HashMap<String, WorldUpdateTracker>();
  1676. private void registerEvents()
  1677. {
  1678. if(worldTracker == null) {
  1679. worldTracker = new WorldTracker();
  1680. MinecraftForge.EVENT_BUS.register(worldTracker);
  1681. }
  1682. // To trigger rendering.
  1683. onblockchange = core.isTrigger("blockupdate");
  1684. onlightingchange = core.isTrigger("lightingupdate");
  1685. onchunkpopulate = core.isTrigger("chunkpopulate");
  1686. onchunkgenerate = core.isTrigger("chunkgenerate");
  1687. onblockchange_with_id = core.isTrigger("blockupdate-with-id");
  1688. if(onblockchange_with_id)
  1689. onblockchange = true;
  1690. }
  1691. private ForgeWorld getWorldByName(String name) {
  1692. return worlds.get(name);
  1693. }
  1694. private ForgeWorld getWorld(IWorld w) {
  1695. return getWorld(w, true);
  1696. }
  1697. private ForgeWorld getWorld(IWorld w, boolean add_if_not_found) {
  1698. if(last_world == w) {
  1699. return last_fworld;
  1700. }
  1701. String wname = ForgeWorld.getWorldName(w);
  1702. for(ForgeWorld fw : worlds.values()) {
  1703. if(fw.getRawName().equals(wname)) {
  1704. last_world = w;
  1705. last_fworld = fw;
  1706. if(fw.isLoaded() == false) {
  1707. fw.setWorldLoaded(w);
  1708. // Add tracker
  1709. WorldUpdateTracker wit = new WorldUpdateTracker();
  1710. wit.worldid = fw.getName();
  1711. wit.world = w;
  1712. updateTrackers.put(fw.getName(), wit);
  1713. w.getWorld().addEventListener(wit);
  1714. }
  1715. return fw;
  1716. }
  1717. }
  1718. ForgeWorld fw = null;
  1719. if(add_if_not_found) {
  1720. /* Add to list if not found */
  1721. fw = new ForgeWorld(w);
  1722. worlds.put(fw.getName(), fw);
  1723. // Add tracker
  1724. WorldUpdateTracker wit = new WorldUpdateTracker();
  1725. wit.worldid = fw.getName();
  1726. wit.world = w;
  1727. updateTrackers.put(fw.getName(), wit);
  1728. w.getWorld().addEventListener(wit);
  1729. }
  1730. last_world = w;
  1731. last_fworld = fw;
  1732. return fw;
  1733. }
  1734. /*
  1735. private void removeWorld(ForgeWorld fw) {
  1736. WorldUpdateTracker wit = updateTrackers.remove(fw.getName());
  1737. if(wit != null) {
  1738. //fw.getWorld().removeWorldAccess(wit);
  1739. }
  1740. worlds.remove(fw.getName());
  1741. if(last_fworld == fw) {
  1742. last_world = null;
  1743. last_fworld = null;
  1744. }
  1745. }
  1746. */
  1747. private void initMetrics() {
  1748. /*
  1749. try {
  1750. Mod m = DynmapMod.class.getAnnotation(Mod.class);
  1751. metrics = new ForgeMetrics(m.name(), m.version());
  1752. ;
  1753. ForgeMetrics.Graph features = metrics.createGraph("Features Used");
  1754. features.addPlotter(new ForgeMetrics.Plotter("Internal Web Server") {
  1755. @Override
  1756. public int getValue() {
  1757. if (!core.configuration.getBoolean("disable-webserver", false))
  1758. return 1;
  1759. return 0;
  1760. }
  1761. });
  1762. features.addPlotter(new ForgeMetrics.Plotter("Login Security") {
  1763. @Override
  1764. public int getValue() {
  1765. if(core.configuration.getBoolean("login-enabled", false))
  1766. return 1;
  1767. return 0;
  1768. }
  1769. });
  1770. features.addPlotter(new ForgeMetrics.Plotter("Player Info Protected") {
  1771. @Override
  1772. public int getValue() {
  1773. if(core.player_info_protected)
  1774. return 1;
  1775. return 0;
  1776. }
  1777. });
  1778. ForgeMetrics.Graph maps = metrics.createGraph("Map Data");
  1779. maps.addPlotter(new ForgeMetrics.Plotter("Worlds") {
  1780. @Override
  1781. public int getValue() {
  1782. if(core.mapManager != null)
  1783. return core.mapManager.getWorlds().size();
  1784. return 0;
  1785. }
  1786. });
  1787. maps.addPlotter(new ForgeMetrics.Plotter("Maps") {
  1788. @Override
  1789. public int getValue() {
  1790. int cnt = 0;
  1791. if(core.mapManager != null) {
  1792. for(DynmapWorld w :core.mapManager.getWorlds()) {
  1793. cnt += w.maps.size();
  1794. }
  1795. }
  1796. return cnt;
  1797. }
  1798. });
  1799. maps.addPlotter(new ForgeMetrics.Plotter("HD Maps") {
  1800. @Override
  1801. public int getValue() {
  1802. int cnt = 0;
  1803. if(core.mapManager != null) {
  1804. for(DynmapWorld w :core.mapManager.getWorlds()) {
  1805. for(MapType mt : w.maps) {
  1806. if(mt instanceof HDMap) {
  1807. cnt++;
  1808. }
  1809. }
  1810. }
  1811. }
  1812. return cnt;
  1813. }
  1814. });
  1815. for (String mod : modsused) {
  1816. features.addPlotter(new ForgeMetrics.Plotter(mod + " Blocks") {
  1817. @Override
  1818. public int getValue() {
  1819. return 1;
  1820. }
  1821. });
  1822. }
  1823. metrics.start();
  1824. } catch (IOException e) {
  1825. // Failed to submit the stats :-(
  1826. }
  1827. */
  1828. }
  1829. private void saveWorlds() {
  1830. File f = new File(core.getDataFolder(), "forgeworlds.yml");
  1831. ConfigurationNode cn = new ConfigurationNode(f);
  1832. ArrayList<HashMap<String,Object>> lst = new ArrayList<HashMap<String,Object>>();
  1833. for(DynmapWorld fw : core.mapManager.getWorlds()) {
  1834. HashMap<String, Object> vals = new HashMap<String, Object>();
  1835. vals.put("name", fw.getRawName());
  1836. vals.put("height", fw.worldheight);
  1837. vals.put("sealevel", fw.sealevel);
  1838. vals.put("nether", fw.isNether());
  1839. vals.put("the_end", ((ForgeWorld)fw).isTheEnd());
  1840. vals.put("title", fw.getTitle());
  1841. lst.add(vals);
  1842. }
  1843. cn.put("worlds", lst);
  1844. cn.put("isMCPC", isMCPC);
  1845. cn.put("useSaveFolderAsName", useSaveFolder);
  1846. cn.put("maxWorldHeight", ForgeWorld.getMaxWorldHeight());
  1847. cn.save();
  1848. }
  1849. private void loadWorlds() {
  1850. isMCPC = server.getServerModName().contains("mcpc");
  1851. File f = new File(core.getDataFolder(), "forgeworlds.yml");
  1852. if(f.canRead() == false) {
  1853. useSaveFolder = true;
  1854. if (isMCPC) {
  1855. ForgeWorld.setMCPCMapping();
  1856. }
  1857. else {
  1858. ForgeWorld.setSaveFolderMapping();
  1859. }
  1860. return;
  1861. }
  1862. ConfigurationNode cn = new ConfigurationNode(f);
  1863. cn.load();
  1864. // If defined, use maxWorldHeight
  1865. ForgeWorld.setMaxWorldHeight(cn.getInteger("maxWorldHeight", 256));
  1866. // If existing, only switch to save folder if MCPC+
  1867. useSaveFolder = isMCPC;
  1868. // If setting defined, use it
  1869. if (cn.containsKey("useSaveFolderAsName")) {
  1870. useSaveFolder = cn.getBoolean("useSaveFolderAsName", useSaveFolder);
  1871. }
  1872. if (isMCPC) {
  1873. ForgeWorld.setMCPCMapping();
  1874. }
  1875. else if (useSaveFolder) {
  1876. ForgeWorld.setSaveFolderMapping();
  1877. }
  1878. // If inconsistent between MCPC and non-MCPC
  1879. if (isMCPC != cn.getBoolean("isMCPC", false)) {
  1880. return;
  1881. }
  1882. List<Map<String,Object>> lst = cn.getMapList("worlds");
  1883. if(lst == null) {
  1884. Log.warning("Discarding bad forgeworlds.yml");
  1885. return;
  1886. }
  1887. for(Map<String,Object> world : lst) {
  1888. try {
  1889. String name = (String)world.get("name");
  1890. int height = (Integer)world.get("height");
  1891. int sealevel = (Integer)world.get("sealevel");
  1892. boolean nether = (Boolean)world.get("nether");
  1893. boolean theend = (Boolean)world.get("the_end");
  1894. String title = (String)world.get("title");
  1895. if(name != null) {
  1896. ForgeWorld fw = new ForgeWorld(name, height, sealevel, nether, theend, title);
  1897. fw.setWorldUnloaded();
  1898. core.processWorldLoad(fw);
  1899. worlds.put(fw.getName(), fw);
  1900. }
  1901. } catch (Exception x) {
  1902. Log.warning("Unable to load saved worlds from forgeworlds.yml");
  1903. return;
  1904. }
  1905. }
  1906. }
  1907. public void serverStarted() {
  1908. this.onStart();
  1909. if (core != null) {
  1910. core.serverStarted();
  1911. }
  1912. }
  1913. public MinecraftServer getMCServer() {
  1914. return server;
  1915. }
  1916. }
  1917. class DynmapCommandHandler
  1918. {
  1919. private String cmd;
  1920. private DynmapPlugin plugin;
  1921. public DynmapCommandHandler(String cmd, DynmapPlugin p)
  1922. {
  1923. this.cmd = cmd;
  1924. this.plugin = p;
  1925. }
  1926. public void register(CommandDispatcher<CommandSource> cd) {
  1927. cd.register(Commands.literal(cmd).
  1928. then(RequiredArgumentBuilder.<CommandSource, String> argument("args", StringArgumentType.greedyString()).
  1929. executes((ctx) -> this.execute(plugin.getMCServer(), ctx.getSource(), ctx.getInput()))).
  1930. executes((ctx) -> this.execute(plugin.getMCServer(), ctx.getSource(), ctx.getInput())));
  1931. }
  1932. // @Override
  1933. public int execute(MinecraftServer server, CommandSource sender,
  1934. String cmdline) throws CommandException {
  1935. String[] args = cmdline.split("\\s+");
  1936. plugin.onCommand(sender, cmd, Arrays.copyOfRange(args, 1, args.length));
  1937. return 1;
  1938. }
  1939. // @Override
  1940. public String getUsage(CommandSource arg0) {
  1941. return "Run /" + cmd + " help for details on using command";
  1942. }
  1943. }
  1944. class DynmapCommand extends DynmapCommandHandler {
  1945. DynmapCommand(DynmapPlugin p) {
  1946. super("dynmap", p);
  1947. }
  1948. }
  1949. class DmapCommand extends DynmapCommandHandler {
  1950. DmapCommand(DynmapPlugin p) {
  1951. super("dmap", p);
  1952. }
  1953. }
  1954. class DmarkerCommand extends DynmapCommandHandler {
  1955. DmarkerCommand(DynmapPlugin p) {
  1956. super("dmarker", p);
  1957. }
  1958. }
  1959. class DynmapExpCommand extends DynmapCommandHandler {
  1960. DynmapExpCommand(DynmapPlugin p) {
  1961. super("dynmapexp", p);
  1962. }
  1963. }