diff --git a/gradle.properties b/gradle.properties index c1f1ddc..26e1d6f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ parchment_mappings=1.20.1:2023.07.02 loader_version=0.14.21 # Mod Properties -mod_version=3.1 +mod_version=3.2.2 maven_group=com.cstav.genshinstrument archives_base_name=genshinstrument diff --git a/src/main/java/com/cstav/genshinstrument/GInstrumentMod.java b/src/main/java/com/cstav/genshinstrument/GInstrumentMod.java index c598ea7..6e8b321 100644 --- a/src/main/java/com/cstav/genshinstrument/GInstrumentMod.java +++ b/src/main/java/com/cstav/genshinstrument/GInstrumentMod.java @@ -3,6 +3,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.cstav.genshinstrument.block.ModBlockEntities; +import com.cstav.genshinstrument.block.ModBlocks; import com.cstav.genshinstrument.criteria.ModCriteria; import com.cstav.genshinstrument.item.ModItems; import com.cstav.genshinstrument.networking.ModPacketHandler; @@ -19,10 +21,14 @@ public void onInitialize() { ModPacketHandler.registerServerPackets(); ModCriteria.register(); - ModSounds.regsiter(); + ModSounds.load(); + + + ModBlocks.load(); + ModBlockEntities.load(); ModCreativeModeTabs.regsiter(); - ModItems.register(); + ModItems.load(); } } \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/ModCreativeModeTabs.java b/src/main/java/com/cstav/genshinstrument/ModCreativeModeTabs.java index d423923..c24b36d 100644 --- a/src/main/java/com/cstav/genshinstrument/ModCreativeModeTabs.java +++ b/src/main/java/com/cstav/genshinstrument/ModCreativeModeTabs.java @@ -12,13 +12,13 @@ public class ModCreativeModeTabs { - public static final CreativeModeTab INSTRUMENTS = FabricItemGroup.builder() + public static final CreativeModeTab INSTRUMENTS_TAB = FabricItemGroup.builder() .icon(() -> new ItemStack(ModItems.FLORAL_ZITHER)) .title(Component.translatable("genshinstrument.itemGroup.instruments")) .build(); public static void regsiter() { - Registry.register(BuiltInRegistries.CREATIVE_MODE_TAB, new ResourceLocation(GInstrumentMod.MODID, "instruments_group"), INSTRUMENTS); + Registry.register(BuiltInRegistries.CREATIVE_MODE_TAB, new ResourceLocation(GInstrumentMod.MODID, "instruments_group"), INSTRUMENTS_TAB); } diff --git a/src/main/java/com/cstav/genshinstrument/block/LyreInstrumentBlock.java b/src/main/java/com/cstav/genshinstrument/block/LyreInstrumentBlock.java new file mode 100644 index 0000000..f2387b8 --- /dev/null +++ b/src/main/java/com/cstav/genshinstrument/block/LyreInstrumentBlock.java @@ -0,0 +1,29 @@ +package com.cstav.genshinstrument.block; + +import com.cstav.genshinstrument.block.partial.AbstractInstrumentBlock; +import com.cstav.genshinstrument.block.partial.InstrumentBlockEntity; +import com.cstav.genshinstrument.networking.OpenInstrumentPacketSender; +import com.cstav.genshinstrument.util.ServerUtil; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; + + +//TODO remove after tests +public class LyreInstrumentBlock extends AbstractInstrumentBlock { + + public LyreInstrumentBlock(Properties pProperties) { + super(pProperties); + } + + @Override + public InstrumentBlockEntity newBlockEntity(BlockPos pPos, BlockState pState) { + return new InstrumentBlockEntity(pPos, pState); + } + + @Override + protected OpenInstrumentPacketSender instrumentPacketSender() { + return (player, hand) -> ServerUtil.sendInternalOpenPacket(player, hand, "windsong_lyre"); + } + +} \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/block/ModBlockEntities.java b/src/main/java/com/cstav/genshinstrument/block/ModBlockEntities.java new file mode 100644 index 0000000..df6995a --- /dev/null +++ b/src/main/java/com/cstav/genshinstrument/block/ModBlockEntities.java @@ -0,0 +1,24 @@ +package com.cstav.genshinstrument.block; + +import com.cstav.genshinstrument.GInstrumentMod; +import com.cstav.genshinstrument.block.partial.InstrumentBlockEntity; + +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; + +public abstract class ModBlockEntities { + public static void load() {}; + + public static final BlockEntityType INSTRUMENT_BE = regsiter("instrument_be", + BlockEntityType.Builder.of((pos, state) -> new InstrumentBlockEntity(pos, state), ModBlocks.LYRE_BLOCK) + .build(null) + ); + + private static BlockEntityType regsiter(final String name, final BlockEntityType bet) { + Registry.register(BuiltInRegistries.BLOCK_ENTITY_TYPE, new ResourceLocation(GInstrumentMod.MODID, name), bet); + return bet; + } +} diff --git a/src/main/java/com/cstav/genshinstrument/block/ModBlocks.java b/src/main/java/com/cstav/genshinstrument/block/ModBlocks.java new file mode 100644 index 0000000..2aa56b4 --- /dev/null +++ b/src/main/java/com/cstav/genshinstrument/block/ModBlocks.java @@ -0,0 +1,26 @@ +package com.cstav.genshinstrument.block; + +import com.cstav.genshinstrument.GInstrumentMod; + +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockBehaviour.Properties; + +public abstract class ModBlocks { + public static void load() {}; + + //NOTE for testing purposes + public static final Block + LYRE_BLOCK = register("lyre_block", new LyreInstrumentBlock(Properties.copy(Blocks.OAK_WOOD))) + ; + + + private static Block register(final String name, final Block block) { + Registry.register(BuiltInRegistries.BLOCK, new ResourceLocation(GInstrumentMod.MODID, name), block); + return block; + } + +} diff --git a/src/main/java/com/cstav/genshinstrument/block/partial/AbstractInstrumentBlock.java b/src/main/java/com/cstav/genshinstrument/block/partial/AbstractInstrumentBlock.java new file mode 100644 index 0000000..56dd558 --- /dev/null +++ b/src/main/java/com/cstav/genshinstrument/block/partial/AbstractInstrumentBlock.java @@ -0,0 +1,85 @@ +package com.cstav.genshinstrument.block.partial; + +import com.cstav.genshinstrument.client.ModArmPose; +import com.cstav.genshinstrument.event.PosePlayerArmEvent.PosePlayerArmEventArgs; +import com.cstav.genshinstrument.networking.ModPacketHandler; +import com.cstav.genshinstrument.networking.OpenInstrumentPacketSender; +import com.cstav.genshinstrument.networking.packets.instrument.NotifyInstrumentOpenPacket; +import com.cstav.genshinstrument.util.ModEntityData; +import com.cstav.genshinstrument.util.ServerUtil; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; + +public abstract class AbstractInstrumentBlock extends BaseEntityBlock { + + /** + * @param onOpenRequest A server-side event fired when the player has requested to interact + * with the instrument. + * It should should send a packet to the given player for opening this instrument's screen. + */ + public AbstractInstrumentBlock(Properties pProperties) { + super(pProperties); + } + + + // Abstract implementations + protected abstract OpenInstrumentPacketSender instrumentPacketSender(); + @Override + public abstract InstrumentBlockEntity newBlockEntity(BlockPos pPos, BlockState pState); + + + @Override + public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, + BlockHitResult pHit) { + if (pLevel.isClientSide) + return InteractionResult.CONSUME; + + + final BlockEntity be = pLevel.getBlockEntity(pPos); + if (!(be instanceof InstrumentBlockEntity)) + return InteractionResult.FAIL; + + if (ServerUtil.sendOpenPacket((ServerPlayer)pPlayer, instrumentPacketSender(), pPos)) { + ((InstrumentBlockEntity)be).users.add(pPlayer.getUUID()); + return InteractionResult.SUCCESS; + } + + return InteractionResult.FAIL; + } + + + @Override + public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pMovedByPiston) { + final BlockEntity be = pLevel.getBlockEntity(pPos); + if (!(be instanceof InstrumentBlockEntity)) + return; + + + final InstrumentBlockEntity ibe = (InstrumentBlockEntity)be; + + for (final Player player : pLevel.players()) { + ibe.users.forEach((user) -> { + ModEntityData.setInstrumentClosed(pLevel.getPlayerByUUID(user)); + ModPacketHandler.sendToClient(new NotifyInstrumentOpenPacket(user, false), (ServerPlayer)player); + }); + } + } + + + @Environment(EnvType.CLIENT) + public void onPosePlayerArm(PosePlayerArmEventArgs args) { + ModArmPose.poseForBlockInstrument(args); + } + +} \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/block/partial/InstrumentBlockEntity.java b/src/main/java/com/cstav/genshinstrument/block/partial/InstrumentBlockEntity.java new file mode 100644 index 0000000..3af0444 --- /dev/null +++ b/src/main/java/com/cstav/genshinstrument/block/partial/InstrumentBlockEntity.java @@ -0,0 +1,27 @@ +package com.cstav.genshinstrument.block.partial; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import com.cstav.genshinstrument.block.ModBlockEntities; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class InstrumentBlockEntity extends BlockEntity { + + public Set users = new HashSet(); + + public InstrumentBlockEntity(BlockEntityType pType, BlockPos pPos, BlockState pBlockState) { + super(pType, pPos, pBlockState); + } + + //TODO remove after tests + public InstrumentBlockEntity(BlockPos pPos, BlockState pBlockState) { + super(ModBlockEntities.INSTRUMENT_BE, pPos, pBlockState); + } + +} \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/client/ClientInitiator.java b/src/main/java/com/cstav/genshinstrument/client/ClientInitiator.java index 20afe9c..eb31a8b 100644 --- a/src/main/java/com/cstav/genshinstrument/client/ClientInitiator.java +++ b/src/main/java/com/cstav/genshinstrument/client/ClientInitiator.java @@ -7,6 +7,7 @@ import com.cstav.genshinstrument.client.gui.screens.instrument.drum.AratakisGreatAndGloriousDrumScreen; import com.cstav.genshinstrument.client.gui.screens.instrument.floralzither.FloralZitherScreen; import com.cstav.genshinstrument.client.gui.screens.instrument.partial.InstrumentThemeLoader; +import com.cstav.genshinstrument.client.gui.screens.instrument.test.banjo.BanjoInstrumentScreen; import com.cstav.genshinstrument.client.gui.screens.instrument.vintagelyre.VintageLyreScreen; import com.cstav.genshinstrument.client.gui.screens.instrument.windsonglyre.WindsongLyreScreen; import com.cstav.genshinstrument.event.ClientEvents; @@ -20,8 +21,11 @@ public class ClientInitiator implements ClientModInitializer { private static final List> LOAD_ME = List.of( - AratakisGreatAndGloriousDrumScreen.class, FloralZitherScreen.class, VintageLyreScreen.class, - WindsongLyreScreen.class + WindsongLyreScreen.class, VintageLyreScreen.class, + FloralZitherScreen.class, AratakisGreatAndGloriousDrumScreen.class, + + //TODO remove after tests + BanjoInstrumentScreen.class ); diff --git a/src/main/java/com/cstav/genshinstrument/client/ModArmPose.java b/src/main/java/com/cstav/genshinstrument/client/ModArmPose.java new file mode 100644 index 0000000..2b6dd25 --- /dev/null +++ b/src/main/java/com/cstav/genshinstrument/client/ModArmPose.java @@ -0,0 +1,37 @@ +package com.cstav.genshinstrument.client; + +import com.cstav.genshinstrument.event.PosePlayerArmEvent.HandType; +import com.cstav.genshinstrument.event.PosePlayerArmEvent.PosePlayerArmEventArgs; +import com.cstav.genshinstrument.util.ModEntityData; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.model.geom.ModelPart; + +@Environment(EnvType.CLIENT) +public abstract class ModArmPose { + public static final float HAND_HEIGHT_ROT = .9f; + + public static void poseForItemInstrument(final PosePlayerArmEventArgs args) { + if (!ModEntityData.isInstrumentOpen(args.player) || !ModEntityData.isInstrumentItem(args.player)) + return; + + final ModelPart arm = args.arm; + if (args.hand == HandType.LEFT) { + arm.xRot = -HAND_HEIGHT_ROT; + arm.zRot = 0.85f; + } else { + arm.xRot = -HAND_HEIGHT_ROT; + arm.zRot = -0.35f; + } + + args.setCanceled(true); + } + + public static void poseForBlockInstrument(final PosePlayerArmEventArgs args) { + args.arm.xRot = -HAND_HEIGHT_ROT; + + args.setCanceled(true); + } + +} \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/client/config/ModClientConfigs.java b/src/main/java/com/cstav/genshinstrument/client/config/ModClientConfigs.java index 9cd4afa..fad1b26 100644 --- a/src/main/java/com/cstav/genshinstrument/client/config/ModClientConfigs.java +++ b/src/main/java/com/cstav/genshinstrument/client/config/ModClientConfigs.java @@ -22,7 +22,7 @@ public class ModClientConfigs { public static final EnumValue GRID_LABEL_TYPE; public static final EnumValue CHANNEL_TYPE; public static final BooleanValue STOP_MUSIC_ON_PLAY, EMIT_RING_ANIMATION, SHARED_INSTRUMENT, - RENDER_BACKGROUND, ACCEPTED_GENSHIN_CONSENT, ACCURATE_ACCIDENTALS; + RENDER_BACKGROUND, ACCEPTED_GENSHIN_CONSENT, ACCURATE_NOTES; public static final EnumValue ZITHER_SOUND_TYPE; public static final EnumValue DRUM_LABEL_TYPE; @@ -45,7 +45,7 @@ public class ModClientConfigs { SHARED_INSTRUMENT = configBuilder.comment("Defines whether you will see others playing on your instrument's screen") .define("display_other_players", true); RENDER_BACKGROUND = configBuilder.define("render_background", true); - ACCURATE_ACCIDENTALS = configBuilder.define("accurate_accidentals", true); + ACCURATE_NOTES = configBuilder.define("accurate_notes", true); ACCEPTED_GENSHIN_CONSENT = configBuilder.define("accepted_genshin_consent", false); diff --git a/src/main/java/com/cstav/genshinstrument/client/config/enumType/ZitherSoundType.java b/src/main/java/com/cstav/genshinstrument/client/config/enumType/ZitherSoundType.java index 7cdbbe5..4f19319 100644 --- a/src/main/java/com/cstav/genshinstrument/client/config/enumType/ZitherSoundType.java +++ b/src/main/java/com/cstav/genshinstrument/client/config/enumType/ZitherSoundType.java @@ -5,6 +5,10 @@ import com.cstav.genshinstrument.sound.ModSounds; import com.cstav.genshinstrument.sound.NoteSound; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; + +@Environment(EnvType.CLIENT) public enum ZitherSoundType { OLD(() -> ModSounds.ZITHER_OLD_NOTE_SOUNDS), NEW(() -> ModSounds.ZITHER_NEW_NOTE_SOUNDS); diff --git a/src/main/java/com/cstav/genshinstrument/client/config/enumType/label/NoteGridLabel.java b/src/main/java/com/cstav/genshinstrument/client/config/enumType/label/NoteGridLabel.java index ddea65f..2470865 100644 --- a/src/main/java/com/cstav/genshinstrument/client/config/enumType/label/NoteGridLabel.java +++ b/src/main/java/com/cstav/genshinstrument/client/config/enumType/label/NoteGridLabel.java @@ -28,7 +28,7 @@ public enum NoteGridLabel implements INoteLabel { ).append(LabelUtil.getCutNoteName(ng(note)).substring(1)) ), ABC_1((note) -> Component.literal( - LabelUtil.ABC[ng(note).row] + (gs(note).columns() - ng(note).column) + String.valueOf(LabelUtil.ABC[ng(note).row]) + (gs(note).columns() - ng(note).column) )), ABC_2((note) -> Component.literal( ( diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/drum/AratakisGreatAndGloriousDrumScreen.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/drum/AratakisGreatAndGloriousDrumScreen.java index 6fcb7cf..e9beb6a 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/drum/AratakisGreatAndGloriousDrumScreen.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/drum/AratakisGreatAndGloriousDrumScreen.java @@ -9,8 +9,6 @@ import com.cstav.genshinstrument.client.gui.screens.instrument.partial.note.NoteButton; import com.cstav.genshinstrument.client.gui.screens.options.instrument.AbstractInstrumentOptionsScreen; import com.cstav.genshinstrument.client.gui.screens.options.instrument.DrumOptionsScren; -import com.cstav.genshinstrument.sound.ModSounds; -import com.cstav.genshinstrument.sound.NoteSound; import com.mojang.blaze3d.platform.InputConstants.Key; import net.fabricmc.api.EnvType; @@ -34,7 +32,7 @@ public ResourceLocation getInstrumentId() { } @Override - public ResourceLocation getNotesLocation() { + public ResourceLocation getNoteSymbolsLocation() { return getResourceFromRoot("note/notes.png"); } @@ -58,15 +56,15 @@ protected AbstractInstrumentOptionsScreen initInstrumentOptionsScreen() { protected void init() { initOptionsButton(height/2 + 25); - final LinearLayout layout1 = createRow(DrumButtonType.DON, 2.25f), - layout2 = createRow(DrumButtonType.KA, 1.5f); + final LinearLayout layout1 = createRow(DrumButtonType.DON, 2), + layout2 = createRow(DrumButtonType.KA, 1.3f); // Make layout magic layout1.arrangeElements(); layout2.arrangeElements(); layout1.setPosition((width - layout1.getWidth()) / 2, (int)(height * .8f)); - layout2.setPosition((width - layout2.getWidth()) / 2, layout1.getY() - layout1.getHeight()); + layout2.setPosition((width - layout2.getWidth()) / 2, layout1.getY() - layout1.getHeight()/2); layout1.arrangeElements(); layout2.arrangeElements(); @@ -84,7 +82,7 @@ protected void init() { private LinearLayout createRow(DrumButtonType type, float widthPercent) { final LinearLayout layout = new LinearLayout( 0, 0, - (int)(width/widthPercent), NoteButton.getSize(), + (int)(width/widthPercent), getNoteSize(), Orientation.HORIZONTAL ); @@ -101,12 +99,7 @@ private NoteButton createButton(DrumButtonType btnType, LinearLayout container, return btn; } - - - @Override - public NoteSound[] getSounds() { - return ModSounds.GLORIOUS_DRUM; - } + private static final InstrumentThemeLoader THEME_LOADER = initThemeLoader(GInstrumentMod.MODID, INSTRUMENT_ID); @Override diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/drum/DrumButtonType.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/drum/DrumButtonType.java index aceed97..faec984 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/drum/DrumButtonType.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/drum/DrumButtonType.java @@ -10,25 +10,22 @@ import net.fabricmc.api.Environment; public enum DrumButtonType { - DON(0, ModSounds.GLORIOUS_DRUM[0], "glorious_drum.don"), - KA(1, ModSounds.GLORIOUS_DRUM[1], "glorious_drum.ka"); + DON(ModSounds.GLORIOUS_DRUM[0], "glorious_drum.don"), + KA(ModSounds.GLORIOUS_DRUM[1], "glorious_drum.ka"); private final String transKey; private final NoteSound sound; - private final int index; - private DrumButtonType(int index, NoteSound sound, String transKey) { + private DrumButtonType(NoteSound sound, String transKey) { this.sound = sound; - this.index = index; - this.transKey = INoteLabel.TRANSLATABLE_PATH + transKey; } public NoteSound getSound() { return sound; } - public int getIndex() { - return index; + public int getSpriteIndex(final boolean isRight) { + return ((this == KA) && isRight) ? 2 : ordinal(); } public String getTransKey() { return transKey; diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/drum/DrumNoteButton.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/drum/DrumNoteButton.java index 4d2e134..b23d847 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/drum/DrumNoteButton.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/drum/DrumNoteButton.java @@ -34,10 +34,7 @@ public DrumNoteIdentifier getIdentifier() { @Override protected NoteButtonRenderer initNoteRenderer() { - return new NoteButtonRenderer(this, - btnType.getIndex(), 2, - 13, .34f, 1.01f - ); + return new NoteButtonRenderer(this, btnType.getSpriteIndex(isRight), 3); } } diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/AbstractGridInstrumentScreen.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/AbstractGridInstrumentScreen.java index 27290de..e430eaf 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/AbstractGridInstrumentScreen.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/AbstractGridInstrumentScreen.java @@ -3,6 +3,7 @@ import java.awt.Color; import java.util.Map; import java.util.NoSuchElementException; +import java.util.function.Consumer; import com.cstav.genshinstrument.GInstrumentMod; import com.cstav.genshinstrument.client.ClientUtil; @@ -14,6 +15,7 @@ import com.cstav.genshinstrument.client.keyMaps.KeyMappings; import com.cstav.genshinstrument.networking.buttonidentifier.NoteButtonIdentifier; import com.cstav.genshinstrument.networking.buttonidentifier.NoteGridButtonIdentifier; +import com.cstav.genshinstrument.sound.NoteSound; import com.mojang.blaze3d.platform.InputConstants.Key; import com.mojang.blaze3d.systems.RenderSystem; @@ -42,6 +44,41 @@ public int columns() { public int rows() { return DEF_ROWS; } + + /** + *

