mirror of
				https://github.com/SquidDev-CC/CC-Tweaked
				synced 2025-10-31 21:52:59 +00:00 
			
		
		
		
	Track owning entity when sending sounds
This allows us to sync the position to the entity immediately, rather than the sound jumping about. Someone has set up rick-rolling pocket computers (<3 to whoever did this), and the lag on them irritates me enough to fix this. Fixes #1074
This commit is contained in:
		| @@ -6,11 +6,11 @@ | |||||||
| package dan200.computercraft.client.sound; | package dan200.computercraft.client.sound; | ||||||
| 
 | 
 | ||||||
| import dan200.computercraft.ComputerCraft; | import dan200.computercraft.ComputerCraft; | ||||||
|  | import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; | ||||||
| import io.netty.buffer.ByteBuf; | import io.netty.buffer.ByteBuf; | ||||||
| import net.minecraft.client.Minecraft; | import net.minecraft.client.Minecraft; | ||||||
| import net.minecraft.client.audio.SoundHandler; | import net.minecraft.client.audio.SoundHandler; | ||||||
| import net.minecraft.util.ResourceLocation; | import net.minecraft.util.ResourceLocation; | ||||||
| import net.minecraft.util.math.vector.Vector3d; |  | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * An instance of a speaker, which is either playing a {@link DfpwmStream} stream or a normal sound. |  * An instance of a speaker, which is either playing a {@link DfpwmStream} stream or a normal sound. | ||||||
| @@ -44,7 +44,7 @@ public class SpeakerInstance | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public void playAudio( Vector3d position, float volume ) |     public void playAudio( SpeakerPosition position, float volume ) | ||||||
|     { |     { | ||||||
|         SoundHandler soundManager = Minecraft.getInstance().getSoundManager(); |         SoundHandler soundManager = Minecraft.getInstance().getSoundManager(); | ||||||
| 
 | 
 | ||||||
| @@ -63,7 +63,7 @@ public class SpeakerInstance | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public void playSound( Vector3d position, ResourceLocation location, float volume, float pitch ) |     public void playSound( SpeakerPosition position, ResourceLocation location, float volume, float pitch ) | ||||||
|     { |     { | ||||||
|         SoundHandler soundManager = Minecraft.getInstance().getSoundManager(); |         SoundHandler soundManager = Minecraft.getInstance().getSoundManager(); | ||||||
|         currentStream = null; |         currentStream = null; | ||||||
| @@ -78,7 +78,7 @@ public class SpeakerInstance | |||||||
|         soundManager.play( sound ); |         soundManager.play( sound ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void setPosition( Vector3d position ) |     void setPosition( SpeakerPosition position ) | ||||||
|     { |     { | ||||||
|         if( sound != null ) sound.setPosition( position ); |         if( sound != null ) sound.setPosition( position ); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
|  */ |  */ | ||||||
| package dan200.computercraft.client.sound; | package dan200.computercraft.client.sound; | ||||||
| 
 | 
 | ||||||
| import net.minecraft.util.math.vector.Vector3d; | import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; | ||||||
| import net.minecraftforge.api.distmarker.Dist; | import net.minecraftforge.api.distmarker.Dist; | ||||||
| import net.minecraftforge.client.event.sound.PlayStreamingSourceEvent; | import net.minecraftforge.client.event.sound.PlayStreamingSourceEvent; | ||||||
| import net.minecraftforge.eventbus.api.SubscribeEvent; | import net.minecraftforge.eventbus.api.SubscribeEvent; | ||||||
| @@ -48,7 +48,7 @@ public class SpeakerManager | |||||||
|         if( sound != null ) sound.stop(); |         if( sound != null ) sound.stop(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static void moveSound( UUID source, Vector3d position ) |     public static void moveSound( UUID source, SpeakerPosition position ) | ||||||
|     { |     { | ||||||
|         SpeakerInstance sound = sounds.get( source ); |         SpeakerInstance sound = sounds.get( source ); | ||||||
|         if( sound != null ) sound.setPosition( position ); |         if( sound != null ) sound.setPosition( position ); | ||||||
|   | |||||||
| @@ -5,13 +5,14 @@ | |||||||
|  */ |  */ | ||||||
| package dan200.computercraft.client.sound; | package dan200.computercraft.client.sound; | ||||||
| 
 | 
 | ||||||
|  | import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; | ||||||
| import net.minecraft.client.audio.IAudioStream; | import net.minecraft.client.audio.IAudioStream; | ||||||
| import net.minecraft.client.audio.ITickableSound; | import net.minecraft.client.audio.ITickableSound; | ||||||
| import net.minecraft.client.audio.LocatableSound; | import net.minecraft.client.audio.LocatableSound; | ||||||
| import net.minecraft.client.audio.SoundSource; | import net.minecraft.client.audio.SoundSource; | ||||||
|  | import net.minecraft.entity.Entity; | ||||||
| import net.minecraft.util.ResourceLocation; | import net.minecraft.util.ResourceLocation; | ||||||
| import net.minecraft.util.SoundCategory; | import net.minecraft.util.SoundCategory; | ||||||
| import net.minecraft.util.math.vector.Vector3d; |  | ||||||
| 
 | 
 | ||||||
| import javax.annotation.Nullable; | import javax.annotation.Nullable; | ||||||
| import java.util.concurrent.Executor; | import java.util.concurrent.Executor; | ||||||
| @@ -22,7 +23,11 @@ public class SpeakerSound extends LocatableSound implements ITickableSound | |||||||
|     Executor executor; |     Executor executor; | ||||||
|     DfpwmStream stream; |     DfpwmStream stream; | ||||||
| 
 | 
 | ||||||
|     SpeakerSound( ResourceLocation sound, DfpwmStream stream, Vector3d position, float volume, float pitch ) |     private Entity entity; | ||||||
|  | 
 | ||||||
|  |     private boolean stopped = false; | ||||||
|  | 
 | ||||||
|  |     SpeakerSound( ResourceLocation sound, DfpwmStream stream, SpeakerPosition position, float volume, float pitch ) | ||||||
|     { |     { | ||||||
|         super( sound, SoundCategory.RECORDS ); |         super( sound, SoundCategory.RECORDS ); | ||||||
|         setPosition( position ); |         setPosition( position ); | ||||||
| @@ -32,22 +37,35 @@ public class SpeakerSound extends LocatableSound implements ITickableSound | |||||||
|         attenuation = AttenuationType.LINEAR; |         attenuation = AttenuationType.LINEAR; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void setPosition( Vector3d position ) |     void setPosition( SpeakerPosition position ) | ||||||
|     { |     { | ||||||
|         x = (float) position.x(); |         x = position.position().x; | ||||||
|         y = (float) position.y(); |         y = position.position().y; | ||||||
|         z = (float) position.z(); |         z = position.position().z; | ||||||
|  |         entity = position.entity(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public boolean isStopped() |     public boolean isStopped() | ||||||
|     { |     { | ||||||
|         return false; |         return stopped; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void tick() |     public void tick() | ||||||
|     { |     { | ||||||
|  |         if( entity == null ) return; | ||||||
|  |         if( !entity.isAlive() ) | ||||||
|  |         { | ||||||
|  |             stopped = true; | ||||||
|  |             looping = false; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             x = entity.getX(); | ||||||
|  |             y = entity.getY(); | ||||||
|  |             z = entity.getZ(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Nullable |     @Nullable | ||||||
|   | |||||||
| @@ -7,8 +7,8 @@ package dan200.computercraft.shared.network.client; | |||||||
| 
 | 
 | ||||||
| import dan200.computercraft.client.sound.SpeakerManager; | import dan200.computercraft.client.sound.SpeakerManager; | ||||||
| import dan200.computercraft.shared.network.NetworkMessage; | import dan200.computercraft.shared.network.NetworkMessage; | ||||||
|  | import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; | ||||||
| import net.minecraft.network.PacketBuffer; | import net.minecraft.network.PacketBuffer; | ||||||
| import net.minecraft.util.math.vector.Vector3d; |  | ||||||
| import net.minecraftforge.api.distmarker.Dist; | import net.minecraftforge.api.distmarker.Dist; | ||||||
| import net.minecraftforge.api.distmarker.OnlyIn; | import net.minecraftforge.api.distmarker.OnlyIn; | ||||||
| import net.minecraftforge.fml.network.NetworkEvent; | import net.minecraftforge.fml.network.NetworkEvent; | ||||||
| @@ -27,14 +27,14 @@ import java.util.UUID; | |||||||
| public class SpeakerAudioClientMessage implements NetworkMessage | public class SpeakerAudioClientMessage implements NetworkMessage | ||||||
| { | { | ||||||
|     private final UUID source; |     private final UUID source; | ||||||
|     private final Vector3d pos; |     private final SpeakerPosition.Message pos; | ||||||
|     private final ByteBuffer content; |     private final ByteBuffer content; | ||||||
|     private final float volume; |     private final float volume; | ||||||
| 
 | 
 | ||||||
|     public SpeakerAudioClientMessage( UUID source, Vector3d pos, float volume, ByteBuffer content ) |     public SpeakerAudioClientMessage( UUID source, SpeakerPosition pos, float volume, ByteBuffer content ) | ||||||
|     { |     { | ||||||
|         this.source = source; |         this.source = source; | ||||||
|         this.pos = pos; |         this.pos = pos.asMessage(); | ||||||
|         this.content = content; |         this.content = content; | ||||||
|         this.volume = volume; |         this.volume = volume; | ||||||
|     } |     } | ||||||
| @@ -42,7 +42,7 @@ public class SpeakerAudioClientMessage implements NetworkMessage | |||||||
|     public SpeakerAudioClientMessage( PacketBuffer buf ) |     public SpeakerAudioClientMessage( PacketBuffer buf ) | ||||||
|     { |     { | ||||||
|         source = buf.readUUID(); |         source = buf.readUUID(); | ||||||
|         pos = new Vector3d( buf.readDouble(), buf.readDouble(), buf.readDouble() ); |         pos = SpeakerPosition.Message.read( buf ); | ||||||
|         volume = buf.readFloat(); |         volume = buf.readFloat(); | ||||||
| 
 | 
 | ||||||
|         SpeakerManager.getSound( source ).pushAudio( buf ); |         SpeakerManager.getSound( source ).pushAudio( buf ); | ||||||
| @@ -53,9 +53,7 @@ public class SpeakerAudioClientMessage implements NetworkMessage | |||||||
|     public void toBytes( @Nonnull PacketBuffer buf ) |     public void toBytes( @Nonnull PacketBuffer buf ) | ||||||
|     { |     { | ||||||
|         buf.writeUUID( source ); |         buf.writeUUID( source ); | ||||||
|         buf.writeDouble( pos.x() ); |         pos.write( buf ); | ||||||
|         buf.writeDouble( pos.y() ); |  | ||||||
|         buf.writeDouble( pos.z() ); |  | ||||||
|         buf.writeFloat( volume ); |         buf.writeFloat( volume ); | ||||||
|         buf.writeBytes( content.duplicate() ); |         buf.writeBytes( content.duplicate() ); | ||||||
|     } |     } | ||||||
| @@ -64,6 +62,6 @@ public class SpeakerAudioClientMessage implements NetworkMessage | |||||||
|     @OnlyIn( Dist.CLIENT ) |     @OnlyIn( Dist.CLIENT ) | ||||||
|     public void handle( NetworkEvent.Context context ) |     public void handle( NetworkEvent.Context context ) | ||||||
|     { |     { | ||||||
|         SpeakerManager.getSound( source ).playAudio( pos, volume ); |         SpeakerManager.getSound( source ).playAudio( pos.reify(), volume ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,8 +7,8 @@ package dan200.computercraft.shared.network.client; | |||||||
| 
 | 
 | ||||||
| import dan200.computercraft.client.sound.SpeakerManager; | import dan200.computercraft.client.sound.SpeakerManager; | ||||||
| import dan200.computercraft.shared.network.NetworkMessage; | import dan200.computercraft.shared.network.NetworkMessage; | ||||||
|  | import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; | ||||||
| import net.minecraft.network.PacketBuffer; | import net.minecraft.network.PacketBuffer; | ||||||
| import net.minecraft.util.math.vector.Vector3d; |  | ||||||
| import net.minecraftforge.api.distmarker.Dist; | import net.minecraftforge.api.distmarker.Dist; | ||||||
| import net.minecraftforge.api.distmarker.OnlyIn; | import net.minecraftforge.api.distmarker.OnlyIn; | ||||||
| import net.minecraftforge.fml.network.NetworkEvent; | import net.minecraftforge.fml.network.NetworkEvent; | ||||||
| @@ -26,33 +26,31 @@ import java.util.UUID; | |||||||
| public class SpeakerMoveClientMessage implements NetworkMessage | public class SpeakerMoveClientMessage implements NetworkMessage | ||||||
| { | { | ||||||
|     private final UUID source; |     private final UUID source; | ||||||
|     private final Vector3d pos; |     private final SpeakerPosition.Message pos; | ||||||
| 
 | 
 | ||||||
|     public SpeakerMoveClientMessage( UUID source, Vector3d pos ) |     public SpeakerMoveClientMessage( UUID source, SpeakerPosition pos ) | ||||||
|     { |     { | ||||||
|         this.source = source; |         this.source = source; | ||||||
|         this.pos = pos; |         this.pos = pos.asMessage(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public SpeakerMoveClientMessage( PacketBuffer buf ) |     public SpeakerMoveClientMessage( PacketBuffer buf ) | ||||||
|     { |     { | ||||||
|         source = buf.readUUID(); |         source = buf.readUUID(); | ||||||
|         pos = new Vector3d( buf.readDouble(), buf.readDouble(), buf.readDouble() ); |         pos = SpeakerPosition.Message.read( buf ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void toBytes( @Nonnull PacketBuffer buf ) |     public void toBytes( @Nonnull PacketBuffer buf ) | ||||||
|     { |     { | ||||||
|         buf.writeUUID( source ); |         buf.writeUUID( source ); | ||||||
|         buf.writeDouble( pos.x() ); |         pos.write( buf ); | ||||||
|         buf.writeDouble( pos.y() ); |  | ||||||
|         buf.writeDouble( pos.z() ); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     @OnlyIn( Dist.CLIENT ) |     @OnlyIn( Dist.CLIENT ) | ||||||
|     public void handle( NetworkEvent.Context context ) |     public void handle( NetworkEvent.Context context ) | ||||||
|     { |     { | ||||||
|         SpeakerManager.moveSound( source, pos ); |         SpeakerManager.moveSound( source, pos.reify() ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,9 +7,9 @@ package dan200.computercraft.shared.network.client; | |||||||
| 
 | 
 | ||||||
| import dan200.computercraft.client.sound.SpeakerManager; | import dan200.computercraft.client.sound.SpeakerManager; | ||||||
| import dan200.computercraft.shared.network.NetworkMessage; | import dan200.computercraft.shared.network.NetworkMessage; | ||||||
|  | import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; | ||||||
| import net.minecraft.network.PacketBuffer; | import net.minecraft.network.PacketBuffer; | ||||||
| import net.minecraft.util.ResourceLocation; | import net.minecraft.util.ResourceLocation; | ||||||
| import net.minecraft.util.math.vector.Vector3d; |  | ||||||
| import net.minecraftforge.api.distmarker.Dist; | import net.minecraftforge.api.distmarker.Dist; | ||||||
| import net.minecraftforge.api.distmarker.OnlyIn; | import net.minecraftforge.api.distmarker.OnlyIn; | ||||||
| import net.minecraftforge.fml.network.NetworkEvent; | import net.minecraftforge.fml.network.NetworkEvent; | ||||||
| @@ -27,15 +27,15 @@ import java.util.UUID; | |||||||
| public class SpeakerPlayClientMessage implements NetworkMessage | public class SpeakerPlayClientMessage implements NetworkMessage | ||||||
| { | { | ||||||
|     private final UUID source; |     private final UUID source; | ||||||
|     private final Vector3d pos; |     private final SpeakerPosition.Message pos; | ||||||
|     private final ResourceLocation sound; |     private final ResourceLocation sound; | ||||||
|     private final float volume; |     private final float volume; | ||||||
|     private final float pitch; |     private final float pitch; | ||||||
| 
 | 
 | ||||||
|     public SpeakerPlayClientMessage( UUID source, Vector3d pos, ResourceLocation event, float volume, float pitch ) |     public SpeakerPlayClientMessage( UUID source, SpeakerPosition pos, ResourceLocation event, float volume, float pitch ) | ||||||
|     { |     { | ||||||
|         this.source = source; |         this.source = source; | ||||||
|         this.pos = pos; |         this.pos = pos.asMessage(); | ||||||
|         sound = event; |         sound = event; | ||||||
|         this.volume = volume; |         this.volume = volume; | ||||||
|         this.pitch = pitch; |         this.pitch = pitch; | ||||||
| @@ -44,7 +44,7 @@ public class SpeakerPlayClientMessage implements NetworkMessage | |||||||
|     public SpeakerPlayClientMessage( PacketBuffer buf ) |     public SpeakerPlayClientMessage( PacketBuffer buf ) | ||||||
|     { |     { | ||||||
|         source = buf.readUUID(); |         source = buf.readUUID(); | ||||||
|         pos = new Vector3d( buf.readDouble(), buf.readDouble(), buf.readDouble() ); |         pos = SpeakerPosition.Message.read( buf ); | ||||||
|         sound = buf.readResourceLocation(); |         sound = buf.readResourceLocation(); | ||||||
|         volume = buf.readFloat(); |         volume = buf.readFloat(); | ||||||
|         pitch = buf.readFloat(); |         pitch = buf.readFloat(); | ||||||
| @@ -54,9 +54,7 @@ public class SpeakerPlayClientMessage implements NetworkMessage | |||||||
|     public void toBytes( @Nonnull PacketBuffer buf ) |     public void toBytes( @Nonnull PacketBuffer buf ) | ||||||
|     { |     { | ||||||
|         buf.writeUUID( source ); |         buf.writeUUID( source ); | ||||||
|         buf.writeDouble( pos.x() ); |         pos.write( buf ); | ||||||
|         buf.writeDouble( pos.y() ); |  | ||||||
|         buf.writeDouble( pos.z() ); |  | ||||||
|         buf.writeResourceLocation( sound ); |         buf.writeResourceLocation( sound ); | ||||||
|         buf.writeFloat( volume ); |         buf.writeFloat( volume ); | ||||||
|         buf.writeFloat( pitch ); |         buf.writeFloat( pitch ); | ||||||
| @@ -66,6 +64,6 @@ public class SpeakerPlayClientMessage implements NetworkMessage | |||||||
|     @OnlyIn( Dist.CLIENT ) |     @OnlyIn( Dist.CLIENT ) | ||||||
|     public void handle( NetworkEvent.Context context ) |     public void handle( NetworkEvent.Context context ) | ||||||
|     { |     { | ||||||
|         SpeakerManager.getSound( source ).playSound( pos, sound, volume, pitch ); |         SpeakerManager.getSound( source ).playSound( pos.reify(), sound, volume, pitch ); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -29,7 +29,6 @@ import net.minecraft.util.math.vector.Vector3d; | |||||||
| import net.minecraft.world.World; | import net.minecraft.world.World; | ||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| import javax.annotation.Nullable; |  | ||||||
| import java.util.*; | import java.util.*; | ||||||
| 
 | 
 | ||||||
| import static dan200.computercraft.api.lua.LuaValues.checkFinite; | import static dan200.computercraft.api.lua.LuaValues.checkFinite; | ||||||
| @@ -57,7 +56,7 @@ public abstract class SpeakerPeripheral implements IPeripheral | |||||||
| 
 | 
 | ||||||
|     private long clock = 0; |     private long clock = 0; | ||||||
|     private long lastPositionTime; |     private long lastPositionTime; | ||||||
|     private Vector3d lastPosition; |     private SpeakerPosition lastPosition; | ||||||
| 
 | 
 | ||||||
|     private long lastPlayTime; |     private long lastPlayTime; | ||||||
| 
 | 
 | ||||||
| @@ -72,10 +71,11 @@ public abstract class SpeakerPeripheral implements IPeripheral | |||||||
|     { |     { | ||||||
|         clock++; |         clock++; | ||||||
| 
 | 
 | ||||||
|         Vector3d pos = getPosition(); |         SpeakerPosition position = getPosition(); | ||||||
|         World world = getWorld(); |         World level = position.level(); | ||||||
|         if( world == null ) return; |         Vector3d pos = position.position(); | ||||||
|         MinecraftServer server = world.getServer(); |         if( level == null ) return; | ||||||
|  |         MinecraftServer server = level.getServer(); | ||||||
| 
 | 
 | ||||||
|         synchronized( pendingNotes ) |         synchronized( pendingNotes ) | ||||||
|         { |         { | ||||||
| @@ -83,7 +83,7 @@ public abstract class SpeakerPeripheral implements IPeripheral | |||||||
|             { |             { | ||||||
|                 lastPlayTime = clock; |                 lastPlayTime = clock; | ||||||
|                 server.getPlayerList().broadcast( |                 server.getPlayerList().broadcast( | ||||||
|                     null, pos.x, pos.y, pos.z, sound.volume * 16, world.dimension(), |                     null, pos.x, pos.y, pos.z, sound.volume * 16, level.dimension(), | ||||||
|                     new SPlaySoundPacket( sound.location, SoundCategory.RECORDS, pos, sound.volume, sound.pitch ) |                     new SPlaySoundPacket( sound.location, SoundCategory.RECORDS, pos, sound.volume, sound.pitch ) | ||||||
|                 ); |                 ); | ||||||
|             } |             } | ||||||
| @@ -125,20 +125,20 @@ public abstract class SpeakerPeripheral implements IPeripheral | |||||||
|         { |         { | ||||||
|             lastPlayTime = clock; |             lastPlayTime = clock; | ||||||
|             NetworkHandler.sendToAllAround( |             NetworkHandler.sendToAllAround( | ||||||
|                 new SpeakerPlayClientMessage( getSource(), pos, sound.location, sound.volume, sound.pitch ), |                 new SpeakerPlayClientMessage( getSource(), position, sound.location, sound.volume, sound.pitch ), | ||||||
|                 world, pos, sound.volume * 16 |                 level, pos, sound.volume * 16 | ||||||
|             ); |             ); | ||||||
|             syncedPosition( pos ); |             syncedPosition( position ); | ||||||
|         } |         } | ||||||
|         else if( dfpwmState != null && dfpwmState.shouldSendPending( now ) ) |         else if( dfpwmState != null && dfpwmState.shouldSendPending( now ) ) | ||||||
|         { |         { | ||||||
|             // If clients need to receive another batch of audio, send it and then notify computers our internal buffer is |             // If clients need to receive another batch of audio, send it and then notify computers our internal buffer is | ||||||
|             // free again. |             // free again. | ||||||
|             NetworkHandler.sendToAllTracking( |             NetworkHandler.sendToAllTracking( | ||||||
|                 new SpeakerAudioClientMessage( getSource(), pos, dfpwmState.getVolume(), dfpwmState.pullPending( now ) ), |                 new SpeakerAudioClientMessage( getSource(), position, dfpwmState.getVolume(), dfpwmState.pullPending( now ) ), | ||||||
|                 getWorld().getChunkAt( new BlockPos( pos ) ) |                 level.getChunkAt( new BlockPos( pos ) ) | ||||||
|             ); |             ); | ||||||
|             syncedPosition( pos ); |             syncedPosition( position ); | ||||||
| 
 | 
 | ||||||
|             // And notify computers that we have space for more audio. |             // And notify computers that we have space for more audio. | ||||||
|             synchronized( computers ) |             synchronized( computers ) | ||||||
| @@ -153,25 +153,19 @@ public abstract class SpeakerPeripheral implements IPeripheral | |||||||
|         // Push position updates to any speakers which have ever played a note, |         // Push position updates to any speakers which have ever played a note, | ||||||
|         // have moved by a non-trivial amount and haven't had a position update |         // have moved by a non-trivial amount and haven't had a position update | ||||||
|         // in the last second. |         // in the last second. | ||||||
|         if( lastPosition != null && (clock - lastPositionTime) >= 20 ) |         if( lastPosition != null && (clock - lastPositionTime) >= 20 && !lastPosition.withinDistance( position, 0.1 ) ) | ||||||
|         { |         { | ||||||
|             Vector3d position = getPosition(); |             // TODO: What to do when entities move away? How do we notify people left behind that they're gone. | ||||||
|             if( lastPosition.distanceToSqr( position ) >= 0.1 ) |             NetworkHandler.sendToAllTracking( | ||||||
|             { |                 new SpeakerMoveClientMessage( getSource(), position ), | ||||||
|                 NetworkHandler.sendToAllTracking( |                 level.getChunkAt( new BlockPos( pos ) ) | ||||||
|                     new SpeakerMoveClientMessage( getSource(), position ), |             ); | ||||||
|                     getWorld().getChunkAt( new BlockPos( position ) ) |             syncedPosition( position ); | ||||||
|                 ); |  | ||||||
|                 syncedPosition( position ); |  | ||||||
|             } |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Nullable |  | ||||||
|     public abstract World getWorld(); |  | ||||||
| 
 |  | ||||||
|     @Nonnull |     @Nonnull | ||||||
|     public abstract Vector3d getPosition(); |     public abstract SpeakerPosition getPosition(); | ||||||
| 
 | 
 | ||||||
|     @Nonnull |     @Nonnull | ||||||
|     public UUID getSource() |     public UUID getSource() | ||||||
| @@ -373,7 +367,7 @@ public abstract class SpeakerPeripheral implements IPeripheral | |||||||
|         shouldStop = true; |         shouldStop = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void syncedPosition( Vector3d position ) |     private void syncedPosition( SpeakerPosition position ) | ||||||
|     { |     { | ||||||
|         lastPosition = position; |         lastPosition = position; | ||||||
|         lastPositionTime = clock; |         lastPositionTime = clock; | ||||||
|   | |||||||
| @@ -0,0 +1,117 @@ | |||||||
|  | /* | ||||||
|  |  * This file is part of ComputerCraft - http://www.computercraft.info | ||||||
|  |  * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. | ||||||
|  |  * Send enquiries to dratcliffe@gmail.com | ||||||
|  |  */ | ||||||
|  | package dan200.computercraft.shared.peripheral.speaker; | ||||||
|  | 
 | ||||||
|  | import net.minecraft.client.Minecraft; | ||||||
|  | import net.minecraft.entity.Entity; | ||||||
|  | import net.minecraft.network.PacketBuffer; | ||||||
|  | import net.minecraft.util.ResourceLocation; | ||||||
|  | import net.minecraft.util.math.vector.Vector3d; | ||||||
|  | import net.minecraft.world.World; | ||||||
|  | 
 | ||||||
|  | import javax.annotation.Nonnull; | ||||||
|  | import javax.annotation.Nullable; | ||||||
|  | import java.util.OptionalInt; | ||||||
|  | 
 | ||||||
|  | public final class SpeakerPosition | ||||||
|  | { | ||||||
|  |     private final World level; | ||||||
|  |     private final Vector3d position; | ||||||
|  |     private final Entity entity; | ||||||
|  | 
 | ||||||
|  |     private SpeakerPosition( @Nullable World level, @Nonnull Vector3d position, @Nullable Entity entity ) | ||||||
|  |     { | ||||||
|  |         this.level = level; | ||||||
|  |         this.position = position; | ||||||
|  |         this.entity = entity; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static SpeakerPosition of( @Nullable World level, @Nonnull Vector3d position ) | ||||||
|  |     { | ||||||
|  |         return new SpeakerPosition( level, position, null ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static SpeakerPosition of( @Nonnull Entity entity ) | ||||||
|  |     { | ||||||
|  |         return new SpeakerPosition( entity.level, entity.getEyePosition( 1 ), entity ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Nullable | ||||||
|  |     public World level() | ||||||
|  |     { | ||||||
|  |         return level; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Nonnull | ||||||
|  |     public Vector3d position() | ||||||
|  |     { | ||||||
|  |         return position; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Nullable | ||||||
|  |     public Entity entity() | ||||||
|  |     { | ||||||
|  |         return entity; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public boolean withinDistance( SpeakerPosition other, double distanceSq ) | ||||||
|  |     { | ||||||
|  |         return level == other.level && entity == other.entity && position.distanceToSqr( other.position ) <= distanceSq; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Message asMessage() | ||||||
|  |     { | ||||||
|  |         if( level == null ) throw new NullPointerException( "Cannot send a position without a level" ); | ||||||
|  |         return new Message( level.dimension().getRegistryName(), position, entity == null ? OptionalInt.empty() : OptionalInt.of( entity.getId() ) ); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public static final class Message | ||||||
|  |     { | ||||||
|  |         private final ResourceLocation level; | ||||||
|  |         private final Vector3d position; | ||||||
|  |         private final OptionalInt entity; | ||||||
|  | 
 | ||||||
|  |         private Message( ResourceLocation level, Vector3d position, OptionalInt entity ) | ||||||
|  |         { | ||||||
|  |             this.level = level; | ||||||
|  |             this.position = position; | ||||||
|  |             this.entity = entity; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public static Message read( @Nonnull PacketBuffer buffer ) | ||||||
|  |         { | ||||||
|  |             ResourceLocation level = buffer.readResourceLocation(); | ||||||
|  |             Vector3d position = new Vector3d( buffer.readDouble(), buffer.readDouble(), buffer.readDouble() ); | ||||||
|  |             OptionalInt entity = buffer.readBoolean() ? OptionalInt.of( buffer.readInt() ) : OptionalInt.empty(); | ||||||
|  |             return new Message( level, position, entity ); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void write( @Nonnull PacketBuffer buffer ) | ||||||
|  |         { | ||||||
|  |             buffer.writeResourceLocation( level ); | ||||||
|  | 
 | ||||||
|  |             buffer.writeDouble( position.x ); | ||||||
|  |             buffer.writeDouble( position.y ); | ||||||
|  |             buffer.writeDouble( position.z ); | ||||||
|  | 
 | ||||||
|  |             buffer.writeBoolean( entity.isPresent() ); | ||||||
|  |             if( entity.isPresent() ) buffer.writeInt( entity.getAsInt() ); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         @Nonnull | ||||||
|  |         public SpeakerPosition reify() | ||||||
|  |         { | ||||||
|  |             Minecraft minecraft = Minecraft.getInstance(); | ||||||
|  |             World level = minecraft.level; | ||||||
|  |             if( level != null && !level.dimension().getRegistryName().equals( this.level ) ) level = null; | ||||||
|  | 
 | ||||||
|  |             return new SpeakerPosition( | ||||||
|  |                 level, position, | ||||||
|  |                 level != null && entity.isPresent() ? level.getEntity( entity.getAsInt() ) : null | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -14,7 +14,6 @@ import net.minecraft.tileentity.ITickableTileEntity; | |||||||
| import net.minecraft.tileentity.TileEntityType; | import net.minecraft.tileentity.TileEntityType; | ||||||
| import net.minecraft.util.Direction; | import net.minecraft.util.Direction; | ||||||
| import net.minecraft.util.math.vector.Vector3d; | import net.minecraft.util.math.vector.Vector3d; | ||||||
| import net.minecraft.world.World; |  | ||||||
| import net.minecraftforge.common.capabilities.Capability; | import net.minecraftforge.common.capabilities.Capability; | ||||||
| import net.minecraftforge.common.util.LazyOptional; | import net.minecraftforge.common.util.LazyOptional; | ||||||
| 
 | 
 | ||||||
| @@ -79,17 +78,11 @@ public class TileSpeaker extends TileGeneric implements ITickableTileEntity | |||||||
|             this.speaker = speaker; |             this.speaker = speaker; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         @Override |  | ||||||
|         public World getWorld() |  | ||||||
|         { |  | ||||||
|             return speaker.getLevel(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         @Nonnull |         @Nonnull | ||||||
|         @Override |         @Override | ||||||
|         public Vector3d getPosition() |         public SpeakerPosition getPosition() | ||||||
|         { |         { | ||||||
|             return Vector3d.atCenterOf( speaker.getBlockPos() ); |             return SpeakerPosition.of( speaker.getLevel(), Vector3d.atCenterOf( speaker.getBlockPos() ) ); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         @Override |         @Override | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ import dan200.computercraft.shared.network.NetworkHandler; | |||||||
| import dan200.computercraft.shared.pocket.items.ItemPocketComputer; | import dan200.computercraft.shared.pocket.items.ItemPocketComputer; | ||||||
| import net.minecraft.entity.Entity; | import net.minecraft.entity.Entity; | ||||||
| import net.minecraft.entity.LivingEntity; | import net.minecraft.entity.LivingEntity; | ||||||
|  | import net.minecraft.entity.item.ItemEntity; | ||||||
| import net.minecraft.entity.player.PlayerEntity; | import net.minecraft.entity.player.PlayerEntity; | ||||||
| import net.minecraft.entity.player.PlayerInventory; | import net.minecraft.entity.player.PlayerInventory; | ||||||
| import net.minecraft.entity.player.ServerPlayerEntity; | import net.minecraft.entity.player.ServerPlayerEntity; | ||||||
| @@ -61,6 +62,11 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces | |||||||
|             LivingEntity living = (LivingEntity) entity; |             LivingEntity living = (LivingEntity) entity; | ||||||
|             return living.getMainHandItem() == stack || living.getOffhandItem() == stack ? entity : null; |             return living.getMainHandItem() == stack || living.getOffhandItem() == stack ? entity : null; | ||||||
|         } |         } | ||||||
|  |         else if( entity instanceof ItemEntity ) | ||||||
|  |         { | ||||||
|  |             ItemEntity itemEntity = (ItemEntity) entity; | ||||||
|  |             return itemEntity.getItem() == stack ? entity : null; | ||||||
|  |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             return null; |             return null; | ||||||
|   | |||||||
| @@ -9,7 +9,6 @@ import dan200.computercraft.api.peripheral.IPeripheral; | |||||||
| import dan200.computercraft.api.pocket.AbstractPocketUpgrade; | import dan200.computercraft.api.pocket.AbstractPocketUpgrade; | ||||||
| import dan200.computercraft.api.pocket.IPocketAccess; | import dan200.computercraft.api.pocket.IPocketAccess; | ||||||
| import dan200.computercraft.shared.Registry; | import dan200.computercraft.shared.Registry; | ||||||
| import net.minecraft.entity.Entity; |  | ||||||
| import net.minecraft.util.ResourceLocation; | import net.minecraft.util.ResourceLocation; | ||||||
| 
 | 
 | ||||||
| import javax.annotation.Nonnull; | import javax.annotation.Nonnull; | ||||||
| @@ -26,23 +25,13 @@ public class PocketSpeaker extends AbstractPocketUpgrade | |||||||
|     @Override |     @Override | ||||||
|     public IPeripheral createPeripheral( @Nonnull IPocketAccess access ) |     public IPeripheral createPeripheral( @Nonnull IPocketAccess access ) | ||||||
|     { |     { | ||||||
|         return new PocketSpeakerPeripheral(); |         return new PocketSpeakerPeripheral( access ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void update( @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral ) |     public void update( @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral ) | ||||||
|     { |     { | ||||||
|         if( !(peripheral instanceof PocketSpeakerPeripheral) ) return; |         if( !(peripheral instanceof PocketSpeakerPeripheral) ) return; | ||||||
| 
 |         ((PocketSpeakerPeripheral) peripheral).update(); | ||||||
|         PocketSpeakerPeripheral speaker = (PocketSpeakerPeripheral) peripheral; |  | ||||||
| 
 |  | ||||||
|         Entity entity = access.getEntity(); |  | ||||||
|         if( entity != null ) |  | ||||||
|         { |  | ||||||
|             speaker.setLocation( entity.getCommandSenderWorld(), entity.getEyePosition( 1 ) ); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         speaker.update(); |  | ||||||
|         access.setLight( speaker.madeSound() ? 0x3320fc : -1 ); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -6,7 +6,10 @@ | |||||||
| package dan200.computercraft.shared.pocket.peripherals; | package dan200.computercraft.shared.pocket.peripherals; | ||||||
| 
 | 
 | ||||||
| import dan200.computercraft.api.peripheral.IPeripheral; | import dan200.computercraft.api.peripheral.IPeripheral; | ||||||
|  | import dan200.computercraft.api.pocket.IPocketAccess; | ||||||
|  | import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; | ||||||
| import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral; | import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral; | ||||||
|  | import net.minecraft.entity.Entity; | ||||||
| import net.minecraft.util.math.vector.Vector3d; | import net.minecraft.util.math.vector.Vector3d; | ||||||
| import net.minecraft.world.World; | import net.minecraft.world.World; | ||||||
| 
 | 
 | ||||||
| @@ -14,26 +17,21 @@ import javax.annotation.Nonnull; | |||||||
| 
 | 
 | ||||||
| public class PocketSpeakerPeripheral extends UpgradeSpeakerPeripheral | public class PocketSpeakerPeripheral extends UpgradeSpeakerPeripheral | ||||||
| { | { | ||||||
|     private World world = null; |     private final IPocketAccess access; | ||||||
|  |     private World level; | ||||||
|     private Vector3d position = Vector3d.ZERO; |     private Vector3d position = Vector3d.ZERO; | ||||||
| 
 | 
 | ||||||
|     void setLocation( World world, Vector3d position ) |     public PocketSpeakerPeripheral( IPocketAccess access ) | ||||||
|     { |     { | ||||||
|         this.position = position; |         this.access = access; | ||||||
|         this.world = world; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public World getWorld() |  | ||||||
|     { |  | ||||||
|         return world; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Nonnull |     @Nonnull | ||||||
|     @Override |     @Override | ||||||
|     public Vector3d getPosition() |     public SpeakerPosition getPosition() | ||||||
|     { |     { | ||||||
|         return world != null ? position : null; |         Entity entity = access.getEntity(); | ||||||
|  |         return entity == null ? SpeakerPosition.of( level, position ) : SpeakerPosition.of( entity ); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
| @@ -41,4 +39,19 @@ public class PocketSpeakerPeripheral extends UpgradeSpeakerPeripheral | |||||||
|     { |     { | ||||||
|         return other instanceof PocketSpeakerPeripheral; |         return other instanceof PocketSpeakerPeripheral; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void update() | ||||||
|  |     { | ||||||
|  |         Entity entity = access.getEntity(); | ||||||
|  |         if( entity != null ) | ||||||
|  |         { | ||||||
|  |             level = entity.level; | ||||||
|  |             position = entity.position(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         super.update(); | ||||||
|  | 
 | ||||||
|  |         access.setLight( madeSound() ? 0x3320fc : -1 ); | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -12,11 +12,11 @@ import dan200.computercraft.api.turtle.ITurtleAccess; | |||||||
| import dan200.computercraft.api.turtle.TurtleSide; | import dan200.computercraft.api.turtle.TurtleSide; | ||||||
| import dan200.computercraft.api.turtle.TurtleUpgradeType; | import dan200.computercraft.api.turtle.TurtleUpgradeType; | ||||||
| import dan200.computercraft.shared.Registry; | import dan200.computercraft.shared.Registry; | ||||||
|  | import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition; | ||||||
| import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral; | import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral; | ||||||
| import net.minecraft.client.renderer.model.ModelResourceLocation; | import net.minecraft.client.renderer.model.ModelResourceLocation; | ||||||
| import net.minecraft.util.ResourceLocation; | import net.minecraft.util.ResourceLocation; | ||||||
| import net.minecraft.util.math.vector.Vector3d; | import net.minecraft.util.math.vector.Vector3d; | ||||||
| import net.minecraft.world.World; |  | ||||||
| import net.minecraftforge.api.distmarker.Dist; | import net.minecraftforge.api.distmarker.Dist; | ||||||
| import net.minecraftforge.api.distmarker.OnlyIn; | import net.minecraftforge.api.distmarker.OnlyIn; | ||||||
| 
 | 
 | ||||||
| @@ -36,17 +36,11 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade | |||||||
|             this.turtle = turtle; |             this.turtle = turtle; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         @Override |  | ||||||
|         public World getWorld() |  | ||||||
|         { |  | ||||||
|             return turtle.getWorld(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         @Nonnull |         @Nonnull | ||||||
|         @Override |         @Override | ||||||
|         public Vector3d getPosition() |         public SpeakerPosition getPosition() | ||||||
|         { |         { | ||||||
|             return Vector3d.atCenterOf( turtle.getPosition() ); |             return SpeakerPosition.of( turtle.getWorld(), Vector3d.atCenterOf( turtle.getPosition() ) ); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         @Override |         @Override | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Jonathan Coates
					Jonathan Coates