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/MixinPlayerSwapItemInHand_NetworkHandler.java b/src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerSwapItemInHand_NetworkHandler.java
new file mode 100644
index 000000000..40119828e
--- /dev/null
+++ b/src/main/java/one/oktw/galaxy/mixin/event/MixinPlayerSwapItemInHand_NetworkHandler.java
@@ -0,0 +1,44 @@
+/*
+ * 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.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(ServerPlayNetworkHandler.class)
+public class MixinPlayerSwapItemInHand_NetworkHandler {
+ @Shadow
+ public ServerPlayerEntity player;
+
+ @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;
+ main.getEventManager().emit(new PlayerSwapItemInHandEvent(player));
+ }
+
+}
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/Main.kt b/src/main/kotlin/one/oktw/galaxy/Main.kt
index ab61ee396..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,6 +100,7 @@ class Main : DedicatedServerModInitializer, CoroutineScope {
eventManager.register(Elevator())
eventManager.register(AngelBlock())
eventManager.register(CustomItemEventHandler())
+ eventManager.register(Gun())
})
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/event/type/PlayerDropItemEvent.kt b/src/main/kotlin/one/oktw/galaxy/event/type/PlayerDropItemEvent.kt
new file mode 100644
index 000000000..033963f10
--- /dev/null
+++ b/src/main/kotlin/one/oktw/galaxy/event/type/PlayerDropItemEvent.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 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/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/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/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/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)
+ )
+ }
+}
diff --git a/src/main/resources/galaxy.mixin.json b/src/main/resources/galaxy.mixin.json
index 07f25f563..4f8306527 100644
--- a/src/main/resources/galaxy.mixin.json
+++ b/src/main/resources/galaxy.mixin.json
@@ -7,14 +7,18 @@
"MixinPlayerChat_MeCommand",
"MixinPlayerChat_NetworkHandler",
"MixinPlayerChat_SayCommand",
+ "MixinPlayerDropItem_NetworkHandler",
"MixinPlayerInteractBlock_NetworkHandler",
"MixinPlayerInteractItem_NetworkHandler",
"MixinPlayerJump_NetworkHandler",
+ "MixinPlayerPickupItem_ItemEntity",
"MixinPlayerSneak_NetworkHandler",
- "MixinPlayerUseItemOnBlock_ItemStack"
+ "MixinPlayerSwapItemInHand_NetworkHandler",
+ "MixinPlayerUseItemOnBlock_ItemStack",
+ "MixinUpdateSelectedSlot_NetworkHandler"
],
"client": [],
"injectors": {
"defaultRequire": 1
}
-}
+}
\ No newline at end of file