diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml index c3c010b..c89a1fe 100644 --- a/.forgejo/workflows/build.yml +++ b/.forgejo/workflows/build.yml @@ -31,7 +31,7 @@ jobs: run: ./gradlew build - name: capture build artifacts if: ${{ matrix.java == '21' }} # Only upload artifacts built from latest java - uses: https://github.com/actions/upload-artifact@v4 + uses: https://github.com/actions/upload-artifact@v3 with: name: Artifacts path: build/libs/ \ No newline at end of file diff --git a/src/main/java/ovh/sad/animalrp/AnimalRP.java b/src/main/java/ovh/sad/animalrp/AnimalRP.java index 280072a..2659bc9 100644 --- a/src/main/java/ovh/sad/animalrp/AnimalRP.java +++ b/src/main/java/ovh/sad/animalrp/AnimalRP.java @@ -8,10 +8,11 @@ import ovh.sad.animalrp.animals.Cat; import ovh.sad.animalrp.animals.Dog; import ovh.sad.animalrp.animals.Fox; import ovh.sad.animalrp.animals.Bee; - +import ovh.sad.animalrp.commands.EmoteCommand; import ovh.sad.animalrp.commands.InteractionCommand; import ovh.sad.animalrp.commands.NoChatCommand; import ovh.sad.animalrp.commands.TfCommand; +import ovh.sad.animalrp.util.Emote; import ovh.sad.animalrp.util.Mood; import eu.pb4.placeholders.api.PlaceholderContext; import eu.pb4.placeholders.api.PlaceholderHandler; @@ -20,6 +21,8 @@ import eu.pb4.placeholders.api.Placeholders; import java.util.HashMap; import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; @@ -27,10 +30,12 @@ import org.slf4j.LoggerFactory; public class AnimalRP implements ModInitializer { + public static ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); + public static HashMap users = new HashMap<>(); public static HashMap noChat = new HashMap<>(); public static HashMap animals = new HashMap<>(); - // public static Emote emotes; + public static Emote emotes; public static final String MOD_ID = "animal-rp"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); @@ -40,6 +45,8 @@ public class AnimalRP implements ModInitializer { animals.put("dog", new Dog()); animals.put("fox", new Fox()); animals.put("bee", new Bee()); + emotes = new Emote(); + Placeholders.register(Identifier.of("animalrp", "animalcolor"), new PlaceholderHandler() { @Override public PlaceholderResult onPlaceholderRequest(PlaceholderContext ctx, @Nullable String arg) { @@ -55,7 +62,7 @@ public class AnimalRP implements ModInitializer { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> { (new TfCommand()).Command(dispatcher, registryAccess, environment); (new NoChatCommand()).Command(dispatcher, registryAccess, environment); - + (new EmoteCommand()).Command(dispatcher, registryAccess, environment); (new InteractionCommand("headpats", Mood.HAPPY, "%s petted you! %s", "You petted %s! %s")).Command(dispatcher, registryAccess, environment); (new InteractionCommand("kiss", Mood.CUTE, "%s kissed you.. 0////0 %s", "You kissed %s.. 0////0 %s")).Command(dispatcher, registryAccess, environment); diff --git a/src/main/java/ovh/sad/animalrp/animals/Bee.java b/src/main/java/ovh/sad/animalrp/animals/Bee.java index 3abbfef..5403a76 100644 --- a/src/main/java/ovh/sad/animalrp/animals/Bee.java +++ b/src/main/java/ovh/sad/animalrp/animals/Bee.java @@ -34,7 +34,6 @@ public class Bee extends Animal { Integer times; } - ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); private static Item[] _allFlowers = { Items.ALLIUM, Items.AZURE_BLUET, Items.BLUE_ORCHID, Items.CORNFLOWER, Items.DANDELION, Items.LILY_OF_THE_VALLEY, Items.OXEYE_DAISY, @@ -170,7 +169,7 @@ public class Bee extends Animal { && type != Blocks.AIR && type != Blocks.WATER) { if (!sneakers.contains(player.getUuid())) { sneakers.add(player.getUuid()); - executor.schedule(new Runnable() { + AnimalRP.executor.schedule(new Runnable() { @Override public void run() { if (sneakers.contains(player.getUuid())) diff --git a/src/main/java/ovh/sad/animalrp/animals/beeold.txt b/src/main/java/ovh/sad/animalrp/animals/beeold.txt deleted file mode 100644 index 253ff49..0000000 --- a/src/main/java/ovh/sad/animalrp/animals/beeold.txt +++ /dev/null @@ -1,165 +0,0 @@ -package ovh.sad.animalrp.animals; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import net.fabricmc.fabric.api.event.player.UseItemCallback; -import net.minecraft.block.Block; -import net.minecraft.block.Blocks; -import net.minecraft.component.DataComponentTypes; -import net.minecraft.component.type.FoodComponent; -import net.minecraft.entity.effect.StatusEffectInstance; -import net.minecraft.entity.effect.StatusEffects; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.sound.SoundCategory; -import net.minecraft.sound.SoundEvents; -import net.minecraft.util.Identifier; -import net.minecraft.util.TypedActionResult; -import ovh.sad.animalrp.AnimalRP; -import ovh.sad.animalrp.util.Mood; -import ovh.sad.animalrp.util.TextDestroyer; - -public class Bee extends Animal { - class Row { - Item mat; - Integer times; - } - - ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); - - private static Item[] _allFlowers = { Items.ALLIUM, Items.AZURE_BLUET, Items.BLUE_ORCHID, - Items.CORNFLOWER, Items.DANDELION, Items.LILY_OF_THE_VALLEY, Items.OXEYE_DAISY, - Items.POPPY, Items.TORCHFLOWER, Items.ORANGE_TULIP, Items.PINK_TULIP, Items.RED_TULIP, - Items.WHITE_TULIP }; - public static List allFlowers = Arrays.asList(_allFlowers); - public static Identifier beeFoodKey = Identifier.of("animalrp", "bee_food"); - public static HashMap inARow = new HashMap(); - TextDestroyer destroyer = new TextDestroyer(new String[] { - ">_<", "*buzz*", - ";3", ":3", "εწз", " ≧◠◡◠≦ ", "*stings you*", "*humms*", - "*i'm a bee*" - }, new String[][] { - { "e", "ee" }, - { "b", "bzz" }, - { "h", "hh" }, - { "ie", "ee" }, - { "be", "bee" }, - { "E", "EE" }, - { "B", "BZZ" }, - { "H", "HH" }, - { "IE", "EE" }, - { "BE", "BEE" } - }); - - ArrayList sneakers = new ArrayList(); - - public Bee() { - super("bee", "Buzz...", "#FFFF00"); - this.moodSounds.put(Mood.HAPPY, SoundEvents.ENTITY_BEE_LOOP); - this.moodSounds.put(Mood.CUTE, SoundEvents.ENTITY_BEE_LOOP); - this.moodSounds.put(Mood.SAD, SoundEvents.ENTITY_BEE_HURT); - this.moodSounds.put(Mood.STRESSED, SoundEvents.ENTITY_BEE_STING); - this.moodSounds.put(Mood.ANGRY, SoundEvents.ENTITY_BEE_LOOP_AGGRESSIVE); - UseItemCallback.EVENT.register((player, world, hand) -> { - System.out.println("1"); - Animal animal = AnimalRP.users.get(player.getUuid()); - - ItemStack item = player.getStackInHand(hand); - - if (item == null) // air interact - return TypedActionResult.pass(item); - System.out.println("2"); - - if (!allFlowers.contains(item.getItem())) { // not a flower - return TypedActionResult.pass(item); - } - System.out.println("3"); - - Boolean incorrect = false; - - if (animal == null) { - incorrect = true; - } else { - if (animal.name != this.name) { - incorrect = true; - } - } - System.out.println("3"); - - if (incorrect) { - if (item.get(AnimalRP.BEE_FOOD) != null) { - item.remove(AnimalRP.BEE_FOOD); - item.remove(DataComponentTypes.FOOD); - - return TypedActionResult.success(item, false); - } - return TypedActionResult.fail(item); - } - System.out.println("4"); - - if (item.get(AnimalRP.BEE_FOOD) != null) { // correct animal, but foodkey already set - return TypedActionResult.fail(item); - } - System.out.println("5"); -// .statusEffect(new StatusEffectInstance(StatusEffects.SPEED, 20 *4, 1, true, true, true), 1) - - FoodComponent food = new FoodComponent.Builder() - .alwaysEdible() - .nutrition(4) - .saturationModifier(9.4f) - .build(); - System.out.println("6"); - - item.set(DataComponentTypes.FOOD, food); - item.set(AnimalRP.BEE_FOOD, false); - System.out.println("7"); - - return TypedActionResult.success(item, false); - }); - } - - // called from the 'Sneaking' mixin. - public void onSneak(ServerPlayerEntity player, boolean status) { - Animal animal = AnimalRP.users.get(player.getUuid()); - if (animal == null) - return; - if (animal.name != this.name) - return; - - Block type = player.getWorld().getBlockState(player.getBlockPos().down()).getBlock(); - - if (status - && type != Blocks.AIR && type != Blocks.WATER) { - if (!sneakers.contains(player.getUuid())) { - sneakers.add(player.getUuid()); - executor.schedule(new Runnable() { - @Override - public void run() { - if (sneakers.contains(player.getUuid())) - sneakers.remove(player.getUuid()); - } - }, 1, TimeUnit.SECONDS); - } else { - sneakers.remove(player.getUuid()); - player.addStatusEffect( - new StatusEffectInstance(StatusEffects.LEVITATION, 20, 5, true, true, true)); - player.getWorld().playSound(player, player.getBlockPos(), - animal.moodSounds.get(Mood.HAPPY), SoundCategory.PLAYERS, 10F, 1); - } - } - } - - @Override - public String chatTransformations(String message) { - return destroyer.destroy(message); - } -} diff --git a/src/main/java/ovh/sad/animalrp/commands/EmoteCommand.java b/src/main/java/ovh/sad/animalrp/commands/EmoteCommand.java new file mode 100644 index 0000000..63f15fc --- /dev/null +++ b/src/main/java/ovh/sad/animalrp/commands/EmoteCommand.java @@ -0,0 +1,65 @@ +package ovh.sad.animalrp.commands; + +import java.util.stream.Collectors; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; + +import eu.pb4.placeholders.api.TextParserUtils; +import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.entity.Entity; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import ovh.sad.animalrp.AnimalRP; +import ovh.sad.animalrp.util.Emote; +import ovh.sad.animalrp.util.Emote.Emotes; + +public class EmoteCommand { + public void Command(CommandDispatcher dispatcher, CommandRegistryAccess registryAccess, + CommandManager.RegistrationEnvironment environment) { + dispatcher.register(CommandManager.literal("emote") + .then(CommandManager.argument("emote", StringArgumentType.string()) + .executes((context) -> { + Entity sender = context.getSource().getEntity(); + final String arg = StringArgumentType.getString(context, "emote"); + + if (!(sender instanceof ServerPlayerEntity)) { + context.getSource().sendFeedback( + () -> Text.literal("I'm sorry console.").withColor(8421504), false); + return 0; + } + + ServerPlayerEntity player = context.getSource().getPlayer(); + + Emote.Emotes emote; + + try { + emote = Emotes.valueOf(arg.toUpperCase()); + } catch(Exception e) { + emote = null; + } + + if(emote == null) { + this.options(context.getSource()); + return 0; + } + + if(AnimalRP.emotes.isPlayerEmoting(player.getUuid())) { + context.getSource().sendFeedback(() -> Text.literal("Stopped emoting.").withColor(8421504), false); + AnimalRP.emotes.stopEmote(player.getUuid()); + } else { + context.getSource().sendFeedback(() -> Text.literal("Emoting!").withColor(65280), false); + AnimalRP.emotes.playEmote(player.getUuid(), context.getSource().getPlayer(), emote); + } + return 1; + }))); + } + + @SuppressWarnings("deprecation") + private void options(ServerCommandSource player) { + player.sendFeedback(() -> TextParserUtils.formatText("You have " + String.join(", ", Emote.emotes.keySet().stream().map(Emote.Emotes::name).map(String::toLowerCase).collect(Collectors.toSet())) + " as options."), false); + } + +} \ No newline at end of file diff --git a/src/main/java/ovh/sad/animalrp/util/Emote.java b/src/main/java/ovh/sad/animalrp/util/Emote.java new file mode 100644 index 0000000..bd8810d --- /dev/null +++ b/src/main/java/ovh/sad/animalrp/util/Emote.java @@ -0,0 +1,160 @@ +package ovh.sad.animalrp.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import net.minecraft.particle.DustParticleEffect; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.math.Vec3d; +import ovh.sad.animalrp.AnimalRP; + +public class Emote { + class PlayerEmote { + ServerPlayerEntity entity; + Emotes emote; + + PlayerEmote( ServerPlayerEntity entity, + Emotes emote) { + this.entity = entity; + this.emote = emote; + } + } + + public enum Emotes { + HAPPY, UWU, RAWR, LOVE, RAWR2, HAPPY2 + } + + public static HashMap emotes = new HashMap(); + private HashMap players = new HashMap(); + { + emotes.put(Emotes.HAPPY, new String[] { // Emote by PotionOfHarming! + "0010000000100", + "0101000001010", + "0000000000000", + "0000011100000" + }); + emotes.put(Emotes.UWU, new String[] { + "0101000001010", + "0010000000100", + "0000000000000", + "0000011100000" + }); + + emotes.put(Emotes.RAWR, new String[] { + "0000100", + "0100010", + "0000100", + "0100010", + "0000100", + }); + emotes.put(Emotes.RAWR2, new String[] { + "001000000010", + "010100000101", + "001000000010", + "000010101000", + "000001010000", + }); + emotes.put(Emotes.LOVE, new String[] { + "0001001000", + "0010000100", + "0100001000", + "0010000100", + "0001001000", + }); + emotes.put(Emotes.HAPPY2, new String[] { + "010011100", + "000010010", + "000010010", + "010011100" + }); + } + + public Emote() { + AnimalRP.executor.scheduleWithFixedDelay(new Runnable() { + @Override + public void run() { + Set> playerset = players.entrySet(); + + for (Iterator> iterator = playerset.iterator(); iterator.hasNext();) { + Entry value = iterator.next(); + if (value.getValue().entity.isDisconnected()) { + iterator.remove(); + } else { + drawEmote(value.getValue().entity, value.getValue().emote); + } + } + } + }, 0, 250, TimeUnit.MILLISECONDS); + } + + public void drawEmote(ServerPlayerEntity player, Emotes emote) { + List locs = getEmoteLocs(player.getPos().subtract(0, player.isSneaking() ? .5 : 0, 0), + emotes.get(emote), player.getRotationVector()); + for (Vec3d loc : locs) { + player.getWorld().addParticle(new DustParticleEffect(Vec3d.unpackRgb(16777215).toVector3f(), 0.5f), loc.x, + loc.y, loc.z, 0, 0, 0); + } + } + + public static List getEmoteLocs(Vec3d loc, String[] ttEmote, Vec3d rotationLoc) { + List> locations = new ArrayList<>(); + int y = 0; + int distance = 10; + for (String s : ttEmote) { + List emoteTextLine = textToEmote(s); + List addLocs = new ArrayList<>(); + for (int x = 0; x < emoteTextLine.size(); x++) { + float y2 = (float) y / ((float) distance / 2); + float side = (((float) emoteTextLine.get(x) / distance) - ((float) ttEmote[0].length()) / 2 / distance); + Vec3d idfk = rotationLoc.normalize(); + Vec3d rotation = new Vec3d(idfk.x, 0, idfk.y); + Vec3d rot = rotation.crossProduct(new Vec3d(0, side, 0)); + Vec3d addLoc = loc.add(rot); + Vec3d newAloc = new Vec3d(addLoc.x, loc.getY() + ((float) ttEmote.length / distance - y2 + 2.25), + addLoc.y); + addLocs.add(newAloc); + } + locations.add(addLocs); + y++; + } + + List locs = new ArrayList<>(); + + for (List listLocs : locations) { + locs.addAll(listLocs); + } + + return locs; + } + + private static List textToEmote(String textToEmote) { + List locs = new ArrayList<>(); + for (int i = 0; i < textToEmote.length(); i++) { + char l = textToEmote.charAt(i); + String letter = String.valueOf(l); + if (letter.equals("1")) { + locs.add(i); + } + } + return locs; + } + + public void playEmote(UUID uuid, ServerPlayerEntity entity, Emotes emote) { + this.players.put(uuid, new PlayerEmote(entity, emote)); + + } + + public void stopEmote(UUID uuid) { + this.players.remove(uuid); + } + + public boolean isPlayerEmoting(UUID uuid) { + return this.players.containsKey(uuid); + } +} \ No newline at end of file