From 6970864d8d3c3e35cf8d08033ab6ba75dee17b70 Mon Sep 17 00:00:00 2001 From: gnembon Date: Fri, 10 May 2019 01:26:39 -0300 Subject: [PATCH] cameramode, and draw commands --- src/main/java/carpet/CarpetServer.java | 8 +- src/main/java/carpet/CarpetSettings.java | 736 ++++++++++++++++++ .../carpet/commands/CameraModeCommand.java | 66 ++ .../java/carpet/commands/DrawCommand.java | 165 ++++ src/main/java/carpet/utils/Messenger.java | 4 +- .../java/net/fabricmc/example/ExampleMod.java | 14 - .../fabricmc/example/mixin/ExampleMixin.java | 15 - src/main/resources/fabric.mod.json | 7 +- 8 files changed, 976 insertions(+), 39 deletions(-) create mode 100644 src/main/java/carpet/CarpetSettings.java create mode 100644 src/main/java/carpet/commands/CameraModeCommand.java create mode 100644 src/main/java/carpet/commands/DrawCommand.java delete mode 100644 src/main/java/net/fabricmc/example/ExampleMod.java delete mode 100644 src/main/java/net/fabricmc/example/mixin/ExampleMixin.java diff --git a/src/main/java/carpet/CarpetServer.java b/src/main/java/carpet/CarpetServer.java index dd1dab93..b78ec21f 100644 --- a/src/main/java/carpet/CarpetServer.java +++ b/src/main/java/carpet/CarpetServer.java @@ -1,10 +1,10 @@ package carpet; -//import carpet.commands.CameraModeCommand; +import carpet.commands.CameraModeCommand; //import carpet.commands.CarpetCommand; //import carpet.commands.CounterCommand; //import carpet.commands.DistanceCommand; -//import carpet.commands.DrawCommand; +import carpet.commands.DrawCommand; //import carpet.commands.ScriptCommand; //import carpet.commands.InfoCommand; //import carpet.commands.LogCommand; @@ -56,11 +56,11 @@ public class CarpetServer // static for now - easier to handle all around the co //LogCommand.register(dispatcher); //SpawnCommand.register(dispatcher); //PlayerCommand.register(dispatcher); - //CameraModeCommand.register(dispatcher); + CameraModeCommand.register(dispatcher); //InfoCommand.register(dispatcher); //DistanceCommand.register(dispatcher); //PerimeterInfoCommand.register(dispatcher); - //DrawCommand.register(dispatcher); + DrawCommand.register(dispatcher); //ScriptCommand.register(dispatcher); TestCommand.register(dispatcher); diff --git a/src/main/java/carpet/CarpetSettings.java b/src/main/java/carpet/CarpetSettings.java new file mode 100644 index 00000000..297a5887 --- /dev/null +++ b/src/main/java/carpet/CarpetSettings.java @@ -0,0 +1,736 @@ +package carpet; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import java.io.File; +import java.io.FileWriter; +import java.io.FileReader; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.FileNotFoundException; + +//import carpet.helpers.SpawnChunks; +import carpet.utils.Messenger; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.dedicated.DedicatedServer; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.world.dimension.DimensionType; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.server.MinecraftServer; + +public class CarpetSettings +{ + public static boolean locked = false; + public static final String carpetVersion = "v19_05_01"; + + public static final Logger LOG = LogManager.getLogger(); + private static final Map settings_store; + public static final CarpetSettingEntry FalseEntry = CarpetSettingEntry.create("void","all","Error").choices("None",""); + + public static final String[] default_tags = {"tnt","fix","survival","creative", "experimental","optimizations","feature","commands"}; //tab completion only + public static boolean skipGenerationChecks = false; + + static { + settings_store = new HashMap<>(); + set_defaults(); + } + + //those don't have to mimic defaults - defaults will be ' + //static store + public static int n_pushLimit = 12; + public static boolean b_hopperCounters = false; + public static boolean b_shulkerSpawningInEndCities = false; + public static boolean b_fastRedstoneDust = false; + public static int railPowerLimitAdjusted = 8; + public static boolean b_disableSpawnChunks = false; + public static boolean b_movableTileEntities = false; + public static boolean b_huskSpawningInTemples = false; + + private static CarpetSettingEntry rule(String s1, String s2, String s3) { return CarpetSettingEntry.create(s1,s2,s3);} + + private static void set_defaults() + { + CarpetSettingEntry[] RuleList = new CarpetSettingEntry[] { + rule("watchdogCrashFix", "fix", "Fixes server crashing supposedly on falling behind 60s in ONE tick, yeah bs."). + extraInfo("Fixed 1.12 watchdog crash in 1.13 pre-releases, reintroduced with 1.13, GG."), + rule("portalSuffocationFix", "fix", "Nether portals correctly place entities going through") + .extraInfo("Entities shouldn't suffocate in obsidian"), + rule("superSecretSetting", "experimental","Gbhs sgnf sadsgras fhskdpri!"), + rule("invisibilityFix", "fix", "Guardians honor players' invisibility effect"), + rule("portalCreativeDelay", "creative", "Portals won't let a creative player go through instantly") + .extraInfo("Holding obsidian in either hand won't let you through at all"), + rule("ctrlQCraftingFix", "fix survival", "Dropping entire stacks works also from on the crafting UI result slot"), + rule("persistentParrots", "survival feature", "Parrots don't get of your shoulders until you receive damage"), + //!rule("growingUpWallJump", "fix", "Mobs growing up won't glitch into walls or go through fences"), + //!rule("reloadSuffocationFix", "fix experimental", "Won't let mobs glitch into blocks when reloaded.") + // .extraInfo("Can cause slight differences in mobs behaviour"), + rule("xpNoCooldown", "creative", "Players absorb XP instantly, without delay"), + rule("combineXPOrbs", "creative", "XP orbs combine with other into bigger orbs"), + rule("stackableShulkerBoxes", "survival", "Empty shulker boxes can stack to 64 when dropped on the ground") + .extraInfo("To move them around between inventories, use shift click to move entire stacks"), + rule("explosionNoBlockDamage", "tnt", "Explosions won't destroy blocks"), + rule("tntPrimerMomentumRemoved", "tnt", "Removes random TNT momentum when primed"), + rule("fastRedstoneDust", "experimental optimizations", "Lag optimizations for redstone dust") + .extraInfo("by Theosib").boolAccelerate().defaultFalse(), + rule("huskSpawningInTemples", "experimental feature", "Only husks spawn in desert temples").boolAccelerate(), + rule("shulkerSpawningInEndCities", "feature experimental", "Shulkers will respawn in end cities").boolAccelerate(), + rule("unloadedEntityFix", "experimental creative", "Entities pushed or moved into unloaded chunks no longer disappear"), + rule("TNTDoNotUpdate", "tnt", "TNT doesn't update when placed against a power source"), + rule("antiCheatSpeed", "creative surival", "Prevents players from rubberbanding when moving too fast"), + rule("quasiConnectivity", "creative", "Pistons, droppers and dispensers react if block above them is powered") + .defaultTrue(), + rule("flippinCactus", "creative survival", "Players can flip and rotate blocks when holding cactus") + .extraInfo("Doesn't cause block updates when rotated/flipped", + "Applies to pistons, observers, droppers, repeaters, stairs, glazed terracotta etc..."), + rule("hopperCounters", "commands creative survival","hoppers pointing to wool will count items passing through them") + .extraInfo("Enables /counter command, and actions while placing red and green carpets on wool blocks", + "Use /counter reset to reset the counter, and /counter to query", + "In survival, place green carpet on same color wool to query, red to reset the counters", + "Counters are global and shared between players, 16 channels available", + "Items counted are destroyed, count up to one stack per tick per hopper") + .isACommand().boolAccelerate().defaultFalse(), + rule("renewableSponges", "experimental feature", "Guardians turn into Elder Guardian when struck by lightning"), + rule("movableTileEntities", "experimental", "Pistons can push tile entities, like hoppers, chests etc.").boolAccelerate(), + rule("desertShrubs", "feature", "Saplings turn into dead shrubs in hot climates and no water access when it attempts to grow into a tree"), + rule("silverFishDropGravel", "experimental", "Silverfish drop a gravel item when breaking out of a block"), + rule("summonNaturalLightning","creative", "summoning a lightning bolt has all the side effects of natural lightning"), + rule("commandSpawn", "commands", "Enables /spawn command for spawn tracking").isACommand(), + rule("commandTick", "commands", "Enables /tick command to control game speed").isACommand(), + rule("commandLog", "commands", "Enables /log command to monitor events in the game via chat and overlays").isACommand(), + rule("commandDistance", "commands", "Enables /distance command to measure in game distance between points").isACommand() + .extraInfo("Also enables brown carpet placement action if 'carpets' rule is turned on as well"), + rule("commandInfo", "commands", "Enables /info command for blocks and entities").isACommand() + .extraInfo("Also enables gray carpet placement action ") + .extraInfo("and yellow carpet placement action for entities if 'carpets' rule is turned on as well"), + rule("commandCameramode", "commands", "Enables /c and /s commands to quickly switch between camera and survival modes").isACommand() + .extraInfo("/c and /s commands are available to all players regardless of their permission levels"), + rule("commandPerimeterInfo", "commands", "Enables /perimeterinfo command").isACommand() + .extraInfo("... that scans the area around the block for potential spawnable spots"), + rule("commandDraw", "commands", "Enables /draw commands").isACommand() + .extraInfo("... allows for drawing simple shapes"), + rule("commandScript", "commands", "Enables /script command").isACommand() + .extraInfo("a powerful in-game scripting API"), + rule("commandPlayer", "commands", "Enables /player command to control/spawn players").isACommand(), + rule("carpets", "survival", "Placing carpets may issue carpet commands for non-op players"), + rule("missingTools", "survival", "Pistons, Glass and Sponge can be broken faster with their appropriate tools"), + rule("portalCaching", "survival experimental", "Alternative, persistent caching strategy for nether portals"), + rule("calmNetherFires", "experimental", "Permanent fires don't schedule random updates"), + rule("fillUpdates", "creative", "fill/clone/setblock and structure blocks cause block updates").defaultTrue(), + rule("pushLimit", "creative","Customizable piston push limit") + .choices("12","10 12 14 100").setNotStrict().numAccelerate(), + rule("railPowerLimit", "creative", "Customizable powered rail power range") + .choices("9","9 15 30").setNotStrict().validate( (s) -> + railPowerLimitAdjusted = CarpetSettings.getInt("railPowerLimit") - 1), + rule("fillLimit", "creative","Customizable fill/clone volume limit") + .choices("32768","32768 250000 1000000").setNotStrict(), + rule("maxEntityCollisions", "optimizations", "Customizable maximal entity collision limits, 0 for no limits") + .choices("0","0 1 20").setNotStrict(), + //???rule("pistonGhostBlocksFix", "fix", "Fix for piston ghost blocks") + // .extraInfo("true(serverOnly) option works with all clients, including vanilla", + // "clientAndServer option requires compatible carpet clients and messes up flying machines") + // .choices("false","false true clientAndServer"), + //???rule("waterFlow", "optimizations", "fixes water flowing issues") + // .choices("vanilla","vanilla optimized correct"), + rule("sleepingThreshold", "experimental", "The percentage of required sleeping players to skip the night") + .extraInfo("Use values from 0 to 100, 100 for default (all players needed)") + .choices("100","0 10 50 100").setNotStrict(), + rule("customMOTD", "creative","Sets a different motd message on client trying to connect to the server") + .extraInfo("use '_' to use the startup setting from server.properties") + .choices("_","_").setNotStrict(), + rule("rotatorBlock", "experimental", "Cactus in dispensers rotates blocks.") + .extraInfo("Cactus in a dispenser gives the dispenser the ability to rotate the blocks " + + "that are in front of it anti-clockwise if possible."), + rule("viewDistance", "creative", "Changes the view distance of the server.") + .extraInfo("Set to 0 to not override the value in server settings.") + .choices("0", "0 12 16 32 64").setNotStrict() + .validate( (s) -> { + int viewDistance = getInt("viewDistance"); + if (CarpetServer.minecraft_server.isDedicated()) + { + if (viewDistance < 2) + { + viewDistance = ((DedicatedServer) CarpetServer.minecraft_server).getProperties().viewDistance; + } + if (viewDistance > 64) + { + viewDistance = 64; + } + if (viewDistance != CarpetServer.minecraft_server.getPlayerManager().getViewDistance()) + CarpetServer.minecraft_server.getPlayerManager().setViewDistance(viewDistance, viewDistance); + } + else + { + CarpetSettings.get(s).setForce("0"); + Messenger.print_server_message(CarpetServer.minecraft_server, "view distance can only be changed on a server"); + } + }), + /*rule("disableSpawnChunks", "creative", "Removes the spawn chunks.") + .validate((s) -> { + if (!CarpetSettings.getBool("disableSpawnChunks")) { + ServerWorld overworld = CarpetServer.minecraft_server.getWorld(DimensionType.OVERWORLD); + if (overworld == null) + return; + + List chunkList = SpawnChunks.listIncludedChunks(overworld); + + // Reused from MinecraftServer initialWorldChunkLoad + CompletableFuture completablefuture = overworld.getChunkProvider().loadChunks(chunkList, (c) -> {}); + while (!completablefuture.isDone()) { + try { + completablefuture.get(1L, TimeUnit.SECONDS); + } catch (InterruptedException interruptedexception) { + throw new RuntimeException(interruptedexception); + } catch (ExecutionException executionexception) { + if (executionexception.getCause() instanceof RuntimeException) { + throw (RuntimeException) executionexception.getCause(); + } + + throw new RuntimeException(executionexception.getCause()); + } catch (TimeoutException var22) { + } + } + } + }).boolAccelerate(),*/ + rule("kelpGenerationGrowLimit", "feature", "limits growth limit of newly naturally generated kelp to this amount of blocks") + .choices("25", "0 2 25").setNotStrict(), + rule("renewableCoral", "feature", "Coral structures will grow with bonemeal from coral plants"), + rule("placementRotationFix", "fix", "fixes block placement rotation issue when player rotates quickly while placing blocks"), + rule("leadFix", "fix", "Fixes leads breaking/becoming invisible in unloaded chunks") + .extraInfo("You may still get visibly broken leash links on the client side, but server side the link is still there."), + }; + for (CarpetSettingEntry rule: RuleList) + { + settings_store.put(rule.getName(), rule); + } + } + + private static void notifyPlayersCommandsChanged() + { + if (CarpetServer.minecraft_server == null) + { + return; + } + for (ServerPlayerEntity entityplayermp : CarpetServer.minecraft_server.getPlayerManager().getPlayerList()) + { + CarpetServer.minecraft_server.getCommandManager().sendCommandTree(entityplayermp); + } + } + + public static void apply_settings_from_conf(MinecraftServer server) + { + Map conf = read_conf(server); + boolean is_locked = locked; + locked = false; + if (is_locked) + { + LOG.info("[CM]: Carpet Mod is locked by the administrator"); + } + for (String key: conf.keySet()) + { + set(key, conf.get(key)); + LOG.info("[CM]: loaded setting "+key+" as "+conf.get(key)+" from carpet.conf"); + } + locked = is_locked; + } + private static void disable_commands_by_default() + { + for (CarpetSettingEntry entry: settings_store.values()) + { + if (entry.getName().startsWith("command")) + { + entry.defaultFalse(); + } + } + } + + private static Map read_conf(MinecraftServer server) + { + try + { + File settings_file = server.getLevelStorage().resolveFile(server.getLevelName(), "carpet.conf"); + BufferedReader b = new BufferedReader(new FileReader(settings_file)); + String line = ""; + Map result = new HashMap(); + while ((line = b.readLine()) != null) + { + line = line.replaceAll("\\r|\\n", ""); + if ("locked".equalsIgnoreCase(line)) + { + disable_commands_by_default(); + locked = true; + } + String[] fields = line.split("\\s+",2); + if (fields.length > 1) + { + if (get(fields[0])==FalseEntry) + { + LOG.error("[CM]: Setting " + fields[0] + " is not a valid - ignoring..."); + continue; + } + if (!(Arrays.asList(get(fields[0]).getOptions()).contains(fields[1])) && get(fields[0]).isStrict()) + { + LOG.error("[CM]: The value of " + fields[1] + " for " + fields[0] + " is not valid - ignoring..."); + continue; + } + result.put(fields[0],fields[1]); + } + } + b.close(); + return result; + } + catch(FileNotFoundException e) + { + return new HashMap<>(); + } + catch (IOException e) + { + e.printStackTrace(); + return new HashMap<>(); + } + + } + private static void write_conf(MinecraftServer server, Map values) + { + if (locked) return; + try + { + File settings_file = server.getLevelStorage().resolveFile(server.getLevelName(), "carpet.conf"); + FileWriter fw = new FileWriter(settings_file); + for (String key: values.keySet()) + { + fw.write(key+" "+values.get(key)+"\n"); + } + fw.close(); + } + catch (IOException e) + { + e.printStackTrace(); + LOG.error("[CM]: failed write the carpet.conf"); + } + } + + // stores different defaults in the file + public static boolean setDefaultRule(MinecraftServer server, String setting_name, String string_value) + { + if (locked) return false; + if (settings_store.containsKey(setting_name)) + { + Map conf = read_conf(server); + conf.put(setting_name, string_value); + write_conf(server, conf); + set(setting_name,string_value); + return true; + } + return false; + } + // removes overrides of the default values in the file + public static boolean removeDefaultRule(MinecraftServer server, String setting_name) + { + if (locked) return false; + if (settings_store.containsKey(setting_name)) + { + Map conf = read_conf(server); + conf.remove(setting_name); + write_conf(server, conf); + set(setting_name,get(setting_name).getDefault()); + return true; + } + return false; + } + + //changes setting temporarily + public static boolean set(String setting_name, String string_value) + { + CarpetSettingEntry en = get(setting_name); + if (en != FalseEntry) + { + en.set(string_value); + //reload_stat(setting_name); + //CarpetClientRuleChanger.updateCarpetClientsRule(setting_name, string_value); + return true; + } + return false; + } + + // used as CarpetSettings.get("pushLimit").integer to get the int value of push limit + public static CarpetSettingEntry get(String setting_name) + { + if (!settings_store.containsKey(setting_name) ) + { + return FalseEntry; + } + return settings_store.get(setting_name); + } + + public static int getInt(String setting_name) + { + return get(setting_name).getIntegerValue(); + } + public static boolean getBool(String setting_name) + { + return get(setting_name).getBoolValue(); + } + public static String getString(String setting_name) { return get(setting_name).getStringValue(); } + public static float getFloat(String setting_name) + { + return get(setting_name).getFloatValue(); + } + public static CarpetSettingEntry[] findAll(String tag) + { + ArrayList res = new ArrayList(); + for (String rule: settings_store.keySet().stream().sorted().collect(Collectors.toList())) + { + if (tag == null || settings_store.get(rule).matches(tag)) + { + res.add(settings_store.get(rule)); + } + } + return res.toArray(new CarpetSettingEntry[0]); + } + public static CarpetSettingEntry[] find_nondefault(MinecraftServer server) + { + ArrayList res = new ArrayList(); + Map defaults = read_conf(server); + for (String rule: settings_store.keySet().stream().sorted().collect(Collectors.toList())) + { + if (!settings_store.get(rule).isDefault() || defaults.containsKey(rule)) + { + res.add(settings_store.get(rule)); + } + } + return res.toArray(new CarpetSettingEntry[0]); + } + public static CarpetSettingEntry[] findStartupOverrides(MinecraftServer server) + { + ArrayList res = new ArrayList(); + if (locked) return res.toArray(new CarpetSettingEntry[0]); + Map defaults = read_conf(server); + for (String rule: settings_store.keySet().stream().sorted().collect(Collectors.toList())) + { + if (defaults.containsKey(rule)) + { + res.add(settings_store.get(rule)); + } + } + return res.toArray(new CarpetSettingEntry[0]); + } + public static String[] toStringArray(CarpetSettingEntry[] entry_array) + { + return Stream.of(entry_array).map(CarpetSettingEntry::getName).toArray( String[]::new ); + } + public static ArrayList getAllCarpetSettings() + { + ArrayList res = new ArrayList(); + for (String rule: settings_store.keySet().stream().sorted().collect(Collectors.toList())) + { + res.add(settings_store.get(rule)); + } + + return res; + } + public static CarpetSettingEntry getCarpetSetting(String rule) + { + return settings_store.get(rule); + } + + public static void resetToVanilla() + { + for (String rule: settings_store.keySet()) + { + get(rule).reset(); + //reload_stat(rule); + } + } + + public static void resetToUserDefaults(MinecraftServer server) + { + resetToVanilla(); + apply_settings_from_conf(server); + } + + public static void resetToCreative() + { + resetToBugFixes(); + set("fillLimit","500000"); + set("fillUpdates","false"); + set("portalCreativeDelay","true"); + set("portalCaching","true"); + set("flippinCactus","true"); + set("hopperCounters","true"); + set("antiCheatSpeed","true"); + + } + public static void resetToSurvival() + { + resetToBugFixes(); + set("ctrlQCraftingFix","true"); + set("persistentParrots", "true"); + set("stackableEmptyShulkerBoxes","true"); + set("flippinCactus","true"); + set("hopperCounters","true"); + set("carpets","true"); + set("missingTools","true"); + set("portalCaching","true"); + set("miningGhostBlocksFix","true"); + } + public static void resetToBugFixes() + { + resetToVanilla(); + set("portalSuffocationFix","true"); + set("pistonGhostBlocksFix","serverOnly"); + set("portalTeleportationFix","true"); + set("entityDuplicationFix","true"); + set("inconsistentRedstoneTorchesFix","true"); + set("llamaOverfeedingFix","true"); + set("invisibilityFix","true"); + set("potionsDespawnFix","true"); + set("liquidsNotRandom","true"); + set("mobsDontControlMinecarts","true"); + set("breedingMountingDisabled","true"); + set("growingUpWallJump","true"); + set("reloadSuffocationFix","true"); + set("watchdogFix","true"); + set("unloadedEntityFix","true"); + set("hopperDuplicationFix","true"); + set("calmNetherFires","true"); + } + + public static class CarpetSettingEntry + { + private String rule; + private String string; + private int integer; + private boolean bool; + private float flt; + private String[] options; + private String[] tags; + private String toast; + private String[] extra_info; + private String default_string_value; + private boolean isFloat; + private boolean strict; + private List> validators; + + //factory + public static CarpetSettingEntry create(String rule_name, String tags, String toast) + { + return new CarpetSettingEntry(rule_name, tags, toast); + } + private CarpetSettingEntry(String rule_name, String tags_string, String toast_string) + { + set("false"); + rule = rule_name; + default_string_value = string; + tags = tags_string.split("\\s+"); // never empty + toast = toast_string; + options = "true false".split("\\s+"); + isFloat = false; + extra_info = null; + strict = true; + validators = null; + } + public CarpetSettingEntry defaultTrue() + { + set("true"); + default_string_value = string; + options = "true false".split("\\s+"); + return this; + } + public CarpetSettingEntry validate(Consumer method) + { + if (validators == null) + { + validators = new ArrayList<>(); + } + validators.add(method); + return this; + } + public CarpetSettingEntry boolAccelerate() + { + Consumer validator = (name) -> { + try + { + Field f = CarpetSettings.class.getDeclaredField("b_"+name); + f.setBoolean(null, CarpetSettings.getBool(name)); + } + catch (IllegalAccessException e) + { + CarpetSettings.LOG.error("[CM Error] rule "+name+" has wrong access to boolean accelerator"); + } + catch (NoSuchFieldException e) + { + CarpetSettings.LOG.error("[CM Error] rule "+name+" doesn't have a boolean accelerator"); + } + }; + return validate(validator); + } + public CarpetSettingEntry numAccelerate() + { + Consumer validator = (name) -> { + try + { + Field f = CarpetSettings.class.getDeclaredField("n_"+name); + if (CarpetSettings.get(name).isFloat) + { + f.setDouble(null, (double) CarpetSettings.getFloat(name)); + } + else + { + f.setInt(null, CarpetSettings.getInt(name)); + } + } + catch (IllegalAccessException e) + { + CarpetSettings.LOG.error("[CM Error] rule "+name+" wrong type of numerical accelerator"); + } + catch (NoSuchFieldException e) + { + CarpetSettings.LOG.error("[CM Error] rule "+name+" doesn't have a numerical accelerator"); + } + }; + return validate(validator); + } + + + public CarpetSettingEntry isACommand() + { + return this.defaultTrue().validate( (s) -> notifyPlayersCommandsChanged()); + } + + public CarpetSettingEntry defaultFalse() + { + set("false"); + default_string_value = string; + options = "true false".split("\\s+"); + return this; + } + + public CarpetSettingEntry choices(String defaults, String options_string) + { + set(defaults); + default_string_value = string; + options = options_string.split("\\s+"); + return this; + } + public CarpetSettingEntry extraInfo(String ... extra_info_string) + { + extra_info = extra_info_string; + return this; + } + + public CarpetSettingEntry setFloat() + { + isFloat = true; + strict = false; + return this; + } + + public CarpetSettingEntry setNotStrict() + { + strict = false; + return this; + } + + private void set(String unparsed) + { + setForce(unparsed); + if (validators != null) + { + validators.forEach((r) -> r.accept(this.getName())); + } + } + private void setForce(String unparsed) + { + string = unparsed; + try + { + integer = Integer.parseInt(unparsed); + } + catch(NumberFormatException e) + { + integer = 0; + } + try + { + flt = Float.parseFloat(unparsed); + } + catch(NumberFormatException e) + { + flt = 0.0F; + } + bool = (integer > 0) || Boolean.parseBoolean(unparsed); + } + + //accessors + public boolean isDefault() { return string.equals(default_string_value); } + public String getDefault() { return default_string_value; } + public String toString() { return rule + ": " + string; } + public String getToast() { return toast; } + public String[] getInfo() { return extra_info == null?new String[0]:extra_info; } + public String[] getOptions() { return options;} + public String[] getTags() { return tags; } + public String getName() { return rule; } + public String getStringValue() { return string; } + public boolean getBoolValue() { return bool; } + public int getIntegerValue() { return integer; } + public float getFloatValue() { return flt; } + public boolean getIsFloat() { return isFloat;} + + //actual stuff + public void reset() + { + set(default_string_value); + } + + public boolean matches(String tag) + { + tag = tag.toLowerCase(); + if (rule.toLowerCase().contains(tag)) + { + return true; + } + for (String t: tags) + { + if (tag.equalsIgnoreCase(t)) + { + return true; + } + } + return false; + } + public String getNextValue() + { + int i; + for(i = 0; i < options.length; i++) + { + if(options[i].equals(string)) + { + break; + } + } + i++; + return options[i % options.length]; + } + + public boolean isStrict() + { + return strict; + } + } +} + diff --git a/src/main/java/carpet/commands/CameraModeCommand.java b/src/main/java/carpet/commands/CameraModeCommand.java new file mode 100644 index 00000000..fc9a358b --- /dev/null +++ b/src/main/java/carpet/commands/CameraModeCommand.java @@ -0,0 +1,66 @@ +package carpet.commands; + +import carpet.CarpetSettings; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.command.arguments.EntityArgumentType; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.world.GameMode; + +import static net.minecraft.server.command.CommandManager.argument; +import static net.minecraft.server.command.CommandManager.literal; + +public class CameraModeCommand +{ + public static void register(CommandDispatcher dispatcher) + { + LiteralArgumentBuilder camera = literal("c"). + requires((player) -> CarpetSettings.getBool("commandCameramode")). + executes((c) -> cameraMode(c.getSource(), c.getSource().getPlayer())). + then(argument("player", EntityArgumentType.player()). + executes( (c) -> cameraMode(c.getSource(), EntityArgumentType.getPlayer(c, "player")))); + + LiteralArgumentBuilder survival = literal("s"). + requires((player) -> CarpetSettings.getBool("commandCameramode")). + executes((c) -> survivalMode( + c.getSource(), + c.getSource().getPlayer())). + then(argument("player", EntityArgumentType.player()). + executes( (c) -> survivalMode(c.getSource(), EntityArgumentType.getPlayer(c, "player")))); + + dispatcher.register(camera); + dispatcher.register(survival); + } + private static boolean iCanHasPermissions(ServerCommandSource source, PlayerEntity player) + { + try + { + return source.hasPermissionLevel(2) || source.getPlayer() == player; + } + catch (CommandSyntaxException e) + { + return true; // shoudn't happen because server has all permissions anyways + } + } + private static int cameraMode(ServerCommandSource source, PlayerEntity player) + { + if (!(iCanHasPermissions(source, player))) return 0; + player.setGameMode(GameMode.SPECTATOR); + player.addPotionEffect(new StatusEffectInstance(StatusEffects.NIGHT_VISION, 999999, 0, false, false)); + player.addPotionEffect(new StatusEffectInstance(StatusEffects.CONDUIT_POWER, 999999, 0, false, false)); + return 1; + } + private static int survivalMode(ServerCommandSource source, PlayerEntity player) + { + if (!(iCanHasPermissions(source, player))) return 0; + player.setGameMode(GameMode.SURVIVAL); + player.removePotionEffect(StatusEffects.NIGHT_VISION); + player.removePotionEffect(StatusEffects.CONDUIT_POWER); + return 1; + } + +} diff --git a/src/main/java/carpet/commands/DrawCommand.java b/src/main/java/carpet/commands/DrawCommand.java new file mode 100644 index 00000000..3ec9e7fe --- /dev/null +++ b/src/main/java/carpet/commands/DrawCommand.java @@ -0,0 +1,165 @@ +package carpet.commands; + +import carpet.CarpetSettings; +import carpet.utils.Messenger; +import com.google.common.collect.Lists; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import net.minecraft.block.Block; +import net.minecraft.block.pattern.CachedBlockPosition; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.command.arguments.BlockPosArgumentType; +import net.minecraft.command.arguments.BlockPredicateArgumentType; +import net.minecraft.command.arguments.BlockStateArgument; +import net.minecraft.command.arguments.BlockStateArgumentType; +import net.minecraft.inventory.Inventory; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.server.world.ServerWorld; + +import java.util.List; +import java.util.function.Predicate; + +import static net.minecraft.server.command.CommandManager.argument; +import static net.minecraft.server.command.CommandManager.literal; + +public class DrawCommand +{ + public static void register(CommandDispatcher dispatcher) + { + LiteralArgumentBuilder command = literal("draw"). + requires((player) -> CarpetSettings.getBool("commandDraw")). + then(literal("sphere"). + then(argument("center",BlockPosArgumentType.create()). + then(argument("radius",IntegerArgumentType.integer(1)). + then(argument("block",BlockStateArgumentType.create()). + executes((c)-> drawCircle( + c.getSource(), + BlockPosArgumentType.getBlockPos(c, "center"), + IntegerArgumentType.getInteger(c, "radius"), + BlockStateArgumentType.getBlockState (c,"block"), + null + ) + ). + then(literal("replace"). + then(argument("filter",BlockPredicateArgumentType.create()) + .executes((c)-> drawCircle( + c.getSource(), + BlockPosArgumentType.getBlockPos(c, "center"), + IntegerArgumentType.getInteger(c, "radius"), + BlockStateArgumentType.getBlockState(c,"block"), + BlockPredicateArgumentType.getBlockPredicate(c, + "filter") + )))))))); + dispatcher.register(command); + } + + + private static int drawCircle(ServerCommandSource source, BlockPos pos, int radius, BlockStateArgument block, + Predicate replacement) + { + return drawCircle(source, pos, (double)radius, (double)radius, (double)radius, block, replacement, false); + } + private static int drawCircle(ServerCommandSource source, BlockPos pos, double radiusX, double radiusY, double radiusZ, + BlockStateArgument block, Predicate replacement, boolean solid) + { + int affected = 0; + ServerWorld world = source.getWorld(); + + radiusX += 0.5; + radiusY += 0.5; + radiusZ += 0.5; + + final double invRadiusX = 1 / radiusX; + final double invRadiusY = 1 / radiusY; + final double invRadiusZ = 1 / radiusZ; + + final int ceilRadiusX = (int) Math.ceil(radiusX); + final int ceilRadiusY = (int) Math.ceil(radiusY); + final int ceilRadiusZ = (int) Math.ceil(radiusZ); + + BlockPos.Mutable mbpos = new BlockPos.Mutable(pos); + List list = Lists.newArrayList(); + + double nextXn = 0; + + forX: for (int x = 0; x <= ceilRadiusX; ++x) { + final double xn = nextXn; + nextXn = (x + 1) * invRadiusX; + double nextYn = 0; + forY: for (int y = 0; y <= ceilRadiusY; ++y) { + final double yn = nextYn; + nextYn = (y + 1) * invRadiusY; + double nextZn = 0; + forZ: for (int z = 0; z <= ceilRadiusZ; ++z) { + final double zn = nextZn; + nextZn = (z + 1) * invRadiusZ; + + double distanceSq = lengthSq(xn, yn, zn); + if (distanceSq > 1) { + if (z == 0) { + if (y == 0) { + break forX; + } + break forY; + } + break forZ; + } + + if (!solid) { + if (lengthSq(nextXn, yn, zn) <= 1 && lengthSq(xn, nextYn, zn) <= 1 && lengthSq(xn, yn, nextZn) <= 1) { + continue; + } + } + + for (int xmod = -1; xmod < 2; xmod+= 2) + { + for (int ymod = -1; ymod < 2; ymod += 2) + { + for (int zmod = -1; zmod < 2; zmod += 2) + { + mbpos.set(pos.getX()+xmod*x, pos.getY()+ymod*y, pos.getZ()+zmod*z); + if (replacement == null || replacement.test( + new CachedBlockPosition( world, mbpos, true))) + { + BlockEntity tileentity = world.getBlockEntity(mbpos); + if (tileentity instanceof Inventory) + { + ((Inventory)tileentity).clear(); + } + + if (block.setBlockState( + world, + mbpos, + 2 | (CarpetSettings.getBool("fillUpdates") ?0:1024) + )) + { + list.add(mbpos.toImmutable()); + ++affected; + } + } + } + } + } + } + } + } + if (CarpetSettings.getBool("fillUpdates")) + { + + for (BlockPos blockpos1 : list) + { + Block blokc = world.getBlockState(blockpos1).getBlock(); + world.updateNeighbors(blockpos1, blokc); // or always version???? + } + } + Messenger.m(source, "gi Filled "+affected+" blocks"); + + return 1; + } + private static double lengthSq(double x, double y, double z) + { + return (x * x) + (y * y) + (z * z); + } +} diff --git a/src/main/java/carpet/utils/Messenger.java b/src/main/java/carpet/utils/Messenger.java index 509933a3..f1031ca4 100644 --- a/src/main/java/carpet/utils/Messenger.java +++ b/src/main/java/carpet/utils/Messenger.java @@ -9,8 +9,8 @@ import net.minecraft.network.chat.TextComponent; import net.minecraft.ChatFormat; import net.minecraft.network.chat.BaseComponent; import net.minecraft.server.MinecraftServer; -import net.minecraft.network.chat.ClickEvent;// text.event.ClickEvent; -import net.minecraft.network.chat.HoverEvent;// text.event.HoverEvent; +import net.minecraft.network.chat.ClickEvent; +import net.minecraft.network.chat.HoverEvent; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; diff --git a/src/main/java/net/fabricmc/example/ExampleMod.java b/src/main/java/net/fabricmc/example/ExampleMod.java deleted file mode 100644 index e5ed082e..00000000 --- a/src/main/java/net/fabricmc/example/ExampleMod.java +++ /dev/null @@ -1,14 +0,0 @@ -package net.fabricmc.example; - -import net.fabricmc.api.ModInitializer; - -public class ExampleMod implements ModInitializer { - @Override - public void onInitialize() { - // This code runs as soon as Minecraft is in a mod-load-ready state. - // However, some things (like resources) may still be uninitialized. - // Proceed with mild caution. - - System.out.println("Hello Fabric world!"); - } -} diff --git a/src/main/java/net/fabricmc/example/mixin/ExampleMixin.java b/src/main/java/net/fabricmc/example/mixin/ExampleMixin.java deleted file mode 100644 index 0fc8f682..00000000 --- a/src/main/java/net/fabricmc/example/mixin/ExampleMixin.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.fabricmc.example.mixin; - -import net.minecraft.client.MinecraftClient; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(MinecraftClient.class) -public class ExampleMixin { - @Inject(at = @At("HEAD"), method = "init()V") - private void init(CallbackInfo info) { - System.out.println("This line is printed by an example mod mixin!"); - } -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 26ac594c..9694d372 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -3,23 +3,22 @@ "id": "modid", "version": "${version}", - "name": "Example Mod", + "name": "Carpet Mod in Fabric", "description": "This is an example description! Tell everyone what your mod is about!", "authors": [ "Me!" ], "contact": { "homepage": "https://fabricmc.net/", - "sources": "https://github.com/FabricMC/fabric-example-mod" + "sources": "https://github.com/gnembon/fabric-carpet" }, - "license": "CC0-1.0", + "license": "GNU LGPL V3", "icon": "assets/modid/icon.png", "environment": "*", "entrypoints": { "main": [ - "net.fabricmc.example.ExampleMod" ] }, "mixins": [