Skip to content

Commit e7c19bc

Browse files
committed
Change speakers to use the SPacketCustomSound packet instead
The method to register new SoundEvents is private, which means that few (if any) mods actually register them. Consequently, one could not use the speaker to play any modded sound, as they weren't registered on the server side. Using SPacketCustomSound does mean we can no longer determine if a sound exists or not, but I think a price I'm willing to pay in order to allow playing modded sounds.
1 parent 914df8b commit e7c19bc

File tree

1 file changed

+56
-77
lines changed

1 file changed

+56
-77
lines changed

src/main/java/dan200/computercraft/shared/peripheral/speaker/SpeakerPeripheral.java

Lines changed: 56 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,39 @@
88

99
import dan200.computercraft.ComputerCraft;
1010
import dan200.computercraft.api.lua.ILuaContext;
11-
import dan200.computercraft.api.lua.ILuaTask;
1211
import dan200.computercraft.api.lua.LuaException;
1312
import dan200.computercraft.api.peripheral.IComputerAccess;
1413
import dan200.computercraft.api.peripheral.IPeripheral;
14+
import net.minecraft.network.play.server.SPacketCustomSound;
15+
import net.minecraft.server.MinecraftServer;
1516
import net.minecraft.util.ResourceLocation;
1617
import net.minecraft.util.SoundCategory;
1718
import net.minecraft.util.SoundEvent;
1819
import net.minecraft.util.math.BlockPos;
1920
import net.minecraft.world.World;
2021

2122
import javax.annotation.Nonnull;
22-
import javax.annotation.Nullable;
2323

2424
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
2525
import static dan200.computercraft.core.apis.ArgumentHelper.optReal;
2626

