PageRenderTime 85ms CodeModel.GetById 10ms app.highlight 62ms RepoModel.GetById 1ms app.codeStats 1ms

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

http://github.com/webbukkit/dynmap
Java | 2110 lines | 1634 code | 164 blank | 312 comment | 282 complexity | ee4192eaa1a8e4f56e1545475a6be6d4 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1package org.dynmap.forge_1_13_2;
   2
   3import java.io.File;
   4import java.io.InputStream;
   5import java.lang.reflect.Field;
   6import java.net.InetSocketAddress;
   7import java.net.SocketAddress;
   8import java.util.ArrayList;
   9import java.util.Arrays;
  10import java.util.Collections;
  11import java.util.HashMap;
  12import java.util.HashSet;
  13import java.util.Iterator;
  14import java.util.List;
  15import java.util.Map;
  16import java.util.Map.Entry;
  17import java.util.Optional;
  18import java.util.PriorityQueue;
  19import java.util.Set;
  20import java.util.UUID;
  21import java.util.concurrent.Callable;
  22import java.util.concurrent.CancellationException;
  23import java.util.concurrent.ConcurrentLinkedQueue;
  24import java.util.concurrent.ExecutionException;
  25import java.util.concurrent.Future;
  26import java.util.concurrent.FutureTask;
  27import java.util.regex.Pattern;
  28
  29import net.minecraft.block.Block;
  30import net.minecraft.block.material.Material;
  31import net.minecraft.block.state.IBlockState;
  32import net.minecraft.command.CommandException;
  33import net.minecraft.command.CommandSource;
  34import net.minecraft.command.Commands;
  35import net.minecraft.entity.Entity;
  36import net.minecraft.entity.player.EntityPlayer;
  37import net.minecraft.entity.player.EntityPlayerMP;
  38import net.minecraft.init.Blocks;
  39import net.minecraft.item.Item;
  40import net.minecraft.network.NetHandlerPlayServer;
  41import net.minecraft.network.NetworkManager;
  42import net.minecraft.particles.IParticleData;
  43import net.minecraft.server.MinecraftServer;
  44import net.minecraft.server.management.UserListBans;
  45import net.minecraft.server.management.UserListIPBans;
  46import net.minecraft.server.management.UserListOps;
  47import net.minecraft.server.management.PlayerProfileCache;
  48import net.minecraft.util.ObjectIntIdentityMap;
  49import net.minecraft.util.ResourceLocation;
  50import net.minecraft.util.SoundCategory;
  51import net.minecraft.util.SoundEvent;
  52import net.minecraft.util.math.BlockPos;
  53import net.minecraft.util.math.ChunkPos;
  54import net.minecraft.util.registry.IRegistry;
  55import net.minecraft.util.registry.RegistryNamespaced;
  56import net.minecraft.util.text.ITextComponent;
  57import net.minecraft.util.text.TextComponentString;
  58import net.minecraft.world.IBlockReader;
  59import net.minecraft.world.IWorld;
  60import net.minecraft.world.IWorldEventListener;
  61import net.minecraft.world.World;
  62import net.minecraft.world.WorldServer;
  63import net.minecraft.world.biome.Biome;
  64import net.minecraft.world.chunk.Chunk;
  65import net.minecraft.world.chunk.ChunkSection;
  66import net.minecraft.world.chunk.IChunk;
  67import net.minecraftforge.common.MinecraftForge;
  68import net.minecraftforge.event.ServerChatEvent;
  69import net.minecraftforge.event.world.ChunkEvent;
  70import net.minecraftforge.event.world.WorldEvent;
  71import net.minecraftforge.fml.ModList;
  72import net.minecraftforge.fml.ModContainer;
  73import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerChangedDimensionEvent;
  74import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
  75import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedOutEvent;
  76import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerRespawnEvent;
  77import net.minecraftforge.registries.ForgeRegistries;
  78import net.minecraftforge.registries.ForgeRegistry;
  79import net.minecraftforge.registries.RegistryManager;
  80import net.minecraftforge.fml.common.gameevent.TickEvent;
  81import net.minecraftforge.fml.common.registry.GameRegistry;
  82import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
  83import net.minecraftforge.fml.loading.moddiscovery.ModInfo;
  84import net.minecraftforge.forgespi.language.IModInfo;
  85
  86import org.apache.commons.codec.Charsets;
  87import org.apache.commons.codec.binary.Base64;
  88import org.apache.logging.log4j.LogManager;
  89import org.apache.logging.log4j.Logger;
  90import org.apache.maven.artifact.versioning.ArtifactVersion;
  91import org.dynmap.ConfigurationNode;
  92import org.dynmap.DynmapChunk;
  93import org.dynmap.DynmapCommonAPIListener;
  94import org.dynmap.DynmapCore;
  95import org.dynmap.DynmapLocation;
  96import org.dynmap.DynmapWorld;
  97import org.dynmap.Log;
  98import org.dynmap.MapManager;
  99import org.dynmap.PlayerList;
 100import org.dynmap.common.BiomeMap;
 101import org.dynmap.common.DynmapCommandSender;
 102import org.dynmap.common.DynmapPlayer;
 103import org.dynmap.common.DynmapServerInterface;
 104import org.dynmap.common.DynmapListenerManager.EventType;
 105import org.dynmap.debug.Debug;
 106import org.dynmap.forge_1_13_2.DmapCommand;
 107import org.dynmap.forge_1_13_2.DmarkerCommand;
 108import org.dynmap.forge_1_13_2.DynmapCommand;
 109import org.dynmap.forge_1_13_2.DynmapMod;
 110import org.dynmap.forge_1_13_2.permissions.FilePermissions;
 111import org.dynmap.forge_1_13_2.permissions.OpPermissions;
 112import org.dynmap.forge_1_13_2.permissions.PermissionProvider;
 113import org.dynmap.permissions.PermissionsHandler;
 114import org.dynmap.renderer.DynmapBlockState;
 115import org.dynmap.utils.DynIntHashMap;
 116import org.dynmap.utils.DynmapLogger;
 117import org.dynmap.utils.MapChunkCache;
 118import org.dynmap.utils.VisibilityLimit;
 119
 120import com.google.common.collect.Iterables;
 121import com.google.gson.Gson;
 122import com.google.gson.GsonBuilder;
 123import com.google.gson.JsonParseException;
 124import com.mojang.authlib.GameProfile;
 125import com.mojang.authlib.properties.Property;
 126import com.mojang.brigadier.CommandDispatcher;
 127import com.mojang.brigadier.arguments.StringArgumentType;
 128import com.mojang.brigadier.builder.LiteralArgumentBuilder;
 129import com.mojang.brigadier.builder.RequiredArgumentBuilder;
 130import com.mojang.brigadier.exceptions.CommandSyntaxException;
 131
 132import net.minecraft.state.IProperty;
 133import net.minecraftforge.eventbus.api.SubscribeEvent;
 134
 135public class DynmapPlugin
 136{ 
 137    private DynmapCore core;
 138    private PermissionProvider permissions;
 139    private boolean core_enabled;
 140    public SnapshotCache sscache;
 141    public PlayerList playerList;
 142    private MapManager mapManager;
 143    private net.minecraft.server.MinecraftServer server;
 144    public static DynmapPlugin plugin;
 145    private ChatHandler chathandler;
 146    private HashMap<String, Integer> sortWeights = new HashMap<String, Integer>(); 
 147    // Drop world load ticket after 30 seconds
 148    private long worldIdleTimeoutNS = 30 * 1000000000L;
 149    private HashMap<String, ForgeWorld> worlds = new HashMap<String, ForgeWorld>();
 150    private IWorld last_world;
 151    private ForgeWorld last_fworld;
 152    private Map<String, ForgePlayer> players = new HashMap<String, ForgePlayer>();
 153    //TODO private ForgeMetrics metrics;
 154    private HashSet<String> modsused = new HashSet<String>();
 155    private ForgeServer fserver = new ForgeServer();
 156    private boolean tickregistered = false;
 157    // TPS calculator
 158    private double tps;
 159    private long lasttick;
 160    private long avgticklen;
 161    // Per tick limit, in nsec
 162    private long perTickLimit = (50000000); // 50 ms
 163    private boolean isMCPC = false;
 164    private boolean useSaveFolder = true;
 165    private Field displayName = null; // MCPC+ display name
 166	
 167    private static final int SIGNPOST_ID = 63;
 168    private static final int WALLSIGN_ID = 68;
 169
 170    private static final String[] TRIGGER_DEFAULTS = { "blockupdate", "chunkpopulate", "chunkgenerate" };
 171
 172    private static final Pattern patternControlCode = Pattern.compile("(?i)\\u00A7[0-9A-FK-OR]");
 173
 174    public static class BlockUpdateRec {
 175    	IWorld w;
 176    	String wid;
 177    	int x, y, z;
 178    }
 179    ConcurrentLinkedQueue<BlockUpdateRec> blockupdatequeue = new ConcurrentLinkedQueue<BlockUpdateRec>();
 180
 181    public static DynmapBlockState[] stateByID;
 182    
 183    /**
 184     * Initialize block states (org.dynmap.blockstate.DynmapBlockState)
 185     */
 186    public void initializeBlockStates() {
 187    	stateByID = new DynmapBlockState[512*32];	// Simple map - scale as needed
 188    	Arrays.fill(stateByID, DynmapBlockState.AIR); // Default to air
 189
 190    	ObjectIntIdentityMap<IBlockState> bsids = Block.BLOCK_STATE_IDS;
 191
 192        DynmapBlockState basebs = null;
 193        Block baseb = null;
 194        int baseidx = 0;
 195    	
 196    	Iterator<IBlockState> iter = bsids.iterator();
 197		while (iter.hasNext()) {
 198			IBlockState bs = iter.next();
 199			int idx = bsids.get(bs);
 200    		if (idx >= stateByID.length) {
 201    			int plen = stateByID.length;
 202    			stateByID = Arrays.copyOf(stateByID, idx+1);
 203    			Arrays.fill(stateByID, plen, stateByID.length, DynmapBlockState.AIR);
 204    		}
 205            Block b = bs.getBlock();
 206    		// If this is new block vs last, it's the base block state
 207    		if (b != baseb) {
 208    			basebs = null;
 209                baseidx = idx;
 210                baseb = b;
 211    		}
 212    		
 213            ResourceLocation ui = b.getRegistryName();
 214            if (ui == null) {
 215            	continue;
 216            }
 217            String bn = ui.getNamespace() + ":" + ui.getPath();
 218            // Only do defined names, and not "air"
 219            if (!bn.equals(DynmapBlockState.AIR_BLOCK)) {
 220                Material mat = bs.getMaterial();
 221                String statename = "";
 222                for(IProperty p : bs.getProperties()) {
 223                	if (statename.length() > 0) {
 224                		statename += ",";
 225                	}
 226                	statename += p.getName() + "=" + bs.get(p).toString();
 227                }
 228                //Log.info("bn=" + bn + ", statenme=" + statename + ",idx=" + idx + ",baseidx=" + baseidx);
 229                DynmapBlockState dbs = new DynmapBlockState(basebs, idx - baseidx, bn, statename, mat.toString(), idx);
 230                stateByID[idx] = dbs;
 231                if (basebs == null) { basebs = dbs; }
 232                if (mat.isSolid()) {
 233                    dbs.setSolid();
 234                }
 235                if (mat == Material.AIR) {
 236                    dbs.setAir();
 237                }
 238                if (mat == Material.WOOD) {
 239                    dbs.setLog();
 240                }
 241                if (mat == Material.LEAVES) {
 242                    dbs.setLeaves();
 243                }
 244            }
 245    	}
 246        for (int gidx = 0; gidx < DynmapBlockState.getGlobalIndexMax(); gidx++) {
 247        	DynmapBlockState bs = DynmapBlockState.getStateByGlobalIndex(gidx);
 248        	//Log.info(gidx + ":" + bs.toString() + ", gidx=" + bs.globalStateIndex + ", sidx=" + bs.stateIndex);
 249        }
 250    }
 251
 252    public static final Item getItemByID(int id) {
 253        return Item.getItemById(id);
 254    }
 255    
 256    public static final String getBlockUnlocalizedName(Block b) {
 257    	return b.getNameTextComponent().getString();
 258    }
 259    
 260    private static Biome[] biomelist = null;
 261    
 262    public static final Biome[] getBiomeList() {
 263        if (biomelist == null) {
 264        	biomelist = new Biome[256];
 265        	Iterator<Biome> iter = ForgeRegistries.BIOMES.iterator();
 266        	while (iter.hasNext()) {
 267                Biome b = iter.next();
 268                int bidx = RegistryNamespaced.BIOME.getId(b);
 269        		if (bidx >= biomelist.length) {
 270        			biomelist = Arrays.copyOf(biomelist, bidx + biomelist.length);
 271        		}
 272        		biomelist[bidx] = b;
 273        	}
 274        }
 275        return biomelist;
 276    }
 277    public static final NetworkManager getNetworkManager(NetHandlerPlayServer nh) {
 278        return nh.netManager;
 279    }
 280    
 281    private ForgePlayer getOrAddPlayer(EntityPlayer p) {
 282        String name = p.getEntity().getName().getString();
 283    	ForgePlayer fp = players.get(name);
 284    	if(fp != null) {
 285    		fp.player = p;
 286    	}
 287    	else {
 288    		fp = new ForgePlayer(p);
 289    		players.put(name, fp);
 290    	}
 291    	return fp;
 292    }
 293    
 294    private static class TaskRecord implements Comparable<Object>
 295    {
 296        private long ticktorun;
 297        private long id;
 298        private FutureTask<?> future;
 299        @Override
 300        public int compareTo(Object o)
 301        {
 302            TaskRecord tr = (TaskRecord)o;
 303
 304            if (this.ticktorun < tr.ticktorun)
 305            {
 306                return -1;
 307            }
 308            else if (this.ticktorun > tr.ticktorun)
 309            {
 310                return 1;
 311            }
 312            else if (this.id < tr.id)
 313            {
 314                return -1;
 315            }
 316            else if (this.id > tr.id)
 317            {
 318                return 1;
 319            }
 320            else
 321            {
 322                return 0;
 323            }
 324        }
 325    }
 326
 327    private class ChatMessage {
 328    	String message;
 329    	EntityPlayer sender;
 330    }
 331    private ConcurrentLinkedQueue<ChatMessage> msgqueue = new ConcurrentLinkedQueue<ChatMessage>();
 332    
 333    public class ChatHandler {
 334		@SubscribeEvent
 335		public void handleChat(ServerChatEvent event) {
 336		    String msg = event.getMessage();
 337            if(!msg.startsWith("/")) {
 338                ChatMessage cm = new ChatMessage();
 339                cm.message = msg;
 340                cm.sender = event.getPlayer();
 341                msgqueue.add(cm);
 342            }
 343		}
 344    }
 345
 346    /** TODO: depends on forge chunk manager
 347    private static class WorldBusyRecord {
 348        long last_ts;
 349        Ticket ticket;
 350    }
 351    private static HashMap<Integer, WorldBusyRecord> busy_worlds = new HashMap<Integer, WorldBusyRecord>();
 352    
 353    private void setBusy(World w) {
 354        setBusy(w, null);
 355    }
 356    static void setBusy(World w, Ticket t) {
 357        if(w == null) return;
 358        if (!DynmapMod.useforcedchunks) return;
 359        WorldBusyRecord wbr = busy_worlds.get(w.provider.getDimension());
 360        if(wbr == null) {   // Not busy, make ticket and keep spawn loaded
 361            Debug.debug("World " + w.getWorldInfo().getWorldName() + "/"+ w.provider.getDimensionType().getName() + " is busy");
 362            wbr = new WorldBusyRecord();
 363            if(t != null)
 364                wbr.ticket = t;
 365            else
 366                wbr.ticket = ForgeChunkManager.requestTicket(DynmapMod.instance, w, ForgeChunkManager.Type.NORMAL);
 367            if(wbr.ticket != null) {
 368                BlockPos cc = w.getSpawnPoint();
 369                ChunkPos ccip = new ChunkPos(cc.getX() >> 4, cc.getZ() >> 4);
 370                ForgeChunkManager.forceChunk(wbr.ticket, ccip);
 371                busy_worlds.put(w.provider.getDimension(), wbr);  // Add to busy list
 372            }
 373        }
 374        wbr.last_ts = System.nanoTime();
 375    }
 376    
 377    private void doIdleOutOfWorlds() {
 378        if (!DynmapMod.useforcedchunks) return;
 379        long ts = System.nanoTime() - worldIdleTimeoutNS;
 380        for(Iterator<WorldBusyRecord> itr = busy_worlds.values().iterator(); itr.hasNext();) {
 381            WorldBusyRecord wbr = itr.next();
 382            if(wbr.last_ts < ts) {
 383                World w = wbr.ticket.world;
 384                Debug.debug("World " + w.getWorldInfo().getWorldName() + "/" + wbr.ticket.world.provider.getDimensionType().getName() + " is idle");
 385                if (wbr.ticket != null)
 386                    ForgeChunkManager.releaseTicket(wbr.ticket);    // Release hold on world 
 387                itr.remove();
 388            }
 389        }
 390    }
 391    */
 392    
 393    public static class OurLog implements DynmapLogger {
 394        Logger log;
 395        public static final String DM = "[Dynmap] ";
 396        OurLog() {
 397            log = LogManager.getLogger("Dynmap");
 398        }
 399        @Override
 400        public void info(String s) {
 401            log.info(DM + s);
 402        }
 403
 404        @Override
 405        public void severe(Throwable t) {
 406            log.fatal(t);
 407        }
 408
 409        @Override
 410        public void severe(String s) {
 411            log.fatal(DM + s);
 412        }
 413
 414        @Override
 415        public void severe(String s, Throwable t) {
 416            log.fatal(DM + s, t);
 417        }
 418
 419        @Override
 420        public void verboseinfo(String s) {
 421            log.info(DM + s);
 422        }
 423
 424        @Override
 425        public void warning(String s) {
 426            log.warn(DM + s);
 427        }
 428
 429        @Override
 430        public void warning(String s, Throwable t) {
 431            log.warn(DM + s, t);
 432        }
 433    }
 434    
 435    public DynmapPlugin(MinecraftServer srv)
 436    {
 437        plugin = this;
 438        this.server = srv;
 439        
 440        displayName = null;
 441        try {
 442            displayName = EntityPlayerMP.class.getField("displayName");
 443        } catch (SecurityException e) {
 444        } catch (NoSuchFieldException e) {
 445        }
 446    }
 447
 448    public boolean isOp(String player) {
 449    	String[] ops = server.getPlayerList().getOppedPlayers().getKeys();
 450    	for (String op : ops) {
 451    		if (op.equalsIgnoreCase(player)) {
 452    			return true;
 453    		}
 454    	}
 455    	return (server.isSinglePlayer() && player.equalsIgnoreCase(server.getServerOwner()));
 456    }
 457    
 458    private boolean hasPerm(EntityPlayer psender, String permission) {  
 459        PermissionsHandler ph = PermissionsHandler.getHandler();
 460        if((psender != null) && ph.hasPermission(psender.getEntity().getName().getString(), permission)) {
 461            return true;
 462        }
 463        return permissions.has(psender, permission);
 464    }
 465    
 466    private boolean hasPermNode(EntityPlayer psender, String permission) {
 467        PermissionsHandler ph = PermissionsHandler.getHandler();
 468        if((psender != null) && ph.hasPermissionNode(psender.getEntity().getName().getString(), permission)) {
 469            return true;
 470        }
 471        return permissions.hasPermissionNode(psender, permission);
 472    } 
 473
 474    private Set<String> hasOfflinePermissions(String player, Set<String> perms) {
 475        Set<String> rslt = null;
 476        PermissionsHandler ph = PermissionsHandler.getHandler();
 477        if(ph != null) {
 478            rslt = ph.hasOfflinePermissions(player, perms);
 479        }
 480        Set<String> rslt2 = hasOfflinePermissions(player, perms);
 481        if((rslt != null) && (rslt2 != null)) {
 482            Set<String> newrslt = new HashSet<String>(rslt);
 483            newrslt.addAll(rslt2);
 484            rslt = newrslt;
 485        }
 486        else if(rslt2 != null) {
 487            rslt = rslt2;
 488        }
 489        return rslt;
 490    }
 491    private boolean hasOfflinePermission(String player, String perm) {
 492        PermissionsHandler ph = PermissionsHandler.getHandler();
 493        if(ph != null) {
 494            if(ph.hasOfflinePermission(player, perm)) {
 495                return true;
 496            }
 497        }
 498        return permissions.hasOfflinePermission(player, perm);
 499    }
 500
 501    /**
 502     * Server access abstraction class
 503     */
 504    public class ForgeServer extends DynmapServerInterface
 505    {
 506        /* Server thread scheduler */
 507        private Object schedlock = new Object();
 508        private long cur_tick;
 509        private long next_id;
 510        private long cur_tick_starttime;
 511        private PriorityQueue<TaskRecord> runqueue = new PriorityQueue<TaskRecord>();
 512
 513        public ForgeServer() {
 514        }
 515
 516        private GameProfile getProfileByName(String player) {
 517            PlayerProfileCache cache = server.getPlayerProfileCache();
 518            return cache.getGameProfileForUsername(player);
 519        }
 520        
 521        @Override
 522        public int getBlockIDAt(String wname, int x, int y, int z) {
 523            return -1;
 524        }
 525		
 526        @Override
 527        public int isSignAt(String wname, int x, int y, int z) {
 528            return -1;
 529        }
 530
 531        @Override
 532        public void scheduleServerTask(Runnable run, long delay)
 533        {
 534            TaskRecord tr = new TaskRecord();
 535            tr.future = new FutureTask<Object>(run, null);
 536
 537            /* Add task record to queue */
 538            synchronized (schedlock)
 539            {
 540                tr.id = next_id++;
 541                tr.ticktorun = cur_tick + delay;
 542                runqueue.add(tr);
 543            }
 544        }
 545        @Override
 546        public DynmapPlayer[] getOnlinePlayers()
 547        {
 548            if(server.getPlayerList() == null)
 549                return new DynmapPlayer[0];
 550            List<?> playlist = server.getPlayerList().getPlayers();
 551            int pcnt = playlist.size();
 552            DynmapPlayer[] dplay = new DynmapPlayer[pcnt];
 553
 554            for (int i = 0; i < pcnt; i++)
 555            {
 556                EntityPlayer p = (EntityPlayer)playlist.get(i);
 557                dplay[i] = getOrAddPlayer(p);
 558            }
 559
 560            return dplay;
 561        }
 562        @Override
 563        public void reload()
 564        {
 565            plugin.onDisable();
 566            plugin.onEnable();
 567            plugin.onStart();
 568        }
 569        @Override
 570        public DynmapPlayer getPlayer(String name)
 571        {
 572            List<?> players = server.getPlayerList().getPlayers();
 573
 574            for (Object o : players)
 575            {
 576                EntityPlayer p = (EntityPlayer)o;
 577
 578                if (p.getEntity().getName().getString().equalsIgnoreCase(name))
 579                {
 580                    return getOrAddPlayer(p);
 581                }
 582            }
 583
 584            return null;
 585        }
 586        @Override
 587        public Set<String> getIPBans()
 588        {
 589            UserListIPBans bl = server.getPlayerList().getBannedIPs();
 590            Set<String> ips = new HashSet<String>();
 591
 592            for (String s : bl.getKeys()) {
 593                ips.add(s);
 594            }
 595            
 596            return ips;
 597        }
 598        @Override
 599        public <T> Future<T> callSyncMethod(Callable<T> task) {
 600        	return callSyncMethod(task, 0);
 601        }
 602        public <T> Future<T> callSyncMethod(Callable<T> task, long delay)
 603        {
 604            TaskRecord tr = new TaskRecord();
 605            FutureTask<T> ft = new FutureTask<T>(task);
 606            tr.future = ft;
 607
 608            /* Add task record to queue */
 609            synchronized (schedlock)
 610            {
 611                tr.id = next_id++;
 612                tr.ticktorun = cur_tick + delay;
 613                runqueue.add(tr);
 614            }
 615
 616            return ft;
 617        }
 618        @Override
 619        public String getServerName()
 620        {
 621            String sn;
 622            if (server.isSinglePlayer())
 623                sn = "Integrated";
 624            else
 625                sn = server.getServerHostname();
 626        	if(sn == null) sn = "Unknown Server";
 627        	return sn;
 628        }
 629        @Override
 630        public boolean isPlayerBanned(String pid)
 631        {
 632            UserListBans bl = server.getPlayerList().getBannedPlayers();
 633            return bl.isBanned(getProfileByName(pid));
 634        }
 635        
 636        @Override
 637        public String stripChatColor(String s)
 638        {
 639            return patternControlCode.matcher(s).replaceAll("");
 640        }
 641        private Set<EventType> registered = new HashSet<EventType>();
 642        @Override
 643        public boolean requestEventNotification(EventType type)
 644        {
 645            if (registered.contains(type))
 646            {
 647                return true;
 648            }
 649
 650            switch (type)
 651            {
 652                case WORLD_LOAD:
 653                case WORLD_UNLOAD:
 654                    /* Already called for normal world activation/deactivation */
 655                    break;
 656
 657                case WORLD_SPAWN_CHANGE:
 658                    /*TODO
 659                    pm.registerEvents(new Listener() {
 660                        @EventHandler(priority=EventPriority.MONITOR)
 661                        public void onSpawnChange(SpawnChangeEvent evt) {
 662                            DynmapWorld w = new BukkitWorld(evt.getWorld());
 663                            core.listenerManager.processWorldEvent(EventType.WORLD_SPAWN_CHANGE, w);
 664                        }
 665                    }, DynmapPlugin.this);
 666                    */
 667                    break;
 668
 669                case PLAYER_JOIN:
 670                case PLAYER_QUIT:
 671                    /* Already handled */
 672                    break;
 673
 674                case PLAYER_BED_LEAVE:
 675                    /*TODO
 676                    pm.registerEvents(new Listener() {
 677                        @EventHandler(priority=EventPriority.MONITOR)
 678                        public void onPlayerBedLeave(PlayerBedLeaveEvent evt) {
 679                            DynmapPlayer p = new BukkitPlayer(evt.getPlayer());
 680                            core.listenerManager.processPlayerEvent(EventType.PLAYER_BED_LEAVE, p);
 681                        }
 682                    }, DynmapPlugin.this);
 683                    */
 684                    break;
 685
 686                case PLAYER_CHAT:
 687                	if (chathandler == null) {
 688                		chathandler = new ChatHandler();
 689                		MinecraftForge.EVENT_BUS.register(chathandler);
 690                	}
 691                    break;
 692
 693                case BLOCK_BREAK:
 694                    /*TODO
 695                    pm.registerEvents(new Listener() {
 696                        @EventHandler(priority=EventPriority.MONITOR)
 697                        public void onBlockBreak(BlockBreakEvent evt) {
 698                            if(evt.isCancelled()) return;
 699                            Block b = evt.getBlock();
 700                            if(b == null) return;
 701                            Location l = b.getLocation();
 702                            core.listenerManager.processBlockEvent(EventType.BLOCK_BREAK, b.getType().getId(),
 703                                    BukkitWorld.normalizeWorldName(l.getWorld().getName()), l.getBlockX(), l.getBlockY(), l.getBlockZ());
 704                        }
 705                    }, DynmapPlugin.this);
 706                    */
 707                    break;
 708
 709                case SIGN_CHANGE:
 710                    /*TODO
 711                    pm.registerEvents(new Listener() {
 712                        @EventHandler(priority=EventPriority.MONITOR)
 713                        public void onSignChange(SignChangeEvent evt) {
 714                            if(evt.isCancelled()) return;
 715                            Block b = evt.getBlock();
 716                            Location l = b.getLocation();
 717                            String[] lines = evt.getLines();
 718                            DynmapPlayer dp = null;
 719                            Player p = evt.getPlayer();
 720                            if(p != null) dp = new BukkitPlayer(p);
 721                            core.listenerManager.processSignChangeEvent(EventType.SIGN_CHANGE, b.getType().getId(),
 722                                    BukkitWorld.normalizeWorldName(l.getWorld().getName()), l.getBlockX(), l.getBlockY(), l.getBlockZ(), lines, dp);
 723                        }
 724                    }, DynmapPlugin.this);
 725                    */
 726                    break;
 727
 728                default:
 729                    Log.severe("Unhandled event type: " + type);
 730                    return false;
 731            }
 732
 733            registered.add(type);
 734            return true;
 735        }
 736        @Override
 737        public boolean sendWebChatEvent(String source, String name, String msg)
 738        {
 739            return DynmapCommonAPIListener.fireWebChatEvent(source, name, msg);
 740        }
 741        @Override
 742        public void broadcastMessage(String msg)
 743        {
 744            ITextComponent component = new TextComponentString(msg);
 745            server.getPlayerList().sendMessage(component);
 746            Log.info(stripChatColor(msg));
 747        }
 748        @Override
 749        public String[] getBiomeIDs()
 750        {
 751            BiomeMap[] b = BiomeMap.values();
 752            String[] bname = new String[b.length];
 753
 754            for (int i = 0; i < bname.length; i++)
 755            {
 756                bname[i] = b[i].toString();
 757            }
 758
 759            return bname;
 760        }
 761        @Override
 762        public double getCacheHitRate()
 763        {
 764            if(sscache != null)
 765                return sscache.getHitRate();
 766            return 0.0;
 767        }
 768        @Override
 769        public void resetCacheStats()
 770        {
 771            if(sscache != null)
 772                sscache.resetStats();
 773        }
 774        @Override
 775        public DynmapWorld getWorldByName(String wname)
 776        {
 777        	return DynmapPlugin.this.getWorldByName(wname);
 778        }
 779        @Override
 780        public DynmapPlayer getOfflinePlayer(String name)
 781        {
 782            /*
 783            OfflinePlayer op = getServer().getOfflinePlayer(name);
 784            if(op != null) {
 785                return new BukkitPlayer(op);
 786            }
 787            */
 788            return null;
 789        }
 790        @Override
 791        public Set<String> checkPlayerPermissions(String player, Set<String> perms)
 792        {
 793            net.minecraft.server.management.PlayerList scm = server.getPlayerList();
 794            if (scm == null) return Collections.emptySet();
 795            UserListBans bl = scm.getBannedPlayers();
 796            if (bl == null) return Collections.emptySet();
 797            if(bl.isBanned(getProfileByName(player))) {
 798                return Collections.emptySet();
 799            }
 800            Set<String> rslt = hasOfflinePermissions(player, perms);
 801            if (rslt == null) {
 802                rslt = new HashSet<String>();
 803                if(plugin.isOp(player)) {
 804                    rslt.addAll(perms);
 805                }
 806            }
 807            return rslt;
 808        }
 809        @Override
 810        public boolean checkPlayerPermission(String player, String perm)
 811        {
 812            net.minecraft.server.management.PlayerList scm = server.getPlayerList();
 813            if (scm == null) return false;
 814            UserListBans bl = scm.getBannedPlayers();
 815            if (bl == null) return false;
 816            if(bl.isBanned(getProfileByName(player))) {
 817                return false;
 818            }
 819            return hasOfflinePermission(player, perm);
 820        }
 821        /**
 822         * Render processor helper - used by code running on render threads to request chunk snapshot cache from server/sync thread
 823         */
 824        @Override
 825        public MapChunkCache createMapChunkCache(DynmapWorld w, List<DynmapChunk> chunks,
 826                boolean blockdata, boolean highesty, boolean biome, boolean rawbiome)
 827        {
 828            ForgeMapChunkCache c = (ForgeMapChunkCache) w.getChunkCache(chunks);
 829            if(c == null) {
 830            	return null;
 831            }
 832            if (w.visibility_limits != null)
 833            {
 834                for (VisibilityLimit limit: w.visibility_limits)
 835                {
 836                    c.setVisibleRange(limit);
 837                }
 838
 839                c.setHiddenFillStyle(w.hiddenchunkstyle);
 840            }
 841
 842            if (w.hidden_limits != null)
 843            {
 844                for (VisibilityLimit limit: w.hidden_limits)
 845                {
 846                    c.setHiddenRange(limit);
 847                }
 848
 849                c.setHiddenFillStyle(w.hiddenchunkstyle);
 850            }
 851
 852            if (c.setChunkDataTypes(blockdata, biome, highesty, rawbiome) == false)
 853            {
 854                Log.severe("CraftBukkit build does not support biome APIs");
 855            }
 856
 857            if (chunks.size() == 0)     /* No chunks to get? */
 858            {
 859                c.loadChunks(0);
 860                return c;
 861            }
 862            
 863            //Now handle any chunks in server thread that are already loaded (on server thread)
 864            final ForgeMapChunkCache cc = c;
 865            Future<Boolean> f = this.callSyncMethod(new Callable<Boolean>() {
 866                public Boolean call() throws Exception {
 867                    // Update busy state on world
 868                    ForgeWorld fw = (ForgeWorld)cc.getWorld();
 869                    //TODO
 870                    //setBusy(fw.getWorld());
 871                    cc.getLoadedChunks();
 872                    return true;
 873                }
 874            }, 0);
 875            try {
 876                f.get();
 877            }
 878            catch (CancellationException cx) {
 879                return null;
 880            }
 881            catch (ExecutionException xx) {
 882                Log.severe("Exception while loading chunks", xx.getCause());
 883                return null;
 884            }
 885            catch (Exception ix) {
 886                Log.severe(ix);
 887                return null;
 888            }
 889            if(w.isLoaded() == false) {
 890            	return null;
 891            }
 892            // Now, do rest of chunk reading from calling thread
 893            c.readChunks(chunks.size());
 894            
 895            return c;
 896        }
 897        @Override
 898        public int getMaxPlayers()
 899        {
 900            return server.getMaxPlayers();
 901        }
 902        @Override
 903        public int getCurrentPlayers()
 904        {
 905            return server.getPlayerList().getCurrentPlayerCount();
 906        }
 907
 908        @SubscribeEvent
 909		public void tickEvent(TickEvent.ServerTickEvent event)  {
 910            if (event.phase == TickEvent.Phase.START) {
 911                return;
 912            }
 913            cur_tick_starttime = System.nanoTime();
 914            long elapsed = cur_tick_starttime - lasttick;
 915            lasttick = cur_tick_starttime;
 916            avgticklen = ((avgticklen * 99) / 100) + (elapsed / 100);
 917            tps = (double)1E9 / (double)avgticklen;
 918            // Tick core
 919            if (core != null) {
 920                core.serverTick(tps);
 921            }
 922
 923            boolean done = false;
 924            TaskRecord tr = null;
 925
 926            while(!blockupdatequeue.isEmpty()) {
 927                BlockUpdateRec r = blockupdatequeue.remove();
 928                IBlockState bs = r.w.getBlockState(new BlockPos(r.x, r.y, r.z));
 929                int idx = Block.BLOCK_STATE_IDS.get(bs);
 930                if(!org.dynmap.hdmap.HDBlockModels.isChangeIgnoredBlock(stateByID[idx])) {
 931                    if(onblockchange_with_id)
 932                        mapManager.touch(r.wid, r.x, r.y, r.z, "blockchange[" + idx + "]");
 933                    else
 934                        mapManager.touch(r.wid, r.x, r.y, r.z, "blockchange");
 935                }
 936            }
 937
 938            long now;
 939
 940            synchronized(schedlock) {
 941                cur_tick++;
 942                now = System.nanoTime();
 943                tr = runqueue.peek();
 944                /* Nothing due to run */
 945                if((tr == null) || (tr.ticktorun > cur_tick) || ((now - cur_tick_starttime) > perTickLimit)) {
 946                    done = true;
 947                }
 948                else {
 949                    tr = runqueue.poll();
 950                }
 951            }
 952            while (!done) {
 953                tr.future.run();
 954
 955                synchronized(schedlock) {
 956                    tr = runqueue.peek();
 957                    now = System.nanoTime();
 958                    /* Nothing due to run */
 959                    if((tr == null) || (tr.ticktorun > cur_tick) || ((now - cur_tick_starttime) > perTickLimit)) {
 960                        done = true;
 961                    }
 962                    else {
 963                        tr = runqueue.poll();
 964                    }
 965                }
 966            }
 967            while(!msgqueue.isEmpty()) {
 968                ChatMessage cm = msgqueue.poll();
 969                DynmapPlayer dp = null;
 970                if(cm.sender != null)
 971                    dp = getOrAddPlayer(cm.sender);
 972                else
 973                    dp = new ForgePlayer(null);
 974
 975                core.listenerManager.processChatEvent(EventType.PLAYER_CHAT, dp, cm.message);
 976            }
 977            /* Check for idle worlds */
 978            if((cur_tick % 20) == 0) {
 979            	//TODO
 980                //doIdleOutOfWorlds();
 981            }
 982		}
 983
 984		@Override
 985		public boolean isModLoaded(String name) {
 986			boolean loaded = ModList.get().isLoaded(name);
 987			if (loaded) {
 988                modsused.add(name);
 989			}
 990			return loaded;
 991		}
 992		@Override
 993		public String getModVersion(String name) {
 994		    Optional<? extends ModContainer> mod = ModList.get().getModContainerById(name);    // Try case sensitive lookup
 995		    if (mod.isPresent()) {
 996		    	ArtifactVersion vi = mod.get().getModInfo().getVersion();
 997		    	return vi.getMajorVersion() + "." + vi.getMinorVersion() + "." + vi.getIncrementalVersion();
 998		    }
 999		    return null;
1000		}
1001        @Override
1002        public double getServerTPS() {
1003            return tps;
1004        }
1005        
1006        @Override
1007        public String getServerIP() {
1008            if (server.isSinglePlayer())
1009                return "0.0.0.0";
1010            else
1011                return server.getServerHostname();
1012        }
1013        @Override
1014        public File getModContainerFile(String name) {
1015        	ModFileInfo mfi = ModList.get().getModFileById(name);    // Try case sensitive lookup
1016            if (mfi != null) {
1017            	File f = mfi.getFile().getFilePath().toFile();
1018                return f;
1019            }
1020        	return null;
1021        }
1022        @Override
1023        public List<String> getModList() {
1024        	List<ModInfo> mil = ModList.get().getMods();
1025        	List<String> lst = new ArrayList<String>();
1026        	for (ModInfo mi : mil) {
1027        		lst.add(mi.getModId());
1028        	}
1029        	return lst;
1030        }
1031
1032        @Override
1033        public Map<Integer, String> getBlockIDMap() {
1034            Map<Integer, String> map = new HashMap<Integer, String>();
1035            return map;
1036        }
1037
1038        @Override
1039        public InputStream openResource(String modid, String rname) {
1040            if (modid != null) {
1041                Optional<? extends ModContainer> mc = ModList.get().getModContainerById(modid);
1042                Object mod = (mc.isPresent()) ? mc.get().getMod() : null;
1043                if (mod != null) {
1044                    InputStream is = mod.getClass().getClassLoader().getResourceAsStream(rname);
1045                    if (is != null) {
1046                        return is;
1047                    }
1048                }
1049            }
1050            List<ModInfo> mcl = ModList.get().getMods();
1051            for (ModInfo mci : mcl) {
1052                Optional<? extends ModContainer> mc = ModList.get().getModContainerById(mci.getModId());
1053                Object mod = (mc.isPresent()) ? mc.get().getMod() : null;
1054                if (mod == null) continue;
1055                InputStream is = mod.getClass().getClassLoader().getResourceAsStream(rname);
1056                if (is != null) {
1057                    return is;
1058                }
1059            }
1060            return null;
1061        }
1062        /**
1063         * Get block unique ID map (module:blockid)
1064         */
1065        @Override
1066        public Map<String, Integer> getBlockUniqueIDMap() {
1067            HashMap<String, Integer> map = new HashMap<String, Integer>();
1068            return map;
1069        }
1070        /**
1071         * Get item unique ID map (module:itemid)
1072         */
1073        @Override
1074        public Map<String, Integer> getItemUniqueIDMap() {
1075            HashMap<String, Integer> map = new HashMap<String, Integer>();
1076            return map;
1077        }
1078
1079    }
1080    private static final Gson gson = new GsonBuilder().create();
1081
1082    public class TexturesPayload {
1083        public long timestamp;
1084        public String profileId;
1085        public String profileName;
1086        public boolean isPublic;
1087        public Map<String, ProfileTexture> textures;
1088
1089    }
1090    public class ProfileTexture {
1091        public String url;
1092    }
1093    
1094    /**
1095     * Player access abstraction class
1096     */
1097    public class ForgePlayer extends ForgeCommandSender implements DynmapPlayer
1098    {
1099        private EntityPlayer player;
1100        private final String skinurl;
1101        private final UUID uuid;
1102
1103
1104        public ForgePlayer(EntityPlayer p)
1105        {
1106            player = p;
1107            String url = null;
1108        	if (player != null) {
1109        		uuid = player.getUniqueID();
1110        		GameProfile prof = player.getGameProfile();
1111        		if (prof != null) {
1112        	        Property textureProperty = Iterables.getFirst(prof.getProperties().get("textures"), null);
1113
1114        	        if (textureProperty != null) {
1115        	        	TexturesPayload result = null;
1116        	        	try {
1117        	        		String json = new String(Base64.decodeBase64(textureProperty.getValue()), Charsets.UTF_8);
1118        	        		result = gson.fromJson(json, TexturesPayload.class);
1119        	        	} catch (JsonParseException e) {
1120        	        	}
1121        	        	if ((result != null) && (result.textures != null) && (result.textures.containsKey("SKIN"))) {
1122        	        		url = result.textures.get("SKIN").url;
1123        	        	}
1124        			}
1125        		}
1126        	}
1127        	else {
1128        		uuid = null;
1129        	}
1130        	skinurl = url;
1131        }
1132        @Override
1133        public boolean isConnected()
1134        {
1135            return true;
1136        }
1137        @Override
1138        public String getName()
1139        {
1140        	if(player != null)
1141        		return player.getEntity().getName().getString();
1142        	else
1143        		return "[Server]";
1144        }
1145        @Override
1146        public String getDisplayName()
1147        {
1148        	if(player != null) {
1149        	    if (displayName != null) {
1150        	        try {
1151                        return (String) displayName.get(player);
1152                    } catch (IllegalArgumentException e) {
1153                    } catch (IllegalAccessException e) {
1154                    }
1155        	    }
1156        		return player.getDisplayName().getUnformattedComponentText();
1157        	}
1158        	else
1159        		return "[Server]";
1160        }
1161        @Override
1162        public boolean isOnline()
1163        {
1164            return true;
1165        }
1166        @Override
1167        public DynmapLocation getLocation()
1168        {
1169            if (player == null)
1170            {
1171                return null;
1172            }
1173
1174            return toLoc(player.world, player.posX, player.posY, player.posZ);
1175        }
1176        @Override
1177        public String getWorld()
1178        {
1179            if (player == null)
1180            {
1181                return null;
1182            }
1183
1184            if (player.world != null)
1185            {
1186                return DynmapPlugin.this.getWorld(player.world).getName();
1187            }
1188
1189            return null;
1190        }
1191        @Override
1192        public InetSocketAddress getAddress()
1193        {
1194            if((player != null) && (player instanceof EntityPlayerMP)) {
1195            	NetHandlerPlayServer nsh = ((EntityPlayerMP)player).connection;
1196            	if((nsh != null) && (getNetworkManager(nsh) != null)) {
1197            		SocketAddress sa = getNetworkManager(nsh).getRemoteAddress();
1198            		if(sa instanceof InetSocketAddress) {
1199            			return (InetSocketAddress)sa;
1200            		}
1201            	}
1202            }
1203            return null;
1204        }
1205        @Override
1206        public boolean isSneaking()
1207        {
1208            if (player != null)
1209            {
1210                return player.isSneaking();
1211            }
1212
1213            return false;
1214        }
1215        @Override
1216        public double getHealth()
1217        {
1218            if (player != null)
1219            {
1220                double h = player.getHealth();
1221                if(h > 20) h = 20;
1222                return h;  // Scale to 20 range
1223            }
1224            else
1225            {
1226                return 0;
1227            }
1228        }
1229        @Override
1230        public int getArmorPoints()
1231        {
1232            if (player != null)
1233            {
1234                return player.getTotalArmorValue();
1235            }
1236            else
1237            {
1238                return 0;
1239            }
1240        }
1241        @Override
1242        public DynmapLocation getBedSpawnLocation()
1243        {
1244            return null;
1245        }
1246        @Override
1247        public long getLastLoginTime()
1248        {
1249            return 0;
1250        }
1251        @Override
1252        public long getFirstLoginTime()
1253        {
1254            return 0;
1255        }
1256        @Override
1257        public boolean hasPrivilege(String privid)
1258        {
1259            if(player != null)
1260                return hasPerm(player, privid);
1261            return false;
1262        }
1263        @Override
1264        public boolean isOp()
1265        {
1266        	return DynmapPlugin.this.isOp(player.getEntity().getName().getString());
1267    	}
1268        @Override
1269        public void sendMessage(String msg)
1270        {
1271            ITextComponent ichatcomponent = new TextComponentString(msg);
1272            player.sendMessage(ichatcomponent);
1273        }
1274        @Override
1275        public boolean isInvisible() {
1276        	if(player != null) {
1277        		return player.isInvisible();
1278        	}
1279        	return false;
1280        }
1281        @Override
1282        public int getSortWeight() {
1283            Integer wt = sortWeights.get(getName());
1284            if (wt != null)
1285                return wt;
1286            return 0;
1287        }
1288        @Override
1289        public void setSortWeight(int wt) {
1290            if (wt == 0) {
1291                sortWeights.remove(getName());
1292            }
1293            else {
1294                sortWeights.put(getName(), wt);
1295            }
1296        }
1297        @Override
1298        public boolean hasPermissionNode(String node) {
1299            if(player != null)
1300                return hasPermNode(player, node);
1301            return false;
1302        }
1303        @Override
1304        public String getSkinURL() {
1305        	return skinurl;
1306        }
1307        @Override
1308        public UUID getUUID() {
1309        	return uuid;
1310        }
1311    }
1312    /* Handler for generic console command sender */
1313    public class ForgeCommandSender implements DynmapCommandSender
1314    {
1315        private CommandSource sender;
1316
1317        protected ForgeCommandSender() {
1318        	sender = null;
1319        }
1320
1321        public ForgeCommandSender(CommandSource send)
1322        {
1323            sender = send;
1324        }
1325
1326        @Override
1327        public boolean hasPrivilege(String privid)
1328        {
1329        	return true;
1330        }
1331
1332        @Override
1333        public void sendMessage(String msg)
1334        {
1335        	if(sender != null) {
1336                ITextComponent ichatcomponent = new TextComponentString(msg);
1337                sender.sendFeedback(ichatcomponent, false);
1338        	}
1339        }
1340
1341        @Override
1342        public boolean isConnected()
1343        {
1344            return false;
1345        }
1346        @Override
1347        public boolean isOp()
1348        {
1349            return true;
1350        }
1351        @Override
1352        public boolean hasPermissionNode(String node) {
1353            return true;
1354        } 
1355    }
1356
1357    public void loadExtraBiomes(String mcver) {
1358    	int cnt = 0;
1359        BiomeMap.loadWellKnownByVersion(mcver);
1360
1361    	Biome[] list = getBiomeList();
1362    	
1363        for(int i = 0; i < list.length; i++) {
1364            Biome bb = list[i];
1365            if(bb != null) {
1366                String id = bb.getRegistryName().getPath();
1367                float tmp = bb.getDefaultTemperature(), hum = bb.getDownfall();
1368                int watermult = bb.getWaterColor();
1369                Log.verboseinfo("biome[" + i + "]: hum=" + hum + ", tmp=" + tmp + ", mult=" + Integer.toHexString(watermult));
1370
1371                BiomeMap bmap = BiomeMap.byBiomeID(i);
1372                if (bmap.isDefault()) {
1373                    bmap = new BiomeMap(i, id, tmp, hum);
1374                    Log.verboseinfo("Add custom biome [" + bmap.toString() + "] (" + i + ")");
1375                    cnt++;
1376                }
1377                else {
1378                    bmap.setTemperature(tmp);
1379                    bmap.setRainfall(hum);
1380                }
1381                if (watermult != -1) {
1382                    bmap.setWaterColorMultiplier(watermult);
1383                	Log.verboseinfo("Set watercolormult for " + bmap.toString() + " (" + i + ") to " + Integer.toHexString(watermult));
1384                }
1385            }
1386        }
1387        if(cnt > 0)
1388        	Log.info("Added " + cnt + " custom biome mappings");
1389    }
1390
1391    private String[] getBiomeNames() {
1392        Biome[] list = getBiomeList();
1393        String[] lst = new String[list.length];
1394        for(int i = 0; i < list.length; i++) {
1395            Biome bb = list[i];
1396            if (bb != null) {
1397                lst[i] = bb.getRegistryName().getPath();
1398            }
1399        }
1400        return lst;
1401    }
1402
1403    public void onEnable()
1404    {
1405        /* Get MC version */
1406        String mcver = server.getMinecraftVersion();
1407
1408        /* Load extra biomes */
1409        loadExtraBiomes(mcver);
1410        /* Set up player login/quit event handler */
1411        registerPlayerLoginListener();
1412        /* Initialize permissions handler */
1413        permissions = FilePermissions.create();
1414        if(permissions == null) {
1415            permissions = new OpPermissions(new String[] { "webchat", "marker.icons", "marker.list", "webregister", "stats", "hide.self", "show.self" });
1416        }
1417        /* Get and initialize data folder */
1418        File dataDirectory = new File("dynmap");
1419
1420        if (dataDirectory.exists() == false)
1421        {
1422            dataDirectory.mkdirs();
1423        }
1424
1425        /* Instantiate core */
1426        if (core == null)
1427        {
1428            core = new DynmapCore();
1429        }
1430
1431        /* Inject dependencies */
1432        core.setPluginJarFile(DynmapMod.jarfile);
1433        core.setPluginVersion(DynmapMod.ver);
1434        core.setMinecraftVersion(mcver);
1435        core.setDataFolder(dataDirectory);
1436        core.setServer(fserver);
1437        ForgeMapChunkCache.init();
1438        core.setTriggerDefault(TRIGGER_DEFAULTS);
1439        core.setBiomeNames(getBiomeNames());
1440
1441        if(!core.initConfiguration(null))
1442        {
1443        	return;
1444        }
1445        DynmapCommonAPIListener.apiInitialized(core);
1446    }
1447    
1448    private static int test(CommandSource source) throws CommandSyntaxException
1449	{
1450        System.out.println(source.toString());
1451		return 1;
1452    }
1453    
1454    private DynmapCommand dynmapCmd;
1455    private DmapCommand dmapCmd;
1456    private DmarkerCommand dmarkerCmd;
1457    private DynmapExpCommand dynmapexpCmd;
1458
1459    public void onStarting(CommandDispatcher<CommandSource> cd) {
1460        /* Register command hander */
1461        dynmapCmd = new DynmapCommand(this);
1462        dmapCmd = new DmapCommand(this);
1463        dmarkerCmd = new DmarkerCommand(this);
1464        dynmapexpCmd = new DynmapExpCommand(this);
1465        dynmapCmd.register(cd);
1466        dmapCmd.register(cd);
1467        dmarkerCmd.register(cd);
1468        dynmapexpCmd.register(cd);
1469
1470        Log.info("Register commands");
1471    }
1472    
1473    public void onStart() {
1474    	initializeBlockStates();
1475        /* Enable core */
1476        if (!core.enableCore(null))
1477        {
1478            return;
1479        }
1480        core_enabled = true;
1481        VersionCheck.runCheck(core);
1482        // Get per tick time limit
1483        perTickLimit = core.getMaxTickUseMS() * 1000000;
1484        // Prep TPS
1485        lasttick = System.nanoTime();
1486        tps = 20.0;
1487        
1488        /* Register tick handler */
1489        if(!tickregistered) {
1490            MinecraftForge.EVENT_BUS.register(fserver);
1491            tickregistered = true;
1492        }
1493
1494        playerList = core.playerList;
1495        sscache = new SnapshotCache(core.getSnapShotCacheSize(), core.u

Large files files are truncated, but you can click here to view the full file