diff --git a/.github/workflows/merge-docs.yml b/.github/workflows/merge-docs.yml index 77ce22ec..11dccee0 100644 --- a/.github/workflows/merge-docs.yml +++ b/.github/workflows/merge-docs.yml @@ -5,7 +5,6 @@ on: - master paths: - "docs/**" - - "!docs/scarpet/Full.md" jobs: Scarpet: runs-on: ubuntu-latest diff --git a/.github/workflows/rules-to-wiki.yml b/.github/workflows/rules-to-wiki.yml index 07f5e4e6..76e25bf3 100644 --- a/.github/workflows/rules-to-wiki.yml +++ b/.github/workflows/rules-to-wiki.yml @@ -21,25 +21,6 @@ jobs: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: ${{ runner.os }}-gradle - - name: Generate RulePrinter class - run: | - cd src/main/java/carpet/utils - echo " - package carpet.utils; - import carpet.CarpetServer; - import carpet.settings.SettingsManager; - import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; - import java.lang.System; - public class RulePrinter implements PreLaunchEntrypoint { - @Override - public void onPreLaunch() { - CarpetServer.onGameStarted(); - CarpetServer.settingsManager.printAllRulesToLog(null); - System.exit(0); - } - } - " > RulePrinter.java - cd ../../../../../ - name: Replace fabric.mod.json run: | cd src/main/resources diff --git a/.gitignore b/.gitignore index fe54eae4..aca7bbba 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,9 @@ publish/ *.ipr *.iws +# eclipse +*.launch + # vscode .settings/ diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index 5cecceeb..41c83e2e 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -1910,7 +1910,7 @@ Here is a list of built-in types, with their return value formats, as well as a * `'anchor'`: string of `feet` or `eyes`. * `'entitytype'`: string representing a type of entity * `'floatrange'`: pair of two numbers where one is smaller than the other - * `'players'`: returning a list of valid player entities. If configured with `'single'` returns only one player or `null`. + * `'players'`: returning a list of valid player name string, logged in or not. If configured with `'single'` returns only one player or `null`. * `'intrange'`: same as `'floatrange'`, but requiring integers. * `'enchantment'`: name of an enchantment * `'item'`: triple of item type, count of 1, and nbt. diff --git a/docs/scarpet/api/Overview.md b/docs/scarpet/api/Overview.md index 1a8142c5..3e6ddbdf 100644 --- a/docs/scarpet/api/Overview.md +++ b/docs/scarpet/api/Overview.md @@ -211,7 +211,7 @@ Here is a list of built-in types, with their return value formats, as well as a * `'anchor'`: string of `feet` or `eyes`. * `'entitytype'`: string representing a type of entity * `'floatrange'`: pair of two numbers where one is smaller than the other - * `'players'`: returning a list of valid player entities. If configured with `'single'` returns only one player or `null`. + * `'players'`: returning a list of valid player name string, logged in or not. If configured with `'single'` returns only one player or `null`. * `'intrange'`: same as `'floatrange'`, but requiring integers. * `'enchantment'`: name of an enchantment * `'item'`: triple of item type, count of 1, and nbt. diff --git a/src/main/java/carpet/CarpetExtension.java b/src/main/java/carpet/CarpetExtension.java index 3a49951a..c7d30457 100644 --- a/src/main/java/carpet/CarpetExtension.java +++ b/src/main/java/carpet/CarpetExtension.java @@ -20,50 +20,104 @@ public interface CarpetExtension * Runs once per loaded world once the server / gamerules etc are fully loaded * but before worlds are loaded * Can be loaded multiple times in SinglePlayer + * + * @param server The {@link MinecraftServer} instance that loaded */ default void onServerLoaded(MinecraftServer server) {} /** * Runs once per loaded world once the World files are fully loaded * Can be loaded multiple times in SinglePlayer + * + * @param server The current {@link MinecraftServer} instance + * */ default void onServerLoadedWorlds(MinecraftServer server) {} /** * Runs once per game tick, as a first thing in the tick + * + * @param server The current {@link MinecraftServer} instance + * */ default void onTick(MinecraftServer server) {} /** * Register your own commands right after vanilla commands are added * If that matters for you + * + * @param dispatcher The current {@link CommandSource} dispatcher + * where you should register your commands + * */ default void registerCommands(CommandDispatcher dispatcher) {} /** * Provide your own custom settings manager managed in the same way as base /carpet * command, but separated to its own command as defined in SettingsManager. + * + * @return Your custom {@link SettingsManager} instance to be managed by Carpet + * */ default SettingsManager customSettingsManager() {return null;} /** - * todiddalidoo + * Event that gets called when a player logs in + * + * @param player The {@link ServerPlayerEntity} that logged in + * */ default void onPlayerLoggedIn(ServerPlayerEntity player) {} /** - * todiddalidoo + * Event that gets called when a player logs out + * + * @param player The {@link ServerPlayerEntity} that logged out + * */ default void onPlayerLoggedOut(ServerPlayerEntity player) {} + /** + * Event that gets called when the server closes. + * Can be called multiple times in singleplayer + * + * @param server The {@link MinecraftServer} that is closing + * + */ default void onServerClosed(MinecraftServer server) {} + /** + * Event that gets called when the server reloads (usually + * when running the /reload command) + * + * @param server The {@link MinecraftServer} that is reloading + * + */ default void onReload(MinecraftServer server) {} + /** + * Event that gets called when a player logs in + * + * @return A {@link String} usually being the extension's id + * + */ default String version() {return null;} + /** + * Called when registering custom loggers + * + */ default void registerLoggers() {} + /** + * Method for Carpet to get the translations for extension's + * rules. + * + * @param lang A {@link String} being the language id selected by the user + * @return A {@link Map} containing the string key with it's + * respective translation {@link String} or {@link null} if not available + * + */ default Map canHasTranslations(String lang) { return null;} /** @@ -79,7 +133,7 @@ public interface CarpetExtension * * EntityEventsGroup.Event class: to handle `entity_event('foo', ...)` type of events * - * @param expression: Passed CarpetExpression to add built-in functions to + * @param expression Passed {@link CarpetExpression} to add built-in functions to */ default void scarpetApi(CarpetExpression expression) {} diff --git a/src/main/java/carpet/CarpetServer.java b/src/main/java/carpet/CarpetServer.java index 265821af..4b94b3fa 100644 --- a/src/main/java/carpet/CarpetServer.java +++ b/src/main/java/carpet/CarpetServer.java @@ -7,6 +7,7 @@ import java.util.Random; import carpet.commands.*; import carpet.network.ServerNetworkHandler; +import carpet.helpers.HopperCounter; import carpet.helpers.TickSpeed; import carpet.logging.LoggerRegistry; import carpet.script.CarpetScriptServer; @@ -44,6 +45,12 @@ public class CarpetServer implements ClientModInitializer,DedicatedServerModInit } // Separate from onServerLoaded, because a server can be loaded multiple times in singleplayer + /** + * Registers a {@link CarpetExtension} to be managed by Carpet.
+ * Should be called before Carpet's startup, like in Fabric Loader's + * {@link net.fabricmc.api.ModInitializer} entrypoint + * @param extension The instance of a {@link CarpetExtension} to be registered + */ public static void manageExtension(CarpetExtension extension) { extensions.add(extension); @@ -85,6 +92,7 @@ public class CarpetServer implements ClientModInitializer,DedicatedServerModInit { extensions.forEach(e -> e.onServerLoadedWorlds(minecraftServer)); scriptServer.initializeForWorld(); + HopperCounter.resetAll(minecraftServer); } public static void tick(MinecraftServer server) diff --git a/src/main/java/carpet/commands/TickCommand.java b/src/main/java/carpet/commands/TickCommand.java index 696512e2..27c6ef27 100644 --- a/src/main/java/carpet/commands/TickCommand.java +++ b/src/main/java/carpet/commands/TickCommand.java @@ -35,7 +35,7 @@ public class TickCommand executes((c) -> setTps(c.getSource(), getFloat(c, "rate"))))). then(literal("warp"). executes( (c)-> setWarp(c.getSource(), 0, null)). - then(argument("ticks", integer(0,4000000)). + then(argument("ticks", integer(0)). suggests( (c, b) -> suggestMatching(new String[]{"3600","72000"},b)). executes((c) -> setWarp(c.getSource(), getInteger(c,"ticks"), null)). then(argument("tail command", greedyString()). @@ -143,4 +143,3 @@ public class TickCommand } } - diff --git a/src/main/java/carpet/mixins/ArmorStandEntity_scarpetMarkerMixin.java b/src/main/java/carpet/mixins/ArmorStandEntity_scarpetMarkerMixin.java index 1547a91b..193532a6 100644 --- a/src/main/java/carpet/mixins/ArmorStandEntity_scarpetMarkerMixin.java +++ b/src/main/java/carpet/mixins/ArmorStandEntity_scarpetMarkerMixin.java @@ -1,7 +1,6 @@ package carpet.mixins; import carpet.CarpetServer; -import carpet.CarpetSettings; import carpet.script.api.Auxiliary; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; diff --git a/src/main/java/carpet/mixins/ClientPlayerEntity_clientCommandMixin.java b/src/main/java/carpet/mixins/ClientPlayerEntity_clientCommandMixin.java index 94bd965b..62999f0d 100644 --- a/src/main/java/carpet/mixins/ClientPlayerEntity_clientCommandMixin.java +++ b/src/main/java/carpet/mixins/ClientPlayerEntity_clientCommandMixin.java @@ -2,6 +2,7 @@ package carpet.mixins; import carpet.CarpetServer; import carpet.network.CarpetClient; +import carpet.settings.SettingsManager; import net.minecraft.client.network.ClientPlayerEntity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -23,6 +24,10 @@ public class ClientPlayerEntity_clientCommandMixin { ClientPlayerEntity playerSource = (ClientPlayerEntity)(Object) this; CarpetServer.settingsManager.inspectClientsideCommand(playerSource.getCommandSource(), string); + CarpetServer.extensions.forEach(e -> { + SettingsManager sm = e.customSettingsManager(); + if (sm != null) sm.inspectClientsideCommand(playerSource.getCommandSource(), string); + }); } } } diff --git a/src/main/java/carpet/mixins/InfestedBlockMixin.java b/src/main/java/carpet/mixins/InfestedBlockMixin.java index 1f086b17..9f63995e 100644 --- a/src/main/java/carpet/mixins/InfestedBlockMixin.java +++ b/src/main/java/carpet/mixins/InfestedBlockMixin.java @@ -2,13 +2,11 @@ package carpet.mixins; import carpet.CarpetSettings; import net.minecraft.block.Block; -import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.InfestedBlock; import net.minecraft.item.ItemStack; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; diff --git a/src/main/java/carpet/mixins/PistonBlock_movableTEMixin.java b/src/main/java/carpet/mixins/PistonBlock_movableTEMixin.java index e8def5d4..606c78bb 100644 --- a/src/main/java/carpet/mixins/PistonBlock_movableTEMixin.java +++ b/src/main/java/carpet/mixins/PistonBlock_movableTEMixin.java @@ -19,7 +19,6 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import java.util.List; import java.util.Map; -import java.util.Set; @Mixin(PistonBlock.class) public abstract class PistonBlock_movableTEMixin extends FacingBlock diff --git a/src/main/java/carpet/mixins/PlayerEntity_creativeNoClipMixin.java b/src/main/java/carpet/mixins/PlayerEntity_creativeNoClipMixin.java index adba18ba..342783e4 100644 --- a/src/main/java/carpet/mixins/PlayerEntity_creativeNoClipMixin.java +++ b/src/main/java/carpet/mixins/PlayerEntity_creativeNoClipMixin.java @@ -3,14 +3,9 @@ package carpet.mixins; import carpet.CarpetSettings; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.MovementType; -import net.minecraft.entity.player.PlayerAbilities; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/carpet/mixins/PlayerManager_scarpetEventsMixin.java b/src/main/java/carpet/mixins/PlayerManager_scarpetEventsMixin.java index af989650..6911f8f1 100644 --- a/src/main/java/carpet/mixins/PlayerManager_scarpetEventsMixin.java +++ b/src/main/java/carpet/mixins/PlayerManager_scarpetEventsMixin.java @@ -2,7 +2,6 @@ package carpet.mixins; import net.minecraft.server.PlayerManager; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.world.dimension.DimensionType; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; diff --git a/src/main/java/carpet/mixins/ProjectileEntityMixin.java b/src/main/java/carpet/mixins/ProjectileEntityMixin.java index 9da4b575..8f49d861 100644 --- a/src/main/java/carpet/mixins/ProjectileEntityMixin.java +++ b/src/main/java/carpet/mixins/ProjectileEntityMixin.java @@ -8,7 +8,6 @@ import net.minecraft.entity.projectile.PersistentProjectileEntity; import net.minecraft.entity.projectile.ProjectileEntity; import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.EntityHitResult; -import net.minecraft.util.hit.HitResult; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/carpet/mixins/ProjectileEntity_extremeMixin.java b/src/main/java/carpet/mixins/ProjectileEntity_extremeMixin.java index a0ee0f01..c08dd633 100644 --- a/src/main/java/carpet/mixins/ProjectileEntity_extremeMixin.java +++ b/src/main/java/carpet/mixins/ProjectileEntity_extremeMixin.java @@ -2,7 +2,6 @@ package carpet.mixins; import carpet.utils.RandomTools; import net.minecraft.entity.projectile.PersistentProjectileEntity; -import net.minecraft.entity.projectile.ProjectileEntity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; diff --git a/src/main/java/carpet/mixins/ServerChunkManagerMixin.java b/src/main/java/carpet/mixins/ServerChunkManagerMixin.java index 91afbe4b..c8bfcd21 100644 --- a/src/main/java/carpet/mixins/ServerChunkManagerMixin.java +++ b/src/main/java/carpet/mixins/ServerChunkManagerMixin.java @@ -2,19 +2,13 @@ package carpet.mixins; import carpet.fakes.ServerChunkManagerInterface; import carpet.utils.SpawnReporter; -import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.minecraft.entity.SpawnGroup; import net.minecraft.server.world.ChunkTicketManager; import net.minecraft.server.world.ServerChunkManager; import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.math.BlockPos; import net.minecraft.util.registry.RegistryKey; -import net.minecraft.world.SpawnHelper; import net.minecraft.world.World; import net.minecraft.world.WorldProperties; -import net.minecraft.world.chunk.WorldChunk; -import net.minecraft.world.dimension.DimensionType; -import net.minecraft.world.level.LevelProperties; import org.apache.commons.lang3.tuple.Pair; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -23,7 +17,6 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import java.util.HashMap; import java.util.HashSet; diff --git a/src/main/java/carpet/mixins/ServerChunkManager_tickMixin.java b/src/main/java/carpet/mixins/ServerChunkManager_tickMixin.java index 0dd3b461..5a198899 100644 --- a/src/main/java/carpet/mixins/ServerChunkManager_tickMixin.java +++ b/src/main/java/carpet/mixins/ServerChunkManager_tickMixin.java @@ -17,12 +17,9 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.function.BooleanSupplier; import com.google.common.collect.Lists; diff --git a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_antiCheatDisabledMixin.java b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_antiCheatDisabledMixin.java index 3579ff8c..b7a616e8 100644 --- a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_antiCheatDisabledMixin.java +++ b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_antiCheatDisabledMixin.java @@ -1,11 +1,8 @@ package carpet.mixins; import carpet.CarpetSettings; -import net.minecraft.network.ClientConnection; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.math.Vec3d; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; diff --git a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_coreMixin.java b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_coreMixin.java index 43fabd5c..313990f2 100644 --- a/src/main/java/carpet/mixins/ServerPlayNetworkHandler_coreMixin.java +++ b/src/main/java/carpet/mixins/ServerPlayNetworkHandler_coreMixin.java @@ -1,11 +1,8 @@ package carpet.mixins; import carpet.CarpetServer; -import net.minecraft.network.ClientConnection; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; import net.minecraft.text.Text; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; diff --git a/src/main/java/carpet/mixins/ServerPlayerEntity_scarpetEventMixin.java b/src/main/java/carpet/mixins/ServerPlayerEntity_scarpetEventMixin.java index dabf607a..f53ad308 100644 --- a/src/main/java/carpet/mixins/ServerPlayerEntity_scarpetEventMixin.java +++ b/src/main/java/carpet/mixins/ServerPlayerEntity_scarpetEventMixin.java @@ -6,7 +6,6 @@ import com.mojang.authlib.GameProfile; import net.minecraft.entity.Entity; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.stat.Stat; diff --git a/src/main/java/carpet/mixins/ServerPlayerInteractionManager_scarpetEventsMixin.java b/src/main/java/carpet/mixins/ServerPlayerInteractionManager_scarpetEventsMixin.java index 72ed11e7..559fbc91 100644 --- a/src/main/java/carpet/mixins/ServerPlayerInteractionManager_scarpetEventsMixin.java +++ b/src/main/java/carpet/mixins/ServerPlayerInteractionManager_scarpetEventsMixin.java @@ -4,7 +4,6 @@ import carpet.fakes.ServerPlayerInteractionManagerInterface; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; -import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerInteractionManager; diff --git a/src/main/java/carpet/mixins/ServerWorld_tickMixin.java b/src/main/java/carpet/mixins/ServerWorld_tickMixin.java index 5f0e42f8..1ac73b71 100644 --- a/src/main/java/carpet/mixins/ServerWorld_tickMixin.java +++ b/src/main/java/carpet/mixins/ServerWorld_tickMixin.java @@ -7,7 +7,6 @@ import net.minecraft.util.profiler.Profiler; import net.minecraft.util.registry.RegistryKey; import net.minecraft.village.raid.RaidManager; import net.minecraft.world.MutableWorldProperties; -import net.minecraft.world.WanderingTraderManager; import net.minecraft.world.World; import net.minecraft.world.border.WorldBorder; import net.minecraft.world.dimension.DimensionType; @@ -18,7 +17,6 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.function.BiFunction; import java.util.function.BooleanSupplier; import java.util.function.Supplier; diff --git a/src/main/java/carpet/mixins/SpawnHelperInnerMixin.java b/src/main/java/carpet/mixins/SpawnHelperInnerMixin.java index d14c8e80..2f4478b2 100644 --- a/src/main/java/carpet/mixins/SpawnHelperInnerMixin.java +++ b/src/main/java/carpet/mixins/SpawnHelperInnerMixin.java @@ -2,7 +2,6 @@ package carpet.mixins; import carpet.fakes.SpawnHelperInnerInterface; import carpet.utils.SpawnReporter; -import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import net.minecraft.entity.SpawnGroup; import net.minecraft.util.math.GravityField; diff --git a/src/main/java/carpet/mixins/SummonCommandMixin.java b/src/main/java/carpet/mixins/SummonCommandMixin.java index 11dcf6e6..4f936254 100644 --- a/src/main/java/carpet/mixins/SummonCommandMixin.java +++ b/src/main/java/carpet/mixins/SummonCommandMixin.java @@ -5,22 +5,14 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.LightningEntity; import net.minecraft.entity.mob.SkeletonHorseEntity; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.text.TranslatableText; -import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.command.SummonCommand; import net.minecraft.server.world.ServerWorld; -import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.GameRules; import net.minecraft.world.LocalDifficulty; 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.Redirect; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(SummonCommand.class) public class SummonCommandMixin diff --git a/src/main/java/carpet/mixins/World_movableTEMixin.java b/src/main/java/carpet/mixins/World_movableTEMixin.java index 818676c0..13a217c9 100644 --- a/src/main/java/carpet/mixins/World_movableTEMixin.java +++ b/src/main/java/carpet/mixins/World_movableTEMixin.java @@ -10,7 +10,6 @@ import net.minecraft.server.world.ChunkHolder; import net.minecraft.util.math.BlockPos; import net.minecraft.util.profiler.Profiler; import net.minecraft.world.BlockView; -import net.minecraft.world.MutableWorldProperties; import net.minecraft.world.WorldAccess; import net.minecraft.world.World; import net.minecraft.world.chunk.EmptyChunk; diff --git a/src/main/java/carpet/script/CarpetScriptHost.java b/src/main/java/carpet/script/CarpetScriptHost.java index eebda1d6..5bde0061 100644 --- a/src/main/java/carpet/script/CarpetScriptHost.java +++ b/src/main/java/carpet/script/CarpetScriptHost.java @@ -136,7 +136,7 @@ public class CarpetScriptHost extends ScriptHost String hostName = main.getName(); List commandArgs = path.stream().filter(t -> t.isArgument).map(t -> t.surface).collect(Collectors.toList()); if (commandArgs.size() != (functionSpec.function.getNumParams()-functionSpec.args.size()) ) - throw CommandArgument.error("Number of parameters in function doesn't match parameters for a command"); + throw CommandArgument.error("Number of parameters in function "+functionSpec.function.fullName()+" doesn't match parameters for a command"); if (path.isEmpty()) { return command.executes((c) -> execute(c, hostName, functionSpec, Collections.emptyList())); diff --git a/src/main/java/carpet/script/CarpetScriptServer.java b/src/main/java/carpet/script/CarpetScriptServer.java index 58351dd9..6ec6b14e 100644 --- a/src/main/java/carpet/script/CarpetScriptServer.java +++ b/src/main/java/carpet/script/CarpetScriptServer.java @@ -50,6 +50,13 @@ public class CarpetScriptServer private static final List bundledModuleData = new ArrayList<>(); private static final List ruleModuleData = new ArrayList<>(); + /** + * Registers a Scarpet App to be always available to be loaded + * in the /script load list. + * @see BundledModule#fromPath(ClassLoader, String, String, boolean) + * + * @param app The {@link BundledModule} of the app + */ public static void registerBuiltInScript(BundledModule app) { bundledModuleData.add(app); @@ -57,10 +64,11 @@ public class CarpetScriptServer /** * Registers a Scarpet App to be used as a Rule App - * (to be controlled with the value of a Carpet rule) + * (to be controlled with the value of a Carpet rule). + * Libraries should be registered with {@link #registerBuiltInScript(BundledModule)} instead + * @see BundledModule#fromPath(ClassLoader, String, String, boolean) * - * @param app is the BundledModule of an app. Libraries - * should be registered as builtInScripts instead + * @param app The {@link BundledModule} of the app. */ public static void registerSettingsApp(BundledModule app) { ruleModuleData.add(app); @@ -214,13 +222,6 @@ public class CarpetScriptServer // Messenger.m(source, "r Failed to add "+name+" app: invalid app config (via '__config()' function)"); // return false; //} - if (module == null) - { - Messenger.m(source, "r Unable to locate the app, but created empty "+name+" app instead"); - modules.put(name, newHost); - return true; - } - String code = module.getCode(); if (module.getCode() == null) { Messenger.m(source, "r Unable to load "+name+" app - not found"); diff --git a/src/main/java/carpet/script/Fluff.java b/src/main/java/carpet/script/Fluff.java index 0546d2aa..ba2a70fd 100644 --- a/src/main/java/carpet/script/Fluff.java +++ b/src/main/java/carpet/script/Fluff.java @@ -1,7 +1,6 @@ package carpet.script; import carpet.script.exception.ExpressionException; -import carpet.script.exception.InternalExpressionException; import carpet.script.value.Value; import java.util.ArrayList; diff --git a/src/main/java/carpet/script/bundled/BundledModule.java b/src/main/java/carpet/script/bundled/BundledModule.java index 08145546..e66b91fa 100644 --- a/src/main/java/carpet/script/bundled/BundledModule.java +++ b/src/main/java/carpet/script/bundled/BundledModule.java @@ -17,14 +17,46 @@ public class BundledModule extends Module this.name = name; this.code = code; } + /** + * Creates a new {@link BundledModule} with an app located in Carpet's script storage. + * @param scriptName A {@link String} being the name of the script. The extension will be autocompleted + * @param isLibrary A {@link boolean} indicating whether or not the script is a library + * @return The created {@link BundledModule} + */ public static BundledModule carpetNative(String scriptName, boolean isLibrary) { - BundledModule module = new BundledModule(null, null, isLibrary); - try - { - module.name = scriptName.toLowerCase(Locale.ROOT); + return fromPath("assets/carpet/scripts/", scriptName, isLibrary); + } + + /** + * Creates a new {@link BundledModule} with an app located at a specified place. + * @see #fromPathWithCustomName(ClassLoader, String, String, boolean) + * + * @param path A {@link String} being the path to the directory where the app is located. + * @param scriptName A {@link String} being the name of the script. The extension will be autocompleted + * @param isLibrary A {@link boolean} indicating whether or not the script is a library + * @return The created {@link BundledModule} + */ + public static BundledModule fromPath(String path, String scriptName, boolean isLibrary) { + return fromPathWithCustomName(path+scriptName+(isLibrary?".scl":".sc"), scriptName, isLibrary); + } + + /** + * Creates a new {@link BundledModule} with an app located at the specified fullPath with a custom name. + * @see #fromPath(ClassLoader, String, String, boolean) + * + * @param fullPath A {@link String} being the full path to the app's code, including file and extension. + * @param scriptName A {@link String} being the custom name for the script. + * @param isLibrary A {@link boolean} indicating whether or not the script is a library + * @return The created {@link BundledModule} + */ + public static BundledModule fromPathWithCustomName(String fullPath, String customName, boolean isLibrary) { + BundledModule module = new BundledModule(null, null, isLibrary); + try + { + module.name = customName.toLowerCase(Locale.ROOT); module.code = IOUtils.toString( - BundledModule.class.getClassLoader().getResourceAsStream("assets/carpet/scripts/"+scriptName+(isLibrary?".scl":".sc")), + BundledModule.class.getClassLoader().getResourceAsStream(fullPath), StandardCharsets.UTF_8 ); } diff --git a/src/main/java/carpet/script/value/BlockValue.java b/src/main/java/carpet/script/value/BlockValue.java index f86158a0..e883f27f 100644 --- a/src/main/java/carpet/script/value/BlockValue.java +++ b/src/main/java/carpet/script/value/BlockValue.java @@ -1,7 +1,6 @@ package carpet.script.value; import carpet.script.CarpetContext; -import carpet.script.LazyValue; import carpet.script.exception.InternalExpressionException; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; diff --git a/src/main/java/carpet/script/value/ListValue.java b/src/main/java/carpet/script/value/ListValue.java index 0c730b63..3637837a 100644 --- a/src/main/java/carpet/script/value/ListValue.java +++ b/src/main/java/carpet/script/value/ListValue.java @@ -13,7 +13,6 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.LongTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; -import net.minecraft.util.registry.Registry; import java.util.ArrayList; import java.util.Arrays; @@ -25,7 +24,6 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.StreamSupport; -import static carpet.script.value.NBTSerializableValue.nameFromRegistryId; import static java.lang.Math.abs; public class ListValue extends AbstractListValue implements ContainerValueInterface diff --git a/src/main/java/carpet/script/value/ThreadValue.java b/src/main/java/carpet/script/value/ThreadValue.java index d49a4d32..fd833bec 100644 --- a/src/main/java/carpet/script/value/ThreadValue.java +++ b/src/main/java/carpet/script/value/ThreadValue.java @@ -2,7 +2,6 @@ package carpet.script.value; import carpet.script.Context; import carpet.script.Expression; -import carpet.script.LazyValue; import carpet.script.Tokenizer; import carpet.script.exception.ExitStatement; import carpet.script.exception.ExpressionException; diff --git a/src/main/java/carpet/settings/ParsedRule.java b/src/main/java/carpet/settings/ParsedRule.java index 052eed7a..2c802fae 100644 --- a/src/main/java/carpet/settings/ParsedRule.java +++ b/src/main/java/carpet/settings/ParsedRule.java @@ -16,6 +16,14 @@ import java.util.Set; import static carpet.utils.Translations.tr; +/** + * A parsed Carpet rule, with its field, name, value, and other useful stuff. + * + * It is generated from the fields with the {@link Rule} annotation + * when being parsed by {@link SettingsManager#parseSettingsClass(Class)}. + * + * @param The field's type + */ public final class ParsedRule implements Comparable { public final Field field; public final String name; @@ -177,6 +185,9 @@ public final class ParsedRule implements Comparable { return this; } + /** + * @return The value of this {@link ParsedRule}, in its type + */ public T get() { try @@ -189,11 +200,19 @@ public final class ParsedRule implements Comparable { } } + /** + * @return The value of this {@link ParsedRule}, as a {@link String} + */ public String getAsString() { return convertToString(get()); } + /** + * @return The value of this {@link ParsedRule}, converted to a {@link boolean}. + * It will only return {@link true} if it's a true {@link boolean} or + * a number greater than zero. + */ public boolean getBoolValue() { if (type == boolean.class) return (Boolean) get(); @@ -201,11 +220,17 @@ public final class ParsedRule implements Comparable { return false; } + /** + * @return Wether or not this {@link ParsedRule} is in its default value + */ public boolean isDefault() { return defaultValue.equals(get()); } + /** + * Resets this rule to its default value + */ public void resetToDefault(ServerCommandSource source) { set(source, defaultValue, defaultAsString); @@ -247,16 +272,28 @@ public final class ParsedRule implements Comparable { return String.format("rule.%s.name", name); } + /** + * @return A {@link String} being the translated {@link ParsedRule#name} of this rule, + * in Carpet's configured language. + */ public String translatedName(){ String key = translationKey(); return Translations.hasTranslation(key) ? tr(key) + String.format(" (%s)", name): name; } + /** + * @return A {@link String} being the translated {@link ParsedRule#description} of this rule, + * in Carpet's configured language. + */ public String translatedDescription() { return tr(String.format("rule.%s.desc", (name)), description); } + /** + * @return A {@link String} being the translated {@link ParsedRule#extraInfo} of this + * {@link ParsedRule}, in Carpet's configured language. + */ public List translatedExtras() { if (!Translations.hasTranslations()) return extraInfo; diff --git a/src/main/java/carpet/settings/RuleCategory.java b/src/main/java/carpet/settings/RuleCategory.java index a6f0e302..9f05bac6 100644 --- a/src/main/java/carpet/settings/RuleCategory.java +++ b/src/main/java/carpet/settings/RuleCategory.java @@ -12,6 +12,11 @@ public class RuleCategory public static final String TNT = "tnt"; public static final String DISPENSER = "dispenser"; public static final String SCARPET = "scarpet"; + /** + * Rules with this {@link RuleCategory} will have a client-side + * counterpart, so they can be set independently without the server + * being Carpet's + */ public static final String CLIENT = "client"; } diff --git a/src/main/java/carpet/settings/SettingsManager.java b/src/main/java/carpet/settings/SettingsManager.java index 9c19b3f9..490591cc 100644 --- a/src/main/java/carpet/settings/SettingsManager.java +++ b/src/main/java/carpet/settings/SettingsManager.java @@ -48,9 +48,19 @@ import static net.minecraft.command.CommandSource.suggestMatching; import static net.minecraft.server.command.CommandManager.argument; import static net.minecraft.server.command.CommandManager.literal; +/** + * Manages and parses Carpet rules with their own command. + * @see #SettingsManager(String, String, String) + * + */ public class SettingsManager { private Map> rules = new HashMap<>(); + /** + * Whether or not this {@link SettingsManager} is locked. That is specified + * by writing "locked" at the beginning of the settings file. May not + * correctly react to changes. + */ public boolean locked; private final String version; private final String identifier; @@ -59,7 +69,13 @@ public class SettingsManager private List, String>> observers = new ArrayList<>(); private static List, String>> staticObservers = new ArrayList<>(); - + /** + * Creates a new {@link SettingsManager} without a fancy name. + * @see #SettingsManager(String, String, String) + * + * @param version A {@link String} with the mod's version + * @param identifier A {@link String} with the mod's id, will be the command name + */ public SettingsManager(String version, String identifier) { this.version = version; @@ -67,6 +83,14 @@ public class SettingsManager this.fancyName = identifier; } + /** + * Creates a new {@link SettingsManager} with a fancy name + * @see #SettingsManager(String, String) + * + * @param version A {@link String} with the mod's version + * @param identifier A {@link String} with the mod's id, will be the command name + * @param fancyName A {@link String} being the mod's fancy name. + */ public SettingsManager(String version, String identifier, String fancyName) { this.version = version; @@ -74,22 +98,41 @@ public class SettingsManager this.fancyName = fancyName; } + /** + * @return A {@link String} being this {@link SettingsManager}'s + * identifier, which is also the command name + */ public String getIdentifier() { return identifier; } + /** + * Attaches a {@link MinecraftServer} to this {@link SettingsManager}.
+ * This is handled automatically by Carpet + * @param server The {@link MinecraftServer} instance to be attached + */ public void attachServer(MinecraftServer server) { this.server = server; loadConfigurationFromConf(); } + /** + * Detaches the {@link MinecraftServer} of this {@link SettingsManager} and + * resets its {@link ParsedRule}s to their default values.
+ * This is handled automatically by Carpet + */ public void detachServer() { for (ParsedRule rule : rules.values()) rule.resetToDefault(null); server = null; } + /** + * Adds all annotated fields with the {@link Rule} annotation + * to this {@link SettingsManager} in order to handle them. + * @param settingsClass The class that will be analyzed + */ public void parseSettingsClass(Class settingsClass) { for (Field f : settingsClass.getDeclaredFields()) @@ -101,10 +144,31 @@ public class SettingsManager } } + /** + * Adds a custom rule observer to changes in rules from + * this specific {@link SettingsManager} instance. + * @see SettingsManager#addGlobalRuleObserver(TriConsumer) + * + * @param observer A {@link TriConsumer} that will be called with + * the used {@link ServerCommandSource}, the changed + * {@link ParsedRule} and a {@link String} being the + * value that the user typed. + */ public void addRuleObserver(TriConsumer, String> observer) { observers.add(observer); } + + /** + * Adds a custom rule observer to changes in rules from + * any registered {@link SettingsManger} instance. + * @see SettingsManager#addRuleObserver(TriConsumer) + * + * @param observer A {@link TriConsumer} that will be called with + * the used {@link ServerCommandSource}, the changed + * {@link ParsedRule} and a {@link String} being the + * value that the user typed. + */ public static void addGlobalRuleObserver(TriConsumer, String> observer) { staticObservers.add(observer); @@ -133,6 +197,10 @@ public class SettingsManager } } + /** + * Initializes Scarpet rules in this {@link SettingsManager}, if any.
+ * This is handled automatically by Carpet. + */ public void initializeScarpetRules() { for (ParsedRule rule : rules.values()) { @@ -142,6 +210,10 @@ public class SettingsManager } } + /** + * @return An {@link Iterable} list of all categories + * from rules in this {@link SettingsManager} + */ public Iterable getCategories() { Set categories = new HashSet<>(); @@ -150,16 +222,29 @@ public class SettingsManager } + /** + * Gets a registered rule in this {@link SettingsManager} by its name. + * @param name The rule name + * @return The {@link ParsedRule} with that name + */ public ParsedRule getRule(String name) { return rules.get(name); } + /** + * @return A {@link Collection} of the registered rules in this + * {@link SettingsManager}. + */ public Collection> getRules() { return rules.values().stream().sorted().collect(Collectors.toList()); } + /** + * @return A {@link Collection} of {@link ParsedRule}s that have defaults + * for this world different than the rule's default value. + */ public Collection> findStartupOverrides() { Set defaults = readSettingsFromConf().getLeft().keySet(); @@ -167,7 +252,10 @@ public class SettingsManager sorted().collect(Collectors.toList()); } - + /** + * @return A collection of {@link ParsedRule} that are not in + * their default value + */ public Collection> getNonDefault() { return rules.values().stream().filter(r -> !r.isDefault()).sorted().collect(Collectors.toList()); @@ -178,6 +266,10 @@ public class SettingsManager return server.getSavePath(WorldSavePath.ROOT).resolve(identifier+".conf").toFile(); } + /** + * Disables all {@link ParsedRule} with the {@link RuleCategory#COMMAND} category, + * called when the {@link SettingsManager} is {@link #locked}. + */ public void disableBooleanCommands() { for (ParsedRule rule : rules.values()) @@ -213,6 +305,9 @@ public class SettingsManager ///todo is it really needed? resendCommandTree(); } + /** + * Notifies all players that the commands changed by resending the command tree. + */ public void notifyPlayersCommandsChanged() { if (server == null || server.getPlayerManager() == null) @@ -228,6 +323,15 @@ public class SettingsManager })); } + /** + * Returns whether the the {@link ServerCommandSource} can execute + * a command given the required permission level, according to + * Carpet's standard for permissions. + * @param source The origin {@link ServerCommandSource} + * @param commandLevel A {@link String} being the permission level (either 0-4, a + * {@link boolean} value or "ops". + * @return Whether or not the {@link ServerCommandSource} meets the required level + */ public static boolean canUseCommand(ServerCommandSource source, String commandLevel) { switch (commandLevel) @@ -245,6 +349,12 @@ public class SettingsManager return false; } + /** + * @param commandLevel A {@link String} being a permission level according to + * Carpet's standard for permissions (either 0-4, a {@link boolean}, + * or "ops". + * @return An {@link int} with the translated Vanilla permission level + */ public static int getCommandLevel(String commandLevel) { switch (commandLevel) @@ -347,6 +457,15 @@ public class SettingsManager }).sorted().collect(ImmutableList.toImmutableList()); } + /** + * A method to pretty print in markdown (useful for Github wiki/readme) the current + * registered rules for a category to the log. Contains the name, description, + * categories, type, defaults, wether or not they are strict, their suggested + * values, and the descriptions of their validators. + * @param category A {@link String} being the category to print, {@link null} to print + * all registered rules. + * @return {@link int} 1 if things didn't fail, and all the info to System.out + */ public int printAllRulesToLog(String category) { PrintStream ps = System.out; @@ -393,6 +512,11 @@ public class SettingsManager return rule; } + /** + * Registers the the settings command for this {@link SettingsManager}.
+ * It is handled automatically by Carpet. + * @param dispatcher The current {@link CommandDispatcher} + */ public void registerCommand(CommandDispatcher dispatcher) { if (dispatcher.getRoot().getChildren().stream().anyMatch(node -> node.getName().equalsIgnoreCase(identifier))) @@ -584,7 +708,7 @@ public class SettingsManager public void inspectClientsideCommand(ServerCommandSource source, String string) { - if (string.startsWith("/carpet ")) + if (string.startsWith("/"+identifier+" ")) { String[] res = string.split("\\s+", 3); if (res.length == 3) diff --git a/src/main/java/carpet/utils/RulePrinter.java b/src/main/java/carpet/utils/RulePrinter.java new file mode 100644 index 00000000..07a1f6ed --- /dev/null +++ b/src/main/java/carpet/utils/RulePrinter.java @@ -0,0 +1,22 @@ +package carpet.utils; + +import carpet.CarpetServer; +import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint; +import java.lang.System; +/** + * Runs only from GitHub Actions to generate the wiki + * page with all Carpet rules on it. + * It is here so it can be managed by the IDE + * + * @author altrisi + * + */ +public class RulePrinter implements PreLaunchEntrypoint { + + @Override + public void onPreLaunch() { + CarpetServer.onGameStarted(); + CarpetServer.settingsManager.printAllRulesToLog(null); + System.exit(0); + } +} diff --git a/src/main/java/carpet/utils/SpawnReporter.java b/src/main/java/carpet/utils/SpawnReporter.java index ae3ab5ab..1c17dd40 100644 --- a/src/main/java/carpet/utils/SpawnReporter.java +++ b/src/main/java/carpet/utils/SpawnReporter.java @@ -231,8 +231,9 @@ public class SpawnReporter return SpawnGroup.AMBIENT; case CYAN: return SpawnGroup.WATER_AMBIENT; + default: + return null; } - return null; } public static SpawnGroup get_creature_type_from_code(String type_code) diff --git a/src/main/resources/assets/carpet/scripts/ai_tracker.sc b/src/main/resources/assets/carpet/scripts/ai_tracker.sc index ba57d146..ad8a7d64 100644 --- a/src/main/resources/assets/carpet/scripts/ai_tracker.sc +++ b/src/main/resources/assets/carpet/scripts/ai_tracker.sc @@ -49,7 +49,7 @@ villager_buddy_detection() -> __toggle('villager_buddy_detection', null); item_pickup() -> __toggle('item_pickup', null); portal_cooldown() -> __toggle('portal_cooldown', null); health() -> __toggle('health', null); - +//xpstack() -> __toggle('xpstack', null); //1.17 feature toggle_boxes() -> ( @@ -365,6 +365,17 @@ global_functions = { null ] }, + + 'xpstack' -> { + 'experience_orb' -> [ + _(arg) -> _(orb) -> ( + ct = query(orb, 'nbt', 'Count'); + [[], [], if (ct > 1, [['stack', 'stack:', ct]],[]) ] + ), + , + null + ] + }, }; global_villager_food = { @@ -505,13 +516,18 @@ __tick_tracker() -> p = player(); [px, py, pz] = pos(p); in_dimension(p, - for (entity_area('living', px, py, pz, global_range, global_range, global_range), + for (entity_area('valid', px, py, pz, global_range, global_range, global_range), __handle_entity(_) ) ); schedule(global_interval, '__tick_tracker'); ); +global_entity_anchors = { + 'experience_orb' -> 'xyz', + 'player' -> 'xyz' +}; + __handle_entity(e) -> ( entity_type = e ~ 'type'; @@ -531,7 +547,8 @@ __handle_entity(e) -> if (labels_to_add, base_height = 0; - [snap, base_pos] = if(e~'type'=='player', ['xyz', [0, e~'height', 0]], ['dxydz', [0.5, e~'height'+0.4, 0.5]]); + snap = global_entity_anchors:(e~'type') || 'dxydz'; + base_pos = if(snap == 'xyz', [0, e~'height'+0.3, 0], [0.5, e~'height'+0.3, 0.5]); for (labels_to_add, if (length(_) == 2, [label, text] = _; diff --git a/src/main/resources/assets/carpet/scripts/overlay.sc b/src/main/resources/assets/carpet/scripts/overlay.sc index 8de413af..a78aa78f 100644 --- a/src/main/resources/assets/carpet/scripts/overlay.sc +++ b/src/main/resources/assets/carpet/scripts/overlay.sc @@ -27,35 +27,76 @@ global_renderers = m( } ); -__command() -> ''; +global_shapes = {'sphere' -> [], 'box' -> []}; -monument() -> __toggle('monument', 'structures'); -fortress() -> __toggle('fortress', 'structures'); -mansion() -> __toggle('mansion', 'structures'); -jungle_pyramid() -> __toggle('jungle_pyramid', 'structures'); -desert_pyramid() -> __toggle('desert_pyramid', 'structures'); -endcity() -> __toggle('endcity', 'structures'); -igloo() -> __toggle('igloo', 'structures'); -shipwreck() -> __toggle('shipwreck', 'structures'); -swamp_hut() -> __toggle('swamp_hut', 'structures'); -stronghold() -> __toggle('stronghold', 'structures'); -ocean_ruin() -> __toggle('ocean_ruin', 'structures'); -buried_treasure() -> __toggle('buried_treasure', 'structures'); -pillager_outpost() -> __toggle('pillager_outpost', 'structures'); -mineshaft() -> __toggle('mineshaft', 'structures'); -village() -> __toggle('village', 'structures'); -nether_fossil() -> __toggle('nether_fossil', 'structures'); -bastion_remnant() -> __toggle('bastion_remnant', 'structures'); -ruined_portal() -> __toggle('ruined_portal', 'structures'); - -slime_chunks() -> __toggle('slime_chunks', 'chunks'); - -portal_coordinates() -> __toggle('coords', 'portals'); -portal_links() -> __toggle('links', 'portals'); +__config() -> +{ + 'commands' -> { + 'structure ' -> _(s) -> __toggle(s, 'structures'), + 'slime_chunks' -> ['__toggle', 'slime_chunks', 'chunks'], + 'portal coordinates' -> ['__toggle', 'coords', 'portals'], + 'portal links' -> ['__toggle', 'links', 'portals'], + ' following ' -> ['display_shape', [null,0xffffffff], true], + ' at ' -> ['display_shape', [null,0xffffffff], false], + ' following ' -> ['display_shape', true], + ' at ' -> ['display_shape', false], + ' clear' -> 'clear_shape', + 'clear' -> 'clear', + }, + 'arguments' -> { + 'structure' -> {'type' -> 'term', 'suggest' -> [ + 'monument', 'fortress', 'mansion', 'jungle_pyramid', + 'desert_pyramid', 'endcity', 'igloo', 'shipwreck', + 'swamp_hut', 'stronghold', 'ocean_ruin', 'buried_treasure', + 'pillager_outpost', 'mineshaft', 'village', 'nether_fossil', + 'bastion_remnant', 'ruined_portal' + ]}, + 'player' -> {'type' -> 'players', 'single' -> true}, + 'radius' -> {'type' -> 'int', 'min' -> 0, 'max' -> 1024, 'suggest' -> [128, 24, 32]}, + 'shape' -> {'type' -> 'term', 'options' -> keys(global_shapes) }, + 'color' -> {'type' -> 'teamcolor'} + } +}; +display_shape(shape, r, player, color, following) -> +( -clear() -> for(global_renderers, global_renderers:_:'tasks' = m() ); + player = player(player); + if (!player, return()); + if (shape == 'sphere', + shape_config = { + 'center' -> if(following, [0,0,0], pos(player)), + 'radius' -> r + } + , shape == 'box', + shape_config = { + 'from' -> if(following, [-r,-r,-r], pos(player)-r), + 'to' -> if(following, [r,r,r], pos(player)+r) + } + ); + if (shape_config, + if (following, shape_config:'follow' = player); + shape_config:'fill' = color:1 - 200; + shape_config:'color' = color:1; + shape_config:'line' = 5; + draw_shape(shape, 72000, shape_config); + global_shapes:shape += shape_config; + ) +); + + +clear_shape(shape) -> +( + for(global_shapes:shape, draw_shape(shape, 0, _)); + global_shapes:shape = []; +); + +clear() -> +( + for(global_renderers, global_renderers:_:'tasks' = m() ); + for(global_shapes, clear_shape(_)); +); __toggle(feature, renderer) -> ( @@ -63,11 +104,11 @@ __toggle(feature, renderer) -> config = global_renderers:renderer; if( has(config:'tasks':feature), delete(config:'tasks':feature); - 'disabled '+feature+' overlays'; + print(p, format('gi disabled '+feature+' overlays')); , config:'tasks' += feature; if (!config:'active', call(config:'handler', p~'name')); - 'enabled '+feature+' overlays'; + print(p, format('gi enabled '+feature+' overlays')); ) ); @@ -81,6 +122,9 @@ __should_run(renderer, player_name) -> l(p, config); ); + + + __structure_renderer(player_name) -> ( l(p, config) = __should_run('structures', player_name);