diff options
Diffstat (limited to 'src/main')
34 files changed, 790 insertions, 34 deletions
diff --git a/src/main/generated/.cache/4145a4ade350d062a154f42d7ad0d98fb52bf04b b/src/main/generated/.cache/4145a4ade350d062a154f42d7ad0d98fb52bf04b index 072c021..d246b4f 100644 --- a/src/main/generated/.cache/4145a4ade350d062a154f42d7ad0d98fb52bf04b +++ b/src/main/generated/.cache/4145a4ade350d062a154f42d7ad0d98fb52bf04b @@ -1,3 +1,3 @@ -// 1.21.1 2025-02-09T00:02:42.294183715 Pirate Radio/Recipes -84f8cd2b2d9d1afcf2a5cf000905c264a6d8267c data/pirate-radio/recipe/disposable-transmitter.json +// 1.21.1 2025-03-14T18:16:59.621431904 Pirate Radio/Recipes +368c94ec69c8320836c81014b1cfeab0742cb6e8 data/pirate-radio/recipe/disposable-transmitter.json 86e73a1d034dc407ce65e0e61af19b1db43e1939 data/pirate-radio/advancement/recipes/misc/disposable-transmitter.json diff --git a/src/main/generated/.cache/bd1ee27e4c10ec669c0e0894b64dd83a58902c72 b/src/main/generated/.cache/bd1ee27e4c10ec669c0e0894b64dd83a58902c72 index cf1f8c7..8e7e12b 100644 --- a/src/main/generated/.cache/bd1ee27e4c10ec669c0e0894b64dd83a58902c72 +++ b/src/main/generated/.cache/bd1ee27e4c10ec669c0e0894b64dd83a58902c72 @@ -1,5 +1,4 @@ -// 1.21.1 2025-02-09T00:02:42.294917543 Pirate Radio/Model Definitions -3507512497435bf1047ebd71ae1f4881ceb67f44 assets/pirate-radio/models/item/fm-receiver.json +// 1.21.1 2025-03-14T18:16:59.623037325 Pirate Radio/Model Definitions ab60b602066c94b5746065e1b139a383a6c26429 assets/pirate-radio/models/item/powerbank.json fb8af1b0939020c3a89a7736e47d9f688b38a2c9 assets/pirate-radio/models/item/storage-card.json dbc04d664dacd99a76580bcff2c5b944abb0730e assets/pirate-radio/models/item/sbc.json diff --git a/src/main/generated/assets/pirate-radio/models/item/fm-receiver.json b/src/main/generated/assets/pirate-radio/models/item/fm-receiver.json deleted file mode 100644 index 71813c4..0000000 --- a/src/main/generated/assets/pirate-radio/models/item/fm-receiver.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "minecraft:item/generated", - "textures": { - "layer0": "pirate-radio:item/fm-receiver" - } -} \ No newline at end of file diff --git a/src/main/generated/data/pirate-radio/recipe/disposable-transmitter.json b/src/main/generated/data/pirate-radio/recipe/disposable-transmitter.json index 2a1d645..87b9be6 100644 --- a/src/main/generated/data/pirate-radio/recipe/disposable-transmitter.json +++ b/src/main/generated/data/pirate-radio/recipe/disposable-transmitter.json @@ -10,9 +10,6 @@ }, { "item": "pirate-radio:powerbank" - }, - { - "item": "pirate-radio:storage-card" } ], "result": { diff --git a/src/main/kotlin/space/autistic/radio/CommonProxy.kt b/src/main/kotlin/space/autistic/radio/CommonProxy.kt new file mode 100644 index 0000000..76a4b22 --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/CommonProxy.kt @@ -0,0 +1,10 @@ +package space.autistic.radio + +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.item.ItemStack +import net.minecraft.util.Hand + +open class CommonProxy : SidedProxy { + override fun useStorageCard(player: PlayerEntity, item: ItemStack, hand: Hand) { + } +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/PirateRadio.kt b/src/main/kotlin/space/autistic/radio/PirateRadio.kt index 54d0b9f..d463e41 100644 --- a/src/main/kotlin/space/autistic/radio/PirateRadio.kt +++ b/src/main/kotlin/space/autistic/radio/PirateRadio.kt @@ -1,17 +1,58 @@ package space.autistic.radio +import com.mojang.serialization.Codec import net.fabricmc.api.ModInitializer +import net.fabricmc.fabric.api.event.registry.DynamicRegistries +import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking +import net.minecraft.item.ItemStack +import net.minecraft.registry.Registry +import net.minecraft.registry.RegistryKey +import net.minecraft.text.Text +import net.minecraft.util.Identifier import org.slf4j.LoggerFactory +import space.autistic.radio.antenna.Antenna +import space.autistic.radio.antenna.PirateRadioAntennaSerializers +import space.autistic.radio.network.StorageCardUpdateC2SPayload +import kotlin.math.max +import kotlin.math.min object PirateRadio : ModInitializer { - const val MOD_ID = "pirate-radio" - private val logger = LoggerFactory.getLogger(MOD_ID) + var proxy: SidedProxy? = null + const val MOD_ID = "pirate-radio" + val logger = LoggerFactory.getLogger(MOD_ID) - override fun onInitialize() { - logger.info("This project is made with love by a queer trans person.\n" + - "The folks of these identities who have contributed to the project would like to make their identities known:\n" + - "Autgender; Not a person; Anticapitalist; Genderqueer; Trans.") - PirateRadioItems.initialize() - PirateRadioEntityTypes.initialize() - } + + override fun onInitialize() { + if (proxy == null) { + proxy = CommonProxy() + } + logger.info( + "This project is made with love by a queer trans person.\n" + + "The folks of these identities who have contributed to the project would like to make their identities known:\n" + + "Autgender; Not a person; Anticapitalist; Genderqueer; Trans." + ) + PirateRadioRegistries.initialize() + PirateRadioAntennaSerializers.initialize() + DynamicRegistries.registerSynced(PirateRadioRegistryKeys.ANTENNA, Antenna.CODEC) + PayloadTypeRegistry.playC2S() + .register(StorageCardUpdateC2SPayload.PAYLOAD_ID, StorageCardUpdateC2SPayload.CODEC) + ServerPlayNetworking.registerGlobalReceiver(StorageCardUpdateC2SPayload.PAYLOAD_ID) { payload, context -> + if (!context.player().isAlive) { + return@registerGlobalReceiver + } + val stack = context.player().inventory.getStack(payload.slot) + if (stack.isOf(PirateRadioItems.STORAGE_CARD)) { + stack.set(PirateRadioComponents.FREQUENCY, min(1080, max(768, payload.frequency))) + var text = payload.text + if (text.length > 16384) { + text = text.substring(0, 16384) + } + stack.set(PirateRadioComponents.MESSAGE, Text.literal(text)) + } + } + PirateRadioComponents.initialize() + PirateRadioItems.initialize() + PirateRadioEntityTypes.initialize() + } } \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/PirateRadioComponents.kt b/src/main/kotlin/space/autistic/radio/PirateRadioComponents.kt new file mode 100644 index 0000000..f79f26a --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/PirateRadioComponents.kt @@ -0,0 +1,30 @@ +package space.autistic.radio + +import net.minecraft.component.ComponentType +import net.minecraft.network.codec.PacketCodecs +import net.minecraft.registry.Registries +import net.minecraft.registry.Registry +import net.minecraft.text.Text +import net.minecraft.text.TextCodecs +import net.minecraft.util.Identifier +import net.minecraft.util.dynamic.Codecs + +object PirateRadioComponents { + val FREQUENCY = Registry.register( + Registries.DATA_COMPONENT_TYPE, + Identifier.of(PirateRadio.MOD_ID, "frequency"), + ComponentType.builder<Int>().codec( + Codecs.rangedInt(768, 1080) + ).packetCodec(PacketCodecs.VAR_INT).build() + ) + + val MESSAGE = Registry.register( + Registries.DATA_COMPONENT_TYPE, + Identifier.of(PirateRadio.MOD_ID, "message"), + ComponentType.builder<Text>().codec(TextCodecs.STRINGIFIED_CODEC).packetCodec(TextCodecs.REGISTRY_PACKET_CODEC) + .cache().build() + ) + + fun initialize() { + } +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/PirateRadioEntityTypes.kt b/src/main/kotlin/space/autistic/radio/PirateRadioEntityTypes.kt index f147394..3fbb34f 100644 --- a/src/main/kotlin/space/autistic/radio/PirateRadioEntityTypes.kt +++ b/src/main/kotlin/space/autistic/radio/PirateRadioEntityTypes.kt @@ -11,13 +11,31 @@ import net.minecraft.registry.RegistryKey import net.minecraft.registry.RegistryKeys import net.minecraft.util.Identifier import space.autistic.radio.entity.ElectronicsTraderEntity +import space.autistic.radio.entity.DisposableTransmitterEntity object PirateRadioEntityTypes { - val ELECTRONICS_TRADER_KEY = RegistryKey.of(RegistryKeys.ENTITY_TYPE, Identifier.of(PirateRadio.MOD_ID, "electronics-trader")) - val ELECTRONICS_TRADER = register(EntityType.Builder.create(::ElectronicsTraderEntity, SpawnGroup.MISC).dimensions(0.6F, 1.95F).eyeHeight(1.62F).maxTrackingRange(10), ELECTRONICS_TRADER_KEY) + val ELECTRONICS_TRADER_KEY = + RegistryKey.of(RegistryKeys.ENTITY_TYPE, Identifier.of(PirateRadio.MOD_ID, "electronics-trader")) + val ELECTRONICS_TRADER = register( + EntityType.Builder.create(::ElectronicsTraderEntity, SpawnGroup.MISC).dimensions(0.6F, 1.95F).eyeHeight(1.62F) + .maxTrackingRange(10), ELECTRONICS_TRADER_KEY + ) - fun <T : Entity> register(entityTypeBuilder: EntityType.Builder<T>, registryKey: RegistryKey<EntityType<*>>): EntityType<T> { - return Registry.register(Registries.ENTITY_TYPE, registryKey.value, entityTypeBuilder.build(registryKey.value.path)) + val DISPOSABLE_TRANSMITTER_KEY = RegistryKey.of(RegistryKeys.ENTITY_TYPE, Identifier.of(PirateRadio.MOD_ID, "disposable-transmitter")) + val DISPOSABLE_TRANSMITTER = register( + EntityType.Builder.create(::DisposableTransmitterEntity, SpawnGroup.MISC).dimensions(0.5F, 0.5F).eyeHeight(0F) + .maxTrackingRange(10).trackingTickInterval(Integer.MAX_VALUE), DISPOSABLE_TRANSMITTER_KEY + ) + + fun <T : Entity> register( + entityTypeBuilder: EntityType.Builder<T>, + registryKey: RegistryKey<EntityType<*>> + ): EntityType<T> { + return Registry.register( + Registries.ENTITY_TYPE, + registryKey.value, + entityTypeBuilder.build(registryKey.value.path) + ) } fun initialize() { diff --git a/src/main/kotlin/space/autistic/radio/PirateRadioItems.kt b/src/main/kotlin/space/autistic/radio/PirateRadioItems.kt index 490acaf..e00e4e6 100644 --- a/src/main/kotlin/space/autistic/radio/PirateRadioItems.kt +++ b/src/main/kotlin/space/autistic/radio/PirateRadioItems.kt @@ -2,12 +2,16 @@ package space.autistic.radio import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents import net.minecraft.item.Item +import net.minecraft.item.ItemFrameItem import net.minecraft.item.ItemGroups import net.minecraft.registry.Registries import net.minecraft.registry.Registry import net.minecraft.registry.RegistryKey import net.minecraft.registry.RegistryKeys +import net.minecraft.text.Text import net.minecraft.util.Identifier +import space.autistic.radio.item.DisposableTransmitterItem +import space.autistic.radio.item.StorageCardItem object PirateRadioItems { val SBC_KEY = RegistryKey.of(RegistryKeys.ITEM, Identifier.of(PirateRadio.MOD_ID, "sbc")) @@ -17,11 +21,20 @@ object PirateRadioItems { val POWERBANK_KEY = RegistryKey.of(RegistryKeys.ITEM, Identifier.of(PirateRadio.MOD_ID, "powerbank")) val POWERBANK = register(Item(Item.Settings()), POWERBANK_KEY) val STORAGE_CARD_KEY = RegistryKey.of(RegistryKeys.ITEM, Identifier.of(PirateRadio.MOD_ID, "storage-card")) - val STORAGE_CARD = register(Item(Item.Settings()), STORAGE_CARD_KEY) - val DISPOSABLE_TRANSMITTER_KEY = RegistryKey.of(RegistryKeys.ITEM, Identifier.of(PirateRadio.MOD_ID, "disposable-transmitter")) - val DISPOSABLE_TRANSMITTER = register(Item(Item.Settings()), DISPOSABLE_TRANSMITTER_KEY) - val FM_RECEIVER_KEY = RegistryKey.of(RegistryKeys.ITEM, Identifier.of(PirateRadio.MOD_ID, "fm-receiver")) - val FM_RECEIVER = register(Item(Item.Settings()), FM_RECEIVER_KEY) + val STORAGE_CARD = register( + StorageCardItem( + Item.Settings().maxCount(1).component(PirateRadioComponents.FREQUENCY, 768) + .component(PirateRadioComponents.MESSAGE, Text.literal("")) + ), STORAGE_CARD_KEY + ) + val DISPOSABLE_TRANSMITTER_KEY = + RegistryKey.of(RegistryKeys.ITEM, Identifier.of(PirateRadio.MOD_ID, "disposable-transmitter")) + val DISPOSABLE_TRANSMITTER = register( + DisposableTransmitterItem(PirateRadioEntityTypes.DISPOSABLE_TRANSMITTER, Item.Settings()), + DISPOSABLE_TRANSMITTER_KEY + ) +// val FM_RECEIVER_KEY = RegistryKey.of(RegistryKeys.ITEM, Identifier.of(PirateRadio.MOD_ID, "fm-receiver")) +// val FM_RECEIVER = register(Item(Item.Settings()), FM_RECEIVER_KEY) fun register(item: Item, registryKey: RegistryKey<Item>): Item { return Registry.register(Registries.ITEM, registryKey.value, item) diff --git a/src/main/kotlin/space/autistic/radio/PirateRadioRegistries.kt b/src/main/kotlin/space/autistic/radio/PirateRadioRegistries.kt new file mode 100644 index 0000000..6010d3c --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/PirateRadioRegistries.kt @@ -0,0 +1,12 @@ +package space.autistic.radio + +import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder +import net.fabricmc.fabric.api.event.registry.RegistryAttribute + +object PirateRadioRegistries { + val ANTENNA_SERIALIZER = FabricRegistryBuilder.createSimple(PirateRadioRegistryKeys.ANTENNA_SERIALIZER) + .attribute(RegistryAttribute.SYNCED).buildAndRegister() + + fun initialize() { + } +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/PirateRadioRegistryKeys.kt b/src/main/kotlin/space/autistic/radio/PirateRadioRegistryKeys.kt new file mode 100644 index 0000000..eb5db1f --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/PirateRadioRegistryKeys.kt @@ -0,0 +1,13 @@ +package space.autistic.radio + +import net.minecraft.registry.Registry +import net.minecraft.registry.RegistryKey +import net.minecraft.util.Identifier +import space.autistic.radio.PirateRadio.MOD_ID +import space.autistic.radio.antenna.Antenna +import space.autistic.radio.antenna.AntennaSerializer + +object PirateRadioRegistryKeys { + val ANTENNA_SERIALIZER = RegistryKey.ofRegistry<AntennaSerializer<*>>(Identifier.of(MOD_ID, "antenna_serializer")) + val ANTENNA = RegistryKey.ofRegistry<Antenna<*>>(Identifier.of(MOD_ID, "antenna")) +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/SidedProxy.kt b/src/main/kotlin/space/autistic/radio/SidedProxy.kt new file mode 100644 index 0000000..0e34ec9 --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/SidedProxy.kt @@ -0,0 +1,9 @@ +package space.autistic.radio + +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.item.ItemStack +import net.minecraft.util.Hand + +interface SidedProxy { + fun useStorageCard(player: PlayerEntity, item: ItemStack, hand: Hand) +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/antenna/Antenna.kt b/src/main/kotlin/space/autistic/radio/antenna/Antenna.kt new file mode 100644 index 0000000..c403081 --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/antenna/Antenna.kt @@ -0,0 +1,9 @@ +package space.autistic.radio.antenna + +import space.autistic.radio.PirateRadioRegistries + +data class Antenna<T>(val type: AntennaSerializer<T>, val data: T) { + companion object { + val CODEC = PirateRadioRegistries.ANTENNA_SERIALIZER.codec.dispatch({ it.type }, AntennaSerializer<*>::codec) + } +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/antenna/AntennaSerializer.kt b/src/main/kotlin/space/autistic/radio/antenna/AntennaSerializer.kt new file mode 100644 index 0000000..11d0234 --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/antenna/AntennaSerializer.kt @@ -0,0 +1,8 @@ +package space.autistic.radio.antenna + +import com.mojang.serialization.MapCodec + +interface AntennaSerializer<T> { + val codec: MapCodec<Antenna<T>> + get +} diff --git a/src/main/kotlin/space/autistic/radio/antenna/ConstAntenna.kt b/src/main/kotlin/space/autistic/radio/antenna/ConstAntenna.kt new file mode 100644 index 0000000..401972c --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/antenna/ConstAntenna.kt @@ -0,0 +1,7 @@ +package space.autistic.radio.antenna + +import com.mojang.serialization.Codec + +object ConstAntenna : AntennaSerializer<Float> { + override val codec = Codec.FLOAT.fieldOf("level").xmap({ Antenna(this, it) }, { it.data }) +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/antenna/PirateRadioAntennaSerializers.kt b/src/main/kotlin/space/autistic/radio/antenna/PirateRadioAntennaSerializers.kt new file mode 100644 index 0000000..19cfff8 --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/antenna/PirateRadioAntennaSerializers.kt @@ -0,0 +1,18 @@ +package space.autistic.radio.antenna + +import net.minecraft.registry.Registry +import net.minecraft.util.Identifier +import space.autistic.radio.PirateRadio +import space.autistic.radio.PirateRadioRegistries + +object PirateRadioAntennaSerializers { + val CONST = register(Identifier.of(PirateRadio.MOD_ID, "const"), ConstAntenna) + val WASM = register(Identifier.of(PirateRadio.MOD_ID, "wasm"), WasmAntenna) + + private fun <T> register(id: Identifier, antennaSerializer: AntennaSerializer<T>): AntennaSerializer<T> { + return Registry.register(PirateRadioRegistries.ANTENNA_SERIALIZER, id, antennaSerializer) + } + + fun initialize() { + } +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/antenna/WasmAntenna.kt b/src/main/kotlin/space/autistic/radio/antenna/WasmAntenna.kt new file mode 100644 index 0000000..32c96bb --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/antenna/WasmAntenna.kt @@ -0,0 +1,7 @@ +package space.autistic.radio.antenna + +import net.minecraft.util.Identifier + +object WasmAntenna : AntennaSerializer<Identifier> { + override val codec = Identifier.CODEC.fieldOf("model").xmap({ Antenna(this, it) }, { it.data }) +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/entity/DisposableTransmitterEntity.kt b/src/main/kotlin/space/autistic/radio/entity/DisposableTransmitterEntity.kt new file mode 100644 index 0000000..fe26a86 --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/entity/DisposableTransmitterEntity.kt @@ -0,0 +1,178 @@ +package space.autistic.radio.entity + +import net.minecraft.entity.Entity +import net.minecraft.entity.EntityType +import net.minecraft.entity.data.DataTracker +import net.minecraft.entity.data.TrackedDataHandlerRegistry +import net.minecraft.entity.decoration.AbstractDecorationEntity +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.nbt.NbtCompound +import net.minecraft.network.listener.ClientPlayPacketListener +import net.minecraft.network.packet.Packet +import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket +import net.minecraft.server.network.EntityTrackerEntry +import net.minecraft.util.ActionResult +import net.minecraft.util.Hand +import net.minecraft.util.math.* +import net.minecraft.world.World +import net.minecraft.world.event.GameEvent +import space.autistic.radio.PirateRadioComponents +import space.autistic.radio.PirateRadioEntityTypes +import space.autistic.radio.PirateRadioItems +import kotlin.math.max +import kotlin.math.min + +class DisposableTransmitterEntity : AbstractDecorationEntity { + var despawnDelay = 60 * 60 * 20 + + constructor(type: EntityType<out DisposableTransmitterEntity>?, world: World?) : super(type, world) + + constructor( + type: EntityType<out DisposableTransmitterEntity>?, + world: World?, + pos: BlockPos, + facing: Direction + ) : super( + type, world, pos + ) { + this.setFacing(facing) + } + + constructor( + world: World, + blockPos2: BlockPos, + direction: Direction + ) : this(PirateRadioEntityTypes.DISPOSABLE_TRANSMITTER, world, blockPos2, direction) + + override fun initDataTracker(builder: DataTracker.Builder) { + builder.add(TEXT, "") + builder.add(FREQUENCY, 768) + } + + override fun tick() { + super.tick() + if (!world.isClient) { + this.tickDespawnDelay(); + } + } + + private fun tickDespawnDelay() { + if (this.despawnDelay > 0 && this.despawnDelay-- == 0) { + this.discard() + } + } + + override fun setFacing(facing: Direction) { + this.facing = facing + if (facing.axis.isHorizontal) { + this.pitch = 0.0f + this.yaw = (this.facing.horizontal * 90).toFloat() + } else { + this.pitch = (-90 * facing.direction.offset()).toFloat() + this.yaw = 0.0f + } + + this.prevPitch = this.pitch + this.prevYaw = this.yaw + this.updateAttachmentPosition() + } + + override fun calculateBoundingBox(pos: BlockPos, side: Direction): Box { + val center = Vec3d.ofCenter(pos).offset(side, -(1.0 - DEPTH) / 2.0) + val axis = side.axis + val dx = if (axis === Direction.Axis.X) DEPTH else WIDTH + val dy = if (axis === Direction.Axis.Y) DEPTH else HEIGHT + val dz = if (axis === Direction.Axis.Z) DEPTH else WIDTH + return Box.of(center, dx, dy, dz) + } + + // leave this true for performance + override fun canStayAttached(): Boolean = true + + override fun onBreak(breaker: Entity?) { + // hmm, what to do here... + } + + override fun onPlace() { + // hmm, what to do here... + } + + var text: String + get() { + return this.dataTracker[TEXT] + } + set(value) { + this.dataTracker[TEXT] = value + } + + var frequency: Int + get() { + return this.dataTracker[FREQUENCY] + } + set(value) { + this.dataTracker[FREQUENCY] = value + } + + override fun writeCustomDataToNbt(nbt: NbtCompound) { + super.writeCustomDataToNbt(nbt) + nbt.putByte("Facing", this.facing.id.toByte()) + nbt.putInt("DespawnDelay", this.despawnDelay) + nbt.putString("Text", this.text) + nbt.putBoolean("Invisible", this.isInvisible) + nbt.putInt("Frequency", this.frequency) + } + + override fun readCustomDataFromNbt(nbt: NbtCompound) { + super.readCustomDataFromNbt(nbt) + this.despawnDelay = nbt.getInt("DespawnDelay") + this.setFacing(Direction.byId(nbt.getByte("Facing").toInt())) + this.text = nbt.getString("Text") + this.isInvisible = nbt.getBoolean("Invisible") + this.frequency = min(1080, max(768, nbt.getInt("Frequency"))) + } + + override fun createSpawnPacket(entityTrackerEntry: EntityTrackerEntry): Packet<ClientPlayPacketListener> { + return EntitySpawnS2CPacket(this, facing.id, this.getAttachedBlockPos()) + } + + override fun onSpawnPacket(packet: EntitySpawnS2CPacket) { + super.onSpawnPacket(packet) + this.setFacing(Direction.byId(packet.entityData)) + } + + override fun getBodyYaw(): Float { + val direction = this.horizontalFacing + val i = if (direction.axis.isVertical) 90 * direction.direction.offset() else 0 + return MathHelper.wrapDegrees(180 + direction.horizontal * 90 + i).toFloat() + } + + override fun interact(player: PlayerEntity, hand: Hand): ActionResult { + val itemStack = player.getStackInHand(hand) + val noTextInTransmitter = this.text.isEmpty() + val isCard = itemStack.isOf(PirateRadioItems.STORAGE_CARD) + val holdingMessage = isCard && (itemStack.get(PirateRadioComponents.MESSAGE)?.literalString ?: "").isNotEmpty() + if (!world.isClient) { + if (noTextInTransmitter) { + if (holdingMessage && !this.isRemoved) { + this.frequency = itemStack.getOrDefault(PirateRadioComponents.FREQUENCY, 768) + this.text = itemStack.get(PirateRadioComponents.MESSAGE)?.literalString ?: "" + this.emitGameEvent(GameEvent.BLOCK_CHANGE, player) + itemStack.decrementUnlessCreative(1, player) + } + } + return ActionResult.CONSUME + } else { + return if (noTextInTransmitter && holdingMessage) ActionResult.SUCCESS else ActionResult.PASS + } + } + + companion object { + private val TEXT = + DataTracker.registerData(DisposableTransmitterEntity::class.java, TrackedDataHandlerRegistry.STRING) + private val FREQUENCY = + DataTracker.registerData(DisposableTransmitterEntity::class.java, TrackedDataHandlerRegistry.INTEGER) + const val DEPTH = 0.0625 + private const val WIDTH = 0.75 + private const val HEIGHT = 0.75 + } +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/entity/ElectronicsTraderEntity.kt b/src/main/kotlin/space/autistic/radio/entity/ElectronicsTraderEntity.kt index 3aa53b1..1acbeb4 100644 --- a/src/main/kotlin/space/autistic/radio/entity/ElectronicsTraderEntity.kt +++ b/src/main/kotlin/space/autistic/radio/entity/ElectronicsTraderEntity.kt @@ -21,7 +21,7 @@ class ElectronicsTraderEntity(entityType: EntityType<out ElectronicsTraderEntity override fun fillRecipes() { val offers = this.getOffers() offers.add(TradeOffer(TradedItem(Items.EMERALD, 5), ItemStack(PirateRadioItems.POWERBANK), 3, 0, 0f)) - offers.add(TradeOffer(TradedItem(Items.EMERALD, 10), ItemStack(PirateRadioItems.FM_RECEIVER), 3, 0, 0f)) +// offers.add(TradeOffer(TradedItem(Items.EMERALD, 10), ItemStack(PirateRadioItems.FM_RECEIVER), 3, 0, 0f)) offers.add(TradeOffer(TradedItem(Items.EMERALD, 15), ItemStack(PirateRadioItems.SBC), 3, 0, 0f)) offers.add(TradeOffer(TradedItem(Items.EMERALD, 5), ItemStack(PirateRadioItems.STORAGE_CARD), 3, 0, 0f)) offers.add(TradeOffer(TradedItem(Items.EMERALD, 1), ItemStack(PirateRadioItems.WIRE), 3, 0, 0f)) @@ -29,7 +29,7 @@ class ElectronicsTraderEntity(entityType: EntityType<out ElectronicsTraderEntity override fun tickMovement() { if (!this.world.isClient) { - super.setDespawnDelay(1000) + super.setDespawnDelay(-1) } super.tickMovement() } diff --git a/src/main/kotlin/space/autistic/radio/item/DisposableTransmitterItem.kt b/src/main/kotlin/space/autistic/radio/item/DisposableTransmitterItem.kt new file mode 100644 index 0000000..c9a53e4 --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/item/DisposableTransmitterItem.kt @@ -0,0 +1,56 @@ +package space.autistic.radio.item + +import net.minecraft.component.DataComponentTypes +import net.minecraft.component.type.NbtComponent +import net.minecraft.entity.EntityType +import net.minecraft.entity.decoration.AbstractDecorationEntity +import net.minecraft.item.ItemFrameItem +import net.minecraft.item.ItemUsageContext +import net.minecraft.util.ActionResult +import net.minecraft.world.event.GameEvent +import space.autistic.radio.PirateRadioEntityTypes +import space.autistic.radio.entity.DisposableTransmitterEntity + +class DisposableTransmitterItem( + private val entityType: EntityType<out AbstractDecorationEntity>?, + settings: Settings? +) : + ItemFrameItem(entityType, settings) { + + override fun useOnBlock(context: ItemUsageContext): ActionResult { + val blockPos = context.blockPos + val direction = context.side + val blockPos2 = blockPos.offset(direction) + val playerEntity = context.player + val itemStack = context.stack + if (playerEntity != null && !this.canPlaceOn(playerEntity, direction, itemStack, blockPos2)) { + return ActionResult.FAIL + } else { + val world = context.world + val abstractDecorationEntity: AbstractDecorationEntity + if (this.entityType === PirateRadioEntityTypes.DISPOSABLE_TRANSMITTER) { + abstractDecorationEntity = DisposableTransmitterEntity(world, blockPos2, direction) + } else { + return ActionResult.success(world.isClient) + } + + val nbtComponent = itemStack.getOrDefault(DataComponentTypes.ENTITY_DATA, NbtComponent.DEFAULT) + if (!nbtComponent.isEmpty) { + EntityType.loadFromEntityNbt(world, playerEntity, abstractDecorationEntity, nbtComponent) + } + + if (abstractDecorationEntity.canStayAttached()) { + if (!world.isClient) { + abstractDecorationEntity.onPlace() + world.emitGameEvent(playerEntity, GameEvent.ENTITY_PLACE, abstractDecorationEntity.pos) + world.spawnEntity(abstractDecorationEntity) + } + + itemStack.decrement(1) + return ActionResult.success(world.isClient) + } else { + return ActionResult.CONSUME + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/item/StorageCardItem.kt b/src/main/kotlin/space/autistic/radio/item/StorageCardItem.kt new file mode 100644 index 0000000..da1b057 --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/item/StorageCardItem.kt @@ -0,0 +1,20 @@ +package space.autistic.radio.item + +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.item.Item +import net.minecraft.item.ItemStack +import net.minecraft.stat.Stats +import net.minecraft.util.Hand +import net.minecraft.util.TypedActionResult +import net.minecraft.world.World +import space.autistic.radio.PirateRadio + +class StorageCardItem(settings: Settings) : Item(settings) { + + override fun use(world: World, user: PlayerEntity, hand: Hand): TypedActionResult<ItemStack> { + val itemStack = user.getStackInHand(hand) + PirateRadio.proxy!!.useStorageCard(user, itemStack, hand) + user.incrementStat(Stats.USED.getOrCreateStat(this)) + return TypedActionResult.success(itemStack, world.isClient()) + } +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/network/StorageCardUpdateC2SPayload.kt b/src/main/kotlin/space/autistic/radio/network/StorageCardUpdateC2SPayload.kt new file mode 100644 index 0000000..9ffa75a --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/network/StorageCardUpdateC2SPayload.kt @@ -0,0 +1,27 @@ +package space.autistic.radio.network + +import net.minecraft.network.RegistryByteBuf +import net.minecraft.network.codec.PacketCodec +import net.minecraft.network.codec.PacketCodecs +import net.minecraft.network.packet.CustomPayload +import net.minecraft.util.Identifier +import space.autistic.radio.PirateRadio + +@JvmRecord +data class StorageCardUpdateC2SPayload(val slot: Int, val text: String, val frequency: Int) : CustomPayload { + override fun getId(): CustomPayload.Id<out CustomPayload> = PAYLOAD_ID + + companion object { + val PAYLOAD_IDENTIFIER = Identifier.of(PirateRadio.MOD_ID, "storage-card-update") + val PAYLOAD_ID = CustomPayload.Id<StorageCardUpdateC2SPayload>(PAYLOAD_IDENTIFIER) + val CODEC: PacketCodec<RegistryByteBuf, StorageCardUpdateC2SPayload> = PacketCodec.tuple( + PacketCodecs.VAR_INT, + StorageCardUpdateC2SPayload::slot, + PacketCodecs.STRING, + StorageCardUpdateC2SPayload::text, + PacketCodecs.VAR_INT, + StorageCardUpdateC2SPayload::frequency, + ::StorageCardUpdateC2SPayload + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/space/autistic/radio/wasm/Bindings.kt b/src/main/kotlin/space/autistic/radio/wasm/Bindings.kt new file mode 100644 index 0000000..cc123a1 --- /dev/null +++ b/src/main/kotlin/space/autistic/radio/wasm/Bindings.kt @@ -0,0 +1,173 @@ +package space.autistic.radio.wasm + +import com.dylibso.chicory.runtime.HostFunction +import com.dylibso.chicory.runtime.ImportFunction +import com.dylibso.chicory.runtime.Instance +import com.dylibso.chicory.wasm.types.Value +import com.dylibso.chicory.wasm.types.ValueType +import java.lang.invoke.MethodHandles +import java.lang.invoke.MethodType +import java.lang.reflect.Method +import java.lang.reflect.ParameterizedType + +class Bindings { + + companion object { + @JvmStatic + fun longToInt(long: Long): Int = long.toInt() + + @JvmStatic + fun stringArg(instance: Instance, address: Long): String { + return instance.memory().readCString(address.toInt()) + } + + @JvmStatic + fun boolArg(bool: Long): Boolean { + return bool != 0L + } + + @JvmStatic + fun intListArg(instance: Instance, argc: Long, argv: Long): List<Int> { + return IntArray(argc.toInt()) { + instance.memory().readInt(argv.toInt() + 4 * it) + }.toList() + } + + private val lookup = MethodHandles.lookup() + fun bindFunc( + module: String, + name: String, + inLookup: MethodHandles.Lookup, + method: Method, + receiver: Any + ): ImportFunction { + val baseHandle = inLookup.unreflect(method).bindTo(receiver) + val wasmParameters = ArrayList<ValueType>() + val filters = method.genericParameterTypes.map { + when (it) { + Int::class.java -> { + wasmParameters.add(ValueType.I32) + lookup.findStatic( + Bindings::class.java, "longToInt", MethodType.methodType(Int::class.java, Long::class.java) + ) + } + + Long::class.java -> { + wasmParameters.add(ValueType.I64) + MethodHandles.identity(Long::class.java) + } + + Float::class.java -> { + wasmParameters.add(ValueType.F32) + lookup.findStatic( + Value::class.java, "longToFloat", MethodType.methodType(Float::class.java, Long::class.java) + ) + } + + Double::class.java -> { + wasmParameters.add(ValueType.F64) + lookup.findStatic( + Value::class.java, + "longToDouble", + MethodType.methodType(Double::class.java, Long::class.java) + ) + } + + String::class.java -> { + wasmParameters.add(ValueType.I32) + lookup.findStatic( + Bindings::class.java, + "stringArg", + MethodType.methodType(String::class.java, Instance::class.java, Long::class.java) + ) + } + + Boolean::class.java -> { + wasmParameters.add(ValueType.I32) + lookup.findStatic( + Bindings::class.java, + "boolArg", + MethodType.methodType(Boolean::class.java, Long::class.java) + ) + } + + is ParameterizedType -> { + if (it.rawType == List::class.java) { + val converter = when (it.actualTypeArguments[0]) { + java.lang.Integer::class.java -> "intListArg" + else -> throw IllegalArgumentException(it.actualTypeArguments[0].toString()) + } + wasmParameters.add(ValueType.I32) + wasmParameters.add(ValueType.I32) + lookup.findStatic( + Bindings::class.java, + converter, + MethodType.methodType( + List::class.java, + Instance::class.java, + Long::class.java, + Long::class.java + ) + ) + } else { + throw IllegalArgumentException(it.toString()) + } + } + + else -> throw IllegalArgumentException(it.toString()) + } + } + val filterTypes = ArrayList<Class<*>>() + filters.forEach { methodHandle -> + filterTypes.addAll(methodHandle.type().parameterList()) + } + var i = 0 + val permutation = IntArray(filterTypes.size) { + if (filterTypes[it] == Instance::class.java) 0 else ++i + } + var handle = baseHandle + var j = 0 + filters.forEach { + handle = MethodHandles.collectArguments(handle, j, it) + j += it.type().parameterCount() + } + val newtype = MethodType.methodType( + baseHandle.type().returnType(), Instance::class.java, *Array(i) { Long::class.java }) + handle = MethodHandles.permuteArguments(handle, newtype, *permutation) + handle = handle.asSpreader(LongArray::class.java, i) + return when (method.genericReturnType) { + Void.TYPE -> HostFunction(module, name, wasmParameters, emptyList()) { instance, args -> + handle.invokeExact(instance, args) + Value.EMPTY_VALUES + } + + Int::class.java -> HostFunction(module, name, wasmParameters, listOf(ValueType.I32)) { instance, args -> + val result: Int = handle.invokeExact(instance, args) as Int + longArrayOf(result.toLong()) + } + + Boolean::class.java -> HostFunction( + module, + name, + wasmParameters, + listOf(ValueType.I32) + ) { instance, args -> + val result: Boolean = handle.invokeExact(instance, args) as Boolean + longArrayOf(if (result) 1L else 0L) + } + + Float::class.java -> HostFunction( + module, + name, + wasmParameters, + listOf(ValueType.F32) + ) { instance, args -> + val result: Float = handle.invokeExact(instance, args) as Float + longArrayOf(Value.floatToLong(result)) + } + + else -> throw IllegalArgumentException(method.genericReturnType.toString()) + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/pirate-radio/blockstates/disposable-transmitter.json b/src/main/resources/assets/pirate-radio/blockstates/disposable-transmitter.json new file mode 100644 index 0000000..854abc8 --- /dev/null +++ b/src/main/resources/assets/pirate-radio/blockstates/disposable-transmitter.json @@ -0,0 +1,10 @@ +{ + "variants": { + "facing=down": { "model": "pirate-radio:block/disposable-transmitter-vertical" }, + "facing=up": { "model": "pirate-radio:block/disposable-transmitter-vertical" }, + "facing=north": { "model": "pirate-radio:block/disposable-transmitter" }, + "facing=south": { "model": "pirate-radio:block/disposable-transmitter" }, + "facing=west": { "model": "pirate-radio:block/disposable-transmitter" }, + "facing=east": { "model": "pirate-radio:block/disposable-transmitter" } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/pirate-radio/lang/en_us.json b/src/main/resources/assets/pirate-radio/lang/en_us.json index 9627729..81145f0 100644 --- a/src/main/resources/assets/pirate-radio/lang/en_us.json +++ b/src/main/resources/assets/pirate-radio/lang/en_us.json @@ -6,5 +6,25 @@ "item.pirate-radio.disposable-transmitter": "Disposable Pirate Radio Transmitter", "item.pirate-radio.fm-receiver": "FM Receiver", "entity.pirate-radio.electronics-trader": "Microcenter", - "pirate-radio.fm-receiver": "FM Receiver" + "pirate-radio.fm-receiver": "FM Receiver", + "pirate-radio.skin-pack": "Skin pack: %s", + "pirate-radio.frequency.plus": "+", + "pirate-radio.frequency.minus": "-", + "pirate-radio.volume.plus": "+", + "pirate-radio.volume.minus": "-", + "pirate-radio.mode": "Mode", + "pirate-radio.frequency.plus.narrated": "Increase Frequency", + "pirate-radio.frequency.minus.narrated": "Decrease Frequency", + "pirate-radio.volume.plus.narrated": "Increase Volume", + "pirate-radio.volume.minus.narrated": "Decrease Volume", + "pirate-radio.mode.selected": "Mode: %s", + "pirate-radio.mode.full": "Full", + "pirate-radio.mode.fast": "Fast", + "pirate-radio.mode.deaf": "Deaf", + "pirate-radio.volume.selected": "Volume: %s", + "pirate-radio.volume.off": "Off", + "pirate-radio.frequency.selected": "Frequency: %s.%s MHz", + "pirate-radio.storage-card": "SD Card", + "pirate-radio.message": "Message...", + "pirate-radio.frequency.edit": "Frequency" } \ No newline at end of file diff --git a/src/main/resources/assets/pirate-radio/models/block/disposable-transmitter-vertical.json b/src/main/resources/assets/pirate-radio/models/block/disposable-transmitter-vertical.json new file mode 100644 index 0000000..39dc38e --- /dev/null +++ b/src/main/resources/assets/pirate-radio/models/block/disposable-transmitter-vertical.json @@ -0,0 +1,29 @@ +{ + "textures": { + "antenna": "minecraft:block/iron_block", + "body": "minecraft:block/coal_block" + }, + "elements": [ + { "from": [ 6.5, 6.9, 15.4 ], + "to": [ 9.5, 9.1, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#body" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#body" }, + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#body" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#body" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#body" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#body" } + } + }, + { "from": [ 7, 7, 9 ], + "to": [ 7.1, 7.1, 15.4 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#antenna" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#antenna" }, + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#antenna" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#antenna" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#antenna" } + } + } + ] +} diff --git a/src/main/resources/assets/pirate-radio/models/block/disposable-transmitter.json b/src/main/resources/assets/pirate-radio/models/block/disposable-transmitter.json new file mode 100644 index 0000000..f5e26dc --- /dev/null +++ b/src/main/resources/assets/pirate-radio/models/block/disposable-transmitter.json @@ -0,0 +1,30 @@ +{ + "textures": { + "antenna": "minecraft:block/iron_block", + "body": "minecraft:block/coal_block" + }, + "elements": [ + { "from": [ 6.5, 0.9, 15.4 ], + "to": [ 9.5, 3.1, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#body" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#body" }, + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#body" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#body" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#body" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#body" } + } + }, + { "from": [ 7, 1, 15.3 ], + "to": [ 7.1, 7.5, 15.4 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#antenna" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#antenna" }, + "north": { "uv": [ 0, 0, 16, 16 ], "texture": "#antenna" }, + "south": { "uv": [ 0, 0, 16, 16 ], "texture": "#antenna" }, + "west": { "uv": [ 0, 0, 16, 16 ], "texture": "#antenna" }, + "east": { "uv": [ 0, 0, 16, 16 ], "texture": "#antenna" } + } + } + ] +} diff --git a/src/main/resources/assets/pirate-radio/textures/entity/electronics-trader.png b/src/main/resources/assets/pirate-radio/textures/entity/electronics-trader.png new file mode 100644 index 0000000..b86a4ef --- /dev/null +++ b/src/main/resources/assets/pirate-radio/textures/entity/electronics-trader.png Binary files differdiff --git a/src/main/resources/assets/pirate-radio/textures/gui/radio-receiver.png b/src/main/resources/assets/pirate-radio/textures/gui/radio-receiver.png new file mode 100644 index 0000000..b86a4ef --- /dev/null +++ b/src/main/resources/assets/pirate-radio/textures/gui/radio-receiver.png Binary files differdiff --git a/src/main/resources/assets/pirate-radio/textures/item/disposable-transmitter.png b/src/main/resources/assets/pirate-radio/textures/item/disposable-transmitter.png new file mode 100644 index 0000000..c815369 --- /dev/null +++ b/src/main/resources/assets/pirate-radio/textures/item/disposable-transmitter.png Binary files differdiff --git a/src/main/resources/data/pirate-radio/pirate-radio/antenna/const.json b/src/main/resources/data/pirate-radio/pirate-radio/antenna/const.json new file mode 100644 index 0000000..6f7a630 --- /dev/null +++ b/src/main/resources/data/pirate-radio/pirate-radio/antenna/const.json @@ -0,0 +1,4 @@ +{ + "type": "pirate-radio:const", + "level": 1.0 +} \ No newline at end of file diff --git a/src/main/resources/data/pirate-radio/pirate-radio/antenna/null.json b/src/main/resources/data/pirate-radio/pirate-radio/antenna/null.json new file mode 100644 index 0000000..6b7a819 --- /dev/null +++ b/src/main/resources/data/pirate-radio/pirate-radio/antenna/null.json @@ -0,0 +1,4 @@ +{ + "type": "pirate-radio:const", + "level": 0.0 +} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 71f2518..c7d859a 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -34,6 +34,12 @@ } ] }, + "mixins": [ + { + "config": "pirate-radio.client-mixins.json", + "environment": "client" + } + ], "depends": { "fabricloader": ">=0.16.10", "minecraft": "~1.21.1", diff --git a/src/main/resources/pirate-radio.client-mixins.json b/src/main/resources/pirate-radio.client-mixins.json new file mode 100644 index 0000000..27a5861 --- /dev/null +++ b/src/main/resources/pirate-radio.client-mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "space.autistic.radio.client.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + ], + "client": [ + "BlockStatesLoaderMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file |