27-
public class SpeakerPeripheral implements IPeripheral {
28-
private TileSpeaker m_speaker;
27+
public class SpeakerPeripheral implements IPeripheral
28+
{
29+
private final TileSpeaker m_speaker;
2930
private long m_clock;
3031
private long m_lastPlayTime;
3132
private int m_notesThisTick;
3233

3334
public SpeakerPeripheral()
3435
{
35-
m_clock = 0;
36-
m_lastPlayTime = 0;
37-
m_notesThisTick = 0;
36+
this( null );
3837
}
3938

40-
SpeakerPeripheral(TileSpeaker speaker)
39+
SpeakerPeripheral( TileSpeaker speaker )
4140
{
42-
this();
41+
m_clock = 0;
42+
m_lastPlayTime = 0;
43+
m_notesThisTick = 0;
4344
m_speaker = speaker;
4445
}
4546

@@ -64,15 +65,9 @@ public BlockPos getPos()
6465
@Override
6566
public boolean equals( IPeripheral other )
6667
{
67-
if( other != null && other instanceof SpeakerPeripheral )
68-
{
69-
SpeakerPeripheral otherSpeaker = (SpeakerPeripheral) other;
70-
return otherSpeaker.m_speaker == m_speaker;
71-
}
72-
else
73-
{
74-
return false;
75-
}
68+
if( other == this ) return true;
69+
if( !(other instanceof SpeakerPeripheral) ) return false;
70+
return m_speaker == ((SpeakerPeripheral) other).m_speaker;
7671
}
7772

7873
@Nonnull
@@ -87,8 +82,8 @@ public String getType()
8782
public String[] getMethodNames()
8883
{
8984
return new String[] {
90-
"playSound", // Plays sound at resourceLocator
91-
"playNote" // Plays note
85+
"playSound", // Plays sound at resourceLocator
86+
"playNote" // Plays note
9287
};
9388
}
9489

@@ -100,18 +95,22 @@ public Object[] callMethod( @Nonnull IComputerAccess computerAccess, @Nonnull IL
10095
// playSound
10196
case 0:
10297
{
103-
return playSound(args, context, false);
98+
String name = getString( args, 0 );
99+
float volume = (float) optReal( args, 1, 1.0 );
100+
float pitch = (float) optReal( args, 2, 1.0 );
101+
102+
return new Object[] { playSound( context, name, volume, pitch, false ) };
104103
}
105104

106105
// playNote
107106
case 1:
108107
{
109-
return playNote(args, context);
108+
return playNote( args, context );
110109
}
111110

112111
default:
113112
{
114-
throw new LuaException("Method index out of range!");
113+
throw new LuaException( "Method index out of range!" );
115114
}
116115

117116
}
@@ -120,75 +119,55 @@ public Object[] callMethod( @Nonnull IComputerAccess computerAccess, @Nonnull IL
120119
@Nonnull
121120
private synchronized Object[] playNote( Object[] arguments, ILuaContext context ) throws LuaException
122121
{
123-
String name = getString(arguments, 0);
122+
String name = getString( arguments, 0 );
124123
float volume = (float) optReal( arguments, 1, 1.0 );
125124
float pitch = (float) optReal( arguments, 2, 1.0 );
125+
126+
String noteName = "block.note." + name;
126127

127-
// Check if sound exists
128-
if ( !SoundEvent.REGISTRY.containsKey( new ResourceLocation( "block.note." + name ) ) )
128+
// Check if the note exists
129+
if( !SoundEvent.REGISTRY.containsKey( new ResourceLocation( noteName ) ) )
129130
{
130-
throw new LuaException("Invalid instrument, \"" + arguments[0] + "\"!");
131+
throw new LuaException( "Invalid instrument, \"" + name + "\"!" );
131132
}
132133

133134
// If the resource location for note block notes changes, this method call will need to be updated
134-
Object[] returnValue = playSound(
135-
new Object[] {
136-
"block.note." + name,
137-
(double)Math.min( volume, 3f ),
138-
Math.pow( 2.0f, ( pitch - 12.0f ) / 12.0f)
139-
}, context, true
135+
boolean success = playSound( context, noteName,
136+
Math.min( volume, 3f ),
137+
(float) Math.pow( 2.0, (pitch - 12.0) / 12.0 ), true
140138
);
141139

142-
if( returnValue[0] instanceof Boolean && (Boolean) returnValue[0] )
140+
if( success ) m_notesThisTick++;
141+
return new Object[] { success };
142+
}
143+
144+
private synchronized boolean playSound( ILuaContext context, String name, float volume, float pitch, boolean isNote ) throws LuaException
145+
{
146+
if( m_clock - m_lastPlayTime < TileSpeaker.MIN_TICKS_BETWEEN_SOUNDS &&
147+
(!isNote || m_clock - m_lastPlayTime != 0 || m_notesThisTick >= ComputerCraft.maxNotesPerTick) )
143148
{
144-
m_notesThisTick++;
149+
// Rate limiting occurs when we've already played a sound within the last tick, or we've
150+
// played more notes than allowable within the current tick.
151+
return false;
145152
}
146153

147-
return returnValue;
148-
}
154+
final World world = getWorld();
155+
final BlockPos pos = getPos();
149156

150-
@Nonnull
151-
private synchronized Object[] playSound( Object[] arguments, ILuaContext context, boolean isNote ) throws LuaException
152-
{
153-
String name = getString(arguments, 0);
154-
float volume = (float) optReal( arguments, 1, 1.0 );
155-
float pitch = (float) optReal( arguments, 2, 1.0 );
157+
context.issueMainThreadTask( () -> {
158+
MinecraftServer server = world.getMinecraftServer();
159+
if( server == null ) return null;
156160

157-
ResourceLocation resourceName = new ResourceLocation( name );
161+
double x = pos.getX() + 0.5, y = pos.getY() + 0.5, z = pos.getZ() + 0.5;
162+
server.getPlayerList().sendToAllNearExcept(
163+
null, x, y, z, volume > 1.0f ? 16 * volume : 16.0, world.provider.getDimension(),
164+
new SPacketCustomSound( name, SoundCategory.RECORDS, x, y, z, volume, pitch )
165+
);
166+
return null;
167+
} );
158168

159-
if( m_clock - m_lastPlayTime >= TileSpeaker.MIN_TICKS_BETWEEN_SOUNDS || ( ( m_clock - m_lastPlayTime == 0 ) && ( m_notesThisTick < ComputerCraft.maxNotesPerTick ) && isNote ) )
160-
{
161-
if( SoundEvent.REGISTRY.containsKey(resourceName) )
162-
{
163-
final World world = getWorld();
164-
final BlockPos pos = getPos();
165-
final ResourceLocation resource = resourceName;
166-
final float vol = volume;
167-
final float soundPitch = pitch;
168-
169-
context.issueMainThreadTask(new ILuaTask()
170-
{
171-
@Nullable
172-
@Override
173-
public Object[] execute() throws LuaException
174-
{
175-
world.playSound( null, pos, SoundEvent.REGISTRY.getObject( resource ), SoundCategory.RECORDS, Math.min( vol, 3f ), soundPitch );
176-
return null;
177-
}
178-
});
179-
180-
m_lastPlayTime = m_clock;
181-
return new Object[]{true}; // Success, return true
182-
}
183-
else
184-
{
185-
return new Object[]{false}; // Failed - sound not existent, return false
186-
}
187-
}
188-
else
189-
{
190-
return new Object[]{false}; // Failed - rate limited, return false
191-
}
169+
m_lastPlayTime = m_clock;
170+
return true;
192171
}
193172
}
194173

0 commit comments

Comments
 (0)