diff options
author | SoniEx2 <endermoneymod@gmail.com> | 2025-03-04 22:45:19 -0300 |
---|---|---|
committer | SoniEx2 <endermoneymod@gmail.com> | 2025-03-04 22:45:19 -0300 |
commit | 79ff3692b9462fc79d93bd74213ce6904340fc13 (patch) | |
tree | 22055c038783b87cceffe3d2220cc2b568a4493d /src/client |
First public commit
Diffstat (limited to 'src/client')
9 files changed, 285 insertions, 0 deletions
diff --git a/src/client/kotlin/space/autistic/radio/client/PirateRadioClient.kt b/src/client/kotlin/space/autistic/radio/client/PirateRadioClient.kt new file mode 100644 index 0000000..54b7640 --- /dev/null +++ b/src/client/kotlin/space/autistic/radio/client/PirateRadioClient.kt @@ -0,0 +1,35 @@ +package space.autistic.radio.client + +import com.mojang.brigadier.CommandDispatcher +import net.fabricmc.api.ClientModInitializer +import net.fabricmc.fabric.api.client.command.v2.ClientCommandManager +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource +import net.fabricmc.fabric.api.client.rendering.v1.EntityRendererRegistry +import net.minecraft.client.MinecraftClient +import net.minecraft.command.CommandRegistryAccess +import org.slf4j.LoggerFactory +import space.autistic.radio.PirateRadio +import space.autistic.radio.PirateRadio.MOD_ID +import space.autistic.radio.PirateRadioEntityTypes +import space.autistic.radio.client.entity.ElectronicsTraderEntityRenderer +import space.autistic.radio.client.gui.FmReceiverScreen + +object PirateRadioClient : ClientModInitializer { + private val logger = LoggerFactory.getLogger(MOD_ID) + + override fun onInitializeClient() { + EntityRendererRegistry.register(PirateRadioEntityTypes.ELECTRONICS_TRADER, ::ElectronicsTraderEntityRenderer) + PirateRadioEntityModelLayers.initialize() + ClientCommandRegistrationCallback.EVENT.register { dispatcher, _ -> + dispatcher.register( + ClientCommandManager.literal("fm").executes { + it.source.client.send { + it.source.client.setScreen(FmReceiverScreen()) + } + 0 + } + ) + } + } +} \ No newline at end of file diff --git a/src/client/kotlin/space/autistic/radio/client/PirateRadioDataGenerator.kt b/src/client/kotlin/space/autistic/radio/client/PirateRadioDataGenerator.kt new file mode 100644 index 0000000..b5130a1 --- /dev/null +++ b/src/client/kotlin/space/autistic/radio/client/PirateRadioDataGenerator.kt @@ -0,0 +1,62 @@ +package space.autistic.radio.client + +import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint +import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator +import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput +import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider +import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider +import net.minecraft.data.client.BlockStateModelGenerator +import net.minecraft.data.client.ItemModelGenerator +import net.minecraft.data.client.Models +import net.minecraft.data.server.recipe.RecipeExporter +import net.minecraft.data.server.recipe.RecipeProvider +import net.minecraft.data.server.recipe.ShapelessRecipeJsonBuilder +import net.minecraft.item.ItemStack +import net.minecraft.recipe.Ingredient +import net.minecraft.recipe.Recipe +import net.minecraft.recipe.ShapelessRecipe +import net.minecraft.recipe.book.CraftingRecipeCategory +import net.minecraft.recipe.book.RecipeCategory +import net.minecraft.registry.RegistryWrapper +import net.minecraft.util.Identifier +import net.minecraft.util.collection.DefaultedList +import space.autistic.radio.PirateRadio.MOD_ID +import space.autistic.radio.PirateRadioItems +import java.util.concurrent.CompletableFuture + +class PirateRadioItemModelGenerator(output: FabricDataOutput) : FabricModelProvider(output) { + override fun generateBlockStateModels(modelGenerator: BlockStateModelGenerator) { + } + + override fun generateItemModels(modelGenderator: ItemModelGenerator) { + modelGenderator.register(PirateRadioItems.SBC, Models.GENERATED) + modelGenderator.register(PirateRadioItems.WIRE, Models.GENERATED) + modelGenderator.register(PirateRadioItems.POWERBANK, Models.GENERATED) + modelGenderator.register(PirateRadioItems.FM_RECEIVER, Models.GENERATED) + modelGenderator.register(PirateRadioItems.STORAGE_CARD, Models.GENERATED) + modelGenderator.register(PirateRadioItems.DISPOSABLE_TRANSMITTER, Models.GENERATED) + } + +} + +class PirateRadioRecipeGenerator( + output: FabricDataOutput?, + registriesFuture: CompletableFuture<RegistryWrapper.WrapperLookup>? +) : FabricRecipeProvider(output, registriesFuture) { + override fun generate(exporter: RecipeExporter) { + ShapelessRecipeJsonBuilder.create(RecipeCategory.MISC, PirateRadioItems.DISPOSABLE_TRANSMITTER) + .input(PirateRadioItems.SBC).input(PirateRadioItems.WIRE).input(PirateRadioItems.POWERBANK) + .input(PirateRadioItems.STORAGE_CARD) + .criterion("has_sbc", RecipeProvider.conditionsFromItem(PirateRadioItems.SBC)).offerTo(exporter) + } + +} + +object PirateRadioDataGenerator : DataGeneratorEntrypoint { + override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) { + val pack = fabricDataGenerator.createPack() + + pack.addProvider(::PirateRadioItemModelGenerator) + pack.addProvider(::PirateRadioRecipeGenerator) + } +} \ No newline at end of file diff --git a/src/client/kotlin/space/autistic/radio/client/PirateRadioEntityModelLayers.kt b/src/client/kotlin/space/autistic/radio/client/PirateRadioEntityModelLayers.kt new file mode 100644 index 0000000..765912d --- /dev/null +++ b/src/client/kotlin/space/autistic/radio/client/PirateRadioEntityModelLayers.kt @@ -0,0 +1,18 @@ +package space.autistic.radio.client + +import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry +import net.minecraft.client.model.TexturedModelData +import net.minecraft.client.render.entity.model.EntityModelLayer +import net.minecraft.client.render.entity.model.VillagerResemblingModel +import net.minecraft.util.Identifier +import space.autistic.radio.PirateRadio + +object PirateRadioEntityModelLayers { + val ELECTRONICS_TRADER = EntityModelLayer(Identifier.of(PirateRadio.MOD_ID, "electronics-trader"), "main") + + fun initialize() { + EntityModelLayerRegistry.registerModelLayer(ELECTRONICS_TRADER) { + TexturedModelData.of(VillagerResemblingModel.getModelData(), 64, 64) + } + } +} \ No newline at end of file diff --git a/src/client/kotlin/space/autistic/radio/client/antenna/AntennaModel.kt b/src/client/kotlin/space/autistic/radio/client/antenna/AntennaModel.kt new file mode 100644 index 0000000..74a7c96 --- /dev/null +++ b/src/client/kotlin/space/autistic/radio/client/antenna/AntennaModel.kt @@ -0,0 +1,19 @@ +package space.autistic.radio.client.antenna + +import org.joml.Vector3d + +interface AntennaModel { + /** + * Returns the linear power level/gain to apply for a receiver at the given position. The receiver is assumed to be + * vertically oriented. + * + * Note: 1.0f = 0dB, 0.5f = -3dB (approx.), 0.1f = -10dB. + */ + fun apply(position: Vector3d): Float + + /** + * Returns whether to process block/material attenuation. Useful for "global" antennas (i.e. those that return a + * constant for all positions given to [apply]). + */ + fun shouldAttenuate(): Boolean +} \ No newline at end of file diff --git a/src/client/kotlin/space/autistic/radio/client/antenna/AntennaModelFactory.kt b/src/client/kotlin/space/autistic/radio/client/antenna/AntennaModelFactory.kt new file mode 100644 index 0000000..33a7087 --- /dev/null +++ b/src/client/kotlin/space/autistic/radio/client/antenna/AntennaModelFactory.kt @@ -0,0 +1,7 @@ +package space.autistic.radio.client.antenna + +import org.joml.Quaterniond + +interface AntennaModelFactory { + fun create(orientation: Quaterniond): AntennaModel +} \ No newline at end of file diff --git a/src/client/kotlin/space/autistic/radio/client/antenna/NullModel.kt b/src/client/kotlin/space/autistic/radio/client/antenna/NullModel.kt new file mode 100644 index 0000000..3c188b6 --- /dev/null +++ b/src/client/kotlin/space/autistic/radio/client/antenna/NullModel.kt @@ -0,0 +1,13 @@ +package space.autistic.radio.client.antenna + +import org.joml.Vector3d + +class NullModel : AntennaModel { + override fun apply(position: Vector3d): Float { + return 0f + } + + override fun shouldAttenuate(): Boolean { + return false + } +} diff --git a/src/client/kotlin/space/autistic/radio/client/antenna/WasmAntennaFactory.kt b/src/client/kotlin/space/autistic/radio/client/antenna/WasmAntennaFactory.kt new file mode 100644 index 0000000..7181e95 --- /dev/null +++ b/src/client/kotlin/space/autistic/radio/client/antenna/WasmAntennaFactory.kt @@ -0,0 +1,97 @@ +package space.autistic.radio.client.antenna + +import com.dylibso.chicory.experimental.aot.AotMachineFactory +import com.dylibso.chicory.runtime.ExportFunction +import com.dylibso.chicory.runtime.ImportValues +import com.dylibso.chicory.runtime.Instance +import com.dylibso.chicory.wasm.ChicoryException +import com.dylibso.chicory.wasm.InvalidException +import com.dylibso.chicory.wasm.Parser +import com.dylibso.chicory.wasm.types.MemoryLimits +import com.dylibso.chicory.wasm.types.Value +import com.dylibso.chicory.wasm.types.ValueType +import org.joml.Quaterniond +import org.joml.Vector3d +import space.autistic.radio.PirateRadio +import java.util.logging.Level +import java.util.logging.Logger + +class WasmAntennaFactory(moduleBytes: ByteArray) : AntennaModelFactory { + var failing = false + private val instanceBuilder = run { + try { + val module = Parser.parse(moduleBytes) + Instance.builder(module).withMachineFactory(AotMachineFactory(module)).withImportValues(defaultImports) + // capped at 1MB per antenna + .withMemoryLimits(MemoryLimits(0, 16)) + } catch (e: ChicoryException) { + logger.log(Level.SEVERE, "Error while trying to parse antenna model.", e) + failing = true + null + } + } + + override fun create(orientation: Quaterniond): AntennaModel { + if (failing) { + return NullModel() + } + try { + val instance = instanceBuilder!!.build() + // see basic module abi convention: https://github.com/WebAssembly/tool-conventions/blob/4487bbc2f5a0ad6b5ca76e233bdfa5ed4513dd8c/BasicModuleABI.md + var initialize: ExportFunction? = null + try { + initialize = instance.export("_initialize") + } catch (_: InvalidException) { + // export may not exist, it's fine + } + initialize?.apply() + // initialize antenna orientation + instance.export("set-orientation").apply( + orientation.x.toRawBits(), + orientation.y.toRawBits(), + orientation.z.toRawBits(), + orientation.w.toRawBits() + ) + if (instance.exports().global("should-attenuate").type != ValueType.I32) { + logger.log( + Level.SEVERE, "Error while trying to initialize antenna model: missing 'should-attenuate'" + ) + failing = true + return NullModel() + } + val shouldAttenuate = instance.exports().global("should-attenuate").value != 0L + val apply = instance.export("apply") + return object : AntennaModel { + override fun apply(position: Vector3d): Float { + if (failing) { + return 0f + } + try { + return Value.longToFloat( + apply.apply( + position.x.toRawBits(), position.y.toRawBits(), position.z.toRawBits() + )[0] + ) + } catch (e: ChicoryException) { + logger.log(Level.SEVERE, "Error while trying to evaluate antenna model.", e) + failing = true + return 0f + } + } + + override fun shouldAttenuate(): Boolean { + return shouldAttenuate + } + } + } catch (e: ChicoryException) { + logger.log(Level.SEVERE, "Error while trying to initialize antenna model.", e) + failing = true + return NullModel() + } + } + + companion object { + private val defaultImports = ImportValues.builder().build() + private val logger = Logger.getLogger(PirateRadio.MOD_ID) + } +} \ No newline at end of file diff --git a/src/client/kotlin/space/autistic/radio/client/entity/ElectronicsTraderEntityRenderer.kt b/src/client/kotlin/space/autistic/radio/client/entity/ElectronicsTraderEntityRenderer.kt new file mode 100644 index 0000000..91c29db --- /dev/null +++ b/src/client/kotlin/space/autistic/radio/client/entity/ElectronicsTraderEntityRenderer.kt @@ -0,0 +1,23 @@ +package space.autistic.radio.client.entity + +import net.minecraft.client.render.entity.EntityRendererFactory +import net.minecraft.client.render.entity.MobEntityRenderer +import net.minecraft.client.render.entity.model.VillagerResemblingModel +import net.minecraft.util.Identifier +import space.autistic.radio.PirateRadio +import space.autistic.radio.client.PirateRadioEntityModelLayers +import space.autistic.radio.entity.ElectronicsTraderEntity + +class ElectronicsTraderEntityRenderer(context: EntityRendererFactory.Context) : + MobEntityRenderer<ElectronicsTraderEntity, VillagerResemblingModel<ElectronicsTraderEntity>>( + context, + VillagerResemblingModel(context.getPart(PirateRadioEntityModelLayers.ELECTRONICS_TRADER)), + 0.5f + ) { + + companion object { + val TEXTURE = Identifier.of(PirateRadio.MOD_ID, "electronics-trader") + } + + override fun getTexture(entity: ElectronicsTraderEntity?): Identifier = TEXTURE +} \ No newline at end of file diff --git a/src/client/kotlin/space/autistic/radio/client/gui/FmReceiverScreen.kt b/src/client/kotlin/space/autistic/radio/client/gui/FmReceiverScreen.kt new file mode 100644 index 0000000..4bd4db2 --- /dev/null +++ b/src/client/kotlin/space/autistic/radio/client/gui/FmReceiverScreen.kt @@ -0,0 +1,11 @@ +package space.autistic.radio.client.gui + +import net.minecraft.client.gui.screen.Screen +import net.minecraft.text.Text + +class FmReceiverScreen : Screen(Text.translatable("pirate-radio.fm-receiver")) { + + override fun init() { + // TODO + } +} \ No newline at end of file |