Gets the sound array used by this instrument. + * Its length must be equal to this Note Grid's {@code row*column}.

+ * Each sound is used on press by the their index on the grid. + * @return The array of sounds used by this instruments. + */ + public abstract NoteSound[] getSounds(); + + + /** + *

+ * An SSTI instrument is a Singular Sound-Type Instrument, such that + * only the first note in {@link AbstractGridInstrumentScreen#getSounds} will get used. + *

+ * Notes will start with the {@link NoteSound#MIN_PITCH set minimum pitch}, + * and increment their pitch up by 1 for every new instance. + *

+ * This behaviour can be changed by overriding {@link AbstractGridInstrumentScreen#initNoteGrid}. + */ + public boolean isSSTI() { + return false; + } + + @Override + public void setPitch(int pitch) { + if (!isSSTI()) + super.setPitch(pitch); + } + + @Override + protected void initPitch(Consumer pitchConsumer) { + if (!isSSTI()) + super.initPitch(pitchConsumer); + } /** @@ -77,9 +114,9 @@ public NoteButton getNoteButton(final int row, final int column) throws IndexOut * @return The new Note Grid */ public NoteGrid initNoteGrid() { - return new NoteGrid( - rows(), columns(), getSounds(), this - ); + return isSSTI() + ? new NoteGrid(getSounds(), this, NoteSound.MIN_PITCH) + : new NoteGrid(getSounds(), this); } public final NoteGrid noteGrid = initNoteGrid(); @@ -96,7 +133,7 @@ protected AbstractInstrumentOptionsScreen initInstrumentOptionsScreen() { } @Override - public ResourceLocation getNotesLocation() { + public ResourceLocation getNoteSymbolsLocation() { return new ResourceLocation(GInstrumentMod.MODID, getGlobalRootPath() + "grid_notes.png"); } @@ -132,10 +169,7 @@ public void render(GuiGraphics gui, int pMouseX, int pMouseY, float pPartialTick * to customize the background. */ protected void renderInstrumentBackground(final GuiGraphics gui) { - if (columns() != 3) - return; - - final int clefX = grid.getX() - NoteButton.getSize() + 8; + final int clefX = grid.getX() - getNoteSize() + 8; for (int i = 0; i < columns(); i++) { renderClef(gui, i, clefX); @@ -144,8 +178,8 @@ protected void renderInstrumentBackground(final GuiGraphics gui) { } protected void renderClef(final GuiGraphics gui, final int index, final int x) { - gui.blit(getResourceFromGlob("background/clefs.png"), - x, grid.getY() + (NoteButton.getSize() + 16) * index, + gui.blit(getInternalResourceFromGlob("background/clefs.png"), + x, grid.getY() + NoteGrid.getPaddingVert() + getLayerAddition(index) - 5, index * CLEF_WIDTH, 0, CLEF_WIDTH, CLEF_HEIGHT, CLEF_WIDTH*3, CLEF_HEIGHT @@ -153,12 +187,19 @@ protected void renderClef(final GuiGraphics gui, final int index, final int x) { } protected void renderStaff(final GuiGraphics gui, final int index) { - gui.blit(getResourceFromGlob("background/staff.png"), - grid.getX() + 2, grid.getY() + 8 + ((NoteButton.getSize() + NoteGrid.PADDING_VERT + 6) * index), + gui.blit(getInternalResourceFromGlob("background/staff.png"), + grid.getX() + 2, grid.getY() + NoteGrid.getPaddingVert() + getLayerAddition(index), 0, 0, - grid.getWidth() - 5, NoteButton.getSize(), - grid.getWidth() - 5, NoteButton.getSize() + grid.getWidth() - 5, getNoteSize(), + grid.getWidth() - 5, getNoteSize() ); } + + /** + * Used for background rendering while determining how deep to go down + */ + protected int getLayerAddition(final int index) { + return index * (getNoteSize() + NoteGrid.getPaddingVert()*2); + } } diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/AbstractInstrumentScreen.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/AbstractInstrumentScreen.java index d4c39d4..4c48cf0 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/AbstractInstrumentScreen.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/AbstractInstrumentScreen.java @@ -3,11 +3,14 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Optional; +import java.util.function.Consumer; +import com.cstav.genshinstrument.GInstrumentMod; import com.cstav.genshinstrument.client.config.ModClientConfigs; import com.cstav.genshinstrument.client.gui.screens.instrument.GenshinConsentScreen; import com.cstav.genshinstrument.client.gui.screens.instrument.partial.note.NoteButton; import com.cstav.genshinstrument.client.gui.screens.options.instrument.AbstractInstrumentOptionsScreen; +import com.cstav.genshinstrument.item.InstrumentItem; import com.cstav.genshinstrument.networking.ModPacketHandler; import com.cstav.genshinstrument.networking.buttonidentifier.NoteButtonIdentifier; import com.cstav.genshinstrument.networking.packets.instrument.CloseInstrumentPacket; @@ -26,21 +29,41 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; @Environment(EnvType.CLIENT) public abstract class AbstractInstrumentScreen extends Screen { public static final String[] DEFAULT_NOTE_LAYOUT = new String[] {"C", "D", "E", "F", "G", "A", "B"}; + + @SuppressWarnings("resource") + public int getNoteSize() { + final int guiScale = Minecraft.getInstance().options.guiScale().get(); + + return switch (guiScale) { + case 0 -> 40; + case 1 -> 35; + case 2 -> 46; + case 3 -> 48; + case 4 -> 41; + default -> guiScale * 18; + }; + } /** * The set pitch of all note buttons in this screen */ - private int pitch = ModClientConfigs.PITCH.get().intValue(); + private int pitch; public int getPitch() { return pitch; } public void setPitch(int pitch) { this.pitch = NoteSound.clampPitch(pitch); + notesIterable().forEach((note) -> note.setPitch(this.pitch)); + } + + protected void initPitch(final Consumer pitchConsumer) { + pitchConsumer.accept(ModClientConfigs.PITCH.get().intValue()); } @@ -64,28 +87,47 @@ protected static final InstrumentThemeLoader initThemeLoader(String modId, Strin /** * @return The location of all labels present in this instrument */ - public abstract ResourceLocation getNotesLocation(); + public abstract ResourceLocation getNoteSymbolsLocation(); - - /** - *

Gets the sound array used by this instrument. - * Its length must be equal to this Note Grid's {@code row*column}.

- * Each sound is used on press by the their index on the grid. - * @return The array of sounds used by this instruments. - */ - public abstract NoteSound[] getSounds(); /** * @return The layout of the note names accross the instrument's rows. - * @apiNote All built-in instruments' layouts are derived from + * @implNote All built-in instruments' layouts are derived from * - * Genshin Music app configs + * Specy's Genshin Music app * */ public String[] noteLayout() { return DEFAULT_NOTE_LAYOUT; } + /** + * Handles this instrument being closed by either recieving a false signal from {@link InstrumentOpenProvider#isOpen} + * or, if it is an item, if the item has been ripped out of the player's hands. + * @return Whether the instrument has closed as a result of this method + */ + public boolean handleAbruptClosing() { + final Player player = minecraft.player; + + if (!ModEntityData.isInstrumentOpen(player)) { + onClose(false); + return true; + } + + // Handle item not in hand seperately + // This is done like so because there is no event (that I know of) for when an item is moved/removed + if ( + (ModEntityData.isInstrumentItem(player) && interactionHand.isPresent()) + && !(player.getItemInHand(interactionHand.get()).getItem() instanceof InstrumentItem) + ) { + onClose(true); + return true; + } + + return false; + } + + /** * @return Whether this instrument is derived from Genshin Impact * @apiNote This value will help the mod determine whether a disclaimer pop-up should appear upon opening this @@ -122,13 +164,25 @@ public static String getGlobalRootPath() { return "textures/gui/instrument/"; } public ResourceLocation getResourceFromGlob(final String path) { - return new ResourceLocation(getModId(), getGlobalRootPath() + path); + return getSourcePath().withPath(getGlobalRootPath() + path); + } + public static ResourceLocation getInternalResourceFromGlob(final String path) { + return new ResourceLocation(GInstrumentMod.MODID, getGlobalRootPath() + path); } /** - * Shorthand for {@code getRootPath() + getInstrumentId()} + * Gets the resource path under this instrument. + * It will usually be {@code textures/gui/instrument//}. + * {@code instrument} is as specified by {@link AbstractInstrumentScreen#getSourcePath getSourcePath}. */ protected String getPath() { - return getGlobalRootPath() + getInstrumentId().getPath() + "/"; + return getGlobalRootPath() + getSourcePath().getPath() + "/"; + } + + /** + * Override this method if you want to reference another directory for resources + */ + public ResourceLocation getSourcePath() { + return getInstrumentId(); } public String getModId() { @@ -143,22 +197,23 @@ public String getModId() { * @see {@link AbstractInstrumentScreen#getResourceFrom(ResourceLocation, String)} */ public ResourceLocation getResourceFromRoot(final String path) { - return new ResourceLocation(getModId(), getPath() + path); + return getSourcePath().withPath(getPath() + path); } public final AbstractInstrumentOptionsScreen optionsScreen = initInstrumentOptionsScreen(); - public final InteractionHand interactionHand; + public final Optional interactionHand; public AbstractInstrumentScreen(final InteractionHand hand) { super(CommonComponents.EMPTY); - interactionHand = hand; + interactionHand = Optional.ofNullable(hand); } @Override protected void init() { + initPitch(this::setPitch); optionsScreen.init(minecraft, width, height); if (isGenshinInstrument() && !ModClientConfigs.ACCEPTED_GENSHIN_CONSENT.get()) @@ -227,20 +282,36 @@ private void unlockFocused() { ((NoteButton)getFocused()).locked = false; } + + private boolean isOptionsScreenActive; + public boolean isOptionsScreenActive() { + return isOptionsScreenActive; + } + public void onOptionsOpen() { setFocused(null); minecraft.setScreen(optionsScreen); + + isOptionsScreenActive = true; } public void onOptionsClose() { minecraft.setScreen(this); + isOptionsScreenActive = false; } @Override public void onClose() { - ModEntityData.setInstrumentOpen(minecraft.player, false); - ModPacketHandler.sendToServer(new CloseInstrumentPacket()); + onClose(true); + } + public void onClose(final boolean notify) { + if (notify) { + ModEntityData.setInstrumentClosed(minecraft.player); + ModPacketHandler.sendToServer(new CloseInstrumentPacket()); + } + if (isOptionsScreenActive) + optionsScreen.onClose(); super.onClose(); } diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/InstrumentThemeLoader.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/InstrumentThemeLoader.java index 25b914f..1fade42 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/InstrumentThemeLoader.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/InstrumentThemeLoader.java @@ -1,8 +1,8 @@ package com.cstav.genshinstrument.client.gui.screens.instrument.partial; import java.awt.Color; -import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.function.Consumer; import java.util.function.Function; @@ -30,6 +30,8 @@ */ @Environment(EnvType.CLIENT) public class InstrumentThemeLoader { + private static final HashMap CACHES = new HashMap<>(); + private static final ArrayList LOADERS = new ArrayList<>(); private static final Color DEF_NOTE_PRESSED_THEME = new Color(255, 249, 239); @@ -100,21 +102,41 @@ public static void onResourcesReload(EventArgs.Empty empty) { for (final InstrumentThemeLoader instrumentLoader : LOADERS) { final ResourceLocation styleLocation = instrumentLoader.getInstrumentStyleLocation(); + try { + JsonObject styleInfo; + + // If it is already cached, then let it be + if (CACHES.containsKey(styleLocation)) { + styleInfo = CACHES.get(styleLocation); + + for (final Consumer listener : instrumentLoader.listeners) + listener.accept(styleInfo); + + GInstrumentMod.LOGGER.info("Loaded instrument style from the already cached "+styleLocation); + continue; + } + + + styleInfo = JsonParser.parseReader( + rManager.getResource(styleLocation).get().openAsReader() + ).getAsJsonObject(); // Call all load listeners on the current loader for (final Consumer listener : instrumentLoader.listeners) - listener.accept(JsonParser.parseReader( - rManager.getResource(styleLocation).get().openAsReader() - ).getAsJsonObject()); + listener.accept(styleInfo); - GInstrumentMod.LOGGER.info("Loaded instrument style from "+styleLocation); + + CACHES.put(styleLocation, styleInfo); + GInstrumentMod.LOGGER.info("Loaded and cached instrument style from "+styleLocation); - } catch (IOException e) { - GInstrumentMod.LOGGER.error("Unable to load instrument styler for " + styleLocation, e); + } catch (Exception e) { + GInstrumentMod.LOGGER.error("Met an exception upon loading the instrument styler from "+styleLocation, e); continue; } } + + CACHES.clear(); } diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteButton.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteButton.java index 4108695..fff8b04 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteButton.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteButton.java @@ -10,6 +10,7 @@ import com.cstav.genshinstrument.networking.buttonidentifier.NoteButtonIdentifier; import com.cstav.genshinstrument.networking.packets.instrument.InstrumentPacket; import com.cstav.genshinstrument.sound.NoteSound; +import com.cstav.genshinstrument.util.ModEntityData; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -19,31 +20,18 @@ import net.minecraft.client.gui.narration.NarratedElementType; import net.minecraft.client.gui.narration.NarrationElementOutput; import net.minecraft.client.sounds.SoundManager; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; @Environment(EnvType.CLIENT) public abstract class NoteButton extends AbstractButton { - - @SuppressWarnings("resource") - public static int getSize() { - final int guiScale = Minecraft.getInstance().options.guiScale().get(); - - return switch (guiScale) { - case 0 -> 40; - case 1 -> 35; - case 2 -> 46; - case 3 -> 48; - default -> guiScale * 18; - }; - } - - /** - *

Returns the identifier of this button.

- * You may use the {@link DefaultNoteButtonIdentifier default implementation} if you're too lazy. + * Returns the UI identifier of this button. */ public NoteButtonIdentifier getIdentifier() { - return new DefaultNoteButtonIdentifier(getSound()); + return new DefaultNoteButtonIdentifier(getSound(), getPitch(), false); } @@ -53,18 +41,24 @@ public NoteButtonIdentifier getIdentifier() { private NoteSound sound; private NoteLabelSupplier labelSupplier; - private NoteButtonRenderer noteRenderer; + protected NoteButtonRenderer noteRenderer; protected abstract NoteButtonRenderer initNoteRenderer(); public NoteButton(NoteSound sound, - NoteLabelSupplier labelSupplier, AbstractInstrumentScreen instrumentScreen) { + NoteLabelSupplier labelSupplier, AbstractInstrumentScreen instrumentScreen, int pitch) { + + super(0, 0, 42, 42, Component.empty()); - super(0, 0, getSize(), getSize(), null); + width = height = instrumentScreen.getNoteSize(); this.sound = sound; this.labelSupplier = labelSupplier; this.instrumentScreen = instrumentScreen; + this.pitch = pitch; + } + public NoteButton(NoteSound sound, NoteLabelSupplier labelSupplier, AbstractInstrumentScreen instrumentScreen) { + this(sound, labelSupplier, instrumentScreen, instrumentScreen.getPitch()); } @@ -78,16 +72,13 @@ public NoteLabelSupplier getLabelSupplier() { public void updateNoteLabel() { setMessage(getLabelSupplier().get(this)); } + public NoteSound getSound() { return sound; } public void setSound(NoteSound sound) { this.sound = sound; - - // Update the sound for the sound (default) identifier - if (getIdentifier() instanceof DefaultNoteButtonIdentifier) - ((DefaultNoteButtonIdentifier)getIdentifier()).setSound(sound); } @@ -112,7 +103,7 @@ public int getInitY() { } public Point getCenter() { - return ClientUtil.getInitCenter(initX, initY, getSize(), width); + return ClientUtil.getInitCenter(initX, initY, instrumentScreen.getNoteSize(), width); } public void moveToCenter() { final Point center = getCenter(); @@ -120,6 +111,15 @@ public void moveToCenter() { } + private int pitch; + public int getPitch() { + return pitch; + } + public void setPitch(final int pitch) { + this.pitch = NoteSound.clampPitch(pitch); + updateNoteLabel(); + } + public NoteNotation getNotation() { return NoteNotation.NONE; } @@ -147,12 +147,19 @@ public void play() { if (locked) return; - sound.playLocally(instrumentScreen.getPitch()); + sound.playLocally(getPitch()); + + + final Player player = minecraft.player; + + final BlockPos pos = ModEntityData.isInstrumentItem(player) + ? player.blockPosition() + : ModEntityData.getInstrumentBlockPos(player); // Send sound packet to server ModPacketHandler.sendToServer( - new InstrumentPacket( - sound, instrumentScreen.getPitch(), + new InstrumentPacket(pos, + sound, getPitch(), instrumentScreen.interactionHand, instrumentScreen.getInstrumentId(), getIdentifier() ) diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteButtonRenderer.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteButtonRenderer.java index c36d2ab..2d4d0f4 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteButtonRenderer.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteButtonRenderer.java @@ -18,8 +18,8 @@ public class NoteButtonRenderer { private static final Minecraft MINECRAFT = Minecraft.getInstance(); private static final double - FLAT_TEXTURE_HEIGHT_MULTIPLIER = 3.7f/1.3f, - FLAT_TEXTURE_WIDTH_MULTIPLIER = 1.7f/1.3f, + FLAT_TEXTURE_HEIGHT_MULTIPLIER = 3.7/1.3, + FLAT_TEXTURE_WIDTH_MULTIPLIER = 1.7/1.3, SHARP_MULTIPLIER = .8f, DOUBLE_SHARP_MULTIPLIER = .9f ; @@ -32,10 +32,8 @@ public class NoteButtonRenderer { noteLocation, noteBgLocation, accidentalsLocation; // Texture properties - protected final int noteTextureRow, rowsInNoteTexture; - private final int noteTextureWidth; - //FIXME Actually figure out a formula instead of guessing - private final float randomAssMultiplier1, randomAssMultiplier2; + public int noteTextureRow; + protected final int rowsInNoteTexture; // Animations public final NoteAnimationController noteAnimation; @@ -43,8 +41,7 @@ public class NoteButtonRenderer { protected final ArrayList rings = new ArrayList<>(); - public NoteButtonRenderer(NoteButton noteButton, int noteTextureRow, int rowsInNoteTexture, - int noteTextureWidth, float randomAssMultiplier1, float randomAssMultiplier2) { + public NoteButtonRenderer(NoteButton noteButton, int noteTextureRow, int rowsInNoteTexture) { this.noteButton = noteButton; instrumentScreen = noteButton.instrumentScreen; @@ -57,15 +54,9 @@ public NoteButtonRenderer(NoteButton noteButton, int noteTextureRow, int rowsInN rootLocation = instrumentScreen.getResourceFromRoot("note"); - noteLocation = instrumentScreen.getNotesLocation(); + noteLocation = instrumentScreen.getNoteSymbolsLocation(); noteBgLocation = getResourceFromRoot("note_bg.png"); accidentalsLocation = getResourceFromRoot("accidentals.png"); - - - - this.noteTextureWidth = noteTextureWidth; - this.randomAssMultiplier1 = randomAssMultiplier1; - this.randomAssMultiplier2 = randomAssMultiplier2; } @@ -117,12 +108,10 @@ protected void renderNote(final GuiGraphics gui, final InstrumentThemeLoader the gui.blit(noteLocation, noteButton.getX() + noteWidth/2, noteButton.getY() + noteHeight/2, - //NOTE: I have no clue whatsoever how on earth these 1.025 and .9 multipliers actually work. - // Like seriously wtf why fkuaherjgaeorg i hate maths - //NOTE: Moved said numbers to the randomAss vars - noteWidth * noteTextureRow * randomAssMultiplier2, 0, + noteWidth * noteTextureRow, 0, + noteWidth, noteHeight, - (int)(noteWidth * (noteTextureWidth / rowsInNoteTexture) * randomAssMultiplier1), noteButton.getHeight()/2 + noteWidth * rowsInNoteTexture, noteButton.getHeight()/2 ); ClientUtil.resetShaderColor(); @@ -187,9 +176,9 @@ protected void renderAccidental(GuiGraphics gui, int index, int offsetX, int off gui.blit(accidentalsLocation, noteButton.getX() - 9 + offsetX, noteButton.getY() - 6 + offsetY, - noteButton.isPlaying() ? textureWidth/2 : 0, (spritePartHeight) * index - index, + noteButton.isPlaying() ? textureWidth/2 : 0, spritePartHeight * index - index, - textureWidth/2, spritePartHeight + ((index == 1) ? 3 : 0), + textureWidth/2, spritePartHeight, textureWidth - (((index != 0) && noteButton.isPlaying()) ? 1 : 0), textureHeight ); } diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteGrid.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteGrid.java index 6d322fe..e59c4f6 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteGrid.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteGrid.java @@ -23,7 +23,13 @@ */ @Environment(EnvType.CLIENT) public class NoteGrid implements Iterable { - public static final int PADDING_HORZ = 9, PADDING_VERT = 7; + + public static int getPaddingHorz() { + return 9; + } + public static int getPaddingVert() { + return 7; + } public final AbstractGridInstrumentScreen instrumentScreen; @@ -31,30 +37,63 @@ public class NoteGrid implements Iterable { private NoteSound[] noteSounds; public final int rows, columns; + public final boolean isSSTI; + + /** + * @param begginingNote The note to start the linear pitch increment. Only gets used if this is an SSTI instrument. + * @param noteSkip The amount of pitch to skip for each note button. Only gets used if this is an SSTI instrument. + */ + public NoteGrid(NoteSound[] noteSounds, AbstractGridInstrumentScreen instrumentScreen, + int begginingNote, int noteSkip) { - public NoteGrid(int rows, int columns, NoteSound[] noteSounds, AbstractGridInstrumentScreen instrumentScreen) { this.instrumentScreen = instrumentScreen; - this.rows = rows; - this.columns = columns; this.noteSounds = noteSounds; + rows = instrumentScreen.rows(); + columns = instrumentScreen.columns(); + + isSSTI = instrumentScreen.isSSTI(); + // Construct the note grid notes = new NoteButton[columns][rows]; - for (int i = 0; i < columns; i++) { + for (int i = columns - 1; i >= 0; i--) { final NoteButton[] buttonRow = new NoteButton[rows]; for (int j = 0; j < rows; j++) - buttonRow[j] = createNote(j, i); + if (isSSTI) { + buttonRow[j] = createNote(j, i, begginingNote); + begginingNote += noteSkip; + } else + buttonRow[j] = createNote(j, i); notes[i] = buttonRow; } } - + public NoteGrid(NoteSound[] noteSounds, AbstractGridInstrumentScreen instrumentScreen) { + this(noteSounds, instrumentScreen, 0, 0); + } + /** + * @param begginingNote The note to start the linear pitch increment. Only gets used if this is an SSTI instrument. + */ + public NoteGrid(NoteSound[] noteSounds, AbstractGridInstrumentScreen instrumentScreen, int begginingNote) { + this(noteSounds, instrumentScreen, begginingNote, 1); + } + + /** + * Creates a note for a singular sound type instrument + */ + protected NoteButton createNote(int row, int column, int pitch) { + return new NoteGridButton(row, column, + noteSounds[0], getLabelSupplier() + , instrumentScreen, pitch); + } protected NoteButton createNote(int row, int column) { return new NoteGridButton(row, column, getSoundAt(noteSounds, row, column), getLabelSupplier() , instrumentScreen); } + + /** * Evaulates the sound at the given indexes, and returns it * @param sounds The sound array of this instrument @@ -79,15 +118,15 @@ public void setNoteSounds(final NoteSound[] noteSounds) { for (int i = 0; i < columns; i++) for (int j = 0; j < rows; j++) - notes[i][j].setSound(getSoundAt(noteSounds, j, i)); + notes[i][j].setSound(isSSTI ? noteSounds[0] : getSoundAt(noteSounds, j, i)); } public HashMap genKeyboardMap(final Key[][] keyMap) { final HashMap result = new HashMap<>(rows * columns); - for (int i = 0; i < keyMap.length; i++) - for (int j = 0; j < keyMap[0].length; j++) + for (int i = 0; i < columns; i++) + for (int j = 0; j < rows; j++) result.put(keyMap[i][j], notes[i][j]); return result; @@ -103,7 +142,7 @@ public HashMap genKeyboardMap(final Key[][] keyMap) { */ public AbstractLayout initNoteGridLayout(final float vertAlignment, final int screenWidth, final int screenHeight) { final GridLayout grid = new GridLayout(); - grid.defaultCellSetting().padding(PADDING_HORZ, PADDING_VERT); + grid.defaultCellSetting().padding(getPaddingHorz(), getPaddingVert()); final RowHelper rowHelper = grid.createRowHelper(rows); forEach(rowHelper::addChild); diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteGridButton.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteGridButton.java index 734bc98..27e9fd6 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteGridButton.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteGridButton.java @@ -22,6 +22,13 @@ public NoteGridButton(int row, int column, NoteSound sound, NoteLabelSupplier la this.row = row; this.column = column; } + public NoteGridButton(int row, int column, NoteSound sound, NoteLabelSupplier labelSupplier, + AbstractGridInstrumentScreen instrumentScreen, int pitch) { + super(sound, labelSupplier, instrumentScreen, pitch); + + this.row = row; + this.column = column; + } @Override public NoteGridButtonIdentifier getIdentifier() { @@ -30,7 +37,7 @@ public NoteGridButtonIdentifier getIdentifier() { @Override public NoteNotation getNotation() { - return ModClientConfigs.ACCURATE_ACCIDENTALS.get() + return ModClientConfigs.ACCURATE_NOTES.get() ? NoteNotation.getNotation(LabelUtil.getNoteName(this)) : NoteNotation.NONE; } @@ -38,10 +45,14 @@ public NoteNotation getNotation() { @Override protected NoteButtonRenderer initNoteRenderer() { - return new NoteButtonRenderer(this, - row, ((AbstractGridInstrumentScreen)instrumentScreen).rows(), - 57, .9f, 1.025f - ); + return new NoteButtonRenderer(this, row, LabelUtil.ABC.length); + } + + @Override + public void updateNoteLabel() { + super.updateNoteLabel(); + noteRenderer.noteTextureRow = ModClientConfigs.ACCURATE_NOTES.get() + ? LabelUtil.getABCOffset(this) : row; } } \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteRing.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteRing.java index 4719543..3288dc4 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteRing.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/NoteRing.java @@ -16,7 +16,7 @@ public class NoteRing { public static final String RING_GLOB_FILENAME = "ring.png"; - protected final RingAnimationController ringAnimation = new RingAnimationController(.3f, 40, this); + protected final RingAnimationController ringAnimation; public final NoteButton note; public int size; @@ -24,7 +24,9 @@ public class NoteRing { public NoteRing(final NoteButton note, final boolean isForeign) { this.note = note; + ringAnimation = new RingAnimationController(.3f, 40, this); + // Immediately play if (isForeign) ringAnimation.play(-.4f); else @@ -38,7 +40,7 @@ public void render(final GuiGraphics gui) { ringAnimation.update(); - final Point ringCenter = ClientUtil.getInitCenter(note.getInitX(), note.getInitY(), NoteButton.getSize(), size); + final Point ringCenter = ClientUtil.getInitCenter(note.getInitX(), note.getInitY(), note.instrumentScreen.getNoteSize(), size); ClientUtil.setShaderColor(note.instrumentScreen.getThemeLoader().getNoteTheme(), alpha); diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/animation/NoteAnimationController.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/animation/NoteAnimationController.java index 3079d33..6e08d4b 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/animation/NoteAnimationController.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/animation/NoteAnimationController.java @@ -37,9 +37,9 @@ protected void animFrame(final float targetTime, final float deltaValue) { protected void resetAnimVars() { super.resetAnimVars(); - button.setWidth(NoteButton.getSize()); - button.setHeight(NoteButton.getSize()); - dSize = NoteButton.getSize(); + button.setWidth(button.instrumentScreen.getNoteSize()); + button.setHeight(button.instrumentScreen.getNoteSize()); + dSize = button.instrumentScreen.getNoteSize(); button.setPosition(button.getInitX(), button.getInitY()); } diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/animation/RingAnimationController.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/animation/RingAnimationController.java index 1a88733..53adc99 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/animation/RingAnimationController.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/partial/note/animation/RingAnimationController.java @@ -1,7 +1,6 @@ package com.cstav.genshinstrument.client.gui.screens.instrument.partial.note.animation; import com.cstav.genshinstrument.client.AnimationController; -import com.cstav.genshinstrument.client.gui.screens.instrument.partial.note.NoteButton; import com.cstav.genshinstrument.client.gui.screens.instrument.partial.note.NoteRing; import net.fabricmc.api.EnvType; @@ -10,7 +9,7 @@ @Environment(EnvType.CLIENT) public class RingAnimationController extends AnimationController { - protected final double initSize = NoteButton.getSize() * .8; + protected final double initSize; protected final float initAlpha = -.08f; protected final NoteRing ring; @@ -20,6 +19,8 @@ public RingAnimationController(float duration, final float ringSizeMultiplier, f super(duration, 1.1f); this.ringSizeMultiplier = ringSizeMultiplier; this.ring = ring; + + initSize = ring.note.instrumentScreen.getNoteSize() * .8; } diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/test/banjo/BanjoInstrumentScreen.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/test/banjo/BanjoInstrumentScreen.java new file mode 100644 index 0000000..9866630 --- /dev/null +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/test/banjo/BanjoInstrumentScreen.java @@ -0,0 +1,79 @@ +package com.cstav.genshinstrument.client.gui.screens.instrument.test.banjo; + +import com.cstav.genshinstrument.GInstrumentMod; +import com.cstav.genshinstrument.client.gui.screens.instrument.floralzither.FloralZitherScreen; +import com.cstav.genshinstrument.client.gui.screens.instrument.partial.AbstractGridInstrumentScreen; +import com.cstav.genshinstrument.client.gui.screens.instrument.partial.InstrumentThemeLoader; +import com.cstav.genshinstrument.sound.ModSounds; +import com.cstav.genshinstrument.sound.NoteSound; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.InteractionHand; + +//TODO remove after tests +@Environment(EnvType.CLIENT) +public class BanjoInstrumentScreen extends AbstractGridInstrumentScreen { + public static final String INSTRUMENT_ID = "banjo"; + public static final String[] NOTES_LAYOUT = {"F#", "G", "G#", "A", "A#", "B", "C", "C#", "D", "D#", "E", "F"}; + + + @Override + public int rows() { + return 8; + } + + @SuppressWarnings("resource") + public int getNoteSize() { + final int guiScale = Minecraft.getInstance().options.guiScale().get(); + + return switch (guiScale) { + case 0 -> 40; + case 1 -> 35; + case 2 -> 41; + case 3 -> 48; + case 4 -> 41; + default -> guiScale * 18; + }; + } + + + public BanjoInstrumentScreen(InteractionHand hand) { + super(hand); + } + @Override + public ResourceLocation getInstrumentId() { + return new ResourceLocation(GInstrumentMod.MODID, INSTRUMENT_ID); + } + + + @Override + public ResourceLocation getSourcePath() { + return new ResourceLocation(GInstrumentMod.MODID, FloralZitherScreen.INSTRUMENT_ID); + } + + + @Override + public NoteSound[] getSounds() { + return ModSounds.BANJO; + } + + @Override + public String[] noteLayout() { + return NOTES_LAYOUT; + } + + @Override + public boolean isSSTI() { + return true; + } + + + private static final InstrumentThemeLoader THEME_LOADER = initThemeLoader(GInstrumentMod.MODID, FloralZitherScreen.INSTRUMENT_ID); + @Override + public InstrumentThemeLoader getThemeLoader() { + return THEME_LOADER; + } +} \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/vintagelyre/VintageLyreScreen.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/vintagelyre/VintageLyreScreen.java index 8721523..743b2bd 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/vintagelyre/VintageLyreScreen.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/vintagelyre/VintageLyreScreen.java @@ -43,9 +43,7 @@ public String[] noteLayout() { @Override public NoteGrid initNoteGrid() { - return new VintageNoteGrid( - rows(), columns(), getSounds(), this - ); + return new VintageNoteGrid(getSounds(), this); } diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/vintagelyre/VintageNoteButton.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/vintagelyre/VintageNoteButton.java index 82fe6be..d6e453a 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/vintagelyre/VintageNoteButton.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/vintagelyre/VintageNoteButton.java @@ -26,7 +26,7 @@ private boolean isDefaultFlat() { @Override public NoteNotation getNotation() { - return ModClientConfigs.ACCURATE_ACCIDENTALS.get() + return ModClientConfigs.ACCURATE_NOTES.get() ? super.getNotation() : isDefaultFlat() ? NoteNotation.FLAT : NoteNotation.NONE; } diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/vintagelyre/VintageNoteGrid.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/vintagelyre/VintageNoteGrid.java index 30fd0ff..2b3d685 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/vintagelyre/VintageNoteGrid.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/instrument/vintagelyre/VintageNoteGrid.java @@ -10,8 +10,8 @@ @Environment(EnvType.CLIENT) public class VintageNoteGrid extends NoteGrid { - public VintageNoteGrid(int rows, int columns, NoteSound[] sounds, VintageLyreScreen instrumentScreen) { - super(rows, columns, sounds, instrumentScreen); + public VintageNoteGrid(NoteSound[] sounds, VintageLyreScreen instrumentScreen) { + super(sounds, instrumentScreen); } @Override diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/options/instrument/AbstractInstrumentOptionsScreen.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/options/instrument/AbstractInstrumentOptionsScreen.java index 4be3dc9..a00656d 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/options/instrument/AbstractInstrumentOptionsScreen.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/options/instrument/AbstractInstrumentOptionsScreen.java @@ -7,7 +7,6 @@ import com.cstav.genshinstrument.client.config.ModClientConfigs; import com.cstav.genshinstrument.client.config.enumType.InstrumentChannelType; -import com.cstav.genshinstrument.client.config.enumType.label.NoteGridLabel; import com.cstav.genshinstrument.client.gui.screens.instrument.partial.AbstractInstrumentScreen; import com.cstav.genshinstrument.client.gui.screens.instrument.partial.note.NoteButton; import com.cstav.genshinstrument.client.gui.screens.instrument.partial.note.label.INoteLabel; @@ -86,7 +85,16 @@ protected int getButtonHeight() { public final boolean isOverlay; protected final @Nullable INoteLabel[] labels; - protected final @Nullable INoteLabel currLabel; + protected @Nullable INoteLabel currLabel; + + /** + * Override to {@code false} tp disable the pitch slider from the options. + * @apiNote SSTI-type instruments do not want a pitch slider. They tend to max out from beginning to end. + */ + public boolean isPitchSliderEnabled() { + return true; + } + public final @Nullable AbstractInstrumentScreen instrumentScreen; @@ -98,7 +106,6 @@ public AbstractInstrumentOptionsScreen(@Nullable AbstractInstrumentScreen screen lastScreen = null; labels = getLabels(); - currLabel = getCurrentLabel(); } public AbstractInstrumentOptionsScreen(final Screen lastScreen) { super(Component.translatable("button.genshinstrument.instrumentOptions")); @@ -108,13 +115,13 @@ public AbstractInstrumentOptionsScreen(final Screen lastScreen) { this.instrumentScreen = null; this.lastScreen = lastScreen; - // Default to NoteGridLabel's values - labels = NoteGridLabel.values(); - currLabel = ModClientConfigs.GRID_LABEL_TYPE.get(); + labels = getLabels(); } @Override protected void init() { + currLabel = getCurrentLabel(); + final GridLayout grid = new GridLayout(); grid.defaultCellSetting() @@ -159,36 +166,37 @@ protected void initAudioSection(final GridLayout grid, final RowHelper rowHelper getBigButtonWidth(), 20, Component.translatable(SOUND_CHANNEL_KEY), this::onChannelTypeChanged); rowHelper.addChild(instrumentChannel, 2); - final AbstractSliderButton pitchSlider = new AbstractSliderButton(0, 0, getSmallButtonWidth(), 20, - CommonComponents.EMPTY, - Mth.clampedMap(getPitch(), NoteSound.MIN_PITCH, NoteSound.MAX_PITCH, 0, 1)) { - - final DecimalFormat format = new DecimalFormat("0.00"); - { - pitch = getPitch(); - updateMessage(); - } - - - private int pitch; - - @Override - protected void updateMessage() { - this.setMessage( - Component.translatable("button.genshinstrument.pitch").append(": " - + LabelUtil.getNoteName(pitch, AbstractInstrumentScreen.DEFAULT_NOTE_LAYOUT, 0) - + " ("+format.format(NoteSound.getPitchByNoteOffset(pitch))+")" - ) - ); - } - - @Override - protected void applyValue() { - pitch = (int)Mth.clampedLerp(NoteSound.MIN_PITCH, NoteSound.MAX_PITCH, value); - onPitchChanged(this, pitch); - } - }; - rowHelper.addChild(pitchSlider); + if (isPitchSliderEnabled()) { + final AbstractSliderButton pitchSlider = new AbstractSliderButton(0, 0, getSmallButtonWidth(), 20, + CommonComponents.EMPTY, + Mth.clampedMap(getPitch(), NoteSound.MIN_PITCH, NoteSound.MAX_PITCH, 0, 1)) { + + final DecimalFormat format = new DecimalFormat("0.00"); + { + pitch = getPitch(); + updateMessage(); + } + + private int pitch; + + @Override + protected void updateMessage() { + this.setMessage( + Component.translatable("button.genshinstrument.pitch").append(": " + + LabelUtil.getNoteName(pitch, AbstractInstrumentScreen.DEFAULT_NOTE_LAYOUT, 0) + + " ("+format.format(NoteSound.getPitchByNoteOffset(pitch))+")" + ) + ); + } + + @Override + protected void applyValue() { + pitch = (int)Mth.clampedLerp(NoteSound.MIN_PITCH, NoteSound.MAX_PITCH, value); + onPitchChanged(this, pitch); + } + }; + rowHelper.addChild(pitchSlider); + } final CycleButton stopMusic = CycleButton.booleanBuilder(CommonComponents.OPTION_ON, CommonComponents.OPTION_OFF) .withInitialValue(ModClientConfigs.STOP_MUSIC_ON_PLAY.get()) @@ -219,14 +227,14 @@ protected void initVisualsSection(final GridLayout grid, final RowHelper rowHelp ); rowHelper.addChild(sharedInstrument); - final CycleButton accurateAccidentals = CycleButton.booleanBuilder(CommonComponents.OPTION_ON, CommonComponents.OPTION_OFF) - .withInitialValue(ModClientConfigs.ACCURATE_ACCIDENTALS.get()) - .withTooltip((value) -> Tooltip.create(Component.translatable("button.genshinstrument.accurate_accidentals.tooltip"))) + final CycleButton accurateNotes = CycleButton.booleanBuilder(CommonComponents.OPTION_ON, CommonComponents.OPTION_OFF) + .withInitialValue(ModClientConfigs.ACCURATE_NOTES.get()) + .withTooltip((value) -> Tooltip.create(Component.translatable("button.genshinstrument.accurate_notes.tooltip"))) .create(0, 0, getSmallButtonWidth(), getButtonHeight(), - Component.translatable("button.genshinstrument.accurate_accidentals"), this::onAccurateAccidentalsChanged + Component.translatable("button.genshinstrument.accurate_notes"), this::onAccurateNotesChanged ); - rowHelper.addChild(accurateAccidentals); + rowHelper.addChild(accurateNotes); if (labels != null) { @@ -298,8 +306,8 @@ protected void onEmitRingChanged(final CycleButton button, final boolea protected void onSharedInstrumentChanged(final CycleButton button, final boolean value) { ModClientConfigs.SHARED_INSTRUMENT.set(value); } - protected void onAccurateAccidentalsChanged(final CycleButton button, final boolean value) { - ModClientConfigs.ACCURATE_ACCIDENTALS.set(value); + protected void onAccurateNotesChanged(final CycleButton button, final boolean value) { + ModClientConfigs.ACCURATE_NOTES.set(value); if (isOverlay) instrumentScreen.notesIterable().forEach(NoteButton::updateNoteLabel); diff --git a/src/main/java/com/cstav/genshinstrument/client/gui/screens/options/instrument/GridInstrumentOptionsScreen.java b/src/main/java/com/cstav/genshinstrument/client/gui/screens/options/instrument/GridInstrumentOptionsScreen.java index 47881a1..bc348cd 100644 --- a/src/main/java/com/cstav/genshinstrument/client/gui/screens/options/instrument/GridInstrumentOptionsScreen.java +++ b/src/main/java/com/cstav/genshinstrument/client/gui/screens/options/instrument/GridInstrumentOptionsScreen.java @@ -41,6 +41,12 @@ protected void saveLabel(final INoteLabel newLabel) { } + @Override + public boolean isPitchSliderEnabled() { + return (instrumentScreen == null) || + !((AbstractGridInstrumentScreen)instrumentScreen).isSSTI(); + } + @Override protected void initVisualsSection(GridLayout grid, RowHelper rowHelper) { diff --git a/src/main/java/com/cstav/genshinstrument/client/keyMaps/KeyMappings.java b/src/main/java/com/cstav/genshinstrument/client/keyMaps/KeyMappings.java index 3446052..01e81a4 100644 --- a/src/main/java/com/cstav/genshinstrument/client/keyMaps/KeyMappings.java +++ b/src/main/java/com/cstav/genshinstrument/client/keyMaps/KeyMappings.java @@ -12,9 +12,9 @@ public class KeyMappings { public static final Key[][] GRID_INSTRUMENT_MAPPINGS = createInstrumentMaps(new int[][] { - {81, 87, 69, 82, 84, 89, 85}, - {65, 83, 68, 70, 71, 72, 74}, - {90, 88, 67, 86, 66, 78, 77} + {81, 87, 69, 82, 84, 89, 85, 73}, + {65, 83, 68, 70, 71, 72, 74, 75}, + {90, 88, 67, 86, 66, 78, 77, 44} }); // Glorious drum diff --git a/src/main/java/com/cstav/genshinstrument/event/ClientEvents.java b/src/main/java/com/cstav/genshinstrument/event/ClientEvents.java index 5a06679..3354bf5 100644 --- a/src/main/java/com/cstav/genshinstrument/event/ClientEvents.java +++ b/src/main/java/com/cstav/genshinstrument/event/ClientEvents.java @@ -1,16 +1,20 @@ package com.cstav.genshinstrument.event; +import com.cstav.genshinstrument.block.partial.AbstractInstrumentBlock; import com.cstav.genshinstrument.client.config.ModClientConfigs; import com.cstav.genshinstrument.client.gui.screens.instrument.partial.AbstractInstrumentScreen; import com.cstav.genshinstrument.event.InstrumentPlayedEvent.ByPlayer.ByPlayerArgs; import com.cstav.genshinstrument.event.InstrumentPlayedEvent.InstrumentPlayedEventArgs; -import com.cstav.genshinstrument.item.InstrumentItem; +import com.cstav.genshinstrument.event.PosePlayerArmEvent.PosePlayerArmEventArgs; import com.cstav.genshinstrument.sound.NoteSound; +import com.cstav.genshinstrument.util.ModEntityData; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.minecraft.client.Minecraft; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.Block; @Environment(EnvType.CLIENT) public abstract class ClientEvents { @@ -19,21 +23,28 @@ public abstract class ClientEvents { public static void register() { + PosePlayerArmEvent.EVENT.register(ClientEvents::posePlayerArmEvent); + ClientTickEvents.START_CLIENT_TICK.register(ClientEvents::onClientTick); InstrumentPlayedEvent.EVENT.register(ClientEvents::onInstrumentPlayed); - ClientTickEvents.START_CLIENT_TICK.register(ClientEvents::onWorldTick); } + // Handle block instrument arm pose + public static void posePlayerArmEvent(final PosePlayerArmEventArgs args) { + final Player player = args.player; + if (!ModEntityData.isInstrumentOpen(player) || ModEntityData.isInstrumentItem(player)) + return; + + + final Block block = player.level().getBlockState(ModEntityData.getInstrumentBlockPos(player)).getBlock(); + if (block instanceof AbstractInstrumentBlock blockInstrument) + blockInstrument.onPosePlayerArm(args); + } // Responsible for closing the instrument screen when // an instrument item is missing from the player's hands - public static void onWorldTick(Minecraft mc) { - if (!(MINECRAFT.screen instanceof AbstractInstrumentScreen)) - return; - - final AbstractInstrumentScreen screen = (AbstractInstrumentScreen) MINECRAFT.screen; - if (!(MINECRAFT.player.getItemInHand(screen.interactionHand).getItem() instanceof InstrumentItem)) - screen.onClose(); + public static void onClientTick(Minecraft mc) { + AbstractInstrumentScreen.getCurrentScreen(mc).ifPresent(AbstractInstrumentScreen::handleAbruptClosing); } diff --git a/src/main/java/com/cstav/genshinstrument/event/InstrumentPlayedEvent.java b/src/main/java/com/cstav/genshinstrument/event/InstrumentPlayedEvent.java index 876c767..ea77f2b 100644 --- a/src/main/java/com/cstav/genshinstrument/event/InstrumentPlayedEvent.java +++ b/src/main/java/com/cstav/genshinstrument/event/InstrumentPlayedEvent.java @@ -1,15 +1,19 @@ package com.cstav.genshinstrument.event; +import java.util.Optional; + +import com.cstav.genshinstrument.event.InstrumentPlayedEvent.ByPlayer.ByPlayerArgs; +import com.cstav.genshinstrument.event.InstrumentPlayedEvent.InstrumentPlayedEventArgs; import com.cstav.genshinstrument.event.impl.Cancelable; import com.cstav.genshinstrument.event.impl.EventArgs; import com.cstav.genshinstrument.event.impl.ModEvent; import com.cstav.genshinstrument.networking.buttonidentifier.NoteButtonIdentifier; import com.cstav.genshinstrument.sound.NoteSound; +import com.cstav.genshinstrument.util.ModEntityData; import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; @@ -17,7 +21,7 @@ import net.minecraft.world.level.Level; @FunctionalInterface -public interface InstrumentPlayedEvent extends ModEvent { +public interface InstrumentPlayedEvent extends ModEvent { Event EVENT = EventFactory.createArrayBacked(InstrumentPlayedEvent.class, (listeners) -> args -> ModEvent.handleEvent(listeners, args) @@ -27,6 +31,8 @@ public interface InstrumentPlayedEvent extends ModEvent { + public interface ByPlayer extends ModEvent { Event EVENT = EventFactory.createArrayBacked(ByPlayer.class, (listeners) -> args -> { @@ -67,22 +72,31 @@ public interface ByPlayer extends ModEvent { @Cancelable public static class ByPlayerArgs extends InstrumentPlayedEventArgs { public final Player player; + + // The values below will only be supplied if initiated from an item /** The instrument held by the player who initiated the sound */ - public final ItemStack instrument; - public final InteractionHand hand; + public final Optional itemInstrument; + /** The hand holding the instrument played by this player */ + public final Optional hand; + + public final Optional blockInstrumentPos; - public ByPlayerArgs(NoteSound sound, Player player, InteractionHand hand, + public ByPlayerArgs(NoteSound sound, int pitch, Player player, BlockPos pos, Optional hand, ResourceLocation instrumentId, NoteButtonIdentifier noteIdentifier, boolean isClientSide) { - super(sound, player.level(), player.blockPosition(), instrumentId, noteIdentifier, isClientSide); + super(sound, pitch, player.level(), pos, instrumentId, noteIdentifier, isClientSide); this.player = player; - this.hand = hand; - instrument = (hand == null) ? null : player.getItemInHand(hand); + if (hand.isPresent()) { + this.hand = hand; + itemInstrument = Optional.of((hand == null) ? null : player.getItemInHand(hand.get())); - // Handle provided unmatching id - if (!instrumentId.equals(BuiltInRegistries.ITEM.getKey(instrument.getItem()))) - setCanceled(true); + blockInstrumentPos = Optional.empty(); + } else { + itemInstrument = Optional.empty(); + this.hand = Optional.empty(); + blockInstrumentPos = Optional.ofNullable(ModEntityData.getInstrumentBlockPos(player)); + } } } } diff --git a/src/main/java/com/cstav/genshinstrument/event/PosePlayerArmEvent.java b/src/main/java/com/cstav/genshinstrument/event/PosePlayerArmEvent.java new file mode 100644 index 0000000..34fd400 --- /dev/null +++ b/src/main/java/com/cstav/genshinstrument/event/PosePlayerArmEvent.java @@ -0,0 +1,42 @@ +package com.cstav.genshinstrument.event; + +import com.cstav.genshinstrument.event.PosePlayerArmEvent.PosePlayerArmEventArgs; +import com.cstav.genshinstrument.event.impl.Cancelable; +import com.cstav.genshinstrument.event.impl.EventArgs; +import com.cstav.genshinstrument.event.impl.ModEvent; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.world.entity.player.Player; + +@Environment(EnvType.CLIENT) +public interface PosePlayerArmEvent extends ModEvent { + + @Environment(EnvType.CLIENT) + @Cancelable + public static class PosePlayerArmEventArgs extends EventArgs { + + public final Player player; + public final HandType hand; + public final ModelPart arm; + + public PosePlayerArmEventArgs(final Player player, final HandType hand, final ModelPart arm) { + this.player = player; + this.hand = hand; + this.arm = arm; + } + + } + @Environment(EnvType.CLIENT) + public enum HandType { + LEFT, RIGHT + } + + Event EVENT = EventFactory.createArrayBacked(PosePlayerArmEvent.class, + (listeners) -> args -> ModEvent.handleEvent(listeners, args) + ); + +} diff --git a/src/main/java/com/cstav/genshinstrument/event/impl/Cancelable.java b/src/main/java/com/cstav/genshinstrument/event/impl/Cancelable.java index 132a1d4..a33566f 100644 --- a/src/main/java/com/cstav/genshinstrument/event/impl/Cancelable.java +++ b/src/main/java/com/cstav/genshinstrument/event/impl/Cancelable.java @@ -1,7 +1,10 @@ package com.cstav.genshinstrument.event.impl; import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -@Target(value = ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) public @interface Cancelable {} \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/event/impl/EventArgs.java b/src/main/java/com/cstav/genshinstrument/event/impl/EventArgs.java index cf592c2..e4838cb 100644 --- a/src/main/java/com/cstav/genshinstrument/event/impl/EventArgs.java +++ b/src/main/java/com/cstav/genshinstrument/event/impl/EventArgs.java @@ -10,21 +10,14 @@ public void setCanceled(final boolean isCanceled) { if (isCancelable()) this.canceled = isCanceled; else if (isCanceled) - GInstrumentMod.LOGGER.warn("Attempted to cancel uncancelable event" + getClass().getSimpleName() + "!", this); + GInstrumentMod.LOGGER.warn("Attempted to cancel uncancelable event " + getClass().getSimpleName() + "!", this); } public boolean isCanceled() { return canceled; } - - public static boolean isCancelable(final Class eventArgs) { - final Class superclass = eventArgs.getClass().getSuperclass(); - - return eventArgs.getClass().isAnnotationPresent(Cancelable.class) - || ((superclass != null) && isCancelable(superclass)); - } public boolean isCancelable() { - return isCancelable(getClass()); + return getClass().isAnnotationPresent(Cancelable.class); } diff --git a/src/main/java/com/cstav/genshinstrument/item/InstrumentItem.java b/src/main/java/com/cstav/genshinstrument/item/InstrumentItem.java index a3aa8bd..52b99ff 100644 --- a/src/main/java/com/cstav/genshinstrument/item/InstrumentItem.java +++ b/src/main/java/com/cstav/genshinstrument/item/InstrumentItem.java @@ -1,10 +1,16 @@ package com.cstav.genshinstrument.item; -import com.cstav.genshinstrument.networking.ModPacketHandler; -import com.cstav.genshinstrument.networking.packets.instrument.NotifyInstrumentOpenPacket; -import com.cstav.genshinstrument.networking.packets.instrument.OpenInstrumentPacket; -import com.cstav.genshinstrument.util.ModEntityData; +import com.cstav.genshinstrument.client.ModArmPose; +import com.cstav.genshinstrument.client.gui.screens.instrument.partial.AbstractInstrumentScreen; +import com.cstav.genshinstrument.event.PosePlayerArmEvent; +import com.cstav.genshinstrument.event.PosePlayerArmEvent.PosePlayerArmEventArgs; +import com.cstav.genshinstrument.mixin.util.CommonUtil; +import com.cstav.genshinstrument.networking.OpenInstrumentPacketSender; +import com.cstav.genshinstrument.util.ServerUtil; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.loader.api.FabricLoader; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; @@ -18,13 +24,13 @@ */ public class InstrumentItem extends Item { - protected final ServerPlayerRunnable onOpenRequest; + protected final OpenInstrumentPacketSender onOpenRequest; /** * @param onOpenRequest A server-side event fired when the player has requested to interact * with the instrument. * It should should send a packet to the given player for opening this instrument's screen. */ - public InstrumentItem(final ServerPlayerRunnable onOpenRequest) { + public InstrumentItem(final OpenInstrumentPacketSender onOpenRequest) { this(onOpenRequest, new Properties()); } /** @@ -34,38 +40,34 @@ public InstrumentItem(final ServerPlayerRunnable onOpenRequest) { * @param properties The properties of this instrument item. {@link Properties#stacksTo stack size} * will always be set to 1. */ - public InstrumentItem(final ServerPlayerRunnable onOpenRequest, final Properties properties) { + public InstrumentItem(final OpenInstrumentPacketSender onOpenRequest, final Properties properties) { super(properties.stacksTo(1)); this.onOpenRequest = onOpenRequest; } - - static void sendOpenRequest(ServerPlayer player, InteractionHand hand, String instrumentType) { - ModPacketHandler.sendToClient(new OpenInstrumentPacket(instrumentType, hand), player); - } @Override public InteractionResultHolder use(Level pLevel, Player pPlayer, InteractionHand pUsedHand) { - if (!pLevel.isClientSide) { - onOpenRequest.run((ServerPlayer)pPlayer, pUsedHand); + return pLevel.isClientSide ? InteractionResultHolder.pass(pPlayer.getItemInHand(pUsedHand)) + : ServerUtil.sendOpenPacket((ServerPlayer)pPlayer, pUsedHand, onOpenRequest) + ? InteractionResultHolder.success(pPlayer.getItemInHand(pUsedHand)) + : InteractionResultHolder.fail(pPlayer.getItemInHand(pUsedHand)); + } - // Update the the capabilty on server - ModEntityData.setInstrumentOpen(pPlayer, true); - // And clients - pLevel.players().forEach((player) -> - ModPacketHandler.sendToClient( - new NotifyInstrumentOpenPacket(pPlayer.getUUID(), true), - (ServerPlayer)player - ) - ); - } - - return InteractionResultHolder.success(pPlayer.getItemInHand(pUsedHand)); + + static { + if (FabricLoader.getInstance().getEnvironmentType() != EnvType.SERVER) + PosePlayerArmEvent.EVENT.register(InstrumentItem::itemArmPose); + } + @Environment(EnvType.CLIENT) + private static void itemArmPose(final PosePlayerArmEventArgs args) { + CommonUtil.getItemInHands(InstrumentItem.class, args.player).ifPresent((item) -> + item.onPosePlayerArm(args) + ); } - - @FunctionalInterface - public static interface ServerPlayerRunnable { - void run(final ServerPlayer player, final InteractionHand hand); + @Environment(EnvType.CLIENT) + public void onPosePlayerArm(PosePlayerArmEventArgs args) { + ModArmPose.poseForItemInstrument(args); } } diff --git a/src/main/java/com/cstav/genshinstrument/item/ModItems.java b/src/main/java/com/cstav/genshinstrument/item/ModItems.java index 0e66380..75346fd 100644 --- a/src/main/java/com/cstav/genshinstrument/item/ModItems.java +++ b/src/main/java/com/cstav/genshinstrument/item/ModItems.java @@ -1,5 +1,7 @@ package com.cstav.genshinstrument.item; +import static com.cstav.genshinstrument.util.ServerUtil.sendInternalOpenPacket; + import com.cstav.genshinstrument.GInstrumentMod; import com.cstav.genshinstrument.ModCreativeModeTabs; @@ -16,17 +18,23 @@ public abstract class ModItems { public static final Item WINDSONG_LYRE = register("windsong_lyre", new InstrumentItem( - (player, hand) -> InstrumentItem.sendOpenRequest(player, hand, "windsong_lyre") + (player, hand) -> sendInternalOpenPacket(player, hand, "windsong_lyre") )), VINTAGE_LYRE = register("vintage_lyre", new InstrumentItem( - (player, hand) -> InstrumentItem.sendOpenRequest(player, hand, "vintage_lyre") + (player, hand) -> sendInternalOpenPacket(player, hand, "vintage_lyre") )), FLORAL_ZITHER = register("floral_zither", new InstrumentItem( - (player, hand) -> InstrumentItem.sendOpenRequest(player, hand, "floral_zither") + (player, hand) -> sendInternalOpenPacket(player, hand, "floral_zither") )), GLORIOUS_DRUM = register("glorious_drum", new InstrumentItem( - (player, hand) -> InstrumentItem.sendOpenRequest(player, hand, "glorious_drum") - )) + (player, hand) -> sendInternalOpenPacket(player, hand, "glorious_drum") + )), + + //TODO remove after tests + BANJO = register("banjo", new InstrumentItem( + (player, hand) -> sendInternalOpenPacket(player, hand, "banjo") + ) + ) ; @@ -40,7 +48,7 @@ private static Item register(final String id, final Item item) { private static void addToItemGroups(final Item item) { // All shall go to the instruments and toold tab - addToTab(ModCreativeModeTabs.INSTRUMENTS, item); + addToTab(ModCreativeModeTabs.INSTRUMENTS_TAB, item); addToTab(CreativeModeTabs.TOOLS_AND_UTILITIES, item); } @@ -53,7 +61,7 @@ private static void addToTab(final ResourceKey tab, final Item - public static void register() { + public static void load() { GInstrumentMod.LOGGER.info("Registered all instrument items"); } diff --git a/src/main/java/com/cstav/genshinstrument/mixin/optional/InstrumentAnimMixin.java b/src/main/java/com/cstav/genshinstrument/mixin/optional/InstrumentAnimMixin.java index 34891d7..a12ea13 100644 --- a/src/main/java/com/cstav/genshinstrument/mixin/optional/InstrumentAnimMixin.java +++ b/src/main/java/com/cstav/genshinstrument/mixin/optional/InstrumentAnimMixin.java @@ -6,13 +6,12 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.cstav.genshinstrument.item.InstrumentItem; -import com.cstav.genshinstrument.mixin.util.MixinConstants; -import com.cstav.genshinstrument.util.ModEntityData; +import com.cstav.genshinstrument.event.PosePlayerArmEvent; +import com.cstav.genshinstrument.event.PosePlayerArmEvent.HandType; +import com.cstav.genshinstrument.event.PosePlayerArmEvent.PosePlayerArmEventArgs; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.ModelPart; -import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; @@ -24,33 +23,29 @@ public abstract class InstrumentAnimMixin { @Shadow private ModelPart leftArm; + @Inject(at = @At("HEAD"), method = "poseLeftArm", cancellable = true) - private void injectInstrumentUseAnim(LivingEntity entity, CallbackInfo info) { - if (!(entity instanceof Player)) + private void injectLeftArmPose(LivingEntity entity, CallbackInfo info) { + if (!(entity instanceof Player player)) return; - boolean isInRight = isInstrumentInHand(entity, InteractionHand.MAIN_HAND), - isInLeft = isInstrumentInHand(entity, InteractionHand.OFF_HAND); - - if (!(isInLeft || isInRight)) - return; - - if (!ModEntityData.isInstrumentOpen((Player)entity)) - return; + final PosePlayerArmEventArgs args = new PosePlayerArmEventArgs(player, HandType.LEFT, leftArm); + PosePlayerArmEvent.EVENT.invoker().triggered(args); - - rightArm.xRot = -MixinConstants.HAND_HEIGHT_ROT; - rightArm.zRot = -0.35f; - - leftArm.xRot = -MixinConstants.HAND_HEIGHT_ROT; - leftArm.zRot = 0.85f; - - info.cancel(); + if (args.isCanceled()) + info.cancel(); } + @Inject(at = @At("HEAD"), method = "poseRightArm", cancellable = true) + private void injectRightArmPose(LivingEntity entity, CallbackInfo info) { + if (!(entity instanceof Player player)) + return; + + final PosePlayerArmEventArgs args = new PosePlayerArmEventArgs(player, HandType.RIGHT, rightArm); + PosePlayerArmEvent.EVENT.invoker().triggered(args); - private static boolean isInstrumentInHand(final LivingEntity entity, final InteractionHand hand) { - return entity.getItemInHand(hand).getItem() instanceof InstrumentItem; + if (args.isCanceled()) + info.cancel(); } } \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/mixin/util/CommonUtil.java b/src/main/java/com/cstav/genshinstrument/mixin/util/CommonUtil.java new file mode 100644 index 0000000..2239282 --- /dev/null +++ b/src/main/java/com/cstav/genshinstrument/mixin/util/CommonUtil.java @@ -0,0 +1,24 @@ +package com.cstav.genshinstrument.mixin.util; + +import java.util.Optional; + +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; + +public abstract class CommonUtil { + + @SuppressWarnings("unchecked") + public static Optional getItemInHands(final Class item, final Player player) { + final Item mainItem = player.getItemInHand(InteractionHand.MAIN_HAND).getItem(), + offItem = player.getItemInHand(InteractionHand.OFF_HAND).getItem(); + + if (item.isInstance(mainItem)) + return Optional.of((T)mainItem); + else if (item.isInstance(offItem)) + return Optional.of((T)offItem); + + return Optional.empty(); + } + +} diff --git a/src/main/java/com/cstav/genshinstrument/mixin/util/MixinConstants.java b/src/main/java/com/cstav/genshinstrument/mixin/util/MixinConstants.java index 916fd7b..3b2d9c6 100644 --- a/src/main/java/com/cstav/genshinstrument/mixin/util/MixinConstants.java +++ b/src/main/java/com/cstav/genshinstrument/mixin/util/MixinConstants.java @@ -1,12 +1,12 @@ package com.cstav.genshinstrument.mixin.util; +import com.cstav.genshinstrument.GInstrumentMod; + public abstract class MixinConstants { /** * The name of the root capability of this mod; all the entity data of the mod shall go under that compound tag */ - public static final String ROOT_CAP = "instrument_caps"; - - public static final float HAND_HEIGHT_ROT = .9f; + public static final String ROOT_CAP = GInstrumentMod.MODID+":instrument_caps"; } diff --git a/src/main/java/com/cstav/genshinstrument/networking/ModPacket.java b/src/main/java/com/cstav/genshinstrument/networking/IModPacket.java similarity index 73% rename from src/main/java/com/cstav/genshinstrument/networking/ModPacket.java rename to src/main/java/com/cstav/genshinstrument/networking/IModPacket.java index 7784238..747550b 100644 --- a/src/main/java/com/cstav/genshinstrument/networking/ModPacket.java +++ b/src/main/java/com/cstav/genshinstrument/networking/IModPacket.java @@ -11,10 +11,10 @@ /** * An interface for all packets under the Genshin Instruments mod. - * All its implementers must have a {@code TYPE} field of type {@link PacketType} (see {@link ModPacket#type}) + * All its implementers must have a {@code TYPE} field of type {@link PacketType} (see {@link IModPacket#type}) * and a constructor that takes a {@link FriendlyByteBuf}. */ -public interface ModPacket extends FabricPacket { +public interface IModPacket extends FabricPacket { void handle(Player player, PacketSender responseSender); @Override @@ -23,16 +23,11 @@ default void write(FriendlyByteBuf buf) {} @Override default PacketType getType() { - try { - return (PacketType)getClass().getField("TYPE").get(null); - } catch (Exception e) { - GInstrumentMod.LOGGER.info("Failed to fetch packet type of "+getClass().getSimpleName()+". Perhaps a TYPE field is absent?"); - return null; - } + return type(getClass()); } - public static PacketType type(final Class packetType) { + public static PacketType type(final Class packetType) { return PacketType.create( new ResourceLocation(GInstrumentMod.MODID, packetType.getSimpleName().toLowerCase()), diff --git a/src/main/java/com/cstav/genshinstrument/networking/ModPacketHandler.java b/src/main/java/com/cstav/genshinstrument/networking/ModPacketHandler.java index 3b6fa14..5e65748 100644 --- a/src/main/java/com/cstav/genshinstrument/networking/ModPacketHandler.java +++ b/src/main/java/com/cstav/genshinstrument/networking/ModPacketHandler.java @@ -2,7 +2,7 @@ import java.util.List; -import com.cstav.genshinstrument.GInstrumentMod; +import com.cstav.genshinstrument.networking.buttonidentifier.DefaultNoteButtonIdentifier; import com.cstav.genshinstrument.networking.buttonidentifier.DrumNoteIdentifier; import com.cstav.genshinstrument.networking.buttonidentifier.NoteButtonIdentifier; import com.cstav.genshinstrument.networking.buttonidentifier.NoteGridButtonIdentifier; @@ -11,20 +11,19 @@ import com.cstav.genshinstrument.networking.packets.instrument.NotifyInstrumentOpenPacket; import com.cstav.genshinstrument.networking.packets.instrument.OpenInstrumentPacket; import com.cstav.genshinstrument.networking.packets.instrument.PlayNotePacket; -import com.cstav.genshinstrument.util.ServerUtil; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.networking.v1.FabricPacket; -import net.fabricmc.fabric.api.networking.v1.PacketType; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; import net.minecraft.server.level.ServerPlayer; public class ModPacketHandler { @SuppressWarnings("unchecked") - private static final List> + private static final List> S2C_PACKETS = List.of(new Class[] { - PlayNotePacket.class, OpenInstrumentPacket.class, NotifyInstrumentOpenPacket.class + PlayNotePacket.class, OpenInstrumentPacket.class, + NotifyInstrumentOpenPacket.class }), C2S_PACKETS = List.of(new Class[] { InstrumentPacket.class, CloseInstrumentPacket.class @@ -32,52 +31,33 @@ public class ModPacketHandler { ; @SuppressWarnings("unchecked") - private static final List> ACCEPTABLE_IDENTIFIERS = List.of(new Class[] { + public static final List> ACCEPTABLE_IDENTIFIERS = List.of(new Class[] { + DefaultNoteButtonIdentifier.class, NoteButtonIdentifier.class, NoteGridButtonIdentifier.class, DrumNoteIdentifier.class }); - /** - * @see ServerUtil#getValidNoteIdentifier - */ - public static Class getValidIdentifier(String classType) - throws ClassNotFoundException { - return ServerUtil.getValidNoteIdentifier(classType, ACCEPTABLE_IDENTIFIERS); - } - public static void registerClientPackets() { - for (final Class packetClass : S2C_PACKETS) { + for (final Class packetClass : S2C_PACKETS) { ClientPlayNetworking.registerGlobalReceiver( - getPacketType(packetClass), - ModPacket::handle + IModPacket.type(packetClass), + IModPacket::handle ); } } public static void registerServerPackets() { - for (final Class packetClass : C2S_PACKETS) { + for (final Class packetClass : C2S_PACKETS) { ServerPlayNetworking.registerGlobalReceiver( - getPacketType(packetClass), - ModPacket::handle + IModPacket.type(packetClass), + IModPacket::handle ); } } - @SuppressWarnings("unchecked") - private static PacketType getPacketType(final Class packetClass) { - try { - - return (PacketType)(packetClass.getField("TYPE").get(null)); - - } catch (Exception e) { - GInstrumentMod.LOGGER.error("Failed to register packet type " + packetClass.getSimpleName(), e); - return null; - } - } - public static void sendToServer(final FabricPacket packet) { ClientPlayNetworking.send(packet); diff --git a/src/main/java/com/cstav/genshinstrument/networking/OpenInstrumentPacketSender.java b/src/main/java/com/cstav/genshinstrument/networking/OpenInstrumentPacketSender.java new file mode 100644 index 0000000..9116058 --- /dev/null +++ b/src/main/java/com/cstav/genshinstrument/networking/OpenInstrumentPacketSender.java @@ -0,0 +1,9 @@ +package com.cstav.genshinstrument.networking; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; + +@FunctionalInterface +public interface OpenInstrumentPacketSender { + void send(final ServerPlayer player, final InteractionHand hand); +} \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/DefaultNoteButtonIdentifier.java b/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/DefaultNoteButtonIdentifier.java index e70c26a..ffe6175 100644 --- a/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/DefaultNoteButtonIdentifier.java +++ b/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/DefaultNoteButtonIdentifier.java @@ -12,37 +12,49 @@ */ public class DefaultNoteButtonIdentifier extends NoteButtonIdentifier { - private NoteSound sound; + private final NoteSound sound; + private final int pitch; + private final boolean identifyByPitch; - public DefaultNoteButtonIdentifier(final NoteSound sound) { + public DefaultNoteButtonIdentifier(final NoteSound sound, final int pitch, final boolean identifyByPitch) { this.sound = sound; + this.pitch = pitch; + this.identifyByPitch = identifyByPitch; } - @Environment(EnvType.CLIENT) - public DefaultNoteButtonIdentifier(final NoteButton note) { - this(note.getSound()); - } - - public void setSound(NoteSound sound) { + public DefaultNoteButtonIdentifier(final NoteSound sound, final int pitch) { this.sound = sound; + this.pitch = pitch; + this.identifyByPitch = true; + } + + @Environment(EnvType.CLIENT) + public DefaultNoteButtonIdentifier(final NoteButton note, final boolean identifyByPitch) { + this(note.getSound(), note.getPitch(), identifyByPitch); } public DefaultNoteButtonIdentifier(final FriendlyByteBuf buf) { sound = NoteSound.readFromNetwork(buf); + pitch = buf.readInt(); + identifyByPitch = buf.readBoolean(); } @Override public void writeToNetwork(FriendlyByteBuf buf) { super.writeToNetwork(buf); + sound.writeToNetwork(buf); + buf.writeInt(pitch); + buf.writeBoolean(identifyByPitch); } - + public boolean matches(NoteButtonIdentifier other) { return MatchType.forceMatch(other, this::matchSound); } private boolean matchSound(final DefaultNoteButtonIdentifier other) { - return other.sound.equals(sound); + return other.sound.equals(sound) + && ((identifyByPitch && other.identifyByPitch) ? (pitch == other.pitch) : true); } } \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/DrumNoteIdentifier.java b/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/DrumNoteIdentifier.java index 60d7e31..56b1c2b 100644 --- a/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/DrumNoteIdentifier.java +++ b/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/DrumNoteIdentifier.java @@ -14,7 +14,7 @@ public class DrumNoteIdentifier extends DefaultNoteButtonIdentifier { @Environment(EnvType.CLIENT) public DrumNoteIdentifier(final DrumNoteButton note) { - super(note); + super(note, false); noteType = note.btnType; isRight = note.isRight; } diff --git a/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/NoteButtonIdentifier.java b/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/NoteButtonIdentifier.java index cf708bb..4538dc4 100644 --- a/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/NoteButtonIdentifier.java +++ b/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/NoteButtonIdentifier.java @@ -1,9 +1,11 @@ package com.cstav.genshinstrument.networking.buttonidentifier; +import java.util.List; import java.util.function.Function; import com.cstav.genshinstrument.client.gui.screens.instrument.partial.note.NoteButton; -import com.cstav.genshinstrument.networking.ModPacketHandler; +import com.cstav.genshinstrument.networking.packets.INoteIdentifierSender; +import com.cstav.genshinstrument.util.ServerUtil; import com.mojang.logging.LogUtils; import net.minecraft.network.FriendlyByteBuf; @@ -41,10 +43,15 @@ public boolean equals(Object other) { return false; } + /** + * @apiNote Consider implementing {@link INoteIdentifierSender} + * and using the {@link INoteIdentifierSender#readNoteIdentifierFromNetwork} instead. + */ + public static NoteButtonIdentifier readFromNetwork(FriendlyByteBuf buf, + List> acceptableIdentifiers) { - public static NoteButtonIdentifier readIdentifier(FriendlyByteBuf buf) { try { - return ModPacketHandler.getValidIdentifier(buf.readUtf()) + return ServerUtil.getValidNoteIdentifier(buf.readUtf(), acceptableIdentifiers) .getDeclaredConstructor(FriendlyByteBuf.class).newInstance(buf); } catch (Exception e) { LogUtils.getLogger().error("Error initializing button identifier", e); @@ -52,7 +59,7 @@ public static NoteButtonIdentifier readIdentifier(FriendlyByteBuf buf) { } } - + /** * A class holding methods to simplify the usage of the {@link NoteButtonIdentifier#matches matches} function diff --git a/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/NoteGridButtonIdentifier.java b/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/NoteGridButtonIdentifier.java index 8dda9d0..699b950 100644 --- a/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/NoteGridButtonIdentifier.java +++ b/src/main/java/com/cstav/genshinstrument/networking/buttonidentifier/NoteGridButtonIdentifier.java @@ -1,5 +1,6 @@ package com.cstav.genshinstrument.networking.buttonidentifier; +import com.cstav.genshinstrument.client.gui.screens.instrument.partial.AbstractGridInstrumentScreen; import com.cstav.genshinstrument.client.gui.screens.instrument.partial.note.NoteGridButton; import net.fabricmc.api.EnvType; @@ -12,7 +13,7 @@ public class NoteGridButtonIdentifier extends DefaultNoteButtonIdentifier { @Environment(EnvType.CLIENT) public NoteGridButtonIdentifier(final NoteGridButton button) { - super(button); + super(button, ((AbstractGridInstrumentScreen)button.instrumentScreen).isSSTI()); this.row = button.row; this.column = button.column; } diff --git a/src/main/java/com/cstav/genshinstrument/networking/packets/INoteIdentifierSender.java b/src/main/java/com/cstav/genshinstrument/networking/packets/INoteIdentifierSender.java new file mode 100644 index 0000000..3f8fde0 --- /dev/null +++ b/src/main/java/com/cstav/genshinstrument/networking/packets/INoteIdentifierSender.java @@ -0,0 +1,21 @@ +package com.cstav.genshinstrument.networking.packets; + +import java.util.List; + +import com.cstav.genshinstrument.networking.IModPacket; +import com.cstav.genshinstrument.networking.ModPacketHandler; +import com.cstav.genshinstrument.networking.buttonidentifier.NoteButtonIdentifier; + +import net.minecraft.network.FriendlyByteBuf; + +public interface INoteIdentifierSender extends IModPacket { + + default List> acceptableIdentifiers() { + return ModPacketHandler.ACCEPTABLE_IDENTIFIERS; + } + + default NoteButtonIdentifier readNoteIdentifierFromNetwork(final FriendlyByteBuf buf) { + return NoteButtonIdentifier.readFromNetwork(buf, acceptableIdentifiers()); + } + +} \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/CloseInstrumentPacket.java b/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/CloseInstrumentPacket.java index 949122b..2e7df33 100644 --- a/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/CloseInstrumentPacket.java +++ b/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/CloseInstrumentPacket.java @@ -1,25 +1,23 @@ package com.cstav.genshinstrument.networking.packets.instrument; -import com.cstav.genshinstrument.networking.ModPacket; +import com.cstav.genshinstrument.networking.IModPacket; import com.cstav.genshinstrument.networking.ModPacketHandler; import com.cstav.genshinstrument.util.ModEntityData; import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.PacketType; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Player; -public class CloseInstrumentPacket implements ModPacket { - public static final PacketType TYPE = ModPacket.type(CloseInstrumentPacket.class); +public class CloseInstrumentPacket implements IModPacket { public CloseInstrumentPacket() {} public CloseInstrumentPacket(FriendlyByteBuf buf) {} - + @Override public void handle(Player player, PacketSender responseSender) { - ModEntityData.setInstrumentOpen(player, false); + ModEntityData.setInstrumentClosed(player); for (final Player oPlayer : player.level().players()) ModPacketHandler.sendToClient(new NotifyInstrumentOpenPacket(player.getUUID(), false), (ServerPlayer)oPlayer); diff --git a/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/InstrumentPacket.java b/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/InstrumentPacket.java index 28aca9e..2679185 100644 --- a/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/InstrumentPacket.java +++ b/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/InstrumentPacket.java @@ -1,32 +1,34 @@ package com.cstav.genshinstrument.networking.packets.instrument; -import com.cstav.genshinstrument.networking.ModPacket; +import java.util.Optional; + import com.cstav.genshinstrument.networking.buttonidentifier.NoteButtonIdentifier; +import com.cstav.genshinstrument.networking.packets.INoteIdentifierSender; import com.cstav.genshinstrument.sound.NoteSound; import com.cstav.genshinstrument.util.ModEntityData; import com.cstav.genshinstrument.util.ServerUtil; import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.PacketType; +import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; -public class InstrumentPacket implements ModPacket { - public static final PacketType TYPE = ModPacket.type(InstrumentPacket.class); - +public class InstrumentPacket implements INoteIdentifierSender { private final NoteSound sound; - private final InteractionHand hand; + private final Optional hand; private final int pitch; + private final BlockPos pos; private final ResourceLocation instrumentId; private final NoteButtonIdentifier noteIdentifier; - public InstrumentPacket(NoteSound sound, int pitch, InteractionHand hand, + public InstrumentPacket(BlockPos pos, NoteSound sound, int pitch, Optional hand, ResourceLocation instrumentId, NoteButtonIdentifier noteIdentifier) { + this.pos = pos; this.sound = sound; this.hand = hand; this.pitch = pitch; @@ -35,18 +37,20 @@ public InstrumentPacket(NoteSound sound, int pitch, InteractionHand hand, this.noteIdentifier = noteIdentifier; } public InstrumentPacket(FriendlyByteBuf buf) { + pos = buf.readBlockPos(); sound = NoteSound.readFromNetwork(buf); - hand = buf.readEnum(InteractionHand.class); + hand = buf.readOptional((fbb) -> buf.readEnum(InteractionHand.class)); pitch = buf.readInt(); instrumentId = buf.readResourceLocation(); - noteIdentifier = NoteButtonIdentifier.readIdentifier(buf); + noteIdentifier = readNoteIdentifierFromNetwork(buf); } @Override public void write(final FriendlyByteBuf buf) { + buf.writeBlockPos(pos); sound.writeToNetwork(buf); - buf.writeEnum(hand); + buf.writeOptional(hand, FriendlyByteBuf::writeEnum); buf.writeInt(pitch); buf.writeResourceLocation(instrumentId); @@ -59,7 +63,7 @@ public void handle(Player player, PacketSender responseSender) { if (!ModEntityData.isInstrumentOpen(player)) return; - ServerUtil.sendPlayNotePackets((ServerPlayer)player, hand, sound, instrumentId, noteIdentifier, pitch); + ServerUtil.sendPlayNotePackets((ServerPlayer)player, pos, hand, sound, instrumentId, noteIdentifier, pitch); } } \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/NotifyInstrumentOpenPacket.java b/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/NotifyInstrumentOpenPacket.java index 432efb1..ad556f6 100644 --- a/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/NotifyInstrumentOpenPacket.java +++ b/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/NotifyInstrumentOpenPacket.java @@ -1,40 +1,68 @@ package com.cstav.genshinstrument.networking.packets.instrument; +import java.util.Optional; import java.util.UUID; -import com.cstav.genshinstrument.networking.ModPacket; +import com.cstav.genshinstrument.networking.IModPacket; import com.cstav.genshinstrument.util.ModEntityData; import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.PacketType; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.entity.player.Player; -public class NotifyInstrumentOpenPacket implements ModPacket { - public static final PacketType TYPE = ModPacket.type(NotifyInstrumentOpenPacket.class); - +public class NotifyInstrumentOpenPacket implements IModPacket { private final UUID playerUUID; private final boolean isOpen; - public NotifyInstrumentOpenPacket(final UUID playerUUID, final boolean isOpen) { + private final Optional pos; + + public NotifyInstrumentOpenPacket(UUID playerUUID, final boolean isOpen) { this.playerUUID = playerUUID; + this.isOpen = isOpen; + this.pos = Optional.empty(); + } + /** + * Constructs a {@link NotifyInstrumentOpenPacket} that notifies of an open state + * with an optional instrument block position. + */ + public NotifyInstrumentOpenPacket(UUID playerUUID, Optional pos) { + this.playerUUID = playerUUID; + + this.isOpen = true; + this.pos = pos; } + public NotifyInstrumentOpenPacket(final FriendlyByteBuf buf) { playerUUID = buf.readUUID(); isOpen = buf.readBoolean(); + pos = buf.readOptional(FriendlyByteBuf::readBlockPos); } @Override public void write(FriendlyByteBuf buf) { buf.writeUUID(playerUUID); buf.writeBoolean(isOpen); + buf.writeOptional(pos, FriendlyByteBuf::writeBlockPos); } + @SuppressWarnings("resource") @Override public void handle(Player player, PacketSender responseSender) { - ModEntityData.setInstrumentOpen(player.level().getPlayerByUUID(playerUUID), isOpen); + final Player _player = Minecraft.getInstance().level.getPlayerByUUID(playerUUID); + + if (isOpen) { + + if (pos.isPresent()) + ModEntityData.setInstrumentOpen(_player, pos.get()); + else + ModEntityData.setInstrumentOpen(_player); + + } else + ModEntityData.setInstrumentClosed(_player); } } diff --git a/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/OpenInstrumentPacket.java b/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/OpenInstrumentPacket.java index 848d098..37494eb 100644 --- a/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/OpenInstrumentPacket.java +++ b/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/OpenInstrumentPacket.java @@ -1,55 +1,62 @@ package com.cstav.genshinstrument.networking.packets.instrument; import java.util.Map; +import java.util.Optional; import java.util.function.Function; import java.util.function.Supplier; import com.cstav.genshinstrument.client.gui.screens.instrument.drum.AratakisGreatAndGloriousDrumScreen; import com.cstav.genshinstrument.client.gui.screens.instrument.floralzither.FloralZitherScreen; -import com.cstav.genshinstrument.client.gui.screens.instrument.partial.AbstractInstrumentScreen; +import com.cstav.genshinstrument.client.gui.screens.instrument.test.banjo.BanjoInstrumentScreen; import com.cstav.genshinstrument.client.gui.screens.instrument.vintagelyre.VintageLyreScreen; import com.cstav.genshinstrument.client.gui.screens.instrument.windsonglyre.WindsongLyreScreen; -import com.cstav.genshinstrument.networking.ModPacket; +import com.cstav.genshinstrument.networking.IModPacket; import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.PacketType; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; -public class OpenInstrumentPacket implements ModPacket { - public static final PacketType TYPE = ModPacket.type(OpenInstrumentPacket.class); - - private static final Map>> OPEN_INSTRUMENT = Map.of( +public class OpenInstrumentPacket implements IModPacket { + + private static final Map>> INSTRUMENT_MAP = Map.of( "windsong_lyre", () -> WindsongLyreScreen::new, "vintage_lyre", () -> VintageLyreScreen::new, "floral_zither", () -> FloralZitherScreen::new, - "glorious_drum", () -> AratakisGreatAndGloriousDrumScreen::new + "glorious_drum", () -> AratakisGreatAndGloriousDrumScreen::new, + + //TODO remove after tests + "banjo", () -> BanjoInstrumentScreen::new ); + protected Map>> getInstrumentMap() { + return INSTRUMENT_MAP; + } + private final String instrumentType; - private final InteractionHand hand; + private final Optional hand; public OpenInstrumentPacket(final String instrumentScreen, final InteractionHand hand) { this.instrumentType = instrumentScreen; - this.hand = hand; + this.hand = Optional.ofNullable(hand); } public OpenInstrumentPacket(FriendlyByteBuf buf) { instrumentType = buf.readUtf(); - hand = buf.readEnum(InteractionHand.class); + hand = buf.readOptional((fbb) -> fbb.readEnum(InteractionHand.class)); } @Override public void write(FriendlyByteBuf buf) { buf.writeUtf(instrumentType); - buf.writeEnum(hand); + buf.writeOptional(hand, FriendlyByteBuf::writeEnum); } @Override public void handle(Player player, PacketSender responseSender) { - Minecraft.getInstance().setScreen(OPEN_INSTRUMENT.get(instrumentType).get().apply(hand)); + Minecraft.getInstance().setScreen(getInstrumentMap().get(instrumentType).get().apply(hand.orElse(null))); } } \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/PlayNotePacket.java b/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/PlayNotePacket.java index b16bcc0..8a915d2 100644 --- a/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/PlayNotePacket.java +++ b/src/main/java/com/cstav/genshinstrument/networking/packets/instrument/PlayNotePacket.java @@ -3,22 +3,19 @@ import java.util.Optional; import java.util.UUID; -import com.cstav.genshinstrument.networking.ModPacket; import com.cstav.genshinstrument.networking.buttonidentifier.NoteButtonIdentifier; +import com.cstav.genshinstrument.networking.packets.INoteIdentifierSender; import com.cstav.genshinstrument.sound.NoteSound; import net.fabricmc.fabric.api.networking.v1.PacketSender; -import net.fabricmc.fabric.api.networking.v1.PacketType; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; -public class PlayNotePacket implements ModPacket { - public static final PacketType TYPE = ModPacket.type(PlayNotePacket.class); - - +public class PlayNotePacket implements INoteIdentifierSender { + private final BlockPos blockPos; private final NoteSound sound; private final int pitch; @@ -45,7 +42,7 @@ public PlayNotePacket(FriendlyByteBuf buf) { sound = NoteSound.readFromNetwork(buf); pitch = buf.readInt(); instrumentId = buf.readResourceLocation(); - noteIdentifier = NoteButtonIdentifier.readIdentifier(buf); + noteIdentifier = readNoteIdentifierFromNetwork(buf); playerUUID = buf.readOptional(FriendlyByteBuf::readUUID); hand = buf.readOptional((fbb) -> fbb.readEnum(InteractionHand.class)); @@ -67,7 +64,7 @@ public void write(FriendlyByteBuf buf) { @Override public void handle(Player player, PacketSender responseSender) { sound.playAtPos( - pitch, playerUUID.orElse(null), hand.orElse(null), + pitch, playerUUID.orElse(null), hand, instrumentId, noteIdentifier, blockPos ); } diff --git a/src/main/java/com/cstav/genshinstrument/sound/ModSounds.java b/src/main/java/com/cstav/genshinstrument/sound/ModSounds.java index 602367e..4bd3dfb 100644 --- a/src/main/java/com/cstav/genshinstrument/sound/ModSounds.java +++ b/src/main/java/com/cstav/genshinstrument/sound/ModSounds.java @@ -3,9 +3,12 @@ import static com.cstav.genshinstrument.sound.NoteSoundRegistrer.createInstrumentNotes; import static com.cstav.genshinstrument.sound.NoteSoundRegistrer.registerNote; +import java.util.Optional; + import com.cstav.genshinstrument.GInstrumentMod; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; public class ModSounds { @@ -19,6 +22,11 @@ public class ModSounds { GLORIOUS_DRUM = new NoteSound[] { registerNote(loc("glorious_drum_don")), registerNote(loc("glorious_drum_ka"), true) + }, + + // TODO remove after tests + BANJO = new NoteSound[] { + new NoteSound(NoteBlockInstrument.BANJO.getSoundEvent().value(), Optional.empty()) } ; @@ -30,7 +38,7 @@ private static ResourceLocation loc(final String name) { } - public static void regsiter() { + public static void load() { GInstrumentMod.LOGGER.info("Registered all note sounds for instruments"); } diff --git a/src/main/java/com/cstav/genshinstrument/sound/NoteSound.java b/src/main/java/com/cstav/genshinstrument/sound/NoteSound.java index aafda75..da6599b 100644 --- a/src/main/java/com/cstav/genshinstrument/sound/NoteSound.java +++ b/src/main/java/com/cstav/genshinstrument/sound/NoteSound.java @@ -129,7 +129,7 @@ private static boolean metInstrumentVolume() { * @param pos The position at which the sound was fired from */ @Environment(EnvType.CLIENT) - public void playAtPos(int pitch, UUID playerUUID, InteractionHand hand, + public void playAtPos(int pitch, UUID playerUUID, Optional hand, ResourceLocation instrumentId, NoteButtonIdentifier buttonIdentifier, BlockPos pos) { final Minecraft minecraft = Minecraft.getInstance(); @@ -145,12 +145,14 @@ public void playAtPos(int pitch, UUID playerUUID, InteractionHand hand, // Send instrument played event if (playerUUID == null) InstrumentPlayedEvent.EVENT.invoker().triggered( - new InstrumentPlayedEventArgs(this, level, pos, instrumentId, buttonIdentifier, true) + new InstrumentPlayedEventArgs( + this, pitch, level, pos, instrumentId, buttonIdentifier, true + ) ); else InstrumentPlayedEvent.ByPlayer.EVENT.invoker().triggered( new ByPlayerArgs( - this, level.getPlayerByUUID(playerUUID), hand, + this, pitch, level.getPlayerByUUID(playerUUID), pos, hand, instrumentId, buttonIdentifier, true ) ); @@ -209,7 +211,7 @@ public static int clampPitch(final int pitch) { * */ public static float getPitchByNoteOffset(final int pitch) { - return (float)Math.pow(2, (double)pitch/LabelUtil.NOTES_PER_SCALE); + return (float)Math.pow(2, (double)pitch / LabelUtil.NOTES_PER_SCALE); } diff --git a/src/main/java/com/cstav/genshinstrument/util/CommonUtil.java b/src/main/java/com/cstav/genshinstrument/util/CommonUtil.java index 674d9c2..03ac5af 100644 --- a/src/main/java/com/cstav/genshinstrument/util/CommonUtil.java +++ b/src/main/java/com/cstav/genshinstrument/util/CommonUtil.java @@ -36,4 +36,28 @@ public static ResourceLocation getResourceFrom(final ResourceLocation dir, final ); } + + /** + * Provides a similar behaviour to python's indexing, + * where negatives are counted backwards. + */ + public static int pyWrap(int index, final int arrLength) { + while (index < 0) + index += arrLength; + + return index; + } + /** + * Wraps the index around an array + */ + public static int wrapAround(int index, final int arrLength) { + return index % arrLength; + } + /** + * Performs both {@link LabelUtil#pyWrap} and {@link LabelUtil#wrapAround} + */ + public static int doublyPyWrap(int index, final int arrLength) { + return wrapAround(pyWrap(index, arrLength), arrLength); + } + } diff --git a/src/main/java/com/cstav/genshinstrument/util/LabelUtil.java b/src/main/java/com/cstav/genshinstrument/util/LabelUtil.java index 1873c0f..1ff20f4 100644 --- a/src/main/java/com/cstav/genshinstrument/util/LabelUtil.java +++ b/src/main/java/com/cstav/genshinstrument/util/LabelUtil.java @@ -4,8 +4,10 @@ import java.util.Map; +import com.cstav.genshinstrument.GInstrumentMod; import com.cstav.genshinstrument.client.config.ModClientConfigs; import com.cstav.genshinstrument.client.gui.screens.instrument.partial.AbstractGridInstrumentScreen; +import com.cstav.genshinstrument.client.gui.screens.instrument.partial.AbstractInstrumentScreen; import com.cstav.genshinstrument.client.gui.screens.instrument.partial.note.NoteGridButton; public abstract class LabelUtil { @@ -13,9 +15,11 @@ public abstract class LabelUtil { public static final String[] DO_RE_MI = { "do", "re", "mi", "fa", "so", "la", "ti" - }, + } + ; + public static final char[] ABC = { - "C", "D", "E", "F", "G", "A", "B" + 'C', 'D', 'E', 'F', 'G', 'A', 'B' } ; @@ -61,52 +65,41 @@ private static String[] strArr(final String... arr) { public static String getNoteName(final int pitch, final String[] noteLayout, final int offset) { - final String baseNote = noteLayout[wrapAround(offset, noteLayout.length)]; + final String baseNote = noteLayout[CommonUtil.wrapAround(offset, noteLayout.length)]; final String[] scale = NOTE_SCALES.get(baseNote); - return scale[(doublyPyWrap(pitch, scale.length))]; + return scale[(CommonUtil.doublyPyWrap(pitch, scale.length))]; } public static String getNoteName(final NoteGridButton gridButton) { final AbstractGridInstrumentScreen screen = (AbstractGridInstrumentScreen) gridButton.instrumentScreen; - return getNoteName( - screen.getPitch(), screen.noteLayout(), - gridButton.row + gridButton.column * screen.rows() - ); + return getNoteName(screen.getPitch(), screen.noteLayout(), getNoteOffset(gridButton)); + } + public static int getNoteOffset(final NoteGridButton gridButton) { + return gridButton.row + gridButton.column * ((AbstractGridInstrumentScreen)gridButton.instrumentScreen).rows(); } public static String getCutNoteName(final NoteGridButton gridButton) { - String result = LabelUtil.getNoteName(gridButton); - - if (ModClientConfigs.ACCURATE_ACCIDENTALS.get()) - result = String.valueOf(result.charAt(0)); + return getCutNoteName(LabelUtil.getNoteName(gridButton)); + } + public static String getCutNoteName(String noteName) { + if (ModClientConfigs.ACCURATE_NOTES.get()) + noteName = String.valueOf(noteName.charAt(0)); - return result; + return noteName; } - /** - * Provides a similar behaviour to python's indexing, - * where negatives are counted backwards. - */ - private static int pyWrap(int index, final int arrLength) { - while (index < 0) - index += arrLength; + public static int getABCOffset(final char note, final AbstractInstrumentScreen screen) { + for (int i = 0; i < ABC.length; i++) { + if (note == ABC[i]) + return i; + } - return index; + GInstrumentMod.LOGGER.warn("Could not get note letter "+note+" for "+screen.getInstrumentId()+"!"); + return 0; } - /** - * Wraps the index around an array - */ - private static int wrapAround(int index, final int arrLength) { - while (index >= arrLength) - index -= arrLength; - return index; - } - /** - * Performs both {@link LabelUtil#pyWrap} and {@link LabelUtil#wrapAround} - */ - private static int doublyPyWrap(int index, final int arrLength) { - return wrapAround(pyWrap(index, arrLength), arrLength); + public static int getABCOffset(final NoteGridButton gridButton) { + return getABCOffset(getNoteName(gridButton).charAt(0), gridButton.instrumentScreen); } } \ No newline at end of file diff --git a/src/main/java/com/cstav/genshinstrument/util/ModEntityData.java b/src/main/java/com/cstav/genshinstrument/util/ModEntityData.java index 869d0a4..5f497a2 100644 --- a/src/main/java/com/cstav/genshinstrument/util/ModEntityData.java +++ b/src/main/java/com/cstav/genshinstrument/util/ModEntityData.java @@ -2,12 +2,16 @@ import com.cstav.genshinstrument.mixin.util.IEntityModData; +import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; +//TODO: Change to "InstrumentEntityData" and remove all "instruments" from method names public abstract class ModEntityData { - public static final String INSTRUMENT_OPEN_TAG_NAME = "instrumentOpen"; + public static final String OPEN_TAG = "instrumentOpen", + IS_ITEM_TAG = "isItem", BLOCK_POS_TAG = "blockPos"; public static CompoundTag getModTag(final Entity entity) { @@ -16,14 +20,34 @@ public static CompoundTag getModTag(final Entity entity) { public static boolean isInstrumentOpen(final Player player) { - final CompoundTag modData = getModTag(player); - return modData.contains(INSTRUMENT_OPEN_TAG_NAME, CompoundTag.TAG_BYTE) - ? modData.getBoolean(INSTRUMENT_OPEN_TAG_NAME) - : false; + return getModTag(player).getBoolean(OPEN_TAG); + } + public static boolean isInstrumentItem(final Player player) { + return getModTag(player).getBoolean(IS_ITEM_TAG); + } + + public static BlockPos getInstrumentBlockPos(final Player player) { + final CompoundTag posTag = getModTag(player).getCompound(BLOCK_POS_TAG); + return posTag.isEmpty() ? null : NbtUtils.readBlockPos(posTag); + } + + + public static void setInstrumentOpen(final Player player, final BlockPos pos) { + final CompoundTag modTag = getModTag(player); + modTag.putBoolean(OPEN_TAG, true); + modTag.put(BLOCK_POS_TAG, NbtUtils.writeBlockPos(pos)); + + modTag.putBoolean(IS_ITEM_TAG, false); + } + public static void setInstrumentOpen(final Player player) { + final CompoundTag modTag = getModTag(player); + modTag.putBoolean(OPEN_TAG, true); + + modTag.putBoolean(IS_ITEM_TAG, true); } - public static void setInstrumentOpen(final Player player, final boolean isOpen) { - getModTag(player).putBoolean(INSTRUMENT_OPEN_TAG_NAME, isOpen); + public static void setInstrumentClosed(final Player player) { + getModTag(player).putBoolean(OPEN_TAG, false); } } diff --git a/src/main/java/com/cstav/genshinstrument/util/ServerUtil.java b/src/main/java/com/cstav/genshinstrument/util/ServerUtil.java index a6cf391..397d2ab 100644 --- a/src/main/java/com/cstav/genshinstrument/util/ServerUtil.java +++ b/src/main/java/com/cstav/genshinstrument/util/ServerUtil.java @@ -7,8 +7,11 @@ import com.cstav.genshinstrument.event.InstrumentPlayedEvent.ByPlayer.ByPlayerArgs; import com.cstav.genshinstrument.event.InstrumentPlayedEvent.InstrumentPlayedEventArgs; import com.cstav.genshinstrument.networking.ModPacketHandler; +import com.cstav.genshinstrument.networking.OpenInstrumentPacketSender; import com.cstav.genshinstrument.networking.buttonidentifier.DefaultNoteButtonIdentifier; import com.cstav.genshinstrument.networking.buttonidentifier.NoteButtonIdentifier; +import com.cstav.genshinstrument.networking.packets.instrument.NotifyInstrumentOpenPacket; +import com.cstav.genshinstrument.networking.packets.instrument.OpenInstrumentPacket; import com.cstav.genshinstrument.networking.packets.instrument.PlayNotePacket; import com.cstav.genshinstrument.sound.NoteSound; @@ -32,16 +35,18 @@ public class ServerUtil { * Sends {@link PlayNotePacket}s in the specified {@link ServerUtil#PLAY_DISTANCE}. * This method treats the sound as it was produced by a player. * @param player The player producing the sounds - * @param hand The hand of the player producing the sounds + * @param hand The hand of the player producing the sounds. Empty for when it was not a player. * @param sound The sound tp initiate - * @param sound The sound to initiate * @param instrumentId The ID of the instrument initiating the sound * @param pitch The pitch of the sound to initiate */ - public static void sendPlayNotePackets(ServerPlayer player, InteractionHand hand, + public static void sendPlayNotePackets(ServerPlayer player, Optional hand, NoteSound sound, ResourceLocation instrumentId, int pitch) { - sendPlayNotePackets(player, hand, sound, instrumentId, new DefaultNoteButtonIdentifier(sound), pitch); + sendPlayNotePackets( + player, player.blockPosition(), hand, + sound, instrumentId, new DefaultNoteButtonIdentifier(sound, pitch), pitch + ); } /** * Sends {@link PlayNotePacket}s in the specified {@link ServerUtil#PLAY_DISTANCE}. @@ -51,15 +56,15 @@ public static void sendPlayNotePackets(ServerPlayer player, InteractionHand hand * @param sound The sound tp initiate * @param pitch The pitch of the sound to initiate */ - public static void sendPlayNotePackets(ServerPlayer player, InteractionHand hand, + public static void sendPlayNotePackets(ServerPlayer player, BlockPos pos, Optional hand, NoteSound sound, ResourceLocation instrumentId, NoteButtonIdentifier noteIdentifier, int pitch) { for (final Player listener : noteListeners(player.level(), player.blockPosition())) ModPacketHandler.sendToClient( new PlayNotePacket( - player.blockPosition(), sound, pitch, + pos, sound, pitch, instrumentId, noteIdentifier, - Optional.of(player.getUUID()), Optional.of(hand) + Optional.of(player.getUUID()), hand ), (ServerPlayer)listener ); @@ -67,13 +72,13 @@ public static void sendPlayNotePackets(ServerPlayer player, InteractionHand hand // Trigger an instrument game event // This is done so that sculk sensors can pick up the instrument's sound player.level().gameEvent( - GameEvent.INSTRUMENT_PLAY, player.blockPosition(), + GameEvent.INSTRUMENT_PLAY, pos, GameEvent.Context.of(player) ); // Fire a player-specific event InstrumentPlayedEvent.ByPlayer.EVENT.invoker().triggered( - new ByPlayerArgs(sound, player, hand, instrumentId, noteIdentifier, false) + new ByPlayerArgs(sound, pitch, player, pos, hand, instrumentId, noteIdentifier, false) ); } @@ -87,7 +92,7 @@ public static void sendPlayNotePackets(ServerPlayer player, InteractionHand hand * @param pitch The pitch of the sound to initiate */ public static void sendPlayNotePackets(Level level, BlockPos pos, NoteSound sound, ResourceLocation instrumentId, int pitch) { - sendPlayNotePackets(level, pos, sound, instrumentId, new DefaultNoteButtonIdentifier(sound), pitch); + sendPlayNotePackets(level, pos, sound, instrumentId, new DefaultNoteButtonIdentifier(sound, pitch), pitch); } /** * Sends {@link PlayNotePacket}s in the specified {@link ServerUtil#PLAY_DISTANCE}. @@ -126,7 +131,7 @@ public static void sendPlayNotePackets(Level level, BlockPos pos, NoteSound soun // Fire a generic instrument event InstrumentPlayedEvent.EVENT.invoker().triggered( - new InstrumentPlayedEventArgs(sound, (ServerLevel)level, pos, instrumentId, noteIdentifier, false) + new InstrumentPlayedEventArgs(sound, pitch, (ServerLevel)level, pos, instrumentId, noteIdentifier, false) ); } @@ -158,4 +163,49 @@ public static Class getValidNoteIdentifier(Strin throw new ClassNotFoundException("Class type "+classType+" could not be evaluated as part of the acceptable identifiers"); } + + // Item/block stuff + /** + * Sends an instrument open packet as an item + */ + public static boolean sendOpenPacket(ServerPlayer player, InteractionHand usedHand, OpenInstrumentPacketSender onOpenRequest) { + return sendOpenPacket(player, usedHand, onOpenRequest, null); + } + /** + * Sends an instrument open packet as a block + */ + public static boolean sendOpenPacket(ServerPlayer player, OpenInstrumentPacketSender onOpenRequest, BlockPos pos) { + return sendOpenPacket(player, null, onOpenRequest, pos); + } + private static boolean sendOpenPacket(ServerPlayer player, InteractionHand usedHand, OpenInstrumentPacketSender onOpenRequest, + BlockPos pos) { + + onOpenRequest.send(player, usedHand); + + // Update the the capabilty on server + if (pos == null) + ModEntityData.setInstrumentOpen(player); + else + ModEntityData.setInstrumentOpen(player, pos); + + // And clients + final Optional playPos = Optional.ofNullable(pos); + + player.level().players().forEach((nearbyPlayer) -> + ModPacketHandler.sendToClient( + new NotifyInstrumentOpenPacket(player.getUUID(), playPos), + (ServerPlayer)nearbyPlayer + ) + ); + + return true; + } + + /** + * @apiNote This method should only be used by the internal Genshin Instruments mod! + */ + public static void sendInternalOpenPacket(ServerPlayer player, InteractionHand hand, String instrumentType) { + ModPacketHandler.sendToClient(new OpenInstrumentPacket(instrumentType, hand), player); + } + } diff --git a/src/main/resources/assets/genshinstrument/lang/en_us.json b/src/main/resources/assets/genshinstrument/lang/en_us.json index bbc2450..6f65f59 100644 --- a/src/main/resources/assets/genshinstrument/lang/en_us.json +++ b/src/main/resources/assets/genshinstrument/lang/en_us.json @@ -35,8 +35,8 @@ "button.genshinstrument.shared_instrument": "Shared Instrument Screen", "button.genshinstrument.render_background": "Show Background Visuals", - "button.genshinstrument.accurate_accidentals": "Accurate Accidentals", - "button.genshinstrument.accurate_accidentals.tooltip": "When on, provides a pitch-accurate representation of the accidentals used by this instrument's layout", + "button.genshinstrument.accurate_notes": "Accurate Notes", + "button.genshinstrument.accurate_notes.tooltip": "When on, provides a pitch-accurate representation of the note symbols and accidentals used by this instrument's layout", diff --git a/src/main/resources/assets/genshinstrument/lang/he_il.json b/src/main/resources/assets/genshinstrument/lang/he_il.json index ab1d5ad..36d928e 100644 --- a/src/main/resources/assets/genshinstrument/lang/he_il.json +++ b/src/main/resources/assets/genshinstrument/lang/he_il.json @@ -30,8 +30,8 @@ "button.genshinstrument.shared_instrument": "מסך נגינה משותף", "button.genshinstrument.render_background": "הצג תפאורות רקע", - "button.genshinstrument.accurate_accidentals": "סימני היתק מדוייקים", - "button.genshinstrument.accurate_accidentals.tooltip": "כאשר אופציה זו מופעלת, יוצגו יתקיהם של כל התווים בהתאם לגובה הצליל הנבחר", + "button.genshinstrument.accurate_notes": "תווים מדוייקים", + "button.genshinstrument.accurate_notes.tooltip": "כאשר אופציה זו מופעלת, יוצגו התווים ויתקיהם בהתאם לגובה הצליל הנבחר", diff --git a/src/main/resources/assets/genshinstrument/lang/ru_ru.json b/src/main/resources/assets/genshinstrument/lang/ru_ru.json index 44a6e0b..6c67276 100644 --- a/src/main/resources/assets/genshinstrument/lang/ru_ru.json +++ b/src/main/resources/assets/genshinstrument/lang/ru_ru.json @@ -25,8 +25,8 @@ "button.genshinstrument.shared_instrument": "Экран общего инструмента", "button.genshinstrument.render_background": "Показать фоновые визуальные", - "button.genshinstrument.accurate_accidentals": "Точные случайности", - "button.genshinstrument.accurate_accidentals.tooltip": "Во включенном состоянии обеспечивает точное отображение питч-аккомпанемента, используемого в схеме данного инструмента", + "button.genshinstrument.accurate_notes": "Точные примечания", + "button.genshinstrument.accurate_notes.tooltip": "Во включенном состоянии обеспечивает точное отображение нотных символов и аккомпанементов, используемых в раскладке данного инструмента", "button.genshinstrument.instrumentOptions": "Варианты инструментов", diff --git a/src/main/resources/assets/genshinstrument/textures/gui/instrument/glorious_drum/note/notes.png b/src/main/resources/assets/genshinstrument/textures/gui/instrument/glorious_drum/note/notes.png index fb4913b..86d42a2 100644 Binary files a/src/main/resources/assets/genshinstrument/textures/gui/instrument/glorious_drum/note/notes.png and b/src/main/resources/assets/genshinstrument/textures/gui/instrument/glorious_drum/note/notes.png differ diff --git a/src/main/resources/data/genshinstrument/tags/blocks/instruments.json b/src/main/resources/data/genshinstrument/tags/blocks/instruments.json new file mode 100644 index 0000000..ee98a1b --- /dev/null +++ b/src/main/resources/data/genshinstrument/tags/blocks/instruments.json @@ -0,0 +1,3 @@ +{ + "values": [] +} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 4e71d6a..02b88aa 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "id": "genshinstrument", - "version": "3.1", + "version": "3.2.2", "name": "Genshin Instruments", "description": "A mod that brings Genshin Impact's instruments to Minecraft!\nThis is my first ever published mod, and I am quite proud of it :')\nHope you enjoy it as much as I do!!", "authors": [