megabroke

This commit is contained in:
gnembon committed 2019-05-11 05:01:26 -03:00
1 parent ec66779474
commit a28f7be625
20 files changed
+2242 -3

No files matched your search

+2 -2
View File
@@ -7,10 +7,10 @@ import carpet.commands.CameraModeCommand;
import carpet.commands.DrawCommand;
//import carpet.commands.ScriptCommand;
//import carpet.commands.InfoCommand;
//import carpet.commands.LogCommand;
//import carpet.commands.PerimeterInfoCommand;
//import carpet.commands.PlayerCommand;
//import carpet.commands.SpawnCommand;
import carpet.commands.LogCommand;
import carpet.commands.TestCommand;
//import carpet.commands.TickCommand;
//import carpet.logging.LoggerRegistry;
@@ -53,7 +53,7 @@ public class CarpetServer // static for now - easier to handle all around the co
//CarpetCommand.register(dispatcher);
//TickCommand.register(dispatcher);
//CounterCommand.register(dispatcher);
//LogCommand.register(dispatcher);
LogCommand.register(dispatcher);
//SpawnCommand.register(dispatcher);
//PlayerCommand.register(dispatcher);
CameraModeCommand.register(dispatcher);
@@ -0,0 +1,214 @@
package carpet.commands;
import carpet.CarpetSettings;
import carpet.logging.Logger;
import carpet.logging.LoggerRegistry;
import carpet.utils.Messenger;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.command.CommandManager;
import net.minecraft.entity.player.PlayerEntity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.mojang.brigadier.arguments.StringArgumentType.getString;
import static net.minecraft.server.command.CommandSource.suggestMatching;
public class LogCommand
{
public static void register(CommandDispatcher<ServerCommandSource> dispatcher)
{
LiteralArgumentBuilder<ServerCommandSource> literalargumentbuilder = CommandManager.literal("log").
requires((player) -> CarpetSettings.getBool("commandLog")).
executes((context) -> listLogs(context.getSource())).
then(CommandManager.literal("clear").
executes( (c) -> unsubFromAll(c.getSource(), c.getSource().getName())).
then(CommandManager.argument("player", StringArgumentType.word()).
suggests( (c, b)-> suggestMatching(c.getSource().getPlayerNames(),b)).
executes( (c) -> unsubFromAll(c.getSource(), getString(c, "player")))));
literalargumentbuilder.then(CommandManager.argument("log name",StringArgumentType.word()).
suggests( (c, b)-> suggestMatching(LoggerRegistry.getLoggerNames(),b)).
executes( (c)-> toggleSubscription(c.getSource(), c.getSource().getName(), getString(c, "log name"))).
then(CommandManager.literal("clear").
executes( (c) -> unsubFromLogger(
c.getSource(),
c.getSource().getName(),
getString(c, "log name")))).
then(CommandManager.argument("option", StringArgumentType.word()).
suggests( (c, b) -> suggestMatching(
(LoggerRegistry.getLogger(getString(c, "log name"))==null
?new String[]{}
:LoggerRegistry.getLogger(getString(c, "log name")).getOptions()),
b)).
executes( (c) -> subscribePlayer(
c.getSource(),
c.getSource().getName(),
getString(c, "log name"),
getString(c, "option"))).
then(CommandManager.argument("player", StringArgumentType.word()).
suggests( (c, b) -> suggestMatching(c.getSource().getPlayerNames(),b)).
executes( (c) -> subscribePlayer(
c.getSource(),
getString(c, "player"),
getString(c, "log name"),
getString(c, "option"))))));
dispatcher.register(literalargumentbuilder);
}
private static int listLogs(ServerCommandSource source)
{
PlayerEntity player;
try
{
player = source.getPlayer();
}
catch (CommandSyntaxException e)
{
Messenger.m(source, "For players only");
return 0;
}
Map<String,String> subs = LoggerRegistry.getPlayerSubscriptions(source.getName());
if (subs == null)
{
subs = new HashMap<>();
}
List<String> all_logs = new ArrayList<>(LoggerRegistry.getLoggerNames());
Collections.sort(all_logs);
Messenger.m(player, "w _____________________");
Messenger.m(player, "w Available logging options:");
for (String lname: all_logs)
{
List<Object> comp = new ArrayList<>();
String color = subs.containsKey(lname)?"w":"g";
comp.add("w - "+lname+": ");
Logger logger = LoggerRegistry.getLogger(lname);
String [] options = logger.getOptions();
if (options.length == 0)
{
if (subs.containsKey(lname))
{
comp.add("l Subscribed ");
}
else
{
comp.add(color + " [Subscribe] ");
comp.add("^w subscribe to " + lname);
comp.add("!/log " + lname);
}
}
else
{
for (String option : logger.getOptions())
{
if (subs.containsKey(lname) && subs.get(lname).equalsIgnoreCase(option))
{
comp.add("l [" + option + "] ");
} else
{
comp.add(color + " [" + option + "] ");
comp.add("^w subscribe to " + lname + " " + option);
comp.add("!/log " + lname + " " + option);
}
}
}
if (subs.containsKey(lname))
{
comp.add("nb [X]");
comp.add("^w Click to unsubscribe");
comp.add("!/log "+lname);
}
Messenger.m(player,comp.toArray(new Object[0]));
}
return 1;
}
private static int unsubFromAll(ServerCommandSource source, String player_name)
{
PlayerEntity player = source.getMinecraftServer().getPlayerManager().getPlayer(player_name);
if (player == null)
{
Messenger.m(source, "r No player specified");
return 0;
}
for (String logname : LoggerRegistry.getLoggerNames())
{
LoggerRegistry.unsubscribePlayer(player_name, logname);
}
Messenger.m(source, "gi Unsubscribed from all logs");
return 1;
}
private static int unsubFromLogger(ServerCommandSource source, String player_name, String logname)
{
PlayerEntity player = source.getMinecraftServer().getPlayerManager().getPlayer(player_name);
if (player == null)
{
Messenger.m(source, "r No player specified");
return 0;
}
if (LoggerRegistry.getLogger(logname) == null)
{
Messenger.m(source, "r Unknown logger: ","rb "+logname);
return 0;
}
LoggerRegistry.unsubscribePlayer(player_name, logname);
Messenger.m(source, "gi Unsubscribed from "+logname);
return 1;
}
private static int toggleSubscription(ServerCommandSource source, String player_name, String logName)
{
PlayerEntity player = source.getMinecraftServer().getPlayerManager().getPlayer(player_name);
if (player == null)
{
Messenger.m(source, "r No player specified");
return 0;
}
if (LoggerRegistry.getLogger(logName) == null)
{
Messenger.m(source, "r Unknown logger: ","rb "+logName);
return 0;
}
boolean subscribed = LoggerRegistry.togglePlayerSubscription(player_name, logName);
if (subscribed)
{
Messenger.m(source, "gi "+player_name+" subscribed to " + logName + ".");
}
else
{
Messenger.m(source, "gi "+player_name+" unsubscribed from " + logName + ".");
}
return 1;
}
private static int subscribePlayer(ServerCommandSource source, String player_name, String logname, String option)
{
PlayerEntity player = source.getMinecraftServer().getPlayerManager().getPlayer(player_name);
if (player == null)
{
Messenger.m(source, "r No player specified");
return 0;
}
if (LoggerRegistry.getLogger(logname) == null)
{
Messenger.m(source, "r Unknown logger: ","rb "+logname);
return 0;
}
LoggerRegistry.subscribePlayer(player_name, logname, option);
if (option!=null)
{
Messenger.m(source, "gi Subscribed to " + logname + "(" + option + ")");
}
else
{
Messenger.m(source, "gi Subscribed to " + logname);
}
return 1;
}
}
@@ -0,0 +1,156 @@
package carpet.helpers;
import carpet.utils.Messenger;
import com.google.common.collect.Maps;
import it.unimi.dsi.fastutil.objects.Object2LongLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import net.minecraft.util.DyeColor;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.network.chat.BaseComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.server.MinecraftServer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
public class HopperCounter
{
public static final Map<DyeColor, HopperCounter> COUNTERS;
static
{
EnumMap<DyeColor, HopperCounter> counterMap = new EnumMap<>(DyeColor.class);
for (DyeColor color : DyeColor.values())
{
counterMap.put(color, new HopperCounter(color));
}
COUNTERS = Maps.immutableEnumMap(counterMap);
}
public final DyeColor color;
private final Object2LongMap<Item> counter = new Object2LongLinkedOpenHashMap<>();
private long startTick;
private long startMillis;
// private PubSubInfoProvider<Long> pubSubProvider;
private HopperCounter(DyeColor color)
{
this.color = color;
// pubSubProvider = new PubSubInfoProvider<>(QuickCarpet.PUBSUB, "carpet.counter." + color.getName(), 0, this::getTotalItems);
}
public void add(MinecraftServer server, ItemStack stack)
{
if (startTick == 0)
{
startTick = server.getTicks();
startMillis = System.currentTimeMillis();
}
Item item = stack.getItem();
counter.put(item, counter.getLong(item) + stack.getAmount());
// pubSubProvider.publish();
}
public void reset(MinecraftServer server)
{
counter.clear();
startTick = server.getTicks();
startMillis = System.currentTimeMillis();
// pubSubProvider.publish();
}
public static void resetAll(MinecraftServer server)
{
for (HopperCounter counter : COUNTERS.values())
{
counter.reset(server);
}
}
public static List<BaseComponent> formatAll(MinecraftServer server, boolean realtime)
{
List<BaseComponent> text = new ArrayList<>();
for (HopperCounter counter : COUNTERS.values())
{
List<BaseComponent> temp = counter.format(server, realtime, false);
if (temp.size() > 1)
{
if (!text.isEmpty()) text.add(Messenger.s(""));
text.addAll(temp);
}
}
if (text.isEmpty())
{
text.add(Messenger.s("No items have been counted yet."));
}
return text;
}
public List<BaseComponent> format(MinecraftServer server, boolean realTime, boolean brief)
{
if (counter.isEmpty())
{
if (brief)
{
return Collections.singletonList(Messenger.c("g "+color+": -, -/h, - min "));
}
return Collections.singletonList(Messenger.s(String.format("No items for %s yet", color.getName())));
}
long total = getTotalItems();
long ticks = Math.max(realTime ? (System.currentTimeMillis() - startMillis) / 50 : server.getTicks() - startTick, 1);
if (total == 0)
{
if (brief)
{
return Collections.singletonList(Messenger.c(String.format("c %s: 0, 0/h, %.1f min ", color, ticks / (20.0 * 60.0))));
}
return Collections.singletonList(Messenger.c(String.format("w No items for %s yet (%.2f min.%s)",
color.getName(), ticks / (20.0 * 60.0), (realTime ? " - real time" : "")),
"nb [X]", "^g reset", "!/counter " + color.getName() +" reset"));
}
if (brief)
{
return Collections.singletonList(Messenger.c(String.format("c %s: %d, %d/h, %.1f min ",
color.getName(), total, total * (20 * 60 * 60) / ticks, ticks / (20.0 * 60.0))));
}
List<BaseComponent> items = new ArrayList<>();
items.add(Messenger.c(String.format("w Items for %s (%.2f min.%s), total: %d, (%.1f/h):",
color, ticks*1.0/(20*60), (realTime?" - real time":""), total, total*1.0*(20*60*60)/ticks),
"nb [X]", "^g reset", "!/counter "+color+" reset"
));
items.addAll(counter.object2LongEntrySet().stream().map(e ->
{
BaseComponent itemName = new TranslatableComponent(e.getKey().getTranslationKey());
long count = e.getLongValue();
return Messenger.c("w - ", itemName, String.format("w : %d, %.1f/h",
count,
count * (20.0 * 60.0 * 60.0) / ticks));
}).collect(Collectors.toList()));
return items;
}
public static HopperCounter getCounter(String color)
{
try
{
DyeColor colorEnum = DyeColor.valueOf(color.toUpperCase(Locale.ROOT));
return COUNTERS.get(colorEnum);
}
catch (IllegalArgumentException e)
{
return null;
}
}
public long getTotalItems()
{
return counter.values().stream().mapToLong(Long::longValue).sum();
}
}
+169
View File
@@ -0,0 +1,169 @@
package carpet.helpers;
import carpet.CarpetServer;
import carpet.utils.Messenger;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.command.CommandManager;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.MinecraftServer;
import net.minecraft.network.chat.BaseComponent;
public class TickSpeed
{
public static final int PLAYER_GRACE = 2;
public static float tickrate = 20.0f;
public static long mspt = 50l;
public static long time_bias = 0;
public static long time_warp_start_time = 0;
public static long time_warp_scheduled_ticks = 0;
public static PlayerEntity time_advancerer = null;
public static String tick_warp_callback = null;
public static ServerCommandSource tick_warp_sender = null;
public static int player_active_timeout = 0;
public static boolean process_entities = true;
public static boolean is_paused = false;
public static boolean is_superHot = false;
public static void reset_player_active_timeout()
{
if (player_active_timeout < PLAYER_GRACE)
{
player_active_timeout = PLAYER_GRACE;
}
}
public static void add_ticks_to_run_in_pause(int ticks)
{
player_active_timeout = PLAYER_GRACE+ticks;
}
public static void tickrate(float rate)
{
tickrate = rate;
mspt = (long)(1000.0/tickrate);
if (mspt <=0)
{
mspt = 1l;
tickrate = 1000.0f;
}
}
public static BaseComponent tickrate_advance(PlayerEntity player, int advance, String callback, ServerCommandSource source)
{
if (0 == advance)
{
tick_warp_callback = null;
tick_warp_sender = null;
finish_time_warp();
return Messenger.c("gi Warp interrupted");
}
if (time_bias > 0)
{
return Messenger.c("l Another player is already advancing time at the moment. Try later or talk to them");
}
time_advancerer = player;
time_warp_start_time = System.nanoTime();
time_warp_scheduled_ticks = advance;
time_bias = advance;
tick_warp_callback = callback;
tick_warp_sender = source;
return Messenger.c("gi Warp speed ....");
}
public static void finish_time_warp()
{
long completed_ticks = time_warp_scheduled_ticks - time_bias;
double milis_to_complete = System.nanoTime()-time_warp_start_time;
if (milis_to_complete == 0.0)
{
milis_to_complete = 1.0;
}
milis_to_complete /= 1000000.0;
int tps = (int) (1000.0D*completed_ticks/milis_to_complete);
double mspt = (1.0*milis_to_complete)/completed_ticks;
time_warp_scheduled_ticks = 0;
time_warp_start_time = 0;
if (tick_warp_callback != null)
{
CommandManager icommandmanager = tick_warp_sender.getMinecraftServer().getCommandManager();
try
{
int j = icommandmanager.execute(tick_warp_sender, tick_warp_callback);
if (j < 1)
{
if (time_advancerer != null)
{
Messenger.m(time_advancerer, "r Command Callback failed: ", "rb /"+tick_warp_callback,"/"+tick_warp_callback);
}
}
}
catch (Throwable var23)
{
if (time_advancerer != null)
{
Messenger.m(time_advancerer, "r Command Callback failed - unknown error: ", "rb /"+tick_warp_callback,"/"+tick_warp_callback);
}
}
tick_warp_callback = null;
tick_warp_sender = null;
}
if (time_advancerer != null)
{
Messenger.m(time_advancerer, String.format("gi ... Time warp completed with %d tps, or %.2f mspt",tps, mspt ));
time_advancerer = null;
}
else
{
Messenger.print_server_message(CarpetServer.minecraft_server, String.format("... Time warp completed with %d tps, or %.2f mspt",tps, mspt ));
}
time_bias = 0;
}
public static boolean continueWarp()
{
if (time_bias > 0)
{
if (time_bias == time_warp_scheduled_ticks) //first call after previous tick, adjust start time
{
time_warp_start_time = System.nanoTime();
}
time_bias -= 1;
return true;
}
else
{
finish_time_warp();
return false;
}
}
public static void tick(MinecraftServer server)
{
process_entities = true;
if (player_active_timeout > 0)
{
player_active_timeout--;
}
if (is_paused)
{
if (player_active_timeout < PLAYER_GRACE)
{
process_entities = false;
}
}
else if (is_superHot)
{
if (player_active_timeout <= 0)
{
process_entities = false;
}
}
}
}
@@ -0,0 +1,29 @@
package carpet.logging;
import carpet.utils.HUDController;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.chat.BaseComponent;
public class HUDLogger extends Logger
{
public HUDLogger(String logName, String def, String[] options)
{
super(logName, def, options);
}
@Override
public void removePlayer(String playerName)
{
PlayerEntity player = playerFromName(playerName);
if (player != null) HUDController.clear_player(player);
super.removePlayer(playerName);
}
@Override
public void sendPlayerMessage(PlayerEntity player, BaseComponent... messages)
{
for (BaseComponent m:messages) HUDController.addMessage(player, m);
}
}
+193
View File
@@ -0,0 +1,193 @@
package carpet.logging;
import carpet.CarpetServer;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.chat.BaseComponent;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
public class Logger
{
// The set of subscribed and online players.
private Map<String, String> subscribedOnlinePlayers;
// The set of subscribed and offline players.
private Map<String,String> subscribedOfflinePlayers;
// The logName of this log. Gets prepended to logged messages.
private String logName;
private String default_option;
private String[] options;
public Logger(String logName, String def, String [] options)
{
subscribedOnlinePlayers = new HashMap<>();
subscribedOfflinePlayers = new HashMap<>();
this.logName = logName;
this.default_option = def;
this.options = options;
}
public String getDefault()
{
return default_option;
}
public String [] getOptions()
{
if (options == null)
{
return new String[0];
}
return options;
}
public String getLogName()
{
return logName;
}
/**
* Subscribes the player with the given logName to the logger.
*/
public void addPlayer(String playerName, String option)
{
if (playerFromName(playerName) != null)
{
subscribedOnlinePlayers.put(playerName, option);
}
else
{
subscribedOfflinePlayers.put(playerName, option);
}
LoggerRegistry.setAccess(this);
}
/**
* Unsubscribes the player with the given logName from the logger.
*/
public void removePlayer(String playerName)
{
subscribedOnlinePlayers.remove(playerName);
subscribedOfflinePlayers.remove(playerName);
LoggerRegistry.setAccess(this);
}
/**
* Returns true if there are any online subscribers for this log.
*/
public boolean hasOnlineSubscribers()
{
return subscribedOnlinePlayers.size() > 0;
}
/**
* serves messages to players fetching them from the promise
* will repeat invocation for players that share the same option
*/
@FunctionalInterface
public interface lMessage { BaseComponent [] get(String playerOption, PlayerEntity player);}
public void log(lMessage messagePromise)
{
for (Map.Entry<String,String> en : subscribedOnlinePlayers.entrySet())
{
PlayerEntity player = playerFromName(en.getKey());
if (player != null)
{
BaseComponent [] messages = messagePromise.get(en.getValue(),player);
if (messages != null)
sendPlayerMessage(player, messages);
}
}
}
/**
* guarantees that each message for each option will be evaluated once from the promise
* and served the same way to all other players subscribed to the same option
*/
@FunctionalInterface
public interface lMessageIgnorePlayer { BaseComponent [] get(String playerOption);}
public void log(lMessageIgnorePlayer messagePromise)
{
Map<String, BaseComponent[]> cannedMessages = new HashMap<>();
for (Map.Entry<String,String> en : subscribedOnlinePlayers.entrySet())
{
PlayerEntity player = playerFromName(en.getKey());
if (player != null)
{
String option = en.getValue();
if (!cannedMessages.containsKey(option))
{
cannedMessages.put(option,messagePromise.get(option));
}
BaseComponent [] messages = cannedMessages.get(option);
if (messages != null)
sendPlayerMessage(player, messages);
}
}
}
/**
* guarantees that message is evaluated once, so independent from the player and chosen option
*/
public void log(Supplier<BaseComponent[]> messagePromise)
{
BaseComponent [] cannedMessages = null;
for (Map.Entry<String,String> en : subscribedOnlinePlayers.entrySet())
{
PlayerEntity player = playerFromName(en.getKey());
if (player != null)
{
if (cannedMessages == null) cannedMessages = messagePromise.get();
sendPlayerMessage(player, cannedMessages);
}
}
}
public void sendPlayerMessage(PlayerEntity player, BaseComponent ... messages)
{
Arrays.stream(messages).forEach(player::sendMessage);
}
/**
* Gets the {@code PlayerEntity} instance for a player given their UUID. Returns null if they are offline.
*/
protected PlayerEntity playerFromName(String name)
{
return CarpetServer.minecraft_server.getPlayerManager().getPlayer(name);
}
// ----- Event Handlers ----- //
public void onPlayerConnect(PlayerEntity player)
{
// If the player was subscribed to the log and offline, move them to the set of online subscribers.
String playerName = player.getName().getString();
if (subscribedOfflinePlayers.containsKey(playerName))
{
subscribedOnlinePlayers.put(playerName, subscribedOfflinePlayers.get(playerName));
subscribedOfflinePlayers.remove(playerName);
}
LoggerRegistry.setAccess(this);
}
public void onPlayerDisconnect(PlayerEntity player)
{
// If the player was subscribed to the log, move them to the set of offline subscribers.
String playerName = player.getName().getString();
if (subscribedOnlinePlayers.containsKey(playerName))
{
subscribedOfflinePlayers.put(playerName, subscribedOnlinePlayers.get(playerName));
subscribedOnlinePlayers.remove(playerName);
}
LoggerRegistry.setAccess(this);
}
public String getAcceptedOption(String arg)
{
if (options != null && Arrays.asList(options).contains(arg)) return arg;
return null;
}
}
@@ -0,0 +1,157 @@
package carpet.logging;
import carpet.CarpetSettings;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumDyeColor;
import net.minecraft.server.MinecraftServer;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class LoggerRegistry
{
// Map from logger names to loggers.
private static Map<String, Logger> loggerRegistry = new HashMap<>();
// Map from player names to the set of names of the logs that player is subscribed to.
private static Map<String, Map<String, String>> playerSubscriptions = new HashMap<>();
//statics to quickly asses if its worth even to call each one
public static boolean __tnt;
public static boolean __projectiles;
public static boolean __fallingBlocks;
public static boolean __kills;
public static boolean __tps;
public static boolean __counter;
public static boolean __mobcaps;
public static boolean __damage;
public static boolean __packets;
public static boolean __weather;
public static void initLoggers()
{
registerLogger("tnt", new Logger("tnt", "brief", new String[]{"brief", "full"}));
registerLogger("projectiles", new Logger("projectiles", "brief", new String[]{"brief", "full"}));
registerLogger("fallingBlocks",new Logger("fallingBlocks", "brief", new String[]{"brief", "full"}));
registerLogger("kills", new Logger("kills", null, null));
registerLogger("damage", new Logger("damage", "all", new String[]{"all","players","me"}));
registerLogger("weather", new Logger("weather", null, null));
registerLogger("tps", new HUDLogger("tps", null, null));
registerLogger("packets", new HUDLogger("packets", null, null));
registerLogger("counter",new HUDLogger("counter","white", Arrays.stream(EnumDyeColor.values()).map(Object::toString).toArray(String[]::new)));
registerLogger("mobcaps", new HUDLogger("mobcaps", "dynamic",new String[]{"dynamic", "overworld", "nether","end"}));
}
/**
* Gets the logger with the given name. Returns null if no such logger exists.
*/
public static Logger getLogger(String name) { return loggerRegistry.get(name); }
/**
* Gets the set of logger names.
*/
public static Set<String> getLoggerNames() { return loggerRegistry.keySet(); }
/**
* Subscribes the player with name playerName to the log with name logName.
*/
public static void subscribePlayer(String playerName, String logName, String option)
{
if (!playerSubscriptions.containsKey(playerName)) playerSubscriptions.put(playerName, new HashMap<>());
Logger log = loggerRegistry.get(logName);
if (option == null) option = log.getDefault();
playerSubscriptions.get(playerName).put(logName,option);
log.addPlayer(playerName, option);
}
/**
* Unsubscribes the player with name playerName from the log with name logName.
*/
public static void unsubscribePlayer(String playerName, String logName)
{
if (playerSubscriptions.containsKey(playerName))
{
Map<String,String> subscriptions = playerSubscriptions.get(playerName);
subscriptions.remove(logName);
loggerRegistry.get(logName).removePlayer(playerName);
if (subscriptions.size() == 0) playerSubscriptions.remove(playerName);
}
}
/**
* If the player is not subscribed to the log, then subscribe them. Otherwise, unsubscribe them.
*/
public static boolean togglePlayerSubscription(String playerName, String logName)
{
if (playerSubscriptions.containsKey(playerName) && playerSubscriptions.get(playerName).containsKey(logName))
{
unsubscribePlayer(playerName, logName);
return false;
}
else
{
subscribePlayer(playerName, logName, null);
return true;
}
}
/**
* Get the set of logs the current player is subscribed to.
*/
public static Map<String,String> getPlayerSubscriptions(String playerName)
{
if (playerSubscriptions.containsKey(playerName))
{
return playerSubscriptions.get(playerName);
}
return null;
}
protected static void setAccess(Logger logger)
{
String name = logger.getLogName();
boolean value = logger.hasOnlineSubscribers();
try
{
Field f = LoggerRegistry.class.getDeclaredField("__"+name);
f.setBoolean(null, value);
}
catch (IllegalAccessException e)
{
CarpetSettings.LOG.error("Cannot change logger quick access field");
}
catch (NoSuchFieldException e)
{
CarpetSettings.LOG.error("Wrong logger name");
}
}
/**
* Called when the server starts. Creates the logs used by Carpet mod.
*/
private static void registerLogger(String name, Logger logger)
{
loggerRegistry.put(name, logger);
setAccess(logger);
}
public static void playerConnected(EntityPlayer player)
{
for(Logger log: loggerRegistry.values() )
{
log.onPlayerConnect(player);
}
}
public static void playerDisconnected(EntityPlayer player)
{
for(Logger log: loggerRegistry.values() )
{
log.onPlayerDisconnect(player);
}
}
}
@@ -0,0 +1,102 @@
package carpet.logging.logHelpers;
import carpet.logging.LoggerRegistry;
import carpet.utils.Messenger;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.MobEffects;
import net.minecraft.util.DamageSource;
import net.minecraft.util.text.ITextComponent;
import java.util.function.Supplier;
public class DamageReporter
{
private static ITextComponent[] verifyAndProduceMessage(String option, EntityPlayer player, Entity from, Entity to, Supplier<ITextComponent> messageFuture)
{
if ("all".equalsIgnoreCase(option)
|| ("players".equalsIgnoreCase(option) && (from instanceof EntityPlayer || to instanceof EntityPlayer))
|| ("me".equalsIgnoreCase(option) && ( (from == player) || ( to == player) ) ))
{
return new ITextComponent[]{messageFuture.get()};
}
return null;
}
public static boolean register_damage_attacker(Entity target, EntityLivingBase source, float amount)
{
if (!LoggerRegistry.__damage) return true;
LoggerRegistry.getLogger("damage").log( (option, player)->
verifyAndProduceMessage(option, player, source, target, () ->
Messenger.c(source.getDisplayName(),
"g attacking ", target.getDisplayName(),"g for ",
String.format("r %.2f",amount), "g points of damage")
)
);
return true;
}
public static void register_damage(EntityLivingBase target, DamageSource source, float amount)
{
if (!LoggerRegistry.__damage) return;
if (source.isFireDamage() && (target.isImmuneToFire() ||
target.isPotionActive(MobEffects.FIRE_RESISTANCE)))
return;
LoggerRegistry.getLogger("damage").log( (option, player)->
verifyAndProduceMessage(option, player, source.getTrueSource(), target, () ->
Messenger.c(target.getDisplayName(),
"g receiving ",
String.format("r %.2f", amount),
String.format("g points of damage from %s", source.getDamageType()))
)
);
}
public static void register_final_damage(EntityLivingBase target, DamageSource source, float amount)
{
if (!LoggerRegistry.__damage) return;
LoggerRegistry.getLogger("damage").log( (option, player)->
verifyAndProduceMessage(option, player, source.getTrueSource(), target, () ->
Messenger.c("g - total received ",
String.format("r %.2f", amount),
"g points of damage")
)
);
}
public static void modify_damage(EntityLivingBase target, DamageSource source, float previous_amount, float final_amount, String component)
{
if (!LoggerRegistry.__damage)
return;
if (previous_amount == final_amount)
return;
if (source.isFireDamage() && (target.isImmuneToFire() ||
target.isPotionActive(MobEffects.FIRE_RESISTANCE)))
return;
LoggerRegistry.getLogger("damage").log( (option, player)->
verifyAndProduceMessage(option, player, source.getTrueSource(), target, () ->
{
if (final_amount == 0.0f)
{
return Messenger.c("g - reduced to ","r 0.0","g due to: "+component);
}
else if (previous_amount > final_amount)
{
float reduction = previous_amount-final_amount;
return Messenger.c("g - reduced to ",
String.format("l %.2f",final_amount),
String.format("g by %.2f (%.1f%% less) due to: %s",reduction,100.0*reduction/previous_amount, component));
}
else
{
float increase = final_amount-previous_amount;
return Messenger.c("g - increased to ",
String.format("r %.2f",final_amount),
String.format("g by %.2f (%.1f%% more) due to: %s",increase,100.0*increase/previous_amount, component));
}
}
)
);
}
}
@@ -0,0 +1,26 @@
package carpet.logging.logHelpers;
import carpet.logging.LoggerRegistry;
import carpet.utils.Messenger;
import net.minecraft.util.text.ITextComponent;
public class KillLogHelper {
public static void onSweep(String name, int count)
{
LoggerRegistry.getLogger("kills").log( () -> new ITextComponent[]{
Messenger.c("g "+name+" smacked ","r "+count,"g entities with sweeping")});
}
public static void onNonSweepAttack(String name)
{
LoggerRegistry.getLogger("kills").log( () -> new ITextComponent[]{
Messenger.c("g "+name+" smacked ","r 1","g (no sweeping)")});
}
public static void onDudHit(String name)
{
LoggerRegistry.getLogger("kills").log( () -> new ITextComponent[]{
Messenger.c("g "+name+" dud hot = no one affected")});
}
}
@@ -0,0 +1,8 @@
package carpet.logging.logHelpers;
public class PacketCounter
{
public static long totalOut=0;
public static long totalIn=0;
public static void reset() {totalIn = 0l; totalOut = 0L; }
}
@@ -0,0 +1,41 @@
package carpet.logging.logHelpers;
import carpet.logging.LoggerRegistry;
import carpet.utils.Messenger;
import net.minecraft.util.text.ITextComponent;
public class TNTLogHelper
{
private double primedX, primedY, primedZ, primedAngle;
/**
* Runs when the TNT is primed. Expects the position and motion angle of the TNT.
*/
public void onPrimed(double x, double y, double z, float angle)
{
primedX = x;
primedY = y;
primedZ = z;
primedAngle = angle;
}
/**
* Runs when the TNT explodes. Expects the position of the TNT.
*/
public void onExploded(double x, double y, double z)
{
LoggerRegistry.getLogger("tnt").log( (option) -> {
switch (option)
{
case "brief":
return new ITextComponent[]{Messenger.c(
"l P ",Messenger.dblt("l",primedX,primedY,primedZ,primedAngle),
"r E ",Messenger.dblt("r",x, y, z))};
case "full":
return new ITextComponent[]{Messenger.c(
"l P ",Messenger.dblf("l",primedX,primedY,primedZ,primedAngle),
"r E ",Messenger.dblf("r",x, y, z))};
}
return null;
});
}
}
@@ -0,0 +1,80 @@
package carpet.logging.logHelpers;
import carpet.logging.Logger;
import carpet.logging.LoggerRegistry;
import carpet.utils.Messenger;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.ITextComponent;
import java.util.ArrayList;
import java.util.List;
/**
* A generic log helper for logging the trajectory of things like blocks and throwables.
*/
public class TrajectoryLogHelper
{
private static final int MAX_TICKS_PER_LINE = 20;
private boolean doLog;
private Logger logger;
private ArrayList<Vec3d> positions = new ArrayList<>();
private ArrayList<Vec3d> motions = new ArrayList<>();
public TrajectoryLogHelper(String logName)
{
this.logger = LoggerRegistry.getLogger(logName);
this.doLog = this.logger.hasOnlineSubscribers();
}
public void onTick(double x, double y, double z, double motionX, double motionY, double motionZ)
{
if (!doLog) return;
positions.add(new Vec3d(x, y, z));
motions.add(new Vec3d(motionX, motionY, motionZ));
}
public void onFinish()
{
if (!doLog) return;
logger.log( (option) -> {
List<ITextComponent> comp = new ArrayList<>();
switch (option)
{
case "brief":
comp.add(Messenger.s(""));
List<String> line = new ArrayList<>();
for (int i = 0; i < positions.size(); i++)
{
Vec3d pos = positions.get(i);
Vec3d mot = motions.get(i);
line.add("w x");
line.add(String.format("^w Tick: %d\nx: %f\ny: %f\nz: %f\n------------\nmx: %f\nmy: %f\nmz: %f",
i, pos.x, pos.y, pos.z, mot.x, mot.y, mot.z));
if ((((i+1) % MAX_TICKS_PER_LINE)==0) || i == positions.size()-1)
{
comp.add(Messenger.c(line.toArray(new Object[0])));
line.clear();
}
}
break;
case "full":
comp.add(Messenger.c("w ---------"));
for (int i = 0; i < positions.size(); i++)
{
Vec3d pos = positions.get(i);
Vec3d mot = motions.get(i);
comp.add(Messenger.c(
String.format("w tick: %3d pos",i),Messenger.dblt("w",pos.x, pos.y, pos.z),
"w mot",Messenger.dblt("w",mot.x, mot.y, mot.z)));
}
break;
}
return comp.toArray(new ITextComponent[0]);
});
doLog = false;
}
}
@@ -0,0 +1,15 @@
package carpet.mixins.logging;
import net.minecraft.client.network.packet.PlayerListHeaderS2CPacket;
import net.minecraft.network.chat.Component;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(PlayerListHeaderS2CPacket.class)
public interface PlayerListHeaderS2CPacketMixin {
@Accessor("header")
void setHeader(Component header);
@Accessor("footer")
void setFooter(Component footer);
}
+227
View File
@@ -0,0 +1,227 @@
package carpet.utils;
import net.minecraft.block.Block;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.block.Material;
import net.minecraft.block.MaterialColor;
import net.minecraft.block.BlockState;
import net.minecraft.entity.mob.MobEntityWithAi;
import net.minecraft.entity.ai.goal.WanderAroundGoal;
import net.minecraft.entity.ai.PathfindingUtil;
import net.minecraft.entity.mob.ZombiePigmanEntity;
import net.minecraft.block.BlockPlacementEnvironment;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.registry.Registry;
import net.minecraft.network.chat.BaseComponent;
import net.minecraft.world.World;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BlockInfo
{
public static Map<BlockSoundGroup, String> soundName = new HashMap<BlockSoundGroup, String>() {{
put(BlockSoundGroup.WOOD, "wood" );
put(BlockSoundGroup.GROUND, "gravel");
put(BlockSoundGroup.PLANT, "grass" );
put(BlockSoundGroup.STONE, "stone" );
put(BlockSoundGroup.METAL, "metal" );
put(BlockSoundGroup.GLASS , "glass" );
put(BlockSoundGroup.CLOTH , "wool" );
put(BlockSoundGroup.SAND , "sand" );
put(BlockSoundGroup.SNOW , "snow" );
put(BlockSoundGroup.LADDER, "ladder");
put(BlockSoundGroup.ANVIL , "anvil" );
put(BlockSoundGroup.SLIME , "slime" );
put(BlockSoundGroup.WET_GRASS , "sea_grass" );
put(BlockSoundGroup.CORAL , "coral" );
}};
public static Map<MaterialColor, String> mapColourName = new HashMap<MaterialColor, String>() {{
put(MaterialColor.AIR , "air" );
put(MaterialColor.GRASS , "grass" );
put(MaterialColor.SAND , "sand" );
put(MaterialColor.WOOL , "wool" );
put(MaterialColor.TNT , "tnt" );
put(MaterialColor.ICE , "ice" );
put(MaterialColor.IRON , "iron" );
put(MaterialColor.FOLIAGE , "foliage" );
put(MaterialColor.SNOW , "snow" );
put(MaterialColor.CLAY , "clay" );
put(MaterialColor.DIRT , "dirt" );
put(MaterialColor.STONE , "stone" );
put(MaterialColor.WATER , "water" );
put(MaterialColor.WOOD , "wood" );
put(MaterialColor.QUARTZ , "quartz" );
put(MaterialColor.ADOBE , "adobe" );
put(MaterialColor.MAGENTA , "magenta" );
put(MaterialColor.LIGHT_BLUE, "light_blue");
put(MaterialColor.YELLOW , "yellow" );
put(MaterialColor.LIME , "lime" );
put(MaterialColor.PINK , "pink" );
put(MaterialColor.GRAY , "gray" );
put(MaterialColor.LIGHT_GRAY, "light_gray");
put(MaterialColor.CYAN , "cyan" );
put(MaterialColor.PURPLE , "purple" );
put(MaterialColor.BLUE , "blue" );
put(MaterialColor.BROWN , "brown" );
put(MaterialColor.GREEN , "green" );
put(MaterialColor.RED , "red" );
put(MaterialColor.BLACK , "black" );
put(MaterialColor.GOLD , "gold" );
put(MaterialColor.DIAMOND , "diamond" );
put(MaterialColor.LAPIS , "lapis" );
put(MaterialColor.EMERALD , "emerald" );
put(MaterialColor.OBSIDIAN , "obsidian" );
put(MaterialColor.NETHERRACK, "netherrack");
put(MaterialColor.WHITE_TERRACOTTA , "white_terracotta" );
put(MaterialColor.ORANGE_TERRACOTTA , "orange_terracotta" );
put(MaterialColor.MAGENTA_TERRACOTTA , "magenta_terracotta" );
put(MaterialColor.LIGHT_BLUE_TERRACOTTA, "light_blue_terracotta" );
put(MaterialColor.YELLOW_TERRACOTTA , "yellow_terracotta" );
put(MaterialColor.LIME_TERRACOTTA , "lime_terracotta" );
put(MaterialColor.PINK_TERRACOTTA , "pink_terracotta" );
put(MaterialColor.GRAY_TERRACOTTA , "gray_terracotta" );
put(MaterialColor.LIGHT_GRAY_TERRACOTTA, "light_gray_terracotta" );
put(MaterialColor.CYAN_TERRACOTTA , "cyan_terracotta" );
put(MaterialColor.PURPLE_TERRACOTTA , "purple_terracotta" );
put(MaterialColor.BLUE_TERRACOTTA , "blue_terracotta" );
put(MaterialColor.BROWN_TERRACOTTA , "brown_terracotta" );
put(MaterialColor.GREEN_TERRACOTTA , "green_terracotta" );
put(MaterialColor.RED_TERRACOTTA , "red_terracotta" );
put(MaterialColor.BLACK_TERRACOTTA , "black_terracotta" );
}};
public static Map<Material, String> materialName = new HashMap<Material, String>() {{
put(Material.AIR , "air" );
put(Material.STRUCTURE_VOID , "void" );
put(Material.PORTAL , "portal" );
put(Material.CARPET , "carpet" );
put(Material.PLANTS , "plant" );
put(Material.OCEAN_PLANT , "water_plant" );
put(Material.VINE , "vine" );
put(Material.SEA_GRASS , "sea_grass" );
put(Material.WATER , "water" );
put(Material.BUBBLE_COLUMN , "bubble_column");
put(Material.LAVA , "lava" );
put(Material.SNOW , "snow_layer" );
put(Material.FIRE , "fire" );
put(Material.CIRCUITS , "redstone_bits");
put(Material.WEB , "cobweb" );
put(Material.REDSTONE_LIGHT , "redstone_lamp");
put(Material.CLAY , "clay" );
put(Material.GROUND , "dirt" );
put(Material.GRASS , "grass" );
put(Material.PACKED_ICE , "packed_ice" );
put(Material.SAND , "sand" );
put(Material.SPONGE , "sponge" );
put(Material.WOOD , "wood" );
put(Material.CLOTH , "wool" );
put(Material.TNT , "tnt" );
put(Material.LEAVES , "leaves" );
put(Material.GLASS , "glass" );
put(Material.ICE , "ice" );
put(Material.CACTUS , "cactus" );
put(Material.ROCK , "stone" );
put(Material.IRON , "iron" );
put(Material.CRAFTED_SNOW , "snow" );
put(Material.ANVIL , "anvil" );
put(Material.BARRIER , "barrier" );
put(Material.PISTON , "piston" );
put(Material.CORAL , "coral" );
put(Material.GOURD , "gourd" );
put(Material.DRAGON_EGG , "dragon_egg" );
put(Material.CAKE , "cake" );
}};
public static List<BaseComponent> blockInfo(BlockPos pos, World world)
{
BlockState state = world.getBlockState(pos);
Material material = state.getMaterial();
Block block = state.getBlock();
String metastring = "";
for (net.minecraft.state.IProperty<?> iproperty : state.getProperties())
{
metastring += ", "+iproperty.getName() + '='+state.get(iproperty);
}
List<BaseComponent> lst = new ArrayList<>();
lst.add(Messenger.s(""));
lst.add(Messenger.s("====================================="));
lst.add(Messenger.s(String.format("Block info for %s%s (id %d%s):",Registry.BLOCK.getKey(block),metastring, Registry.BLOCK.getId(block), metastring )));
lst.add(Messenger.s(String.format(" - Material: %s", materialName.get(material))));
lst.add(Messenger.s(String.format(" - Map colour: %s", mapColourName.get(state.getMaterialColor(world, pos)))));
lst.add(Messenger.s(String.format(" - Sound type: %s", soundName.get(block.getBlockSoundGroup()))));
lst.add(Messenger.s(""));
lst.add(Messenger.s(String.format(" - Full block: %s", state.isFullCube() )));
lst.add(Messenger.s(String.format(" - Normal cube: %s", state.isNormalCube())));
lst.add(Messenger.s(String.format(" - Is liquid: %s", material.isLiquid())));
lst.add(Messenger.s(String.format(" - Is solid: %s", material.isSolid())));
lst.add(Messenger.s(""));
lst.add(Messenger.s(String.format(" - Light in: %d, above: %d", world.getLight(pos), world.getLight(pos.up()))));
lst.add(Messenger.s(String.format(" - Brightness in: %.2f, above: %.2f", world.getBrightness(pos), world.getBrightness(pos.up()))));
lst.add(Messenger.s(String.format(" - Is opaque: %s", material.isOpaque() )));
lst.add(Messenger.s(String.format(" - Light opacity: %d", state.getOpacity(world,pos))));
lst.add(Messenger.s(String.format(" - Blocks light: %s", state.propagatesSkylightDown(world, pos))));
lst.add(Messenger.s(String.format(" - Emitted light: %d", state.getLightValue())));
lst.add(Messenger.s(String.format(" - Picks neighbour light value: %s", state.useNeighborBrightness(world, pos))));
lst.add(Messenger.s(""));
lst.add(Messenger.s(String.format(" - Causes suffocation: %s", state.causesSuffocation())));
lst.add(Messenger.s(String.format(" - Blocks movement on land: %s", !state.canPlaceAtSide(world,pos, BlockPlacementEnvironment.LAND))));
lst.add(Messenger.s(String.format(" - Blocks movement in air: %s", !state.canPlaceAtSide(world,pos, BlockPlacementEnvironment.AIR))));
lst.add(Messenger.s(String.format(" - Blocks movement in liquids: %s", !state.canPlaceAtSide(world,pos, BlockPlacementEnvironment.WATER))));
lst.add(Messenger.s(String.format(" - Can burn: %s", material.isFlammable())));
lst.add(Messenger.s(String.format(" - Requires a tool: %s", !material.isToolNotRequired())));
lst.add(Messenger.s(String.format(" - Hardness: %.2f", state.getBlockHardness(world, pos))));
lst.add(Messenger.s(String.format(" - Blast resistance: %.2f", block.getExplosionResistance())));
lst.add(Messenger.s(String.format(" - Ticks randomly: %s", block.ticksRandomly(state))));
lst.add(Messenger.s(""));
lst.add(Messenger.s(String.format(" - Can provide power: %s", state.canProvidePower())));
lst.add(Messenger.s(String.format(" - Strong power level: %d", world.getStrongPower(pos))));
lst.add(Messenger.s(String.format(" - Redstone power level: %d", world.getRedstonePowerFromNeighbors(pos))));
lst.add(Messenger.s(""));
lst.add(wander_chances(pos.up(), world));
return lst;
}
private static BaseComponent wander_chances(BlockPos pos, World worldIn)
{
MobEntityWithAi creature = new ZombiePigmanEntity(worldIn);
creature.onInitialSpawn(worldIn.getDifficultyForLocation(pos), null, null);
creature.setLocationAndAngles(pos.getX()+0.5F, pos.getY(), pos.getZ()+0.5F, 0.0F, 0.0F);
WanderAroundGoal wander = new WanderAroundGoal(creature, 0.8D);
int success = 0;
for (int i=0; i<1000; i++)
{
Vec3d vec = PathfindingUtil.findRandomTarget(creature, 10, 7);
if (vec == null)
{
continue;
}
success++;
}
long total_ticks = 0;
for (int trie=0; trie<1000; trie++)
{
int i;
for (i=1;i<30*20*60; i++) //*60 used to be 5 hours, limited to 30 mins
{
if (wander.shouldExecute())
{
break;
}
}
total_ticks += 3*i;
}
creature.remove();
long total_time = (total_ticks)/1000/20;
return Messenger.s(String.format(" - Wander chance above: %.1f%%%%\n - Average standby above: %s",
(100.0F*success)/1000,
((total_time>5000)?"INFINITY":(Long.toString(total_time)+" s"))
));
}
}
@@ -0,0 +1,64 @@
package carpet.utils;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.network.chat.BaseComponent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class DistanceCalculator
{
public static final HashMap<String, Vec3d> START_POINT_STORAGE = new HashMap<>();
public static boolean hasStartingPoint(ServerCommandSource source)
{
return START_POINT_STORAGE.containsKey(source.getName());
}
public static List<BaseComponent> findDistanceBetweenTwoPoints(Vec3d pos1, Vec3d pos2)
{
double dx = MathHelper.abs((float)pos1.x-(float)pos2.x);
double dy = MathHelper.abs((float)pos1.y-(float)pos2.y);
double dz = MathHelper.abs((float)pos1.z-(float)pos2.z);
double manhattan = dx+dy+dz;
double spherical = MathHelper.sqrt(dx*dx + dy*dy + dz*dz);
double cylindrical = MathHelper.sqrt(dx*dx + dz*dz);
List<BaseComponent> res = new ArrayList<>();
res.add(Messenger.c("w Distance between ",
Messenger.tp("c",pos1),"w and ",
Messenger.tp("c",pos2),"w :"));
res.add(Messenger.c("w - Manhattan: ", String.format("wb %.1f", manhattan)));
res.add(Messenger.c("w - Spherical: ", String.format("wb %.2f", spherical)));
res.add(Messenger.c("w - Cylindrical: ", String.format("wb %.2f", cylindrical)));
return res;
}
public static int distance(ServerCommandSource source, Vec3d pos1, Vec3d pos2)
{
Messenger.send(source, findDistanceBetweenTwoPoints(pos1, pos2));
return 1;
}
public static int setStart(ServerCommandSource source, Vec3d pos)
{
START_POINT_STORAGE.put(source.getName(), pos);
Messenger.m(source,"gi Initial point set to: ", Messenger.tp("g",pos));
return 1;
}
public static int setEnd(ServerCommandSource source, Vec3d pos)
{
if ( !hasStartingPoint(source) )
{
START_POINT_STORAGE.put(source.getName(), pos);
Messenger.m(source,"gi There was no initial point for "+source.getName());
Messenger.m(source,"gi Initial point set to: ", Messenger.tp("g",pos));
return 0;
}
Messenger.send(source, findDistanceBetweenTwoPoints( START_POINT_STORAGE.get(source.getName()), pos));
return 1;
}
}
@@ -0,0 +1,13 @@
package carpet.utils;
import java.util.LinkedHashMap;
import java.util.Map;
public class EvictingQueue<K,V> extends LinkedHashMap<K,V>
{
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest)
{
return this.size() > 10;
}
}
@@ -0,0 +1,133 @@
package carpet.utils;
import carpet.helpers.HopperCounter;
import carpet.helpers.TickSpeed;
import carpet.logging.LoggerRegistry;
import carpet.logging.logHelpers.PacketCounter;
import carpet.mixins.logging.PlayerListHeaderS2CPacketMixin;
import net.minecraft.entity.EntityCategory;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.client.network.packet.PlayerListHeaderS2CPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.Pair;
import net.minecraft.util.math.MathHelper;
import net.minecraft.network.chat.BaseComponent;
import net.minecraft.network.chat.TextComponent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class HUDController
{
public static Map<PlayerEntity, List<BaseComponent>> player_huds = new HashMap<>();
public static void addMessage(PlayerEntity player, BaseComponent hudMessage)
{
if (!player_huds.containsKey(player))
{
player_huds.put(player, new ArrayList<>());
}
else
{
player_huds.get(player).add(new TextComponent("\n"));
}
player_huds.get(player).add(hudMessage);
}
public static void clear_player(PlayerEntity player)
{
PlayerListHeaderS2CPacket packet = new PlayerListHeaderS2CPacket();
((PlayerListHeaderS2CPacketMixin)packet).setHeader(new TextComponent(""));
((PlayerListHeaderS2CPacketMixin)packet).setFooter(new TextComponent(""));
((ServerPlayerEntity)player).networkHandler.sendPacket(packet);
}
public static void update_hud(MinecraftServer server)
{
if(server.getTicks() % 20 != 0)
return;
player_huds.clear();
if (LoggerRegistry.__tps)
LoggerRegistry.getLogger("tps").log(()-> send_tps_display(server));
if (LoggerRegistry.__mobcaps)
LoggerRegistry.getLogger("mobcaps").log((option, player) -> {
int dim = player.dimension.getRawId();
switch (option)
{
case "overworld":
dim = 0;
break;
case "nether":
dim = -1;
break;
case "end":
dim = 1;
break;
}
return send_mobcap_display(dim);
});
if(LoggerRegistry.__counter)
LoggerRegistry.getLogger("counter").log((option)->send_counter_info(server, option));
if (LoggerRegistry.__packets)
LoggerRegistry.getLogger("packets").log(()-> packetCounter());
for (PlayerEntity player: player_huds.keySet())
{
PlayerListHeaderS2CPacket packet = new PlayerListHeaderS2CPacket();
((PlayerListHeaderS2CPacketMixin)packet).setHeader(new TextComponent(""));
((PlayerListHeaderS2CPacketMixin)packet).setFooter(Messenger.c(player_huds.get(player).toArray(new Object[0])));
((ServerPlayerEntity)player).networkHandler.sendPacket(packet);
}
}
private static BaseComponent [] send_tps_display(MinecraftServer server)
{
double MSPT = MathHelper.average(server.lastTickLengths) * 1.0E-6D;
double TPS = 1000.0D / Math.max((TickSpeed.time_warp_start_time != 0)?0.0:TickSpeed.mspt, MSPT);
String color = Messenger.heatmap_color(MSPT,TickSpeed.mspt);
return new BaseComponent[]{Messenger.c(
"g TPS: ", String.format(Locale.US, "%s %.1f",color, TPS),
"g MSPT: ", String.format(Locale.US,"%s %.1f", color, MSPT))};
}
private static BaseComponent [] send_mobcap_display(int dim)
{
List<BaseComponent> components = new ArrayList<>();
for (EntityCategory type:EntityCategory.values())
{
Pair<Integer,Integer> counts = SpawnReporter.mobcaps.get(dim).getOrDefault(type, new Pair<>(0, 0));
int actual = counts.getLeft(); int limit = counts.getRight();
components.add(Messenger.c(
(actual+limit == 0)?"g -":Messenger.heatmap_color(actual,limit)+" "+actual,
Messenger.creatureTypeColor(type)+" /"+((actual+limit == 0)?"-":limit)
));
components.add(Messenger.c("w "));
}
components.remove(components.size()-1);
return new BaseComponent[]{Messenger.c(components.toArray(new Object[0]))};
}
private static BaseComponent [] send_counter_info(MinecraftServer server, String color)
{
HopperCounter counter = HopperCounter.getCounter(color);
List <BaseComponent> res = counter == null ? Collections.emptyList() : counter.format(server, false, true);
return new BaseComponent[]{ Messenger.c(res.toArray(new Object[0]))};
}
private static BaseComponent [] packetCounter()
{
BaseComponent [] ret = new BaseComponent[]{
Messenger.c("w I/" + PacketCounter.totalIn + " O/" + PacketCounter.totalOut),
};
PacketCounter.reset();
return ret;
}
}
@@ -0,0 +1,510 @@
package carpet.utils;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.util.Pair;
import net.minecraft.util.registry.Registry;
import net.minecraft.network.chat.BaseComponent;
import net.minecraft.world.World;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.DyeColor;
import net.minecraft.entity.EntityCategory;
import net.minecraft.world.biome.Biome;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.dimension.DimensionType;
import net.minecraft.world.SpawnHelper;
import net.minecraft.entity.SpawnRestriction;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.Entity;
import net.minecraft.entity.passive.OcelotEntity;
import net.minecraft.world.Heightmap;
import net.minecraft.world.gen.chunk.ChunkGenerator;
import java.lang.Math;
public class SpawnReporter
{
public static String [] mob_groups = {"hostile","passive","water","ambient"};
public static boolean mock_spawns = false;
public static Long track_spawns = 0L;
public static final HashMap<Integer, HashMap<EntityCategory, Pair<Integer,Integer>>> mobcaps = new HashMap<>();
public static final HashMap<String, HashMap<String,Long>> spawn_stats = new HashMap<String, HashMap<String,Long>>();
public static double mobcap_exponent = 0.0D;
public static final HashMap<String, Long> spawn_attempts = new HashMap<String, Long>();
public static final HashMap<String, Long> overall_spawn_ticks = new HashMap<String, Long>();
public static final HashMap<String, Long> spawn_ticks_full = new HashMap<String, Long>();
public static final HashMap<String, Long> spawn_ticks_fail = new HashMap<String, Long>();
public static final HashMap<String, Long> spawn_ticks_succ = new HashMap<String, Long>();
public static final HashMap<String, Long> spawn_ticks_spawns = new HashMap<String, Long>();
public static final HashMap<String, Long> spawn_cap_count = new HashMap<String, Long>();
public static class SpawnPos
{
public String mob;
public BlockPos pos;
public SpawnPos(String mob, BlockPos pos)
{
this.mob = mob;
this.pos = pos;
}
}
public static final HashMap<String, EvictingQueue<SpawnPos, Integer>> spawned_mobs = new HashMap<>();
public static final HashMap<String, Integer> spawn_tries = new HashMap<>();
public static BlockPos lower_spawning_limit = null;
public static BlockPos upper_spawning_limit = null;
static {
reset_spawn_stats(true);
}
public static void registerSpawn(LivingEntity el, String type, String mob, BlockPos pos) { registerSpawn(el, type, mob, pos, 1L);}
public static void registerSpawn(LivingEntity el, String type, String mob, BlockPos pos, long value)
{
if (lower_spawning_limit != null)
{
if (!( (lower_spawning_limit.getX() <= pos.getX() && pos.getX() <= upper_spawning_limit.getX()) &&
(lower_spawning_limit.getY() <= pos.getY() && pos.getY() <= upper_spawning_limit.getY()) &&
(lower_spawning_limit.getZ() <= pos.getZ() && pos.getZ() <= upper_spawning_limit.getZ())
))
{
return;
}
}
long count = spawn_stats.get(type).getOrDefault(mob, 0L);
spawn_stats.get(type).put(mob, count + value);
spawned_mobs.get(type).put(new SpawnPos(mob, new BlockPos(el)), 1);
}
public static List<BaseComponent> printMobcapsForDimension(int dim)
{
String name = DimensionType.byRawId(dim).toString();
List<BaseComponent> lst = new ArrayList<>();
lst.add(Messenger.s(String.format("Mobcaps for %s:",name)));
for (EntityCategory enumcreaturetype : EntityCategory.values())
{
String type_code = String.format("%s", enumcreaturetype);
Pair<Integer, Integer> stat = mobcaps.get(dim).getOrDefault(enumcreaturetype, new Pair<>(0,0));
int cur = stat.getLeft();
int max = stat.getRight();
int rounds = spawn_tries.get(type_code);
lst.add( Messenger.c(String.format("w %s: ",type_code),
(cur+max==0)?"g -/-":String.format("%s %d/%d", (cur >= max)?"r":((cur >= 8*max/10)?"y":"l") ,cur, max),
(rounds == 1)?"w ":String.format("fi (%d rounds/tick)",spawn_tries.get(type_code))
));
}
return lst;
}
public static List<BaseComponent> recent_spawns(World world, String creature_type_code)
{
EntityCategory creature_type = get_creature_type_from_code(creature_type_code);
List<BaseComponent> lst = new ArrayList<>();
if ((track_spawns == 0L))
{
lst.add(Messenger.s("Spawn tracking not started"));
return lst;
}
if (creature_type == null)
{
lst.add(Messenger.s(String.format("Incorrect creature type: %s",creature_type_code)));
return lst;
}
String type_code = get_type_string(creature_type);
lst.add(Messenger.s(String.format("Recent %s spawns:",type_code)));
for (SpawnPos entry: spawned_mobs.get(type_code).keySet())
{
lst.add( Messenger.c(String.format("w - %s ",entry.mob), Messenger.tp("wb",entry.pos)));
}
if (lst.size()==1)
{
lst.add(Messenger.s(" - Nothing spawned yet, sorry."));
}
return lst;
}
public static List<BaseComponent> show_mobcaps(BlockPos pos, World worldIn)
{
DyeColor under = WoolTool.getWoolColorAtPosition(worldIn, pos.down());
if (under == null)
{
if (track_spawns > 0L)
{
return tracking_report(worldIn);
}
else
{
//return print_general_mobcaps(worldIn);
}
}
String creature_type = get_type_code_from_wool_code(under);
if (creature_type != null)
{
if (track_spawns > 0L)
{
return recent_spawns(worldIn, creature_type);
}
else
{
return printEntitiesByType(creature_type, worldIn);
}
}
if (track_spawns > 0L)
{
return tracking_report(worldIn);
}
else
{
return tracking_report(worldIn);
//// TODO
//return print_general_mobcaps(worldIn);
}
}
public static String get_type_code_from_wool_code(DyeColor color)
{
switch (color)
{
case RED:
return "hostile";
case GREEN:
return "passive";
case BLUE:
return "water";
case BROWN:
return "ambient";
}
return null;
}
public static EntityCategory get_creature_type_from_code(String type_code)
{
if ("hostile".equalsIgnoreCase(type_code))
{
return EntityCategory.MONSTER;
}
else if ("passive".equalsIgnoreCase(type_code))
{
return EntityCategory.CREATURE;
}
else if ("water".equalsIgnoreCase(type_code))
{
return EntityCategory.WATER_CREATURE;
}
else if ("ambient".equalsIgnoreCase(type_code))
{
return EntityCategory.AMBIENT;
}
return null;
}
public static String get_type_string(EntityCategory type)
{
return String.format("%s", type);
}
public static String get_creature_code_from_string(String str)
{
return get_type_string(get_creature_type_from_code(str));
}
public static List<BaseComponent> printEntitiesByType(String creature_type_code, World worldIn) //Class<?> entityType)
{
EntityCategory typ = get_creature_type_from_code(creature_type_code);
List<BaseComponent> lst = new ArrayList<>();
if (typ == null)
{
lst.add(Messenger.c(String.format("r Incorrect creature type: %s",creature_type_code)));
return lst;
}
Class<?> cls = typ.getBaseClass();// getCreatureClass();
lst.add( Messenger.s(String.format("Loaded entities for %s class:", get_type_string(typ))));
for (Entity entity : worldIn.loadedEntityList)
{
if ((!(entity instanceof LivingEntity) || !((LivingEntity)entity).isNoDespawnRequired()) && cls.isAssignableFrom(entity.getClass()))
{
lst.add(Messenger.c("w - ",
Messenger.tp("w", entity.posX, entity.posY, entity.posZ),"w : "+EntityType.getId(entity.getType())));
}
}
if (lst.size()==1)
{
lst.add(Messenger.s(" - Empty."));
}
return lst;
}
public static void initialize_mocking()
{
reset_spawn_stats(false);
mock_spawns = true;
}
public static void stop_mocking()
{
reset_spawn_stats(false);
mock_spawns = false;
}
public static void reset_spawn_stats(boolean full)
{
spawn_stats.clear();
spawned_mobs.clear();
for (EntityCategory enumcreaturetype : EntityCategory.values())
{
String type_code = String.format("%s", enumcreaturetype);
if (full)
{
spawn_tries.put(type_code, 1);
}
for (String suffix: new String[] {""," (N)"," (E)"})
{
String code = type_code+suffix;
overall_spawn_ticks.put(code, 0L);
spawn_attempts.put(code, 0L);
spawn_ticks_full.put(code, 0L);
spawn_ticks_fail.put(code, 0L);
spawn_ticks_succ.put(code, 0L);
spawn_ticks_spawns.put(code, 0L);
spawn_cap_count.put(code, 0L);
}
spawn_stats.put(type_code, new HashMap<>());
spawned_mobs.put(type_code, new EvictingQueue<>());
}
mobcaps.put(-1,new HashMap<>());
mobcaps.put(0,new HashMap<>());
mobcaps.put(1,new HashMap<>());
track_spawns = 0L;
}
public static List<BaseComponent> tracking_report(World worldIn)
{
List<BaseComponent> report = new ArrayList<>();
if (track_spawns == 0L)
{
report.add(Messenger.c(
"w Spawn tracking disabled, type '",
"wi /spawn tracking start","/spawn tracking start",
"w ' to enable"));
return report;
}
Long duration = (long) worldIn.getServer().getTickCounter() - track_spawns;
report.add(Messenger.c("bw --------------------"));
String simulated = mock_spawns?"[SIMULATED] ":"";
String location = (lower_spawning_limit != null)?String.format("[in (%d, %d, %d)x(%d, %d, %d)]",
lower_spawning_limit.getX(),lower_spawning_limit.getY(),lower_spawning_limit.getZ(),
upper_spawning_limit.getX(),upper_spawning_limit.getY(),upper_spawning_limit.getZ() ):"";
report.add(Messenger.s(String.format("%sSpawn statistics %s: for %.1f min", simulated, location, (duration/72000.0)*60)));
for (EntityCategory enumcreaturetype : EntityCategory.values())
{
String type_code = String.format("%s", enumcreaturetype);
boolean there_are_mobs_to_list = false;
for (String world_code: new String[] {"", " (N)", " (E)"})
{
String code = type_code+world_code;
if (spawn_ticks_spawns.get(code) > 0L)
{
there_are_mobs_to_list = true;
double hours = overall_spawn_ticks.get(code)/72000.0;
report.add(Messenger.s(String.format(" > %s (%.1f min), %.1f m/t, {%.1f%%F / %.1f%%- / %.1f%%+}; %.2f s/att",
code,
60*hours,
(1.0D*spawn_cap_count.get(code))/ spawn_attempts.get(code),
(100.0D*spawn_ticks_full.get(code))/ spawn_attempts.get(code),
(100.0D*spawn_ticks_fail.get(code))/ spawn_attempts.get(code),
(100.0D*spawn_ticks_succ.get(code))/ spawn_attempts.get(code),
(1.0D*spawn_ticks_spawns.get(code))/(spawn_ticks_fail.get(code)+spawn_ticks_succ.get(code))
)));
}
}
if (there_are_mobs_to_list)
{
for (String creature_name : spawn_stats.get(type_code).keySet())
{
report.add(Messenger.s(String.format(" - %s: %d spawns, %d per hour",
creature_name,
spawn_stats.get(type_code).get(creature_name),
(72000 * spawn_stats.get(type_code).get(creature_name)/duration ))));
}
}
}
return report;
}
public static void killEntity(LivingEntity entity)
{
if (entity.isPassenger())
{
entity.getRidingEntity().remove();
}
if (entity.isBeingRidden())
{
for (Entity e: entity.getPassengers())
{
e.remove();
}
}
if (entity instanceof OcelotEntity)
{
for (Entity e: entity.getEntityWorld().getEntitiesWithinAABB(OcelotEntity.class, entity.getBoundingBox()))
{
e.remove();
}
}
entity.remove();
}
public static List<BaseComponent> report(BlockPos pos, World worldIn)
{
List<BaseComponent> rep = new ArrayList<>();
int x = pos.getX(); int y = pos.getY(); int z = pos.getZ();
Chunk chunk = worldIn.getChunk(pos);
int lc = chunk.getTopBlockY(Heightmap.Type.LIGHT_BLOCKING, x, z) + 1;
String where = String.format((y >= lc) ? "%d blocks above it." : "%d blocks below it.", MathHelper.abs(y-lc));
if (y == lc) where = "right at it.";
rep.add(Messenger.s(String.format("Maximum spawn Y value for (%+d, %+d) is %d. You are "+where, x, z, lc )));
rep.add(Messenger.s("Spawns:"));
for (EntityCategory enumcreaturetype : EntityCategory.values())
{
String type_code = String.format("%s", enumcreaturetype).substring(0, 3);
List<Biome.SpawnEntry> lst = ((ChunkGenerator)worldIn.getChunkManager().getChunkGenerator()).getEntitySpawnList(enumcreaturetype, pos);
if (lst != null && !lst.isEmpty())
{
for (Biome.SpawnEntry SpawnListEntry animal : lst)
{
boolean canspawn = SpawnHelper.canCreatureTypeSpawnAtLocation(SpawnRestriction.getPlacementType(animal.entityType), worldIn, pos, animal.entityType);
int will_spawn = -1;
boolean fits = false;
boolean fits1 = false;
LivingEntity entityliving;
try
{
entityliving = animal.entityType.create(worldIn);
}
catch (Exception exception)
{
exception.printStackTrace();
return rep;
}
boolean fits_true = false;
boolean fits_false = false;
if (canspawn)
{
will_spawn = 0;
for (int attempt = 0; attempt < 50; ++attempt)
{
float f = (float)x + 0.5F;
float f1 = (float)z + 0.5F;
entityliving.setLocationAndAngles((double)f, (double)y, (double)f1, worldIn.rand.nextFloat() * 360.0F, 0.0F);
fits1 = entityliving.isNotColliding();
for (int i = 0; i < 20; ++i)
{
if (entityliving.canSpawn(worldIn, false))
{
will_spawn += 1;
}
}
entityliving.onInitialSpawn(worldIn.getDifficultyForLocation(new BlockPos(entityliving)), null, null);
// the code invokes onInitialSpawn after getCanSpawHere
fits = fits1 && entityliving.isNotColliding();
if (fits)
{
fits_true = true;
}
else
{
fits_false = true;
}
killEntity(entityliving);
try
{
entityliving = animal.entityType.create(worldIn);
}
catch (Exception exception)
{
exception.printStackTrace();
return rep;
}
}
}
String creature_name = Registry.ENTITY_TYPE.getKey(entityliving.getType()).toString().replaceFirst("minecraft:","");
String pack_size = String.format("%d", entityliving.getMaxSpawnedInChunk());//String.format("%d-%d", animal.minGroupCount, animal.maxGroupCount);
int weight = animal.getItemWeight();
if (canspawn)
{
String c = (fits_true && will_spawn>0)?"e":"gi";
rep.add(Messenger.c(
String.format("%s %s: %s (%d:%d-%d/%d), can: ",c,type_code,creature_name,weight,animal.minGroupCount, animal.maxGroupCount, entityliving.getMaxSpawnedInChunk()),
"l YES",
c+" , fit: ",
((fits_true && fits_false)?"y YES and NO":(fits_true?"l YES":"r NO")),
c+" , will: ",
((will_spawn>0)?"l ":"r ")+Math.round((double)will_spawn)/10+"%"
));
}
else
{
rep.add(Messenger.c(String.format("gi %s: %s (%d:%d-%d/%d), can: ",type_code,creature_name,weight,animal.minGroupCount, animal.maxGroupCount, entityliving.getMaxSpawnedInChunk()), "n NO"));
}
killEntity(entityliving);
}
}
}
return rep;
}
public static boolean check_player_within_spawning_range(World worldServerIn, float x, float y, float z)
{
for (int i = 0; i < worldServerIn.playerEntities.size(); ++i)
{
PlayerEntity entityplayer = worldServerIn.playerEntities.get(i);
if (EntityPredicates.NOT_SPECTATING.test(entityplayer))
{
double d0 = entityplayer.getDistanceSq(x, y, z);
if ( d0 > 24.0*24.0 && d0 < 128.0*128.0)
{
return true;
}
}
}
return false;
}
}
+101
View File
@@ -0,0 +1,101 @@
package carpet.utils;
import carpet.CarpetSettings;
import carpet.helpers.HopperCounter;
import net.minecraft.block.Material;
import net.minecraft.block.MaterialColor;
import net.minecraft.block.BlockState;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.DyeColor;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.network.chat.BaseComponent;
import net.minecraft.world.World;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class WoolTool
{
private static final HashMap<MaterialColor,DyeColor> Material2Dye = new HashMap<>();
static
{
for (DyeColor color: DyeColor.values())
{
Material2Dye.put(color.getMaterialColor(),color);
}
}
public static void carpetPlacedAction(DyeColor color, PlayerEntity placer, BlockPos pos, World worldIn)
{
if (!CarpetSettings.getBool("carpets"))
{
return;
}
switch (color)
{
case PINK:
if (CarpetSettings.getBool("commandSpawn"))
Messenger.send(placer, SpawnReporter.report(pos, worldIn));
break;
case BLACK:
if (CarpetSettings.getBool("commandSpawn"))
Messenger.send(placer, SpawnReporter.show_mobcaps(pos, worldIn));
break;
case BROWN:
if (CarpetSettings.getBool("commandDistance"))
{
ServerCommandSource source = placer.getCommandSource();
if (!DistanceCalculator.hasStartingPoint(source) || placer.isSneaking()) {
DistanceCalculator.setStart(source, new Vec3d(pos));
}
else {
DistanceCalculator.setEnd(source, new Vec3d(pos));
}
}
break;
case GRAY:
if (CarpetSettings.getBool("commandInfo"))
Messenger.send(placer, BlockInfo.blockInfo(pos.down(), worldIn));
break;
case YELLOW:
if (CarpetSettings.getBool("commandInfo"))
EntityInfo.issue_entity_info(placer);
break;
case GREEN:
if (CarpetSettings.getBool("hopperCounters"))
{
DyeColor under = getWoolColorAtPosition(worldIn, pos.down());
if (under == null) return;
HopperCounter counter = HopperCounter.getCounter(under.toString());
if (counter != null)
Messenger.send(placer, counter.format(worldIn.getServer(), false, false));
}
break;
case RED:
if (CarpetSettings.getBool("hopperCounters"))
{
DyeColor under = getWoolColorAtPosition(worldIn, pos.down());
if (under == null) return;
HopperCounter counter = HopperCounter.getCounter(under.toString());
if (counter == null) return;
counter.reset(placer.getServer());
List<BaseComponent> res = new ArrayList<>();
res.add(Messenger.s(String.format("%s counter reset",under.toString())));
Messenger.send(placer, res);
}
break;
}
}
public static DyeColor getWoolColorAtPosition(World worldIn, BlockPos pos)
{
BlockState state = worldIn.getBlockState(pos);
if (state.getMaterial() != Material.CLOTH || !state.isFullCube())
return null;
return Material2Dye.get(state.getMaterialColor(worldIn, pos));
}
}
+2 -1
View File
@@ -4,7 +4,8 @@
"compatibilityLevel": "JAVA_8",
"mixins": [
"carpetServer/CommandManagerMixin",
"carpetServer/MinecraftServerMixin"
"carpetServer/MinecraftServerMixin",
"logging/PlayerListHeaderS2CPacketMixin"
],
"client": [
"carpetServer/MinecraftClientMixin",