From 30ee8bd3d432a47cb6477e9632cbbeb48696a41a Mon Sep 17 00:00:00 2001 From: jimchen5209 Date: Sun, 7 Jan 2024 13:41:29 +0800 Subject: [PATCH 1/3] Prepare for weapen events --- ...otBarSlotUpdate_ScreenHandlerListener.java | 48 +++++++++++++++++++ ...ixinUpdateSelectedSlot_NetworkHandler.java | 43 +++++++++++++++++ .../event/type/HotBarSlotUpdateEvent.kt | 25 ++++++++++ .../event/type/UpdateSelectedSlotEvent.kt | 24 ++++++++++ src/main/resources/galaxy.mixin.json | 6 ++- 5 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 src/main/java/one/oktw/galaxy/mixin/event/MixinHotBarSlotUpdate_ScreenHandlerListener.java create mode 100644 src/main/java/one/oktw/galaxy/mixin/event/MixinUpdateSelectedSlot_NetworkHandler.java create mode 100644 src/main/kotlin/one/oktw/galaxy/event/type/HotBarSlotUpdateEvent.kt create mode 100644 src/main/kotlin/one/oktw/galaxy/event/type/UpdateSelectedSlotEvent.kt diff --git a/src/main/java/one/oktw/galaxy/mixin/event/MixinHotBarSlotUpdate_ScreenHandlerListener.java b/src/main/java/one/oktw/galaxy/mixin/event/MixinHotBarSlotUpdate_ScreenHandlerListener.java new file mode 100644 index 000000000..e8d2869b0 --- /dev/null +++ b/src/main/java/one/oktw/galaxy/mixin/event/MixinHotBarSlotUpdate_ScreenHandlerListener.java @@ -0,0 +1,48 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2021 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.mixin.event; + +import net.minecraft.item.ItemStack; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import one.oktw.galaxy.Main; +import one.oktw.galaxy.event.type.HotBarSlotUpdateEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(targets = {"net/minecraft/server/network/ServerPlayerEntity$2"}) +public class MixinHotBarSlotUpdate_ScreenHandlerListener { + @Shadow(aliases = {"field_29183"}) + private ServerPlayerEntity player; + + @Inject( + method = "onSlotUpdate(Lnet/minecraft/screen/ScreenHandler;ILnet/minecraft/item/ItemStack;)V", + at = @At(value = "RETURN") + ) + private void onSlotUpdate(ScreenHandler handler, int slotId, ItemStack stack, CallbackInfo ci) { + Main main = Main.Companion.getMain(); + if (main == null) return; + if (slotId >= 36 && slotId <= 45) { + main.getEventManager().emit(new HotBarSlotUpdateEvent(player, handler, slotId, stack)); + } + } +} diff --git a/src/main/java/one/oktw/galaxy/mixin/event/MixinUpdateSelectedSlot_NetworkHandler.java b/src/main/java/one/oktw/galaxy/mixin/event/MixinUpdateSelectedSlot_NetworkHandler.java new file mode 100644 index 000000000..7db010696 --- /dev/null +++ b/src/main/java/one/oktw/galaxy/mixin/event/MixinUpdateSelectedSlot_NetworkHandler.java @@ -0,0 +1,43 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2021 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.mixin.event; + +import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import one.oktw.galaxy.Main; +import one.oktw.galaxy.event.type.UpdateSelectedSlotEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerPlayNetworkHandler.class) +public class MixinUpdateSelectedSlot_NetworkHandler { + @Shadow + public ServerPlayerEntity player; + + @Inject(method = "onUpdateSelectedSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerEntity;updateLastActionTime()V")) + private void onUpdateSelectedSlot(UpdateSelectedSlotC2SPacket packet, CallbackInfo ci) { + Main main = Main.Companion.getMain(); + if (main == null) return; + main.getEventManager().emit(new UpdateSelectedSlotEvent(packet, player)); + } +} diff --git a/src/main/kotlin/one/oktw/galaxy/event/type/HotBarSlotUpdateEvent.kt b/src/main/kotlin/one/oktw/galaxy/event/type/HotBarSlotUpdateEvent.kt new file mode 100644 index 000000000..c69f2c13a --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/event/type/HotBarSlotUpdateEvent.kt @@ -0,0 +1,25 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2021 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.event.type + +import net.minecraft.item.ItemStack +import net.minecraft.screen.ScreenHandler +import net.minecraft.server.network.ServerPlayerEntity + +class HotBarSlotUpdateEvent(val player: ServerPlayerEntity, val handler: ScreenHandler, val slotId: Int, val item: ItemStack) : Event diff --git a/src/main/kotlin/one/oktw/galaxy/event/type/UpdateSelectedSlotEvent.kt b/src/main/kotlin/one/oktw/galaxy/event/type/UpdateSelectedSlotEvent.kt new file mode 100644 index 000000000..91812a0a2 --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/event/type/UpdateSelectedSlotEvent.kt @@ -0,0 +1,24 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2021 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.event.type + +import net.minecraft.network.packet.c2s.play.UpdateSelectedSlotC2SPacket +import net.minecraft.server.network.ServerPlayerEntity + +class UpdateSelectedSlotEvent(val packet: UpdateSelectedSlotC2SPacket, val player: ServerPlayerEntity) : Event diff --git a/src/main/resources/galaxy.mixin.json b/src/main/resources/galaxy.mixin.json index 07f25f563..b42110651 100644 --- a/src/main/resources/galaxy.mixin.json +++ b/src/main/resources/galaxy.mixin.json @@ -3,6 +3,7 @@ "package": "one.oktw.galaxy.mixin.event", "compatibilityLevel": "JAVA_16", "mixins": [ + "MixinHotBarSlotUpdate_ScreenHandlerListener", "MixinPlayerAction_NetworkHandler", "MixinPlayerChat_MeCommand", "MixinPlayerChat_NetworkHandler", @@ -11,10 +12,11 @@ "MixinPlayerInteractItem_NetworkHandler", "MixinPlayerJump_NetworkHandler", "MixinPlayerSneak_NetworkHandler", - "MixinPlayerUseItemOnBlock_ItemStack" + "MixinPlayerUseItemOnBlock_ItemStack", + "MixinUpdateSelectedSlot_NetworkHandler" ], "client": [], "injectors": { "defaultRequire": 1 } -} +} \ No newline at end of file From 9920ceb84cb32cc8cfc9a92614e212cf419a6e26 Mon Sep 17 00:00:00 2001 From: jimchen5209 Date: Sun, 7 Jan 2024 13:41:30 +0800 Subject: [PATCH 2/3] feat: add weapon item --- src/main/kotlin/one/oktw/galaxy/Main.kt | 1 + .../one/oktw/galaxy/command/commands/Admin.kt | 4 +- .../galaxy/command/commands/admin/GetGun.kt | 126 ++++++++++++++++++ .../kotlin/one/oktw/galaxy/item/CustomItem.kt | 5 +- .../one/oktw/galaxy/item/CustomItemHelper.kt | 3 +- src/main/kotlin/one/oktw/galaxy/item/Gun.kt | 64 +++++++++ src/main/kotlin/one/oktw/galaxy/item/Sword.kt | 52 ++++++++ .../kotlin/one/oktw/galaxy/item/Weapon.kt | 41 ++---- .../one/oktw/galaxy/item/data/GunData.kt | 60 +++++++++ .../one/oktw/galaxy/item/data/SwordData.kt | 36 +++++ .../one/oktw/galaxy/item/data/WeaponData.kt | 39 ++++++ .../one/oktw/galaxy/item/event/Weapon.kt | 68 ++++++++++ .../one/oktw/galaxy/item/type/WeaponType.kt | 24 ++++ .../one/oktw/galaxy/sound/GalaxySound.kt | 59 ++++++++ 14 files changed, 546 insertions(+), 36 deletions(-) create mode 100644 src/main/kotlin/one/oktw/galaxy/command/commands/admin/GetGun.kt create mode 100644 src/main/kotlin/one/oktw/galaxy/item/Gun.kt create mode 100644 src/main/kotlin/one/oktw/galaxy/item/Sword.kt create mode 100644 src/main/kotlin/one/oktw/galaxy/item/data/GunData.kt create mode 100644 src/main/kotlin/one/oktw/galaxy/item/data/SwordData.kt create mode 100644 src/main/kotlin/one/oktw/galaxy/item/data/WeaponData.kt create mode 100644 src/main/kotlin/one/oktw/galaxy/item/event/Weapon.kt create mode 100644 src/main/kotlin/one/oktw/galaxy/item/type/WeaponType.kt create mode 100644 src/main/kotlin/one/oktw/galaxy/sound/GalaxySound.kt diff --git a/src/main/kotlin/one/oktw/galaxy/Main.kt b/src/main/kotlin/one/oktw/galaxy/Main.kt index ab61ee396..b2e64465b 100644 --- a/src/main/kotlin/one/oktw/galaxy/Main.kt +++ b/src/main/kotlin/one/oktw/galaxy/Main.kt @@ -99,6 +99,7 @@ class Main : DedicatedServerModInitializer, CoroutineScope { eventManager.register(Elevator()) eventManager.register(AngelBlock()) eventManager.register(CustomItemEventHandler()) +// eventManager.register(Weapon()) }) ServerLifecycleEvents.SERVER_STOPPING.register { diff --git a/src/main/kotlin/one/oktw/galaxy/command/commands/Admin.kt b/src/main/kotlin/one/oktw/galaxy/command/commands/Admin.kt index 3bc68f616..b4802942b 100644 --- a/src/main/kotlin/one/oktw/galaxy/command/commands/Admin.kt +++ b/src/main/kotlin/one/oktw/galaxy/command/commands/Admin.kt @@ -1,6 +1,6 @@ /* * OKTW Galaxy Project - * Copyright (C) 2018-2021 + * Copyright (C) 2018-2022 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published @@ -23,6 +23,7 @@ import net.minecraft.server.command.CommandManager import net.minecraft.server.command.ServerCommandSource import one.oktw.galaxy.command.Command import one.oktw.galaxy.command.commands.admin.FlySpeed +import one.oktw.galaxy.command.commands.admin.GetGun import one.oktw.galaxy.command.commands.admin.GetItem import one.oktw.galaxy.command.commands.admin.RegisterBlock @@ -32,6 +33,7 @@ class Admin : Command { CommandManager.literal("admin") .requires { source -> source.hasPermissionLevel(2) } .then(GetItem().command) + .then(GetGun().command) .then(RegisterBlock.command) .then(FlySpeed().command) ) diff --git a/src/main/kotlin/one/oktw/galaxy/command/commands/admin/GetGun.kt b/src/main/kotlin/one/oktw/galaxy/command/commands/admin/GetGun.kt new file mode 100644 index 000000000..ee75a3205 --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/command/commands/admin/GetGun.kt @@ -0,0 +1,126 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2023 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.command.commands.admin + +import com.mojang.brigadier.Command +import com.mojang.brigadier.arguments.DoubleArgumentType +import com.mojang.brigadier.arguments.IntegerArgumentType +import com.mojang.brigadier.builder.LiteralArgumentBuilder +import com.mojang.brigadier.context.CommandContext +import net.minecraft.command.argument.IdentifierArgumentType +import net.minecraft.item.ItemStack +import net.minecraft.server.command.CommandManager +import net.minecraft.server.command.ServerCommandSource +import net.minecraft.sound.SoundCategory +import net.minecraft.sound.SoundEvents +import net.minecraft.text.Text +import one.oktw.galaxy.item.CustomItem +import one.oktw.galaxy.item.Gun + +class GetGun { + // /admin getGun [] + private val throughArgument = CommandManager.argument("through", IntegerArgumentType.integer()) + .executes { + val identifier = IdentifierArgumentType.getIdentifier(it, "item") + val item = CustomItem.registry.get(identifier) as Gun? + + if (item == null) { + it.source.sendError(Text.translatable("argument.item.id.invalid", identifier)) + return@executes 0 + } + + val itemStack = item.apply { + weaponData.applyValue( + IntegerArgumentType.getInteger(it, "heat"), + IntegerArgumentType.getInteger(it, "maxTemp"), + DoubleArgumentType.getDouble(it, "cooling"), + DoubleArgumentType.getDouble(it, "damage"), + DoubleArgumentType.getDouble(it, "range"), + IntegerArgumentType.getInteger(it, "through") + ) + }.createItemStack() + return@executes sendItemToSource(it, itemStack) + } + + private val rangeArgument = CommandManager.argument("range", DoubleArgumentType.doubleArg()) + .then(throughArgument) + private val damageArgument = CommandManager.argument("damage", DoubleArgumentType.doubleArg()) + .then(rangeArgument) + private val coolingArgument = CommandManager.argument("cooling", DoubleArgumentType.doubleArg()) + .then(damageArgument) + private val maxTempArgument = CommandManager.argument("maxTemp", IntegerArgumentType.integer()) + .then(coolingArgument) + private val heatArgument = CommandManager.argument("heat", IntegerArgumentType.integer()) + .then(maxTempArgument) + + val command: LiteralArgumentBuilder = CommandManager.literal("getGun") + .then( + CommandManager.argument("item", IdentifierArgumentType.identifier()) + .suggests { _, builder -> + CustomItem.registry.getAll().keys.forEach { identifier -> + if (CustomItem.registry.get(identifier) !is Gun) return@forEach + if (identifier.toString().contains(builder.remaining, ignoreCase = true)) { + builder.suggest(identifier.toString()) + } + } + return@suggests builder.buildFuture() + } + .executes { + val identifier = IdentifierArgumentType.getIdentifier(it, "item") + val item = CustomItem.registry.get(identifier) as Gun? + + if (item == null) { + it.source.sendError(Text.translatable("argument.item.id.invalid", identifier)) + return@executes 0 + } + + return@executes sendItemToSource(it, item.createItemStack()) + } + .then(heatArgument) + ) + + private fun sendItemToSource(it: CommandContext, itemStack: ItemStack): Int { + val player = it.source.playerOrThrow + if (player.inventory.insertStack(itemStack)) { + itemStack.count = 1 + val itemEntity = player.dropItem(itemStack, false) + itemEntity?.setDespawnImmediately() + + player.world.playSound( + null, + player.x, + player.y, + player.z, + SoundEvents.ENTITY_ITEM_PICKUP, + SoundCategory.PLAYERS, + 0.2F, + ((player.random.nextFloat() - player.random.nextFloat()) * 0.7F + 1.0F) * 2.0F + ) + player.playerScreenHandler.sendContentUpdates() + } else { + player.dropItem(itemStack, false)?.apply { + resetPickupDelay() + setOwner(player.uuid) + } + } + it.source.sendFeedback({ Text.translatable("commands.give.success.single", 1, itemStack.toHoverableText(), it.source.displayName) }, true) + + return Command.SINGLE_SUCCESS + } +} diff --git a/src/main/kotlin/one/oktw/galaxy/item/CustomItem.kt b/src/main/kotlin/one/oktw/galaxy/item/CustomItem.kt index 9e65e50a0..a5c77efb3 100644 --- a/src/main/kotlin/one/oktw/galaxy/item/CustomItem.kt +++ b/src/main/kotlin/one/oktw/galaxy/item/CustomItem.kt @@ -1,6 +1,6 @@ /* * OKTW Galaxy Project - * Copyright (C) 2018-2021 + * Copyright (C) 2018-2022 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published @@ -37,7 +37,8 @@ abstract class CustomItem(override val identifier: Identifier, private val baseI Material Tool Upgrade - Weapon + Gun + Sword CustomBlockItem } } diff --git a/src/main/kotlin/one/oktw/galaxy/item/CustomItemHelper.kt b/src/main/kotlin/one/oktw/galaxy/item/CustomItemHelper.kt index 5c80d75dd..d55234bc2 100644 --- a/src/main/kotlin/one/oktw/galaxy/item/CustomItemHelper.kt +++ b/src/main/kotlin/one/oktw/galaxy/item/CustomItemHelper.kt @@ -1,6 +1,6 @@ /* * OKTW Galaxy Project - * Copyright (C) 2018-2021 + * Copyright (C) 2018-2022 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published @@ -23,6 +23,7 @@ import net.minecraft.util.Identifier object CustomItemHelper { fun getItem(itemStack: ItemStack): CustomItem? { + if (itemStack.isEmpty) return null val customNbt = itemStack.getSubNbt("GalaxyData") return customNbt?.getString("CustomItemIdentifier")?.let(Identifier::tryParse) diff --git a/src/main/kotlin/one/oktw/galaxy/item/Gun.kt b/src/main/kotlin/one/oktw/galaxy/item/Gun.kt new file mode 100644 index 000000000..789a6f981 --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/item/Gun.kt @@ -0,0 +1,64 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.item + +import net.minecraft.nbt.NbtCompound +import net.minecraft.util.math.MathHelper +import one.oktw.galaxy.item.data.GunData + +class Gun(id: String, modelData: Int, name: String) : Weapon(id, modelData, name) { + companion object { + val PISTOL = registry.register(Gun("pistol", 3010100, "item.Gun.PISTOL")) + val PISTOL_LASOR = registry.register(Gun("pistol_lasor", 3010200, "item.Gun.PISTOL")) + val PISTOL_LASOR_AIMING = registry.register(Gun("pistol_lasor_aiming", 3010201, "item.Gun.PISTOL")) + val SNIPER = registry.register(Gun("sniper", 3010300, "item.Gun.SNIPER")) + val SNIPER_AIMING = registry.register(Gun("sniper_aiming", 3010301, "item.Gun.SNIPER")) + val RAILGUN = registry.register(Gun("railgun", 3010400, "item.Gun.RAILGUN")) + val RAILGUN_AIMING = registry.register(Gun("railgun_aiming", 3010401, "item.Gun.RAILGUN")) + } + + override val weaponData = GunData() + + fun migrateData(item: Gun) { + val oldData = item.weaponData + weaponData.applyValue(oldData.heat, oldData.maxTemp, oldData.cooling, oldData.damage, oldData.range, oldData.through) + } + + override fun readCustomNbt(nbt: NbtCompound): CustomItem { + val nbtData = nbt.getCompound("WeaponData") + weaponData.readFromNbt(nbtData) + return super.readCustomNbt(nbt) + } + + override fun writeCustomNbt(nbt: NbtCompound) { + super.writeCustomNbt(nbt) + nbt.put( + "WeaponData", + NbtCompound().apply { + putUuid("id", MathHelper.randomUuid()) + putInt("heat", weaponData.heat) + putInt("maxTemp", weaponData.maxTemp) + putDouble("cooling", weaponData.cooling) + putDouble("damage", weaponData.damage) + putDouble("range", weaponData.range) + putInt("through", weaponData.through) + } + ) + } +} diff --git a/src/main/kotlin/one/oktw/galaxy/item/Sword.kt b/src/main/kotlin/one/oktw/galaxy/item/Sword.kt new file mode 100644 index 000000000..9476a26a6 --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/item/Sword.kt @@ -0,0 +1,52 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.item + +import net.minecraft.nbt.NbtCompound +import one.oktw.galaxy.item.data.SwordData + +class Sword(id: String, modelData: Int, name: String) : Weapon(id, modelData, name) { + companion object { + val SWORD_KATANA_OFF = registry.register(Sword("sword_katana_off", 3020100, "item.Weapon.KATANA")) + val SWORD_KATANA_ON = registry.register(Sword("sword_katana_on", 3020101, "item.Weapon.KATANA")) + val SWORD_KATANA_SCABBARD = registry.register(Sword("sword_katana_scabbard", 3020102, "item.Weapon.KATANA.SCABARD")) + val SWORD_MAGI_OFF = registry.register(Sword("sword_magi_off", 3020200, "item.Weapon.MAGI")) + val SWORD_MAGI_ON = registry.register(Sword("sword_magi_on", 3020201, "item.Weapon.MAGI")) + val SWORD_GHOST_CUTTER_OFF = registry.register(Sword("sword_ghost_cutter_off", 3020300, "item.event.halloween2018.undeadKiller")) + val SWORD_GHOST_CUTTER_ON = registry.register(Sword("sword_ghost_cutter_on", 3020301, "item.event.halloween2018.undeadKiller")) + val SWORD_NAZO_OFF = registry.register(Sword("sword_nazo_off", 3020400, "item.Weapon.NAZO")) + val SWORD_NAZO_ON = registry.register(Sword("sword_nazo_on", 3020401, "item.Weapon.NAZO")) + val SWORD_NAZO_SCABBARD = registry.register(Sword("sword_nazo_scabbard", 3020402, "item.Weapon.NAZO.SCABARD")) + val SWORD_RANBO_OFF = registry.register(Sword("sword_ranbo_off", 3020500, "item.Weapon.RANBO")) + val SWORD_RANBO_ON = registry.register(Sword("sword_ranbo_on", 3020501, "item.Weapon.RANBO")) + val SWORD_PLASUM_OFF = registry.register(Sword("sword_plasum_off", 3020600, "item.Weapon.PLASUM")) + val SWORD_PLASUM_ON = registry.register(Sword("sword_plasum_on", 3020601, "item.Weapon.PLASUM")) + val SWORD_NANOSABER_OFF = registry.register(Sword("sword_nanosaber_off", 3020700, "item.Weapon.NANOSABER")) + val SWORD_NANOSABER_ON = registry.register(Sword("sword_nanosaber_on", 3020701, "item.Weapon.NANOSABER")) + val SWORD_NANOSABER_SCABBARD = registry.register(Sword("sword_nanosaber_scabbard", 3020702, "item.Weapon.NANOSABER.SCABARD")) + } + + override val weaponData = SwordData() + + override fun readCustomNbt(nbt: NbtCompound): CustomItem { + val nbtData = nbt.getCompound("WeaponData") + weaponData.readFromNbt(nbtData) + return super.readCustomNbt(nbt) + } +} diff --git a/src/main/kotlin/one/oktw/galaxy/item/Weapon.kt b/src/main/kotlin/one/oktw/galaxy/item/Weapon.kt index 7351ec435..f41975390 100644 --- a/src/main/kotlin/one/oktw/galaxy/item/Weapon.kt +++ b/src/main/kotlin/one/oktw/galaxy/item/Weapon.kt @@ -18,49 +18,26 @@ package one.oktw.galaxy.item +import net.minecraft.item.ItemStack import net.minecraft.item.Items.COMMAND_BLOCK -import net.minecraft.nbt.NbtCompound import net.minecraft.text.Text import net.minecraft.text.Text.translatable import net.minecraft.util.Formatting import net.minecraft.util.Identifier -import net.minecraft.util.math.MathHelper +import one.oktw.galaxy.item.data.WeaponData +import one.oktw.galaxy.util.LoreEditor.Companion.loreEditor -class Weapon private constructor(id: String, modelData: Int, private val name: String) : +abstract class Weapon(id: String, modelData: Int, private val name: String) : CustomItem(Identifier("galaxy", "item/weapon/$id"), COMMAND_BLOCK, modelData) { override val cacheable = false - companion object { - val PISTOL = registry.register(Weapon("pistol", 3010100, "item.Gun.PISTOL")) - val PISTOL_LASOR = registry.register(Weapon("pistol_lasor", 3010200, "item.Gun.PISTOL")) - val PISTOL_LASOR_AIMING = registry.register(Weapon("pistol_lasor_aiming", 3010201, "item.Gun.PISTOL")) - val SNIPER = registry.register(Weapon("sniper", 3010300, "item.Gun.SNIPER")) - val SNIPER_AIMING = registry.register(Weapon("sniper_aiming", 3010301, "item.Gun.SNIPER")) - val RAILGUN = registry.register(Weapon("railgun", 3010400, "item.Gun.RAILGUN")) - val RAILGUN_AIMING = registry.register(Weapon("railgun_aiming", 3010401, "item.Gun.RAILGUN")) - val SWORD_KATANA_OFF = registry.register(Weapon("sword_katana_off", 3020100, "item.Weapon.KATANA")) - val SWORD_KATANA_ON = registry.register(Weapon("sword_katana_on", 3020101, "item.Weapon.KATANA")) - val SWORD_KATANA_SCABBARD = registry.register(Weapon("sword_katana_scabbard", 3020102, "item.Weapon.KATANA.SCABARD")) - val SWORD_MAGI_OFF = registry.register(Weapon("sword_magi_off", 3020200, "item.Weapon.MAGI")) - val SWORD_MAGI_ON = registry.register(Weapon("sword_magi_on", 3020201, "item.Weapon.MAGI")) - val SWORD_GHOST_CUTTER_OFF = registry.register(Weapon("sword_ghost_cutter_off", 3020300, "item.event.halloween2018.undeadKiller")) - val SWORD_GHOST_CUTTER_ON = registry.register(Weapon("sword_ghost_cutter_on", 3020301, "item.event.halloween2018.undeadKiller")) - val SWORD_NAZO_OFF = registry.register(Weapon("sword_nazo_off", 3020400, "item.Weapon.NAZO")) - val SWORD_NAZO_ON = registry.register(Weapon("sword_nazo_on", 3020401, "item.Weapon.NAZO")) - val SWORD_NAZO_SCABBARD = registry.register(Weapon("sword_nazo_scabbard", 3020402, "item.Weapon.NAZO.SCABARD")) - val SWORD_RANBO_OFF = registry.register(Weapon("sword_ranbo_off", 3020500, "item.Weapon.RANBO")) - val SWORD_RANBO_ON = registry.register(Weapon("sword_ranbo_on", 3020501, "item.Weapon.RANBO")) - val SWORD_PLASUM_OFF = registry.register(Weapon("sword_plasum_off", 3020600, "item.Weapon.PLASUM")) - val SWORD_PLASUM_ON = registry.register(Weapon("sword_plasum_on", 3020601, "item.Weapon.PLASUM")) - val SWORD_NANOSABER_OFF = registry.register(Weapon("sword_nanosaber_off", 3020700, "item.Weapon.NANOSABER")) - val SWORD_NANOSABER_ON = registry.register(Weapon("sword_nanosaber_on", 3020701, "item.Weapon.NANOSABER")) - val SWORD_NANOSABER_SCABBARD = registry.register(Weapon("sword_nanosaber_scabbard", 3020702, "item.Weapon.NANOSABER.SCABARD")) - } + abstract val weaponData: WeaponData override fun getName(): Text = translatable(name).styled { it.withColor(Formatting.WHITE).withItalic(false) } - override fun writeCustomNbt(nbt: NbtCompound) { - super.writeCustomNbt(nbt) - nbt.put("WeaponData", NbtCompound().apply { putUuid("id", MathHelper.randomUuid()) }) + override fun createItemStack(): ItemStack = super.createItemStack().apply { + loreEditor { + addText(weaponData.toLoreText()) + } } } diff --git a/src/main/kotlin/one/oktw/galaxy/item/data/GunData.kt b/src/main/kotlin/one/oktw/galaxy/item/data/GunData.kt new file mode 100644 index 000000000..b39dd14ea --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/item/data/GunData.kt @@ -0,0 +1,60 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.item.data + +import net.minecraft.nbt.NbtCompound +import net.minecraft.text.Text +import one.oktw.galaxy.item.type.WeaponType + +data class GunData( + var heat: Int = 1, + var maxTemp: Int = 1, + var cooling: Double = 1.0, + var damage: Double = 1.0, + var range: Double = 1.0, + var through: Int = 1 +) : WeaponData(WeaponType.GUN) { + override fun toLoreText() = arrayListOf( + loreText(Text.of("傷害"), damage.toString()), + loreText(Text.of("射程"), range.toString(), "B"), + loreText(Text.of("穿透"), through.toString(), ""), + loreText(Text.of("積熱"), heat.toString(), "K/shot"), + loreText(Text.of("耐熱"), maxTemp.toString(), "K"), + loreText(Text.of("冷卻"), cooling.toString(), "K/t") + ) + + override fun readFromNbt(nbt: NbtCompound) = applyValue( + nbt.getInt("heat"), + nbt.getInt("maxTemp"), + nbt.getDouble("cooling"), + nbt.getDouble("damage"), + nbt.getDouble("range"), + nbt.getInt("through") + ) + + fun applyValue(heat: Int, maxTemp: Int, cooling: Double, damage: Double, range: Double, through: Int) { + this.heat = heat + this.maxTemp = maxTemp + this.cooling = cooling + this.damage = damage + this.range = range + this.through = through + } + +} diff --git a/src/main/kotlin/one/oktw/galaxy/item/data/SwordData.kt b/src/main/kotlin/one/oktw/galaxy/item/data/SwordData.kt new file mode 100644 index 000000000..4bc5cc216 --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/item/data/SwordData.kt @@ -0,0 +1,36 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.item.data + +import net.minecraft.nbt.NbtCompound +import net.minecraft.text.Text +import one.oktw.galaxy.item.type.WeaponType + +data class SwordData( + var damage: Double = 1.0 +) : WeaponData(WeaponType.SWORD) { + override fun toLoreText() = arrayListOf( + loreText(Text.of("傷害"), damage.toString()) + ) + + override fun readFromNbt(nbt: NbtCompound) { + damage = nbt.getDouble("damage") + } + +} diff --git a/src/main/kotlin/one/oktw/galaxy/item/data/WeaponData.kt b/src/main/kotlin/one/oktw/galaxy/item/data/WeaponData.kt new file mode 100644 index 000000000..b0725b5d9 --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/item/data/WeaponData.kt @@ -0,0 +1,39 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.item.data + +import net.minecraft.nbt.NbtCompound +import net.minecraft.text.Style +import net.minecraft.text.Text +import net.minecraft.util.Formatting +import one.oktw.galaxy.item.type.WeaponType + +abstract class WeaponData(val type: WeaponType) { + abstract fun toLoreText(): ArrayList + + abstract fun readFromNbt(nbt: NbtCompound) + + internal fun loreText(key: Text, value: String, unit: String = ""): Text = + key.copy() + .setStyle(Style.EMPTY.withColor(Formatting.AQUA)) + .append(Text.literal(": ").styled { it.withColor(Formatting.DARK_GRAY) }) + .append(Text.literal(value).styled { it.withColor(Formatting.GRAY) }) + .append(Text.literal(unit).styled { it.withColor(Formatting.DARK_GRAY) }) + .styled { it.withItalic(false) } +} diff --git a/src/main/kotlin/one/oktw/galaxy/item/event/Weapon.kt b/src/main/kotlin/one/oktw/galaxy/item/event/Weapon.kt new file mode 100644 index 000000000..5195b8a96 --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/item/event/Weapon.kt @@ -0,0 +1,68 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.item.event + +import net.minecraft.server.network.ServerPlayerEntity +import one.oktw.galaxy.event.annotation.EventListener +import one.oktw.galaxy.event.type.* + +class Weapon { + @EventListener(true) + fun onPlayerInteractItem(event: PlayerInteractItemEvent) { +// var hand = Hand.MAIN_HAND +// var weapon = WeaponData.fromItem(event.player.getStackInHand(hand)) +// if (event.packet.hand == Hand.OFF_HAND) { +// if (weapon == null) { +// hand = Hand.OFF_HAND +// weapon = WeaponData.fromItem(event.player.getStackInHand(hand)) +// } +// } +// if (weapon == null) return +// weapon.shoot(event.player, event.player.world as ServerWorld) + } + + @EventListener(true) + fun onPlayerSneak(event: PlayerSneakEvent) = switchAiming(event.player, true) + + @EventListener(true) + fun onPlayerSneakRelease(event: PlayerSneakReleaseEvent) = switchAiming(event.player, false) + + @EventListener(true) + fun onUpdateSelectedSlot(event: UpdateSelectedSlotEvent) = updateInventory(event.player) + + @EventListener(true) + fun onHotBarSlotUpdate(event: HotBarSlotUpdateEvent) = updateInventory(event.player) + + private fun updateInventory(player: ServerPlayerEntity) = switchAiming(player, player.shouldCancelInteraction()) + + private fun switchAiming(player: ServerPlayerEntity, aiming: Boolean) { +// var hand = Hand.MAIN_HAND +// var weapon = WeaponData.fromItem(player.getStackInHand(hand)) +// if (weapon == null) { +// hand = Hand.OFF_HAND +// weapon = WeaponData.fromItem(player.getStackInHand(hand)) ?: return +// } else { +// val offWeapon = WeaponData.fromItem(player.getStackInHand(Hand.OFF_HAND)) +// if (offWeapon != null) { // turn off offhand aim +// player.setStackInHand(Hand.OFF_HAND, offWeapon.switchAiming(false)) +// } +// } +// player.setStackInHand(hand, weapon.switchAiming(aiming)) + } +} diff --git a/src/main/kotlin/one/oktw/galaxy/item/type/WeaponType.kt b/src/main/kotlin/one/oktw/galaxy/item/type/WeaponType.kt new file mode 100644 index 000000000..24f1ddfd7 --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/item/type/WeaponType.kt @@ -0,0 +1,24 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.item.type + +enum class WeaponType(val type: String) { + GUN("Gun"), + SWORD("Sword") +} diff --git a/src/main/kotlin/one/oktw/galaxy/sound/GalaxySound.kt b/src/main/kotlin/one/oktw/galaxy/sound/GalaxySound.kt new file mode 100644 index 000000000..9421a3450 --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/sound/GalaxySound.kt @@ -0,0 +1,59 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2023 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.sound + +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket +import net.minecraft.registry.entry.RegistryEntry +import net.minecraft.server.MinecraftServer +import net.minecraft.server.world.ServerWorld +import net.minecraft.sound.SoundCategory +import net.minecraft.sound.SoundEvent +import net.minecraft.util.Identifier +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d + +object GalaxySound { + val GUN_SHOOT = Identifier("galaxy:gun.shot") + val GUN_OVERHEAT = Identifier("galaxy:gun.overheat") + + fun playSound( + server: MinecraftServer, + world: ServerWorld, + player: PlayerEntity?, + pos: BlockPos, + soundID: Identifier, + category: SoundCategory, + volume: Float, + pitch: Float + ) { + val registryEntry = RegistryEntry.of(SoundEvent.of(soundID)) + val seed: Long = world.getRandom().nextLong() + val vec3d = Vec3d(pos.x.toDouble(), pos.y.toDouble(), pos.z.toDouble()) + server.playerManager.sendToAround( + player, + vec3d.x, + vec3d.y, + vec3d.z, + if (volume > 1.0F) (16.0 * volume) else 16.0, + world.registryKey, + PlaySoundS2CPacket(registryEntry, category, vec3d.x, vec3d.y, vec3d.z, volume, pitch, seed) + ) + } +} From c43de8fed481341dce90f327db05f37b5509b1ad Mon Sep 17 00:00:00 2001 From: jimchen5209 Date: Sun, 7 Jan 2024 13:41:30 +0800 Subject: [PATCH 3/3] feat: Add gun aiming and shooting --- .../MixinPlayerDropItem_NetworkHandler.java | 53 +++++ .../MixinPlayerPickupItem_ItemEntity.java | 45 ++++ ...nPlayerSwapItemInHand_NetworkHandler.java} | 28 ++- src/main/kotlin/one/oktw/galaxy/Main.kt | 3 +- ...tUpdateEvent.kt => PlayerDropItemEvent.kt} | 6 +- .../event/type/PlayerPickupItemEvent.kt | 23 +++ .../event/type/PlayerSwapItemInHandEvent.kt | 23 +++ .../kotlin/one/oktw/galaxy/item/event/Gun.kt | 193 ++++++++++++++++++ .../one/oktw/galaxy/item/event/Weapon.kt | 68 ------ src/main/resources/galaxy.mixin.json | 4 +- 10 files changed, 356 insertions(+), 90 deletions(-) create mode 100644 src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerDropItem_NetworkHandler.java create mode 100644 src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerPickupItem_ItemEntity.java rename src/main/java/one/oktw/galaxy/mixin/event/{MixinHotBarSlotUpdate_ScreenHandlerListener.java => MixinPlayerSwapItemInHand_NetworkHandler.java} (59%) rename src/main/kotlin/one/oktw/galaxy/event/type/{HotBarSlotUpdateEvent.kt => PlayerDropItemEvent.kt} (76%) create mode 100644 src/main/kotlin/one/oktw/galaxy/event/type/PlayerPickupItemEvent.kt create mode 100644 src/main/kotlin/one/oktw/galaxy/event/type/PlayerSwapItemInHandEvent.kt create mode 100644 src/main/kotlin/one/oktw/galaxy/item/event/Gun.kt delete mode 100644 src/main/kotlin/one/oktw/galaxy/item/event/Weapon.kt diff --git a/src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerDropItem_NetworkHandler.java b/src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerDropItem_NetworkHandler.java new file mode 100644 index 000000000..1b9411bae --- /dev/null +++ b/src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerDropItem_NetworkHandler.java @@ -0,0 +1,53 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.mixin.event; + +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import one.oktw.galaxy.Main; +import one.oktw.galaxy.event.type.PlayerDropItemEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ServerPlayNetworkHandler.class) +public class MixinPlayerDropItem_NetworkHandler { + @Shadow + public ServerPlayerEntity player; + + @Inject( + method = "onPlayerAction", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/server/network/ServerPlayerEntity;dropSelectedItem(Z)Z", + shift = At.Shift.BEFORE + ), cancellable = true) + private void onPlayerAction(PlayerActionC2SPacket packet, CallbackInfo ci) { + Main main = Main.Companion.getMain(); + if (main != null && main.getEventManager().emit(new PlayerDropItemEvent(player)).getCancel()) { + ci.cancel(); + player.currentScreenHandler.syncState(); + } + } + + +} diff --git a/src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerPickupItem_ItemEntity.java b/src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerPickupItem_ItemEntity.java new file mode 100644 index 000000000..ac3ab7b36 --- /dev/null +++ b/src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerPickupItem_ItemEntity.java @@ -0,0 +1,45 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.mixin.event; + +import net.minecraft.entity.ItemEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.network.ServerPlayerEntity; +import one.oktw.galaxy.Main; +import one.oktw.galaxy.event.type.PlayerPickupItemEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(ItemEntity.class) +public class MixinPlayerPickupItem_ItemEntity { + @Inject( + method = "onPlayerCollision", + at = @At( + value = "INVOKE", + target = "Lnet/minecraft/entity/player/PlayerEntity;triggerItemPickedUpByEntityCriteria(Lnet/minecraft/entity/ItemEntity;)V", + shift = At.Shift.AFTER + )) + private void onPlayerCollision(PlayerEntity player, CallbackInfo ci) { + Main main = Main.Companion.getMain(); + if (main == null) return; + main.getEventManager().emit(new PlayerPickupItemEvent((ServerPlayerEntity) player)); + } +} diff --git a/src/main/java/one/oktw/galaxy/mixin/event/MixinHotBarSlotUpdate_ScreenHandlerListener.java b/src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerSwapItemInHand_NetworkHandler.java similarity index 59% rename from src/main/java/one/oktw/galaxy/mixin/event/MixinHotBarSlotUpdate_ScreenHandlerListener.java rename to src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerSwapItemInHand_NetworkHandler.java index e8d2869b0..40119828e 100644 --- a/src/main/java/one/oktw/galaxy/mixin/event/MixinHotBarSlotUpdate_ScreenHandlerListener.java +++ b/src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerSwapItemInHand_NetworkHandler.java @@ -1,6 +1,6 @@ /* * OKTW Galaxy Project - * Copyright (C) 2018-2021 + * Copyright (C) 2018-2022 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published @@ -18,31 +18,27 @@ package one.oktw.galaxy.mixin.event; -import net.minecraft.item.ItemStack; -import net.minecraft.screen.ScreenHandler; +import net.minecraft.network.packet.c2s.play.PlayerActionC2SPacket; +import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import one.oktw.galaxy.Main; -import one.oktw.galaxy.event.type.HotBarSlotUpdateEvent; +import one.oktw.galaxy.event.type.PlayerSwapItemInHandEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(targets = {"net/minecraft/server/network/ServerPlayerEntity$2"}) -public class MixinHotBarSlotUpdate_ScreenHandlerListener { - @Shadow(aliases = {"field_29183"}) - private ServerPlayerEntity player; +@Mixin(ServerPlayNetworkHandler.class) +public class MixinPlayerSwapItemInHand_NetworkHandler { + @Shadow + public ServerPlayerEntity player; - @Inject( - method = "onSlotUpdate(Lnet/minecraft/screen/ScreenHandler;ILnet/minecraft/item/ItemStack;)V", - at = @At(value = "RETURN") - ) - private void onSlotUpdate(ScreenHandler handler, int slotId, ItemStack stack, CallbackInfo ci) { + @Inject(method = "onPlayerAction", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerEntity;clearActiveItem()V", shift = At.Shift.AFTER)) + private void onPlayerAction(PlayerActionC2SPacket packet, CallbackInfo ci) { Main main = Main.Companion.getMain(); if (main == null) return; - if (slotId >= 36 && slotId <= 45) { - main.getEventManager().emit(new HotBarSlotUpdateEvent(player, handler, slotId, stack)); - } + main.getEventManager().emit(new PlayerSwapItemInHandEvent(player)); } + } diff --git a/src/main/kotlin/one/oktw/galaxy/Main.kt b/src/main/kotlin/one/oktw/galaxy/Main.kt index b2e64465b..67ca241a2 100644 --- a/src/main/kotlin/one/oktw/galaxy/Main.kt +++ b/src/main/kotlin/one/oktw/galaxy/Main.kt @@ -39,6 +39,7 @@ import one.oktw.galaxy.command.commands.Spawn import one.oktw.galaxy.event.EventManager import one.oktw.galaxy.event.type.ProxyResponseEvent import one.oktw.galaxy.item.event.CustomItemEventHandler +import one.oktw.galaxy.item.event.Gun import one.oktw.galaxy.item.event.Wrench import one.oktw.galaxy.player.Harvest import one.oktw.galaxy.proxy.api.ProxyAPI @@ -99,7 +100,7 @@ class Main : DedicatedServerModInitializer, CoroutineScope { eventManager.register(Elevator()) eventManager.register(AngelBlock()) eventManager.register(CustomItemEventHandler()) -// eventManager.register(Weapon()) + eventManager.register(Gun()) }) ServerLifecycleEvents.SERVER_STOPPING.register { diff --git a/src/main/kotlin/one/oktw/galaxy/event/type/HotBarSlotUpdateEvent.kt b/src/main/kotlin/one/oktw/galaxy/event/type/PlayerDropItemEvent.kt similarity index 76% rename from src/main/kotlin/one/oktw/galaxy/event/type/HotBarSlotUpdateEvent.kt rename to src/main/kotlin/one/oktw/galaxy/event/type/PlayerDropItemEvent.kt index c69f2c13a..033963f10 100644 --- a/src/main/kotlin/one/oktw/galaxy/event/type/HotBarSlotUpdateEvent.kt +++ b/src/main/kotlin/one/oktw/galaxy/event/type/PlayerDropItemEvent.kt @@ -1,6 +1,6 @@ /* * OKTW Galaxy Project - * Copyright (C) 2018-2021 + * Copyright (C) 2018-2022 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published @@ -18,8 +18,6 @@ package one.oktw.galaxy.event.type -import net.minecraft.item.ItemStack -import net.minecraft.screen.ScreenHandler import net.minecraft.server.network.ServerPlayerEntity -class HotBarSlotUpdateEvent(val player: ServerPlayerEntity, val handler: ScreenHandler, val slotId: Int, val item: ItemStack) : Event +class PlayerDropItemEvent(val player: ServerPlayerEntity) : CancelableEvent() diff --git a/src/main/kotlin/one/oktw/galaxy/event/type/PlayerPickupItemEvent.kt b/src/main/kotlin/one/oktw/galaxy/event/type/PlayerPickupItemEvent.kt new file mode 100644 index 000000000..ed00f0bba --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/event/type/PlayerPickupItemEvent.kt @@ -0,0 +1,23 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.event.type + +import net.minecraft.server.network.ServerPlayerEntity + +class PlayerPickupItemEvent(val player: ServerPlayerEntity) : Event diff --git a/src/main/kotlin/one/oktw/galaxy/event/type/PlayerSwapItemInHandEvent.kt b/src/main/kotlin/one/oktw/galaxy/event/type/PlayerSwapItemInHandEvent.kt new file mode 100644 index 000000000..1b3d39c02 --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/event/type/PlayerSwapItemInHandEvent.kt @@ -0,0 +1,23 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.event.type + +import net.minecraft.server.network.ServerPlayerEntity + +class PlayerSwapItemInHandEvent(val player: ServerPlayerEntity) : Event diff --git a/src/main/kotlin/one/oktw/galaxy/item/event/Gun.kt b/src/main/kotlin/one/oktw/galaxy/item/event/Gun.kt new file mode 100644 index 000000000..f63ad031e --- /dev/null +++ b/src/main/kotlin/one/oktw/galaxy/item/event/Gun.kt @@ -0,0 +1,193 @@ +/* + * OKTW Galaxy Project + * Copyright (C) 2018-2022 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package one.oktw.galaxy.item.event + +import net.minecraft.item.ItemStack +import net.minecraft.particle.ParticleTypes +import net.minecraft.server.MinecraftServer +import net.minecraft.server.network.ServerPlayerEntity +import net.minecraft.server.world.ServerWorld +import net.minecraft.sound.SoundCategory +import net.minecraft.sound.SoundEvents +import net.minecraft.util.Hand +import net.minecraft.util.math.BlockPos +import net.minecraft.util.math.Vec3d +import one.oktw.galaxy.event.annotation.EventListener +import one.oktw.galaxy.event.type.* +import one.oktw.galaxy.item.CustomItemHelper +import one.oktw.galaxy.item.Gun +import one.oktw.galaxy.sound.GalaxySound +import java.lang.Math.random +import kotlin.math.abs +import kotlin.math.roundToInt + +class Gun { + @EventListener(true) + fun onPlayerInteractItem(event: PlayerInteractItemEvent) = shoot(event.player) + + @EventListener(true) + fun onPlayerUseItemOnBlock(event: PlayerUseItemOnBlock) = shoot(event.context.player as ServerPlayerEntity) + + @EventListener(true) + fun onPlayerSneak(event: PlayerSneakEvent) = switchAiming(event.player, true) + + @EventListener(true) + fun onPlayerSneakRelease(event: PlayerSneakReleaseEvent) = switchAiming(event.player, false) + + @EventListener(true) + fun onUpdateSelectedSlot(event: UpdateSelectedSlotEvent) = switchAiming(event.player, event.player.shouldCancelInteraction()) + + @EventListener(true) + fun onSwapItem(event: PlayerSwapItemInHandEvent) = switchAiming(event.player, event.player.shouldCancelInteraction()) + + // cancel aiming before dropping + @EventListener(true) + fun onDropItem(event: PlayerDropItemEvent) = switchAiming(event.player, false) + + @EventListener(true) + fun onPickupItem(event: PlayerPickupItemEvent) = switchAiming(event.player, event.player.shouldCancelInteraction()) + + private fun shoot(player: ServerPlayerEntity) { + val items = getWeaponsFromHands(player) + val gun = items[Hand.MAIN_HAND] ?: items[Hand.OFF_HAND] ?: return + shoot(gun, player, player.world as ServerWorld) + } + + private fun getWeaponsFromHands(player: ServerPlayerEntity): Map = mapOf( + Hand.MAIN_HAND to CustomItemHelper.getItem(player.getStackInHand(Hand.MAIN_HAND)) as? Gun, + Hand.OFF_HAND to CustomItemHelper.getItem(player.getStackInHand(Hand.OFF_HAND)) as? Gun + ) + + private fun switchAiming(player: ServerPlayerEntity, aiming: Boolean) { + val items = getWeaponsFromHands(player) + + val hand = if (items[Hand.MAIN_HAND] != null) Hand.MAIN_HAND else if (items[Hand.OFF_HAND] != null) Hand.OFF_HAND else return + + if (hand == Hand.MAIN_HAND && items[Hand.OFF_HAND] != null) { // turn weapon on offhand aiming off + switchAiming(items[Hand.OFF_HAND]!!, false)?.let { player.setStackInHand(Hand.OFF_HAND, it) } + } + + switchAiming(items[hand]!!, aiming)?.let { player.setStackInHand(hand, it) } + } + + private fun shoot(item: Gun, player: ServerPlayerEntity, world: ServerWorld) { + showTrajectory(item, player, world) + playSound(item, player.server, world, player.blockPos) + } + + private fun switchAiming(item: Gun, aiming: Boolean): ItemStack? { + val newItem = if (aiming) { + when (item) { + Gun.PISTOL_LASOR -> Gun.PISTOL_LASOR_AIMING + Gun.SNIPER -> Gun.SNIPER_AIMING + Gun.RAILGUN -> Gun.RAILGUN_AIMING + else -> item + } as Gun + } else { + when (item) { + Gun.PISTOL_LASOR_AIMING -> Gun.PISTOL_LASOR + Gun.SNIPER_AIMING -> Gun.SNIPER + Gun.RAILGUN_AIMING -> Gun.RAILGUN + else -> item + } as Gun + } + if (item != newItem) { + return newItem.apply { + migrateData(item) + }.createItemStack() + } + return null + } + + private fun showTrajectory(item: Gun, player: ServerPlayerEntity, world: ServerWorld) { + val gun = item.weaponData + var playerLookVec = player.rotationVector + if (!player.shouldCancelInteraction()) playerLookVec = drift(playerLookVec) + val line = playerLookVec.multiply(gun.range) + + val interval = when (maxAxis(vecAbs(line))) { + 0 -> vecAbs(line).x.div(0.3) + 1 -> vecAbs(line).y.div(0.3) + 2 -> vecAbs(line).z.div(0.3) + else -> 10.0 + } + var pos = Vec3d(player.x, player.eyeY, player.z).add(vecDiv(line, interval)) + + for (i in 0..interval.roundToInt()) { + world.spawnParticles(ParticleTypes.ENCHANTED_HIT, pos.x, pos.y, pos.z, 1, 0.0, 0.0, 0.0, 0.0) + pos = pos.add(vecDiv(line, interval)) + } + } + + private fun drift(vec: Vec3d) = vecDiv( + vec.multiply(10.0).add(random(), random(), random()) + .subtract(random(), random(), random()), 10.0 + ) + + private fun playSound(item: Gun, server: MinecraftServer, world: ServerWorld, pos: BlockPos) = when (item) { + Gun.PISTOL, Gun.PISTOL_LASOR, Gun.PISTOL_LASOR_AIMING -> + GalaxySound.playSound( + server, + world, + null, + pos, + GalaxySound.GUN_SHOOT, + SoundCategory.PLAYERS, + 1.0f, + (1 + random() / 10 - random() / 10).toFloat() + ) + Gun.SNIPER, Gun.SNIPER_AIMING -> { + world.playSound( + null, + pos, + SoundEvents.ENTITY_BLAZE_HURT, + SoundCategory.PLAYERS, + 1.0f, + 2.0f + ) + world.playSound( + null, + pos, + SoundEvents.ENTITY_FIREWORK_ROCKET_BLAST, + SoundCategory.PLAYERS, + 1.0f, + 0.0f + ) + world.playSound( + null, + pos, + SoundEvents.BLOCK_PISTON_EXTEND, + SoundCategory.PLAYERS, + 1.0f, + 2.0f + ) + } + else -> Unit // TODO RailGun + } + + private fun vecAbs(vec: Vec3d) = Vec3d(abs(vec.x), abs(vec.y), abs(vec.z)) + + private fun maxAxis(vec: Vec3d) = if (vec.x < vec.y) { + if (vec.y < vec.z) 2 else 1 + } else { + if (vec.x < vec.z) 2 else 0 + } + + private fun vecDiv(vec: Vec3d, value: Double) = Vec3d(vec.x / value, vec.y / value, vec.z / value) +} diff --git a/src/main/kotlin/one/oktw/galaxy/item/event/Weapon.kt b/src/main/kotlin/one/oktw/galaxy/item/event/Weapon.kt deleted file mode 100644 index 5195b8a96..000000000 --- a/src/main/kotlin/one/oktw/galaxy/item/event/Weapon.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * OKTW Galaxy Project - * Copyright (C) 2018-2022 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package one.oktw.galaxy.item.event - -import net.minecraft.server.network.ServerPlayerEntity -import one.oktw.galaxy.event.annotation.EventListener -import one.oktw.galaxy.event.type.* - -class Weapon { - @EventListener(true) - fun onPlayerInteractItem(event: PlayerInteractItemEvent) { -// var hand = Hand.MAIN_HAND -// var weapon = WeaponData.fromItem(event.player.getStackInHand(hand)) -// if (event.packet.hand == Hand.OFF_HAND) { -// if (weapon == null) { -// hand = Hand.OFF_HAND -// weapon = WeaponData.fromItem(event.player.getStackInHand(hand)) -// } -// } -// if (weapon == null) return -// weapon.shoot(event.player, event.player.world as ServerWorld) - } - - @EventListener(true) - fun onPlayerSneak(event: PlayerSneakEvent) = switchAiming(event.player, true) - - @EventListener(true) - fun onPlayerSneakRelease(event: PlayerSneakReleaseEvent) = switchAiming(event.player, false) - - @EventListener(true) - fun onUpdateSelectedSlot(event: UpdateSelectedSlotEvent) = updateInventory(event.player) - - @EventListener(true) - fun onHotBarSlotUpdate(event: HotBarSlotUpdateEvent) = updateInventory(event.player) - - private fun updateInventory(player: ServerPlayerEntity) = switchAiming(player, player.shouldCancelInteraction()) - - private fun switchAiming(player: ServerPlayerEntity, aiming: Boolean) { -// var hand = Hand.MAIN_HAND -// var weapon = WeaponData.fromItem(player.getStackInHand(hand)) -// if (weapon == null) { -// hand = Hand.OFF_HAND -// weapon = WeaponData.fromItem(player.getStackInHand(hand)) ?: return -// } else { -// val offWeapon = WeaponData.fromItem(player.getStackInHand(Hand.OFF_HAND)) -// if (offWeapon != null) { // turn off offhand aim -// player.setStackInHand(Hand.OFF_HAND, offWeapon.switchAiming(false)) -// } -// } -// player.setStackInHand(hand, weapon.switchAiming(aiming)) - } -} diff --git a/src/main/resources/galaxy.mixin.json b/src/main/resources/galaxy.mixin.json index b42110651..4f8306527 100644 --- a/src/main/resources/galaxy.mixin.json +++ b/src/main/resources/galaxy.mixin.json @@ -3,15 +3,17 @@ "package": "one.oktw.galaxy.mixin.event", "compatibilityLevel": "JAVA_16", "mixins": [ - "MixinHotBarSlotUpdate_ScreenHandlerListener", "MixinPlayerAction_NetworkHandler", "MixinPlayerChat_MeCommand", "MixinPlayerChat_NetworkHandler", "MixinPlayerChat_SayCommand", + "MixinPlayerDropItem_NetworkHandler", "MixinPlayerInteractBlock_NetworkHandler", "MixinPlayerInteractItem_NetworkHandler", "MixinPlayerJump_NetworkHandler", + "MixinPlayerPickupItem_ItemEntity", "MixinPlayerSneak_NetworkHandler", + "MixinPlayerSwapItemInHand_NetworkHandler", "MixinPlayerUseItemOnBlock_ItemStack", "MixinUpdateSelectedSlot_NetworkHandler" ],