Added /kc dump command for some debug reports
This commit is contained in:
		
							
								
								
									
										17
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								CONTRIBUTING.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					Contribution Guide
 | 
				
			||||||
 | 
					==================
 | 
				
			||||||
 | 
					You can make and publish your changes, and even suggest to merge your changes with main codebase of the server.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Installing Dev Environment
 | 
				
			||||||
 | 
					--------------------------
 | 
				
			||||||
 | 
					 * First of all you need to clone main server code and some other parts, like Forge and Bukkit  
 | 
				
			||||||
 | 
					   `git clone --recursive https://gitlab.prok.pw/Prototik/KCauldron.git`
 | 
				
			||||||
 | 
					 * Move to `KCauldron` directory  
 | 
				
			||||||
 | 
					   `cd KCauldron`
 | 
				
			||||||
 | 
					 * Prepare some stuff  
 | 
				
			||||||
 | 
					   `./gradlew setupCauldron`
 | 
				
			||||||
 | 
					 * For now you need to open project in Eclipse IDE
 | 
				
			||||||
 | 
					   * If you haven't Eclipse on your computer - [download and install it](https://www.eclipse.org/downloads/)  
 | 
				
			||||||
 | 
					   * In Eclipse choose File - Import... - General - Existing Projects into Workspace, specify KCauldron/eclipse folder
 | 
				
			||||||
 | 
					   * Unmark `Copy projects into workspace` button!
 | 
				
			||||||
 | 
					   * Click Finish and start your contributing!
 | 
				
			||||||
@@ -193,7 +193,7 @@
 | 
				
			|||||||
+    // Spigot start
 | 
					+    // Spigot start
 | 
				
			||||||
+
 | 
					+
 | 
				
			||||||
+    /** Positions to update */
 | 
					+    /** Positions to update */
 | 
				
			||||||
+    protected final gnu.trove.map.hash.TLongShortHashMap activeChunkSet_CB;
 | 
					+    public final gnu.trove.map.hash.TLongShortHashMap activeChunkSet_CB;
 | 
				
			||||||
+    public float growthOdds = 100;
 | 
					+    public float growthOdds = 100;
 | 
				
			||||||
+    protected float modifiedOdds = 100;
 | 
					+    protected float modifiedOdds = 100;
 | 
				
			||||||
+
 | 
					+
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,12 @@
 | 
				
			|||||||
package kcauldron;
 | 
					package kcauldron;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.File;
 | 
				
			||||||
 | 
					import java.io.FileOutputStream;
 | 
				
			||||||
 | 
					import java.io.OutputStream;
 | 
				
			||||||
 | 
					import java.io.OutputStreamWriter;
 | 
				
			||||||
 | 
					import java.io.Writer;
 | 
				
			||||||
 | 
					import java.util.List;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import org.bukkit.ChatColor;
 | 
					import org.bukkit.ChatColor;
 | 
				
			||||||
import org.bukkit.World;
 | 
					import org.bukkit.World;
 | 
				
			||||||
import org.bukkit.command.Command;
 | 
					import org.bukkit.command.Command;
 | 
				
			||||||
@@ -10,112 +17,164 @@ import org.bukkit.craftbukkit.entity.CraftPlayer;
 | 
				
			|||||||
import kcauldron.updater.CommandSenderUpdateCallback;
 | 
					import kcauldron.updater.CommandSenderUpdateCallback;
 | 
				
			||||||
import kcauldron.updater.KCauldronUpdater;
 | 
					import kcauldron.updater.KCauldronUpdater;
 | 
				
			||||||
import kcauldron.updater.KVersionRetriever;
 | 
					import kcauldron.updater.KVersionRetriever;
 | 
				
			||||||
import net.minecraft.entity.player.EntityPlayer;
 | 
					import net.minecraft.entity.Entity;
 | 
				
			||||||
