mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-01-22 15:06:58 +00:00
Rewrite speaker networking code
Speakers now play sounds using a custom set of packets. - When playing a sound, we send the resource id, position, volume, pitch and a UUID for the _speaker_ to all nearby clients. - This UUID is then used when we need to update the sound. When the speaker is moved or destroyed, we send a new packet to clients and update accordingly. This does have one side effect, that speakers can now only play one sound at a time. I think this is accceptable - otherwise it's possible to spam ward in a loop. Notes still use the old networking code, and so will not be affected. Closes #823
This commit is contained in:
parent
2fab1a3054
commit
de6f27ceaf
@ -22,6 +22,7 @@ public class ClientHooks
|
|||||||
if( event.getWorld().isClientSide() )
|
if( event.getWorld().isClientSide() )
|
||||||
{
|
{
|
||||||
ClientMonitor.destroyAll();
|
ClientMonitor.destroyAll();
|
||||||
|
SoundManager.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
84
src/main/java/dan200/computercraft/client/SoundManager.java
Normal file
84
src/main/java/dan200/computercraft/client/SoundManager.java
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.client;
|
||||||
|
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.audio.ISound;
|
||||||
|
import net.minecraft.client.audio.ITickableSound;
|
||||||
|
import net.minecraft.client.audio.LocatableSound;
|
||||||
|
import net.minecraft.client.audio.SoundHandler;
|
||||||
|
import net.minecraft.util.SoundCategory;
|
||||||
|
import net.minecraft.util.SoundEvent;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class SoundManager
|
||||||
|
{
|
||||||
|
private static final Map<UUID, MoveableSound> sounds = new HashMap<>();
|
||||||
|
|
||||||
|
public static void playSound( UUID source, Vec3d position, SoundEvent event, float volume, float pitch )
|
||||||
|
{
|
||||||
|
SoundHandler soundManager = Minecraft.getInstance().getSoundManager();
|
||||||
|
|
||||||
|
MoveableSound oldSound = sounds.get( source );
|
||||||
|
if( oldSound != null ) soundManager.stop( oldSound );
|
||||||
|
|
||||||
|
MoveableSound newSound = new MoveableSound( event, position, volume, pitch );
|
||||||
|
sounds.put( source, newSound );
|
||||||
|
soundManager.play( newSound );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopSound( UUID source )
|
||||||
|
{
|
||||||
|
ISound sound = sounds.remove( source );
|
||||||
|
if( sound == null ) return;
|
||||||
|
|
||||||
|
Minecraft.getInstance().getSoundManager().stop( sound );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void moveSound( UUID source, Vec3d position )
|
||||||
|
{
|
||||||
|
MoveableSound sound = sounds.get( source );
|
||||||
|
if( sound != null ) sound.setPosition( position );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void reset()
|
||||||
|
{
|
||||||
|
sounds.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MoveableSound extends LocatableSound implements ITickableSound
|
||||||
|
{
|
||||||
|
protected MoveableSound( SoundEvent sound, Vec3d position, float volume, float pitch )
|
||||||
|
{
|
||||||
|
super( sound, SoundCategory.RECORDS );
|
||||||
|
setPosition( position );
|
||||||
|
this.volume = volume;
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPosition( Vec3d position )
|
||||||
|
{
|
||||||
|
x = (float) position.x();
|
||||||
|
y = (float) position.y();
|
||||||
|
z = (float) position.z();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isStopped()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,10 @@ import com.google.common.cache.LoadingCache;
|
|||||||
import com.google.common.primitives.Primitives;
|
import com.google.common.primitives.Primitives;
|
||||||
import com.google.common.reflect.TypeToken;
|
import com.google.common.reflect.TypeToken;
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
import dan200.computercraft.api.lua.*;
|
import dan200.computercraft.api.lua.IArguments;
|
||||||
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
|
import dan200.computercraft.api.lua.LuaFunction;
|
||||||
|
import dan200.computercraft.api.lua.MethodResult;
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.MethodVisitor;
|
import org.objectweb.asm.MethodVisitor;
|
||||||
import org.objectweb.asm.Type;
|
import org.objectweb.asm.Type;
|
||||||
|
@ -6,11 +6,11 @@
|
|||||||
package dan200.computercraft.data;
|
package dan200.computercraft.data;
|
||||||
|
|
||||||
import dan200.computercraft.ComputerCraft;
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.shared.CommonHooks;
|
||||||
import dan200.computercraft.shared.Registry;
|
import dan200.computercraft.shared.Registry;
|
||||||
import dan200.computercraft.shared.data.BlockNamedEntityLootCondition;
|
import dan200.computercraft.shared.data.BlockNamedEntityLootCondition;
|
||||||
import dan200.computercraft.shared.data.HasComputerIdLootCondition;
|
import dan200.computercraft.shared.data.HasComputerIdLootCondition;
|
||||||
import dan200.computercraft.shared.data.PlayerCreativeLootCondition;
|
import dan200.computercraft.shared.data.PlayerCreativeLootCondition;
|
||||||
import dan200.computercraft.shared.CommonHooks;
|
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.data.DataGenerator;
|
import net.minecraft.data.DataGenerator;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
@ -56,6 +56,9 @@ public final class NetworkHandler
|
|||||||
registerMainThread( 13, NetworkDirection.PLAY_TO_CLIENT, ComputerTerminalClientMessage::new );
|
registerMainThread( 13, NetworkDirection.PLAY_TO_CLIENT, ComputerTerminalClientMessage::new );
|
||||||
registerMainThread( 14, NetworkDirection.PLAY_TO_CLIENT, PlayRecordClientMessage.class, PlayRecordClientMessage::new );
|
registerMainThread( 14, NetworkDirection.PLAY_TO_CLIENT, PlayRecordClientMessage.class, PlayRecordClientMessage::new );
|
||||||
registerMainThread( 15, NetworkDirection.PLAY_TO_CLIENT, MonitorClientMessage.class, MonitorClientMessage::new );
|
registerMainThread( 15, NetworkDirection.PLAY_TO_CLIENT, MonitorClientMessage.class, MonitorClientMessage::new );
|
||||||
|
registerMainThread( 16, NetworkDirection.PLAY_TO_CLIENT, SpeakerPlayClientMessage.class, SpeakerPlayClientMessage::new );
|
||||||
|
registerMainThread( 17, NetworkDirection.PLAY_TO_CLIENT, SpeakerStopClientMessage.class, SpeakerStopClientMessage::new );
|
||||||
|
registerMainThread( 18, NetworkDirection.PLAY_TO_CLIENT, SpeakerMoveClientMessage.class, SpeakerMoveClientMessage::new );
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendToPlayer( PlayerEntity player, NetworkMessage packet )
|
public static void sendToPlayer( PlayerEntity player, NetworkMessage packet )
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.shared.network.client;
|
||||||
|
|
||||||
|
import dan200.computercraft.client.SoundManager;
|
||||||
|
import dan200.computercraft.shared.network.NetworkMessage;
|
||||||
|
import net.minecraft.network.PacketBuffer;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.fml.network.NetworkEvent;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a sound on the client.
|
||||||
|
*
|
||||||
|
* Used by speakers to play sounds.
|
||||||
|
*
|
||||||
|
* @see dan200.computercraft.shared.peripheral.speaker.TileSpeaker
|
||||||
|
*/
|
||||||
|
public class SpeakerMoveClientMessage implements NetworkMessage
|
||||||
|
{
|
||||||
|
private final UUID source;
|
||||||
|
private final Vec3d pos;
|
||||||
|
|
||||||
|
public SpeakerMoveClientMessage( UUID source, Vec3d pos )
|
||||||
|
{
|
||||||
|
this.source = source;
|
||||||
|
this.pos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpeakerMoveClientMessage( PacketBuffer buf )
|
||||||
|
{
|
||||||
|
source = buf.readUUID();
|
||||||
|
pos = new Vec3d( buf.readDouble(), buf.readDouble(), buf.readDouble() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toBytes( @Nonnull PacketBuffer buf )
|
||||||
|
{
|
||||||
|
buf.writeUUID( source );
|
||||||
|
buf.writeDouble( pos.x() );
|
||||||
|
buf.writeDouble( pos.y() );
|
||||||
|
buf.writeDouble( pos.z() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn( Dist.CLIENT )
|
||||||
|
public void handle( NetworkEvent.Context context )
|
||||||
|
{
|
||||||
|
SoundManager.moveSound( source, pos );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.shared.network.client;
|
||||||
|
|
||||||
|
import dan200.computercraft.client.SoundManager;
|
||||||
|
import dan200.computercraft.shared.network.NetworkMessage;
|
||||||
|
import net.minecraft.network.PacketBuffer;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.util.SoundEvent;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.fml.network.NetworkEvent;
|
||||||
|
import net.minecraftforge.registries.ForgeRegistries;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a sound on the client.
|
||||||
|
*
|
||||||
|
* Used by speakers to play sounds.
|
||||||
|
*
|
||||||
|
* @see dan200.computercraft.shared.peripheral.speaker.TileSpeaker
|
||||||
|
*/
|
||||||
|
public class SpeakerPlayClientMessage implements NetworkMessage
|
||||||
|
{
|
||||||
|
private final UUID source;
|
||||||
|
private final Vec3d pos;
|
||||||
|
private final ResourceLocation sound;
|
||||||
|
private final float volume;
|
||||||
|
private final float pitch;
|
||||||
|
|
||||||
|
public SpeakerPlayClientMessage( UUID source, Vec3d pos, ResourceLocation event, float volume, float pitch )
|
||||||
|
{
|
||||||
|
this.source = source;
|
||||||
|
this.pos = pos;
|
||||||
|
sound = event;
|
||||||
|
this.volume = volume;
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpeakerPlayClientMessage( PacketBuffer buf )
|
||||||
|
{
|
||||||
|
source = buf.readUUID();
|
||||||
|
pos = new Vec3d( buf.readDouble(), buf.readDouble(), buf.readDouble() );
|
||||||
|
sound = buf.readResourceLocation();
|
||||||
|
volume = buf.readFloat();
|
||||||
|
pitch = buf.readFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toBytes( @Nonnull PacketBuffer buf )
|
||||||
|
{
|
||||||
|
buf.writeUUID( source );
|
||||||
|
buf.writeDouble( pos.x() );
|
||||||
|
buf.writeDouble( pos.y() );
|
||||||
|
buf.writeDouble( pos.z() );
|
||||||
|
buf.writeResourceLocation( sound );
|
||||||
|
buf.writeFloat( volume );
|
||||||
|
buf.writeFloat( pitch );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn( Dist.CLIENT )
|
||||||
|
public void handle( NetworkEvent.Context context )
|
||||||
|
{
|
||||||
|
SoundEvent sound = ForgeRegistries.SOUND_EVENTS.getValue( this.sound );
|
||||||
|
if( sound != null ) SoundManager.playSound( source, pos, sound, volume, pitch );
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.shared.network.client;
|
||||||
|
|
||||||
|
import dan200.computercraft.client.SoundManager;
|
||||||
|
import dan200.computercraft.shared.network.NetworkMessage;
|
||||||
|
import net.minecraft.network.PacketBuffer;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.fml.network.NetworkEvent;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops a sound on the client
|
||||||
|
*
|
||||||
|
* Called when a speaker is broken.
|
||||||
|
*
|
||||||
|
* @see dan200.computercraft.shared.peripheral.speaker.TileSpeaker
|
||||||
|
*/
|
||||||
|
public class SpeakerStopClientMessage implements NetworkMessage
|
||||||
|
{
|
||||||
|
private final UUID source;
|
||||||
|
|
||||||
|
public SpeakerStopClientMessage( UUID source )
|
||||||
|
{
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpeakerStopClientMessage( PacketBuffer buf )
|
||||||
|
{
|
||||||
|
source = buf.readUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toBytes( @Nonnull PacketBuffer buf )
|
||||||
|
{
|
||||||
|
buf.writeUUID( source );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn( Dist.CLIENT )
|
||||||
|
public void handle( NetworkEvent.Context context )
|
||||||
|
{
|
||||||
|
SoundManager.stopSound( source );
|
||||||
|
}
|
||||||
|
}
|
@ -87,7 +87,7 @@ public class BlockMonitor extends BlockGeneric
|
|||||||
{
|
{
|
||||||
TileMonitor monitor = (TileMonitor) entity;
|
TileMonitor monitor = (TileMonitor) entity;
|
||||||
// Defer the block update if we're being placed by another TE. See #691
|
// Defer the block update if we're being placed by another TE. See #691
|
||||||
if ( livingEntity == null || livingEntity instanceof FakePlayer )
|
if( livingEntity == null || livingEntity instanceof FakePlayer )
|
||||||
{
|
{
|
||||||
monitor.updateNeighborsDeferred();
|
monitor.updateNeighborsDeferred();
|
||||||
return;
|
return;
|
||||||
|
@ -10,17 +10,23 @@ import dan200.computercraft.api.lua.ILuaContext;
|
|||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.api.lua.LuaFunction;
|
import dan200.computercraft.api.lua.LuaFunction;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
import dan200.computercraft.shared.network.NetworkHandler;
|
||||||
|
import dan200.computercraft.shared.network.client.SpeakerMoveClientMessage;
|
||||||
|
import dan200.computercraft.shared.network.client.SpeakerPlayClientMessage;
|
||||||
import net.minecraft.network.play.server.SPlaySoundPacket;
|
import net.minecraft.network.play.server.SPlaySoundPacket;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.state.properties.NoteBlockInstrument;
|
import net.minecraft.state.properties.NoteBlockInstrument;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import net.minecraft.util.ResourceLocationException;
|
import net.minecraft.util.ResourceLocationException;
|
||||||
import net.minecraft.util.SoundCategory;
|
import net.minecraft.util.SoundCategory;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import static dan200.computercraft.api.lua.LuaValues.checkFinite;
|
import static dan200.computercraft.api.lua.LuaValues.checkFinite;
|
||||||
@ -32,20 +38,44 @@ import static dan200.computercraft.api.lua.LuaValues.checkFinite;
|
|||||||
*/
|
*/
|
||||||
public abstract class SpeakerPeripheral implements IPeripheral
|
public abstract class SpeakerPeripheral implements IPeripheral
|
||||||
{
|
{
|
||||||
|
private static final int MIN_TICKS_BETWEEN_SOUNDS = 1;
|
||||||
|
|
||||||
private long clock = 0;
|
private long clock = 0;
|
||||||
private long lastPlayTime = 0;
|
private long lastPlayTime = 0;
|
||||||
private final AtomicInteger notesThisTick = new AtomicInteger();
|
private final AtomicInteger notesThisTick = new AtomicInteger();
|
||||||
|
|
||||||
|
private long lastPositionTime;
|
||||||
|
private Vec3d lastPosition;
|
||||||
|
|
||||||
public void update()
|
public void update()
|
||||||
{
|
{
|
||||||
clock++;
|
clock++;
|
||||||
notesThisTick.set( 0 );
|
notesThisTick.set( 0 );
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// in the last second.
|
||||||
|
if( lastPlayTime > 0 && (clock - lastPositionTime) >= 20 )
|
||||||
|
{
|
||||||
|
Vec3d position = getPosition();
|
||||||
|
if( lastPosition == null || lastPosition.distanceToSqr( position ) >= 0.1 )
|
||||||
|
{
|
||||||
|
lastPosition = position;
|
||||||
|
lastPositionTime = clock;
|
||||||
|
NetworkHandler.sendToAllTracking(
|
||||||
|
new SpeakerMoveClientMessage( getSource(), position ),
|
||||||
|
getWorld().getChunkAt( new BlockPos( position ) )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract World getWorld();
|
public abstract World getWorld();
|
||||||
|
|
||||||
public abstract Vec3d getPosition();
|
public abstract Vec3d getPosition();
|
||||||
|
|
||||||
|
protected abstract UUID getSource();
|
||||||
|
|
||||||
public boolean madeSound( long ticks )
|
public boolean madeSound( long ticks )
|
||||||
{
|
{
|
||||||
return clock - lastPlayTime <= ticks;
|
return clock - lastPlayTime <= ticks;
|
||||||
@ -135,26 +165,37 @@ public abstract class SpeakerPeripheral implements IPeripheral
|
|||||||
|
|
||||||
private synchronized boolean playSound( ILuaContext context, ResourceLocation name, float volume, float pitch, boolean isNote ) throws LuaException
|
private synchronized boolean playSound( ILuaContext context, ResourceLocation name, float volume, float pitch, boolean isNote ) throws LuaException
|
||||||
{
|
{
|
||||||
if( clock - lastPlayTime < TileSpeaker.MIN_TICKS_BETWEEN_SOUNDS &&
|
if( clock - lastPlayTime < MIN_TICKS_BETWEEN_SOUNDS )
|
||||||
(!isNote || clock - lastPlayTime != 0 || notesThisTick.get() >= ComputerCraft.maxNotesPerTick) )
|
|
||||||
{
|
{
|
||||||
// Rate limiting occurs when we've already played a sound within the last tick, or we've
|
// Rate limiting occurs when we've already played a sound within the last tick.
|
||||||
// played more notes than allowable within the current tick.
|
if( !isNote ) return false;
|
||||||
return false;
|
// Or we've played more notes than allowable within the current tick.
|
||||||
|
if( clock - lastPlayTime != 0 || notesThisTick.get() >= ComputerCraft.maxNotesPerTick ) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
World world = getWorld();
|
World world = getWorld();
|
||||||
Vec3d pos = getPosition();
|
Vec3d pos = getPosition();
|
||||||
|
|
||||||
|
float range = MathHelper.clamp( volume, 1.0f, 3.0f ) * 16;
|
||||||
|
|
||||||
context.issueMainThreadTask( () -> {
|
context.issueMainThreadTask( () -> {
|
||||||
MinecraftServer server = world.getServer();
|
MinecraftServer server = world.getServer();
|
||||||
if( server == null ) return null;
|
if( server == null ) return null;
|
||||||
|
|
||||||
float adjVolume = Math.min( volume, 3.0f );
|
if( isNote )
|
||||||
server.getPlayerList().broadcast(
|
{
|
||||||
null, pos.x, pos.y, pos.z, adjVolume > 1.0f ? 16 * adjVolume : 16.0, world.dimension.getType(),
|
server.getPlayerList().broadcast(
|
||||||
new SPlaySoundPacket( name, SoundCategory.RECORDS, pos, adjVolume, pitch )
|
null, pos.x, pos.y, pos.z, range, world.dimension.getType(),
|
||||||
);
|
new SPlaySoundPacket( name, SoundCategory.RECORDS, pos, range, pitch )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
NetworkHandler.sendToAllAround(
|
||||||
|
new SpeakerPlayClientMessage( getSource(), pos, name, range, pitch ),
|
||||||
|
world, pos, range
|
||||||
|
);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@ package dan200.computercraft.shared.peripheral.speaker;
|
|||||||
|
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
import dan200.computercraft.shared.common.TileGeneric;
|
import dan200.computercraft.shared.common.TileGeneric;
|
||||||
|
import dan200.computercraft.shared.network.NetworkHandler;
|
||||||
|
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
||||||
import dan200.computercraft.shared.util.CapabilityUtil;
|
import dan200.computercraft.shared.util.CapabilityUtil;
|
||||||
import net.minecraft.tileentity.ITickableTileEntity;
|
import net.minecraft.tileentity.ITickableTileEntity;
|
||||||
import net.minecraft.tileentity.TileEntityType;
|
import net.minecraft.tileentity.TileEntityType;
|
||||||
@ -19,15 +21,15 @@ import net.minecraftforge.common.util.LazyOptional;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
import static dan200.computercraft.shared.Capabilities.CAPABILITY_PERIPHERAL;
|
||||||
|
|
||||||
public class TileSpeaker extends TileGeneric implements ITickableTileEntity
|
public class TileSpeaker extends TileGeneric implements ITickableTileEntity
|
||||||
{
|
{
|
||||||
public static final int MIN_TICKS_BETWEEN_SOUNDS = 1;
|
|
||||||
|
|
||||||
private final SpeakerPeripheral peripheral;
|
private final SpeakerPeripheral peripheral;
|
||||||
private LazyOptional<IPeripheral> peripheralCap;
|
private LazyOptional<IPeripheral> peripheralCap;
|
||||||
|
private final UUID source = UUID.randomUUID();
|
||||||
|
|
||||||
public TileSpeaker( TileEntityType<TileSpeaker> type )
|
public TileSpeaker( TileEntityType<TileSpeaker> type )
|
||||||
{
|
{
|
||||||
@ -41,6 +43,13 @@ public class TileSpeaker extends TileGeneric implements ITickableTileEntity
|
|||||||
peripheral.update();
|
peripheral.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRemoved()
|
||||||
|
{
|
||||||
|
super.setRemoved();
|
||||||
|
NetworkHandler.sendToAllPlayers( new SpeakerStopClientMessage( source ) );
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public <T> LazyOptional<T> getCapability( @Nonnull Capability<T> cap, @Nullable Direction side )
|
public <T> LazyOptional<T> getCapability( @Nonnull Capability<T> cap, @Nullable Direction side )
|
||||||
@ -83,6 +92,12 @@ public class TileSpeaker extends TileGeneric implements ITickableTileEntity
|
|||||||
return new Vec3d( pos.getX(), pos.getY(), pos.getZ() );
|
return new Vec3d( pos.getX(), pos.getY(), pos.getZ() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected UUID getSource()
|
||||||
|
{
|
||||||
|
return speaker.source;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals( @Nullable IPeripheral other )
|
public boolean equals( @Nullable IPeripheral other )
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
||||||
|
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
|
||||||
|
* Send enquiries to dratcliffe@gmail.com
|
||||||
|
*/
|
||||||
|
package dan200.computercraft.shared.peripheral.speaker;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
|
import dan200.computercraft.shared.network.NetworkHandler;
|
||||||
|
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A speaker peripheral which is used on an upgrade, and so is only attached to one computer.
|
||||||
|
*/
|
||||||
|
public abstract class UpgradeSpeakerPeripheral extends SpeakerPeripheral
|
||||||
|
{
|
||||||
|
private final UUID source = UUID.randomUUID();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final UUID getSource()
|
||||||
|
{
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void detach( @Nonnull IComputerAccess computer )
|
||||||
|
{
|
||||||
|
NetworkHandler.sendToAllPlayers( new SpeakerStopClientMessage( source ) );
|
||||||
|
}
|
||||||
|
}
|
@ -6,11 +6,11 @@
|
|||||||
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.shared.peripheral.speaker.SpeakerPeripheral;
|
import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
public class PocketSpeakerPeripheral extends SpeakerPeripheral
|
public class PocketSpeakerPeripheral extends UpgradeSpeakerPeripheral
|
||||||
{
|
{
|
||||||
private World world = null;
|
private World world = null;
|
||||||
private Vec3d position = Vec3d.ZERO;
|
private Vec3d position = Vec3d.ZERO;
|
||||||
|
@ -715,7 +715,6 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
* more information about the item at the cost of taking longer to run.
|
* more information about the item at the cost of taking longer to run.
|
||||||
* @return The command result.
|
* @return The command result.
|
||||||
* @throws LuaException If the slot is out of range.
|
* @throws LuaException If the slot is out of range.
|
||||||
* @see InventoryMethods#getItemDetail Describes the information returned by a detailed query.
|
|
||||||
* @cc.treturn nil|table Information about the given slot, or {@code nil} if it is empty.
|
* @cc.treturn nil|table Information about the given slot, or {@code nil} if it is empty.
|
||||||
* @cc.usage Print the current slot, assuming it contains 13 dirt.
|
* @cc.usage Print the current slot, assuming it contains 13 dirt.
|
||||||
*
|
*
|
||||||
@ -726,6 +725,7 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
* -- count = 13,
|
* -- count = 13,
|
||||||
* -- }
|
* -- }
|
||||||
* }</pre>
|
* }</pre>
|
||||||
|
* @see InventoryMethods#getItemDetail Describes the information returned by a detailed query.
|
||||||
*/
|
*/
|
||||||
@LuaFunction
|
@LuaFunction
|
||||||
public final MethodResult getItemDetail( ILuaContext context, Optional<Integer> slot, Optional<Boolean> detailed ) throws LuaException
|
public final MethodResult getItemDetail( ILuaContext context, Optional<Integer> slot, Optional<Boolean> detailed ) throws LuaException
|
||||||
|
@ -12,7 +12,7 @@ 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.SpeakerPeripheral;
|
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.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
@ -28,7 +28,7 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade
|
|||||||
private static final ModelResourceLocation leftModel = new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_left", "inventory" );
|
private static final ModelResourceLocation leftModel = new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_left", "inventory" );
|
||||||
private static final ModelResourceLocation rightModel = new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_right", "inventory" );
|
private static final ModelResourceLocation rightModel = new ModelResourceLocation( "computercraft:turtle_speaker_upgrade_right", "inventory" );
|
||||||
|
|
||||||
private static class Peripheral extends SpeakerPeripheral
|
private static class Peripheral extends UpgradeSpeakerPeripheral
|
||||||
{
|
{
|
||||||
ITurtleAccess turtle;
|
ITurtleAccess turtle;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user