Creative Tab and Commands

This commit is contained in:
skippyall
2025-04-25 15:33:17 +02:00
parent 935b2225c9
commit ec31e090b9
14 changed files with 252 additions and 79 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ org.gradle.jvmargs=-Xmx1G
fabric_version=0.121.0+1.21.5
polymer_version=0.12.3+1.21.5
sgui_version=1.8.2+1.21.4
sgui_version=1.9.0+1.21.5
server_translations_version=2.5.0+1.21.5-rc1
universal_graves_version=3.7.1+1.21.5
@@ -0,0 +1,35 @@
package io.github.skippyall.minions;
import eu.pb4.polymer.core.api.item.PolymerItemGroupUtils;
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import java.util.ArrayList;
import java.util.List;
public class MinionCreativeTab {
public static ItemGroup group;
private static final List<ItemStack> items = new ArrayList<>();
public static void add(Item entry) {
items.add(entry.getDefaultStack());
}
public static void collectEntries(ItemGroup.DisplayContext displayContext, ItemGroup.Entries entries) {
entries.addAll(items);
}
public static void registerGroup() {
group = FabricItemGroup.builder()
.displayName(Text.translatable("minions.generic.mod_name"))
.icon(MinionItems.MINION_ITEM::getDefaultStack)
.entries(MinionCreativeTab::collectEntries)
.build();
PolymerItemGroupUtils.registerPolymerItemGroup(Identifier.of(Minions.MOD_ID, "main"), group);
}
}
@@ -0,0 +1,44 @@
package io.github.skippyall.minions;
import eu.pb4.polymer.core.api.item.SimplePolymerItem;
import io.github.skippyall.minions.minion.MinionItem;
import io.github.skippyall.minions.module.Modules;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.DamageResistantComponent;
import net.minecraft.entity.damage.DamageType;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
import java.util.function.Function;
import static io.github.skippyall.minions.Minions.MOD_ID;
public class MinionItems {
public static final TagKey<DamageType> MINION_ITEM_RESISTS = TagKey.of(RegistryKeys.DAMAGE_TYPE, Identifier.of(MOD_ID, "minion_item_resists"));
public static final MinionItem MINION_ITEM = registerItem(Identifier.of(MOD_ID, "minion"), settings -> new MinionItem(settings.component(DataComponentTypes.DAMAGE_RESISTANT, new DamageResistantComponent(MINION_ITEM_RESISTS))));
public static final SimplePolymerItem BASIC_UPGRADE_BASE = registerItem(Identifier.of(MOD_ID, "basic_upgrade_base"), settings -> new SimplePolymerItem(settings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE));
public static final SimplePolymerItem ADVANCED_UPGRADE_BASE = registerItem(Identifier.of(MOD_ID, "advanced_upgrade_base"), settings -> new SimplePolymerItem(settings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE));
public static <T extends Item> T registerItem(Identifier identifier, Function<Item.Settings, T> constructor, Item.Settings settings) {
T item = constructor.apply(settings.registryKey(RegistryKey.of(RegistryKeys.ITEM, identifier)));
MinionCreativeTab.add(item);
return Registry.register(Registries.ITEM, identifier, item);
}
public static <T extends Item> T registerItem(Identifier identifier, Function<Item.Settings, T> constructor) {
return registerItem(identifier, constructor, new Item.Settings());
}
public static void register() {
Modules.register();
}
}
@@ -1,42 +1,18 @@
package io.github.skippyall.minions;
import eu.pb4.polymer.core.api.entity.PolymerEntityUtils;
import eu.pb4.polymer.core.api.item.SimplePolymerItem;
import io.github.skippyall.minions.command.MinionsCommand;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.minion.MinionData;
import io.github.skippyall.minions.minion.MinionItem;
import io.github.skippyall.minions.minion.MinionPersistentState;
import io.github.skippyall.minions.module.Modules;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.DamageResistantComponent;
import net.minecraft.entity.boss.WitherEntity;
import net.minecraft.entity.damage.DamageType;
import net.minecraft.item.Item;
import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.util.Identifier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public class Minions implements ModInitializer {
public static final String MOD_ID = "minions";
public static final TagKey<DamageType> MINION_ITEM_RESISTS = TagKey.of(RegistryKeys.DAMAGE_TYPE, Identifier.of(MOD_ID, "minion_item_resists"));
public static final MinionItem MINION_ITEM = registerItem(Identifier.of(MOD_ID, "minion"), settings -> new MinionItem(settings.component(DataComponentTypes.DAMAGE_RESISTANT, new DamageResistantComponent(MINION_ITEM_RESISTS))));
public static final SimplePolymerItem BASIC_UPGRADE_BASE = registerItem(Identifier.of(MOD_ID, "basic_upgrade_base"), settings -> new SimplePolymerItem(settings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE));
public static final SimplePolymerItem ADVANCED_UPGRADE_BASE = registerItem(Identifier.of(MOD_ID, "advanced_upgrade_base"), settings -> new SimplePolymerItem(settings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE));
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
@@ -54,17 +30,10 @@ public class Minions implements ModInitializer {
});
CommandRegistrationCallback.EVENT.register((commandDispatcher, commandRegistryAccess, registrationEnvironment) -> {
MobCapCommand.registerCommand(commandDispatcher);
MinionsCommand.register(commandDispatcher);
});
Modules.register();
}
private static <T extends Item> T registerItem(Identifier identifier, Function<Item.Settings, T> constructor, Item.Settings settings) {
return Registry.register(Registries.ITEM, identifier, constructor.apply(settings.registryKey(RegistryKey.of(RegistryKeys.ITEM, identifier))));
}
private static <T extends Item> T registerItem(Identifier identifier, Function<Item.Settings, T> constructor) {
return registerItem(identifier, constructor, new Item.Settings());
MinionItems.register();
MinionCreativeTab.registerGroup();
}
}
@@ -1,24 +0,0 @@
package io.github.skippyall.minions;
import com.mojang.brigadier.CommandDispatcher;
import io.github.skippyall.minions.mixinhelper.ChunkLevelManager$DistanceFromNearestPlayerTrackerAccessor;
import io.github.skippyall.minions.mixinhelper.ChunkLevelManagerAccessor;
import io.github.skippyall.minions.mixins.antimobcap.ServerChunkManagerAccessor;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.text.Text;
import static net.minecraft.server.command.CommandManager.literal;
public class MobCapCommand {
public static void registerCommand(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(literal("mobcapdebug")
.executes(context -> {
ChunkTicketManager ticketManager = ((ServerChunkManagerAccessor)context.getSource().getWorld().getChunkManager()).getTicketManager();
int tickedChunkCount = ((ChunkLevelManager$DistanceFromNearestPlayerTrackerAccessor)((ChunkLevelManagerAccessor)ticketManager).minions$getMinionless()).minions$getTickedChunkCount();
context.getSource().sendFeedback(() -> Text.of(String.valueOf(tickedChunkCount)), false);
return 0;
})
);
}
}
@@ -0,0 +1,52 @@
package io.github.skippyall.minions.command;
import com.mojang.brigadier.Message;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandExceptionType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import io.github.skippyall.minions.minion.MinionData;
import io.github.skippyall.minions.minion.MinionPersistentState;
import io.github.skippyall.minions.minion.MinionProfileUtils;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.text.Text;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
public class MinionArgument {
public static final SimpleCommandExceptionType MINION_NOT_PRESENT = new SimpleCommandExceptionType(Text.translatable("minions.command.minion.not_present"));
public static final MinionSuggestionProvider SUGGESTION_PROVIDER = new MinionSuggestionProvider();
public static MinionData parse(String argument) throws CommandSyntaxException {
Optional<MinionData> data = Optional.empty();
if(argument.startsWith(MinionProfileUtils.PREFIX)) {
data = MinionPersistentState.INSTANCE.getMinionWithName(argument);
} else {
try {
data = Optional.ofNullable(MinionPersistentState.INSTANCE.getMinionData(UUID.fromString(argument)));
} catch (IllegalArgumentException ignored) {}
}
if(data.isEmpty()) {
throw MINION_NOT_PRESENT.create();
}
return data.get();
}
public static class MinionSuggestionProvider implements SuggestionProvider<ServerCommandSource> {
@Override
public CompletableFuture<Suggestions> getSuggestions(CommandContext<ServerCommandSource> context, SuggestionsBuilder builder) throws CommandSyntaxException {
for (MinionData data : MinionPersistentState.INSTANCE.getMinionDataList()) {
builder.suggest(data.name());
}
return builder.buildFuture();
}
}
}
@@ -0,0 +1,18 @@
package io.github.skippyall.minions.command;
import com.mojang.brigadier.CommandDispatcher;
import net.minecraft.server.command.ServerCommandSource;
import static net.minecraft.server.command.CommandManager.literal;
public class MinionsCommand {
public static void register(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(
literal("minions")
.then(SpawnSubcommand.SPAWN)
.then(MobCapDebugSubcommand.MOB_CAP_DEBUG)
);
}
}
@@ -0,0 +1,24 @@
package io.github.skippyall.minions.command;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.context.CommandContext;
import io.github.skippyall.minions.mixinhelper.ChunkLevelManager$DistanceFromNearestPlayerTrackerAccessor;
import io.github.skippyall.minions.mixinhelper.ChunkLevelManagerAccessor;
import io.github.skippyall.minions.mixins.antimobcap.ServerChunkManagerAccessor;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.text.Text;
import static net.minecraft.server.command.CommandManager.literal;
public class MobCapDebugSubcommand {
public static final LiteralArgumentBuilder<ServerCommandSource> MOB_CAP_DEBUG = literal("mobcapdebug")
.executes(MobCapDebugSubcommand::mobcapdebugCommand);
public static int mobcapdebugCommand(CommandContext<ServerCommandSource> context) {
ChunkTicketManager ticketManager = ((ServerChunkManagerAccessor)context.getSource().getWorld().getChunkManager()).getTicketManager();
int tickedChunkCount = ((ChunkLevelManager$DistanceFromNearestPlayerTrackerAccessor)((ChunkLevelManagerAccessor)ticketManager).minions$getMinionless()).minions$getTickedChunkCount();
context.getSource().sendFeedback(() -> Text.of(String.valueOf(tickedChunkCount)), false);
return 0;
}
}
@@ -0,0 +1,47 @@
package io.github.skippyall.minions.command;
import com.mojang.brigadier.arguments.BoolArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import io.github.skippyall.minions.minion.MinionData;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import net.minecraft.command.argument.PosArgument;
import net.minecraft.command.argument.Vec3ArgumentType;
import net.minecraft.server.command.ServerCommandSource;
import static net.minecraft.server.command.CommandManager.argument;
import static net.minecraft.server.command.CommandManager.literal;
public class SpawnSubcommand {
public static final LiteralArgumentBuilder<ServerCommandSource> SPAWN = literal("spawn")
.then(argument("minion", StringArgumentType.word())
.suggests(MinionArgument.SUGGESTION_PROVIDER)
.then(argument("pos", Vec3ArgumentType.vec3()))
.executes(context ->
spawnCommand(
context.getSource(),
StringArgumentType.getString(context, "minion"),
Vec3ArgumentType.getPosArgument(context, "pos"),
false
)
)
.then(argument("force", BoolArgumentType.bool())
.executes(context ->
spawnCommand(
context.getSource(),
StringArgumentType.getString(context, "minion"),
Vec3ArgumentType.getPosArgument(context, "pos"),
BoolArgumentType.getBool(context, "force")
)
)
)
);
public static int spawnCommand(ServerCommandSource source, String minion, PosArgument pos, boolean force) throws CommandSyntaxException {
MinionData data = MinionArgument.parse(minion);
MinionFakePlayer.spawnMinion(data, source.getWorld(), pos.getPos(source), pos.getRotation(source), force);
return 0;
}
}
@@ -14,6 +14,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
public class MinionPersistentState extends PersistentState {
@@ -57,7 +58,13 @@ public class MinionPersistentState extends PersistentState {
}
public boolean isMinionNameTaken(String name) {
return minionData.values().stream().anyMatch(data -> data.name().equals(name));
return getMinionWithName(name).isPresent();
}
public Optional<MinionData> getMinionWithName(String name) {
return minionData.values().stream()
.filter(data -> data.name().equals(name))
.findFirst();
}
public static void create(MinecraftServer server) {
@@ -3,8 +3,7 @@ package io.github.skippyall.minions.minion.fakeplayer;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.PropertyMap;
import io.github.skippyall.minions.Minions;
import io.github.skippyall.minions.MinionsTickExecutor;
import io.github.skippyall.minions.MinionItems;
import io.github.skippyall.minions.minion.MinionData;
import io.github.skippyall.minions.gui.MinionGui;
import io.github.skippyall.minions.minion.MinionItem;
@@ -13,7 +12,6 @@ import io.github.skippyall.minions.minion.MinionProfileUtils;
import io.github.skippyall.minions.gui.ModuleInventory;
import io.github.skippyall.minions.program.runtime.MinionRuntime;
import net.minecraft.block.BlockState;
import net.minecraft.block.EndPortalBlock;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.ItemEntity;
@@ -47,7 +45,6 @@ import net.minecraft.world.TeleportTarget;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
public class MinionFakePlayer extends ServerPlayerEntity {
public Runnable fixStartingPosition = () -> {};
@@ -61,17 +58,21 @@ public class MinionFakePlayer extends ServerPlayerEntity {
private final MinionData data;
public static void spawnMinion(MinionData data, ServerWorld level, @Nullable Vec3d pos, @Nullable Vec2f rot) {
spawnMinion(data, level, pos, rot, false);
}
public static void spawnMinion(MinionData data, ServerWorld level, @Nullable Vec3d pos, @Nullable Vec2f rot, boolean force) {
if(!data.isSpawned() || force) {
MinecraftServer server = level.getServer();
PropertyMap skin = data.skin().orElse(null);
GameProfile profile = MinionProfileUtils.makeNewMinionProfile(data.uuid(), data.name(), skin);
doSpawn(data, profile, server, level, pos, rot);
}
}
private static void doSpawn(MinionData data, GameProfile profile, MinecraftServer server, ServerWorld level, @Nullable Vec3d pos, @Nullable Vec2f rot) {
MinionFakePlayer instance = new MinionFakePlayer(server, level, profile, SyncedClientOptions.createDefault(), data);
MinionPersistentState.INSTANCE.updateMinionData(data.withSpawned(true));
@@ -280,7 +281,7 @@ public class MinionFakePlayer extends ServerPlayerEntity {
}
private ItemStack toItemStack() {
ItemStack stack = new ItemStack(Minions.MINION_ITEM);
ItemStack stack = new ItemStack(MinionItems.MINION_ITEM);
MinionItem.setData(data, stack);
return stack;
}
@@ -2,6 +2,7 @@ package io.github.skippyall.minions.mixins.antimobcap;
import io.github.skippyall.minions.mixinhelper.ChunkLevelManager$DistanceFromNearestPlayerTrackerAccessor;
import io.github.skippyall.minions.mixinhelper.ChunkLevelManagerAccessor;
import net.minecraft.server.world.ChunkLevelManager;
import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.server.world.ServerChunkManager;
import org.spongepowered.asm.mixin.Final;
@@ -14,10 +15,10 @@ import org.spongepowered.asm.mixin.injection.ModifyArg;
public class ServerChunkManagerMixin {
@Shadow
@Final
private ChunkTicketManager ticketManager;
private ChunkLevelManager levelManager;
@ModifyArg(method = "tickChunks(Lnet/minecraft/util/profiler/Profiler;J)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/SpawnHelper;setupSpawn(ILjava/lang/Iterable;Lnet/minecraft/world/SpawnHelper$ChunkSource;Lnet/minecraft/world/SpawnDensityCapper;)Lnet/minecraft/world/SpawnHelper$Info;"))
public int useMinionless(int spawningChunkCount) {
return ((ChunkLevelManager$DistanceFromNearestPlayerTrackerAccessor)((ChunkLevelManagerAccessor)ticketManager).minions$getMinionless()).minions$getTickedChunkCount();
return ((ChunkLevelManager$DistanceFromNearestPlayerTrackerAccessor)((ChunkLevelManagerAccessor)levelManager).minions$getMinionless()).minions$getTickedChunkCount();
}
}
@@ -1,5 +1,6 @@
package io.github.skippyall.minions.module;
import io.github.skippyall.minions.MinionItems;
import io.github.skippyall.minions.module.command.Command;
import io.github.skippyall.minions.program.block.CodeBlock;
import net.minecraft.item.Item;
@@ -21,11 +22,7 @@ public class Modules {
AttackModule.registerMe();
}
public static <T extends Item & ModuleItem> T register(Identifier id, T item) {
return Registry.register(Registries.ITEM, id, item);
}
public static SimpleModuleItem register(Identifier id, List<CodeBlock<?,?>> codeBlocks, List<Command> commands, Item vanillaItem) {
return Registry.register(Registries.ITEM, id, new SimpleModuleItem(codeBlocks, commands, new Item.Settings().registryKey(RegistryKey.of(RegistryKeys.ITEM, id)), vanillaItem));
return MinionItems.registerItem(id, settings -> new SimpleModuleItem(codeBlocks, commands, settings, vanillaItem));
}
}
@@ -42,5 +42,7 @@
"minions.generic.name.invalid_char": "Name contains invalid character",
"minions.generic.name.too_long": "Name is too long",
"minions.generic.name.invalid": "Name is invalid",
"minions.generic.name.taken": "This name is already used"
"minions.generic.name.taken": "This name is already used",
"minions.generic.mod_name": "Minions",
"minions.command.minion.not_present": "This minion does not exist"
}