Skip to content

Commit

Permalink
Add personal audio devices
Browse files Browse the repository at this point in the history
- Headset, with noise cancelling to block out other loudspeakers
- Portable radio which plays radio to the headset
- Portable record player which plays discs to the headset
  • Loading branch information
FoundationGames committed Aug 13, 2023
1 parent a7e57d1 commit df1c5de
Show file tree
Hide file tree
Showing 40 changed files with 1,069 additions and 23 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ loader_version=0.14.21
#Fabric api
fabric_version=0.84.0+1.20.1

mod_version = 1.0.0-beta.10
mod_version = 1.0.0-beta.11
maven_group = io.github.foundationgames
archives_base_name = phonos

Expand Down
19 changes: 19 additions & 0 deletions src/main/java/io/github/foundationgames/phonos/Phonos.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.github.foundationgames.phonos.network.PayloadPackets;
import io.github.foundationgames.phonos.radio.RadioDevice;
import io.github.foundationgames.phonos.radio.RadioStorage;
import io.github.foundationgames.phonos.recipe.ItemGlowRecipe;
import io.github.foundationgames.phonos.sound.SoundStorage;
import io.github.foundationgames.phonos.sound.custom.ServerCustomAudio;
import io.github.foundationgames.phonos.sound.emitter.SoundEmitter;
Expand All @@ -23,9 +24,16 @@
import net.fabricmc.fabric.api.gamerule.v1.GameRuleRegistry;
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.minecraft.block.DispenserBlock;
import net.minecraft.block.dispenser.FallibleItemDispenserBehavior;
import net.minecraft.item.ArmorItem;
import net.minecraft.item.ItemStack;
import net.minecraft.recipe.RecipeSerializer;
import net.minecraft.recipe.SpecialRecipeSerializer;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPointer;
import net.minecraft.world.GameRules;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand All @@ -43,6 +51,9 @@ public class Phonos implements ModInitializer {

public static final Identifier STREAMED_SOUND = Phonos.id("streamed");

public static final RecipeSerializer<ItemGlowRecipe> ITEM_GLOW_RECIPE_SERIALIZER = Registry.register(
Registries.RECIPE_SERIALIZER, Phonos.id("crafting_special_itemglow"), new SpecialRecipeSerializer<>(ItemGlowRecipe::new));

@Override
public void onInitialize() {
Registry.register(Registries.ITEM_GROUP, PHONOS_ITEMS.id, FabricItemGroup.builder()
Expand Down Expand Up @@ -100,6 +111,14 @@ public void onInitialize() {
}
});

DispenserBlock.registerBehavior(PhonosItems.HEADSET, new FallibleItemDispenserBehavior() {
@Override
protected ItemStack dispenseSilently(BlockPointer pointer, ItemStack stack) {
this.setSuccess(ArmorItem.dispenseArmor(pointer, stack));
return stack;
}
});

RadioStorage.init();
PhonosCommands.init();
}
Expand Down
40 changes: 38 additions & 2 deletions src/main/java/io/github/foundationgames/phonos/PhonosClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
import io.github.foundationgames.phonos.client.render.block.RadioTransceiverBlockEntityRenderer;
import io.github.foundationgames.phonos.client.render.block.SatelliteStationBlockEntityRenderer;
import io.github.foundationgames.phonos.config.PhonosClientConfig;
import io.github.foundationgames.phonos.item.AudioCableItem;
import io.github.foundationgames.phonos.item.PhonosItems;
import io.github.foundationgames.phonos.item.*;
import io.github.foundationgames.phonos.network.ClientPayloadPackets;
import io.github.foundationgames.phonos.radio.RadioDevice;
import io.github.foundationgames.phonos.radio.RadioStorage;
Expand All @@ -19,6 +18,7 @@
import io.github.foundationgames.phonos.sound.emitter.SoundEmitterStorage;
import io.github.foundationgames.phonos.sound.stream.ClientIncomingStreamHandler;
import io.github.foundationgames.phonos.util.PhonosUtil;
import io.github.foundationgames.phonos.world.sound.entity.HeadsetSoundSource;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents;
Expand All @@ -27,6 +27,7 @@
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.item.ModelPredicateProviderRegistry;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.block.entity.BlockEntityRendererFactories;
import net.minecraft.client.render.entity.model.EntityModelLayer;
Expand All @@ -35,6 +36,7 @@
public class PhonosClient implements ClientModInitializer {
public static final EntityModelLayer AUDIO_CABLE_END_LAYER = new EntityModelLayer(Phonos.id("audio_cable_end"), "main");
public static final EntityModelLayer SATELLITE_LAYER = new EntityModelLayer(Phonos.id("satellite"), "main");
public static final EntityModelLayer HEADSET_LAYER = new EntityModelLayer(Phonos.id("headset"), "main");

@Override
public void onInitializeClient() {
Expand All @@ -45,6 +47,7 @@ public void onInitializeClient() {

JsonEM.registerModelLayer(AUDIO_CABLE_END_LAYER);
JsonEM.registerModelLayer(SATELLITE_LAYER);
JsonEM.registerModelLayer(HEADSET_LAYER);

BlockRenderLayerMap.INSTANCE.putBlock(PhonosBlocks.ELECTRONIC_NOTE_BLOCK, RenderLayer.getCutout());
BlockRenderLayerMap.INSTANCE.putBlock(PhonosBlocks.RADIO_TRANSCEIVER, RenderLayer.getCutout());
Expand All @@ -70,6 +73,38 @@ public void onInitializeClient() {
return 0xFFFFFF;
}, PhonosItems.ALL_AUDIO_CABLES);

ColorProviderRegistry.ITEM.register((stack, tintIndex) -> {
if (tintIndex == 0 && stack.getItem() instanceof HeadsetItem item) {
if (item.hasColor(stack)) {
return item.isGlowing(stack) ? PhonosUtil.brighten(item.getColor(stack), 0.2f) : item.getColor(stack);
}

return item.isGlowing(stack) ? PhonosUtil.brighten(0x4F2E20, 0.2f) : 0x4F2E20;
}

return 0xFFFFFF;
}, PhonosItems.HEADSET);

ModelPredicateProviderRegistry.register(Phonos.id("glowing"), (stack, world, entity, seed) -> {
var item = stack.getItem();

if (item instanceof GlowableItem glow) {
return glow.isGlowing(stack) ? 1 : 0;
}

return 0;
});

ModelPredicateProviderRegistry.register(Phonos.id("has_record"), (stack, world, entity, seed) -> {
var item = stack.getItem();

if (item instanceof PortableRecordPlayerItem player) {
return player.hasRecord(stack) ? 1 : 0;
}

return 0;
});

ClientEntityEvents.ENTITY_LOAD.register((entity, world) -> {
if (entity == MinecraftClient.getInstance().player) {
RadioStorage.clientReset();
Expand All @@ -84,6 +119,7 @@ public void onInitializeClient() {
});

ClientTickEvents.END_WORLD_TICK.register(world -> SoundStorage.getInstance(world).tick(world));
ClientTickEvents.START_CLIENT_TICK.register(HeadsetSoundSource.INSTANCE::tick);

ClientBlockEntityEvents.BLOCK_ENTITY_LOAD.register((be, world) -> {
if (be instanceof SoundEmitter p) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import net.minecraft.client.util.math.MatrixStack;

public class BasicModel extends Model {
private final ModelPart root;
protected final ModelPart root;

public BasicModel(ModelPart root) {
super(RenderLayer::getEntitySolid);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package io.github.foundationgames.phonos.client.model;

import io.github.foundationgames.phonos.item.HeadsetItem;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.model.ModelTransform;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.item.ItemStack;

public class HeadsetModel extends BasicModel {
private final ModelPart main;
private final ModelPart innerTube;
private final ModelPart microphone;

public HeadsetModel(ModelPart root) {
super(root);

this.main = root.getChild("main");
this.innerTube = root.getChild("inner_tube");
this.microphone = root.getChild("microphone");
}

public void render(MatrixStack matrices, VertexConsumerProvider buffers, ModelTransform transform, int light, int overlay, ItemStack stack, HeadsetItem item) {
matrices.push();
this.root.setTransform(transform);
var texture = item.getTexture(stack);

this.microphone.visible = false; // Todo?
this.main.visible = true;
this.innerTube.visible = false;

var buffer = buffers.getBuffer(RenderLayer.getEntityCutoutNoCull(texture));
this.render(matrices, buffer, light, overlay, 1, 1, 1, 1);

this.main.visible = false;
// this.microphone.visible = false;
this.innerTube.visible = true;

int color = item.getColor(stack);
float r = ((color >> 16) & 0xFF) / 255f;
float g = ((color >> 8) & 0xFF) / 255f;
float b = (color & 0xFF) / 255f;

this.render(matrices, buffer, light, overlay, r, g, b, 1);

if (item.isGlowing(stack)) {
buffer = buffers.getBuffer(RenderLayer.getEyes(texture));

this.render(matrices, buffer, light, overlay, r, g, b, 1);
}

matrices.pop();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ private static void buildCableGeometry(CableConnection conn, MatrixStack matrice

loadCableEnd(cableStart);
loadCableEnd(cableEnd);

cableNormal[0].set(-PhonosUtil.SQRT2DIV2, -PhonosUtil.SQRT2DIV2, 0);
cableNormal[1].set(PhonosUtil.SQRT2DIV2, -PhonosUtil.SQRT2DIV2, 0);
cableNormal[2].set(PhonosUtil.SQRT2DIV2, PhonosUtil.SQRT2DIV2, 0);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.github.foundationgames.phonos.client.render.entity;

import io.github.foundationgames.phonos.PhonosClient;
import io.github.foundationgames.phonos.client.model.HeadsetModel;
import io.github.foundationgames.phonos.item.HeadsetItem;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.feature.FeatureRenderer;
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.model.EntityModelLoader;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;

public class HeadsetFeatureRenderer<E extends LivingEntity, M extends BipedEntityModel<E>> extends FeatureRenderer<E, M> {
private final HeadsetModel headsetModel;

public HeadsetFeatureRenderer(FeatureRendererContext<E, M> context, EntityModelLoader models) {
super(context);
this.headsetModel = new HeadsetModel(models.getModelPart(PhonosClient.HEADSET_LAYER));
}

@Override
public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, E entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
var headset = entity.getEquippedStack(EquipmentSlot.HEAD);
if (headset.getItem() instanceof HeadsetItem item) {
this.headsetModel.render(matrices, vertexConsumers, this.getContextModel().getHead().getTransform(), light, OverlayTexture.DEFAULT_UV, headset, item);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.github.foundationgames.phonos.item;

import net.minecraft.item.ItemStack;

public interface GlowableItem {
default void setGlowing(ItemStack stack, boolean glowing) {
stack.getOrCreateSubNbt("display").putBoolean("glowing", glowing);
}

default boolean isGlowing(ItemStack stack) {
var display = stack.getSubNbt("display");
return display != null && display.contains("glowing") && display.getBoolean("glowing");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package io.github.foundationgames.phonos.item;

import io.github.foundationgames.phonos.Phonos;
import net.minecraft.client.item.TooltipContext;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.StackReference;
import net.minecraft.item.DyeableItem;
import net.minecraft.item.Equipment;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.screen.slot.Slot;
import net.minecraft.text.Text;
import net.minecraft.util.*;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;

import java.util.List;

public class HeadsetItem extends Item implements DyeableItem, GlowableItem, Equipment {
public static final Text NOISE_CANCELLING = Text.translatable("tooltip.phonos.item.noise_cancelling").formatted(Formatting.YELLOW);
public static final Text GLOWING = Text.translatable("tooltip.phonos.item.glowing").formatted(Formatting.GRAY, Formatting.ITALIC);

public static final Identifier DEFAULT_TEXTURE = Phonos.id("textures/entity/headset.png");
public static final Identifier NOISE_CANCELLING_TEXTURE = Phonos.id("textures/entity/headset_noise_cancelling.png");

public HeadsetItem(Settings settings) {
super(settings);
}

@Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
return this.equipAndSwap(this, world, user, hand);
}

public boolean isNoiseCancelling(ItemStack stack) {
return stack.hasNbt() && stack.getNbt().getBoolean("noise_cancelling");
}

public void setNoiseCancelling(ItemStack stack, boolean noiseCancelling) {
stack.getOrCreateNbt().putBoolean("noise_cancelling", noiseCancelling);
}

@Override
public boolean onClicked(ItemStack stack, ItemStack otherStack, Slot slot, ClickType clickType, PlayerEntity player, StackReference cursorStackReference) {
if (clickType == ClickType.RIGHT && otherStack.isEmpty()) {
setNoiseCancelling(stack, !isNoiseCancelling(stack));

return true;
}

return super.onClicked(stack, otherStack, slot, clickType, player, cursorStackReference);
}

@Override
public EquipmentSlot getSlotType() {
return EquipmentSlot.HEAD;
}

@Override
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> tooltip, TooltipContext context) {
super.appendTooltip(stack, world, tooltip, context);

if (isNoiseCancelling(stack)) {
tooltip.add(NOISE_CANCELLING);
}

if (isGlowing(stack)) {
tooltip.add(GLOWING);
}
}

public Identifier getTexture(ItemStack stack) {
return isNoiseCancelling(stack) ? NOISE_CANCELLING_TEXTURE : DEFAULT_TEXTURE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public class PhonosItems {
public static final Item GREEN_AUDIO_CABLE = register(new AudioCableItem(DyeColor.GREEN, new Item.Settings()), "green_audio_cable");
public static final Item RED_AUDIO_CABLE = register(new AudioCableItem(DyeColor.RED, new Item.Settings()), "red_audio_cable");
public static final Item BLACK_AUDIO_CABLE = register(new AudioCableItem(DyeColor.BLACK, new Item.Settings()), "black_audio_cable");
public static final Item HEADSET = register(new HeadsetItem(new Item.Settings().maxCount(1)), "headset");
public static final Item PORTABLE_RADIO = register(new PortableRadioItem(new Item.Settings().maxCount(1)), "portable_radio");
public static final Item PORTABLE_RECORD_PLAYER = register(new PortableRecordPlayerItem(new Item.Settings().maxCount(1)), "portable_record_player");

public static final Item[] ALL_AUDIO_CABLES = new Item[] {WHITE_AUDIO_CABLE, ORANGE_AUDIO_CABLE, MAGENTA_AUDIO_CABLE,
LIGHT_BLUE_AUDIO_CABLE, YELLOW_AUDIO_CABLE, LIME_AUDIO_CABLE, PINK_AUDIO_CABLE, GRAY_AUDIO_CABLE,
Expand Down
Loading

0 comments on commit df1c5de

Please sign in to comment.