Add some starting work for a forge tps command. Also update coremod for new FML behaviour
This commit is contained in:
parent
0c06d3b47a
commit
dddb9b3189
6 changed files with 299 additions and 0 deletions
5
common/assets/forge/lang/en_US.lang
Normal file
5
common/assets/forge/lang/en_US.lang
Normal file
|
@ -0,0 +1,5 @@
|
|||
commands.forge.usage=Use /forge <subcommand>. Subcommands are tps, track
|
||||
commands.forge.usage.tracking=Use /forge track <type> <duration>. Valid types are te (Tile Entities). Duration is < 60.
|
||||
commands.forge.tps.summary=%s : Mean tick time: %d ms. Mean TPS: %d
|
||||
|
||||
commands.forge.tracking.te.enabled=Tile Entity tracking enabled for %d seconds.
|
|
@ -1,5 +1,6 @@
|
|||
package net.minecraftforge.classloading;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
|
||||
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
||||
|
@ -7,6 +8,7 @@ import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
|
|||
public class FMLForgePlugin implements IFMLLoadingPlugin
|
||||
{
|
||||
public static boolean RUNTIME_DEOBF = false;
|
||||
public static File forgeLocation;
|
||||
|
||||
@Override
|
||||
public String[] getLibraryRequestClass()
|
||||
|
@ -39,5 +41,6 @@ public class FMLForgePlugin implements IFMLLoadingPlugin
|
|||
public void injectData(Map<String, Object> data)
|
||||
{
|
||||
RUNTIME_DEOBF = (Boolean)data.get("runtimeDeobfuscationEnabled");
|
||||
forgeLocation = (File)data.get("coremodLocation");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,10 @@ import com.google.common.collect.BiMap;
|
|||
import com.google.common.collect.ForwardingSet;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableMultiset;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.common.collect.LinkedHashMultimap;
|
||||
|
@ -34,6 +36,7 @@ import com.google.common.collect.Maps;
|
|||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
import com.google.common.collect.Multiset;
|
||||
import com.google.common.collect.Multisets;
|
||||
import com.google.common.collect.SetMultimap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.collect.TreeMultiset;
|
||||
|
|
|
@ -10,14 +10,18 @@ import net.minecraft.nbt.NBTTagCompound;
|
|||
import net.minecraft.server.management.PlayerInstance;
|
||||
import net.minecraft.world.storage.SaveHandler;
|
||||
import net.minecraft.world.storage.WorldInfo;
|
||||
import net.minecraftforge.classloading.FMLForgePlugin;
|
||||
import net.minecraftforge.common.network.ForgeConnectionHandler;
|
||||
import net.minecraftforge.common.network.ForgeNetworkHandler;
|
||||
import net.minecraftforge.common.network.ForgePacketHandler;
|
||||
import net.minecraftforge.common.network.ForgeTinyPacketHandler;
|
||||
import net.minecraftforge.server.command.ForgeCommand;
|
||||
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import cpw.mods.fml.client.FMLFileResourcePack;
|
||||
import cpw.mods.fml.client.FMLFolderResourcePack;
|
||||
import cpw.mods.fml.common.DummyModContainer;
|
||||
import cpw.mods.fml.common.FMLLog;
|
||||
import cpw.mods.fml.common.LoadController;
|
||||
|
@ -27,6 +31,7 @@ import cpw.mods.fml.common.WorldAccessContainer;
|
|||
import cpw.mods.fml.common.event.FMLConstructionEvent;
|
||||
import cpw.mods.fml.common.event.FMLPostInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLPreInitializationEvent;
|
||||
import cpw.mods.fml.common.event.FMLServerStartingEvent;
|
||||
import cpw.mods.fml.common.network.FMLNetworkHandler;
|
||||
import cpw.mods.fml.common.network.NetworkMod;
|
||||
|
||||
|
@ -174,6 +179,11 @@ public class ForgeDummyContainer extends DummyModContainer implements WorldAcces
|
|||
ForgeChunkManager.loadConfiguration();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void serverStarting(FMLServerStartingEvent evt)
|
||||
{
|
||||
evt.registerServerCommand(new ForgeCommand(evt.getServer()));
|
||||
}
|
||||
@Override
|
||||
public NBTTagCompound getDataForWriting(SaveHandler handler, WorldInfo info)
|
||||
{
|
||||
|
@ -191,4 +201,22 @@ public class ForgeDummyContainer extends DummyModContainer implements WorldAcces
|
|||
DimensionManager.loadDimensionDataMap(tag.hasKey("DimensionData") ? tag.getCompoundTag("DimensionData") : null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getSource()
|
||||
{
|
||||
return FMLForgePlugin.forgeLocation;
|
||||
}
|
||||
@Override
|
||||
public Class<?> getCustomResourcePackClass()
|
||||
{
|
||||
if (getSource().isDirectory())
|
||||
{
|
||||
return FMLFolderResourcePack.class;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FMLFileResourcePack.class;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
113
common/net/minecraftforge/server/ForgeTimeTracker.java
Normal file
113
common/net/minecraftforge/server/ForgeTimeTracker.java
Normal file
|
@ -0,0 +1,113 @@
|
|||
package net.minecraftforge.server;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
import com.google.common.collect.MapMaker;
|
||||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
||||
public class ForgeTimeTracker {
|
||||
public static boolean tileEntityTracking;
|
||||
public static int tileEntityTrackingDuration;
|
||||
public static long tileEntityTrackingTime;
|
||||
|
||||
private Map<TileEntity,int[]> tileEntityTimings;
|
||||
private Map<Entity,int[]> entityTimings;
|
||||
|
||||
private static final ForgeTimeTracker INSTANCE = new ForgeTimeTracker();
|
||||
|
||||
private WeakReference<TileEntity> tile;
|
||||
private WeakReference<Entity> entity;
|
||||
|
||||
private long timing;
|
||||
|
||||
private ForgeTimeTracker()
|
||||
{
|
||||
MapMaker mm = new MapMaker();
|
||||
mm.weakKeys();
|
||||
tileEntityTimings = mm.makeMap();
|
||||
entityTimings = mm.makeMap();
|
||||
}
|
||||
|
||||
|
||||
private void trackTileStart(TileEntity tileEntity, long nanoTime)
|
||||
{
|
||||
if (tileEntityTrackingTime == 0)
|
||||
{
|
||||
tileEntityTrackingTime = nanoTime;
|
||||
}
|
||||
else if (tileEntityTrackingTime + tileEntityTrackingDuration < nanoTime)
|
||||
{
|
||||
tileEntityTracking = false;
|
||||
tileEntityTrackingTime = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
tile = new WeakReference<TileEntity>(tileEntity);
|
||||
timing = nanoTime;
|
||||
}
|
||||
|
||||
|
||||
private void trackTileEnd(TileEntity tileEntity, long nanoTime)
|
||||
{
|
||||
if (tile == null || tile.get() != tileEntity)
|
||||
{
|
||||
tile = null;
|
||||
// race, exit
|
||||
return;
|
||||
}
|
||||
int[] timings = tileEntityTimings.get(tileEntity);
|
||||
if (timings == null)
|
||||
{
|
||||
timings = new int[101];
|
||||
tileEntityTimings.put(tileEntity, timings);
|
||||
}
|
||||
int idx = timings[100] = (timings[100] + 1) % 100;
|
||||
timings[idx] = (int) (nanoTime - timing);
|
||||
}
|
||||
|
||||
public static ImmutableMap<TileEntity,int[]> getTileTimings()
|
||||
{
|
||||
return INSTANCE.buildImmutableTileEntityTimingMap();
|
||||
}
|
||||
|
||||
private ImmutableMap<TileEntity, int[]> buildImmutableTileEntityTimingMap()
|
||||
{
|
||||
Builder<TileEntity, int[]> builder = ImmutableMap.<TileEntity,int[]>builder();
|
||||
for (Entry<TileEntity, int[]> entry : tileEntityTimings.entrySet())
|
||||
{
|
||||
builder.put(entry.getKey(), Arrays.copyOfRange(entry.getValue(), 0, 100));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
public static void trackStart(TileEntity tileEntity)
|
||||
{
|
||||
if (!tileEntityTracking) return;
|
||||
INSTANCE.trackTileStart(tileEntity, System.nanoTime());
|
||||
}
|
||||
|
||||
public static void trackEnd(TileEntity tileEntity)
|
||||
{
|
||||
if (!tileEntityTracking) return;
|
||||
INSTANCE.trackTileEnd(tileEntity, System.nanoTime());
|
||||
}
|
||||
|
||||
public static void trackStart(Entity par1Entity)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static void trackEnd(Entity par1Entity)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
147
common/net/minecraftforge/server/command/ForgeCommand.java
Normal file
147
common/net/minecraftforge/server/command/ForgeCommand.java
Normal file
|
@ -0,0 +1,147 @@
|
|||
package net.minecraftforge.server.command;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.Multiset;
|
||||
|
||||
import net.minecraft.command.CommandBase;
|
||||
import net.minecraft.command.ICommand;
|
||||
import net.minecraft.command.ICommandSender;
|
||||
import net.minecraft.command.WrongUsageException;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.ChatMessageComponent;
|
||||
import net.minecraft.world.ChunkCoordIntPair;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraftforge.common.DimensionManager;
|
||||
import net.minecraftforge.common.ForgeChunkManager;
|
||||
import net.minecraftforge.server.ForgeTimeTracker;
|
||||
|
||||
public class ForgeCommand extends CommandBase {
|
||||
|
||||
private MinecraftServer server;
|
||||
|
||||
public ForgeCommand(MinecraftServer server)
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
private static final DecimalFormat timeFormatter = new DecimalFormat("########0.000");
|
||||
|
||||
@Override
|
||||
public String getCommandName()
|
||||
{
|
||||
return "forge";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandUsage(ICommandSender icommandsender)
|
||||
{
|
||||
return "commands.forge.usage";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRequiredPermissionLevel()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
@Override
|
||||
public void processCommand(ICommandSender sender, String[] args)
|
||||
{
|
||||
if (args.length == 0)
|
||||
{
|
||||
throw new WrongUsageException("commands.forge.usage");
|
||||
}
|
||||
else if ("help".equals(args[0]))
|
||||
{
|
||||
throw new WrongUsageException("commands.forge.usage");
|
||||
}
|
||||
else if ("tps".equals(args[0]))
|
||||
{
|
||||
displayTPS(sender,args);
|
||||
}
|
||||
else if ("tpslog".equals(args[0]))
|
||||
{
|
||||
doTPSLog(sender,args);
|
||||
}
|
||||
else if ("track".equals(args[0]))
|
||||
{
|
||||
handleTracking(sender, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new WrongUsageException("commands.forge.usage");
|
||||
}
|
||||
}
|
||||
|
||||
private void handleTracking(ICommandSender sender, String[] args)
|
||||
{
|
||||
if (args.length != 3)
|
||||
{
|
||||
throw new WrongUsageException("commands.forge.usage.tracking");
|
||||
}
|
||||
String type = args[1];
|
||||
int duration = parseIntBounded(sender, args[2], 1, 60);
|
||||
|
||||
if ("te".equals(type))
|
||||
{
|
||||
doTurnOnTileEntityTracking(sender, duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new WrongUsageException("commands.forge.usage.tracking");
|
||||
}
|
||||
}
|
||||
|
||||
private void doTurnOnTileEntityTracking(ICommandSender sender, int duration)
|
||||
{
|
||||
ForgeTimeTracker.tileEntityTrackingDuration = duration;
|
||||
ForgeTimeTracker.tileEntityTracking = true;
|
||||
sender.sendChatToPlayer(ChatMessageComponent.func_111082_b("commands.forge.tracking.te.enabled", duration));
|
||||
}
|
||||
|
||||
private void doTPSLog(ICommandSender sender, String[] args)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void displayTPS(ICommandSender sender, String[] args)
|
||||
{
|
||||
int dim = 0;
|
||||
boolean summary = true;
|
||||
if (args.length > 1)
|
||||
{
|
||||
dim = parseInt(sender, args[1]);
|
||||
summary = false;
|
||||
}
|
||||
if (summary)
|
||||
{
|
||||
for (Integer dimId : DimensionManager.getIDs())
|
||||
{
|
||||
double worldTickTime = ForgeCommand.mean(this.server.worldTickTimes.get(dimId)) * 1.0E-6D;
|
||||
double worldTPS = Math.min(1000.0/worldTickTime, 20);
|
||||
sender.sendChatToPlayer(ChatMessageComponent.func_111082_b("commands.forge.tps.summary",String.format("Dim %d", dimId), timeFormatter.format(worldTickTime), timeFormatter.format(worldTPS)));
|
||||
}
|
||||
double meanTickTime = ForgeCommand.mean(this.server.tickTimeArray) * 1.0E-6D;
|
||||
double meanTPS = Math.min(1000.0/meanTickTime, 20);
|
||||
sender.sendChatToPlayer(ChatMessageComponent.func_111082_b("commands.forge.tps.summary","Overall", timeFormatter.format(meanTickTime), timeFormatter.format(meanTPS)));
|
||||
}
|
||||
else
|
||||
{
|
||||
double worldTickTime = ForgeCommand.mean(this.server.worldTickTimes.get(dim)) * 1.0E-6D;
|
||||
double worldTPS = Math.min(1000.0/worldTickTime, 20);
|
||||
sender.sendChatToPlayer(ChatMessageComponent.func_111082_b("commands.forge.tps.summary",String.format("Dim %d", dim), timeFormatter.format(worldTickTime), timeFormatter.format(worldTPS)));
|
||||
}
|
||||
}
|
||||
|
||||
private static long mean(long[] values)
|
||||
{
|
||||
long sum = 0l;
|
||||
for (long v : values)
|
||||
{
|
||||
sum+=v;
|
||||
}
|
||||
|
||||
return sum / values.length;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue