mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-08-28 16:22:18 +00:00
fix: another part of syncing with Tweaked codebase
This commit is contained in:
parent
d4f1e34023
commit
861a9e199d
@ -75,6 +75,8 @@ public final class ComputerCraft implements ModInitializer
|
|||||||
) );
|
) );
|
||||||
public static int httpMaxRequests = 16;
|
public static int httpMaxRequests = 16;
|
||||||
public static int httpMaxWebsockets = 4;
|
public static int httpMaxWebsockets = 4;
|
||||||
|
public static int httpDownloadBandwidth = 32 * 1024 * 1024;
|
||||||
|
public static int httpUploadBandwidth = 32 * 1024 * 1024;
|
||||||
|
|
||||||
public static boolean enableCommandBlock = false;
|
public static boolean enableCommandBlock = false;
|
||||||
public static int modemRange = 64;
|
public static int modemRange = 64;
|
||||||
|
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.MinecraftClient;
|
||||||
|
import net.minecraft.client.sound.AbstractSoundInstance;
|
||||||
|
import net.minecraft.client.sound.SoundInstance;
|
||||||
|
import net.minecraft.client.sound.TickableSoundInstance;
|
||||||
|
import net.minecraft.sound.SoundCategory;
|
||||||
|
import net.minecraft.sound.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 )
|
||||||
|
{
|
||||||
|
var soundManager = MinecraftClient.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 )
|
||||||
|
{
|
||||||
|
SoundInstance sound = sounds.remove( source );
|
||||||
|
if( sound == null ) return;
|
||||||
|
|
||||||
|
MinecraftClient.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 AbstractSoundInstance implements TickableSoundInstance
|
||||||
|
{
|
||||||
|
protected MoveableSound( SoundEvent sound, Vec3d position, float volume, float pitch )
|
||||||
|
{
|
||||||
|
super( sound, SoundCategory.RECORDS );
|
||||||
|
setPosition( position );
|
||||||
|
this.volume = volume;
|
||||||
|
this.pitch = pitch;
|
||||||
|
attenuationType = SoundInstance.AttenuationType.LINEAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPosition( Vec3d position )
|
||||||
|
{
|
||||||
|
x = (float) position.getX();
|
||||||
|
y = (float) position.getY();
|
||||||
|
z = (float) position.getZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDone()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -62,6 +62,7 @@ public interface IAPIEnvironment
|
|||||||
@Nullable
|
@Nullable
|
||||||
IPeripheral getPeripheral( ComputerSide side );
|
IPeripheral getPeripheral( ComputerSide side );
|
||||||
|
|
||||||
|
@Nullable
|
||||||
String getLabel();
|
String getLabel();
|
||||||
|
|
||||||
void setLabel( @Nullable String label );
|
void setLabel( @Nullable String label );
|
||||||
|
@ -96,9 +96,8 @@ public abstract class HandleGeneric
|
|||||||
|
|
||||||
protected static SeekableByteChannel asSeekable( Channel channel )
|
protected static SeekableByteChannel asSeekable( Channel channel )
|
||||||
{
|
{
|
||||||
if( !(channel instanceof SeekableByteChannel) ) return null;
|
if( !(channel instanceof SeekableByteChannel seekable) ) return null;
|
||||||
|
|
||||||
SeekableByteChannel seekable = (SeekableByteChannel) channel;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
seekable.position( seekable.position() );
|
seekable.position( seekable.position() );
|
||||||
|
@ -20,6 +20,8 @@ import io.netty.handler.codec.http.websocketx.WebSocketHandshakeException;
|
|||||||
import io.netty.handler.ssl.SslContext;
|
import io.netty.handler.ssl.SslContext;
|
||||||
import io.netty.handler.ssl.SslContextBuilder;
|
import io.netty.handler.ssl.SslContextBuilder;
|
||||||
import io.netty.handler.timeout.ReadTimeoutException;
|
import io.netty.handler.timeout.ReadTimeoutException;
|
||||||
|
import io.netty.handler.traffic.AbstractTrafficShapingHandler;
|
||||||
|
import io.netty.handler.traffic.GlobalTrafficShapingHandler;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
@ -28,9 +30,7 @@ import javax.net.ssl.TrustManagerFactory;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
import java.util.concurrent.SynchronousQueue;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,10 +38,8 @@ import java.util.concurrent.TimeUnit;
|
|||||||
*/
|
*/
|
||||||
public final class NetworkUtils
|
public final class NetworkUtils
|
||||||
{
|
{
|
||||||
public static final ExecutorService EXECUTOR = new ThreadPoolExecutor(
|
public static final ScheduledThreadPoolExecutor EXECUTOR = new ScheduledThreadPoolExecutor(
|
||||||
4, Integer.MAX_VALUE,
|
4,
|
||||||
60L, TimeUnit.SECONDS,
|
|
||||||
new SynchronousQueue<>(),
|
|
||||||
ThreadUtils.builder( "Network" )
|
ThreadUtils.builder( "Network" )
|
||||||
.setPriority( Thread.MIN_PRIORITY + (Thread.NORM_PRIORITY - Thread.MIN_PRIORITY) / 2 )
|
.setPriority( Thread.MIN_PRIORITY + (Thread.NORM_PRIORITY - Thread.MIN_PRIORITY) / 2 )
|
||||||
.build()
|
.build()
|
||||||
@ -52,6 +50,15 @@ public final class NetworkUtils
|
|||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
public static final AbstractTrafficShapingHandler SHAPING_HANDLER = new GlobalTrafficShapingHandler(
|
||||||
|
EXECUTOR, ComputerCraft.httpUploadBandwidth, ComputerCraft.httpDownloadBandwidth
|
||||||
|
);
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
EXECUTOR.setKeepAliveTime( 60, TimeUnit.SECONDS );
|
||||||
|
}
|
||||||
|
|
||||||
private NetworkUtils()
|
private NetworkUtils()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -107,8 +114,18 @@ public final class NetworkUtils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void reloadConfig()
|
||||||
|
{
|
||||||
|
SHAPING_HANDLER.configure( ComputerCraft.httpUploadBandwidth, ComputerCraft.httpDownloadBandwidth );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void reset()
|
||||||
|
{
|
||||||
|
SHAPING_HANDLER.trafficCounter().resetCumulativeTime();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a {@link InetSocketAddress} from a {@link URI}.
|
* Create a {@link InetSocketAddress} from a {@link java.net.URI}.
|
||||||
*
|
*
|
||||||
* Note, this may require a DNS lookup, and so should not be executed on the main CC thread.
|
* Note, this may require a DNS lookup, and so should not be executed on the main CC thread.
|
||||||
*
|
*
|
||||||
|
@ -167,6 +167,7 @@ public class HttpRequest extends Resource<HttpRequest>
|
|||||||
}
|
}
|
||||||
|
|
||||||
ChannelPipeline p = ch.pipeline();
|
ChannelPipeline p = ch.pipeline();
|
||||||
|
p.addLast( NetworkUtils.SHAPING_HANDLER );
|
||||||
if( sslContext != null )
|
if( sslContext != null )
|
||||||
{
|
{
|
||||||
p.addLast( sslContext.newHandler( ch.alloc(), uri.getHost(), socketAddress.getPort() ) );
|
p.addLast( sslContext.newHandler( ch.alloc(), uri.getHost(), socketAddress.getPort() ) );
|
||||||
|
@ -100,9 +100,8 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb
|
|||||||
{
|
{
|
||||||
if( closed || request.checkClosed() ) return;
|
if( closed || request.checkClosed() ) return;
|
||||||
|
|
||||||
if( message instanceof HttpResponse )
|
if( message instanceof HttpResponse response )
|
||||||
{
|
{
|
||||||
HttpResponse response = (HttpResponse) message;
|
|
||||||
|
|
||||||
if( request.redirects.get() > 0 )
|
if( request.redirects.get() > 0 )
|
||||||
{
|
{
|
||||||
@ -137,9 +136,8 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb
|
|||||||
responseHeaders.add( response.headers() );
|
responseHeaders.add( response.headers() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( message instanceof HttpContent )
|
if( message instanceof HttpContent content )
|
||||||
{
|
{
|
||||||
HttpContent content = (HttpContent) message;
|
|
||||||
|
|
||||||
if( responseBody == null )
|
if( responseBody == null )
|
||||||
{
|
{
|
||||||
@ -162,9 +160,8 @@ public final class HttpRequestHandler extends SimpleChannelInboundHandler<HttpOb
|
|||||||
responseBody.addComponent( true, partial.retain() );
|
responseBody.addComponent( true, partial.retain() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( message instanceof LastHttpContent )
|
if( message instanceof LastHttpContent last )
|
||||||
{
|
{
|
||||||
LastHttpContent last = (LastHttpContent) message;
|
|
||||||
responseHeaders.add( last.trailingHeaders() );
|
responseHeaders.add( last.trailingHeaders() );
|
||||||
|
|
||||||
// Set the content length, if not already given.
|
// Set the content length, if not already given.
|
||||||
|
@ -22,6 +22,7 @@ import io.netty.channel.ChannelPipeline;
|
|||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import io.netty.channel.socket.nio.NioSocketChannel;
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
import io.netty.handler.codec.http.HttpClientCodec;
|
import io.netty.handler.codec.http.HttpClientCodec;
|
||||||
|
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||||
import io.netty.handler.codec.http.HttpHeaders;
|
import io.netty.handler.codec.http.HttpHeaders;
|
||||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||||
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
|
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
|
||||||
@ -145,20 +146,22 @@ public class Websocket extends Resource<Websocket>
|
|||||||
protected void initChannel( SocketChannel ch )
|
protected void initChannel( SocketChannel ch )
|
||||||
{
|
{
|
||||||
ChannelPipeline p = ch.pipeline();
|
ChannelPipeline p = ch.pipeline();
|
||||||
|
p.addLast( NetworkUtils.SHAPING_HANDLER );
|
||||||
if( sslContext != null )
|
if( sslContext != null )
|
||||||
{
|
{
|
||||||
p.addLast( sslContext.newHandler( ch.alloc(), uri.getHost(), socketAddress.getPort() ) );
|
p.addLast( sslContext.newHandler( ch.alloc(), uri.getHost(), socketAddress.getPort() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String subprotocol = headers.get( HttpHeaderNames.SEC_WEBSOCKET_PROTOCOL );
|
||||||
WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(
|
WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(
|
||||||
uri, WebSocketVersion.V13, null, true, headers,
|
uri, WebSocketVersion.V13, subprotocol, true, headers,
|
||||||
options.websocketMessage <= 0 ? MAX_MESSAGE_SIZE : options.websocketMessage
|
options.websocketMessage <= 0 ? MAX_MESSAGE_SIZE : options.websocketMessage
|
||||||
);
|
);
|
||||||
|
|
||||||
p.addLast(
|
p.addLast(
|
||||||
new HttpClientCodec(),
|
new HttpClientCodec(),
|
||||||
new HttpObjectAggregator( 8192 ),
|
new HttpObjectAggregator( 8192 ),
|
||||||
WebSocketClientCompressionHandler.INSTANCE,
|
WebsocketCompressionHandler.INSTANCE,
|
||||||
new WebsocketHandler( Websocket.this, handshaker, options )
|
new WebsocketHandler( Websocket.this, handshaker, options )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* 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.core.apis.http.websocket;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandler;
|
||||||
|
import io.netty.handler.codec.compression.ZlibCodecFactory;
|
||||||
|
import io.netty.handler.codec.http.websocketx.extensions.WebSocketClientExtensionHandler;
|
||||||
|
import io.netty.handler.codec.http.websocketx.extensions.compression.DeflateFrameClientExtensionHandshaker;
|
||||||
|
import io.netty.handler.codec.http.websocketx.extensions.compression.PerMessageDeflateClientExtensionHandshaker;
|
||||||
|
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler;
|
||||||
|
|
||||||
|
import static io.netty.handler.codec.http.websocketx.extensions.compression.PerMessageDeflateServerExtensionHandshaker.MAX_WINDOW_SIZE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An alternative to {@link WebSocketClientCompressionHandler} which supports the {@literal client_no_context_takeover}
|
||||||
|
* extension. Makes CC <em>slightly</em> more flexible.
|
||||||
|
*/
|
||||||
|
@ChannelHandler.Sharable
|
||||||
|
final class WebsocketCompressionHandler extends WebSocketClientExtensionHandler
|
||||||
|
{
|
||||||
|
public static final WebsocketCompressionHandler INSTANCE = new WebsocketCompressionHandler();
|
||||||
|
|
||||||
|
private WebsocketCompressionHandler()
|
||||||
|
{
|
||||||
|
super(
|
||||||
|
new PerMessageDeflateClientExtensionHandshaker(
|
||||||
|
6, ZlibCodecFactory.isSupportingWindowSizeAndMemLevel(), MAX_WINDOW_SIZE,
|
||||||
|
true, false
|
||||||
|
),
|
||||||
|
new DeflateFrameClientExtensionHandshaker( false ),
|
||||||
|
new DeflateFrameClientExtensionHandshaker( true )
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -55,9 +55,8 @@ public class WebsocketHandler extends SimpleChannelInboundHandler<Object>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( msg instanceof FullHttpResponse )
|
if( msg instanceof FullHttpResponse response )
|
||||||
{
|
{
|
||||||
FullHttpResponse response = (FullHttpResponse) msg;
|
|
||||||
throw new IllegalStateException( "Unexpected FullHttpResponse (getStatus=" + response.status() + ", content=" + response.content().toString( CharsetUtil.UTF_8 ) + ')' );
|
throw new IllegalStateException( "Unexpected FullHttpResponse (getStatus=" + response.status() + ", content=" + response.content().toString( CharsetUtil.UTF_8 ) + ')' );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,9 +75,8 @@ public class WebsocketHandler extends SimpleChannelInboundHandler<Object>
|
|||||||
websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_INCOMING, converted.length );
|
websocket.environment().addTrackingChange( TrackingField.WEBSOCKET_INCOMING, converted.length );
|
||||||
websocket.environment().queueEvent( MESSAGE_EVENT, websocket.address(), converted, true );
|
websocket.environment().queueEvent( MESSAGE_EVENT, websocket.address(), converted, true );
|
||||||
}
|
}
|
||||||
else if( frame instanceof CloseWebSocketFrame )
|
else if( frame instanceof CloseWebSocketFrame closeFrame )
|
||||||
{
|
{
|
||||||
CloseWebSocketFrame closeFrame = (CloseWebSocketFrame) frame;
|
|
||||||
websocket.close( closeFrame.statusCode(), closeFrame.reasonText() );
|
websocket.close( closeFrame.statusCode(), closeFrame.reasonText() );
|
||||||
}
|
}
|
||||||
else if( frame instanceof PingWebSocketFrame )
|
else if( frame instanceof PingWebSocketFrame )
|
||||||
|
@ -18,7 +18,7 @@ import static org.objectweb.asm.Opcodes.ICONST_0;
|
|||||||
|
|
||||||
final class Reflect
|
final class Reflect
|
||||||
{
|
{
|
||||||
static final Type OPTIONAL_IN = Optional.class.getTypeParameters()[0];
|
static final java.lang.reflect.Type OPTIONAL_IN = Optional.class.getTypeParameters()[0];
|
||||||
|
|
||||||
private Reflect()
|
private Reflect()
|
||||||
{
|
{
|
||||||
@ -52,12 +52,11 @@ final class Reflect
|
|||||||
{
|
{
|
||||||
if( underlying instanceof Class<?> ) return (Class<?>) underlying;
|
if( underlying instanceof Class<?> ) return (Class<?>) underlying;
|
||||||
|
|
||||||
if( underlying instanceof ParameterizedType )
|
if( underlying instanceof ParameterizedType type )
|
||||||
{
|
{
|
||||||
ParameterizedType type = (ParameterizedType) underlying;
|
|
||||||
if( !allowParameter )
|
if( !allowParameter )
|
||||||
{
|
{
|
||||||
for( Type arg : type.getActualTypeArguments() )
|
for( java.lang.reflect.Type arg : type.getActualTypeArguments() )
|
||||||
{
|
{
|
||||||
if( arg instanceof WildcardType ) continue;
|
if( arg instanceof WildcardType ) continue;
|
||||||
if( arg instanceof TypeVariable && ((TypeVariable<?>) arg).getName().startsWith( "capture#" ) )
|
if( arg instanceof TypeVariable && ((TypeVariable<?>) arg).getName().startsWith( "capture#" ) )
|
||||||
|
@ -79,4 +79,19 @@ public class ClientTerminal implements ITerminal
|
|||||||
terminalChanged = true;
|
terminalChanged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void readDescription( NbtCompound nbt )
|
||||||
|
{
|
||||||
|
colour = nbt.getBoolean( "colour" );
|
||||||
|
if( nbt.contains( "terminal" ) )
|
||||||
|
{
|
||||||
|
NbtCompound terminal = nbt.getCompound( "terminal" );
|
||||||
|
resizeTerminal( terminal.getInt( "term_width" ), terminal.getInt( "term_height" ) );
|
||||||
|
this.terminal.readFromNBT( terminal );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
deleteTerminal();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
|
import me.shedaniel.cloth.api.utils.v1.GameInstanceUtils;
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
|
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
|
||||||
@ -30,6 +31,7 @@ import net.minecraft.server.network.ServerPlayerEntity;
|
|||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraft.world.chunk.WorldChunk;
|
||||||
|
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@ -70,6 +72,10 @@ public final class NetworkHandler
|
|||||||
registerMainThread( 12, ComputerDeletedClientMessage.class, ComputerDeletedClientMessage::new );
|
registerMainThread( 12, ComputerDeletedClientMessage.class, ComputerDeletedClientMessage::new );
|
||||||
registerMainThread( 13, ComputerTerminalClientMessage.class, ComputerTerminalClientMessage::new );
|
registerMainThread( 13, ComputerTerminalClientMessage.class, ComputerTerminalClientMessage::new );
|
||||||
registerMainThread( 14, PlayRecordClientMessage.class, PlayRecordClientMessage::new );
|
registerMainThread( 14, PlayRecordClientMessage.class, PlayRecordClientMessage::new );
|
||||||
|
registerMainThread( 15, MonitorClientMessage.class, MonitorClientMessage::new );
|
||||||
|
registerMainThread( 16, SpeakerPlayClientMessage.class, SpeakerPlayClientMessage::new );
|
||||||
|
registerMainThread( 17, SpeakerStopClientMessage.class, SpeakerStopClientMessage::new );
|
||||||
|
registerMainThread( 18, SpeakerMoveClientMessage.class, SpeakerMoveClientMessage::new );
|
||||||
registerMainThread( 19, UploadResultMessage.class, UploadResultMessage::new );
|
registerMainThread( 19, UploadResultMessage.class, UploadResultMessage::new );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,11 +111,6 @@ public final class NetworkHandler
|
|||||||
.getClass();
|
.getClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void sendToPlayer( PlayerEntity player, NetworkMessage packet )
|
|
||||||
{
|
|
||||||
((ServerPlayerEntity) player).networkHandler.sendPacket( new CustomPayloadS2CPacket( ID, encode( packet ) ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
private static PacketByteBuf encode( NetworkMessage message )
|
private static PacketByteBuf encode( NetworkMessage message )
|
||||||
{
|
{
|
||||||
PacketByteBuf buf = new PacketByteBuf( Unpooled.buffer() );
|
PacketByteBuf buf = new PacketByteBuf( Unpooled.buffer() );
|
||||||
@ -118,6 +119,18 @@ public final class NetworkHandler
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void sendToPlayer( PlayerEntity player, NetworkMessage packet )
|
||||||
|
{
|
||||||
|
((ServerPlayerEntity) player).networkHandler.sendPacket( new CustomPayloadS2CPacket( ID, encode( packet ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendToAllPlayers( NetworkMessage packet )
|
||||||
|
{
|
||||||
|
MinecraftServer server = GameInstanceUtils.getServer();
|
||||||
|
server.getPlayerManager()
|
||||||
|
.sendToAll( new CustomPayloadS2CPacket( ID, encode( packet ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
public static void sendToAllPlayers( MinecraftServer server, NetworkMessage packet )
|
public static void sendToAllPlayers( MinecraftServer server, NetworkMessage packet )
|
||||||
{
|
{
|
||||||
server.getPlayerManager()
|
server.getPlayerManager()
|
||||||
@ -136,4 +149,14 @@ public final class NetworkHandler
|
|||||||
.getPlayerManager()
|
.getPlayerManager()
|
||||||
.sendToAround( null, pos.x, pos.y, pos.z, range, world.getRegistryKey(), new CustomPayloadS2CPacket( ID, encode( packet ) ) );
|
.sendToAround( null, pos.x, pos.y, pos.z, range, world.getRegistryKey(), new CustomPayloadS2CPacket( ID, encode( packet ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void sendToAllTracking( NetworkMessage packet, WorldChunk chunk )
|
||||||
|
{
|
||||||
|
// maybe bug with worlds
|
||||||
|
for(PlayerEntity player : chunk.getWorld().getPlayers()) {
|
||||||
|
if (player.getChunkPos().equals(chunk.getPos())) {
|
||||||
|
((ServerPlayerEntity) player).networkHandler.sendPacket( new CustomPayloadS2CPacket( ID, encode( 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.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.fabricmc.fabric.api.network.PacketContext;
|
||||||
|
import net.minecraft.network.PacketByteBuf;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
|
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( PacketByteBuf buf )
|
||||||
|
{
|
||||||
|
source = buf.readUuid();
|
||||||
|
pos = new Vec3d( buf.readDouble(), buf.readDouble(), buf.readDouble() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toBytes( @Nonnull PacketByteBuf buf )
|
||||||
|
{
|
||||||
|
buf.writeUuid( source );
|
||||||
|
buf.writeDouble( pos.getX() );
|
||||||
|
buf.writeDouble( pos.getY() );
|
||||||
|
buf.writeDouble( pos.getZ() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Environment( EnvType.CLIENT )
|
||||||
|
public void handle( PacketContext 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.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.fabricmc.fabric.api.network.PacketContext;
|
||||||
|
import net.minecraft.network.PacketByteBuf;
|
||||||
|
import net.minecraft.sound.SoundEvent;
|
||||||
|
import net.minecraft.sound.SoundEvents;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
|
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 Identifier sound;
|
||||||
|
private final float volume;
|
||||||
|
private final float pitch;
|
||||||
|
|
||||||
|
public SpeakerPlayClientMessage( UUID source, Vec3d pos, Identifier event, float volume, float pitch )
|
||||||
|
{
|
||||||
|
this.source = source;
|
||||||
|
this.pos = pos;
|
||||||
|
sound = event;
|
||||||
|
this.volume = volume;
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpeakerPlayClientMessage( PacketByteBuf buf )
|
||||||
|
{
|
||||||
|
source = buf.readUuid();
|
||||||
|
pos = new Vec3d( buf.readDouble(), buf.readDouble(), buf.readDouble() );
|
||||||
|
sound = buf.readIdentifier();
|
||||||
|
volume = buf.readFloat();
|
||||||
|
pitch = buf.readFloat();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toBytes( @Nonnull PacketByteBuf buf )
|
||||||
|
{
|
||||||
|
buf.writeUuid( source );
|
||||||
|
buf.writeDouble( pos.getX() );
|
||||||
|
buf.writeDouble( pos.getY() );
|
||||||
|
buf.writeDouble( pos.getZ() );
|
||||||
|
buf.writeIdentifier( sound );
|
||||||
|
buf.writeFloat( volume );
|
||||||
|
buf.writeFloat( pitch );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Environment( EnvType.CLIENT )
|
||||||
|
public void handle( PacketContext context )
|
||||||
|
{
|
||||||
|
SoundEvent sound = new SoundEvent(this.sound);
|
||||||
|
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.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.fabricmc.fabric.api.network.PacketContext;
|
||||||
|
import net.minecraft.network.PacketByteBuf;
|
||||||
|
|
||||||
|
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( PacketByteBuf buf )
|
||||||
|
{
|
||||||
|
source = buf.readUuid();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toBytes( @Nonnull PacketByteBuf buf )
|
||||||
|
{
|
||||||
|
buf.writeUuid( source );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public void handle( PacketContext context )
|
||||||
|
{
|
||||||
|
SoundManager.stopSound( source );
|
||||||
|
}
|
||||||
|
}
|
@ -36,7 +36,7 @@ public class BlockMonitor extends BlockGeneric
|
|||||||
|
|
||||||
static final EnumProperty<MonitorEdgeState> STATE = EnumProperty.of( "state", MonitorEdgeState.class );
|
static final EnumProperty<MonitorEdgeState> STATE = EnumProperty.of( "state", MonitorEdgeState.class );
|
||||||
|
|
||||||
public boolean advanced = false;
|
public boolean advanced;
|
||||||
|
|
||||||
public BlockMonitor( Settings settings, BlockEntityType<? extends TileMonitor> type, boolean advanced )
|
public BlockMonitor( Settings settings, BlockEntityType<? extends TileMonitor> type, boolean advanced )
|
||||||
{
|
{
|
||||||
@ -83,9 +83,8 @@ public class BlockMonitor extends BlockGeneric
|
|||||||
super.onPlaced( world, pos, blockState, livingEntity, itemStack );
|
super.onPlaced( world, pos, blockState, livingEntity, itemStack );
|
||||||
|
|
||||||
BlockEntity entity = world.getBlockEntity( pos );
|
BlockEntity entity = world.getBlockEntity( pos );
|
||||||
if( entity instanceof TileMonitor && !world.isClient )
|
if( entity instanceof TileMonitor monitor && !world.isClient )
|
||||||
{
|
{
|
||||||
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 )
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* 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.monitor;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
final class MonitorState
|
||||||
|
{
|
||||||
|
public static final MonitorState UNLOADED = new MonitorState( State.UNLOADED, null );
|
||||||
|
public static final MonitorState MISSING = new MonitorState( State.MISSING, null );
|
||||||
|
|
||||||
|
private final State state;
|
||||||
|
private final TileMonitor monitor;
|
||||||
|
|
||||||
|
private MonitorState( @Nonnull State state, @Nullable TileMonitor monitor )
|
||||||
|
{
|
||||||
|
this.state = state;
|
||||||
|
this.monitor = monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MonitorState present( @Nonnull TileMonitor monitor )
|
||||||
|
{
|
||||||
|
return new MonitorState( State.PRESENT, monitor );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPresent()
|
||||||
|
{
|
||||||
|
return state == State.PRESENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMissing()
|
||||||
|
{
|
||||||
|
return state == State.MISSING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public TileMonitor getMonitor()
|
||||||
|
{
|
||||||
|
return monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
UNLOADED,
|
||||||
|
MISSING,
|
||||||
|
PRESENT,
|
||||||
|
}
|
||||||
|
}
|
@ -51,6 +51,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
private ClientMonitor clientMonitor;
|
private ClientMonitor clientMonitor;
|
||||||
private MonitorPeripheral peripheral;
|
private MonitorPeripheral peripheral;
|
||||||
private boolean needsUpdate = false;
|
private boolean needsUpdate = false;
|
||||||
|
private boolean needsValidating = false;
|
||||||
private boolean destroyed = false;
|
private boolean destroyed = false;
|
||||||
private boolean visiting = false;
|
private boolean visiting = false;
|
||||||
private int width = 1;
|
private int width = 1;
|
||||||
@ -124,6 +125,13 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
@Override
|
@Override
|
||||||
public void blockTick()
|
public void blockTick()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if( needsValidating )
|
||||||
|
{
|
||||||
|
needsValidating = false;
|
||||||
|
validate();
|
||||||
|
}
|
||||||
|
|
||||||
if( needsUpdate )
|
if( needsUpdate )
|
||||||
{
|
{
|
||||||
needsUpdate = false;
|
needsUpdate = false;
|
||||||
@ -143,7 +151,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
{
|
{
|
||||||
for( int y = 0; y < height; y++ )
|
for( int y = 0; y < height; y++ )
|
||||||
{
|
{
|
||||||
TileMonitor monitor = getNeighbour( x, y );
|
TileMonitor monitor = getNeighbour( x, y ).getMonitor();
|
||||||
if( monitor == null )
|
if( monitor == null )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -170,6 +178,8 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
|
|
||||||
int oldXIndex = xIndex;
|
int oldXIndex = xIndex;
|
||||||
int oldYIndex = yIndex;
|
int oldYIndex = yIndex;
|
||||||
|
int oldWidth = width;
|
||||||
|
int oldHeight = height;
|
||||||
|
|
||||||
xIndex = nbt.getInt( NBT_X );
|
xIndex = nbt.getInt( NBT_X );
|
||||||
yIndex = nbt.getInt( NBT_Y );
|
yIndex = nbt.getInt( NBT_Y );
|
||||||
@ -180,14 +190,27 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
{
|
{
|
||||||
// If our index has changed then it's possible the origin monitor has changed. Thus
|
// If our index has changed then it's possible the origin monitor has changed. Thus
|
||||||
// we'll clear our cache. If we're the origin then we'll need to remove the glList as well.
|
// we'll clear our cache. If we're the origin then we'll need to remove the glList as well.
|
||||||
if( oldXIndex == 0 && oldYIndex == 0 && clientMonitor != null ) clientMonitor.destroy();
|
if( oldXIndex == 0 && oldYIndex == 0 && clientMonitor != null )
|
||||||
|
{
|
||||||
|
clientMonitor.destroy();
|
||||||
|
}
|
||||||
clientMonitor = null;
|
clientMonitor = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( xIndex == 0 && yIndex == 0 )
|
if( xIndex == 0 && yIndex == 0 )
|
||||||
{
|
{
|
||||||
// If we're the origin terminal then create it.
|
// If we're the origin terminal then create it.
|
||||||
if( clientMonitor == null ) clientMonitor = new ClientMonitor( advanced, this );
|
if( clientMonitor == null )
|
||||||
|
{
|
||||||
|
clientMonitor = new ClientMonitor( advanced, this );
|
||||||
|
}
|
||||||
|
clientMonitor.readDescription( nbt );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( oldXIndex != xIndex || oldYIndex != yIndex || oldWidth != width || oldHeight != height )
|
||||||
|
{
|
||||||
|
// One of our properties has changed, so ensure we redraw the block
|
||||||
|
updateBlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,9 +222,14 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
nbt.putInt( NBT_Y, yIndex );
|
nbt.putInt( NBT_Y, yIndex );
|
||||||
nbt.putInt( NBT_WIDTH, width );
|
nbt.putInt( NBT_WIDTH, width );
|
||||||
nbt.putInt( NBT_HEIGHT, height );
|
nbt.putInt( NBT_HEIGHT, height );
|
||||||
|
|
||||||
|
if( xIndex == 0 && yIndex == 0 && serverMonitor != null )
|
||||||
|
{
|
||||||
|
serverMonitor.writeDescription( nbt );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TileMonitor getNeighbour( int x, int y )
|
private MonitorState getNeighbour( int x, int y )
|
||||||
{
|
{
|
||||||
BlockPos pos = getPos();
|
BlockPos pos = getPos();
|
||||||
Direction right = getRight();
|
Direction right = getRight();
|
||||||
@ -227,28 +255,27 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
return orientation == Direction.DOWN ? getDirection() : getDirection().getOpposite();
|
return orientation == Direction.DOWN ? getDirection() : getDirection().getOpposite();
|
||||||
}
|
}
|
||||||
|
|
||||||
private TileMonitor getSimilarMonitorAt( BlockPos pos )
|
private MonitorState getSimilarMonitorAt( BlockPos pos )
|
||||||
{
|
{
|
||||||
if( pos.equals( getPos() ) )
|
if( pos.equals( getPos() ) )
|
||||||
{
|
{
|
||||||
return this;
|
return MonitorState.present(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
int y = pos.getY();
|
|
||||||
World world = getWorld();
|
World world = getWorld();
|
||||||
if( world == null || !world.isChunkLoaded( pos ) )
|
if( world == null || !world.isChunkLoaded( pos ) )
|
||||||
{
|
{
|
||||||
return null;
|
return MonitorState.UNLOADED;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockEntity tile = world.getBlockEntity( pos );
|
BlockEntity tile = world.getBlockEntity( pos );
|
||||||
if( !(tile instanceof TileMonitor) )
|
if( !(tile instanceof TileMonitor) )
|
||||||
{
|
{
|
||||||
return null;
|
return MonitorState.MISSING;
|
||||||
}
|
}
|
||||||
|
|
||||||
TileMonitor monitor = (TileMonitor) tile;
|
TileMonitor monitor = (TileMonitor) tile;
|
||||||
return !monitor.visiting && !monitor.destroyed && advanced == monitor.advanced && getDirection() == monitor.getDirection() && getOrientation() == monitor.getOrientation() ? monitor : null;
|
return !monitor.visiting && !monitor.destroyed && advanced == monitor.advanced && getDirection() == monitor.getDirection() && getOrientation() == monitor.getOrientation() ? MonitorState.present( monitor ) : MonitorState.MISSING;
|
||||||
}
|
}
|
||||||
|
|
||||||
// region Sizing and placement stuff
|
// region Sizing and placement stuff
|
||||||
@ -302,6 +329,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
public void cancelRemoval()
|
public void cancelRemoval()
|
||||||
{
|
{
|
||||||
super.cancelRemoval();
|
super.cancelRemoval();
|
||||||
|
needsValidating = true;
|
||||||
TickScheduler.schedule( this );
|
TickScheduler.schedule( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,7 +357,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
return serverMonitor;
|
return serverMonitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
TileMonitor origin = getOrigin();
|
TileMonitor origin = getOrigin().getMonitor();
|
||||||
if( origin == null )
|
if( origin == null )
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@ -356,7 +384,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
{
|
{
|
||||||
for( int y = 0; y < height; y++ )
|
for( int y = 0; y < height; y++ )
|
||||||
{
|
{
|
||||||
TileMonitor monitor = getNeighbour( x, y );
|
TileMonitor monitor = getNeighbour( x, y ).getMonitor();
|
||||||
if( monitor != null )
|
if( monitor != null )
|
||||||
{
|
{
|
||||||
monitor.serverMonitor = serverMonitor;
|
monitor.serverMonitor = serverMonitor;
|
||||||
@ -450,7 +478,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
return yIndex;
|
return yIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TileMonitor getOrigin()
|
private MonitorState getOrigin()
|
||||||
{
|
{
|
||||||
return getNeighbour( 0, 0 );
|
return getNeighbour( 0, 0 );
|
||||||
}
|
}
|
||||||
@ -477,7 +505,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
{
|
{
|
||||||
for( int y = 0; y < height; y++ )
|
for( int y = 0; y < height; y++ )
|
||||||
{
|
{
|
||||||
TileMonitor monitor = getNeighbour( x, y );
|
TileMonitor monitor = getNeighbour( x, y ).getMonitor();
|
||||||
if( monitor != null && monitor.peripheral != null )
|
if( monitor != null && monitor.peripheral != null )
|
||||||
{
|
{
|
||||||
needsTerminal = true;
|
needsTerminal = true;
|
||||||
@ -511,7 +539,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
{
|
{
|
||||||
for( int y = 0; y < height; y++ )
|
for( int y = 0; y < height; y++ )
|
||||||
{
|
{
|
||||||
TileMonitor monitor = getNeighbour( x, y );
|
TileMonitor monitor = getNeighbour( x, y ).getMonitor();
|
||||||
if( monitor == null )
|
if( monitor == null )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -530,7 +558,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
|
|
||||||
private boolean mergeLeft()
|
private boolean mergeLeft()
|
||||||
{
|
{
|
||||||
TileMonitor left = getNeighbour( -1, 0 );
|
TileMonitor left = getNeighbour( -1, 0 ).getMonitor();
|
||||||
if( left == null || left.yIndex != 0 || left.height != height )
|
if( left == null || left.yIndex != 0 || left.height != height )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -542,7 +570,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TileMonitor origin = left.getOrigin();
|
TileMonitor origin = left.getOrigin().getMonitor();
|
||||||
if( origin != null )
|
if( origin != null )
|
||||||
{
|
{
|
||||||
origin.resize( width, height );
|
origin.resize( width, height );
|
||||||
@ -553,7 +581,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
|
|
||||||
private boolean mergeRight()
|
private boolean mergeRight()
|
||||||
{
|
{
|
||||||
TileMonitor right = getNeighbour( width, 0 );
|
TileMonitor right = getNeighbour( width, 0 ).getMonitor();
|
||||||
if( right == null || right.yIndex != 0 || right.height != height )
|
if( right == null || right.yIndex != 0 || right.height != height )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -565,7 +593,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TileMonitor origin = getOrigin();
|
TileMonitor origin = getOrigin().getMonitor();
|
||||||
if( origin != null )
|
if( origin != null )
|
||||||
{
|
{
|
||||||
origin.resize( width, height );
|
origin.resize( width, height );
|
||||||
@ -576,7 +604,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
|
|
||||||
private boolean mergeUp()
|
private boolean mergeUp()
|
||||||
{
|
{
|
||||||
TileMonitor above = getNeighbour( 0, height );
|
TileMonitor above = getNeighbour( 0, height ).getMonitor();
|
||||||
if( above == null || above.xIndex != 0 || above.width != width )
|
if( above == null || above.xIndex != 0 || above.width != width )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -588,7 +616,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TileMonitor origin = getOrigin();
|
TileMonitor origin = getOrigin().getMonitor();
|
||||||
if( origin != null )
|
if( origin != null )
|
||||||
{
|
{
|
||||||
origin.resize( width, height );
|
origin.resize( width, height );
|
||||||
@ -599,7 +627,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
|
|
||||||
private boolean mergeDown()
|
private boolean mergeDown()
|
||||||
{
|
{
|
||||||
TileMonitor below = getNeighbour( 0, -1 );
|
TileMonitor below = getNeighbour( 0, -1 ).getMonitor();
|
||||||
if( below == null || below.xIndex != 0 || below.width != width )
|
if( below == null || below.xIndex != 0 || below.width != width )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -611,7 +639,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TileMonitor origin = below.getOrigin();
|
TileMonitor origin = below.getOrigin().getMonitor();
|
||||||
if( origin != null )
|
if( origin != null )
|
||||||
{
|
{
|
||||||
origin.resize( width, height );
|
origin.resize( width, height );
|
||||||
@ -643,7 +671,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
visiting = true;
|
visiting = true;
|
||||||
if( xIndex > 0 )
|
if( xIndex > 0 )
|
||||||
{
|
{
|
||||||
TileMonitor left = getNeighbour( xIndex - 1, yIndex );
|
TileMonitor left = getNeighbour( xIndex - 1, yIndex ).getMonitor();
|
||||||
if( left != null )
|
if( left != null )
|
||||||
{
|
{
|
||||||
left.contract();
|
left.contract();
|
||||||
@ -651,7 +679,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
}
|
}
|
||||||
if( xIndex + 1 < width )
|
if( xIndex + 1 < width )
|
||||||
{
|
{
|
||||||
TileMonitor right = getNeighbour( xIndex + 1, yIndex );
|
TileMonitor right = getNeighbour( xIndex + 1, yIndex ).getMonitor();
|
||||||
if( right != null )
|
if( right != null )
|
||||||
{
|
{
|
||||||
right.contract();
|
right.contract();
|
||||||
@ -659,7 +687,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
}
|
}
|
||||||
if( yIndex > 0 )
|
if( yIndex > 0 )
|
||||||
{
|
{
|
||||||
TileMonitor below = getNeighbour( xIndex, yIndex - 1 );
|
TileMonitor below = getNeighbour( xIndex, yIndex - 1 ).getMonitor();
|
||||||
if( below != null )
|
if( below != null )
|
||||||
{
|
{
|
||||||
below.contract();
|
below.contract();
|
||||||
@ -667,7 +695,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
}
|
}
|
||||||
if( yIndex + 1 < height )
|
if( yIndex + 1 < height )
|
||||||
{
|
{
|
||||||
TileMonitor above = getNeighbour( xIndex, yIndex + 1 );
|
TileMonitor above = getNeighbour( xIndex, yIndex + 1 ).getMonitor();
|
||||||
if( above != null )
|
if( above != null )
|
||||||
{
|
{
|
||||||
above.contract();
|
above.contract();
|
||||||
@ -681,11 +709,11 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
int height = this.height;
|
int height = this.height;
|
||||||
int width = this.width;
|
int width = this.width;
|
||||||
|
|
||||||
TileMonitor origin = getOrigin();
|
TileMonitor origin = getOrigin().getMonitor();
|
||||||
if( origin == null )
|
if( origin == null )
|
||||||
{
|
{
|
||||||
TileMonitor right = width > 1 ? getNeighbour( 1, 0 ) : null;
|
TileMonitor right = width > 1 ? getNeighbour( 1, 0 ).getMonitor() : null;
|
||||||
TileMonitor below = height > 1 ? getNeighbour( 0, 1 ) : null;
|
TileMonitor below = height > 1 ? getNeighbour( 0, 1 ).getMonitor() : null;
|
||||||
|
|
||||||
if( right != null )
|
if( right != null )
|
||||||
{
|
{
|
||||||
@ -711,7 +739,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
{
|
{
|
||||||
for( int x = 0; x < width; x++ )
|
for( int x = 0; x < width; x++ )
|
||||||
{
|
{
|
||||||
TileMonitor monitor = origin.getNeighbour( x, y );
|
TileMonitor monitor = origin.getNeighbour( x, y ).getMonitor();
|
||||||
if( monitor != null )
|
if( monitor != null )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -730,17 +758,17 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
}
|
}
|
||||||
if( x > 0 )
|
if( x > 0 )
|
||||||
{
|
{
|
||||||
left = origin.getNeighbour( 0, y );
|
left = origin.getNeighbour( 0, y ).getMonitor();
|
||||||
left.resize( x, 1 );
|
left.resize( x, 1 );
|
||||||
}
|
}
|
||||||
if( x + 1 < width )
|
if( x + 1 < width )
|
||||||
{
|
{
|
||||||
right = origin.getNeighbour( x + 1, y );
|
right = origin.getNeighbour( x + 1, y ).getMonitor();
|
||||||
right.resize( width - (x + 1), 1 );
|
right.resize( width - (x + 1), 1 );
|
||||||
}
|
}
|
||||||
if( y + 1 < height )
|
if( y + 1 < height )
|
||||||
{
|
{
|
||||||
below = origin.getNeighbour( 0, y + 1 );
|
below = origin.getNeighbour( 0, y + 1 ).getMonitor();
|
||||||
below.resize( width, height - (y + 1) );
|
below.resize( width, height - (y + 1) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -767,6 +795,34 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
}
|
}
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
private boolean checkMonitorAt( int xIndex, int yIndex )
|
||||||
|
{
|
||||||
|
MonitorState state = getNeighbour( xIndex, yIndex );
|
||||||
|
if( state.isMissing() ) return false;
|
||||||
|
|
||||||
|
TileMonitor monitor = state.getMonitor();
|
||||||
|
if( monitor == null ) return true;
|
||||||
|
|
||||||
|
return monitor.xIndex == xIndex && monitor.yIndex == yIndex && monitor.width == width && monitor.height == height;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validate()
|
||||||
|
{
|
||||||
|
if( xIndex == 0 && yIndex == 0 && width == 1 || height == 1 ) return;
|
||||||
|
|
||||||
|
if( checkMonitorAt( 0, 0 ) && checkMonitorAt( 0, height - 1 ) &&
|
||||||
|
checkMonitorAt( width - 1, 0 ) && checkMonitorAt( width - 1, height - 1 ) )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something in our monitor is invalid. For now, let's just reset ourselves and then try to integrate ourselves
|
||||||
|
// later.
|
||||||
|
ComputerCraft.log.warn( "Monitor is malformed, resetting to 1x1." );
|
||||||
|
resize( 1, 1 );
|
||||||
|
needsUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
private void monitorTouched( float xPos, float yPos, float zPos )
|
private void monitorTouched( float xPos, float yPos, float zPos )
|
||||||
{
|
{
|
||||||
XYPair pair = XYPair.of( xPos, yPos, zPos, getDirection(), getOrientation() )
|
XYPair pair = XYPair.of( xPos, yPos, zPos, getDirection(), getOrientation() )
|
||||||
@ -799,7 +855,7 @@ public class TileMonitor extends TileGeneric implements IPeripheralTile
|
|||||||
{
|
{
|
||||||
for( int x = 0; x < width; x++ )
|
for( int x = 0; x < width; x++ )
|
||||||
{
|
{
|
||||||
TileMonitor monitor = getNeighbour( x, y );
|
TileMonitor monitor = getNeighbour( x, y ).getMonitor();
|
||||||
if( monitor == null )
|
if( monitor == null )
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -12,17 +12,23 @@ 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.fabric.mixin.SoundEventAccess;
|
import dan200.computercraft.fabric.mixin.SoundEventAccess;
|
||||||
|
import dan200.computercraft.shared.network.NetworkHandler;
|
||||||
|
import dan200.computercraft.shared.network.client.SpeakerMoveClientMessage;
|
||||||
|
import dan200.computercraft.shared.network.client.SpeakerPlayClientMessage;
|
||||||
import net.minecraft.block.enums.Instrument;
|
import net.minecraft.block.enums.Instrument;
|
||||||
import net.minecraft.network.packet.s2c.play.PlaySoundIdS2CPacket;
|
import net.minecraft.network.packet.s2c.play.PlaySoundIdS2CPacket;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.sound.SoundCategory;
|
import net.minecraft.sound.SoundCategory;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
import net.minecraft.util.InvalidIdentifierException;
|
import net.minecraft.util.InvalidIdentifierException;
|
||||||
|
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;
|
||||||
@ -34,16 +40,40 @@ 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 final AtomicInteger notesThisTick = new AtomicInteger();
|
private final AtomicInteger notesThisTick = new AtomicInteger();
|
||||||
private long clock = 0;
|
private long clock = 0;
|
||||||
private long lastPlayTime = 0;
|
private long lastPlayTime = 0;
|
||||||
|
|
||||||
|
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.distanceTo( position ) >= 0.1 )
|
||||||
|
{
|
||||||
|
lastPosition = position;
|
||||||
|
lastPositionTime = clock;
|
||||||
|
NetworkHandler.sendToAllTracking(
|
||||||
|
new SpeakerMoveClientMessage( getSource(), position ),
|
||||||
|
getWorld().getWorldChunk( new BlockPos( position ) )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract UUID getSource();
|
||||||
|
|
||||||
public boolean madeSound( long ticks )
|
public boolean madeSound( long ticks )
|
||||||
{
|
{
|
||||||
return clock - lastPlayTime <= ticks;
|
return clock - lastPlayTime <= ticks;
|
||||||
@ -90,16 +120,20 @@ public abstract class SpeakerPeripheral implements IPeripheral
|
|||||||
|
|
||||||
private synchronized boolean playSound( ILuaContext context, Identifier name, float volume, float pitch, boolean isNote ) throws LuaException
|
private synchronized boolean playSound( ILuaContext context, Identifier name, float volume, float pitch, boolean isNote ) throws LuaException
|
||||||
{
|
{
|
||||||
if( clock - lastPlayTime < TileSpeaker.MIN_TICKS_BETWEEN_SOUNDS && (!isNote || clock - lastPlayTime != 0 || notesThisTick.get() >= ComputerCraft.maxNotesPerTick) )
|
if( clock - lastPlayTime < MIN_TICKS_BETWEEN_SOUNDS )
|
||||||
{
|
{
|
||||||
// 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 actualVolume = MathHelper.clamp( volume, 0.0f, 3.0f );
|
||||||
|
float range = actualVolume * 16;
|
||||||
|
|
||||||
context.issueMainThreadTask( () -> {
|
context.issueMainThreadTask( () -> {
|
||||||
MinecraftServer server = world.getServer();
|
MinecraftServer server = world.getServer();
|
||||||
if( server == null )
|
if( server == null )
|
||||||
@ -107,15 +141,18 @@ public abstract class SpeakerPeripheral implements IPeripheral
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
float adjVolume = Math.min( volume, 3.0f );
|
if( isNote )
|
||||||
server.getPlayerManager()
|
{
|
||||||
.sendToAround( null,
|
server.getPlayerManager().sendToAround(
|
||||||
pos.x,
|
null, pos.x, pos.y, pos.z, range, world.getRegistryKey(),
|
||||||
pos.y,
|
new PlaySoundIdS2CPacket( name, SoundCategory.RECORDS, pos, actualVolume, pitch )
|
||||||
pos.z,
|
);
|
||||||
adjVolume > 1.0f ? 16 * adjVolume : 16.0,
|
} else {
|
||||||
world.getRegistryKey(),
|
NetworkHandler.sendToAllAround(
|
||||||
new PlaySoundIdS2CPacket( name, SoundCategory.RECORDS, pos, adjVolume, pitch ) );
|
new SpeakerPlayClientMessage( getSource(), pos, name, actualVolume, pitch ),
|
||||||
|
world, pos, range
|
||||||
|
);
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
@ -19,12 +19,14 @@ import net.minecraft.world.World;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class TileSpeaker extends TileGeneric implements IPeripheralTile
|
public class TileSpeaker extends TileGeneric implements IPeripheralTile
|
||||||
{
|
{
|
||||||
public static final int MIN_TICKS_BETWEEN_SOUNDS = 1;
|
public static final int MIN_TICKS_BETWEEN_SOUNDS = 1;
|
||||||
|
|
||||||
private final SpeakerPeripheral peripheral;
|
private final SpeakerPeripheral peripheral;
|
||||||
|
private final UUID source = UUID.randomUUID();
|
||||||
|
|
||||||
public TileSpeaker( BlockEntityType<TileSpeaker> type, BlockPos pos, BlockState state )
|
public TileSpeaker( BlockEntityType<TileSpeaker> type, BlockPos pos, BlockState state )
|
||||||
{
|
{
|
||||||
@ -66,6 +68,12 @@ public class TileSpeaker extends TileGeneric implements IPeripheralTile
|
|||||||
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 ) );
|
||||||
|
}
|
||||||
|
}
|
@ -8,10 +8,11 @@ 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.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;
|
||||||
|
@ -13,6 +13,7 @@ import dan200.computercraft.api.turtle.TurtleSide;
|
|||||||
import dan200.computercraft.api.turtle.TurtleUpgradeType;
|
import dan200.computercraft.api.turtle.TurtleUpgradeType;
|
||||||
import dan200.computercraft.shared.ComputerCraftRegistry;
|
import dan200.computercraft.shared.ComputerCraftRegistry;
|
||||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral;
|
import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral;
|
||||||
|
import dan200.computercraft.shared.peripheral.speaker.UpgradeSpeakerPeripheral;
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
import net.minecraft.client.util.ModelIdentifier;
|
import net.minecraft.client.util.ModelIdentifier;
|
||||||
@ -71,7 +72,7 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Peripheral extends SpeakerPeripheral
|
private static class Peripheral extends UpgradeSpeakerPeripheral
|
||||||
{
|
{
|
||||||
ITurtleAccess turtle;
|
ITurtleAccess turtle;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user