import net.minecraft.server.MinecraftServer;
 | 
					import net.minecraft.server.MinecraftServer;
 | 
				
			||||||
 | 
					import net.minecraft.tileentity.TileEntity;
 | 
				
			||||||
 | 
					import net.minecraft.world.NextTickListEntry;
 | 
				
			||||||
import net.minecraft.world.WorldServer;
 | 
					import net.minecraft.world.WorldServer;
 | 
				
			||||||
import net.minecraftforge.server.command.ForgeCommand;
 | 
					import net.minecraft.world.chunk.Chunk;
 | 
				
			||||||
 | 
					import net.minecraftforge.common.DimensionManager;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class KCauldronCommand extends Command {
 | 
					public class KCauldronCommand extends Command {
 | 
				
			||||||
    public static final String NAME = "kc";
 | 
						public static final String NAME = "kc";
 | 
				
			||||||
    public static final String CHECK = NAME + ".check";
 | 
						public static final String CHECK = NAME + ".check";
 | 
				
			||||||
    public static final String UPDATE = NAME + ".update";
 | 
						public static final String UPDATE = NAME + ".update";
 | 
				
			||||||
    public static final String TPS = NAME + ".tps";
 | 
						public static final String TPS = NAME + ".tps";
 | 
				
			||||||
    public static final String RESTART = NAME + ".restart";
 | 
						public static final String RESTART = NAME + ".restart";
 | 
				
			||||||
 | 
						public static final String DUMP = NAME + ".dump";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public KCauldronCommand() {
 | 
						public KCauldronCommand() {
 | 
				
			||||||
        super(NAME);
 | 
							super(NAME);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        StringBuilder builder = new StringBuilder();
 | 
							StringBuilder builder = new StringBuilder();
 | 
				
			||||||
        builder.append(String.format("/%s check - Check to update\n", NAME));
 | 
							builder.append(String.format("/%s check - Check to update\n", NAME));
 | 
				
			||||||
        builder.append(String.format("/%s update [version] - Update to specified or latest version\n", NAME));
 | 
							builder.append(String.format("/%s update [version] - Update to specified or latest version\n", NAME));
 | 
				
			||||||
        builder.append(String.format("/%s tps - Show tps statistics\n", NAME));
 | 
							builder.append(String.format("/%s tps - Show tps statistics\n", NAME));
 | 
				
			||||||
        builder.append(String.format("/%s restart - Restart server\n", NAME));
 | 
							builder.append(String.format("/%s restart - Restart server\n", NAME));
 | 
				
			||||||
        setUsage(builder.toString());
 | 
							builder.append(String.format("/%s dump - Dump statistics into kcauldron.dump file\n", NAME));
 | 
				
			||||||
 | 
							setUsage(builder.toString());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        setPermission("kcauldron");
 | 
							setPermission("kc");
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean testPermission(CommandSender target, String permission) {
 | 
						public boolean testPermission(CommandSender target, String permission) {
 | 
				
			||||||
        if (testPermissionSilent(target, permission)) {
 | 
							if (testPermissionSilent(target, permission)) {
 | 
				
			||||||
            return true;
 | 
								return true;
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        target.sendMessage(ChatColor.RED
 | 
							target.sendMessage(ChatColor.RED
 | 
				
			||||||
                + "I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error.");
 | 
									+ "I'm sorry, but you do not have permission to perform this command. Please contact the server administrators if you believe that this is in error.");
 | 
				
			||||||
        return false;
 | 
							return false;
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public boolean testPermissionSilent(CommandSender target, String permission) {
 | 
						public boolean testPermissionSilent(CommandSender target, String permission) {
 | 
				
			||||||
        if (!super.testPermissionSilent(target)) {
 | 
							if (!super.testPermissionSilent(target)) {
 | 
				
			||||||
            return false;
 | 
								return false;
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        for (String p : permission.split(";"))
 | 
							for (String p : permission.split(";"))
 | 
				
			||||||
            if (target.hasPermission(p))
 | 
								if (target.hasPermission(p))
 | 
				
			||||||
                return true;
 | 
									return true;
 | 
				
			||||||
        return false;
 | 
							return false;
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
						@Override
 | 
				
			||||||
    public boolean execute(CommandSender sender, String commandLabel, String[] args) {
 | 
						public boolean execute(CommandSender sender, String commandLabel, String[] args) {
 | 
				
			||||||
        if (!testPermission(sender))
 | 
							if (!testPermission(sender))
 | 
				
			||||||
            return true;
 | 
								return true;
 | 
				
			||||||
        if (args.length == 0) {
 | 
							if (args.length == 0) {
 | 
				
			||||||
            sender.sendMessage(ChatColor.YELLOW + "Please specify action");
 | 
								sender.sendMessage(ChatColor.YELLOW + "Please specify action");
 | 
				
			||||||
            sender.sendMessage(ChatColor.AQUA + usageMessage);
 | 
								sender.sendMessage(ChatColor.AQUA + usageMessage);
 | 
				
			||||||
            return true;
 | 
								return true;
 | 
				
			||||||
        }
 | 
							}
 | 
				
			||||||
        String action = args[0];
 | 
							String action = args[0];
 | 
				
			||||||
        if ("check".equals(action)) {
 | 
							if ("check".equals(action)) {
 | 
				
			||||||
            if (!testPermission(sender, CHECK))
 | 
								if (!testPermission(sender, CHECK))
 | 
				
			||||||
                return true;
 | 
									return true;
 | 
				
			||||||
            sender.sendMessage(ChatColor.GREEN + "Initiated version check...");
 | 
								sender.sendMessage(ChatColor.GREEN + "Initiated version check...");
 | 
				
			||||||
            KVersionRetriever.startServer(new CommandSenderUpdateCallback(sender), false);
 | 
								KVersionRetriever.startServer(new CommandSenderUpdateCallback(sender), false);
 | 
				
			||||||
        } else if ("update".equals(action)) {
 | 
							} else if ("update".equals(action)) {
 | 
				
			||||||
            KCauldronUpdater.initUpdate(sender, args.length > 1 ? args[1] : null);
 | 
								KCauldronUpdater.initUpdate(sender, args.length > 1 ? args[1] : null);
 | 
				
			||||||
        } else if ("tps".equals(action)) {
 | 
							} else if ("tps".equals(action)) {
 | 
				
			||||||
            if (!testPermission(sender, TPS))
 | 
								if (!testPermission(sender, TPS))
 | 
				
			||||||
                return true;
 | 
									return true;
 | 
				
			||||||
            World currentWorld = null;
 | 
								World currentWorld = null;
 | 
				
			||||||
            if (sender instanceof CraftPlayer) {
 | 
								if (sender instanceof CraftPlayer) {
 | 
				
			||||||
                currentWorld = ((CraftPlayer) sender).getWorld();
 | 
									currentWorld = ((CraftPlayer) sender).getWorld();
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
            sender.sendMessage(ChatColor.DARK_BLUE + "---------------------------------------");
 | 
								sender.sendMessage(ChatColor.DARK_BLUE + "---------------------------------------");
 | 
				
			||||||
            final MinecraftServer server = MinecraftServer.getServer();
 | 
								final MinecraftServer server = MinecraftServer.getServer();
 | 
				
			||||||
            for (World world : server.server.getWorlds()) {
 | 
								for (World world : server.server.getWorlds()) {
 | 
				
			||||||
                if (world instanceof CraftWorld) {
 | 
									if (world instanceof CraftWorld) {
 | 
				
			||||||
                    boolean current = currentWorld != null && currentWorld == world;
 | 
										boolean current = currentWorld != null && currentWorld == world;
 | 
				
			||||||
                    net.minecraft.world.World mcWorld = ((CraftWorld) world).getHandle();
 | 
										net.minecraft.world.World mcWorld = ((CraftWorld) world).getHandle();
 | 
				
			||||||
                    String bukkitName = world.getName();
 | 
										String bukkitName = world.getName();
 | 
				
			||||||
                    int dimensionId = mcWorld.provider.dimensionId;
 | 
										int dimensionId = mcWorld.provider.dimensionId;
 | 
				
			||||||
                    String name = mcWorld.provider.getDimensionName();
 | 
										String name = mcWorld.provider.getDimensionName();
 | 
				
			||||||
                    String displayName = name.equals(bukkitName) ? name : String.format("%s | %s", name, bukkitName);
 | 
										String displayName = name.equals(bukkitName) ? name : String.format("%s | %s", name, bukkitName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    double worldTickTime = mean(server.worldTickTimes.get(dimensionId)) * 1.0E-6D;
 | 
										double worldTickTime = mean(server.worldTickTimes.get(dimensionId)) * 1.0E-6D;
 | 
				
			||||||
                    double worldTPS = Math.min(1000.0 / worldTickTime, 20);
 | 
										double worldTPS = Math.min(1000.0 / worldTickTime, 20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    sender.sendMessage(String.format("%s[%d] %s%s %s- %s%.2fms / %.2ftps", ChatColor.GOLD, dimensionId,
 | 
										sender.sendMessage(String.format("%s[%d] %s%s %s- %s%.2fms / %.2ftps", ChatColor.GOLD, dimensionId,
 | 
				
			||||||
                            current ? ChatColor.GREEN : ChatColor.YELLOW, displayName, ChatColor.RESET, ChatColor.DARK_RED, worldTickTime,
 | 
												current ? ChatColor.GREEN : ChatColor.YELLOW, displayName, ChatColor.RESET,
 | 
				
			||||||
                            worldTPS));
 | 
												ChatColor.DARK_RED, worldTickTime, worldTPS));
 | 
				
			||||||
                }
 | 
									}
 | 
				
			||||||
            }
 | 
								}
 | 
				
			||||||
            double meanTickTime = mean(server.tickTimeArray) * 1.0E-6D;
 | 
								double meanTickTime = mean(server.tickTimeArray) * 1.0E-6D;
 | 
				
			||||||
            double meanTPS = Math.min(1000.0 / meanTickTime, 20);
 | 
								double meanTPS = Math.min(1000.0 / meanTickTime, 20);
 | 
				
			||||||
            sender.sendMessage(String.format("%sOverall - %s%s%.2fms / %.2ftps", ChatColor.BLUE, ChatColor.RESET,
 | 
								sender.sendMessage(String.format("%sOverall - %s%s%.2fms / %.2ftps", ChatColor.BLUE, ChatColor.RESET,
 | 
				
			||||||
                    ChatColor.DARK_RED, meanTickTime, meanTPS));
 | 
										ChatColor.DARK_RED, meanTickTime, meanTPS));
 | 
				
			||||||
        } else if ("restart".equals(action)) {
 | 
							} else if ("restart".equals(action)) {
 | 
				
			||||||
            if (!testPermission(sender, RESTART))
 | 
								if (!testPermission(sender, RESTART))
 | 
				
			||||||
                return true;
 | 
									return true;
 | 
				
			||||||
            KCauldron.restart();
 | 
								KCauldron.restart();
 | 
				
			||||||
        } else {
 | 
							} else if ("dump".equals(action)) {
 | 
				
			||||||
            sender.sendMessage(ChatColor.RED + "Unknown action");
 | 
								if (!testPermission(sender, DUMP))
 | 
				
			||||||
        }
 | 
									return true;
 | 
				
			||||||
        return true;
 | 
								try {
 | 
				
			||||||
    }
 | 
									File outputFile = new File("kcauldron.dump");
 | 
				
			||||||
 | 
									OutputStream os = new FileOutputStream(outputFile);
 | 
				
			||||||
 | 
									Writer writer = new OutputStreamWriter(os);
 | 
				
			||||||
 | 
									for (WorldServer world : DimensionManager.getWorlds()) {
 | 
				
			||||||
 | 
										writer.write(String.format("Stats for %s [%s] with id %d\n", world,
 | 
				
			||||||
 | 
												world.provider.getDimensionName(), world.dimension));
 | 
				
			||||||
 | 
										writer.write("Current tick: " + world.worldInfo.getWorldTotalTime() + "\n");
 | 
				
			||||||
 | 
										writer.write("\nEntities: ");
 | 
				
			||||||
 | 
										writer.write("count - " + world.loadedEntityList_KC.size() + "\n");
 | 
				
			||||||
 | 
										for (Entity entity : world.loadedEntityList_KC) {
 | 
				
			||||||
 | 
											writer.write(String.format("  %s at (%.4f;%.4f;%.4f)\n", entity.getClass().getName(),
 | 
				
			||||||
 | 
													entity.posX, entity.posY, entity.posZ));
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										writer.write("\nTileEntities: ");
 | 
				
			||||||
 | 
										writer.write("count - " + world.loadedTileEntityList_KC.size() + "\n");
 | 
				
			||||||
 | 
										for (TileEntity entity : world.loadedTileEntityList_KC) {
 | 
				
			||||||
 | 
											writer.write(String.format("  %s at (%d;%d;%d)\n", entity.getClass().getName(), entity.xCoord,
 | 
				
			||||||
 | 
													entity.yCoord, entity.zCoord));
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										writer.write("\nLoaded chunks: ");
 | 
				
			||||||
 | 
										writer.write("count - " + world.activeChunkSet_CB.size() + "\n");
 | 
				
			||||||
 | 
										for (long chunkKey : world.activeChunkSet_CB.keys()) {
 | 
				
			||||||
 | 
											final int x = WorldServer.keyToX(chunkKey);
 | 
				
			||||||
 | 
											final int z = WorldServer.keyToZ(chunkKey);
 | 
				
			||||||
 | 
											Chunk chunk = world.chunkProvider.provideChunk(x, z);
 | 
				
			||||||
 | 
											if (chunk == null)
 | 
				
			||||||
 | 
												continue;
 | 
				
			||||||
 | 
											writer.write(String.format("Chunk at (%d;%d)\n", x, z));
 | 
				
			||||||
 | 
											@SuppressWarnings("unchecked")
 | 
				
			||||||
 | 
											List<NextTickListEntry> updates = world.getPendingBlockUpdates(chunk, false);
 | 
				
			||||||
 | 
											writer.write("Pending block updates [" + updates.size() + "]:\n");
 | 
				
			||||||
 | 
											for (NextTickListEntry entry : updates) {
 | 
				
			||||||
 | 
												writer.write(String.format("(%d;%d;%d) at %d with priority %d\n", entry.xCoord,
 | 
				
			||||||
 | 
														entry.yCoord, entry.zCoord, entry.scheduledTime, entry.priority));
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										writer.write("-------------------------\n");
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									writer.close();
 | 
				
			||||||
 | 
									sender.sendMessage(ChatColor.RED + "Dump saved!");
 | 
				
			||||||
 | 
								} catch (Exception e) {
 | 
				
			||||||
 | 
									e.printStackTrace();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								sender.sendMessage(ChatColor.RED + "Unknown action");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static final long mean(long[] array) {
 | 
						private static final long mean(long[] array) {
 | 
				
			||||||
        long r = 0;
 | 
							long r = 0;
 | 
				
			||||||
        for (long i : array)
 | 
							for (long i : array)
 | 
				
			||||||
            r += i;
 | 
								r += i;
 | 
				
			||||||
        return r / array.length;
 | 
							return r / array.length;
 | 
				
			||||||
    }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user